一.整体把握
ELF loader 分为内核空间Loader 和用户空间Linker
loader负责加载segement, linker负责重定位和链接动态库
Program Loading 流程:
1. 在Shell 模式下执行外部程序
2. Shell以 fork + exec 方式执行外部程序
3. 通过Int 0x80 中断 调用kernel的exec<sys_execvp> 系统调用服务
Kernel Space loader:
4. Exec调用Program Loader(ELF loader), 将ELF image 载入
5. Program Loader 找到PT_INTERP segment
6. Program Loader将PT_LOAD segment mapping为text/data segment。text segment 由vadder 0x08048000开始,data segment 紧接其后
7. Program loader 调用 interpreter loader 将 program interpreter (ld.so)载入,并且mapping到进程内存空间中;interpreter的text segement由vaddr
0x4000000开始,interpreter的data segment紧接其接之后。
8. Program loader 将 BSS segment 准备好
9. Program loader 将process 的%eip(user-mode)修改为program interpreter的入口;并将%esp 设定为 user-mode的栈(任何共享库的外部程序,一开始都由Program interpreter开始执行)
User Space Linker:
10. Program interpreter 会找到进程所需的共享库(名称和路径)
11. Program interpreter 使用mmap 系统调用将共享库mapping到进程内存空间,以完成进程image的建立。
12. 更新共享库的符号表(symbol table)
13. Program interpreter 跳到进程入口(记录在ELF header里的entry point)。
14.真正开始执行程序!
一.ELF 文件类型
1. 可重定位文件 (Relocatable File)
包含适合其他文件链接来创建可执行文件或者共享目标文件的代码和数据。在Linux中最常见到即是Object-file (gcc –c file.c)产生的目标文件
2. 可执行文件(Executable File)
包含适合于执行的一个程序,此文件规定了exec()如何创建一个进程image
3. 共享目标文件 (Shared Object File)
包含可在两种上下文中链接的代码和数据。最常见的是Linux下.so 的动态链接库文件。
二.ELF文件中的数据表示
Size Align
Elf32_Addr 4 4
Elf32_Half 2 2
Elf32_Off 4 4
Elf32_Sword 4 4
Elf32_Word 4 4
unsigned char 1 1
三.ELF文件格式
Linker View |
ELF header |
Program header table(opt) |
Section 1 |
Section 2 |
… |
Section header table |
Exec View |
ELF header |
Program header table |
Segment 1 |
Segment 2 |
… |
Section header table(opt) |
四.ELF Header部分
#define EI_NIDENT 16
typedef struct {
unsigned char e_ident[EI_NIDENT]; #magic number
Elf32_Half e_type; #exec file or rel file or .so file
Elf32_Half e_machine; #Intel 386 or mips or powerpc
Elf32_Word e_version; #always 1
Elf32_Addr e_entry; #program entry
Elf32_Off e_phoff; #program header table offset in file
Elf32_Off e_shoff; #section header table offset in file
Elf32_Word e_flags; #与处理器有关的flags
Elf32_Half e_ehsize; #Size of ELF header always 0x34
Elf32_Half e_phentsize; #program header entry size 0x20
Elf32_Half e_phnum; #program header number
Elf32_Half e_shentsize; #section header entry size 40bytes
Elf32_Half e_shnum; #section header entry number
Elf32_Half e_shstrndx; # “section name”section
# index(.strtab)
}Elf32_Ehdr;
e_indent[EI_NIDENT] = { 0x7f,‘E’,‘L’,‘F’,EI_CLASS(32bit码or 64bit代码),EI_DATA(大端or小端系统),EI_VERSION(1),0…};