【STM32】.bss .data .text 与Code, RO-data , RW-data, ZI-data的关系

核心就是RAM和ROM的作用和区别

1 .bss .data .text

1.1 bss段:

bss段(bss segment)通常是指用来存放程序中未初始化的全局变量的一块内存区域。
bss是英文Block Started by Symbol的简称。
bss段属于静态内存分配。

1.2 data段:

数据段(data segment)通常是指用来存放程序中已初始化的全局变量的一块内存区域。
数据段属于静态内存分配。

1.3 text段:

代码段(code segment/text segment)通常是指用来存放程序执行代码的一块内存区域。
这部分区域的大小在程序运行前就已经确定,并且内存区域通常属于只读(某些架构也允许代码段为可写,即允许修改程序)。
在代码段中,也有可能包含一些只读的常数变量,例如字符串常量等。

程序本质

一个程序本质上都是由 bss段、data段、text段三个组成的。
这样的概念,不知道最初来源于哪里的规定,但在当前的计算机程序设计中是很重要的一个基本概念。
而且在嵌入式系统的设计中也非常重要,牵涉到嵌入式系统运行时的内存大小分配,存储单元占用空间大小的问题。
在采用段式内存管理的架构中(比如intel的80x86系统),bss段通常是指用来存放程序中未初始化的全局变量的一块内存区域,一般在初始化时bss 段部分将会清零。bss段属于静态内存分配,即程序一开始就将其清零了。

比如,在C语言之类的程序编译完成之后,已初始化的全局变量保存在.data 段中,未初始化的全局变量保存在.bss 段中。
text和data段都在可执行文件中(在嵌入式系统里一般是固化在镜像文件中),由系统从可执行文件中加载;
而==bss段不在可执行文件中,由系统初始化,==全局的未初始化变量存在于.bss段中,具体体现为一个占位符

全局的已初始化变量存于.data段中;而函数内的自动变量都在栈上分配空间;.bss是不占用.exe文件空间的,其内容由操作系统初始化(清零);.data却需要占用,其内容由程序初始化。

bss段(未手动初始化的数据)并不给该段的数据分配空间,只是记录数据所需空间的大小
bss段的大小从可执行文件中得到 ,然后链接器得到这个大小的内存块,紧跟在数据段后面

data段(已手动初始化的数据)则为数据分配空间,数据保存在目标文件中;data段包含经过初始化的全局变量以及它们的值。

包含data段和bss段的整个区段此时通常称为数据区

2 Keil MDK中的Code, RO-data , RW-data, ZI-data

2.1 Code(inc.Data) :

包含两部分,即代码和数据

  • code,即程序代码部分
    -== inline data==. For example, literal pools(文字常量池), and short strings(短字符串)等. 这个一般被忽略,请大家注意!!!
2.2 RO Data:

read-only data,只读的数据
Shows how many bytes are occupied by read-only data. This is in addition to the inline data included in the Code (inc. data) column. 除inline data 之外的所有只读数据。

2.3 RW Data:

read write data,可读写的数据
Shows how many bytes are occupied by read-write data.

2.4 ZI Data:

zero initialized data,零初始化的可读写变量
Shows how many bytes are occupied by zero-initialized data.
keil编译器默认是把你没有初始化的变量都赋值一个0。初始化为零,或者未初始化的变量,都存储于这个区域。

存储Size:

RO size: Code + RO_data
RW size: RW_data + ZI_data
ROM (minimum)size = Code + RO_data + RW_data (即烧/下载程序到FLASH/ROM时,所占用的最小空间)
Total ROM Size (Code + RO Data + RW Data)这样所写的程序占用的ROM的字节总数,也就是说程序所下载到ROM flash 中的大小。

