.bss vs COMMON:到底是什么?

gon*_*one 19 c linker elf

从我的书:

.bss段:

未初始化的全局C变量

共同:

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

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

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

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

int c;
int main() {} ...
Run Code Online (Sandbox Code Playgroud)

应该是COMMON.但是使用objdump -t节目给我说c在.bss中......

困惑

oua*_*uah 18

// file a.c
// file-scope

int a = 0;  // goes into BSS
Run Code Online (Sandbox Code Playgroud)

编译a.c成目标文件后a.o,a符号进入BSS部分.

// file b.c
// file-scope

int b;  // goes into COMMON section
Run Code Online (Sandbox Code Playgroud)

编译b.c成目标文件后b.o,b符号进入COMMON部分.

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

  • `int a = 0;`不一定进入.bss.这实际上是gcc的最新变化.将某些内容初始化为0用于强制符号转换为较旧的gcc版本中的数据,并且经常在需要编辑二进制文件的同时将初始化变量保持为0时使用.内核通常使用(ab).还要注意,公共区域不一定要进入bss,可能会有一堆公共分解成数据部分中的符号. (5认同)

Art*_*Art 13

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

以下是它的工作原理:

$ cat > a.c
int foo;
$ cat > b.c
int foo;
$ cat > main.c
extern int foo;
int main(int argc, char **argv) { return foo; }
$ cc -c a.c && cc -c b.c && cc -c main.c && cc -o x a.o b.o main.o
$ objdump -t a.o | grep foo
0000000000000004       O *COM*  0000000000000004 foo
$ objdump -t b.o | grep foo
0000000000000004       O *COM*  0000000000000004 foo
$ objdump -t x | grep foo
0000000000600828 g     O .bss   0000000000000004              foo
$
Run Code Online (Sandbox Code Playgroud)

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

$ echo "int foo = 0;" > a.c
$ cc -c a.c && cc -c b.c && cc -c main.c && cc -o x a.o b.o main.o
$ echo "int foo = 0;" > b.c
$ cc -c a.c && cc -c b.c && cc -c main.c && cc -o x a.o b.o main.o
b.o:(.bss+0x0): multiple definition of `foo'
a.o:(.bss+0x0): first defined here
collect2: ld returned 1 exit status
$
Run Code Online (Sandbox Code Playgroud)

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

  • @elinx Commons不是一个部分,而是在链接阶段放在右边部分的特别标记的符号.`readelf -S`转储部分.当您使用`readelf -s`转储符号时,Commons将显示出来. (2认同)

Bry*_*ier 9

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

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

PS:如果您使用,gcc您可以使用-fno-common选项强制common符号到该bss部分,这是艺术认为是好的和可取的做法.