STM32 的堆栈静态区
STM32的分区从0x2000 0000开始。静态区,堆,栈。
所有的全局变量,包括静态变量之类的,全部存储在静态存储区。
紧跟静态存储区之后的,是堆区(如没用到malloc,则没有该区),之后是栈区,栈在程序中存储局部变量
先看启动文件startup_stm32f10x_md.s的定义:
; Amount of memory (in bytes) allocated for Stack
; Tailor this value to your application needs
; <h> Stack Configuration
; <o> Stack Size (in Bytes) <0x0-0xFFFFFFFF:8>
; </h>
Stack_Size EQU 0x00000400
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
AREA HEAP, NOINIT, READWRITE, ALIGN=3
__heap_base
Heap_Mem SPACE Heap_Size
__heap_limit
PRESERVE8
THUMB
这里定义了堆栈各自大小,堆:512bytes 栈1k;
所以栈区大小有限制,我们在局部变量中不要定义大数组否则容易溢出。
再看下code ro rw zi
cede:代码 ro也就是常量 rw已初始化的全局变量 zi未初始化的全局变量+栈
编译一个没有用malloc的工程:
查看.map文件:
Removing Unused input sections from the image.
Removing startup_stm32f10x_md.o(HEAP), (512 bytes). 因为没有使用malloc,没有分配堆
Image Symbol Table
Symbol Name Value Ov Type Size Object(Section)
__initial_sp 0x20000960 Data 0 startup_stm32f10x_md.o(STACK)
STACK 0x20000560 Section 1024 startup_stm32f10x_md.o(STACK)
__initial_sp 栈顶地址,躺在0x0800 0000占用四个字节,多说一句 0x0800 0004才是复位向量地址
STACK是栈底,__initial_sp -STACK=0x400 1k字节
==============================================================================
Code (inc. data) RO Data RW Data ZI Data Debug
39562 2998 3550 292 2108 641228 Grand Totals
39562 2998 3550 292 2108 641228 ELF Image Totals
39562 2998 3550 292 0 0 ROM Totals
==============================================================================
Total RO Size (Code + RO Data) 43112 ( 42.10kB)
Total RW Size (RW Data + ZI Data) 2400 ( 2.34kB)
Total ROM Size (Code + RO Data + RW Data) 43404 ( 42.39kB)
==============================================================================
Total RW Size (RW Data + ZI Data) 2400 ( 2.34kB) : 也就是0x960 为栈顶__initial_sp 0x20000960
再加入malloc看一下:
要在编译选项中启用微库,include<stdlib.h>
int *p=NULL;
p=malloc(sizeof(int));
HEAP 0x20000568 Section 512 startup_stm32f10x_md.o(HEAP)
STACK 0x20000768 Section 1024 startup_stm32f10x_md.o(STACK)
__heap_base 0x20000568 Data 0 startup_stm32f10x_md.o(HEAP)
__heap_limit 0x20000768 Data 0 startup_stm32f10x_md.o(HEAP)
__initial_sp 0x20000b68 Data 0 startup_stm32f10x_md.o(STACK)
可见分配了堆,大小为512 bytes在栈的下面,这里也可以看出,堆向上增长,栈向下增长
==============================================================================
Code (inc. data) RO Data RW Data ZI Data Debug
39770 3014 3550 300 2620 395376 Grand Totals
39770 3014 3550 44 2620 395376 ELF Image Totals (compressed)
39770 3014 3550 44 0 0 ROM Totals
==============================================================================
Total RO Size (Code + RO Data) 43320 ( 42.30kB)
Total RW Size (RW Data + ZI Data) 2920 ( 2.85kB)
Total ROM Size (Code + RO Data + RW Data) 43364 ( 42.35kB)
==============================================================================
Total RW Size (RW Data + ZI Data) 2920 ( 2.85kB) 0xB68 栈顶
ZI变为2620比之前例子增加了512bytes 刚好是heap堆的大小
在map中:
==============================================================================
Code (inc. data) RO Data RW Data ZI Data Debug Object Name
36 8 236 0 1536 0 startup_stm32f10x_md.o
==============================================================================
堆也在ZI中。
2920-2400=520 多了个堆512之后还有个8多到哪了?而且可以看到两次之间ZI只增加了堆的512,RW增加了8.
再次查看RW之后发现多了这个:
Image component sizes
==============================================================================
Code (inc. data) RO Data RW Data ZI Data Debug Library Member Name
0 0 0 8 0 0 mvars.o
==============================================================================
还有一个问题 ELF Image Totals和Grand Totals之间RW少了256不过ELF Image Totals 变成了ELF Image Totals (compressed)
找到:http://www.keil.com/support/man/docs/armlink/armlink_CACHFGGB.htm
极好 的网址感谢网友
ELF Image Totals
If you are using RW data compression (the default) to optimize ROM size, the size of the final image changes and this is reflected in the output from --info
. Compare the number of bytes under Grand Totals
and ELF Image Totals
to see the effect of compression.
In the example, RW data compression is not enabled. If data is compressed, the RW value changes.
Object Totals
Shows how many bytes are occupied by objects linked together to generate the image.
(incl. Generated)
armlink might generate image contents, for example, interworking veneers, and input sections such as region tables. If the Object Totals
row includes this type of data, it is shown in this row.
In the example, there are 19 bytes of RO data in total, of which 16 bytes is linker-generated RO data.
Grand Totals
Shows the true size of the image. In the example, there are 10200 bytes of ZI data (in Object Totals
) and 300 of ZI data (in Library Totals)
giving a total of 10500 bytes.
最后附上关于RO,RW, ZI Total ROM Size等的详细说明,摘抄
Code指存储到flash【Rom】中的程序代码。
ZI英语是zero initial,就是程序中用到的变量并且被系统初始化为0的变量的字节数,keil编译器默认是把你没有初始化的变量都赋值一个0,这些变量在程序运行时是保存在RAM中的。
RW是可读可写变量,就是初始化时候就已经赋值了的,RW + ZI就是你的程序总共使用的RAM字节数。
RO是程序中的指令和常量,这些值是被保存到Rom中的。
Total ROM Size (Code + RO Data + RW Data)这样所写的程序占用的ROM的字节总数,也就是说程序所下载到ROM flash 中的大小。为什么Rom中还要存RW,因为掉电后RAM中所有数据都丢失了,每次上电RAM中的数据是被重新赋值的,每次这些固定的值就是存储在Rom中的,为什么不包含ZI段呢,是因为ZI数据都是0,没必要包含,只要程序运行之前将ZI数据所在的区域一律清零即可。包含进去反而浪费存储空间。
实际上,ROM中的指令至少应该有这样的功能:
1. 将RW从ROM中搬到RAM中,因为RW是变量,变量不能存在ROM中。
2. 将ZI所在的RAM区域全部清零,因为ZI区域并不在Image中,所以需要程序根据编译器给出的ZI地址及大小来将相应得RAM区域清零。ZI中也是变量,同理:变量不能存在ROM中。
在程序运行的最初阶段,RO中的指令完成了这两项工作后C程序才能正常访问变量。否则只能运行不含变量的代码。