大多数MCU开发者在开发时都是从main函数开始编程,但MCU在main函数之前做了哪些工作,这部分工作叫做启动文件,每一款芯片的启动文件都值得去研究,因为它是你的程序运行的最开始。目前应用广泛的STM32为例,其启动文件是自动生成的,我们可以去详细分析下这个启动文件在进入main函数之前做了什么。
- 启动文件整体说明
启动文件由汇编编写,这里以STM32在MDK下的启动文件进行分析,启动文件是指系统从上电一直运行到main函数的这段过程,主要完成的内容如下:
(1) 初始化堆栈指针SP=__initial_sp
(2) 初始化PC指针=Reset_Handler (运行的第一个函数)
(3) 初始化系统时钟
(4) 调用 C 库函数 _main 初始化用户堆栈,最终进入到 main 函数
- Hex文件在Flash上的存储结构
下图是编译生成的Hex文件最终烧录到MCU中的存储结构
加载地址:程序保存的位置
链接地址:程序运行的位置
加载数据段和初始化栈:用来进行数据段的重定位和清除bss段,其段包含的内容如下,以data段的拷贝为例,bss段只需清除即可。
(1)Flash上的数据段(初始化的数据段)起始地址
(2)拷贝到到SRAM上的目的地址
(3)数据段的总大小
(4)拷贝数据段的函数scatterload_copy
STM32内部Flash可以直接运行程序,因此其程序的加载地址也是链接地址,否则代码段也需要进行重定位,即把代码从加载地址拷贝到链接地址处。
- 数据在SRAM上的结构
对于程序中初始化的全局变量存储在RAM中,而RAM属于易失性存储器,Flash是非易失性存储器,因此初始化的变量也需要在Flash中存储,上电后重定位到RAM中。
- 启动过程详细分析
(1)上电后设置SP、PC值
上电复位后,硬件会自动根据向量表偏移地址找到向量表,向量表偏移地址的定义如下:
STM32生成的HEX文件在FLASH按如下存放
CPU这时自动从0x0800 0000位置处读取数据赋给栈指针SP,然后自动从0x08000004位置处读取数据赋给PC,程序就跳转到系统复位函数,结果为:
SP = 0x02000810
PC = 0x08000145
(2)执行SystemInit完成系统时钟初始化
(3)拷贝data段到RAM,清除BSS段
执行完系统初始化后进入__main函数,__main是标椎的C库函数,其作用是初始化堆栈,如下图所示,是一个STM32工程编译后的map文件,MDK的散列文件默认链接了data段重定位和BSS段清除的函数。