手动实现STM32启动代码:stm32.ld、start.s与startup.c详解

2025-01-09
来源:网络整理

之前写过一篇文章,开始代码分析。这里的ld.*.s都是自动生成的。为了理解原理,我手动实现了一个。

让我们从三个代码开始。 .ld、.s、.c

.ld

.s

.c

.c2

我们先看一下.ld连接脚本。

在第 1 行中,将连接脚本的功能设置为。也可以删除。

2--100行如上一篇文章中提到的。我的电路板的布局状态。两个RAM,一个然后将定义放在第一个RAM的最后位置。

第16行到第48行分别指定了三个相连的段text、data和bss。注意,第37行在程序运行时将数据段的VMA地址放入RAM中,然后在其上使用AT指定的加载地址。 ,表示编译时生成的elf/bin/hex。这一段的数据被放置在地址空间中,然后当程序运行时,这一段数据被放置在RAM中。

具体初始化请看.c代码。它与上一部分中的汇编代码(,)的功能相同。它初始化数据data。这三个段在地址空间中都是 4 字节对齐的。

先用尺寸工具看一下

目前这段代码的data和bss段的大小都是0,也就是说没有数据。更改代码并添加一些验证。

定义了几个变量,我们来看一下。

代码中怎么设置对齐方式_小程序开发工具代码对齐_代码对齐快捷键

现在长度已经改变了,它与定义变量的实际大小不匹配。考虑到对齐,4( )+1(char )+1(char )+1(char ) =7 变为 8。同理,也是一样的。

使用 nm 工具查看五个变量的分布。它们被放置在 RAM 的最开始处。这是整个程序的第一个全局数据。接下来是4、5、6的部分字符数据。移动位置。

BSS段数据根据连接脚本位于数据段的旁边,也可以定义到偏移段的位置。这个 BSS 从头开始​​,因为它是对齐的。

使用arm-none-eabi- -a .elf 看看

第一个VA是,PA也是这个,FLG是R,E(R是只读,E是可执行)

第一个VA是,FLG是R,E(运行时在fRAM中,段数据放在最上面)

我们看一下中断向量表。

((("."))) 指定的数组放置在 中。

链接描述文件指定此链接应放置在 .text 部分的开头,后面紧跟每个程序的 (*.text)。

该数组的第一个元素是SP的位置,第二个元素是系统处理函数的位置。

连接脚本指定为+96k ==

让我们看一下该数组及其放置位置。

反汇编arm-none-eabi- -S .elf

数组的第一个元素 00 80 01 20 正是 SP 的地址,因为它处于小端模式。这没有问题。第二个要素是中断处理函数。 41 02 00 08。这是处理函数的地址,没问题。该函数地址不是四字节对齐的。只要第二个元素指向一个函数,就暂时忽略它。

要处理设置 SP,请跳转至 。查看汇编代码是否有可以指定对齐的指令。上述问题已得到解释。

代码中怎么设置对齐方式_代码对齐快捷键_小程序开发工具代码对齐

比较简单,只需重新初始化RAM(VMA)中(LVM)中存储的.data段数据,将.bss段填充0,具体改为0x22进行验证即可。对于那些在.c代码中定义的变量,编译和连接时在RAM中指定该变量的VMA地址(由连接脚本指定)。因此,需要访问这些变量的指令在此阶段无法运行,需要等待其初始化完成。 ,为什么要这么做,逻辑很简单。 .data 因为你的程序给出了初始值。由于定义了变量,.bss 部分尚未初始化,但可以使用。

下载调试:+

1.下载,2.加载符号表,3.,,三个函数加断点

当c运行时,第一个断点是第一个,ir查看寄存器。 SP实际上已被初始化。这是向量表第一个元素的值。在此之前,有粉丝朋友表示不需要ldr sp,=。看来不需要了。然后是N下一条指令,这是ldr sp,=。再次初始化sp。

继续执行到断点开头

结合这张图

这时候看看RAM中的值和执行前RAM中的值。

RAM中存在随机值,、0x73、0x74、0x6d分别是s、t、m的三个字母代码值。

程序继续用c查看RAM情况。此时,两个循环已经运行完毕,并检查RAM中的变量值。

红框是RAM变量的值(、、等),说明RAM中的这些变量已经成功初始化。您可以根据变量地址进行检查。

这里先写第一部分启动代码,后面会实现初始化板卡时钟。很多人可能认为有.s就不是C代码了。不用担心这个。主要原因是C代码本身无法设置SP。

如果将函数更改为以下内容并删除 .S,它将是“纯 C”代码

分享