MDK 编译文件大小说明(Program Size)(转)

本文详细解释了ARM程序中的RO、RW和ZI三个段的区别及其作用。RO段包含指令和常量,RW段包含已初始化的变量,而ZI段包含未初始化的变量。文章通过多个示例对比了不同类型的变量如何影响程序的编译结果。

ARM编译中的RO、RW和ZI DATA区段2008-12-17 14:58

ARM程序(指在ARM系统中正在执行的程序,而非保存在ROM中的bin文件)的组成

一个ARM程序包含3部分:RO段,RW段和ZI段

RO是程序中的指令和常量

RW是程序中的已初始化变量

ZI是程序中的未初始化的变量

由以上3点说明可以理解为:RO就是readonly,RW就是read/write,ZI就是zero

ARM映像文件的组成所谓ARM映像文件就是指烧录到ROM中的bin文件,也成为image文件。以下用Image文件来称呼它。Image文件包含了RO和RW数据。之所以Image文件不包含ZI数据,是因为ZI数据都是0,没必要包含,只要程序运行之前将ZI数据所在的区域一律清零即可。包含进去反而浪费存储空间。

Q:为什么Image中必须包含RO和RW?A:因为RO中的指令和常量以及RW中初始化过的变量是不能像ZI那样“无中生有”的。ARM程序的执行过程从以上两点可以知道,烧录到ROM中的image文件与实际运行时的ARM程序之间并不是完全一样的。因此就有必要了解ARM程序是如何从ROM中的image到达实际运行状态的。实际上,RO中的指令至少应该有这样的功能:1. 将RW从ROM中搬到RAM中,因为RW是变量,变量不能存在ROM中。2. 将ZI所在的RAM区域全部清零,因为ZI区域并不在Image中,所以需要程序根据编译器给出的ZI地址及大小来将相应得RAM区域清零。ZI中也是变量,同理:变量不能存在ROM中在程序运行的最初阶段,RO中的指令完成了这两项工作后C程序才能正常访问变量。否则只能运行不含变量的代码。

说了上面的可能还是有些迷糊,RO,RW和ZI到底是什么,下面我将给出几个例子,最直观的来说明RO,RW,ZI在C中是什么意思。

1; RO看下面两段程序,他们之间差了一条语句,这条语句就是声明一个字符常量。因此按照我们之前说的,他们之间应该只会在RO数据中相差一个字节(字符常量为1字节)。

Prog1:#include void main(void){;}Prog2:#include const char a = 5;void main(void){;}

Prog1编译出来后的信息如下:================================================================================

Code RO Data RW Data ZI Data Debug948 60 0 96 0 Grand Totals================================================================================

Total RO Size(Code + RO Data) 1008 ( 0.98kB)Total RW Size(RW Data + ZI Data) 96 ( 0.09kB)Total ROM Size(Code + RO Data + RW Data) 1008 ( 0.98kB)

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

Prog2编译出来后的信息如下:================================================================================

Code RO Data RW Data ZI Data Debug948 61 0 96 0 Grand Totals================================================================================

Total RO Size(Code + RO Data) 1009 ( 0.99kB)Total RW Size(RW Data + ZI Data) 96 ( 0.09kB)Total ROM Size(Code + RO Data + RW Data) 1009 ( 0.99kB)

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

以上两个程序编译出来后的信息可以看出:Prog1和Prog2的RO包含了Code和RO Data两类数据。他们的唯一区别就是Prog2的RO Data比Prog1多了1个字节。这正和之前的推测一致。如果增加的是一条指令而不是一个常量,则结果应该是Code数据大小有差别。

2; RW同样再看两个程序,他们之间只相差一个“已初始化的变量”,按照之前所讲的,已初始化的变量应该是算在RW中的,所以两个程序之间应该是RW大小有区别。

Prog3:#include void main(void){;}Prog4:#include char a = 5;void main(void){;}Prog3编译出来后的信息如下:================================================================================

