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 版。
最佳答案
如果我们使用 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
符号(“变量”)在这个阶段是一个“普通”符号。它尚未“分配”给 BSS。
有关“常用”符号的更多信息,请参阅此问题: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
文件可以引用它,因此它不会是一个“通用”符号。相反,它将立即放入 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
关于c - 确定目标文件的 BSS 大小,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23334930/