MDK __main过程分析
今天分析了一下__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的分析过程。