首页 > 其他分享 >谈谈Keil-MDK编译输出的:Code-data,RO-data,RW-data,ZI-data

谈谈Keil-MDK编译输出的:Code-data,RO-data,RW-data,ZI-data

时间:2022-12-20 17:32:04浏览次数:49  
标签:RO Code ZI int unsigned main data


谈谈Keil-MDK编译输出的:Code-data,RO-data,RW-data,ZI-data( 其中有的可能分析得不太正确,希望可以得到大佬们的指点纠正)



​​浅谈Keil-MDK创建项目&编译过程​​Code-data,RO-data,RW-data,ZI-data 程序运行时加载过程

这些有个大概的了解即可,不用研究太细,主要是让你工程过大的时候规划哈数据怎么存放,硬件资源有限的,开发时得做好规划:

程序存储时占用的ROM区大小(内部Flash): Code + RO-data + RW-data​​
程序执行时的只读区域(RO)(Flash)      :  Code + RO data​​
程序执行时的可读写区域(RW)(SRAM)   :   RW data + ZI data

谈谈Keil-MDK编译输出的:Code-data,RO-data,RW-data,ZI-data_RW-RO-ZI-data


首先来解释哈各表示什么含义

  Code:即代码域,它指的是编译器生成的机器指令,这些内容被存储到ROM 区(也就是STM32 的内部 Flash 中)
  
  RO-data:Read Only data,即只读数据域,它指程序中用到的只读数据,这些数据被存储在 ROM 区( STM32 内部 Flash ),因而程序不能修改其内容。例如 C 语言中 const 关键字定义的变量就是典型的 RO-data
  
  RW-data:Read Write data,即可读写数据域,它指初始化为“非 0 值”的可读写数据,程序刚运行时,这些数据具有非 0 的初始值,且运行的时候它们会常驻在 RAM 区,因而应用程序可以修改其内容。例如 C 语言中使用定义的​​​全局变量​​​,且定义时赋予​​“非 0 值”​​​给该变量 进行初始化
  
  ZI-data:Zero Initialie data,即 0 初始化数据,它指初始化为“0 值”的可读写数据域,它与 RW-data 的区别是程序刚运行时这些数据初始值全都为 0,而后续运行过程与 RW-data 的性质一样,它们也常驻在 RAM 区,因而应用程序可以更改其内容。例如 C 语言中使用定义的全局变量,且定义时赋予“0 值”给该变量进行初始化(若定义该变量时没有赋予初始值,编译器会把它当 ZI-data 来对待,初始化为 0)
  

  ZI-data 的栈空间(Stack)及堆空间(Heap):在 C 语言中,函数内部定义的局部变量属于栈空间,进入函数的时候从向栈空间申请内存给局部变量,退出时释放局部变量,归还内存空间。而使用 malloc 动态分配的变量属于堆空间。在程序中的栈空间和堆空间都是属于 ZI-data 区域的,这些空间都会被初始值化为 0 值。​​(这里值得注意的是栈和堆里面的没初始化的数据是随机数,自己仔细斟酌,通过测试 ZI-data的大小的确等于堆栈的大小之和)​​编译器给出的 ZI-data 占用的空间值中包含了堆栈的大小(经实际测试,若程序中完全没有使用 malloc 动态申请堆空间,编译器会优化,不把堆空间计算在内)

综上所述,以程序的组成构件为例,它们所属的区域类别如图:

程序组件所属类别机器指令Code常量RO-data初始非0的全局变量RW-data初值为0的全局变量ZI-data局部变量ZI-data 栈空间使用malloc动态分配的空间ZI-data 堆空间

完成了,定义的解释,接下来就来实战检验吧

首先建工程包含一个启动文件和main.c 文件

谈谈Keil-MDK编译输出的:Code-data,RO-data,RW-data,ZI-data_RW-RO-ZI-data_02


谈谈Keil-MDK编译输出的:Code-data,RO-data,RW-data,ZI-data_Code_03


; <h> Stack Configuration
; <o> Stack Size (in Bytes) <0x0-0xFFFFFFFF:8>
; </h>

Stack_Size EQU 0x00000400 ; 0x400 = 1024 Byte

AREA STACK, NOINIT, READWRITE, ALIGN=3
Stack_Mem SPACE Stack_Size
__initial_sp


