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