深入浅出了解(.text、.data、.bss、堆空间、栈空间)的含义

接下来所说的是嵌入式系统的内存地址空间的布局,简单的说就是我们写好的代码,在编译过程种中,把代码里不同的变量、函数相应的保存在每个段中(.text、.data、.bss),至于堆空间、栈空间是代码在芯片上运行时才存在的。

  1. .text:代码段。包含了操作系统和应用程序的所有代码。
  2. .data:数据段。存放了操作系统和应用程序当中所有带有初始值的全局变量。
  3. .bss:bss段。存放了操作系统和应用程序当中所有未带初始化的全局变量。
  4. 堆空间:动态分配的内存空间。在系统运行时,可以通过malloc/free之类的函数来申请或者释放一段连续的内存空间
  5. 栈空间:保存运行上下文以及函数调用时的局部变量和形参。

那么问题1,什么样的数据会保存在.text段里?.data段?.bss段?栈空间?堆空间?

答:下面举例说明:

unsigned char gvCh;//全局变量,没有初值,放在.bss段中
unsigned short gvShort;// 全局变量,没有初值,放在.bss段中
unsigned int gvInt = 0x12345678;//全局变量,有初值,放在.data段中
unsigned long gvLong = 0x87654321; //全局变量,有初值,放在.data段中int main(void)//main函数在经过编译以后得到的机器代码,存放在.text代码段当中
{unsigned char arry[10],*p;//局部变量,存放在栈当中p = malloc(10*sizeof(char));//p指针变量指向的空间,存放在堆当中while(1);
}

补充:上面定义的全局变量没有在代码上引用,这里只是举例,如果在实际应用中,它们会被编译器优化掉,那么它们根本就不会占用内存空间。

问题2,上面的例子可能只是给你解开了一部分疑惑,如果用上变量修饰词static、const,那么它们又是怎么存储的呢?

答:下面举例说明:

static unsigned char gvCh;//全局变量,只能在本文件内引用,没有初值,放在.bss段中
const unsigned short gvShort;//全局变量,不可修改(只读),放在.data段中。实际不会定义无初值的const变量
static unsigned int gvInt = 0x12345678;//全局变量,只能在本文件内引用,有初值,放在.data段中
const unsigned long gvLong = 0x87654321;//全局变量,不可修改(只读),放在.data段中。int main(void)
{static unsigned char lvCh;//加上static的局部变量,只能在本函数内引用,函数结束回时不会消失,没有初值,放在.bss段中const unsigned short lvShort;//加上const的局部变量,不可修改(只读),放在.data段中。实际不会定义无初值的const变量static unsigned int lvInt = 0x12345678;//加上static的局部变量,只能在本函数内引用,函数结束回时不会消失,有初值,放在.data段中const unsigned long lvLong = 0x87654321//加上const局部变量,不可修改(只读),放在.data段中while(1);
}

总结,如果变量加上const,不管是全局变量还是局部变量,不管有没有初值,都保存在.data段。如果变量加上static,不会影响变量所保存的段,static的作用是改变变量的作用域。

问题3,我们了解完怎么样的变量该保存到什么段,或许还会有疑惑,.data段的数据和.bss段的数据有什么区别?把数据这么区分出来的作用是什么?

答:原因其实很简单,就是为了节省编译出来的bin文件占用的内存大小。.data段变量的值会记录在bin二进制文件中,而.bss记录的是变量的起始地址和大小,在程序运行时初始化为零。下举例说明:

unsigned char gvCh_init[3] = {1,2,3}; //.data段,如果数组增大100字节,那么bin文件大小会也会随之增大
unsigned char gvCh_no_init[3];//.bss段,如果数组增大为100字节,那么bin文件大小不会发生变化,在bin文件里只是记录这个数组的起始地址和大小,当程序运行时自动把它的值清零。

