keil5编译后生成 Program Size: Code RO-data RW-data ZI-data是什么

 在keil5下全编译了这么多次代码,每次编译完了后都有这么一行提示,闲来没事还是搜索学习了一下。

Program Size: Code=49560 RO-data=7032 RW-data=308 ZI-data=1100180 (数据当然是不一样的哈) 

通过查阅keil5的帮助文档(ARM Development Tools),看到样的的一个数据,如图

 

Code (inc. data)   RO Data   RW Data    ZI Data      Debug
3712        1580        19        44      10200       7436   Object Totals
0              0        16         0          0          0   (incl. Generated)
0              0         3         0          0          0   (incl. Padding)
21376        648       805         4        300      10216   Library Totals 
0              0         6         0          0          0   (incl. Padding)
===============================================================================
Code (inc. data)   RO Data    RW Data    ZI Data      Debug
25088       2228       824         48      10500      17652   Grand Totals
25088       2228       824         48      10500      17652   ELF Image Totals
25088       2228       824         48          0          0   ROM Totals
===============================================================================
Total RO  Size (Code + RO Data)             25912 (  25.30kB)
Total RW  Size (RW Data + ZI Data)          10548 (  10.30kB)
Total ROM Size (Code + RO Data + RW Data)   25960 (  25.35kB)

 (1)Code (inc. data): 网上多大说的是程序代码所占的字节数。但是这种说法并不完全,在官方文档中这么
    一句话:Shows how many bytes are occupied by code. In this image, there are 3712 bytes of code. 
    This includes 1580 bytes of inline data (inc. data), for example, literal pools, and short strings.

    (意思就是说显示代码占用了多少字节。 在上面的这个表中,有3712个字节的代码。 这包括1580字节的内联
    数据,例如文字池短字符串)

    Code中不仅仅包含了代码的大小。其中还包括了inline data(内联数据),比如literal pools(文字池)
    和short strings(短字符串)

 (2)RO-data: 表示程序中的只读常量数据。比如const类型的数据 (除inline data之外的只读数据)。

 (3)RW-data: 表示可读写变量的大小,也就是说是程序中已经初始化的变量大小。

 (4)ZI-data: 表示程序中未初始化的变量大小。就是程序中已经定义但是初始化值为0或者
   是没有初始化赋值的变量(编译器会默认把没有赋值的变量自动赋值为0)。


  下面对几个数值的关系进行说明

  ROM size:  也就是下载到单片机FLASH中的数据为  Code +RO-data +RW-data 和的大小。
  为什么不把ZI-data 也下载进去呢? 其实是没有必要的,这是浪费空间,只要程序一上电运
  行就会把ZI-data 自动清0。

  RAM size: 程序运行时所需要的大小空间为 RW-data+ ZI-data

 

  2019.10.26补充:

最近在学习RT_Thread中,看到里面的文档对这部分分析得很细致,分享一下https://www.rt-thread.org/document/site/programming-manual/basic/basic/

我也搬运一下,记录学习记录。

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

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

linking...
Program Size: Code=48008 RO-data=5660 RW-data=604 ZI-data=2124
After Build - User command \#1: fromelf --bin.\\build\\rtthread-stm32.axf--output rtthread.bin
".\\build\\rtthread-stm32.axf" - 0 Error(s), 0 Warning(s).
Build Time Elapsed: 00:00:07

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

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

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

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

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

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

Total RO Size (Code + RO Data) 53668 ( 52.41kB)
Total RW Size (RW Data + ZI Data) 2728 ( 2.66kB)
Total ROM Size (Code + RO Data + RW Data) 53780 ( 52.52kB)

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 文件,该被烧录文件称为可执行映像文件。如图 3-3 中左图所示,是可执行映像文件烧录到 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 区域清零。

其中动态内存堆为未使用的 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 段中。

 

<think>好的,用户想了解程序大小的组成,包括代码段、只读数据段、读写数据段和零初始化数据段的具体数值,特别是在嵌入式系统的内存布局中。首先,我需要回忆这些段的具体定义和作用。 代码段(Code Segment)通常存储可执行指令,也就是程序的机器代码。这部分是只读的,防止程序被意外修改。只读数据段(RO-Data)包含常量,比如字符串常量和全局常量,这些数据在程序运行期间不会改变。读写数据段(RW-Data)存储已初始化的全局变量和静态变量,这些变量在程序启动时被加载到内存,并且可以被修改。零初始化数据段(ZI-Data)则是未初始化的全局变量和静态变量,它们在程序启动时会被系统初始化为零,实际不占用程序镜像的空间,但运行时需要分配内存。 接下来,我需要考虑嵌入式系统的内存布局。通常,程序镜像包括CodeRO-DataRW-Data,而ZI-Data在运行时由启动代码初始化。内存分为Flash(存储CodeRO-Data)和RAM(存储RW-DataZI-Data)。例如,在Keil MDK中,编译后的输出会显示这些段的大小,帮助开发者优化内存使用。 用户可能想知道如何获取这些数值,可能需要提到编译工具链提供的功能,比如ARM的map文件或者GCC的size命令。此外,优化这些段的策略也很重要,比如使用const关键字减少RW-Data,或者合并字符串常量节省RO-Data空间。 还需要考虑用户可能的后续问题,比如如何减少各段的大小,或者具体的工具使用方法。要确保回答结构清晰,分点说明每个段,并给出示例数值和内存布局图,帮助用户直观理解。最后,生成的相关问题应覆盖内存优化、工具使用、具体案例和ZI-Data的处理方法,这样用户可以有进一步的学习方向。</think>在嵌入式系统中,程序内存布局通常由以下几个关键段组成,其大小组成可通过编译工具链(如ARM GCC、Keil MDK等)的输出报告获取: 1. **代码段(Code)** - 存储可执行机器指令 - 包含函数体、跳转指令等 - 示例数值:$$ \text{Code Size} = 32\text{KB} $$ 2. **只读数据段(RO-Data)** - 存储常量数据(如字符串常量、const全局变量) - 示例数值:$$ \text{RO-Data} = 8\text{KB} $$[^1] 3. **读写数据段(RW-Data)** - 存储已初始化的全局变量和静态变量 - 需要同时占用Flash(存储初始值)和RAM(运行时存储) - 示例数值:$$ \text{RW-Data} = 4\text{KB} $$ 4. **零初始化数据段(ZI-Data)** - 存储未初始化的全局变量和静态变量 - 仅占用RAM空间,在启动时由启动代码初始化为0 - 示例数值:$$ \text{ZI-Data} = 12\text{KB} $$ **内存布局示意图**: ``` +---------------------+ | Flash | +---------------------+ | Code | <- 执行时加载到指令缓存 | RO-Data | <- 只读数据区 | RW-Data初始值 | <- 启动时复制到RAM +---------------------+ | RAM | +---------------------+ | RW-Data运行时副本 | <- 可修改的全局变量 | ZI-Data | <- 启动时清零的变量 | 堆(Heap) | | 栈(Stack) | +---------------------+ ``` **优化策略**: - 使用`const`修饰符将数据放入RO-Data- 避免全局变量初始化冗余(如`int a = 0;`应简化为`int a;`) - 通过编译选项控制内存对齐方式(如`-falign-functions=4`)
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值