我试图更多地了解"常见"可执行文件的一部分,我注意到在编译代码上执行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"部?
答案 0 :(得分:6)
常见部分是链接器知道的内容。它基本上将所有common
内容放入[典型]可执行文件所具有的三个或四个实际部分之一(代码或文本,数据,bss - 有时也有一个rodata)。
因此,在这种情况下,您的变量最终会以.bss结尾,因为它们未初始化。
来自-fcommon
/ -fno-common
在C代码中,控制未初始化的全局变量的放置。 Unix C编译器传统上允许多个定义 通过放置变量,在不同的编译单元中的这些变量 在一个共同的块中。这是-fcommon指定的行为,而且是 大多数目标上GCC的默认值。另一方面,这种行为 ISO C不要求,并且某些目标可能带有速度或 变量引用的代码大小惩罚。 -fno-common选项 指定编译器应放置未初始化的全局 对象文件的数据部分中的变量,而不是 将它们生成为公共块。这具有如果相同的效果 变量在两个不同的编译中声明(没有extern), 链接它们时会出现多重定义错误。在这种情况下, 你必须使用-fcommon进行编译。用-fno-common编译是 对于提供更好性能的目标有用,或者如果你有用 希望验证该程序将始终适用于其他系统 以这种方式处理未初始化的变量声明。
因此,如果有多个名为-fno-common
的全局变量,则-fcommon
或i
只会有所不同[并且它们的大小应相同,否则您的程序将无效,这比未定义的行为更糟糕!]