STM32变量的存储和堆栈

变量

           如上图,这是在KEIL下生成的map文件的最后几行。来理解一下这几个含义,RO:只读,RW:读写,ROM:这个不用解释,固件存储。那么接下的就更好理解了:Code:编译代码段大小;RO Data:编译后只读数据大小;RW Data:编译后读写数据大小。那么,ZI Data怎么理解呢?

       大家都知道,一段代码除了代码段(主要指函数或者语法语句),还有变量;而在变量里面又分全局变量,局部变量,静态变量 ,还有常量(这里我们先定义一个约定, extern 修饰的是外部变量,外部变量肯定是全局变量,因此为方便区分,我们统一将函数内的变量称为局部变量,将函数外的变量,包括extern 修饰的外部变量统一称为全局变量;static 是静态变量;const是常量)。那么这些常量是怎么存放在硬件里面?又是怎样调用的呢?

         首先,代码段和常量,编译之后就不允许修改,知道RAM和ROM属性知道,ROM是不可修改的,而RAM是支持修改的,所以代码段和常量编译之后的存放,肯定就是ROM了,编译完成之后得到是code段和data-ro段,如图(在STM32里面,ROM就是FLASH(内部),起始地址是0x0800 0000):

      其次,全局变量和静态变量有三种种情况,未初始化、初始化值为0和初始化值不为0;为了节省空间,编译器在编译过程中将未初始化和初始化值为0的全局变量和静态变量统一都编译成.bss段(也就是上面提到的 ZI Data);而有初始值得全局或静态变量,编译之后得到的是 data-rw段(STM32中RAM起始地址是0x2000 0000)。

       这里有一点要注意,初始值不为零的全局或静态变量,因为需要记录初始值,所以会保存在镜像文件里面;而在程序运行时,这些值会被搬运到RAM里面以便进行修改,所以这些变量会同时占用RAM空间和ROM空间,这也就解释了上图里面的:ROM SIZE = Code + RO Data + RW Data,这个其实就是最终bin(或image)的大小;RW  Size  = RW Data + ZI Data) ,这个就是代码运行所需要的RAM大小。

         看到这里,细心的同学会发现还有一种变量---局部变量还没说到。我们知道,在函数调用过程其实就是对栈的操作过程。在函数调用时,第一个进栈的是主函数中函数调用后的下一条指令的地址,然后是函数的各个参数,然后是局部变量;当本次函数调用结束后,局部变量先出栈,然后是参数,最后栈顶指针指向最开始存的地址,也就是主函数中的下一条指令。从这里不难发现,局部变量其实是在调用过程中才给他分配空间的,而且是栈空间。

堆与栈

        有了上面的基础再来分析堆栈就简单多了。明确一点,堆(heap)与栈(stack)都是占用RAM空间,其中stack大小分配在.S 文件里进行分配。heap存在两种情况,对于裸机代码,heap的大小直接在.S ,其分配与回收由标准的C接口(malloc和free)进行管理;而在RTOS代码里面,还存在第二个heap空间,就是由RTOS自己的接口进行管理的heap空间,例如FreeRTOS的pvPortMalloc和vPortFree,其大小一般在置文件里修改。

       对于STM32来说,一旦heap和stack大小确定之后,就是不可变的;只是在管理上有很大区别。stack的空间分配与释放由寄存器自行管理的,无需人为操作(也没有接口供你操作),结合上问局部变量的分析,一种典型的栈溢出错误就是使用的局部变量超过的栈空间最大值;而heap(无论是裸机和RTOS)的空间分配与释放都是通过接口人为操作的,一般分配和释放都是成对出现,如果只分配不释放,很容造成堆溢出。

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值