1)MDK中C程式編譯後的結果,即可執行檔案資料分類:
2)目標檔案中各型別資料的儲存位置
ZI-data 在bss段,ZI資料全為0,所以沒有必要佔用Flash空間,執行時佔用RAM。
RW-data在RAM中,掉電丟失,所以需要啟動時從FLASH拷貝到RAM中去,所以RW佔FLASH空間。
由上我們得知keil的編譯結果:
程式佔用 Flash = Code + RO data + RW data
程式執行時候佔用 RAM = RW data + ZI data。
Code + RO data + RW data 的大小也是生成的 bin 檔案的大小
類似的,GCC的編譯結果:
Memory region Used Size Region Size %age Used
FLASH: 480 B 32 KB 1.46%
RAM: 1200 B 4 KB 29.30%
Flash 的大小:Flash = text + data 。
RAM大小:RAM = data + bss。
AREA STACK, NOINIT, READWRITE, ALIGN=3
Stack_Mem SPACE Stack_Size
__initial_sp
其中:
Heap_Size EQU 0x00000200
AREA HEAP, NOINIT, READWRITE, ALIGN=3
__heap_base
Heap_Mem SPACE Heap_Size
__heap_limit
PRESERVE8
THUMB
具體的含義和棧分配相似,開闢空間Heap_Mem,大小為Heap_Size。__heap_base和__heap_limit分別表示堆的起點和終點。
PRESERVE8 指當前檔案位元組對其。ALIGN 偽指令表示對齊填充,可能的取值為2的冪,如 1 、2 、4 、8 、16 等。未跟數位如ALIGN 表示對齊到1個字(2位元組)。
THUMB 表示使用的指令集。
; Vector Table Mapped to Address 0 at Reset
AREA RESET, DATA, READONLY # 定義了RESET區域為READONLY即儲存在Flash。
EXPORT __Vectors # 中斷向量表入口地址,EXPORT 是指該變數可以被匯出,外部可以使用
EXPORT __Vectors_End # 中斷向量表的結束地址
EXPORT __Vectors_Size # 中斷向量表的大小
下面開始建立中斷向量表。
中斷向量表類似一個全是函數指標的陣列,每個函數指標代表對應中斷號的中斷處理程式入口。
向量表的起點是棧頂。DCD是定義一個word(4位元組)的空間。
__Vectors DCD __initial_sp ; Top of Stack
DCD Reset_Handler ; Reset Handler
DCD NMI_Handler ; NMI Handler
DCD HardFault_Handler ; Hard Fault Handler
DCD MemManage_Handler ; MPU Fault Handler
DCD BusFault_Handler ; Bus Fault Handler
DCD UsageFault_Handler ; Usage Fault Handler
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD SVC_Handler ; SVCall Handler
DCD DebugMon_Handler ; Debug Monitor Handler
DCD 0 ; Reserved
DCD PendSV_Handler ; PendSV Handler
DCD SysTick_Handler ; SysTick Handler
//省略中斷向量表
__Vectors_End
__Vectors_Size EQU __Vectors_End - __Vectors # 相減計算中斷向量表的size
AREA |.text|, CODE, READONLY # 定義了一個唯讀的名為 .txt的程式碼段
; Reset handler
Reset_Handler PROC # PROC 組合程式開始,ENDP組合程式結束
EXPORT Reset_Handler [WEAK] # WEAK說明此函數可以被使用者重寫
IMPORT __main # 從外部檔案import一個函數
IMPORT SystemInit
LDR R0, =SystemInit # load SystemInit 函數地址,做系統時鐘初始化
BLX R0 # 跳轉到 SystemInit 函數執行
LDR R0, =__main # load _main
BX R0 # 跳轉到_main執行,此_main非彼main
ENDP
其他一些異常中斷函數,簡單起見直接使用死迴圈代替(在可靠性系統中使用者應該檢測並做特殊處理)。
; Dummy Exception Handlers (infinite loops which can be modified)
NMI_Handler PROC
EXPORT NMI_Handler [WEAK]
B .
ENDP
外設中的一些中斷函數:
Default_Handler PROC
EXPORT WWDG_IRQHandler [WEAK]
EXPORT PVD_IRQHandler [WEAK]
EXPORT TAMPER_IRQHandler [WEAK]
// 省略
DMA2_Channel3_IRQHandler
DMA2_Channel4_5_IRQHandler
B .
ENDP #先都用死迴圈代替,標記了WEAK使用者可以重寫,在外設驅動檔案中已經包含了這些中斷服務程式。
ALIGN
;------------------------------------------------------------------
; User Stack and Heap initialization
;------------------------------------------------------------------
IF :DEF:__MICROLIB # 如果啟用了MDK的微庫microLib
EXPORT __initial_sp # 匯出這三個變數給外部使用
EXPORT __heap_base
EXPORT __heap_limit
ELSE # 如果沒有啟動微庫
IMPORT __use_two_region_memory # 匯入__use_two_region_memory 標號
EXPORT __user_initial_stackheap # 匯出__user_initial_stackheap 方法
__user_initial_stackheap # 標號,表示堆疊初始化程式入口
LDR R0, = Heap_Mem # 堆空間起點(向上增長)
LDR R1, =(Stack_Mem + Stack_Size) # 棧尾部(向下增長)
LDR R2, = (Heap_Mem + Heap_Size) # 堆大小
LDR R3, = Stack_Mem # 棧空間起點
BX LR
ALIGN
ENDIF
END
在startup.s檔案中,跳轉到_main,這個_main並不是c的main函數,而是編譯器內建的一個c庫函數,內部執行了三個步驟:初始化rw段,初始化zi段,呼叫另一個c庫函數__rt_entry()。
__rt_entry()該函數先初始化堆疊和庫函數,然後即呼叫主函數main(),從而進入使用者程式。可以看出主函數main()若退出,則在__rt_entry()最後會再呼叫exit()函數進行退出操作。
什麼是__rt_entry?標準庫或ARM檔案有如下描述。
詳情見:https://developer.arm.com/documentation/dui0475/m/the-c-and-c---library-functions-reference/--rt-entry
所以main函數既不是c程式第一個執行的函數,也不是c程式最後一個執行的函數。在main啟動前,標準庫已經做了很多工作,當跳轉mian時,堆疊已經完成了初始化、C執行時環境已經就緒。
__rt_entry
The symbol __rt_entry is the starting point for a program using the ARM C library.
Control passes to __rt_entry after all scatter-loaded regions have been relocated to their execution addresses.
Usage
1. The default implementation of __rt_entry:
2. Sets up the heap and stack.
3. Initializes the C library by calling __rt_lib_init.
4. Calls main().
5. Shuts down the C library, by calling __rt_lib_shutdown.
6. Exits.
__rt_entry must end with a call to one of the following functions:
exit()
Calls atexit()-registered functions and shuts down the library.
__rt_exit()
Shuts down the library but does not call atexit() functions.
_sys_exit()
Exits directly to the execution environment. It does not shut down the library and does not call atexit() functions.
startup.s檔案中,DCD定義了76箇中斷服務函數入口,76*4=304=0x130。所以在組合檔案中,Flash地址0x08000000起點是DEC中斷函數入口,0x08000130 位置是程式碼起點。如果進行程式碼偵錯跟蹤,可以發現這段組合程式碼實現的是堆和棧的初始化。
啟用微庫時的初始化過程,其中__scatterload 即對堆疊進行初始化,對比不啟用微庫的組合程式,指令條目數已大幅縮減:
0x080007D8 2000 MOVS r0,#0x00
0x080007DA E001 B 0x080007E0
0x080007DC C101 STM r1!,{r0}
0x080007DE 1F12 SUBS r2,r2,#4
0x080007E0 2A00 CMP r2,#0x00
0x080007E2 D1FB BNE 0x080007DC
0x0800012C 015F DCW 0x015F
0x0800012E 0800 DCW 0x0800
__main:
0x08000130 F8DFD00C LDR.W sp,[pc,#12] ; @0x08000140
_main_scatterload:
0x08000134 F000F82E BL.W __scatterload (0x08000194)
__main_after_scatterload:
0x08000138 4800 LDR r0,[pc,#0] ; @0x0800013C
0x0800013A 4700 BX r0
0x0800013C 0969 DCW 0x0969
0x0800013E 0800 DCW 0x0800
__rt_final_cpp:
0x08000140 0428 DCW 0x0428
0x08000142 2000 DCW 0x2000
151: LDR R0, =SystemInit
0x08000144 4806 LDR r0,[pc,#24] ; @0x08000160
152: BLX R0
0x08000146 4780 BLX r0
153: LDR R0, =__main
0x08000148 4806 LDR r0,[pc,#24] ; @0x08000164
154: BX R0
155: ENDP
156:
157: ; Dummy Exception Handlers (infinite loops which can be modified)
158:
159: NMI_Handler PROC
160: EXPORT NMI_Handler [WEAK]
0x0800014A 4700 BX r0
161: B .
162: ENDP
不啟用微庫時的初始化過程,啟動程式碼大大增加。
0x08000130 F000F802 BL.W __scatterload (0x08000138)
0x08000134 F000F847 BL.W __rt_entry (0x080001C6)
0x08000138 A00A ADR r0,{pc}+4 ; @0x08000164
0x0800013A E8900C00 LDM r0,{r10-r11}
0x0800013E 4482 ADD r10,r10,r0
0x08000140 4483 ADD r11,r11,r0
0x08000142 F1AA0701 SUB r7,r10,#0x01
0x08000146 45DA CMP r10,r11
0x08000148 D101 BNE 0x0800014E
0x0800014A F000F83C BL.W __rt_entry (0x080001C6)
0x0800014E F2AF0E09 ADR.W lr,{pc}-0x07 ; @0x08000147
0x08000152 E8BA000F LDM r10!,{r0-r3}
0x08000156 F0130F01 TST r3,#0x01
0x0800015A BF18 IT NE
0x0800015C 1AFB SUBNE r3,r7,r3
0x0800015E F0430301 ORR r3,r3,#0x01
0x08000162 4718 BX r3
0x08000164 1244 DCW 0x1244
0x08000166 0000 DCW 0x0000
0x08000168 1264 DCW 0x1264
0x0800016A 0000 DCW 0x0000
0x0800016C 3A10 SUBS r2,r2,#0x10
0x0800016E BF24 ITT CS
0x08000170 C878 LDMCS r0!,{r3-r6}
0x08000172 C178 STMCS r1!,{r3-r6}
0x08000174 D8FA BHI __scatterload_copy (0x0800016C)
0x08000176 0752 LSLS r2,r2,#29
0x08000178 BF24 ITT CS
0x0800017A C830 LDMCS r0!,{r4-r5}
0x0800017C C130 STMCS r1!,{r4-r5}
0x0800017E BF44 ITT MI
0x08000180 6804 LDRMI r4,[r0,#0x00]
0x08000182 600C STRMI r4,[r1,#0x00]
0x08000184 4770 BX lr
0x08000186 0000 MOVS r0,r0
0x08000188 2300 MOVS r3,#0x00
0x0800018A 2400 MOVS r4,#0x00
0x0800018C 2500 MOVS r5,#0x00
0x0800018E 2600 MOVS r6,#0x00
0x08000190 3A10 SUBS r2,r2,#0x10
0x08000192 BF28 IT CS
0x08000194 C178 STMCS r1!,{r3-r6}
0x08000196 D8FB BHI 0x08000190
0x08000198 0752 LSLS r2,r2,#29
0x0800019A BF28 IT CS
0x0800019C C130 STMCS r1!,{r4-r5}
0x0800019E BF48 IT MI
0x080001A0 600B STRMI r3,[r1,#0x00]
0x080001A2 4770 BX lr
_printf_d:
0x080001A4 2964 CMP r1,#0x64
0x080001A6 F000807D BEQ.W _printf_int_dec (0x080002A4)
_printf_percent_end:
0x080001AA 2000 MOVS r0,#0x00
0x080001AC 4770 BX lr
__rt_lib_init:
0x080001AE B51F PUSH {r0-r4,lr}
__rt_lib_init_fp_1:
0x080001B0 E89D0003 LDM sp,{r0-r1}
0x080001B4 F000FB6C BL.W _init_alloc (0x08000890)
__rt_lib_init_atexit_1:
0x080001B8 F000F93A BL.W _initio (0x08000430)
__rt_lib_init_alloca_1:
0x080001BC BD1F POP {r0-r4,pc}
__rt_lib_shutdown:
0x080001BE B510 PUSH {r4,lr}
__rt_lib_shutdown_stdio_2:
0x080001C0 F000F99F BL.W _terminateio (0x08000502)
__rt_lib_shutdown_fp_trap_1:
0x080001C4 BD10 POP {r4,pc}
__rt_entry:
0x080001C6 F000FA02 BL.W __user_setup_stackheap (0x080005CE)
0x080001CA 4611 MOV r1,r2
__rt_entry_li:
0x080001CC F7FFFFEF BL.W __rt_lib_init (0x080001AE)
__rt_entry_main:
0x080001D0 F001F89A BL.W main (0x08001308)
0x080001D4 F000FB06 BL.W exit (0x080007E4)
__rt_exit:
0x080001D8 B403 PUSH {r0-r1}
__rt_exit_ls:
0x080001DA F7FFFFF0 BL.W __rt_lib_shutdown (0x080001BE)
__rt_exit_exit:
0x080001DE BC03 POP {r0-r1}
0x080001E0 F000FCE8 BL.W _sys_exit (0x08000BB4)
151: LDR R0, =SystemInit
0x080001E4 4809 LDR r0,[pc,#36] ; @0x0800020C
152: BLX R0
0x080001E6 4780 BLX r0
153: LDR R0, =__main
0x080001E8 4809 LDR r0,[pc,#36] ; @0x08000210
154: BX R0
155: ENDP
尊重原創技術文章,轉載請註明:https://www.cnblogs.com/pingwen/p/17320181.html