历史上的今天
今天是:2025年03月08日(星期六)
2019年03月08日 | STM32__main代码分析
2019-03-08 来源:eefocus
STM32启动代码主要是分配堆栈及设置向量表,然后跳转到__main函数。
跳转具体到代码段部分如下:
[cpp] view plain copy
Reset_Handler PROC
EXPORT Reset_Handler [WEAK]
IMPORT __main
LDR R0, = __main
BX R0
ENDP
当您看到__main函数时,估计应该有不少人认为这个是main函数的别名或是编译之后的名字,否则在启动代码中再也无法找到和main相关的字眼了。可事实是,__main和main是完全两个不同的函数,并且你无法找到__main代码,因为这个是编译器自动创建的。
查看MDK的文档,会发现有这么一句说明:It is automatically created by the linker when it sees a definition of main()。简单点来说,当编译器发现定义了main函数,那么就会自动创建__main。
程序经过汇编启动代码,执行到__main()后,可以看出有两个大的函数:
__scatterload():负责把RW/RO输出段从装载域地址复制到运行域地址,并完成了ZI运行域的初始化工作。
__rt_entry():负责初始化堆栈,完成库函数的初始化,最后自动跳转向main()函数。
分析__scatterload()函数
执行到__main(),先跳转到_scatterload下图红框框中代码所示,执行完后,R10和R11就被赋给成了下面两个值。
Map文件中的symbol


然后执行_scatterload_null代码,将R10对应地址存放的的4个字copy到R0~R3中,可以看出
R0:0x1000表示的是keyled.o加载域起始地址
R1:0x30000100为keyled.o运行域地址
R2:0X160为copy的大小,keyled.o的大小从map文件中得知就是0x160 Byte
R3:0X1E4 是_scatterload_copy 代码的起始地址,实用BXR3 就能跳转到_scatterload_copy来复制代码。

跳到_scatterload_copy,开始copy,循环0x16次,每次搬移4个字(16Byte),共搬移0x16*0x10=0x160

复制完keyled.o代码后,进一步循环到_scatterload_null准备好,ZI段需要清零的地址和范围
执行完这个循环后
R1:0x30050000 为ZI段的起始地址
R2:0x618为ZI段大小,换成十进制是1560.从map文件得知ZI大小就是1560Byte
R3:0x20c 为_scatterload_zeroinit 的地址

执行下面红框框中循环体,共清零0x610Byte范围,然后再执行蓝框框中代码,清零8Byte,总共0x618
ZI段清零(0x30050000~0x30050618)

然后使用BX R14跳转到0x000001BC处,顺序执行到BL __rt_enty 指令
成功跳转到__rt_enty函数

分析__rt_entry()函数
先调用__user_setup_stackheap()函数来建立堆栈

可以看出在这个函数中,会执行到BL__user_initial_stackheap()函数,这样也就明白了,为什么使用分散加载文件,需要设置__user_initial_stackheap这个函数来设置堆栈空间。

上一篇:STM32之RCC原理
下一篇:STM32分散加载文件
史海拾趣
|
LabVIEW测量信号时间间隔的实现 摘要 以两路信号为例, 详细阐述了以虚拟仪器方式, 针对不同种类的信号输入硬件板卡, 使用L abV IEW 软件平台实现信 号时间间隔测量的方法。详细解释了各种方法的特点、适用范围及具体实现。另外, 也根据具体的测 ...… 查看全部问答> |
|
大家好: 在我的程序里用了::TrackPopupMenu,程序编译通过了,但连接时又出现如下错误: error LNK2019: 无法解析的外部符号 TrackPopupMenu。 我在.cpp文件中已经#include ,TrackPopupMenu就在winuser.h里,为什 ...… 查看全部问答> |
|
具体点是 现在有多个数据过来 比如说 一号灯亮 二号等亮 三号灭 四号灭 这些是不同个信号源发送过来的 这些都是同时发送给51 能不能让51 同时记录下来 记录后打包做好标记 然后不同时刻发送出去 !! ...… 查看全部问答> |




