5

我试图更多地了解可执行文件的“公共”部分,我注意到在编译代码时,我可以看到仅在目标文件( )而不是可执行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”部分吗?

4

1 回答 1

6

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

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

从 gcc 手册上-fcommon/-fno-common

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

因此,-fno-common或者-fcommon只有在调用多个全局变量时才会有所作为i[并且它们应该具有相同的大小,或者您的程序变得无效,这比未定义的行为差一级!]

于 2013-02-12T19:28:35.500 回答