Code RO Data RW Data ZI Data Debug948 60 0 96 0 Grand Totals================================================================================

Total RO Size(Code + RO Data) 1008 ( 0.98kB)Total RW Size(RW Data + ZI Data) 96 ( 0.09kB)Total ROM Size(Code + RO Data + RW Data) 1008 ( 0.98kB)================================================================================

Prog4编译出来后的信息如下:================================================================================

Code RO Data RW Data ZI Data Debug948 60 1 96 0 Grand Totals================================================================================

Total RO Size(Code + RO Data) 1008 ( 0.98kB)Total RW Size(RW Data + ZI Data) 97 ( 0.09kB)Total ROM Size(Code + RO Data + RW Data) 1009 ( 0.99kB)================================================================================

可以看出Prog3和Prog4之间确实只有RW Data之间相差了1个字节,这个字节正是被初始化过的一个字符型变量“a”所引起的。

3; ZI再看两个程序,他们之间的差别是一个未初始化的变量“a”,从之前的了解中,应该可以推测,这两个程序之间应该只有ZI大小有差别。

Prog3:#include void main(void){;}

Prog4:#include char a;void main(void){;}

Prog3编译出来后的信息如下:================================================================================

Code RO Data RW Data ZI Data Debug948 60 0 96 0 Grand Totals================================================================================

Total RO Size(Code + RO Data) 1008 ( 0.98kB)Total RW Size(RW Data + ZI Data) 96 ( 0.09kB)Total ROM Size(Code + RO Data + RW Data) 1008 ( 0.98kB)================================================================================

Prog4编译出来后的信息如下:================================================================================

Code RO Data RW Data ZI Data Debug948 60 0 97 0 Grand Totals================================================================================

Total RO Size(Code + RO Data) 1008 ( 0.98kB)Total RW Size(RW Data + ZI Data) 97 ( 0.09kB)Total ROM Size(Code + RO Data + RW Data) 1008 ( 0.98kB)================================================================================

编译的结果完全符合推测,只有ZI数据相差了1个字节。这个字节正是未初始化的一个字符型变量“a”所引起的。注意:如果一个变量被初始化为0,则该变量的处理方法与未初始化华变量一样放在ZI区域。即:ARM C程序中,所有的未初始化变量都会被自动初始化为0。

总结:1; C中的指令以及常量被编译后是RO类型数据。2; C中的未被初始化或初始化为0的变量编译后是ZI类型数据。3; C中的已被初始化成非0值的变量编译后市RW类型数据。

附:程序的编译命令(假定C程序名为tst.c):armcc -c -o tst.o tst.carmlink -noremove -elf -nodebug -info totals -info sizes -map -list aa.map -o tst.elf tst.o编译后的信息就在aa.map文件中。

ROM主要指:NAND Flash,Nor Flash

RAM主要指:PSRAM,SDRAM,SRAM,DDRAM

简单的说就是在烧写完的时候是:FLASH中:Code+RO Data+RW Data,运行的时候:RAM: RW Data + ZI Data,当然还要有堆栈的空间。

 

原文地址:

http://blog.sina.com.cn/s/blog_6ec4dce00100tug3.html

