linux下一个可执行文件各数据段分配

1. 文件格式:

现在PC平台流行的可执行文件格式,主要是Windows下的PE(Portable Executable)和Linux的ELF(Executable Linkable Format),它们都是COFF(Common file format)格式的变种。

目标文件就是源代码编译后但未进行链接的那些中间文件(Windows的.obj和Linux的.o),它跟可执行文件的内容与结构很相似,所以一般跟可执行文件格式采用一种格式存储。

动态链接库(Windows的.dll和Linux的.so)及静态链接库(Windows的.lib和Linux的.a)文件都按照可执行文件格式存储。

2. 文件内容:

目标文件中的内容包含编译后的机器指令代码,数据。还包括了链接时所需要的一些信息,比如符号表,调试信息,字符串等。
目标文件将这些信息按不同的属性,以“节(Section)”的形式存储,有时候也叫做“段(Segment)”,它们表示一个一定长度的区域。


(1)代码段(.text)
程序源代码编译后的机器指令

(2)数据段(.data)
已初始化了的全局变量和局部静态变量数据

(3).bss段(.bss)
未初始化的全局变量和局部静态变量

注:
未初始化的全局变量和局部静态变量默认值都为0,本来也可以被放在.data段,但是在目标文件中为它们分配空间是没有必要的。因此,统一放到.bss段,.bss段大小为0,不出现在目标文件中。而变量名以及变量的大小,与其他变量一样,放在了符号表(.symtab段)中。

(4)其他段
除了.text,.data,.bss这3个最常用的段之外,目标文件也有可能包含其他的段,用来保存与程序相关的其他信息。

例如:.symtab符号表,.debug调试信息,.dynamic动态链接信息,等等。

3. 详细分析:

(1)用GCC编译SimpleScriont.c得到了目标文件SimpleSection.o

$ gcc -c SimpleSection.c

(2)使用binutils的工具objdump来查看目标文件内部结构,-h显示各个段的基本信息

$ objdump -h SimpleSection.o

其中,Size表示段的长度,File off(File Offset)表示段所在的位置,
每个段第二行表示段的属性,例如,CONTENTS表示该段在文件中存在。
根据偏移地址我们就可以画出文件结构了。


我们看到,.bss段和.note.GNU-stack段在文件中都不存在。

(3)查看代码段

$ objdump -s -d SimpleSection.o

其中,
-s用于将所有段的内容以16进制的方式打印出来,
-d用于将所有包含指令的段反汇编。

段数据:


最左边一列是偏移量,中间4列是16进制内容,最右边一列是.text段的ASCII码形式。

反汇编结果:


对照反汇编结果,可以看到.text段里包含的正是SimpleSection.c里两个函数func1()和main()的机器指令。

(4)查看数据段


我们看到54000000(0x00000054)正好是全局变量global_init_var的值84,
55000000(0x00000055)正好是局部静态变量static_var的值85。

注:
.rodata段存放的是只读数据,一般是程序里面的只读变量和字符串常量。

(5).bss段
虽然在段的基本信息里,.bss段的大小为4字节,但是.bss段的数据为空,因此不占用目标文件的空间。

.bss段基本信息:


注:
程序中,未初始化的全局变量global_uninit_var和局部静态变量static_var2共占8字节空间,可是.bss段的大小只有4字节大小。原因是,有些编译器会将全局未初始化的变量放到.bss段,有些则不然,只是预留一个未定义的全局变量符号。因此,这里的4字节,指的是static_var2。

4. 符号表

链接的本质,就是把不同的多个目标文件粘合到一起。
每个函数或变量都必须有自己独特的名字,才能避免在链接过程中产生混乱。
在链接中,函数和符号统称为符号(Symbol),函数名或变量名称为符号名(Symbol Name)

每个目标文件都有一个相应的符号表(Symbol Table),记录了目标文件中用到的所有符号。每个符号都有一个对应的值,叫做符号值(Symbol Value),符号值可以是符号所对应的数据在段中的偏移量,也可以是该符号的对齐属性。

符号表保存在.symtab段中,信息如下:


第1列Num表示符号表数组的下标,第2列Value就是符号值,第3列Size为符号大小,第4列第5列分别为符号类型和绑定信息,第6列暂时忽略它,第7列Ndx表示该符号所属的段,最后一列,符号名称。

我们看到func和main的Ndx为1,表示代码段,因为.text在段表中的下标为1。

其中,段表信息如下:


printf这个符号,Ndx为UND(SHN_UNDEF),没有在SimpleSection.c中定义,是被引用的。

global_init_var是已初始化的全局变量,Ndx是3,定义在.data段,偏移量为0
static_var.1553是已初始化的局部静态变量,Ndx是3,定义在.data段,偏移量为4

global_uninit_var是未初始化的全局变量,Ndx是COM(SHN_COMMON)本身并没有在.bss段中。
static_var2.1534是未初始化的局部静态变量,Ndx是4,定义在.bss段,偏移量为0

对于类型为STT_SECTION的符号,名称并没有显示,它们是Ndx所示段的段名

SimpleSection.c这个符号表示编译单元的源文件名。



作者:何幻
链接:http://www.jianshu.com/p/9f981f6433d1
來源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值