MDK Keil编译中CODE-RO-RW-ZI Data -堆栈(全网最全解析)

程序的组成、存储与运行

1、CODE、RO、 RW、 ZI Data 域及堆栈空间

相信大家使用keil做单片机开发的时候,编译成功之后,会出现program size,像我这里就是Program Size: Code=10294 RO-data=8178 RW-data=60 ZI-data=3676 那这些变量的含义都是一些什么呢,他们在程序运行的时候都起什么作用呢?MDK Keil编译中CODE-RO-RW-ZI Data -堆栈(全网最全解析)_第1张图片这里我使用的是muc为STM32F407VET6。这里说明一点这些值的大小都是字节。以字节为单位。

1-1、Code

这个工程所需要的代码域,把工程所有的.c文件.h文件所需要的文件才会编译。同时 这个还与编译的优化等级有关系,编译器选择不同编译器生成的机器指令,这些内容被存储到 ROM 区,ROM就是MCU的flash。掉电不会丢失。
当在option中的c/c++选项之中选择编译优化等级
选择 level-0 时候对应的Program Size如下
MDK Keil编译中CODE-RO-RW-ZI Data -堆栈(全网最全解析)_第2张图片
MDK Keil编译中CODE-RO-RW-ZI Data -堆栈(全网最全解析)_第3张图片选择 level-1 时候对应的Program Size如下

MDK Keil编译中CODE-RO-RW-ZI Data -堆栈(全网最全解析)_第4张图片
MDK Keil编译中CODE-RO-RW-ZI Data -堆栈(全网最全解析)_第5张图片
可以看出来CODE变化比较明显,是因为编译器优化了很多工程所不需要的文件,甚至文件中没有调用的函数都可能会被优化,同时RO、RW、 ZI Data 都有相应的减少。 一般情况下我们选择的优化等级是level-1。

1-2、RO-data

Read Only data,即只读数据域,它指程序中用到的只读数据,这些数据被存储在ROM 区,因而程序不能修改其内容。C 语言中 const 关键字定义的变量就是典型的RO-data。只要是const修饰都纳入,不管是局部还是全局变量

const uint8_t buf[1024] = {1,1,1,1,1,1,1};

MDK Keil编译中CODE-RO-RW-ZI Data -堆栈(全网最全解析)_第6张图片可以看出当程序增加const常量以后,与上张图片对比,生成的代码只增加了8184-8178 = 8 ,可以看出编译器优化了,只编译了赋值的部分,但是如果你在使用的过程中调用,可能这个值会有所增加。

还有一个就是这个定义了7个变量,为什么增加了八字节,定义的数据类型为uint8_t为八位的数据,就是一个字节。同时增加的一个字节可是定义这个变量锁产生的。

1-3、RW-data:

Read Write data,即可读写数据域,它指初始化为“非 0 值”的可读写数据,程序刚运行时,这些数据具有非 0 的初始值,且运行的时候它们会常驻在 RAM 区,因而应用程序可以修改其内容。例如 C 语言中使用定义的全局变量,且定义时赋予“非 0 值”给该变量进行初始化。

uint8_t buf[1024] = {1,1,1,1,1,1,1};

int main(void){
//这里仅代表在主函数中使用buf中的数据
buf[0]=10;
if(buf[0]==10){};
}

这里在main函数之前定义了非零的全局变量,并在main函数中调用了这个变量,则会对rw-data产生影响。如果不调用的话,会因为编译器优化而不会产生。
MDK Keil编译中CODE-RO-RW-ZI Data -堆栈(全网最全解析)_第7张图片可以明显的看出来,RW-data同上图增加的值为1084-60 = 1024字节。

1-4、ZI-data:

Zero Initialie data,即 0 初始化数据,它指初始化为“0 值”的可读写数据域,它与RW-data 的区别是程序刚运行时这些数据初始值全都为 0,均是全局变量,而后续运行过程与 RW-data 的性质一样,它们也常驻在 RAM 区,因而应用程序可以更改其内容。例如 C 语言中使用定义的全局变量,且定义时赋予“0 值”给该变量进行初始化
(若定义该变量时没有赋予初始值,编译器会把它当 ZI-data 来对待,初始化为 0);

