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的分析过程。



  • 9
    点赞
  • 47
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值