; <h> Heap Configuration
; <o> Heap Size (in Bytes) <0x0-0xFFFFFFFF:8>
; </h>

Heap_Size EQU 0x00000200 ; 0x200 = 512 Byte

AREA HEAP, NOINIT, READWRITE, ALIGN=3
__heap_base
Heap_Mem SPACE Heap_Size
__heap_limit

;*******************************************************************************
; User Stack and Heap initialization
;*******************************************************************************
IF :DEF:__MICROLIB

EXPORT __initial_sp
EXPORT __heap_base
EXPORT __heap_limit

ELSE

IMPORT __use_two_region_memory
EXPORT __user_initial_stackheap

__user_initial_stackheap

LDR R0, = Heap_Mem
LDR R1, =(Stack_Mem + Stack_Size)
LDR R2, = (Heap_Mem + Heap_Size)
LDR R3, = Stack_Mem
BX LR

ALIGN

ENDIF

END

谈谈Keil-MDK编译输出的:Code-data,RO-data,RW-data,ZI-data_Code_04

谈谈Keil-MDK编译输出的:Code-data,RO-data,RW-data,ZI-data_Code_05


   值得注意的堆栈的溢出,程序会进入一个中断里面时循环

谈谈Keil-MDK编译输出的:Code-data,RO-data,RW-data,ZI-data_STM32_06

这就对了,由于没有使用到堆,所以被编译器优化了ZI-data = 1024刚好是栈的大小(正确)

谈谈Keil-MDK编译输出的:Code-data,RO-data,RW-data,ZI-data_Keil_07


感兴趣你可以去研究哈自己实现 __use_two_region_memory 怎么写,可以去这里查它该怎么写:

谈谈Keil-MDK编译输出的:Code-data,RO-data,RW-data,ZI-data_MDK_08

谈谈Keil-MDK编译输出的:Code-data,RO-data,RW-data,ZI-data_Code_09


来测测 RO-data 区域:主要测试const 关键字修饰的变量

Test01:

const unsigned char test = 1;

int main()
{
}
void SystemInit(){
}

谈谈Keil-MDK编译输出的:Code-data,RO-data,RW-data,ZI-data_MDK_10

编译结果显示:RO-data 没有变化,进行Test02 测试

Test02:

const unsigned char test = 1;

int main()
{
if( test == 1 ){
// // 打开 GPIOB 端口的时钟
*( unsigned int * )0x40021018 |= ( (1) << 3 );
}
}
void SystemInit(){

}

谈谈Keil-MDK编译输出的:Code-data,RO-data,RW-data,ZI-data_Code_11

编译结果显示:RO-data 没有变化,进行Test03 测试

Test03:

const unsigned char test[1] = { 1 };

int main()
{
}
void SystemInit(){
}

谈谈Keil-MDK编译输出的:Code-data,RO-data,RW-data,ZI-data_Code_12

编译结果显示:RO-data 没有变化,进行Test04 测试

Test04:

const unsigned char test[1] = { 1 };

int main()
{
if( test[0] == 1 ){
// // 打开 GPIOB 端口的时钟
*( unsigned int * )0x40021018 |= ( (1) << 3 );
}
}
void SystemInit(){

}


Test05:

int main()
{
const unsigned char test[1] = { 1 };
if( test[0] == 1 ){
// // 打开 GPIOB 端口的时钟
*( unsigned int * )0x40021018 |= ( (1) << 3 );
}
}
void SystemInit(){
}

谈谈Keil-MDK编译输出的:Code-data,RO-data,RW-data,ZI-data_Keil_13

编译结果显示:哈? RO-data 又回去了, 怎么回事? 在进行测试Test06

Test06:

int main()
{
const unsigned char test[2] = { 1 };
if( test[0] == 1 ){
// // 打开 GPIOB 端口的时钟
*( unsigned int * )0x40021018 |= ( (1) << 3 );
}
}
void SystemInit(){
}


Test07:

int main()
{
const unsigned char test = 1 ;
if( test == 1 ){
// // 打开 GPIOB 端口的时钟
*( unsigned int * )0x40021018 |= ( (1) << 3 );
}
}

void SystemInit(){
}

谈谈Keil-MDK编译输出的:Code-data,RO-data,RW-data,ZI-data_Keil_14

编译结果显示:RO-data 没有变化 所以我也是一串 ?????,测试Test08,Test09

