c - 确定目标文件的 BSS 大小

标签 c gcc linker

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/

相关文章:

带有模板编译错误的 C++ 类

c - 不寻常的 C 函数声明

c - 如何强制从 tty 输入

c - ANSI C S-Linked List - deleteLast() 无法正常工作

android - 通过 Cygwin 在 Windows 上为 x86 Android 构建 Android NDK 工具链

c++ - c/c++ 编译器是否通过二次幂值将常量除法优化为移位?

c - libtomcrypt 的 RSA 签名验证失败

ruby - 我无法通过 rvm 安装 ruby

c - 在 C 中链接库

c++ - 链接器选项 -Bsymbolic