很多人都知道程序是從main函數開始執行的,但在main之前執行了什麼卻不夠了解,本文分別介紹Keil調用的ARMCC以及ARM-NONE-EABI-GCC兩個編譯器生成的在main之前的操作:
Keil MDK啓動文件
總結一下MDK的啓動流程:
1.系統初始化,包括中斷向量表的重新映射
2.加載RW段(.data段初始化)
3.加載ZI段(.bss段初始化)
4.初始化用戶堆棧
5.初始化Microlib
6.調用main函數
microlib 是缺省 C 庫的備選庫。 它旨在與需要裝入到極少量內存中的深層嵌入式應用程序配合使用。 這些應用程序不在操作系統中運行。
microlib 進行了高度優化以使代碼變得很小。 它的功能比缺省 C 庫少,並且根本不具備某些 ISO C 特性。 某些庫函數的運行速度也比較慢,例如,memcpy()。
下圖是Keil調用ARMCC的加載到運行的變化視圖:
稍微解釋下這張圖,從加載加載視圖切換到執行視圖時,代碼存放在ROM中是不用變的,將pc指針指向程序的初始地址就可以依次執行指令,但是已經初始化的全局變量data段與未初始化的全局變量bss段需要從flash中加載到指定的內存地址中。
對於RO與RW段
Loadregion_nameBase表示region_name區域的裝載地址
“Imageregion_nameBase”表示region_name區域的執行地址
“Imageregion_nameLength”表示region_name區域的長度(單位:字節)
對於ZI段
“Imageregion_nameZIBase”表示region_name區域的執行地址
“Imageregion_nameZILength”表示region_name區域的長度(單位:字節)
ARM-NONE-EABI-GCC的crt0啓動流程
利用arm-none-eabi-gcc編譯器生成ELF文件,將ELF文件通過objdump反彙編可以找出main之前的初始化函數_mainCRTStartup。
下圖爲ARM7V-M平臺下_mainCRTStartup的大致流程:
下面看一下ELF文件中各段的分佈:
由上圖可知.text後直接跟.data段,但.data段的地址爲RAM的實際地址。
小結:
arm-none-eabi-gcc不像armcc有將全局變量的值存儲在flash中,所以沒有像scatter_load函數這樣從flash中加載全局變量到ram中,arm-none-eabi-gcc只能靠加載器將.data段直接加載到ram中。