Teat08:

const unsigned char test[ 1024 * 1024 ] =  { 1 };

int main()
{
if( test[0] == 1 ){
// // 打开 GPIOB 端口的时钟
*( unsigned int * )0x40021018 |= ( (1) << 3 );
}
}

void SystemInit(){
}

Test09:

int main()
{
const unsigned char test[ 1024 * 1024 ] = { 1 };
if( test[0] == 1 ){
// // 打开 GPIOB 端口的时钟
*( unsigned int * )0x40021018 |= ( (1) << 3 );
}
}

void SystemInit(){
}

Test08

谈谈Keil-MDK编译输出的:Code-data,RO-data,RW-data,ZI-data_RW-RO-ZI-data_15

Test09

谈谈Keil-MDK编译输出的:Code-data,RO-data,RW-data,ZI-data_RW-RO-ZI-data_16

再抛一个神奇的测试:
#define N 7

int main()
{
const char str[N] = "123456";

}

void SystemInit(){
}
N = 1,2, ; 测试结果

谈谈Keil-MDK编译输出的:Code-data,RO-data,RW-data,ZI-data_RW-RO-ZI-data_17

N = 3, 4 ; 测试结果

谈谈Keil-MDK编译输出的:Code-data,RO-data,RW-data,ZI-data_Code_18

N = 5, 6 , 7, 8; 测试结果

谈谈Keil-MDK编译输出的:Code-data,RO-data,RW-data,ZI-data_MDK_19

N = 9, 10, 11, 12; 测试结果

谈谈Keil-MDK编译输出的:Code-data,RO-data,RW-data,ZI-data_MDK_20

哈,似乎发现了什么规律,再测一哈全局的
#define N 4
const char str[N] = "1";
int main()
{
if( str[0] == '1')
{
*( unsigned int * )0x40021018 |= ( (1) << 3 );
}
}
void SystemInit(){
}
N = 1,2; 测试结果

谈谈Keil-MDK编译输出的:Code-data,RO-data,RW-data,ZI-data_RW-RO-ZI-data_21

N = 3,4; 测试结果

谈谈Keil-MDK编译输出的:Code-data,RO-data,RW-data,ZI-data_Code_22

N = 9, 10; 测试结果

谈谈Keil-MDK编译输出的:Code-data,RO-data,RW-data,ZI-data_MDK_23

Test10:

#define N 10
const int str[N] = {1};
int main()
{
if( str[0] == 1)
{
*( unsigned int * )0x40021018 |= ( (1) << 3 );
}
}
void SystemInit(){
}


RW-data --ZI-data 测试

int a = 1;
int main()
{
if( a == 1)
{
*( unsigned int * )0x40021018 |= ( (1) << 3 );
}
}
void SystemInit(){
}
测试结果: RW-data 增加了

谈谈Keil-MDK编译输出的:Code-data,RO-data,RW-data,ZI-data_Keil_24

Test11:

unsigned char a[1024] = { 0 , 1 , 2};
int main()
{

if( a[0] == 1)
{
*( unsigned int * )0x40021018 |= ( (1) << 3 );
}
}

void SystemInit(){
}
测试结果:RW-data 增加了1024

谈谈Keil-MDK编译输出的:Code-data,RO-data,RW-data,ZI-data_Code_25

Test12:

unsigned char a[1024] = { 0};
int main()
{

if( a[0] == 1)
{
*( unsigned int * )0x40021018 |= ( (1) << 3 );
}
}

void SystemInit(){
}
测试结果:ZI-data 增加了1024

谈谈Keil-MDK编译输出的:Code-data,RO-data,RW-data,ZI-data_RW-RO-ZI-data_26

在 ZI-data 添加上堆的大小

#include <stdlib.h>

int main()
{
unsigned char * p;

p = (unsigned char *)malloc(10);
}
void SystemInit(){
}

谈谈Keil-MDK编译输出的:Code-data,RO-data,RW-data,ZI-data_Keil_27

最后温馨提示:如果定义了没有用到的变量,也就是比较冗余的变量的(编译器这么觉得),很有可能被编译器优化,自己注意一下

 
 
 
 

Code-data,RO-data,RW-data,ZI-data,程序运行时的加载过程

标签:RO,Code,ZI,int,unsigned,main,data
From: https://blog.51cto.com/u_15918664/5956369

相关文章