我将静态变量初始化为0,但是当我看到汇编代码时,我发现只有内存分配给该变量。该值未分配
。当我将静态变量初始化为其他数字时,我可以发现内存已分配了一个值。
我猜想GCC是否认为应该在使用内存之前由OS将内存初始化为0。
我使用的GCC选项是“ gcc -m32 -fno-stack-protector -c -o”
当我将静态变量初始化为0时,C代码和汇编代码为:
static int temp_frOnt=0;
.local temp_front.1909 .comm temp_front.1909,4,4
当我将其初始化为其他数字时,代码为:
.local temp_front.1909 .comm temp_front.1909,4,4
.align 4 .type temp_front.1909, @object .size temp_front.1909, 4 temp_front.1909: .long 1
Michael Karc.. 9
TL:DR:GCC知道BSS保证在目标平台上被零初始化,因此它将零初始化的静态数据放在那里。
大图大多数现代操作系统的程序加载器对于程序的每个部分(如数据部分)都有两种不同的大小。它得到的第一个大小是可执行文件(例如Windows上的PE / COFF.EXE
文件或Linux 上的ELF可执行文件)中存储的数据大小,而第二个大小是程序运行时内存中数据部分的大小。 。
如果正在运行的程序的数据大小大于可执行文件中存储的数据量,则数据部分的其余部分将填充包含零的字节。在您的程序中,该.comm
行告诉链接器保留4个字节而不初始化它们,以便OS在启动时将它们零初始化。
gcc
(或任何其他C编译器)在本.bss
节中分配零静态存储持续时间的变量。该部分中分配的所有内容都将在程序启动时初始化为零。对于分配,它使用comm
伪指令,并且仅指定大小(4个字节)。
您可以使用size命令查看主要部分类型(代码,数据,bss)的大小。如果使用1初始化变量,则它将包含在一个data
节中,并在其中占据4个字节。如果将其初始化为零(或根本不初始化),则将其分配给.bss部分。
ld将所有目标文件的所有数据类型部分(甚至是静态库中的文件)合并到一个数据部分中,然后合并所有.bss
-type部分。可执行输出包含操作系统程序加载器的简化视图。对于ELF文件,这是“ 程序头 ”。您可以使用objdump -p
任意格式或readelf
ELF文件来查看它。
程序头包含不同类型的条目。其中有几个条目,其类型PT_LOAD
描述了操作系统要加载的“段”。这些PT_LOAD条目之一用于数据区(.data
链接该节的位置)。它包含一个条目p_filesz
,该条目指定在ELF文件中提供多少个用于初始化变量的字节,以及一个条目,p_memsz
告诉加载程序应该在地址空间中保留多少空间。关于哪些部分合并到链接器之间不同的PT_LOAD条目的细节取决于命令行选项,但是通常您会找到一个PT_LOAD条目,该条目描述了一个既可读又可写但不可执行的区域,其p_filesz
值是小于p_memsz
项(如果只有一个.bss
,则没有.data
节,则可能为零)。p_filesz
是所有读写数据部分的大小,而p_memsz
较大则还为零初始化变量提供了空间。
数量p_memsz
超过链接到可执行文件p_filesz
的所有.bss
部分的总和。(由于与页面或磁盘块的对齐,这些值可能会有些偏差)
有关程序头条目的说明,请参见System V ABI规范的第5章,尤其是第5-2和5-3页。
操作系统做什么?Linux内核(或另一个兼容ELF的内核)遍历程序头文件中的所有条目。对于每个包含类型的条目,PT_LOAD
它分配虚拟地址空间。它将地址空间的开头与可执行文件中的相应区域相关联,如果该空间可写,则启用写时复制。
如果p_memsz
超过p_filesz
,内核将剩余的地址空间安排为完全清零。因此,.bss
由gcc 在本节中分配的变量最终出现在ELF文件中的PT_LOAD读写条目的“尾部”中,内核提供了零。
任何没有备份数据的整页都可以从写时复制开始映射到共享的零物理页。
TL:DR:GCC知道BSS保证在目标平台上被零初始化,因此它将零初始化的静态数据放在那里。
大图大多数现代操作系统的程序加载器对于程序的每个部分(如数据部分)都有两种不同的大小。它得到的第一个大小是可执行文件(例如Windows上的PE / COFF.EXE
文件或Linux 上的ELF可执行文件)中存储的数据大小,而第二个大小是程序运行时内存中数据部分的大小。 。
如果正在运行的程序的数据大小大于可执行文件中存储的数据量,则数据部分的其余部分将填充包含零的字节。在您的程序中,该.comm
行告诉链接器保留4个字节而不初始化它们,以便OS在启动时将它们零初始化。
gcc
(或任何其他C编译器)在本.bss
节中分配零静态存储持续时间的变量。该部分中分配的所有内容都将在程序启动时初始化为零。对于分配,它使用comm
伪指令,并且仅指定大小(4个字节)。
您可以使用size命令查看主要部分类型(代码,数据,bss)的大小。如果使用1初始化变量,则它将包含在一个data
节中,并在其中占据4个字节。如果将其初始化为零(或根本不初始化),则将其分配给.bss部分。
ld将所有目标文件的所有数据类型部分(甚至是静态库中的文件)合并到一个数据部分中,然后合并所有.bss
-type部分。可执行输出包含操作系统程序加载器的简化视图。对于ELF文件,这是“ 程序头 ”。您可以使用objdump -p
任意格式或readelf
ELF文件来查看它。
程序头包含不同类型的条目。其中有几个条目,其类型PT_LOAD
描述了操作系统要加载的“段”。这些PT_LOAD条目之一用于数据区(.data
链接该节的位置)。它包含一个条目p_filesz
,该条目指定在ELF文件中提供多少个用于初始化变量的字节,以及一个条目,p_memsz
告诉加载程序应该在地址空间中保留多少空间。关于哪些部分合并到链接器之间不同的PT_LOAD条目的细节取决于命令行选项,但是通常您会找到一个PT_LOAD条目,该条目描述了一个既可读又可写但不可执行的区域,其p_filesz
值是小于p_memsz
项(如果只有一个.bss
,则没有.data
节,则可能为零)。p_filesz
是所有读写数据部分的大小,而p_memsz
较大则还为零初始化变量提供了空间。
数量p_memsz
超过链接到可执行文件p_filesz
的所有.bss
部分的总和。(由于与页面或磁盘块的对齐,这些值可能会有些偏差)
有关程序头条目的说明,请参见System V ABI规范的第5章,尤其是第5-2和5-3页。
操作系统做什么?Linux内核(或另一个兼容ELF的内核)遍历程序头文件中的所有条目。对于每个包含类型的条目,PT_LOAD
它分配虚拟地址空间。它将地址空间的开头与可执行文件中的相应区域相关联,如果该空间可写,则启用写时复制。
如果p_memsz
超过p_filesz
,内核将剩余的地址空间安排为完全清零。因此,.bss
由gcc 在本节中分配的变量最终出现在ELF文件中的PT_LOAD读写条目的“尾部”中,内核提供了零。
任何没有备份数据的整页都可以从写时复制开始映射到共享的零物理页。