ELF介绍
Linux下可执行文件的格式是ELF(Executable amd Linkable Format),这种文件格式是基于COFF( Common File Format )文件标准的变种格式。ELF文件的全部定义可以在/usr/include/elf.h
头文件和官网文档内进行查看。
下面所说的地址(虚拟地址或物理地址)一般不可以让内存直接拿来使用,但是可以通过该地址进行辅助计算,进而获得内存空间中正确的地址。
a.out: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=f593abe086161ce758678e314dd80a7e65f9bd7a, for GNU/Linux 3.2.0, not stripped
ELF文件中有头信息、段、节三个重要的概念需要进行了解。由于运行期和链接期中针对程序的划分方案有所差异,所以ELF文件针对两个不同的方案分化出了段和节两个概念,段为程序的运行期提供支持,节为程序的链接期提供支持。
在ELF文件中头信息的位置是固定在最顶部的,其他部分的位置并不是固定的,其中头信息可以检索到头表的起始位置。
在ELF文件中段或节由头(段头或节头)和身体(段或节)组成,头中定义了基本的属性。所有的头会组成一张头表,可以根据头表内不同头的属性索引到不同的身体部分。头表的首表项会记录整个头表的属性(如果存在),头表的属性也可以在头信息中获取。
常用工具
为了观察ELF文件,在Linux中常常使用readelf
显示EFL文件的信息、objdump
对ELF文件进行反汇编、hexdump
或od
或vim
使用不同的进制显示ELF文件中的内容。
头信息
头信息在ELF文件的开头,用于标明该文件是ELF文件、展示基本的信息、展示头表的基本信息。
头信息的存在是为了帮助计算机可不可以执行这个ELF文件(文件格式是否正确、架构是否匹配、ABI是否匹配等等)。
00000000 7f 45 4c 46 02 01 01 00 | 00 00 00 00 00 00 00 00 |.ELF............| Magic 00000010 03 00 3e 00 01 00 00 00 | 40 10 00 00 00 00 00 00 |..>.....@.......| 文件类型 机器类型 版本 | 入口地址 00000020 40 00 00 00 00 00 00 00 | 60 36 00 00 00 00 00 00 |@.......`6......| 段索引地址 | 节索引地址 00000030 00 00 00 00 40 00 38 00 | 0d 00 40 00 1d 00 1c 00 |....@.8...@.....| 标志 头信息大小 段大小 | 段数量 节大小 节数量 字符串表索引地址 ELF Header: Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 Class: ELF64 Data: 2's complement, little endian Version: 1 (current) OS/ABI: UNIX - System V ABI Version: 0 Type: DYN (Position-Independent Executable file) Machine: Advanced Micro Devices X86-64 Version: 0x1 Entry point address: 0x1040 Start of program headers: 64 (bytes into file) Start of section headers: 13920 (bytes into file) Flags: 0x0 Size of this header: 64 (bytes) Size of program headers: 56 (bytes) Number of program headers: 13 Size of section headers: 64 (bytes) Number of section headers: 29 Section header string table index: 28
Magic
标明文件是ELF文件格式以及展示必要的信息。
位置1:7f,特定标志 位置2-4:45 4c 46 = E L F 位置5:ELF文件的执行类型 00:无效的类型 01:32位程序 02:64位程序 位置6:数据编码格式 00:无效的类型 01:高位数据存放在内存的低地址中,低位数据存放在内存的高地址中 02:低位数据存放在内存的低地址中,高位数据存放在内存的高地址中 位置7:版本 0:无效的版本 1:默认值 位置8:内核ABI(Application Binary Interface 应用程序接口)类型 位置9:ABI版本 位置10-16:保留位置
文件类型
标明不同类型的ELF文件。
0 无效的文件类型 1 可重定位文件 编译过程产生的中间文件,链接器可以将中间文件和其他文件或信息进行组合生成可执行文件 2 可执行文件 可以执行的文件 3 动态链接库文件 可执行文件运行时可以从动态链接库文件内获取需要执行的逻辑 4 转储文件 程序在某一时刻保存下来的信息
机器类型
标明ELF文件是运行在哪种体系结构的计算机中的。
入口地址
标明可执行程序的入口地址。
段头表
包含段头表的索引地址(如果没有段,那么对应的地址就是0)、段头的大小、段头的数量。
段头表内的段头在文件内连续存放的。
节头表
包含节头表的索引地址(如果没有节,那么对应的数值就是0)、节头的大小、节头的数量、字符串表在节头表中的位置。
节头表内的节头在文件内连续存放的。
标志位
标明特定处理器的信息。
段头
在ELF文件中,段和段头(段头也可以叫做程序头)并不是连续存放的,可以借助段头内的属性定位到ELF文件中对应段的位置。
因为段是运行期产生的概念,所有段头只对可执行文件或动态链接库这两个会被加载到内存中执行的文件有意义,其他类型的ELF文件可以忽略段头,因为它们不需要使用段,也就更不需要段头对段进行检索。
Elf file type is DYN (Position-Independent Executable file) Entry point 0x1040 There are 13 program headers, starting at offset 64 Program Headers: Type Offset VirtAddr PhysAddr FileSiz MemSiz Flags Align PHDR 0x0000000000000040 0x0000000000000040 0x0000000000000040 0x00000000000002d8 0x00000000000002d8 R 0x8 INTERP 0x0000000000000318 0x0000000000000318 0x0000000000000318 0x000000000000001c 0x000000000000001c R 0x1 [Requesting program interpreter: /lib64/ld-linux-x86-64.so.2] LOAD 0x0000000000000000 0x0000000000000