uint8_t buf[1024] = {0};
uint8_t buf[1024];
int main(void){
//这里仅代表在主函数中使用buf和buf1中的数据
buf[0]=10;
if(buf[0]==10){};
if(buf1[0]==10){};
}

MDK Keil编译中CODE-RO-RW-ZI Data -堆栈(全网最全解析)_第8张图片可以明显的看出来,RW-data同上图增加的值为5724-3676 = 2048字节。

1-5、ZI-data 的栈空间 (Stack) 及堆空间 (Heap):

在 C 语言中,函数内部定义的局部变量属于栈空间,进入函数的时候从向栈空间申请内存给局部变量,退出时释放局部变量,归还内存空间。
使用 malloc 动态分配的变量属于堆空间申请堆空间50字节方法

#include 
	uint8_t *p;
	p = (uint8_t *) malloc(50);
	p[0] = 10;

在程序中的栈空间和堆空间都是属于ZI-data 区域的,这些空间都会被初始值化为 0 值。编译器给出的 ZI-data 占用的空间值中包含了堆栈的大小 (经实际测试,若程序中完全没有使用 malloc 动态申请堆空间,编译器会优化,不把堆空间计算在内)。
MDK Keil编译中CODE-RO-RW-ZI Data -堆栈(全网最全解析)_第9张图片其中栈空间 (Stack) 及堆空间 (Heap)的大小定义会在startup_stm32f407xx.s文件中,用十六进制表示 Stack:hex(0x400)= 1024字节, Heap:hex(0x200)= 512字节这些空间都在ZI-data 中在内部RAM之中。

1-6、总结:MDK Keil编译中CODE-RO-RW-ZI Data -堆栈(全网最全解析)_第10张图片

2、程序的存储与运行

应用程序具有静止状态和运行状态。
静止状态的程序被存储在非易失存储器中,如 STM32 的内部 FLASH,因而系统掉电后也能正常保存。运行状态的时候,程序常常需要修改一些暂存数据,由于运行速度的要求,这些数据往往存放在内存中 (RAM),掉电后这些数据会丢失。
因此,程序在静止与运行的时候它在存储器中的表现是不一样的,见图应用程序的加载视图与执行视图。

MDK Keil编译中CODE-RO-RW-ZI Data -堆栈(全网最全解析)_第11张图片图中的左侧是应用程序的存储状态,右侧是运行状态,而上方是 RAM 存储器区域,下方是 ROM存储器区域。 程序在存储状态时, RO 节 (RO section) 及 RW 节都被保存在 ROM 区。
当程序开始运行时:
****内核直接从 ROM 中读取代码,并且在执行主体代码前,会先执行一段加载代码,它把 RW 节数据从ROM 复制到 RAM,并且在 RAM 加入 ZI 节, ZI 节的数据都被初始化为 0。
****加载完后 RAM 区准备完毕,正式开始执行主体程序。编译生成的 RW-data 的数据属于图中的 RW 节, ZI-data 的数据属于图中的ZI 节。

STM32 的 RO 区域不需要加载到 SRAM,内核直接从 FLASH 读取指令运行。

当程序存储到 STM32 芯片的内部 FLASH 时 (即 ROM 区),占用的空间是 Code、 RO-data 及RW-data 的总和,所以如果这些内容比 STM32 芯片的 FLASH 空间大,程序就无法被正常保存了。
当程序在执行的时候,需要占用内部 SRAM 空间 (即 RAM 区),占用的空间包括 RW-data 和ZI-data。应用程序在各个状态时各区域的组成见表程序状态区域的组成。
MDK Keil编译中CODE-RO-RW-ZI Data -堆栈(全网最全解析)_第12张图片
以上仅作为自己学习的记录,接下还我还会分析mdk生成的map等文件,在里边还有要具体的什么位置存储的什么信息,谢谢大家支持!!!!!

你可能感兴趣的:(stm32,stm32,mcu)