Linux中ELF格式文件介绍
Linux中ELF格式文件介绍
ELF(Executable and Linkable Format)即可执行连接文件格式,是一种比较复杂的文件格式,但其应用广泛。与linux下的其他可执行文件(a.out,cof)相比,它对节的定义和gnu工具链对它的支持使它十分灵活,它保存的足够了系统相关信息使它能支持不同平台上的交叉编译和交叉链接,可移植性很强.同时它在执行中支持动态链接共享库。
通过本文,可以大致了解Linux系统中ELF格式文件的分类,组成,作用,以及其中包含的内容。另外后面介绍了几种常用的对elf文件进行操作的工具,并且对其使用进行简单举例,便于对elf文件有一个比较直观的理解。
主要内容:
[描述]
1 ELF文件简介
2 ELF文件格式
3 ELF的特性
[举例]
1 readelf工具
2 objcopy
3 objdump
4 nm
5 ldd
[其它]
[描述]
1 ELF文件简介
ELF(Executable and Linkable Format)即可执行连接文件格式,是Linux,SVR4和Solaris2.0默认的目标文件格式,目前标准接口委员会TIS已将ELF标准化为一种可移植的目标文件格式,运行于32-bit Intel体系微机上,可与多种操作系统兼容。分析elf文件有助于理解一些重要的系统概念,例如程序的编译和链接,程序的加载和运行等。
(1)ELF文件类型:
有三种类型的ELF文件:
a)可重定位文件:用户和其他目标文件一起创建可执行文件或者共享目标文件,例如lib*.a文件。
b)可执行文件:用于生成进程映像,载入内存执行,例如编译好的可执行文件a.out。
c)共享目标文件:用于和其他共享目标文件或者可重定位文件一起生成elf目标文件或者和执行文件一起创建进程映像,例如lib*.so文件。
(2)ELF文件作用:
ELF文件参与程序的连接(建立一个程序)和程序的执行(运行一个程序),所以可以从不同的角度来看待elf格式的文件:
a)如果用于编译和链接(可重定位文件),则编译器和链接器将把elf文件看作是节头表描述的节的集合,程序头表可选。
b)如果用于加载执行(可执行文件),则加载器则将把elf文件看作是程序头表描述的段的集合,一个段可能包含多个节,节头表可选。
c)如果是共享文件,则两者都含有。
(3)ELF文件总体组成:
elf文件头描述elf文件的总体信息。包括:
系统相关,类型相关,加载相关,链接相关。
系统相关表示:elf文件标识的魔术数,以及硬件和平台等相关信息,增加了elf文件的移植性,使交叉编译成为可能。
类型相关就是前面说的那三个类型。
加载相关:包括程序头表相关信息。
链接相关:节头表相关信息。
下面对其进行了详细的介绍。
2 ELF文件格式
2.1 ELF文件的类型
ELF文件主要有三种类型:
(1)可重定位文件:包含了代码和数据.可与其它ELF文件建立一个可执行或共享的文件:
(2)可执行文件:是可以直接执行的程序:
(3)共享目标文件:包括代码和数据,可以在两个地方链接。第一,连接器可以把它和其它可重定位文件和共享文件一起处理以建立另一个ELF文件;第二,动态链接器把它和一个可执行文件和其它共享文件结合在一起建立一个进程映像。
2.2 ELF文件的组织
ELF文件参与程序的连接(建立一个程序)和程序的执行(运行一个程序),编译器和链接器将其视为节头表(section header table)描述的一些节(section)的集合,而加载器则将其视为程序头表(program header table)描述的段(segment)的集合,通常一个段可以包含多个节。可重定位文件都包含一个节头表,可执行文件都包含一个程序头表。共享文件两者都包含有。为此,ELF文件格式同时提供了两种看待文件内容的方式,反映了不同行为的不同要求。
从链接的角度看,ELF文件从开始到结束,可以看成是如下组成的:
a)ELF文件头
b)程序头表(可选)
c)第1节,第2节,...,第n节,...
d)节头表
从执行的角度看,ELF文件从开始到结束,可以看成是如下组成的:
a)ELF文件头
b)程序头表
c)第1段,第2段,...,
d)节头表(可选)
2.3 文件头(Elf header)
Elf头在程序的开始部位,作为引路表描述整个ELF的文件结构,其信息大致分为四部分:一是系统相关信息,二是目标文件类型,三是加载相关信息,四是链接相关信息。
其中系统相关信息包括elf文件魔数(标识elf文件),平台位数,数据编码方式,elf头部版本,硬件平台e_machine,目标文件版本 e_version,处理器特定标志e_ftags:这些信息的引入极大增强了elf文件的可移植性,使交叉编译成为可能。目标文件类型用e_type的值表示,可重定位文件为1,可执行文件为2,共享文件为3;加载相关信息有:程序进入点e_entry.程序头表偏移量e_phoff,elf头部长度 e_ehsize,程序头表中一个条目的长度e_phentsize,程序头表条目数目e_phnum;链接相关信息有:节头表偏移量e_shoff,节头表中一个条目的长度e_shentsize,节头表条目个数e_shnum ,节头表字符索引e shstmdx。可使用命令"readelf -h filename"来察看文件头的内容。
文件头的数据结构如下:
typedef struct elf32_hdr{
unsigned char e_ident[EI_NIDENT];
Elf32_Half e_type;//目标文件类型
Elf32_Half e_machine;//硬件平台
Elf32_Word e_version;//elf头部版本
Elf32_Addr e_entry;//程序进入点
Elf32_Off e_phoff;//程序头表偏移量
Elf32_Off e_shoff;//节头表偏移量
Elf32_Word e_flags;/处理器特定标志
Elf32_Half e_ehsize;//elf头部长度
Elf32_Half e_phentsize;//程序头表中一个条目的长度
Elf32_Half e_phnum;//程序头表条目数目
Elf32_Half e_shentsize;//节头表中一个条目的长度
Elf32_Half e_shnum;//节头表条目个数
Elf32_Half e_shstrmdx;//节头表字符索引
}Elf32_Ehdr;
2.4 程序头表(program header table)
程序头表告诉系统如何建立一个进程映像.它是从加载执行的角度来看待elf文件.从它的角度看.elf文件被分成许多段,elf文件中的代码、链接信息和注释都以段的形式存放。每个段都在程序头表中有一个表项描述,包含以下属性:段的类型,段的驻留位置相对于文件开始处的偏移,段在内存中的首字节地址,段的物理地址,段在文件映像中的字节数.段在内存映像中的字节数,段在内存和文件中的对齐标记。可用"readelf -l filename"察看程序头表中的内容。程序头表的结构如下:
typedef struct elf32_phdr{
Elf32_Word p_type; //段的类型
Elf32_Off p_offset; //段的位置相对于文件开始处的偏移
Elf32_Addr p_vaddr; //段在内存中的首字节地址
Elf32_Addr p_paddr;//段的物理地址
Elf32_Word p_filesz;//段在文件映像中的字节数
Elf32_Word p_memsz;//段在内存映像中的字节数
Elf32_Word p_flags;//段的标记
Elf32_Word p_align;,/段在内存中的对齐标记
)Elf32_Phdr;
2.5节头表(section header table)
节头表描述程序节,为编译器和链接器服务。它把elf文件分成了许多节.每个节保存着用于不同目的的数据.这些数据可能被前面的程序头重复使用,完成一次任务所需的信息往往被分散到不同的节里。由于节中数据的用途不同,节被分成不同的类型,每种类型的节都有自己组织数据的方式。每一个节在节头表中都有一个表项描述该节的属性,节的属性包括小节名在字符表中的索引,类型,