<think>根据引用[1],C语言编译后的汇编代码是编译器按照规则和优化策略生成的,而纯汇编代码可以由程序员自由组织逻辑。在ARM单片机中,程序编译后的大小是开发者关心的一个指标,因为它直接影响单片机的存储资源占用情况。对于ARM单片机(如使用Cortex-M系列的MCU),编译后程序大小的组成通常由以下几部分组成:1.代码段(TextSegment):存放程序执行代码的区域,包括ARM指令或Thumb指令。2.数据段(DataSegment):存放已初始化的全局变量和静态变量。3.未初始化数据段(BSSSegment):存放未初始化的全局变量和静态变量,程序加载时会被初始化为0。4.只读数据段(Read-OnlyDataSegment):存放常量字符串等只读数据。编译后显示的程序大小一般会以如下形式显示:-Code:代码段大小-RO-data:只读数据大小(包括字符串常量等)-RW-data:已初始化的可读写全局变量大小(在运行时需要被复制到RAM)-ZI-data:未初始化的全局变量大小(在运行时初始化为0的变量所占用空间)其中:-FLASH占用=Code+RO-Data+RW-Data-RAM占用=RW-Data+ZI-Data解析方法:1.查看编译输出:编译器(如ARMCC、GCC)在编译后会输出程序各部分的大小。例如KeilMDK的输出格式如下:```ProgramSize:Code=xxxxRO-data=xxxxRW-data=xxxxZI-data=xxxx```2.使用map文件分析:map文件中会详细列出每个模块占用的代码空间、数据空间,以及全局变量和静态变量的分配情况,从而可以定位占用较大的模块或变量。在分析程序大小时,可参考以下思路:-优化代码段:减少不必要的功能,使用更高效的算法,使用编译器的优化选项(如-Os优化大小)。-优化常量数据:尽量使用压缩格式存储字符串等常量数据。-减少全局变量:避免过多全局变量,特别是大的数组或结构体。-注意库函数使用:部分库函数(如printf)会占用大量空间,可以考虑使用简化版本。引用[5]提到了PUSH和POP指令的栈操作顺序,虽然与程序大小无直接关系,但涉及到函数调用时的栈操作,也会影响程序运行效率。</think> 根据引用内容及ARM体系结构,编译后程序大小(Program Size)的分析解析如下: ### 程序大小的组成结构 编译后的程序大小主要分为4个核心部分: 1. **Code (代码段)** - 存放所有可执行的ARM指令(如算术操作、分支跳等) - 包含编译后的机器码和函数体 - 固定占用Flash空间 2. **RO-data (只读数据段)** - 存储常量数据(如字符串常量、const全局变量) - 包含中断向量表等只读结构 - 固定占用Flash空间 3. **RW-data (已初始化读写数据段)** - 包含初始化非零值的全局/静态变量(如 `int g_val = 5;`) - Flash中存储初始值,运行时加载到RAM - **占用双重空间**:Flash(初始值)+ RAM(运行值) 4. **ZI-data (零初始化数据段)** - 存储默认零值的全局/静态变量(如 `int g_arr[100];`) - 程序启动时由启动代码初始化为0 - **仅占用RAM空间** ### 空间占用计算公式 - **Flash总占用 = Code + RO-data + RW-data** - **RAM总占用 = RW-data + ZI-data** ### 深度解析方法 1. **编译输出分析**(如Keil MDK): ``` Program Size: Code=10240 // 10KB指令 RO-data=512 // 512B常量 RW-data=256 // 256B初始化变量 ZI-data=4096 // 4KB零初始化变量 ``` → Flash占用:10240+512+256 = 11008 Bytes → RAM占用:256+4096 = 4352 Bytes 2. **Map文件定位**(关键方法): - 检查内存区域分布(如引用[4]的地址分配) - 定位大内存占用的模块: ``` ModuleA.o(Text) 0x800 // 代码段占用2KB ModuleB.o(Data) 0x400 // 数据段占用1KB ``` 3. **优化手段**: - 减少冗余代码:避免大数组拷贝(引用[1]) - 压缩常量数据:合并重复字符串 - 调整内存模型:启用 `-Os` 编译优化 - 变量优化:将大型ZI-data改为动态分配 4. **特殊区域分析**: - **启动代码**:包含栈指针初始化(引用[5]) - **中断向量表**:属于RO-data的核心部分 - **对齐填充**:地址对齐导致的空隙(增加Code大小) ### 案例分析 若发现ZI-data异常增大: 1. 检查全局数组声明:`static char buffer[2048];` 2. 确认是否需要动态分配:改为 `malloc(2048)` 3. 效果:ZI-data减少2KB → RAM节省2KB > **注**:栈空间(Stack)和堆空间(Heap)通常不包含在基础统计中,需单独配置(引用[3]启动流程) --- **
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值