Wikipedia提到" bss部分通常包括在文件范围内声明的所有未初始化的变量。"给出以下文件:
int uninit;
int main() {
uninit = 1;
return 0;
}
当我将其编译为可执行文件时,我看到正确填充了bss段:
$ gcc prog1.c -o prog1
$ size prog1
text data bss dec hex filename
1115 552 8 1675 68b prog1
但是,如果我将其编译为目标文件,我就不会看到bss段(我希望它是4):
$ gcc -c prog1.c
$ size prog1.o
text data bss dec hex filename
72 0 0 72 48 prog1.o
我有什么明显的遗失吗?
我正在使用gcc版本4.8.1。
答案 0 :(得分:7)
如果我们使用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
我们发现您的uninit
符号(&#34;变量&#34;)在此阶段是一个常见的&#34;符号。它尚未被分配&#34;到BSS。
有关&#34;常见&#34;的更多信息,请参阅此问题。符号:What does "COM" means in the Ndx column of the .symtab section?
将最终的可执行文件链接在一起后,它将按预期放入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
相反,您可以将uninit
标记为static
。通过这种方式,编译器将知道没有其他.o
文件可以引用它,因此它不会是&#34; common&#34;符号。相反,它会立即按照您的预期放入BSS:
$ cat bss.c
static int uninit;
int main() {
uninit = 1;
return 0;
}
$ gcc -c bss.c
$ size bss.o
text data bss dec hex filename
72 0 4 76 4c bss.o