赞
踩
这句话该怎么理解呢?
我们先创建一个main.c文件,如下所示。
#include <stdio.h>
int a[1000];
int b[1000] = {1};
int main()
{
printf("Hello!");
return 0;
}
在linux环境下用gcc main.c -o a.out
编译一下,得到可执行文件a.out。
使用ls -l a.out
命令和size a.out
查看a.out的段的大小以及占用的磁盘空间。
可见此时可执行文件a.out所占用的磁盘内存空间为12368个字节,而.bss
段显示的大小为4032个字节。
接下来将刚才的main.c
文件修改一下,为全局变量附上初值。
#include <stdio.h>
int a[1000] = {1};
int b[1000] = {1};
int main()
{
printf("Hello!");
return 0;
}
利用gcc编译再次生成可执行文件,并查看其占用的磁盘空间以及各段显示的大小。
可以看到可执行文件的大小增加了4000个字节,也正好是我们刚才初始化后的a[1000]的大小,并且时在.data
段增加了4000个字节,因此印证了将未初始化的全局变量储存在.bss
段是不会消耗磁盘空间的说法。
当程序加载到内存运行时,就会为.bss
段中的数据分配内存并且进行初始化了。
那么程序是如何知道该为我们未初始化的全局变量分配多大的空间的呢?
使用readelf -S a.out
查看可执行文件的段表,段表记录了每个段的名称、类型、地址、偏移、大小等信息。通过这个表中记录的.bss段的信息,系统就会知道加载程序去运行时,应该给我们存放在.bss段里的变量分配多大的内存了。下图为未初始化数组a时,.data和.bss的段信息,可以看到他们的size都是0xfc0 = 4032(dec)。
当我们将a数组进行初始化之后,将会发生以下变化,即将已经初始化后的数组a放进了.data
段,即0xfc0+4000(dec) = 0x1f60。
此外,在elf文件结构中,有一个字符串表.strtab
,里面存放的是elf文件中各个段的名字以及变量名等字符串,字符串表中记录了这些字符串以及对应的下标,需要用到这些字符串时,直接用偏移下标去取就行了。段表中存放的段的名字这一项,就是存的.strtab
中对应字符串的偏移。
通过readelf -s a.out
查看可执行文件的符号表,以47行的b为例,4000代表的是其大小,OBJECT表示其是个变量等。
(.strtab和.systab还不是很理解,后面再补!)
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。