一般C语言编译后的执行语句都编译成及其代码,保存在.text段;已初始化的全局变量和局部静态变量都保存在.data段;未初始化的全局变量和局部静态变量一般放在.bss段里。我们知道未初始化的全局变量和局部静态变量默认都是0,本来他们可以存放在.data段中,但它们的值都为0,放在.data段中是没必要的。程序运行的时候它们的确要占空间,并且可执行文件必须记录所有未初始化的全局变量和局部静态变量的大小综合,记为.bss段。所以.bss段只是为未初始化的全局变量和局部静态变量预留位置而已,它并没有内容,所以它在文件中不占据空间。


BSS用于为符号预留一块内存空间

test.c

#include <stdio.h>

int global_init_var=84;
int global_uninit_val;

void func1(int i)
{
    printf("%d\n",i);
}

int main()
{
    static int static_var=85;
    static int static_var2;

    int a=1;
    int b;

    func1(static_var+static_var2+a+b);

    return a;
}

用命令  objdump -h test.o  查看

wKioL1cfUXOxOQlkAABOtQn-TaM990.png

从结果来看,目标文件除了最基本的代码段、数据段、BSS段,还有3个端分别是只读数据端(.rodata)、注释信息段(.comment)和堆栈提示段(.note.GNU-stack)

从图中可看出,每段的第二行中的CONTENTS,ALLOC等表示段的各种属性,“CONTENTS”表示该段在文件中存在,可以看到BSS段中没有CONTENTS,表示实际上在ELF文件中不存在,而.note.GNU-stack中有CONTENTS,但长度为0,所以暂且认为它在ELF文件中不存在,那么,ELF文件中实际存在的就是.text、.data、.bss、.comment四个段了


有一种命令size,可用来查看ELF文件的代码段、数据段和BSS段的长度

wKioL1cfVHbCJgFeAAAPGo-FiGU669.png


数据段和只读段

.text段保存了已初始化的全局变量和局部静态变量。前面test.c文件里一共有两个这样的变量(global_var和static_var)。这两个变量一共8个字节,所以.data这个段大小为8个字节


我们在调用printf的时候,用到了一个字符串常量"%d\n",存放在.rodata这个段,大小为4个字节。


.rodata段存放的是只读数据,一般存放的是程序的只读变量(如const修饰的变量)和字符串常量。

值得一提的是有时候编译器会把字符串常量放到.data段中,而不会单独放在.rodata段

BSS段

.bss段存放的是未初始化的全局变量和局部静态变量,如上述代码中global_uninit_var和static_var2就放在.bss段中,更准确的说是.bss段为它们预留了空间,我们可以看到.bss段的大小为4个字节,但这两个变量的大小总和却为8.

可通过符号表(symbol table)看到,只有static_var2被存放在了.bss段,而global_uninit_var却没有被存放在任何段,只是一个为定义的"COMMON"符号。

值得一提的是编译单元内部可见的静态变量(比如给global_uninit_var加上static修饰)的却是放在.bss段的




                               ----------------------摘自程序员的自我修养