Linux size 命令,为什么 bss 和 data 部分不为零?

9
我发现了一个名为size的命令,它可以给出ELF文件中某个部分的大小。在尝试使用该命令时,我为最简单的C++程序创建了一个输出文件:
int main(){return 0;}

显然我没有定义任何已初始化或未初始化的数据,那么为什么我的BSS和DATA段大小分别为512和8字节?

我认为这可能是因为int main(),我尝试为下面的C程序创建目标文件:

void main(){}

我还是不理解BSS和DATA段的0值。

是因为这些段被分配了一定大小的内存吗?

编辑- 我原本认为这可能是由于链接库所致,但我的对象是动态链接的,所以这可能不是问题。


3
编译器会链接一个用于C运行时的静态库,其中包含真正调用main()函数的入口点。你可以使用objdump --disassemble命令查看真正的入口点函数。objdump -f命令将显示包括“起始地址”在内的信息。 - sourcejedi
当我在对象上运行objdump时,我看到了一些链接的库,file a.out的输出表明它是动态链接的ELF,因此我认为没有静态链接的库,但我想我错了。 - Time Traveller
1
相关链接:https://unix.stackexchange.com/questions/419697/why-are-true-and-false-so-large/419704#419704 和 https://unix.stackexchange.com/questions/418354/understanding-what-a-linux-binary-is-doing/418357#418357 - Rui F Ribeiro
1
用-g编译它,并在其上运行nm - 您将看到elf文件中的所有符号。 - filo
2个回答

11

int main(){return 0;} 把数据放在 .text 区块中。

$ echo 'int main(){return 0;}' | gcc -xc - -c -o main.o && size main.o
   text    data     bss     dec     hex filename
     67       0       0      67      43 main.o

你可能正在对一个完全链接的可执行文件进行大小估计。

$ gcc main.o -o main && size main
   text    data     bss     dec     hex filename
   1415     544       8    1967     7af main

10
实际上,如果您使用的是与二进制文件连接的libc进行编译,则会在main()函数之前(和之后)添加一些函数。它们主要用于加载动态库(即使在您的情况下不需要),并在main()结束时正确卸载它。

这些函数具有需要存储的全局变量;BSS段中未初始化(零初始化)的全局变量和DATA段中初始化的全局变量。

这就是为什么您将始终在所有使用libc编译的二进制文件中看到BSS和DATA。如果您想摆脱它,那么您应该编写自己的汇编程序,像这样(asm.s):

.globl _start
 _start:
    mov %eax, %ebx

然后,在没有libc的情况下进行编译:

$> gcc -nostdlib -o asm asm.s

你应该将这个ELF二进制文件的占用空间缩小到BSS和DATA段。


谢谢!我找到了我的错误,是时候复习一下gcc和链接库的概念了。 - Time Traveller
1
没问题,这个领域很广阔!你得从某个地方开始!祝你好运,继续加油! :) - perror
请更加精确:"这些函数使用了一点从BSS和DATA段中获取的内存。" 更好地表述为 "这些函数具有需要存储的全局变量;未初始化(零初始化)的全局变量位于BSS段中,而初始化的全局变量位于DATA段中"。 - Paul Ogilvie

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接