【Linux】认识ELF格式文件
1. 什么是ELF文件?
ELF(Executable and Linkable Format)是Linux系统中可执行文件(.exe)、目标文件(.o)、共享库(.a)和核心转储的标准文件格式。
我们都知道文件=属性+内容,下面我们将ELF格式文件的内容展开来说,也就是直接打开后那堆像乱码一样的东西,ELF文件内容包含以下主要部分:
ELF头(ELF Header):描述文件的基本属性,如目标架构、入口地址、段头表和节头表的位置
程序头表(Program Header Table):列举了所有有效的段(segments)和他们的属性。表里记着每个段的开始的位置和位移(offset)、长度,毕竟这些段,都是紧密的放在⼆进制文件中, 需要段表的描述信息,才能把他们每个段分割开。(用于可执行文件和共享库)
节头表(Section Header Table):描述文件的各个节的信息(用于目标文件)
节(Section):ELF文件中的基本组成单位,包含了特定类型的数据。ELF文件的各种信息和数据都存储在不同的节中,如代码节存储了可执行代码,数据节存储了全局变量和静态数据等。
2. readelf命令
功能:显示ELF格式文件的内容信息
readelf [选项] 文件名/目录
接下来我们会使用这个命令来帮助我们学习ELF格式的文件内容
3.ELF头(ELF Header)
我们使用readelf -h myexe来查看一个文件名为myexe的可执行文件的ELF头的内容:
魔数 | Magic | ELF文件标识符,64位小端序格式 |
文件类别 | Class | 64位的ELF文件 |
数据编码 | Data | 使用二进制补码,小端字节序 |
版本 | Version | ELF格式标准版本1 |
操作系统ABI | OS/ABI | 遵循System V应用二进制接口 |
ABI版本 | ABI Version | ABI版本号0 |
文件类型 | Type | 位置无关可执行文件(PIE),支持ASLR |
机器架构 | Machine | 文件适用平台:x86-64位 |
版本 | Version | 文件版本号1 |
入口点地址 | Entry point address | 程序开始执行的内存地址 |
程序头表起始 | Start of program headers | 程序头表在文件中的偏移量 |
程序头大小 | Size of program headers | 每个程序头条目的大小 |
程序头数量 | Number of program headers | 共有13个程序头(段) |
节头表起始 | Start of section headers | 节头表在文件中的偏移量(0x36d0) |
节头大小 | Size of section headers | 每个节头条目的大小 |
节头数量 | Number of section headers | 共有31个节头(节) |
节头字符串表索引 | Section header string table index | 节名称字符串表在节头表中的索引 |
不难看出,ELF头就是用来从宏观上来描述ELF整个格式布局的。其实ELF Header就是一个结构体,在编译器形成可执行程序时就会new一个ELF Header结构体,然后把对应的数据填好。因为之后我们的操作系统也要加载ELF文件去运行,那么也要加载这个结构体。所以不论是编译器还是操作系统都要认识这个ELF Header结构体。
前面我们学习磁盘文件时,把磁盘文件看成了一个一维数组,这里我们也可以把整个ELF格式文件内容也看成一个一维数组,那么我们只需要知道每个部分相对于ELF头最开始位置的偏移量和每个部分的大小就可以管理这个ELF文件内容,而这些都已经记录在了ELF头的内容中了,所以我们可以通过ELF头找到这个ELF文件的所有内容。
4. 程序头表(Program Header Table)
在说这个表之前,我们应该先弄明白什么是段呢?
在OS角度,IO必须以4KB为单位,但是我们能够知道的是每个节肯定不一定刚好是4KB的,大部分节都是小于4KB的,而多个section可能有相同的属性(可读,可写等),所以我们将ELF文件加载到操作系统内部时要把section以4KB对齐的方式合并。这样合并后的东西我们就叫做数据段(segment)。所以ELF文件加载到内存过程中,会先被OS合并成多个段再加载进内存。
而程序头表中记录的其实是:把sections合并为segments的合并方法,告诉我们哪些section要合并在一起,怎么合并。
那么问题又来了,这个合并是什么时候开始的?
合并是在可执行程序加载到内存时进行的,合并后的段我们是查不到的,我们也不需要知道这个,我们只用了解节(section)的内容就可以了,段(segment)是给操作系统看的。
那么我们用readelf命令来看一下可执行文件中的Program Header:
5. 节头表(Section Headers Table)
我们要是想了解每个节的内容其实可以通过查看节头表的内容也可以查到节,因为节头表就是用来描述一个个节的情况。
我们要是想查看ELF的节的信息可以直接通过readelf -S myexe命令查看myexe的节头表:
第一句话告诉了我们,ELF文件到节的初识偏移量为0x36d0,
下面是一些常见节(section)的含义: