Stm32程序启动过程分析
程序在Flash的结构
使用Keil编译程序后,程序分为4部分:
- Code:代码区,指程序中代码即函数体的大小,注意程序中未使用的函数也会算在CODE中,也即会占用FLASH空间,因此不用的函数最好删除掉,以免占用过多FLASH空间;
- RO-data:RO就是只读的意思,程序中只读的变量(也就是带Const的)和已初始化的字符串等;
- RW-data:特指已初始化的可读可写全局/静态变量;
- ZI-data:未初始化的可读可写全局/静态变量,注意初始化为0也算做未初始化,用到的堆空间和栈空间也会被算入这里面;
根据生成的*.map 文件:
可看出Load(下载后没有运行)和 Execution(程序正常运行)下固件的内存映射:
其中Code和RO-data对应RO section,RW section为RW-data,ZI section为ZI-data。
各部分Size情况在*.map文件中有统计:
启动过程
启动方式
因为固定的内存映射方式,代码区域总是从0x00000000开始,数据区域(SRAM)总是从0x20000000开始,在STM32F4xx系列芯片中,有三种boot 模式,通过BOOT[1:0]引脚选择:
同时,将0x00000000映射到相应的启动位置的物理地址。例如从Flash memory启动时,会将0x00000000映射到0x08000000。
启动过程
- 根据BOOT[1:0]确定启动方式,例如从Flash memory启动;
- 取出0x0000_0000(0x0800_0000)的栈指针和0x0000_0004(0x0800_0004)处的PC指针;
栈顶地址可以在*.map 文件中找到 0x2000_0298 + 0x0000_0400。
Reset_Handle的入口地址可以在*.map中找到。
- 根据Startup*.s文件定义的复位函数,执行SystemInit和__main函数。
; Reset handler
Reset_Handler PROC
EXPORT Reset_Handler [WEAK]
IMPORT SystemInit
IMPORT __main
LDR R0, =SystemInit
BLX R0
LDR R0, =__main
BX R0
ENDP
- SystemInit函数可以在*.c文件中找到,不在赘述,比较重要的是__main()函数,该函数通过调用__scatterload_copy实现RW section的拷贝,__scatterload_zeroinit实现ZI section的初始化;
- 初始化堆和栈,而后SRAM结构如下图所示:
- 进入main函数,程序正常运行后,如下图所示。
参考:
https://blog.csdn.net/ybhuangfugui/article/details/75948282
https://www.cnblogs.com/39950436-myqq/p/11387179.html