天天看點

MDK __main過程分析

今天分析了一下__main的流程,和大家分享一下

MDK __main過程分析

在進入__main之間打下斷點, 目前指令“LDR r0 , [pc, #24]“  将PC+24=0x080001E0位址處的資料加載到 r0 中,因為 CM4 内部

使用了指令流水線,讀 PC 時傳回的值是目前指令的位址+4。是以目前指令後,R0等于0x080001E0位址處的資料,如下圖所示:R0=0x080001AD。

MDK __main過程分析

然後運作0x080001C6處的指令 “BX R0”,CM3 中的指令至少是半字對齊的,是以 PC 的 LSB 總是讀回 0。然而, 在分支時,無論是直接寫 PC 的值還是使用分支指令,都必須保證加載到 PC 的數值是奇數(即 LSB=1),用以表明這是在Thumb 狀态下執行。倘若寫了 0,則視為企圖轉入 ARM 模式,CM3 将産生一個 fault 異常。是以目前指令後,PC會跳轉到0x080001AC處的位址。如下圖所示

MDK __main過程分析

然後運作”BL.W __scatterload“ 跳轉到0x080001e4位址的__scatterload函數中去。

MDK __main過程分析

接着向下運作,由于剛開始R4 = 0X08000CD4 R5=0X08000D04。每次循環R4+0X10,是以__scatterload中需要循環3次。

LDM R4,{R0-R2}  從R4指向的位址取3個4位元組的資料,儲存到R0,R1,R2中

MDK __main過程分析

第一次循環:給給定初值的全局變量賦初值。

然後跳轉到R3=0X08000B5D 指向的位址中,通過檢視工程生成的.map檔案可以得知R3指向的位址是__scatterload_copy 函數,形參是R0,R1,R2  

__scatterload_copy                       0x08000b5d   Thumb Code    14  handlers.o(i.__scatterload_copy)

MDK __main過程分析

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)

MDK __main過程分析

最後通過"BX LR"跳出__scatterload_copy函數,如下面2張圖所示。

MDK __main過程分析
MDK __main過程分析

第二次循環:清棧空間

第二次循環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

MDK __main過程分析
MDK __main過程分析

通過函數名稱可以看出目前函數是清零初始化函數

MOVS R0, #00将R0=0

然後STM R1!,{R0} 将0指派給R1所指向的記憶體空間,就是0x20000000,然後R1+4移向下一個位址,R2 - 4循環此處減4

如此循環下去,直到R2減為0。就是将起始位址0x20000000,長度為0x0400的記憶體空間清零。

最後通過BX LR傳回到__scatterload中

MDK __main過程分析
MDK __main過程分析

第三次循環:給未賦初值的全局變量清零。

MDK __main過程分析

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)

MDK __main過程分析

上面已經分析了,真理就不再重複了。

退出後傳回到__scatterload中,由于達到了退出條件,則退出__scatterload函數到__main_after_scatterload中

MDK __main過程分析
MDK __main過程分析

在__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的分析過程。

繼續閱讀