BSS段

2023-05-16

(深入理解计算机系统) bss段,data段、text段、堆(heap)和栈(stack) 1

关于BSS段的大小 2

1. BSS段中的内容 2

2.BSS段在加载运行前的处理 3

3.BSS段的作用 3

4. 代码优化对BSS段的影响 3

5.Linux 下查看段属性的指令: 4

BSS大小实验 4

清除BSS段的一般做法 6

link脚本一般包含类似语句: 6

 

(深入理解计算机系统) bss段,data段、text段、堆(heap)和栈(stack)

一个程序本质上都是由bss段、data段、text段三个组成的。

bss段:

bss段属于静态内存分配。 bss是英文Block Started by Symbol的简称。

 BSS段通常是指用来存放程序中未初始化的全局变量和静态变量的一块内存区域。特点是可读写的,在程序执行之前BSS段会自动清0,所以,未初始的全局变量在程序执行之前已经成0了。

特点是:可读写的,

data段:

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

数据段属于静态内存分配。

text段:

代码段(code segment/text segment)通常是指用来存放程序执行代码的一块内存区域。

这部分区域的大小在程序运行前就已经确定,并且内存区域通常属于只读(某些架构也允许代码段为可写,即允许修改程序)。

在代码段中,也有可能包含一些只读的常数变量,例如字符串常量等。

堆(heap):

堆是用于存放进程运行中被动态分配的内存段,它的大小并不固定,可动态扩张或缩减。

当进程调用malloc等函数分配内存时,新分配的内存就被动态添加到堆上(堆被扩张);

当利用free等函数释放内存时,被释放的内存从堆中被剔除(堆被缩减)。

栈(stack):

栈又称堆栈,是用户存放程序临时创建的局部变量,

也就是说我们函数括弧“{}”中定义的变量(但不包括static声明的变量,static意味着在数据段中存放变量)。

除此以外,在函数被调用时,其参数也会被压入发起调用的进程栈中,并且待到调用结束后,函数的返回值也会被存放回栈中。

由于栈的先进先出(FIFO)特点,所以栈特别方便用来保存/恢复调用现场。

从这个意义上讲,我们可以把堆栈看成一个寄存、交换临时数据的内存区。

 

 

 

 

关于BSS段的大小

BSS段在执行文件中时候不占磁盘空间,要运行的时候才分配空间并清0.

历史原因

而很多时候,数据段里的全局变量都是0(或者没有初始值),那么存储这么多的0到目标文件(可执行)里其实是没有必要的。所以为了节约空间,在生成目标文件的时候,就把没有初始值(实际就是0)的数据段里的变量都放到BSS段里,这样目标文件就不需要那么大的体积里(节约磁盘空间)。只有当目标文件被载入(运行)的时候,加载器负责把BSS段清零(一个循环就可以搞定)。 之后,这个规则慢慢的成为一个标准配置,大多数编译器也就都支持了BSS段。

  1. BSS段中的内容

先明确 BSS 段“存放”的是未初始化的全局变量与局部静态变量,此处指的存放是指为其预留空间(占位符)。但BSS段在磁盘上不是真的占用变量大小的空间,它仅是在该段中记录了所有未初始化全局变量与局部静态变量的大小总和,至于每个变量的大小则存储在符号表的size属性中。即:

BSS段内容:无内容,它将在段表中占一个段描述符,该段描述符的size属性将记录未初始化的全局变量与局部静态变量的大小总和每个未初始化全局对象与静态对象的大小:存储在符号表的 size 属性中

(上述说法求证于C++牛人“蓝色”,表感谢。。。)

注:段表描述了ELF各个段的信息,比如每个段的段名,长度,在文件中的偏移等。ELF文件的段结构就是由段表决定的。

注:段表的结构是一个以“Elf32_shdr”结构体为元素的数组,数组元素个人等于段的数目,每一个结构体对应一个段。将这个结构体称为段描述符。而BSS则仅在段表中占用一个段描述符。但是在实际的ELF文件中不存在该段。

2.BSS段在加载运行前的处理

当可执行文件加载运行前,会为BSS段中的变量分配足够的空间并全部自动清理(因此,才有未初始化的全局变量的值为0的说法)。

3.BSS段的作用

BSS段主要是为了节省可执行文件在磁盘上所占的空间,其仅仅记录变量所需的大小。对未初始化的大型数组的节省效率比较明显。举例如下:

1.static int a[10000];  

2.int main()  

3.{  

4.     //...  

5.}  

在上述程序中,若不存在 BSS 段,则可执行文件将开辟一个 10000 * sizeof(int) 大小的空间,并全部存储为0,int 为4字节的情况下,该变量将在磁盘上占用39KB的空间。但是此时若是存在BSS 段,则在可执行文件中,将只是记录现在的BSS段总大小为40000即可,而无需真正的占据39KB的空间

