编译此代码时:
// external definitions
int value1 = 0;
static int value2 = 0;
gcc编译器生成以下程序集:
.globl value1
.bss
.align 4
.type value1, @object
.size value1, 4
value1:
.zero 4
.local value2
.comm value2,4,4
但是,当我将变量初始化为非零值时,例如:
// external definitions
int value1 = 1;
static int value2 = 1;
gcc编译器生成了以下代码:
.globl value1
.data
.align 4
.type value1, @object
.size value1, 4
value1:
.long 1
.align 4
.type value2, @object
.size value2, 4
value2:
.long 1
我的问题是:
发布于 2012-11-27 17:33:46
一般来说,bss
部分包含未初始化的值,而data
部分包含初始化的值。然而,gcc将初始化为0的值放入bss
部分,而不是data
部分,因为bss
部分无论如何在运行时都会被清零,因此在data
部分存储零没有太大意义,这节省了一些磁盘空间,来自人工gcc:
-fno- zero - initialized in- BSS如果目标支持BSS段,GCC默认会将初始化为零的变量放入BSS。这可以节省结果代码中的空间。此选项关闭了此行为,因为一些程序显式地依赖于进入数据部分的变量
我不知道为什么.comm
要与目标文件本地的静态存储一起使用,它通常用于声明公共符号,如果没有定义/初始化,这些符号应该由链接器与其他目标文件中具有相同名称的符号合并,这就是为什么在第二个示例中不使用它,因为变量是从as
manual初始化的
.comm声明了一个名为symbol的公共符号。在链接时,一个目标文件中的公共符号可以与另一个目标文件
中定义的或相同名称的公共符号合并
发布于 2012-11-27 17:55:26
第一种情况是因为您用零初始化值。这是C standard (第6.7.8节)的一部分,如果没有指定,全局整数将被初始化为0。因此,文件格式通过将二进制文件放在一个特殊的部分中来保持二进制文件更小:bss
。如果你看了一些ELF specification (在第I-15页),你会发现:
.bss此部分保存构成程序内存映像的未初始化数据。根据定义,当程序开始运行时,系统用零初始化数据。该节不占用任何文件空间,如节类型SHT_NOBITS所示。
在第一种情况下,编译器进行了优化。它不需要占用实际二进制文件中的空间来存储初始化器,因为它可以使用bss
段并免费获得您想要的段。
现在,有一个来自外部源的静态输入就有点有趣了(这通常不是这样做的)。但是,在正在编译的模块中,它不应该与其他模块共享,并且应该标记为.local
。我怀疑它这样做是因为没有为初始化器存储实际的值。
在第二个示例中,因为您已经给出了一个非零初始化器,所以它知道它驻留在初始化的数据段data
中。value1
看起来非常相似,但是对于value2
,编译器需要为初始化器预留空间。在这种情况下,不需要将其标记为.local
,因为它只需设置值并使用它即可。它不是全局的,因为没有针对它的.globl
语句。
顺便说一句,http://refspecs.linuxbase.org/是一个很好的地方,可以找到关于二进制格式之类的一些低级细节。
发布于 2012-11-27 17:36:46
BSS是包含在运行时初始化的数据的段,而as数据段包含在程序二进制中初始化的数据。
现在,无论是否在程序中显式完成,静态变量都是初始化的。但有两个单独的类别,初始化(DS)和未初始化(BSS)静态。
BSS中存在的所有值都是那些未在程序代码中初始化的值,因此当程序在运行时加载到0(如果是整数)时被初始化为0(如果是整数),null表示指针等。
因此,当你用0初始化时,这个值会被分配给BSS,在那里,任何其他赋值的值都会在数据段中分配变量。
一个有趣的结果是,在BSS中初始化的数据的大小将不会包括在程序二进制中,而是包括数据段中的数据。
尝试分配一个大型静态数组,并在程序中使用它。查看未在代码中显式初始化的可执行文件的大小。然后用非零值初始化它,如下所示
static int arr[1000] = {2};
在后一种情况下,可执行文件的大小将显著增大。
https://stackoverflow.com/questions/13580950
复制相似问题