如何.bss部分不是零初始化

我们知道.bss包含未初始化的变量。 如果在c代码中,程序员在使用它们之前初始化变量。 然后.bss在执行C代码之前不必为零。

我对吗?

谢谢

在C代码中,任何具有静态存储持续时间的变量都被定义为由规范初始化为0(第6.7.8节初始化,第10段):

如果未显式初始化具有静态存储持续时间的对象,则:

  • 如果它有指针类型,则将其初始化为空指针;
  • 如果它有算术类型,则初始化为(正或无符号)零;
  • 如果是聚合,则根据这些规则初始化(递归)每个成员;
  • 如果它是一个联合,则根据这些规则初始化(递归)第一个命名成员。

一些程序加载器将用零填充整个部分,而其他程序加载器将“按需”填充它作为性能改进。 因此,虽然技术上正确,但是当C代码开始执行时, .bss部分可能并不真正包含全零,它在逻辑上也是如此。 在任何情况下,假设您有一个符合标准的工具链,您可以将其视为全零。

任何初始化为非零值的变量都不会在.bss部分中结束; 它们在.data.rodata部分中处理,具体取决于它们的特定特征。

ELF规范说:

.bss此部分包含有助于程序内存映像的未初始化数据。 根据定义,当程序开始运行时,系统用零初始化数据。 该部分不占用文件空间,如节类型SHT_NOBITS所示。

因此,具有分配给它的值的C全局变量不能放入.bss部分,并且必须进入.data部分。 .data部分包含分配给它的所有变量的初始值。

这取决于变量在代码中的位置。 例如,如果您正在讨论main()或任何其他函数中的局部变量,那么变量将被推送到堆栈中(除非您使用其他修改关键字)。 如果您的变量是全局的且未初始化,则应将其保存在.bss中。 请注意,编译器优化等可能会改变一些事情。 如果你想知道肯定使用readelf来调查linux上的ELF二进制文件。

看起来你可能会对.bss部分最终初始化为零的机制感到困惑。 您编译的代码不一定要将区域显式初始化为零,因为当操作系统首先为进程分配新的内存页时,操作系统会确保页面初始化为零。 这是出于安全原因而完成的,因此当其他进程退出时,进程无法查找留在内存中的秘密。