Keil编译程序的内存分布

RT-Thread 程序内存分布

一般 MCU 包含的存储空间有:片内 Flash 与片内 RAM,RAM 相当于内存,Flash 相当于硬盘。编译器会将一个程序分类为好几个部分,分别存储在 MCU 不同的存储区。

Keil 工程在编译完之后,会有相应的程序所占用的空间提示信息,如下所示:

linking...
Program Size: Code=47364 RO-data=5348 RW-data=608 ZI-data=2112  
FromELF: creating hex file...
After Build - User command #1: fromelf --bin .\build\rtthread-stm32.axf --output rtthread.bin
".\build\rtthread-stm32.axf" - 0 Error(s), 1 Warning(s).
Build Time Elapsed:  00:01:15

上面提到的 Program Size 包含以下几个部分:

1)Code:代码段,存放程序的代码部分;

2)RO-data:只读数据段,存放程序中定义的常量;

3)RW-data:读写数据段,存放初始化为非 0 值的全局变量;

4)ZI-data:0 数据段,存放未初始化的全局变量及初始化为 0 的变量;

编译完工程会生成一个. map 的文件,该文件说明了各个函数占用的大小和地址,在文件的最后几行也说明了上面几个字段的关系:

      Code (inc. data)   RO Data    RW Data    ZI Data      Debug   

     47364       6182       5348        608       2112     708864   Grand Totals
     47364       6182       5348        108       2112     708864   ELF Image Totals (compressed)
     47364       6182       5348        108          0          0   ROM Totals

==============================================================================

    Total RO  Size (Code + RO Data)                52712 (  51.48kB)
    Total RW  Size (RW Data + ZI Data)              2720 (   2.66kB)
    Total ROM Size (Code + RO Data + RW Data)      52820 (  51.58kB)

1)RO Size 包含了 Code 及 RO-data,表示程序占用 Flash 空间的大小;

2)RW Size 包含了 RW-data 及 ZI-data,表示运行时占用的 RAM 的大小;

3)ROM Size 包含了 Code、RO Data 以及 RW Data,表示烧写程序所占用的 Flash 空间的大小;

程序运行之前,需要有文件实体被烧录到 STM32 的 Flash 中,一般是 bin 或者 hex 文件,该被烧录文件称为可执行映像文件。如下图所示,是可执行映像文件烧录到 STM32 后的内存分布,它包含 RO 段和 RW 段两个部分:其中 RO 段中保存了 Code、RO-data 的数据,RW 段保存了 RW-data 的数据,由于 ZI-data 都是 0,所以未包含在映像文件中。

STM32 在上电启动之后默认从 Flash 启动,启动之后会将 RW 段中的 RW-data(初始化的全局变量)搬运到 RAM 中,但不会搬运 RO 段,即 CPU 的执行代码从 Flash 中读取,另外根据编译器给出的 ZI 地址和大小分配出 ZI 段,并将这块 RAM 区域清零。

RT-Thread 内存分布

其中动态内存堆为未使用的 RAM 空间,应用程序申请和释放的内存块都来自该空间。

如下面的例子:

rt_uint8_t* msg_ptr;
msg_ptr = (rt_uint8_t*) rt_malloc (128);
rt_memset(msg_ptr, 0, 128);

代码中的 msg_ptr 指针指向的 128 字节内存空间位于动态内存堆空间中。

而一些全局变量则是存放于 RW 段和 ZI 段中,RW 段存放的是具有初始值的全局变量(而常量形式的全局变量则放置在 RO 段中,是只读属性的),ZI 段存放的系统未初始化的全局变量,如下面的例子:

#include <rtthread.h>

const static rt_uint32_t sensor_enable = 0x000000FE;
rt_uint32_t sensor_value;
rt_bool_t sensor_inited = RT_FALSE;

void sensor_init()
{
     /* ... */
}

sensor_value 存放在 ZI 段中,系统启动后会自动初始化成零(由用户程序或编译器提供的一些库函数初始化成零)。
sensor_inited 变量则存放在 RW 段中
sensor_enable 存放在 RO 段中。

推荐阅读更多精彩内容