ELF文件格式浅析

ELF文件格式浅析

概述

ELFExecutable Linkable Formatlinux操作系统下目标文件和可执行文件的文件格式,目标文件是指由源代码编译后但没有进行连接的中间文件(windows下的.objlinux下的.o),它跟可执行文件的格式基本上式一样的,只是在可执行文件中多了program headers program sections,它们在程序装载的时候要有到。本文主要分析目标文件的格式。

目标文件里有什么了?首先给出目标文件总体结构示意图,如图1所示。图1中我们省去了ELF一些繁琐的结构,把重要的结构提取出来,形成了图1所示的基本结构图。

                                                         

           图1  ELF文件结构

整个文件总体上由三部分组成:文件头(ELF header),段表(Section Header Table),各种段(Section)。由于编译器的不同,这些段在文件结构中的位置可能和上图所示的有些不一样,但是基本结构是相同。

这三部分作用什么,它们之间的联系又是什么呢?下面将对这三部分做具体的分析。

1.    ELF文件头

如果不深入到目标文件内部,是很理解其中的细节的,因此我们选用了下面一段小程序作为具体的分析对象,分析的平台式linux操作系统,程序名为elf.c,程序代码清单如下图所示。

                    

                                                                               2 程序代码

我们使用gcc来编译这个文件:

gcc –c elf.c –o elf.o

生成目标文件elf.o

我们使用readelf命令来查看文件头:

readelf –h elf.o

文件头内容如图3所示:

     

               图3 ELF文件头

文件头描述了整个文件的基本属性,其中定义了ELF魔数、文件机器字节长度、数据存储方式、版本、运行平台、ABI版本、ELF重定位类型、硬件平台、硬件平台版本、入口地址、程序头入口和长度、段表位置和长度,在这里我们看到由文件头可以确定段表在文件中的位置。

ELF文件头数据结构及相关常数定义在/usr/include/elf.h文件里,其定义如图4所示:

       

                         4  ELF文件头结构

ELF文件头数据结构跟前面readelf输出的ELF文件头信息相比较,可以看出它们的结构是一一对应的,其中e_inent[16]对应MagicClassDataVersionOS/ABI这五项,其他部分一一对应。

2.    ELF段表

从图1中我们可以看到,ELF文件中有很多各种各样的段,段表就是描述这些段的基本属性的结构,下面我们使用readelf工具来查看elf.o的段表结构:

readelf –S elf.o

段表的内容如下所示:

  

                                                                            5 段表的内容

从图4相中,我们可以发现,这个ELF文件有10个段,其实只要9个段,第一个段是个无效的段,段表描述了各个段的段名、类型、虚拟地址(目标文件各段的虚拟地址为0)在文件中的偏移位置、大小等详细信息。

段表的结构比较简单,它由“Elf32_Shdr”结构体数组组成,该结构定义在/usr/include/elf.h文件中,其结构如图6所示:

           

                                                                                      6 段表的结构

它和上图一一对应,Elf32_Shdr定义了段表的详细信息。

3.    ELF各种段

代码段,数据段就不用多说了,下面主要说说.shstrtab.symtab.strtabrel.text这几个段。

.shstrtab段是做什么用的呢?这个段里面存放的是各段的段名,比方说,.text.symtab等等这些都是段名, Elf32_Shdr结构中的第一个字段的就是段名,从这些段名可以看出,段名是个字符串,长短不一,无法用一个确定大小的字符数组表示,于是我们把所有的段名都放在一个段,即.shstrtab段,而通过段名在这个段中的偏移位置来得到段名字符串。

同样的,.strtab段和.shstrtab段的功能相似,它里面存放的是程序中出现的各种字符串,包括变量名,函数名等等。

我们知道,目标文件和可执行文件是通过不同的源文件经过编译、链接形成的,程序是以单个文件作为编译的基本单元,每个基本单元生成一个目标文件,再经过链接将这些目标文件组合成可执行程序或更大的目标文件,那么链接的桥梁就是符号表(.symtab)。符号表中记录了符号的类型,是变量还是函数等等;符号的绑定信息,是局部符号还是全局符号,是弱引用还是强引用;还有其他的一些与链接有关的信息。

既然有了符号表,我们还要rel.text这样的重定位段干什么呢?符号表不是都包含了链接信息了?符号表只是说明了各符号的信息,但是它并没有说明具体的链接信息,例如,我们main程序引用了外部变量extern_var,链接表中并没有说明这个符号在elf.o中的什么位置进行链接,链接时使用相对偏移地址还是决定地址,重定位段则说明了这些信息。

通过上面粗略的分析,我们大致的了解了目标文件里的内容,以及为什么有这些内容,他们在文件中的作用是什么,目标文件中的文件头是整个文件的大脑所在,文件头里有程序的入口地址(这个地址对可执行程序有意义),有段表在文件中的偏移,而段表又确定了各个段的位置,通过这些必要的说明,操作系统就可将可执行程序加载到正确的位置执行。

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值