文章目录
ELF: Executable Linkable Format
是一种Unix-like系统上的二进制文件格式标准
ELF标准中的ELF格式有4类
- Relocatable File: 可重定位文件,内容包含了代码和数据,可以被链接成可执行文件或者共享目标文件,比如Linux上的 .o 文件。
- Executable File: 可执行文件,是可以直接执行的程序,比如Linux上的a.out。
- Shared Object File:共享目标文件,包含code和data, 可以作为链接器的输入,在链接阶段和Relocatable File或者Shared Object File一起链接成新的Object File,比如.a文件; 或者在运行阶段,作为动态链接器的输入和Executable File结合,作为进程的一部分来运行,比如 .so 文件。
- CoreDump File:核心转储文件,进程意外终止时,系统可以将该进程的部分内容和终止时的其他状态信息保存到该文件中以供调试分析,比如Linux上的core文件
ELF文件格式
- 链接视图:
ELF Header
test@hfeng:~/workspace/c$ readelf -h foo.o
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: REL (Relocatable file)
Machine: Advanced Micro Devices X86-64
Version: 0x1
Entry point address: 0x0
Start of program headers: 0 (bytes into file)
Start of section headers: 704 (bytes into file)
Flags: 0x0
Size of this header: 64 (bytes)
Size of program headers: 0 (bytes)
Number of program headers: 0
Size of section headers: 64 (bytes)
Number of section headers: 13
Section header string table index: 12
程序头包含了很多重要的信息,每个字段的含义可参考ELF结构文档。主要看下:
- Entry point address:程序的入口地址,这是没有链接的目标文件所以值是0x00
- Start of section headers:段表开始位置的首字节
- Size of section headers:段表的长度(字节为单位)
- Number of section headers:段表中项数,也就是有多少段
- Start of program headers:程序头的其实位置(对于可执行文件重要,现在为0)
- Size of program headers:程序头大小(对于可执行文件重要,现在为0)
- Number of program headers:程序头中的项数,也就是多少Segment(和Section有区别,后面介绍)
- Size of this header:当前ELF文件头的大小,这里是52字节
Section Header Table
test@hfeng:~/workspace/c$ readelf -SW foo.o
There are 13 section headers, starting at offset 0x2c0:
Section Headers:
[Nr] Name Type Address Off Size ES Flg Lk Inf Al
[ 0] NULL 0000000000000000 000000 000000 00 0 0 0
[ 1] .text PROGBITS 0000000000000000 000040 000017 00 AX 0 0 1
[ 2] .rela.text RELA 0000000000000000 000210 000030 18 I 10 1 8
[ 3] .data PROGBITS 0000000000000000 000057 000000 00 WA 0 0 1
[ 4] .bss NOBITS 0000000000000000 000057 000000 00 WA 0 0 1
[ 5] .rodata PROGBITS 0000000000000000 000057 00000d 00 A 0 0 1
[ 6] .comment PROGBITS 0000000000000000 000064 00002a 01 MS 0 0 1
[ 7] .note.GNU-stack PROGBITS 0000000000000000 00008e 000000 00 0 0 1
[ 8] .eh_frame PROGBITS 0000000000000000 000090 000038 00 A 0 0 8
[ 9] .rela.eh_frame RELA 0000000000000000 000240 000018 18 I 10 8 8
[10] .symtab SYMTAB 0000000000000000 0000c8 000120 18 11 9 8
[11] .strtab STRTAB 0000000000000000 0001e8 000027 00 0 0 1
[12] .shstrtab STRTAB 0000000000000000 000258 000061 00 0 0 1
Key to Flags:
W (write), A (alloc), X (execute), M (merge), S (strings), I (info),
L (link order), O (extra OS processing required), G (group), T (TLS),
C (compressed), x (unknown), o (OS specific), E (exclude),
l (large), p (processor specific)
.text 段
.text段保存代码编译后的指令,可以用objdump -s -d foo.o查看foo.o代码段的内容。
test@hfeng:~/workspace/c$ objdump -S foo.o
foo.o: file format elf64-x86-64
Disassembly of section .text:
0000000000000000 <main>:
*/
#include <stdio.h>
int main ()
{
0: 55 push %rbp
1: 48 89 e5 mov %rsp,%rbp
printf("Hello World!\n");
4: 48 8d 3d 00 00 00 00 lea 0x0(%rip),%rdi # b <main+0xb>
b: e8 00 00 00 00 callq 10 <main+0x10>
return 0;
10: b8 00 00 00 00 mov $0x0,%eax
}
15: 5d pop %rbp
16: c3 retq
.data段
data段保存的是已经初始化了的全局静态变量和局部静态变量。使用objdump -x -s -d foo.o查看
.bss 段
用来存放程序中未初始化的全局变量的一块内存区域,一般在初始化时bss段部分将会清零