零、前言
ELF文件:Executable and Linking Format,译为“可执行可连接格式”。
与 Linux 下的其他可执行文件(a.out,cof)相比,它对节的定义和 gnu 工具链对它的支持使它十分灵活,它保存的足够了系统相关信息使它能支持不同平台上的交叉编译和交叉链接,可移植性很强,同时它在执行中支持动态链接共享库。
分析 ELF 文件有助于理解一些重要的系统概念,例如程序的编译和链接,程序的加载和运行等。
一、ELF 文件类型
1、可重定位文件:用户和其他目标文件一起创建可执行文件或者共享目标文件,例如 lib*.a 文件。
2、可执行文件:用于生成进程映像,载入内存执行,例如编译好的可执行文件 a.out。
3、共享目标文件:用于和其他共享目标文件或者可重定位文件一起生成 ELF 目标文件或者和执行文件一起创建进程映像,例如 lib*.so 文件。
二、ELF文件的识别
通过 file 命令可以看到哪种类型的 ELF,比如:
gcc -c helloworld.c
file helloworld.o
helloworld.o: ELF 64-bit LSB relocatable, x86-64, version 1 (SYSV), not stripped
#可重定向文件##
gcc -o helloworld helloworld.o
file helloworld
helloworld: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.15, not stripped
##可执行文件##
file libc.so
libc.so: ELF 32-bit LSB shared object, ARM, version 1 (SYSV), dynamically linked, not stripped
#共享目标文件##
三、ELF 文件作用
ELF 文件参与程序的连接(建立一个程序)和程序的执行(运行一个程序),所以可以从不同的角度来看待elf格式的文件:
1、若其是可重定位文件,用于编译和链接,则编译器和链接器将把 ELF 文件看作是节头表描述的节的集合,程序头表可选。
2、若其是可执行文件,用于加载执行,则加载器将把 ELF 文件看作是程序头表描述的段的集合,一个段可能包含多个节,节头表可选。
3、若其是共享文件,则两者都含有。
目标文件可能既要参与程序链接又要参与程序执行。出于方便性和效率考虑,目标文件格式提供了两种并行视图,分别反映了这些活动的不同需求。编译器,链接器把它看作是 sections 的集合,loader 把它看作是 segments 的集合:
四、ELF 文件总体组成
ELF 文件头描述 ELF 文件的总体信息。包括:
- 系统相关
- 类型相关
- 加载相关
- 链接相关
系统相关表示:ELF 文件标识的魔术数,以及硬件和平台等相关信息,增加了 ELF 文件的移植性,使交叉编译成为可能。
类型相关就是前面说的那个类型。
加载相关:包括程序头表相关信息。
链接相关:节头表相关信息。
ELF 文件参与程序的连接(建立一个程序)和程序的执行(运行一个程序)。
编译器和链接器将其视为节头表(section header table)描述的一些节(section)的集合。
加载器则将其视为程序头表(program header table)描述的段(segment)的集合,通常一个段可以包含多个节。
可重定位文件都包含一个节头表,可执行文件都包含一个程序头表。
共享文件两者都包含有。为此,ELF文件格式同时提供了两种看待文件内容的方式,反映了不同行为的不同要求。
从链接的角度看,ELF 文件从开始到结束,可以看成是如下组成的:
(1)ELF文件头
(2)程序头表(可选)
(3)第1节,第2节,...,第n节,...
(4)节头表
从执行的角度看,ELF文件从开始到结束,可以看成是如下组成的:
(1)ELF文件头
(2)程序头表
(3)第1段、第2段,...,
(4)节头表(可选)
(SAW:Game Over!)