维基百科提到"bss部分通常包括在文件范围内声明的所有未初始化的变量." 给出以下文件:
int uninit;
int main() {
uninit = 1;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
当我将其编译为可执行文件时,我看到正确填充了bss段:
$ gcc prog1.c -o prog1
$ size prog1
text data bss dec hex filename
1115 552 8 1675 68b prog1
Run Code Online (Sandbox Code Playgroud)
但是,如果我将其编译为目标文件,我看不到bss段(我希望它是4):
$ gcc -c prog1.c
$ size prog1.o
text data bss dec hex filename
72 0 0 72 48 prog1.o
Run Code Online (Sandbox Code Playgroud)
有什么明显的东西我不见了吗?
我使用的是gcc版本4.8.1.
如果我们readelf -s
用来查看符号表,我们会看到:
$ readelf -s prog1.o
Symbol table '.symtab' contains 10 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
1: 0000000000000000 0 FILE LOCAL DEFAULT ABS bss.c
2: 0000000000000000 0 SECTION LOCAL DEFAULT 1
3: 0000000000000000 0 SECTION LOCAL DEFAULT 3
4: 0000000000000000 0 SECTION LOCAL DEFAULT 4
5: 0000000000000000 0 SECTION LOCAL DEFAULT 6
6: 0000000000000000 0 SECTION LOCAL DEFAULT 7
7: 0000000000000000 0 SECTION LOCAL DEFAULT 5
8: 0000000000000004 4 OBJECT GLOBAL DEFAULT COM uninit <<<<
9: 0000000000000000 16 FUNC GLOBAL DEFAULT 1 main
Run Code Online (Sandbox Code Playgroud)
我们看到你的uninit
符号("变量")在这个阶段是一个"共同的"符号.它尚未"分配"给BSS.
有关"常用"符号的更多信息,请参阅此问题:"COM"在.symtab部分的Ndx列中的含义是什么?
一旦您的最终可执行文件链接在一起,它将按预期放入BSS.
您可以通过将-fno-common
标志传递给GCC 来绕过此行为:
$ gcc -fno-common -c bss.c
$ size bss.o
text data bss dec hex filename
72 0 4 76 4c bss.o
Run Code Online (Sandbox Code Playgroud)
相反,你可以标记uninit
为static
.这样,编译器就会知道没有其他.o
文件可以引用它,所以它不会是一个"通用"符号.相反,它会立即放入BSS,如您所愿:
$ cat bss.c
Run Code Online (Sandbox Code Playgroud)
static int uninit;
int main() {
uninit = 1;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
$ gcc -c bss.c
$ size bss.o
text data bss dec hex filename
72 0 4 76 4c bss.o
Run Code Online (Sandbox Code Playgroud)