stm32堆栈,rom,flash详细理解
精⼼总结
⾸先
⼀个程序被加载到内存中,这块内存⾸先就存在两种属性:静态分配内存和动态分配内存。
静态分配内存:是在程序编译和链接时就确定好的内存。
动态分配内存:是在程序加载、调⼊、执⾏的时候分配/回收的内存。
任何⼀个程序本质上都是由 bss段、data段、text段三个组成的。
C语⾔上分为栈、堆、bss、data、code段。
bss段:
bss段(bss segment)通常是指⽤来存放程序中未初始化的全局变量的⼀块内存区域。
bss是英⽂Block Started by Symbol的简称。
bss段属于静态内存分配。
data段:
数据段(data segment)通常是指⽤来存放程序中已初始化的全局变量的⼀块内存区域。
数据段属于静态内存分配。
text段:
代码段(code segment/text segment)通常是指⽤来存放程序执⾏代码的⼀块内存区域。
这部分区域的⼤⼩在程序运⾏前就已经确定,并且内存区域通常属于只读(某些架构也允许代码段为可写,即允许修改程序)。
在代码段中,也有可能包含⼀些只读的常数变量,例如字符串常量等。
注意:
l BSS区(未初始化数据段):并不给该段的数据分配空间,仅仅是记录了数据所需空间的⼤⼩。
l DATA(初始化的数据段):为数据分配空间,数据保存在⽬标⽂件中。
上⾯这三段内存就组成了我们编写的程序的本体,但是⼀个程序运⾏起来,还需要更多的数据和数据间的交互,否则这个程序就是死的,⽆⽤的。所以我们还需要为更多的数据和数据交互提供⼀块内存——堆栈。
堆(heap):
堆是⽤于存放进程运⾏中被动态分配的内存段,它的⼤⼩并不固定,可动态扩张或缩减。
当进程调⽤malloc等函数分配内存时,新分配的内存就被动态添加到堆上(堆被扩张);
当利⽤free等函数释放内存时,被释放的内存从堆中被剔除(堆被缩减)。
栈(stack):
字符串常量存放在哪个内存区域 栈⼜称堆栈,是⽤户存放程序临时创建的局部变量,
也就是说我们函数括弧“{}”中定义的变量(但不包括static声明的变量,static意味着在数据段中存放变量)。
除此以外,在函数被调⽤时,其参数也会被压⼊发起调⽤的进程栈中,并且待到调⽤结束后,函数的返回值也会被存放回栈中。
由于栈的先进后出特点,所以栈特别⽅便⽤来保存/恢复调⽤现场。
从这个意义上讲,我们可以把堆栈看成⼀个寄存、交换临时数据的内存区。
来看⼀段代码:
#include<stdio.h>
#include<stdlib.h>
#include<iostream>
#include<string.h>
using namespace std;
static int a=1;//全局初始化区
int b=2;//全局初始化区
char *p;//全局未初始化区
char *p2;//全局未初始化区,BSS段
int *p3;//全局未初始化区,BSS段
int *p4;//全局未初始化区,BSS段
char *p5={"555555555"};//全局初始化区
int main(){
static int c=3;
int d=4;//内存栈
int e=7;//内存栈
char *p6={"555555555"};
p=(char*)malloc(sizeof(char)*10);//内存堆
p2=(char*)malloc(sizeof(char)*10);//内存堆
p3=(int*)malloc(sizeof(int));//内存堆
p4=(int*)malloc(sizeof(int)*10);//内存堆
for(int i=0;i<=9;i++)p4[i]=0x1;
*p3=0x123;
strcpy(p,"123456789");//⽂字常量区
strcpy(p2,"987654321");
strcpy(p2,"123456789");
}
然后回到stm32上⾯:
Flash,SRAM寄存器和输⼊输出端⼝被组织在同⼀个4GB的线性地址空间内。可访问的存储器空间被分成8个主要块,每个块为512MB,如下图,SRAM和FLASH在块1和块0。
FLASH存储下载的程序,全局变量和静态变量,在运⾏时,系统会把这些变量搬运到SRAM。同时根据代码定义,未初始化的全局变量在开始运⾏时会在SRAM开辟⼀块空间保证使⽤。(pass:如果
SRAM是存储运⾏程序中的数据,所以,在运⾏时,我们定义的没有初始化的全局变量和没有初始化的静态变量,使⽤的局部变量,堆栈都放在SRAM中。
所以,只要你不外扩存储器,写完的程序中的所有东西也就会出现在这两个存储器中。
stm32的堆栈理解:
C语⾔上分为栈、堆、bss、data、code段。
C语⾔在单⽚机和PC上的内存中的区域有⼀点不同的是,单⽚机的code段是直接在flash中的,是可以直接从flash读取代码并执⾏的,⽽PC 的code段是在内存中的,在运⾏⼀开始需要从硬盘中将代码搬运到内存中
MDK下Code, RO-data,RW-data,ZI-data这⼏个段:
Code是存储程序代码的。
R O-data是存储const常量和指令。
R W-data是存储初始化值不为0的全局变量。
Z I-data是存储未初始化的全局变量或初始化值为0的全局变量。
所以对应起来stm32中:
Flash=Code + RO Data + RW Data;
RAM= RW-data+ZI-data;
这个是MDK编译之后能够得到的每个段的⼤⼩,也就能得到占⽤相应的FLASH和RAM的⼤⼩,但是还有两个数据段也会占⽤RAM,但是
是在程序运⾏的时候,才会占⽤,那就是堆和栈。在stm32的启动⽂件.s⽂件⾥⾯,就有堆栈的设置,
其实这个堆栈的内存占⽤就是在上⾯RAM分配给RW-data+ZI-data之后的地址开始分配的。所以要注意合理的栈⼤⼩设置。
OS中的堆栈及其内存管理。
嵌⼊式系统的堆栈,不管是⽤什么⽅法来得到内存,感觉他的⽅式都和编程中的堆差不多。⽬前我知道
两种获得内存情况:
(1)⽤庞⼤的全局变量数组来圈住⼀块内存,然后将这个内存拿来进⾏内存管理和分配。这种情况下,堆栈占⽤的内存就是上⾯说的:如果没有初始化数组,或者数组的初始化值为0,堆栈就是占⽤的RAM的ZI-data部分;如果数组初始化值不为0,堆栈就占⽤的RAM的RW-data部分。这种⽅式的好处是容易从逻辑上知道数据的来由和去向。
(2)就是把编译器没有⽤掉的RAM部分拿来做内存分配,也就是除掉RW-data+ZI-data+编译器堆+编译器栈后剩下的RAM内存中的⼀部分或者全部进⾏内存管理和分配。这样的情况下就只需要知道内存剩下部分的⾸地址和内存的尾地址,然后要⽤多少内存,就⽤⾸地址开始挖,做⼀个链表,把内存获取和释放相关信息链接起来,就能及时的对内存进⾏管理了。内存管理的算法多种多样,不详说,这样的情况下:OS的内存分配和⾃⾝局部变量或者全局变量不冲突。
查看.map⽂件,有如下例⼦:
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区域并不在RAM中,所以需要程序根据编译器给出的ZI地址及⼤⼩来将相应得RAM区域清零。ZI中也是变量,同理:变量不能存在ROM中。
在程序运⾏的最初阶段,RO中的指令完成了这两项⼯作后C程序才能正常访问变量。否则只能运⾏不含变量的代码。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论