Keil开发的ARM程序main函数之前的汇编分析
——BIN文件中RW段的数据移动
系统平台:
STM32系列STM32F103ZE,512KB内部FLASH,64KB片内存储;
FLASH地址范围0x0800 0000 ~ 0x0808 0000,用于存放代码;
片内存储地址范围0x2000 0000 ~ 0x2001 0000,用于存放数据;
Cortex-M3上电后来到复位中断(已将前4个字节的值存入MSP堆栈指针),转到__main标号,完成RW段的移动、ZI段的初始化,建立堆栈,初始化库函数,然后跳转到main函数,开启C程序之旅,执行流程如图1所示。
图1 main函数之前的汇编程序执行流程图
本文主要讨论RW段的移动,RW段就是程序中赋了初值的变量,它的搬移我看到过两种方式。在BIN文件中,RO段和RW段之间有8个双字的Region$$Table,4个双字一组,分别用于完成RW段的搬移和ZI段的初始化。
(1) __scatterload_copy来完成
此时RW段的内容保存到内存开始的地方,本文中是0x20000000,用这一方式完成后,内存中存放的不是RW数据的内容,而是一个地址。这个地址是在FLASH中,即指向了其在RO段的地址,实际的内容是在RO段中。
(2) 通过__uncompressed1实现
RW是程序中初始化的变量,但是这些变量有可能初值是0,因此为了节省空间,实际在BIN文件中RW段是压缩过的。调用__uncompressed1解压缩RW段的数据内容,并将其保存到内存开始的地方。
图2 BIN文件中压缩RW段内容
图2是BIN文件中RW段的数据内容,影印部分显示,大小是164字节。其中0x0001 C72C前面8个双字的内容是Region$$Table,将其列出如下。
0x0801 C72C BIN文件中RW段的开始地址
0x2000 0000 RW段要存放到RAM中的地址
0x0000 0334 要存放到RAM中的RW段数据大小
0x0800 0184 执行函数__scatterload_copy或者__uncompressed1的地址
上面4个双字完成RW段的搬移。
0x0801 C7D0 BIN文件的末尾,ZI段的开始
0x2000 0334 ZI段放到RAM中的起始位置
0x0000 F4BC ZI段的大小
0x0800 01E0 执行函数__scatterload_zeroinit的地址
这4个双字完成ZI段的初始化。
图3 RW段内容解压缩后在RAM中排布
将BIN文件中RW解压缩以后(这个解压缩从反汇编可以看到,但是没有看明白),实际内容如图3所示,大小变为820个字节,该补0的地方都已经补足了。