RAM size: RW Data + ZI Data (即程序运行的时,RAM使用的空间)

    1. 为什么ROM(flash)中还要存RW,因为掉电后RAM中所有数据都丢失了,每次上电RAM中的数据是被重新赋值的,每次这些固定的值就是存储在ROM中的,
    2. 为什么不包含ZI段呢,是因为ZI数据都是0,没必要包含,只要程序运行之前将ZI数据所在的区域一律清零即可。包含进去反而浪费存储空间。

    3 例子

    3.1 keil编译输出
    linking...
    Program Size: Code=30550 RO-data=762 RW-data=140 ZI-data=48436  
    
     
     
      Code, RO-data,RW-data ............flash
      RW-data, ZIdata...................RAM
      
       
       
        3.2 MAP

        初始化时RW-data从flash拷贝到RAM

        生成的map文件位于list文件夹下 (KEIL)

            Total RO  Size (Code + RO Data)                31312 (  30.58kB)
            Total RW  Size (RW Data + ZI Data)             48576 (  47.44kB)
            Total ROM Size (Code + RO Data + RW Data)      31452 (  30.71kB)
        
         
         

          C语言变量的存储类别

          内存中供用户使用的存储空间分为代码区与数据区两个部分。
          变量存储在数据区,数据区又可分为静态存储区与动态存储区。

          • 静态存储是指在程序运行期间给变量分配固定存储空间的方式。如全局变量存放在静态存储区中,程序运行时分配空间,程序运行完释放。

          • 动态存储是指在程序运行时根据实际需要动态分配存储空间的方式。如形式参数存放在动态存储区中,在函数调用时分配空间,调用完成释放。

          • 对于静态存储方式的变量可在编译时初始化,默认初值为O或空字符。

          • 对动态存储方式的变量如不赋初值,则它的值是一个不确定的值。

          auto 存储类指明符

          用于说明具有局部作用域的变量,它表示变量具有局部(自动)生成期,但由于它是所有局部作用域变量说明的缺省存储类指明符,所以使用得很 少。要注意的是,所有在函数内部定义的变量都是局部变量,函数内部定义的变量其作用域只在函数内部。它的生存期为该函数运行期间,一旦离开这个函数或这个 函数终止,局部变量也随之消失。

          register 存储类指明符

          当声明了这个指明符后,编译程序将尽可能地为该变量分配CPU内部的寄存器作为变量的存储单元,以加快运行速度。注意,寄存器与存储器是 不同的。寄存器一般在CPU内部,而存储器一般指外部的(比如内存条),CPU内部的寄存器其运算速度是很高的。当寄存器已分配完毕,就自动地分配一个外 部的内存。它的作用等价于auto,也只能用于局部变量和函数的参量说明。

          static 存储类指明符

          表示变量具有静态生成期。static变量的的特点是它离开了其作用域后,其值不会消失。(即内存一直被它占有,不会被释放

          extern 存储类指明符

          一般用在工程文件中。在一个工程文件中因为有多个程序文件,当某一个变量在一个程序文件中定义了之后,如果在另一个程序文件中予以定义, 就会出现重复定义变量的错误。使用extern存储类型指明符就可以指出在该文件外部已经定义了这个变量。extern变量的作用域是整个程序。

          动态数组和静态数组

          动态数组和静态数组虽然在使用时看起来没有什么差别,但他们实现是不一样的。
          反汇编看一下他们的代码。

          数组类型C/C++代码汇编实现简略说明
          局部变量a[7] = 0;MOV DWORD PTR SS:[EBP-C], 0采用EBP在堆栈定位变量[EBP - 28] a[0] … [EBP - 4] a[9]
          静态局部变量s_a[7] = 0;MOV DWORD PTR DS:[4C5E5C], 0静态变量会被放到数据.data段中
          全局变量g_a[7] = 0;MOV DWORD PTR DS:[4C5E84], 0全局变量和静态变量一样,会被放到数据.data段中
          数组指针(malloc)p1_a[7] = 0;MOV EAX, DWORD PTR SS:[EBP-2C] MOV DWORD PTR DS:[EAX+1C], 0对于数组指针,要进行两次寻址 0x1C / 4 = 7
          数组指针(new)p2_a[7] = 0;MOV EAX, DWORD PTR SS:[EBP-30] MOV DWORD PTR DS:[EAX+1C], 0同上

          堆栈

          堆(heap):

          堆是用于存放进程运行中被动态分配的内存段,它的大小并不固定,可动态扩张或缩减。
          当进程调用malloc等函数分配内存时,新分配的内存就被动态添加到堆上(堆被扩张);
          当利用free等函数释放内存时,被释放的内存从堆中被剔除(堆被缩减)。

          栈(stack):

          栈又称堆栈,是用户存放程序临时创建的局部变量,
          也就是说我们函数括弧“{}”中定义的变量(但不包括static声明的变量,static意味着在数据段中存放变量)。
          除此以外,在函数被调用时,其参数也会被压入发起调用的进程栈中,并且待到调用结束后,函数的返回值也会被存放回栈中。
          由于栈的先进先出(FIFO)特点,所以栈特别方便用来保存/恢复调用现场。
          从这个意义上讲,我们可以把堆栈看成一个寄存、交换临时数据的内存区。

          评论
          添加红包

          请填写红包祝福语或标题

          红包个数最小为10个

          红包金额最低5元

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

          抵扣说明:

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

          余额充值