记录Git的一些使用

bss段 : BSS段属于静态内存分配。通常是指用来存放程序中未初始化的全局变量和未初始化的局部静态变量。未初始化的全局变量和未初始化的局部静态变量默认值是0,本来这些变量也可以放到data段的,但是因为他们都是0,所以为他们在data段分配空间并且存放数据0是没有必要的。 程序在运行时,才会给BSS段里面的变量分配内存空间。在目标文件(*.o)和可执行文件中,BSS段只是为未初始化的全局变量和未初始化的局部静态变量预留位置而已,它并没有内容,所以它不占据空间。 section table中保存了BSS段(未初始化的全局变量和未初始化的局部静态变量)内存空间大小总和。(objdump -h *.o 命令可以看到)

data段 :

数据段(datasegment)通常是指用来存放程序中已初始化的全局变量和已初始化的静态变量的一块内存区域。数据段属于静态内存分配。

1

BSS段(Started by Symbol)通常是指用来存放程序中未初始化的全局变量和静态变量的内存区域。

问1:同样是全局变量和静态变量,为什么要区分data与BSS?

原因是为了节省目标文件体积,因为未初始化的全局变量和静态变量默认初值为0,我们都知道了,就没必要 存放在二进制文件空间里,只需要描述一下这个BSS区域占了多大(相当于预约这块空间,运行时再分配给我),这是编译阶段所采用的措施;

问2:那对于代码里引用到这些变量地址怎么处理?

引用变量的实际形式都是内存地址,对于属于BSS段的变量,编译器正常设置变量的地址(不管这地址有没存放东西),处理规则没有特别的不同。

问3:那我运行时需要赋值或引用这些全局变量的值怎么找到它们?

虽然目标文件里没有储存BSS段(只描述大小信息),但程序运行时,要根据这个描述来分配运行内存,同时要把BSS段的内存清零(这也是为什么 未初始化的全局变量和静态变量默认值为0),此时BSS真正占据内存空间;程序的加载与清零动作由加载器来完成。

作者:Anson
链接:https://www.zhihu.com/question/23059602/answer/2421277304
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

2

BBS段

http://en.wikipedia.org/wiki/BSS_segment

通常是指用来存放程序中未初始化的全局变量和静态变量的内存区域(段,Segment)。

在一些常见的编译器里,通常对BBS段的处理方法是:只描述大小,不增加目标文件的体积。

因为变量实际都是内存地址,所以对于属于BSS段的变量,编译器正常设置变量的地址,处理规则没有特别的不同。

负责将BSS段清零的工作一般是由加载器完成的,当一个可执行文件被加载的时候,加载器(可以简单的理解为操作系统)负责把BSS段的内存清零。

一个简单的验证方法,下面的代码:

int bss[655360];

int main(int argc, char* argv[])
{
    bss[1] = -1;
    return 0;
}

不开优化,目标文件大小远远小于655360个int,但如果给bss赋初值:

int bss[655360] = {-1};
 cat x.c
long long int bss[955360];


int main()
{
    bss[1] = -1;
    return 0;
}


 tgcc -c -O0 x.c -o before.o


 vi x.c


 cat x.c
/* long long int bss[955360]; */
long long int bss[955360]={-1};


int main()
{
    bss[1] = -1;
    return 0;
}


 tgcc -c -O0 x.c -o after.o


 ls -al *.o
-rw-r--r--  1 yonghaohu  wheel  7643552  2 16 11:56 after.o
-rw-r--r--  1 yonghaohu  wheel      592  2 16 11:56 before.o

目标文件瞬间变大。

3

CSAPP "bss 是请求二进制零的,映射到匿名文件."加载器只是将bss区域映射到匿名文件,当cpu引用该区域的虚拟页面时,再发生页面调度(内存中找一个牺牲页),用二进制零覆盖牺牲页面,实际上和内存与磁盘之间并没有传送交互数据.所以,bss 的初始化实际上是在运行时.

``