C中的局部和静态变量

Lef*_*dis 18 c assembly static

编译时:

// external definitions
int value1 = 0;
static int value2 = 0;
Run Code Online (Sandbox Code Playgroud)

gcc编译器生成以下程序集:

.globl value1
        .bss
        .align 4
        .type   value1, @object
        .size   value1, 4
value1:
        .zero   4
        .local  value2
        .comm   value2,4,4
Run Code Online (Sandbox Code Playgroud)

但是,当我将变量初始化为零以外的值时,例如:

// external definitions
int value1 = 1;
static int value2 = 1;
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

我的问题是:

  1. 为什么在第一种情况下,值在bss段中分配,而在第二种情况下在数据段中.
  2. 为什么value2变量在第一种情况下定义为.local和.comm,而在第二种情况下不定义.

iab*_*der 11

一般来说,该bss部分包含未初始化的值,该data部分包含初始化值.但是,gcc将初始化为零的值放入bss节而不是data节中,因为bss无论如何该节在运行时被清零,在节中存储零没有多大意义data,这样可以节省一些磁盘空间. GCC:

-fno-zero-initialized-in-bss如果目标支持BSS部分,则GCC默认将初始化为零的变量放入BSS.这可以节省生成的代码中的空间.此选项会关闭此行为,因为某些程序明确依赖于转到数据部分的变量

我不确定为什么.comm用于对象文件本地的静态存储,它通常用于声明公共符号,如果没有定义/初始化,应该由链接器与其他名称相同的符号合并.目标文件,这就是为什么它没有在第二个例子中使用,因为变量是从手册中初始化的as

.comm声明一个名为symbol的公共符号.链接时,一个目标文件中的公共符号可以与另一个目标文件中的相同名称的已定义或公共符号合并

  • @lefty:这就是为什么在Stack Overflow上一个问两个问题不是一个好主意.你不能选择两个答案. (4认同)

Joh*_*ter 5

第一种情况是因为您将值初始化为零.它是C标准(第6.7.8节)的一部分,如果没有指定,则全局整数初始化为0.因此,文件格式通过将特殊部分置于以下位置来提供更小的二进制文件:bss.如果你看一些ELF规范(第I-15页),你会发现:

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

在第一种情况下,编译器进行了优化.它不需要占用实际二进制文件中的空间来存储初始化程序,因为它可以使用该bss段并免费获得所需的段.

现在,你有一个静态来自外部源的事实有点有趣(通常不会这样做).在编译的模块中,不应与其他模块共享,并应标记.local.我怀疑它是这样做的,因为没有为初始化程序存储的实际值.

在第二个示例中,因为您已经给出了非零初始化程序,所以它知道它位于初始化数据段中data. value1看起来非常相似,但是value2,编译器需要为初始化器保留空间.在这种情况下,它不需要标记为.local因为它可以只是放下值并完成它.它不是全球性的,因为它没有.globl声明.

BTW,http: //refspecs.linuxbase.org/ 是一个访问一些关于二进制格式等的低级细节的好地方.