该可执行文件在执行前将重新开辟39KB的空间,并自动初始化为0

4. 代码优化对BSS段的影响

全局变量与静态变量没有初始化或初始化值为0时,都会放在.bss段。初始化为非0值,则放在.data段。

 

考虑以下两个静态变量分别存储在哪个段中:

  1. static int x1 = 1;  
  2. static int x2 = 0;  

很明显可以看出,X1将被发在.data段中。令人意外的是 X2 将被放置在 .bss 段中,因为 x2 的值为0,被认为是未初始化的,因此将会被放在 .bss 段中以节省磁盘空间。

5.Linux 下查看段属性的指令:

用readelf -s 或 objdump -t 查看符号表用readelf -S 或 objdump -h 查看段表

 牵涉到嵌入式系统运行时的内存大小分配,存储单元占用空间大小的问题。

在采用段式内存管理的架构中(比如intel的80x86系统),bss段通常是指用来存放程序中未初始化的全局变量的一块内存区域,

 一般在初始化时bss段部分将会清零。bss段属于静态内存分配,即程序一开始就将其清零了。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

BSS大小实验

比如,在C语言之类的程序编译完成之后,

  1. 已初始化的全局变量保存在.data段中,
  2. 未初始化的全局变量保存在.bss段中。

 

text和data段都在可执行文件中(在嵌入式系统里一般是固化在镜像文件中),由系统从可执行文件中加载;而bss段不在可执行文件中,由系统初始化

 

【例】

两个小程序如下:

程序1:

int ar[30000];

void main()

{

......

}

程序2:

int ar[300000]={1,2,3,4,5,6};

void main()

{

......

}

发现程序2编译之后所得的.exe文件比程序1的要大得多。

 

当下甚为不解,于是手工编译了一下,并使用了/FAs编译选项来查看了一下其各自的.asm,

发现在程序1.asm中ar的定义如下:

_BSS SEGMENT

?ar@@3PAHA DD 0493e0H DUP(?);ar

_BSS ENDS

而在程序2.asm中,ar被定义为:

_DATA SEGMENT

?ar@@3PAHA DD 01H;ar

DD 02H

DD 03H

ORG$+1199988

_DATA ENDS

区别很明显,一个位于.bss段,而另一个位于.data段,两者的区别在于:

全局的未初始化变量存在于.bss段中,具体体现为一个占位符;

全局的已初始化变量存于.data段中;

而函数内的自动变量都在栈上分配空间;

 

.bss是不占用.exe文件空间的,其内容由操作系统初始化(清零);

.data却需要占用,其内容由程序初始化。因此造成了上述情况。

bss段(未手动初始化的数据)并不给该段的数据分配空间,只是记录数据所需空间的大小;

bss段的大小从可执行文件中得到,然后链接器得到这个大小的内存块,紧跟在数据段后面。

data段(已手动初始化的数据)则为数据分配空间,数据保存在目标文件中;

data段包含经过初始化的全局变量以及它们的值。当这个内存区进入程序的地址空间后全部清零。

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

 

 

清除BSS段的一般做法

link脚本一般包含类似语句:

1

2

3

4

5

6

7

8

9

10

11

_bss_start = .;

__bss_start__ = .;

.bss            : 

{

  *(.shbss)

  *(.bss .bss.* .gnu.linkonce.b.*)

  *(COMMON)

}

. = ALIGN (4);

_bss_end = . ;

__bss_end__ = . ;

启动过程的代码一般在汇编做:

1

2

3

4

5

6

7

8

9

    @++++clear the BSS section++++

    ldr     r2,=__bss_start__

    ldr     r3,=__bss_end__

    mov     r12,#0

bss_loop:

    cmp     r2,r3 

    stmltia r2!,{r12}

    blt     bss_loop  

    @----clear the BSS section----

所以不要在C代码中对未初始化的全局变量赋0,因为BSS段会被自动赋0.

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

BSS段 的相关文章

随机推荐

  • Windows远程连接Ubuntu (远程桌面和XDMCP)

    从 RHEL CentOS 转过来 xff0c 几乎所有的编码都在 windows 下 xff0c 不习惯原生 linux 开发 总结了远程连接的两种方式 xff0c 一种用 Windows 自带的 rdp 协议 xff0c 另外一种用 x
  • Linux启动java程序很慢

    Linux启动java程序很慢 xff0c 原因有很多 网上的解决方式也很多 1 修改jre配置参数 xff08 尝试无效 xff0c 可能场景不一 xff09 JAVA HOME jre lib security java securit
  • MySQL数据库备份的几种方式

    MySQL备份的几种方式 最近一直想写点博客 xff0c 但是不知道写什么 xff0c 感觉自己最近的知识没有什么增加 xff0c 今天想到了一篇可以写的博客 以前试过根据data文件夹备份MySQL xff0c 但是从来没有成功过 xff
  • 【docker】深入探讨container,通过container生成image

    深入探讨container 对于上图的理解 image其实是由一层一层的layer来组成的 最底层基于linux内核在上面加了一层一层的layer 从docker仓库pull的image是由Dockerfile来生成 这个image是只读的
  • 创建表时附带的ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic 的解释

    ENGINE 61 InnoDB DEFAULT CHARSET 61 utf8 COLLATE 61 utf8 general ci ROW FORMAT的解释 1 示例 CREATE TABLE 96 student 96 96 id
  • c语言编程“水仙花数”

    文章目录 打印所有的水仙花数 所谓的 水仙花数 是指一个三位数 xff0c 其各位数字的立方和等于该数本身 例如 xff0c 153是水仙花数 xff0c 因为153 61 1 3 43 5 3 43 3 3 打印所有的水仙花数 所谓的 水
  • inux查看日志的几种方法

    linux 日志查看 tail head cat tac sed less echo 1 命令格式 tail 必要参数 选择参数 文件 f 循环读取 q 不显示处理信息 v 显示详细的处理信息 c lt 数目 gt 显示的字节数 n lt
  • asp不能正常用的原因

    前几天做网站时 xff0c 机子出现了这种症状 xff0c 重装过IE和IIS一样也无法解决 xff0c 在百度里找了一下 xff0c 下面的方法真的很适用 症状 xff1a 运行asp程序 包括其他动态网页程序 出现500内部错误信息 x
  • 用DLL实现把数据库的记录导出到EXCEL中(VB)

    39 新建一个ActiveX DLL工程工程名为DbToExcel 39 工程 gt 引用 引用Microsoft ActiveX Data Objects 2 6 Library 39 Microsoft Excel 9 0 Object
  • MySQL转换为SqlServer数据库

    如何将MySQL数据导入到SqlServer中 xff0c 请看以下步骤 xff1a 1 安装mysql数据库的ODBC驱动 xff0c mysql connector odbc 3 51 19 win32 msi 2 打开控制面板管理工具
  • DataTimePicker数据绑定遇到Null时异常的原因

    DateTimePicker1 DataBindings Add 34 Value 34 bindingSource1 34 assessortime 34 如果字段 assessortime的值 为 null 时 就会出现异常 后来发现
  • c#中DataTable与实体集合相互转换

    以下是将集合类转换成DataTable lt summary gt 将集合类转换成DataTable lt summary gt lt param name 61 34 list 34 gt 集合 lt param gt lt return
  • 用Linux命令行生成随机密码的十种方法

    转载自 极客范 xff0c 不得不夸夸强大的Bash啊 xff01 xff01 xff01 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61
  • C++20 Ranges

    VS2019 C 43 43 20的Ranges 01 引入范围的动机02 范围 ranges 03 range v3库04 C 43 43 20 range demo 01 引入范围的动机 C 43 43 17以前的标准库中大多数通用算法
  • 面向对象分析设计步骤

    一 创建用例 初步确定用例 xff1a 1 确定参与者 2 确定用例 xff08 系统操作 xff09 3 确定参与者与用例之间的关系 用例细节描述 xff1a 1 用例名称 2 操作详细描述 3 前置条件描述 4 部署约束 5 正常事件流
  • collect2: ld terminated with signal 9 错误解决办法

    编译android是出现如下错误 xff1a target Java CameraEffectsTests out target common obj APPS CameraEffectsTests intermediates classe
  • 浅谈Stein算法求最大公约数(GCD)的原理及简单应用

    一 Stein算法过程及其简单证明 1 一般步骤 xff1a s1 当两数均为偶数时将其同时除以2至至少一数为奇数为止 xff0c 记录除掉的所有公因数2的乘积k xff1b s2 如果仍有一数为偶数 xff0c 连续除以2直至该数为奇数为
  • 【已解决】@Configration爆红

    64 Configration爆红 问题原因 xff1a 一 xff1a 没有添加依赖 二 xff1a 添加依赖了 xff0c 但是依赖版本过低 解决方法 xff1a 把依赖的版本改的高一点 span class token generic
  • 关于冒泡排序的程序( 第三次作业)

    此前想过把两种排序方式都一起写在一个工程文件里 xff0c 但做了下 xff0c 能力有限 xff0c 没法写完整 xff0c 所以就只能分别写 xff0c 这个是冒泡排序 xff0c 代码已尽量做到准确的注释 xff0c 希望提醒自己往后
  • BSS段

    深入理解计算机系统 bss段 xff0c data段 text段 堆 heap 和栈 stack 1 关于BSS段的大小 2 1 BSS段中的内容 2 2 BSS段在加载运行前的处理 3 3 BSS段的作用 3 4 代码优化对BSS段的影响