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

本文详细解析了ARM程序的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 <stdio.h>
void main(void)
{
;
}
Prog2:
#include <stdio.h>
const char a = 5;
void main(void)
{
;
}
Prog1编译出来后的信息如下:
================================================================================
Code RO Data RW Data ZI Data Debug
948 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 Debug
948 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 <stdio.h>
void main(void)
{
;
}
Prog4:
#include <stdio.h>
char a = 5;
void main(void)
{
;
}
Prog3编译出来后的信息如下:
================================================================================
Code RO Data RW Data ZI Data Debug
948 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 Debug
948 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 <stdio.h>
void main(void)
{
;
}
Prog4:
#include <stdio.h>
char a;
void main(void)
{
;
}
Prog3编译出来后的信息如下:
================================================================================
Code RO Data RW Data ZI Data Debug
948 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 Debug
948 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.c
armlink -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,当然还要有堆栈的空间。
<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]启动流程) --- **
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值