一、首先,笔者文章内容以下面工程内容为基础:
MCU为STM32F103(Cortex-M3内核);
RAM为64K;
FLASH为512K(容量大,有什么ideas,放心大胆就是干);
IAR编译工程文件(包括websocket.c);
链接文件*.icf文件;
编译生成*.map文件;
PLACEMENT SUMMARY部分是*.map文件的其中一大块内容,也是本文涉及的主要内容,关于.map文件的全解析请参看文末的一篇文章链接;
二、下面是笔者工程中map文件PLACEMENT SUMMARY块的开始部分内容:
"P1": place in [from 0x08002000 to 0x0807dfff] { ro};
"P2": place in [from 0x20000000 to 0x20004fff] {rw, block CSTACK, block HEAP };
意思是:
A1段(0x08002000)是初始化向量表映射地址(此向量表映射地址已偏移0x2000);
P1段(0x08002000 至 0x0807dfff,即512K-8K的FLASH)为代码段的映射地址区域(包括各种只读常量和代码);
P2段(0x20000000 至0x2000ffff,即64K的RAM)为各种变量(全局变量,全局静态变量,局部静态变量,局部变量)和堆、栈的映射地址区域;
三、各种变量在内存中的分配和存储
以websocket.c文件为例,进行变量在内存中的分配说明,在websocket.c源文件中进行了如下变量的定义:
进行工程编译后,生成的.map文件P2段内容如下(仅列出了与目标文件websocket相关的变量):
以上数据中:
.data inited(为已初始化数据)
.bss zero(为未初始化数据/零)
uninit(未初始化数据)
websocket.c中定义的8个变量(图示20行—27行),编译后对内存分配进行地址映射时,对应上图中P2段映射到.data段(23行和24行)和bss段(26行—37行)的数据,即:
1、wsTxBuf或wsRxBuf数组变量,占用0x640字节,存储在内存中0x20001170和0x200011b0地址;
2、curflag变量,占用0x1字节,分配在内存中0x2000016e地址;
3、curpage变量,占用0x2字节,分配在内存中0x2000016c地址;
4、curoutnum或handshaked变量,占用0x1字节,分配在内存中0x20003fa7和0x20003fa8地址;
5、curaddr或curdatanum变量,占用0x4字节,分配在内存中0x20003f90和0x20003f94地址;
因此在一些编程中,如有特殊需求,可以通过这种方式查看变量在内存中的存储地址;
通过以上数据总结如下:
- 全局变量和全局静态变量均分配在静态数据区(DATA段和BSS段);
- 全局变量和全局静态变量中,已初始化为0的变量分配在BSS段,已初始化为非0的变量分配在DATA段;
- 全局变量和全局静态变量中,未初始化的变量均分配在BSS段,BSS段在内存分配后系统将自动清0;(此处纠正下,实际清零是IAR的编译器会自动添加一段清零代码在main之前,实现进main之前执行清零BSS段)
- 局部变量分配在CSTACK区或HEAP区,即栈区和堆区(且分配后的地址区域数据均未初始化,未知);
- 由第2点知,如果变量全初始化0时,为了优化考虑,编译器会分配变量到BSS段处理,原因在于bss段的全局变量只占运行时的内存空间,而不占文件空间;
另外,局部静态变量在内存中的分配特点同全局变量、全局静态变量;