为什么常见的部分变量只出现在目标文件而不是可执行文件中?

时间:2013-02-12 19:21:01

标签: c gcc objdump compiler-flags

我试图更多地了解"常见"可执行文件的一部分,我注意到在编译代码上执行objdump时,我只能看到公共代码中的变量只放在目标文件(*.o)而不是可执行文件上。

为什么?

//test.c

int i[1000];
int main(){return 0;}

构建命令:

> gcc -g0 -fcommon -c test.c
> gcc -g0 -fcommon test.c

objdump在符号表的公共部分显示i

> objdump -x test.o
  ...
  SYMBOL TABLE:
  ...
  00000fa0    O   *COM*   00000020  i

除非我在可执行文件上运行它:

> objdump -x a.out
  ...
  SYMBOL TABLE:
  ...
  0804a040 g  O   .bss    00000fa0  i

如果我使用-fno-common标志重建目标文件,而不是像.bss段一样显示在可执行文件上。最终的可执行文件是否没有这个" COMMON"部?

1 个答案:

答案 0 :(得分:6)

常见部分是链接器知道的内容。它基本上将所有common内容放入[典型]可执行文件所具有的三个或四个实际部分之一(代码或文本,数据,bss - 有时也有一个rodata)。

因此,在这种情况下,您的变量最终会以.bss结尾,因为它们未初始化。

来自-fcommon / -fno-common

的gcc手册
  

在C代码中,控制未初始化的全局变量的放置。   Unix C编译器传统上允许多个定义   通过放置变量,在不同的编译单元中的这些变量   在一个共同的块中。这是-fcommon指定的行为,而且是   大多数目标上GCC的默认值。另一方面,这种行为   ISO C不要求,并且某些目标可能带有速度或   变量引用的代码大小惩罚。 -fno-common选项   指定编译器应放置未初始化的全局   对象文件的数据部分中的变量,而不是   将它们生成为公共块。这具有如果相同的效果   变量在两个不同的编译中声明(没有extern),   链接它们时会出现多重定义错误。在这种情况下,   你必须使用-fcommon进行编译。用-fno-common编译是   对于提供更好性能的目标有用,或者如果你有用   希望验证该程序将始终适用于其他系统   以这种方式处理未初始化的变量声明。

因此,如果有多个名为-fno-common的全局变量,则-fcommoni只会有所不同[并且它们的大小应相同,否则您的程序将无效,这比未定义的行为更糟​​糕!]