问题4,unsigned chat gvCh[100] ={0};算不算给数组gvCh设置了初值而被保存在.data段,将占用bin文件大小?

答:在IAR编译器里,unsigned chat gvCh[100] ={0}等同于unsigned chat gvCh[100],保存于.bss段。

问题5,我们知道在芯片上有ROM存储器和RAM存储器,在程序bin文件烧录到芯片上时,不同的段会如何存在于在ROM和RAM里呢?

答:没有一一对应的关系。因为我可以把bin文件烧录到flash(ROM)里面运行,也可以把它烧录到RAM里面运行(调试时会这么做)。

通常地,我们会把编译好的程序烧录到flash(ROM)里面去,芯片掉电时不会消失;对于RAM存储器来说,只有芯片上电代码运行起来,才会被分配使用(栈/堆就是在RAM开辟的)。

问题6,代码中的变量会以什么样的规则存在于ROM存储器和RAM存储器里?

答:主要根据变量在运行时是否可修改,下面举例说明:

unsigned char gvCh;可读写,存放在RAM(无初始值,.bss段)
unsigned int gvInt = 0x12345678;//可读写,存放在RAM(有初始值,.data段)
const unsigned long gvLong = 0x87654321; //只读,存放在ROMint main1(void)//main函数在经过编译以后得到的机器代码,不可修改,存放ROM
{unsigned char arry[10],*p;//可读写,存放在栈当中,也就是在RAM中p = malloc(10*sizeof(char));//p指针变量指向的空间,存放在堆当中,也就是在RAM中while(1);
}

有初始值、并且可读写的全局变量gvInt存放在RAM,但我们知道在RAM的数据掉电会丢失,其实它的初始值0x12345678一开始保存在flash(ROM)里,在芯片上电时,会将初始值复制到RAM里的gvInt变量(它所在RAM的地址在编译后已经确定)。可能我们会疑惑,自己的代码明明没有写给gvInt变量赋值的过程,这一部分代码并不需要我们做。芯片上电就会进入Reset_Handler中断,打开.s启动文件,我们可以发现在Reset_Handler中断里,调用了SystemInit函数,然后再调用了_main(IAR编译器的话是__iar_program_start)函数,在_main函数会进行RW data的复制,和.bss段的初始化,以及C库函数的初始化(比如malloc函数需要初始化才能使用),进而调用main函数进入我们的代码区域。

