STM32关于堆栈,局部变量全局变量内存分配的问题
- 开发环境:IAR for ARM 8.30.1
- MCU:STM32F103RCT6
以一个简单的bootloader程序为例,先来看看map文件中的内存分配:
*******************************************************************************
*** PLACEMENT SUMMARY
***
"A0": place at 0x800'0000 { ro section .intvec }; //ROM的起始位置,从这里开始烧录程序
"P1": place in [from 0x800'0000 to 0x800'4000] { ro }; //整个Bootloader代码的存储空间
define block CSTACK with size = 1K, alignment = 8 { }; //编译器中定义的栈大小,1K字节
define block HEAP with size = 0M, alignment = 8 { }; //没有用到malloc之类的函数,设置为0
"P2": place in [from 0x2000'0000 to 0x2000'bfff] { //RAM的地址空间,分三个部分
rw, block CSTACK, block HEAP };
initialize by copy { rw };
RAM空间地址的三个部分划分:
.data:初始化的全局和静态变量;
.bss:未初始化的全局和静态变量,编译器自动初始化为0;
CSTACK:存放局部变量,局部变量超过栈大小将会发生堆栈溢出,程序崩溃;
"P2", part 1 of 3: 0x89
P2-1 0x2000'0000 0x89 <Init block>
.data inited 0x2000'0000 0x4 stm32f1xx_hal.o [1]
.data inited 0x2000'0004 0x4 system_stm32f1xx.o [1]
.data inited 0x2000'0008 0x38 xlocale_c.o [2]
.data inited 0x2000'0040 0x48 xlocale_c.o [2]
.data inited 0x2000'0088 0x1 stm32f1xx_hal.o [1]
- 0x2000'0089 0x89
"P2", part 2 of 3: 0x10dc
.bss zero 0x2000'008c 0x1000 boot.o [1]
.bss zero 0x2000'108c 0x58 spi.o [1]
.bss zero 0x2000'10e4 0x40 usart.o [1]
.bss zero 0x2000'1128 0x20 stm32f1xx_hal_flash.o [1]
.bss zero 0x2000'1148 0x10 spi_flash.o [1]
.bss zero 0x2000'1158 0x4 spi_flash.o [1]
.bss zero 0x2000'115c 0x4 spi_flash.o [1]
.bss zero 0x2000'1160 0x4 stm32f1xx_hal.o [1]
.bss zero 0x2000'1164 0x4 xfail_s.o [2]
- 0x2000'1168 0x10dc
"P2", part 3 of 3: 0x400
CSTACK 0x2000'1168 0x400 <Block>
CSTACK uninit 0x2000'1168 0x400 <Block tail>
- 0x2000'1568 0x400
这里查看系统剩余的ROM和RAM空间:
Unused ranges:
From To Size
---- -- ----
0x800'3cbd 0x800'4000 0x344
0x2000'0089 0x2000'008b 0x3
0x2000'1568 0x2000'bfff 0xaa98
1.堆栈
- 在IAR中的设置:
CSTACK大小决定了你函数中局部变量的总大小,由系统自动分配和释放,如果定义的局部变量大小超过了栈大小,虽然编译能通过,但是程序无法运行;同样,将CSTACK设置为0,编译器也能编译通过,但程序无法运行
2.全局变量初始化问题
这里的全局变量还包括static声明的静态变量,初始化与未初始化存放的位置不同,初始化为不同的值在占用ROM大小也是不同的
从下面的示例可以看出,全局变量不初始化和初始化为0占用内存一样的,而且他们都是分配在全局未初始化区,系统初始化的时候统一赋值为0;
而初始化为1或者其他值,就会额外占用ROM的空间来存放你要初始化的常数,而且还可以看到初始化为不同的值,占用的ROM和RAM还不一样,下面就有RAM占用反而变小了的情况,这是因为这个变量存放的位置变成了全局初始化区,会受到编译器优化和数据对齐的影响;
- 未初始化
u32 update_file_mark;
void Boot_Initializes(void)
{
u16 i,j;
//以下代码省略
占用内存情况:
14 684 bytes of readonly code memory
869 bytes of readonly data memory
5 481 bytes of readwrite data memory
- 初始化为0
u32 update_file_mark = 0;
占用内存情况:
14 684 bytes of readonly code memory
869 bytes of readonly data memory
5 481 bytes of readwrite data memory
- 初始化为1
u32 update_file_mark = 1;
占用内存情况:
14 684 bytes of readonly code memory
873 bytes of readonly data memory
5 477 bytes of readwrite data memory
- 初始化为0xFFFFFFFF
u32 update_file_mark = 0xFFFFFFFF;
占用内存情况:
14 684 bytes of readonly code memory
872 bytes of readonly data memory
5 477 bytes of readwrite data memory
3.局部变量初始化的问题
还是那个变量,这次放到函数内部让它成为局部变量
可以看到,局部变量初始化与否不会影响到RAM的分配变化,这个从RAM的空间划分的三个部分也可以看出
仅仅影响ROM而且是readonly code memory的变化,其中:
不初始化最节省ROM,初始化为0其次,初始化为其他值可能占用更多的ROM
- 未初始化
void Boot_Initializes(void)
{
u16 i,j;
u32 update_file_mark;
占用内存情况:
14 676 bytes of readonly code memory
869 bytes of readonly data memory
5 477 bytes of readwrite data memory
- 初始化为0
void Boot_Initializes(void)
{
u16 i,j;
u32 update_file_mark = 0;
占用内存情况:
14 680 bytes of readonly code memory
869 bytes of readonly data memory
5 477 bytes of readwrite data memory
- 初始化为1
void Boot_Initializes(void)
{
u16 i,j;
u32 update_file_mark = 1;
占用内存情况:
14 680 bytes of readonly code memory
869 bytes of readonly data memory
5 477 bytes of readwrite data memory
- 初始化为0xFFFFFFFF
void Boot_Initializes(void)
{
u16 i,j;
u32 update_file_mark = 0xFFFFFFFF;
占用内存情况:
14 684 bytes of readonly code memory
869 bytes of readonly data memory
5 477 bytes of readwrite data memory