ELF的全称是Executable Linkable Format,简单理解就是Linux平台下一种二进制文件的格式。本文所涉及到的程序均使用main.c, fun.c, head.h这三个文件。他们编译后生成的可执行文件为res。
main.c
#include<stdio.h>
#include"head.h"
int main(){
int a = 12;
int b = 23;
int c = add(a, b);
printf("%d\n",c);
return 0;
}
head.h
int add(int a, int b);
fun.c
int add(int a, int b){
return (a + b);
}
编译命令:
gcc main.c fun.c -o res
1、ELF常见格式
ELF文件类型 | 说明 | 实例 |
可重定位文件 | 这类文件包含了代码和数据,可以被用来链接成可执行文件或共享目标文件,静态链接库也可以归为这一类 | Linux的.o文件 |
可执行文件 | 这类文件包含了可以直接执行的程序,它的代表就是ELF可执行文件,它们一般都没有扩展名 | 比如/bin/bash文件 |
共享目标文件 | 这类文件包含了代码和数据,可以在两种情况下使用。一种是链接器可以使用这种文件跟其他的可重定位文件和共享目标文件链接,产生新的目标文件。第二种是动态链接器可以将几个这种共享目标文件与可执行文件结合,作为进程映像的一部分来运行 | Linux的.so |
核心转储文件 | 当进程意外终止时,系统可以讲该进程的地址空间的内容及终止时的一些其他信息转储到核心转储文件 | Linux的core dump |
2、ELF文件结构
首先我们看一下ELF文件的总体结构,先有一个大致的了解。
ELF Header Sections ... ... ... Section Header Table String Tables
Symbol Tables
ELF的结构是由多个段(也叫作Section)组成,每一部分的内容都保存在一个段(Section)中。记住一点是,ELF本质上是二进制文件(ELF本身仅仅是存了一堆0和1的序列而已),所谓的段,其实是我们根据二进制的内容先进行解析,解析后根据存的内容不同,划分出了不同的段。
2.1 ELF Header
ELF Header描述了整个文件的基本属性,ELF Header的数据保存在Elf32_Ehdr结构体中
typedef struct{
unsigned char e_ident[16];
Elf32_Half e_type;
Elf32_Half e_machine;
Elf32_Word e_version;
Elf32_Addr e_entry;
Elf32_Off e_phoff;
Elf32_Off e_shoff;
Elf32_Word e_flags;
Elf32_Half e_ephsize;
Elf32_Half e_phentsize;
Elf32_Half e_phnum;
Elf32_Half e_shentsize;
Elf32_Half e_shnum;
Elf32_Half e_shstrndex;
} Elf32_Ehdr;
具体这个结构体的成员含义如下表所示(某些值来源于本文所用的res程序):
成员 | readelf输出结果与含义 |
e_ident | Magic:7f 454c 46 01 01 01 00 00 00 00 00 00 00 00 00 Class: ELF32 Data: 2's complement, little endian Version: 1 (current) OS/ABI: UNIX-System V ABI Version: 0 |
e_type | Type: EXEC (executable file) ELF文件类型 |
e_machine | Machine: Intel 80386 ELF文件的CPU平台属性 |
e_version | Version:0x1 ELF版本号。一般为常数1 |
e_entry | Entry point address: 0x8048320 入口地址,规定ELF程序的入口虚拟地址,操作系统在加载完成该程序后,从这个地址开始执行进程的指令。可重定位文件一般 |