为什么需要.bss 段?

我所知道的是,全局变量和静态变量存储在 .data段中,未初始化的数据存储在 .bss段中。我不明白的是为什么我们要为未初始化的变量设置专门的段?如果一个未初始化的变量在运行时分配了一个值,那么这个变量是否仍然只存在于 .bss段中?

在下面的节目中,a.data段,b.bss段,对吗?如果我理解错误,请纠正我。

#include <stdio.h>
#include <stdlib.h>


int a[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9};
int b[20]; /* Uninitialized, so in the .bss and will not occupy space for 20 * sizeof (int) */


int main ()
{
;
}

另外,考虑下面的节目,

#include <stdio.h>
#include <stdlib.h>
int var[10];  /* Uninitialized so in .bss */
int main ()
{
var[0] = 20  /* **Initialized, where this 'var' will be ?** */
}
62221 次浏览

首先,示例中的这些变量不是未初始化的; C 指定未初始化的静态变量被初始化为0。

所以。Bss 具有更小的可执行文件,节省空间并允许更快地加载程序,因为加载程序只需分配一堆零,而不必从磁盘复制数据。

当运行程序时,程序加载程序将加载。资料及。记忆。中的对象进行写入。资料或。因此 bss 只存储在内存中,它们在任何时候都不会刷新到磁盘上的二进制文件。

.bss段是一种优化。整个 .bss段由一个数字描述,可能是4字节或8字节,这个数字在运行过程中给出了它的大小,而 .data段的大小与初始化变量的大小之和一样大。因此,.bss使可执行文件更小,加载速度更快。否则,变量可能在 .data段中,显式初始化为零; 程序将很难区分这种差异。(详细地说,如果对象位于 .data段中,那么 .bss中对象的地址可能与该地址不同。)

在第一个程序中,a将在 .data段中,而 b将在可执行文件的 .bss段中。一旦加载了程序,区别就变得无关紧要了。在运行时,b占用 20 * sizeof(int)字节。

在第二个程序中,var被分配了空间,而 main()中的赋值修改了这个空间。碰巧 var的空间是在 .bss段而不是 .data段中描述的,但是这并不影响程序在运行时的行为。

原因是为了减少程序的大小。假设您的 C 程序运行在嵌入式系统上,代码和所有常量都保存在真正的 ROM (闪存)中。在这样的系统中,在调用 main ()之前,必须执行一个初始的“ copy-down”来设置所有静态存储持续时间对象。它通常是这样的伪:

for(i=0; i<all_explicitly_initialized_objects; i++)
{
.data[i] = init_value[i];
}


memset(.bss,
0,
all_implicitly_initialized_objects);

哪里。资料及。Bss 存储在 RAM 中,但 init _ value 存储在 ROM 中。如果它是一个段,那么 ROM 必须填充许多零,显著增加 ROM 大小。

基于 RAM 的可执行程序的工作方式类似,尽管它们当然没有真正的 ROM。

此外,memset 可能是一些非常有效的内联汇编,这意味着启动向下复制可以执行得更快。

来自 汇编语言分步编程: Linux 编程的 Jeff Duntemann,关于 。数据部分:

。数据部分包含初始化数据项的数据定义 数据是在程序开始运行之前有一个值的数据 是可执行文件的一部分。当 可执行文件加载到内存中执行。

关于. data 部分,需要记住的重要一点是 定义的初始化数据项越多,可执行文件就越大 将是,并且将它从磁盘加载到内存所需的时间越长 当你运行它的时候。

以及 。 bss部分:

并非所有数据项在程序开始运行之前都需要具有值。 例如,在从磁盘文件读取数据时,需要有一个 数据从磁盘输入后要去的地方。像这样的数据缓冲区 在你的程序的 。 bss部分定义。你留出一些 字节,并为缓冲区提供一个名称,但是不说什么值 都存在于缓冲区中。

在. data 中定义的数据项之间有一个关键的区别 节中定义的数据项 中的数据项添加到可执行文件的大小 一个占用16,000字节(或更多)的缓冲区, 可以在.bss 中定义,并且几乎不添加任何内容 (约50字节的描述)到可执行文件大小。

维基百科的文章 < strong > . bss 提供了一个很好的历史解释,因为这个词是从1950年代中期开始的(我的生日快乐; ——)。

在过去,每一个位都是宝贵的,所以任何发送预留空间信号的方法都是有用的。这个(。 bss)就是卡住的那个。

. data 部分用于不为空的空间,而是将已定义的值输入其中。

系统 V ABI 4.1(1997) (AKA ELF 规范)也包含答案:

.bss此部分保存未初始化的数据,这些数据有助于 根据定义,系统初始化 程序开始运行时带零的数据。如节类型 SHT_NOBITS所示,该节不占用任何文件空间。

说段名 .bss是保留的,有特殊的效果,特别是它的 不占用任何文件空间,因此优于 .data

缺点当然是,当操作系统将所有字节放在内存上时,所有字节都必须设置为 0,这是一个更加严格的限制,但是是一个常见的用例,并且对于未初始化的变量可以很好地工作。

SHT_NOBITS节类型文档重复了这一断言:

此成员以字节为单位给出节的大小。除非节类型为 SHT_NOBITS,否则该节占用 sh_size 类型为 SHT_NOBITS的部分可能有一个非零 但是它在文件中不占用空间。

C 标准没有提到节,但是我们可以使用 objdumpreadelf轻松地验证变量在 Linux 中存储的位置,并得出结论,未初始化的全局变量实际上存储在 .bss中。例如这个答案: 在 C 语言中,声明的、未初始化的变量会发生什么情况?