全局变量是如何存储的?

6
据我所知,全局变量分为两种类型:已初始化和未初始化。它们是如何存储的?它们都存储在可执行文件中吗?我可以想到已初始化的全局变量将其初始值存储在可执行文件中。但是未初始化的全局变量需要存储什么呢?
我的理解如下:
可执行文件被组织为几个节,例如.text、.data 和 .bss。代码存储在.text 节中,已初始化的全局或静态数据存储在.data 节中,而未初始化的全局或静态数据存储在.bss 节中。
感谢您抽出时间查看我的问题。
更新 1 - 11/3/2010 上午9:56
我在这里找到了一个好的参考资料:
汇编语言源代码中的段 - 使用 .text、.data 和 .bss 指令构建文本和数据段
更新 2 - 11/3/2010 上午10:09
@Michael
  1. 我在汇编代码中定义了一个100字节的未初始化数据区,这100个字节没有存储在我的可执行文件中,因为它们没有被初始化。

  2. 谁会在RAM中分配这100个字节的未初始化内存空间?是程序加载器吗?

假设我有以下代码:

int global[100];

void main(void)
{
   //...
}

全局变量 global[100] 未被初始化。在我的可执行文件中,global[100] 将如何被记录?由谁在什么时候分配?如果它被初始化会怎样?

3
通常还有一个 .rdata 段用于存放 const 变量(抱歉使用了矛盾修辞法)。 - ruslik
关于 https://dev59.com/LnA75IYBdhLWcg3weY1f - zneak
2
void main既不是合法的C语言,也不是合法的C++语言。main函数的返回类型必须始终为int - Konrad Rudolph
4个回答

11

已初始化的变量值存储在可执行文件的 .data 段中。未初始化的变量则可以不存储,它们最终会被放到 RAM 的 .bss 段中,但是在可执行文件中,这个段的大小为零,只有所需的内存量存储在段描述符中。.text 部分的代码通过偏移量访问这些变量。 运行时链接器加载器 将这些引用修补为实际的 虚拟地址。例如,大多数类 Unix 操作系统使用的可执行与可链接格式


非常具体于平台的答案,不提及该事实。 - Andrey
内存是平坦的,没有分段。 - Andrey
我一直有一个疑问困扰着我:如果我的可执行文件中未初始化的数据没有存储,操作系统如何知道在运行时分配什么到RAM中? - smwikipedia
2
@Andrey,是的,虚拟地址空间在实际上是平坦的 :) 然后有MMUs、页面、TLBs、高速缓存、NUMA等等。进程VA空间仍然被分区。这就是为什么你会得到分段违规 :) - Nikolai Fetissov
1
@smwikipedia,请阅读ELF规范(或COFF,或其他规范)- 可执行文件存储了.bss大小 - Nikolai Fetissov
显示剩余3条评论

3
在PE文件中,每个段都有两个指定的大小:RAWsize(磁盘上的大小)和Vsize(RAM中的大小)。
当Vsize大于RAWsize时,RAM中的段的其余部分将被清零。
.bss(如果存在)始终具有0的RAWsize,并且未初始化的全局变量位于其中。
另一种常见的方法是使.data的Vsize大于其RAWsize,以便该段的其余部分将包含未初始化的变量。

这有点像悖论。虽然.bss段的RAWsize为0,但.bss段实际上在磁盘上占用空间。否则,就无法记录.bss段的任何线索(我将其称为元线索)。 - smwikipedia
1
ELF工作方式相同;通常“.bss”部分只是与“.data”相同段的一部分,在“filesiz”后面的部分,但在“memsiz”内(例如:使用“readelf -a /bin/ls”进行查看:查找一个具有RW权限和memsiz大于filesiz的段)。 - Peter Cordes

2
您的计算机在程序加载时由操作系统连接器/装载器在虚拟内存中分配全局变量的存储空间。实际的全局变量存储位置位于物理内存层次结构中(高速缓存,RAM内存,SSD/HD后备存储等),由高速缓存和虚拟内存系统映射。这可能会导致存储空间出现碎片。
初始化的全局变量的值从.data段复制到已分配虚拟内存的一部分中。未初始化的全局变量可能会被清零,或者可能会留下垃圾值,这取决于程序运行的特定操作系统的安全性。
还有其他变种,这取决于语言,编译器,语言运行时和操作系统。

感谢您简明扼要的回复,让我更加清晰地了解了事情。从概念上讲,操作系统加载器根据进程的支持可执行文件来布置进程的虚拟地址空间。如果是这样的话,未初始化数据的大小信息必须记录在可执行文件中,尽管其值尚未确定。我说得对吗? - smwikipedia
我认为我需要检查一些exe文件格式,例如PE,以查看事情是否按照我的预期进行。 - smwikipedia
@smwikipedia,静态编译语言可以在二进制文件中储存数据大小(如果在编译时已知)。但也存在动态和解释性语言,在执行过程中直到出现全局变量才分配空间并修复链接。 - hotpaw2
你的回复解释了全局变量何时被分配,这对我非常有帮助。 - smwikipedia

0

未初始化的变量在机器级别上只是指针。它们的空间是在运行时分配的,程序将在稍后的某个时间填充它。

例如,如果在汇编语言中创建全局变量global BYTE 100,那么将保留global作为指向100字节区域的指针。然后程序可以访问该区域以满足其需要。

编辑:我查了一下我的汇编书,发现未初始化的全局变量与初始化的变量一样在.data部分中定义。据我所知,在exe文件中分配了空间(如上面的100字节),但内容是未定义的。在Windows的Intel计算机上,它将成为垃圾;程序负责初始化它。希望这会有所帮助!


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接