.bss vs COMMON:到底是什么?

从我的书:

.bss段:

未初始化的全局C变量

共同:

尚未分配的未经初始化的数据对象

我不得不说,我看不出明显的区别。 我甚至不太明白什么是无限制的,未分配的数据对象……似乎什么也没有。 我使用GNU的readelf工具试着看一些简单的C代码,但是找不到一个COMMON符号。 我读过像FORTRAN的COMMON类型的东西是一个COMMON符号的例子 – 但我不知道FORTRAN

有人可以为我区分这两个吗? 如果可能的话,希望用C的例子? 非常感激。

编辑 :从这篇文章中,变量c在这里:

 int c; int main() {} ... 

应该是COMMON。 但是使用objdump -t显示c在.bss中…

困惑

 // file ac // file-scope int a = 0; // goes into BSS 

在将ac编译成目标文件ao ,符号进入BSS部分。

 // file bc // file-scope int b; // goes into COMMON section 

在将bc编译成目标文件bob符号进入COMMON部分。

在链接aoboab符号都进入BSS部分。 公共符号仅存在于目标文件中,而不存在于可执行文件中。 Unix中COMMON符号的思想是允许在特定条件下在单个公共符号下对同一变量(在不同编译单元中)的多个外部定义。

Commons仅出现在链接阶段之前。 Commons是后来进入bss或数据的东西,但由链接器来决定它的去向。 这允许您在不同的编译单元中定义相同的变量。 据我所知,这主要是为了允许一些具有int foo;古老头文件int foo; 在他们而不是extern int foo;

以下是它的工作原理:

 $ cat > ac int foo; $ cat > bc int foo; $ cat > main.c extern int foo; int main(int argc, char **argv) { return foo; } $ cc -c ac && cc -c bc && cc -c main.c && cc -ox ao bo main.o $ objdump -t ao | grep foo 0000000000000004 O *COM* 0000000000000004 foo $ objdump -t bo | grep foo 0000000000000004 O *COM* 0000000000000004 foo $ objdump -tx | grep foo 0000000000600828 g O .bss 0000000000000004 foo $ 

请注意,这仅在初始化不同编译单元中的至多一个变量时才有效。

 $ echo "int foo = 0;" > ac $ cc -c ac && cc -c bc && cc -c main.c && cc -ox ao bo main.o $ echo "int foo = 0;" > bc $ cc -c ac && cc -c bc && cc -c main.c && cc -ox ao bo main.o bo:(.bss+0x0): multiple definition of `foo' ao:(.bss+0x0): first defined here collect2: ld returned 1 exit status $ 

这是可怕的东西,与古代系统的兼容性,你永远不应该依赖它。 做得恰当 – 在所有编译单元中只有一个全局变量定义,通过标题将其声明为extern。

如果在链接期间允许common ,则不同的单元可以声明相同的变量,链接器将在同一位置定位它们。 这些类型甚至不需要相同,因此它是某种链接时间联合。 这是Fortran的COMMONfunction。 如果您不允许在链接C中使用common ,那么这种情况将导致链接时间错误。 这种common链接仅适用于未初始化的全局变量,因为否则不清楚应该采用哪种初始化。

转到bss的全局变量只是未初始化的全局变量,C定义为初始化为0.大多数对象格式支持只给出大小的部分,加载器将用零填充整个部分。

PS:如果您使用gcc您可以使用-fno-common选项强制将common符号强制为bss部分,因为Art认为这是一个很好且可取的做法。

静态变量最终出现在.bss部分。未初始化的全局变量(非静态)进入.common部分。

 static a; //bss int c; //.common main(){ }