【stm32内存分区】内存中的RW段、ZI段、堆栈怎样存放的?

一、前言

在之前的学习过程中,对stm32内存分布经常会产生一个疑问,在keil编译出来的程序,最后面会统计出各个部分所占用大小,比如下面这个

可以知道程序中的Code(代码段)、RO-data(只读数据段)、RW-data(可读可写数据段)和ZI-data(未初始化或初始化为0的全局变量和静态变量)分别占用的字节数,把RW段和ZI段的字节大小相加为67488byte(转为十六进制为:0x107a0)。

map文件中映像内存分布图
map文件中栈顶地址

 从图中可以发现程序中用到的SRAM大小等于RW段加ZI段的大小,也与__initial_sp栈顶的地址偏移量相等。那么这时就会有个问题,RW加ZI的区域和栈的区域不是重叠了吗?要回答这个问题,我们要先理解两个概念——程序文件、运行中的程序。

二、程序文件

程序文件:程序编译后生成的可执行文件,如:bin文件和hex文件等。

 在程序文件中,分区情况有下面这些:

1. Code段

 也是RO-Code段,包含程序运行的代码(机器码),一直存储在FLASH上。

2. RO-data (read only)

 只读数据段,一般为const关键字修饰的全局变量,开始存储在flash,程序运行时会移到RAM。

3. RW-data (read write)

可读可写数据段,包括初始化不为0的全局变量、static关键字修饰的全局变量和局部变量,在FLASH和RAM中都占用了空间。

4. ZI-data (zero init)

初始化为0的数据段,包括初始化为0或未初始化的全局变量和static修饰的全局变量和局部变量,一直存储在RAM,编译器给出的ZI-data空间实际还包含了堆栈空间(可从前言中的分析看出)。

5. RO

只读段,包括只读代码段(Code段)和只读数据段(RO-data)。

从map文件的最后可以看出前面几个区域的大小关系以及在存储器的分布,RAM的大小等于RW-data段加ZI-data段大小,FLASH的大小等于Code段加RO-data段加RW-data段大小,这时程序中并没有分配堆栈的空间。

程序文件中的内存分布图如下(图中所示每个区域大小因程序而异)

三、运行中的程序

运行中的程序:MCU上电后开始运行的过程。

 MCU上电后开始运行,会初始化堆栈,将RW-data段数据从FLASH移到RAM(类似于memcpy(ram_rw,flash_rw,size)),将RAM中ZI-data段数据清零(类似于memset(zi,0,sizeof(zi))),这些过程是在__main函数中实现的,具体可以参考stm32的启动文件。

程序开始运行后的分区情况主要有:

1. 代码段(code/txt)

存放程序执行代码的内存区域,这块区域在程序运行前就确定了,绝大多数情况在FLASH中,但也可以把code放在RAM中运行。

2. 静态存储区(.bss段+.data段)

静态存储区是.bss段和.data段的统称,其中ZI-data段数据会被加载到.bss段,而RW-data会被加载到.data段。

3. 栈区(stack)

栈区主要用于存放局部变量,函数形参和函数的返回值,属于编译器自动分配和释放的内存。栈的生长方向是从高地址到低地址,当程序出现了莫名奇妙的错误,并进入了hardfault,就要考虑是不是分配的栈空间不够大导致溢出的问题了。

4. 堆区(heap)

堆主要用于动态内存的分配,像 malloc() calloc() realloc() 等函数申请的内存就在堆上面。堆中的内存一般由程序员分配和释放(free函数),若程序员不释放,程序结束时可能由操作系统回收。 堆和栈的生长方向相反的,堆是由低 向高生长。若程序中没有使用到malloc申请堆内存,即使分配了堆空间,那么编译器也会优化掉。
程序运行中的内存分布如下图:(注:pad为保证字节对齐所填充的大小)

四、结语

如有错误,欢迎大家指正!

  • 16
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值