关于嵌入式系统内存地址空间的一些疑问(.text、.data、.bass、堆\栈空间)相关推荐

  1. 鸿蒙系统内存管理,嵌入式系统内存管理-鸿蒙HarmonyOS技术社区-鸿蒙官方战略合作伙伴-51CTO.COM...

    1.概述 操作系统的内存管理功能用于向操作系统提供一致的地址映射功能和内存页面的申请.释放操作.在嵌入式实时系统中,内存管理根据不同的系统,有不同的策略,对于有些系统支持的虚拟内存管理机制,对于另外一 ...

  2. 嵌入式linux+io+优化,嵌入式Linux系统内存优化使用方法研究

    [摘要] 嵌入式系统功能的提高,占用了较大内存空间,继而时常出现运行无响应.基于用户方面看,由于系统内存问题影响运行,针对系统内存与进程应用状态研究,可以调整系统数值与执行文件elf分析,进行系统优化 ...

  3. 嵌入式系统中的EEPROM和FRAM

    对于所有基于微控制器的嵌入式系统而言,存储器都是其中的主要元件.例如开发人员需要足够的ram以存储所有易失性变量.创建缓冲区以及管理各种应用堆栈.RAM对于嵌入式系统相当重要,同样,开发人员也需要一定 ...

  4. SoC嵌入式软件架构设计之中的一个:系统内存需求评估

    内存是SoC(System on Chip,片上系统)集成设计的重要模块.是SoC中成本比重较大的部分.内存管理的软硬件设计是SoC软件架构设计的重要一环,架构设计师必需要在成本和效率中取得平衡,做到 ...

  5. 一种嵌入式系统的内存分配方案

    1 嵌入式系统中对内存分配的要求 ①快速性.嵌入式系统中对实时性的保证,要求内存分配过程要尽可能地快.因此在嵌入式系统中,不可能采用通用操作系统中复杂而完善的内存分配策略,一般都采用简单.快速的内存分 ...

  6. C语言嵌入式系统编程修炼之内存操作

    数据指针 在嵌入式系统的编程中,常常要求在特定的内存单元读写内容,汇编有对应的MOV指令,而除C/C++以外的其它编程语言基本没有直接访问绝对地址的能力.在嵌入式系统的实际调试中,多借助C语言指针所具 ...

  7. 嵌入式系统编程之内存操作的注意事项

    关注.星标公众号,直达精彩内容 ID:技术让梦想更伟大 整理:李肖遥 在嵌入式系统的编程中,内存操作是我们常用到的,但往往也是易错的地方,怎么避免呢,今天给大家分享一些相关的避坑指南. 数据指针 在嵌 ...

  8. 内存回收在嵌入式系统应用方面的调研和总结

    前传 嵌入式系统的内存回收还是比较重要的,因为这块涉及到程序运行性能. 嵌入式系统(比如平板,手机)会更加关注单机性能优化,因而会更加重视系统内存回收. 嵌入式系统不像互联网那种大型分布式服务器系统, ...

  9. 串口 接收端_嵌入式系统串口传输int float型数据的处理

    在做嵌入式系统通信时往往会用到串口,包括嵌入式系统将数据传输给PC,或者是嵌入式系统之间进行数据传输,这时候就会遇到发送数据的问题. 我们知道单片机通过串口发送数据时往往是一次一个字节(8位),如果传 ...

最新文章

  1. Tomcat学习总结(3)——Tomcat优化详细教程
  2. Linux上的WebSphere MQ开发快速入门
  3. unity3d与eclipse协同工作环境
  4. Docker快速搭建Oracle12c
  5. switch c语言讲解,C语言switch使用之诡异用法详解
  6. Zabbix二次开发_03api列表
  7. slf4j-log4j12-1.5.8.jar有什么用
  8. 站长吧asp工具设置_网站更换域名需要怎么办?网站更换域名如何设置?
  9. 组合选择符 深入了解
  10. USDP使用笔记(二) 部署免费的USDP大数据双集群替代CDH CDP与HDP
  11. 对模型进行DP处理(DP-SGD+DP-Logits)
  12. “用户体验及可用性测试”前三章:读书笔记
  13. Python拓展dict类
  14. computed动态颜色
  15. yocs_cmd_vel_mux和yocs_velocity_smoother
  16. 《Python数据分析与挖掘》实战项目 - Python程序设计(期末大作业、课程设计、毕业设计)2012-2021近十年考研英语一真题词汇词频统计与可视化(附代码)
  17. 单相变换器的二次纹波分析
  18. C语言strchr()函数以及strstr()函数的实现
  19. 坯子库怎么导入插件_SketchUp坯子库管理器 坯子插件库免费版v2019.4.0 - 云骑士一键重装系统...
  20. 思科模拟器——RIP协议

热门文章

  1. AgileEAS.NET平台开发实例-药店系统-报表开发(高级篇)
  2. Oracle 多行、多列子查询
  3. [BZOJ3874/AHOI2014]宅男计划
  4. GDataXML解析XML文档
  5. 如何成为CSDN博客专家
  6. 装好了ubuntu,w2k却无法启动了,:(
  7. springboot整合视图层Thymeleaf、freemarker
  8. git初始化及关联远程仓库命令
  9. ubuntu报错:E: 仓库 “http://ppa.launchpad.net/docky-core/ppa/ubuntu bionic Release” 没有 Release 文件
  10. 详解k8s deployment的滚动更新