ELF文件主要有三种类型: (1)可重定位文件包含了代码和数据.可与其它ELF文件建立一个可执行或共享的文件. (2)可执行文件时可直接执行的程序. (3)共享目标文件包括代码和数据.
这里主要分析一下第1种ELF的文件格式,这东西主要由ELF文件头和具体的各个节区组成.我们
可以通过readelf命令来详细查看ELF文件的各个节区.下面简要介绍一下各个部分的结构
1.ELF文件头
内核中对ELF文件头
的结
构(32位机)定义在include/linux/Elf.h中
#define EI_NIDENT 16
typedef struct elf32_hdr{ unsigned char e_ident[EI_NIDENT]; Elf32_Half e_type; Elf32_Half e_machine; Elf32_Word e_version; Elf32_Addr e_entry; /* Entry point */ Elf32_Off e_phoff; Elf32_Off e_shoff; Elf32_Word e_flags; Elf32_Half e_ehsize; Elf32_Half e_phentsize; Elf32_Half e_phnum; Elf32_Half e_shentsize; Elf32_Half e_shnum; Elf32_Half e_shstrndx; } Elf32_Ehdr; |
ELF文件头用来描述整个文件的组织,对可重定位的目标文件而言重要的字段有:文件类型
(
e_type)
,节区头部偏移(
e_shoff
),文件头大小(e_ehsize),节区头部表表项的大小
(e_shentsize),表项的个数(e_shnum),以及链接的字符节区的索引(e_shstrndx)等信息
2.各个节区
A.节区头部表
节区头部表中包含若干个表项,每一个表项都是对本ELF文件中的某个节区的描述,
下面是内核中定义的节区头部表项的数据结构
typedef struct { Elf32_Word sh_name; Elf32_Word sh_type; Elf32_Word sh_flags; Elf32_Addr sh_addr; Elf32_Off sh_offset; Elf32_Word sh_size; Elf32_Word sh_link; Elf32_Word sh_info; Elf32_Word sh_addralign; Elf32_Word sh_entsize; } Elf32_Shdr |
其中sh_name是被描述的节区的名字,这个值实际是 字符串节区的索引,可以理解为指向
实际的名字的指针;sh_type是节区的类型,一般有字符串节区,符号节区,重定位节区等;sh_flags
表示的是此节区中包含的内容是修改(SHF_WRITE),执行(SHF_EXECINSTR)或分配空间
(SHF_ALLOC);
sh_offset和sh_size是定位被描述的节区在此ELF文件中的位置和大小;sh_link一般
表示被描述的节区需要链接的其他节区的索引,这个字段和sh_info一样根据具体的节区被用于表示不
同的含义.
B.字符串表 (sh_type=SHT_STRTAB)
此节区 就是把ELF中将要用到的字符串以'\0'分隔,存到一个连续的区域而成的.
其他节区中需要表示字符串时 一律用字符串表的索引来表示.值得注意的是字符串表可能有多个,因
此其他节区在引用字符串时不只要提供表内的索引,而且还需要提供表的索引.
C.符号表(sh_type=SHT_SYMTAB)
ELF文件为符号表由一个个符合表项构成,每个符号表项用来定位、重定位程序中
符号定义和引用的信息,符号表项数据结构如下
typedef struct elf32_sym{ Elf32_Word st_name; Elf32_Addr st_value; Elf32_Word st_size; unsigned char st_info; unsigned char st_other; Elf32_Half st_shndx; } Elf32_Sym
/*st_info*/ #define ELF32_ST_BIND(x) ((x) >> 4) #define ELF32_ST_TYPE(x) (((unsigned int) x) & 0xf) |
其中,st_name是符号名,如前所述他是某个字符串表的表内索引,st_value可能是符号关
联的取值,有可能是符号的地址或符号的值;st_size应该就是符号
相关的尺寸大小,8位的st_info中
储存着两个信息.高4位名曰绑定信息 主要是描述的是符号是全局的(STB_GLOBAL),局部的
(STB_LOCAL),弱符号(STB_WEAK) 还是程序自定义的.低4位是符号的类型 主要描述的是这个符号是
变量(STT_OBJECT),函数(STT_OBJECT)还是其他类型的符号.
D.重定位表
重定位表中的每个表项都包含了如何修改某个目标项的信息,一般,同一个重定位表中的表
项都是描述同一个节区中符号的修改信息.下面是重定位表项的数据结构:
typedef struct elf32_rel { Elf32_Addr r_offset; Elf32_Word r_info; } Elf32_Rel;
typedef struct elf32_rela{ Elf32_Addr r_offset; Elf32_Word r_info; Elf32_Sword r_addend; } Elf32_Rela /* The following are used with relocations */ #define ELF32_R_SYM(x) ((x) >> 8) #define ELF32_R_TYPE(x) ((x) & 0xff) |
其中,r_offset表示的
是从
节区头部开始到将被重定位影响的存储单位之间的字节偏移 即
指明了重定位操作的实施位置;r_info也包含两个信息 一为重定位类型(低8位) 即指明了重定位操作
的方法,二为被实施重定位的符号索引(高24位) 即指明了操作的实施对象.下表是x86结构下重定位操
作的类型和说明.
x86体系结构下重定位类型
名称 | 数值 | 字段 | 计算 | 说明 |
R_386_NONE | 0 | (无) | (无) |
R_386_32 | 1 | word32 | S+A |
R_386_PC32 | 2 | word32 | S+A-P |
R_386_GOT32 | 3 | word32 | G+A-P | 此重定位类型计算从全局偏移表基址到符号的全局偏移表项之间的距离。它会通知连接编辑器构造一个全局偏移表。 |
R_386_PLT32 | 4 | word32 |
|