Android中ELF文件结构浅析(一)

一、ELF文件头(elf_header)

可以用以下这个数据结构体来描述文件头。

struct Elf64_Ehdr {
  unsigned char e_ident[16];
  Elf64_Half e_type;
  Elf64_Half e_machine;
  Elf64_Word e_version;
  Elf64_Addr e_entry;
  Elf64_Off e_phoff;
  Elf64_Off e_shoff;
  Elf64_Word e_flags;
  Elf64_Half e_ehsize;
  Elf64_Half e_phentsize;
  Elf64_Half e_phnum;
  Elf64_Half e_shentsize;
  Elf64_Half e_shnum;
  Elf64_Half e_shstrndx;
};

其中各个成员的意义如下:

1.  e_ident

        从头开始的16个字节含有 ELF 文件的识别标志,并且提供了一些用于解码 和解析文件内容的数据,是不依赖于具体操作系统的。

0000        7F 45 4C 46 02 01 01 00 00 00 00 00 00 00 00 00

1.1 File identification

        是ELF文件开头的4个字节也就是文件标识EI_MAG[0] ~ EI_MAG[3],这4个字节的内容是固定的。

EI_MAG[0] 0x7F
EI_MAG[1] 0x45 E
EI_MAG[2] 0x4C L
EI_MAG[3] 0x46 F

1.2  EI_CLASS

        是上面块中第五个字节,代表的是目标文件的类型

ELFCLASSNONE 0 无效的种类
ELFCLASS32 1 32位对象
ELFCLASS64 2 64位对象

1.3  EL_DATA

        第六个字节代表着文件中数据采用的编码格式

0x1表示采用小端序,0x2为大端序

1.4  EI_VERSION

        第7个字节EI_VERSION指明 ELF 文件头的版本,目前这个版本号是 EV_CURRENT,即“1”

1.5  EI_OSABI

        第8个字节EI_OSABI表示操作系统/ABI标识

1.6  EI_ABIVERSION

      第9个字节 ABI版本。

1.7  EI_PAD

        第10个字节到第15个字节暂时不使用,留作以后扩展,在实际的文件中应被填 0 补充,其它程序在读取 ELF 文件头时应该忽略这些字节。

1.8  EI_NIDENT

        第16个字节是e_ident[]的大小。

2.  e_type

0010        03 00 B7 00 01 00 00 00 20 13 00 00 00 00 00 00

ET_NONE 0 没有文件类型
ET_REL 1 可重定位文件
ET_EXEC 2 可执行文件
ET_DYN 3 动态链接库文件
ET_CORE 4 Core 文件
ET_LOPROC 0xFF00 处理器指定下限
ET_HIPROC 0xFFFF 处理器指定上限

3.  e_machine

        这一项指定了当前文件可以运行的机器架构

0010        03 00 B7 00 01 00 00 00 20 13 00 00 00 00 00 00

enum MachineArchitecture {
  EM_NONE = 0,       // No machine.
  EM_386 = 3,        // Intel 架构.
  EM_ARM = 40,       // ARM 架构.  0x28
  EM_X86_64 = 62,    // Intel x86-64 架构. 0x3E
  EM_AARCH64 = 183,  // ARM 64位 架构.  0xB7
  // 其他值略过
};

4.  e_version

0010        03 00 B7 00 01 00 00 00 20 13 00 00 00 00 00 00

 同上1.4

5.  e_entry

0010        03 00 B7 00 01 00 00 00 20 13 00 00 00 00 00 00

         程序入口点地址 

6.  e_phoff

0020        40 00 00 00 00 00 00 00 E0 41 00 00 00 00 00 00

        是指明程序头表(program header table)开始处在文件中的偏移量。如果没有程序头表,该值应设为0。

即0x40也是elf_header的大小。

7.  e_shoff

0020        40 00 00 00 00 00 00 00 E0 41 00 00 00 00 00 00

        是指明节头表(section header table)开始处在文件中的偏移量。如果没有节头表,该值应设为 0。

8.  e_flags

0030        00 00 00 00 40 00 38 00 08 00 40 00 18 00 17 00

        这一项给出文件中与特定处理器相关的标志。

#define	EF_MIPS_NOREORDER	0x00000001
#define	EF_MIPS_PIC		0x00000002	/* Contains PIC code */
#define	EF_MIPS_CPIC		0x00000004	/* STD PIC calling sequence */
#define	EF_MIPS_UCODE		0x00000010
#define	EF_MIPS_ABI2		0x00000020	/* N32 */
#define	EF_MIPS_OPTIONS_FIRST	0x00000080
#define	EF_MIPS_ABI		0x0000F000
#define	EF_MIPS_ABI_O32		0x00001000
#define	EF_MIPS_ABI_O64		0x00002000
#define	EF_MIPS_ABI_EABI32	0x00003000
#define	EF_MIPS_ABI_EABI64	0x00004000
#define	EF_MIPS_ARCH_ASE	0x0F000000	/* Architectural extensions */
#define	EF_MIPS_ARCH_ASE_MDMX	0x08000000	/* MDMX multimedia extension */
#define	EF_MIPS_ARCH_ASE_M16	0x04000000	/* MIPS-16 ISA extensions */
#define	EF_MIPS_ARCH		0xF0000000	/* Architecture field */
#define	EF_MIPS_ARCH_1		0x00000000	/* -mips1 code */
#define	EF_MIPS_ARCH_2		0x10000000	/* -mips2 code */
#define	EF_MIPS_ARCH_3		0x20000000	/* -mips3 code */
#define	EF_MIPS_ARCH_4		0x30000000	/* -mips4 code */
#define	EF_MIPS_ARCH_5		0x40000000	/* -mips5 code */
#define	EF_MIPS_ARCH_32		0x50000000	/* -mips32 code */
#define	EF_MIPS_ARCH_64		0x60000000	/* -mips64 code */
#define	EF_MIPS_ARCH_32R2	0x70000000	/* -mips32r2 code */
#define	EF_MIPS_ARCH_64R2	0x80000000	/* -mips64r2 code */

9.  e_ehsize

0030        00 00 00 00 40 00 38 00 08 00 40 00 18 00 17 00

        此字段表明 ELF 文件头的大小,以字节为单位。

10.  e_phentsize

0030        00 00 00 00 40 00 38 00 08 00 40 00 18 00 17 00

        此字段表明在程序头表(program header table)中每一个表项的大小,以字节为单位,每个表项的大小相同。 

11.  e_phnum 

0030        00 00 00 00 40 00 38 00 08 00 40 00 18 00 17 00

        此字段表明程序头表中总共有多少个表项。

        如上图所示

        e_phentsize 乘以 e_phnum 就得到了整个program header table的大小。

12.  e_shentsize

0030        00 00 00 00 40 00 38 00 08 00 40 00 18 00 17 00

        此字段表明在节头表(section header table)中每一个表项的大小,一个节头是节头表中的一项;节头表中所有项占据的空间大小相同。

13.  e_shnum

0030        00 00 00 00 40 00 38 00 08 00 40 00 18 00 17 00

        此字段表明节头表中总共有多少个表项。 

        如上图所示

        e_shentsize 乘以 e_shnum,就得到了整个section header table的大小。

14.  e_shstrndx

0030        00 00 00 00 40 00 38 00 08 00 40 00 18 00 17 00

        节头表中与节名字表相对应的表项的索引。如果文件没有节名字表,此值应设置为 SHN_UNDEF。

0x17转为十进制是23