今天分析了一下__main的流程,和大家分享一下
在進入__main之間打下斷點, 目前指令“LDR r0 , [pc, #24]“ 将PC+24=0x080001E0位址處的資料加載到 r0 中,因為 CM4 内部
使用了指令流水線,讀 PC 時傳回的值是目前指令的位址+4。是以目前指令後,R0等于0x080001E0位址處的資料,如下圖所示:R0=0x080001AD。
然後運作0x080001C6處的指令 “BX R0”,CM3 中的指令至少是半字對齊的,是以 PC 的 LSB 總是讀回 0。然而, 在分支時,無論是直接寫 PC 的值還是使用分支指令,都必須保證加載到 PC 的數值是奇數(即 LSB=1),用以表明這是在Thumb 狀态下執行。倘若寫了 0,則視為企圖轉入 ARM 模式,CM3 将産生一個 fault 異常。是以目前指令後,PC會跳轉到0x080001AC處的位址。如下圖所示
然後運作”BL.W __scatterload“ 跳轉到0x080001e4位址的__scatterload函數中去。
接着向下運作,由于剛開始R4 = 0X08000CD4 R5=0X08000D04。每次循環R4+0X10,是以__scatterload中需要循環3次。
LDM R4,{R0-R2} 從R4指向的位址取3個4位元組的資料,儲存到R0,R1,R2中
第一次循環:給給定初值的全局變量賦初值。
然後跳轉到R3=0X08000B5D 指向的位址中,通過檢視工程生成的.map檔案可以得知R3指向的位址是__scatterload_copy 函數,形參是R0,R1,R2
__scatterload_copy 0x08000b5d Thumb Code 14 handlers.o(i.__scatterload_copy)
LDM R0!,{R3} 從R0指向的位址中的資料加載R3中,然後将R0+4 。如下圖所示R0的值比上圖加4了
STM R1!,{R3} 将R3中的資料儲存到R1指向的位址中,然後将R1+4。如下圖所示R1的值比上圖加4了
這樣循環9次=0x24/4。将記憶體中0XD0000000位址開始的,長度為0x24=36位元組的區域的有初值的全局變量給指派了。
map檔案中
SDRAM_Register 0xd0000004 Data 4 sdram.o(.data)
uwWriteReadStatus 0xd0000008 Data 4 sdram.o(.data)
uwIndex 0xd000000c Data 4 sdram.o(.data)
g_u8flag 0xd0000010 Data 1 sdram.o(.data)
最後通過"BX LR"跳出__scatterload_copy函數,如下面2張圖所示。
第二次循環:清棧空間
第二次循環R0=0X08000D04,R1=0X20000000,R2=0X00000400這是棧空間的位址,然後跳轉到R3=0x08000B6D位址運作。就是__scatterload_zeroinit函數
map檔案可以看到棧空間
Base Addr Size Type Attr Idx E Section Name Object
0x20000000 0x00000400 Zero RW 339 STACK startup_stm32f427x.o
通過函數名稱可以看出目前函數是清零初始化函數
MOVS R0, #00将R0=0
然後STM R1!,{R0} 将0指派給R1所指向的記憶體空間,就是0x20000000,然後R1+4移向下一個位址,R2 - 4循環此處減4
如此循環下去,直到R2減為0。就是将起始位址0x20000000,長度為0x0400的記憶體空間清零。
最後通過BX LR傳回到__scatterload中
第三次循環:給未賦初值的全局變量清零。
R0=0X08000D28,R1=0XD0000024,R2=0X00000210。然後跳轉到R3=0x08000B6D位址運作。就是__scatterload_zeroinit函數。
通過檢視map檔案,可知起始位址為0XD0000024,長度為0x210的記憶體針對那些變量
RCC_Clocks 0xd0000024 Data 16 main.o(.bss)
aTxBuffer 0xd0000034 Data 256 sdram.o(.bss)
aRxBuffer 0xd0000134 Data 256 sdram.o(.bss)
上面已經分析了,真理就不再重複了。
退出後傳回到__scatterload中,由于達到了退出條件,則退出__scatterload函數到__main_after_scatterload中
在__main_after_scatterload中跳轉到main中
LDR R0,[PC,#0] 則R0=0X080001B8位址處的資料,即R0=0X0800087D
BX R0 則跳轉到0X0800087D指定的指令。
通過檢視map檔案得知,這個指定對應的就是main函數
main 0x08000b7d Thumb Code 96 main.o(i.main)
以上就是__main的分析過程。