27

从我的书中:

.bss:

未初始化的全局 C 变量

常见的:

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

我不得不说,我并没有看到明显的区别。我什至不太明白什么是未初始化、未分配的数据对象……似乎什么都没有。我使用 GNU 的readelf工具尝试查看一些简单的 C 代码,但找不到单个常见符号。我读过诸如 FORTRAN 的 COMMON 类型是 COMMON 符号的示例之类的东西 - 但我不知道 FORTRAN

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

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

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

应该是常见的。但是使用objdump -t显示c在.bss中对我来说......

使困惑

4

4 回答 4

25
// file a.c
// file-scope

int a = 0;  // goes into BSS

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

// file b.c
// file-scope

int b;  // goes into COMMON section

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

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

于 2013-05-30T12:26:24.730 回答
15

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
$

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

$ 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
$

这是可怕的东西,与古老的系统兼容,你永远不应该依赖它。正确地做事——所有编译单元中只有一个全局变量定义,通过头文件在其他任何地方声明它。

于 2013-05-30T12:24:47.857 回答
9

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

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

PS:如果您使用gcc,您可以使用选项将符号-fno-common强制到该部分,正如 Art 认为的那样,这是一种很好且可取的做法。commonbss

于 2013-05-30T12:26:31.637 回答
-1

静态变量最终位于 .bss 部分。未初始化的全局变量(非静态)位于 .common 部分。

static a;  //bss
int c;   //.common
main(){
}
于 2013-05-30T12:30:05.680 回答