图解
- ELF文件头
开头16个字节描述了生成该文件的字的大小,以及字节序;
剩余部分包含的信息可支持链接器解析和解释该目标文件,比如文件头的大小、目标文件的类型(重定位、可执行、共享)、机器类型(比如x86-64
)、节头表的文件偏移量、节头表大小和条目数量等 -
.text
节
保存的是被编译程序的机器码; - .rodata节
保存的是只读数据,比如printf
语句中的格式化字符串,及switch
语句使用的jump tables
等; -
.data
节
保存的是已初始化的全局变量和静态C变量;
不保存局部C变量,因为局部C变量由运行时栈维护; -
.bss
节
保存的是未初始化的静态变量及初始化为0的全局变量和静态变量;
.COMMON
伪节里保存的是未初始化的全局变量;
不保存局部C变量,因为局部C变量由运行时栈维护;
.bss
节不占据目标文件的空间,因为没必要; -
.symtab
节
保存的是有关在程序中定义和引用的函数或者全局变量的信息;
每个重定位目标文件都有符号表,即.symtab
节;
跟编译器的符号表不一样,.symtab
符号表不包含局部变量信息; -
.rel.text
节
保存的是.text
节中需要被修正的位置信息;
任何调用外部函数或者引用全局变量的指令都需要被修正;
调用外部函数的指令需要重定位;
引用全局变量的指令需要重定位;
调用局部函数的指令不需要重定位;
在可执行目标文件中不存在重定位信息; -
.rel.data
节
保存的是该文件引用或者定义的的全局变量的重定位信息;
任何初始化值是某个全局变量地址的全局变量需要重定位;
任何在外部定义的函数需要重定位; -
.debug
节 .line
-
strtab
节
保存的是在.symtab
节、.debug
节及
section header节中的
Name字段中的字符串; 以
null`结尾; -
section header table
在目标文件中的每个节都有一个节头表条目;
节头表条目描述的是节的位置和大小信息;
示例
示例1 以SimpleSection.c
为例进行说明
##############SimpleSection.c##################
int printf(const char* format, ...);
int global_init_var = 84;
int global_uninit_var;
void func1(int i)
{
printf("%d\n", i);
}
int main()
{
static int static_var = 85;
static int static_var2;
int a = 1;
int b;
func1(static_var + static_var2 + a + b);
return a;
}
#生成SimpleSection.o
gcc -Og -c SimpleSection.c
readelf -h SimpleSection.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: 944 (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
readelf -S SimpleSection.o
There are 13 section headers, starting at offset 0x3b0:
Section Headers:
[Nr] Name Type Address Offset
Size EntSize Flags Link Info Align
[ 0] NULL 0000000000000000 00000000
0000000000000000 0000000000000000 0 0 0
[ 1] .text PROGBITS 0000000000000000 00000040
0000000000000034 0000000000000000 AX 0 0 1
[ 2] .rela.text RELA 0000000000000000 000002d0
0000000000000048 0000000000000018 I 10 1 8
[ 3] .data PROGBITS 0000000000000000 00000074
0000000000000004 0000000000000000 WA 0 0 4
[ 4] .bss NOBITS 0000000000000000 00000078
0000000000000000 0000000000000000 WA 0 0 1
[ 5] .rodata.str1.1 PROGBITS 0000000000000000 00000078
0000000000000004 0000000000000001 AMS 0 0 1
[ 6] .comment PROGBITS 0000000000000000 0000007c
000000000000002c 0000000000000001 MS 0 0 1
[ 7] .note.GNU-stack PROGBITS 0000000000000000 000000a8
0000000000000000 0000000000000000 0 0 1
[ 8] .eh_frame PROGBITS 0000000000000000 000000a8
0000000000000048 0000000000000000 A 0 0 8
[ 9] .rela.eh_frame RELA 0000000000000000 00000318
0000000000000030 0000000000000018 I 10 8 8
[10] .symtab SYMTAB 0000000000000000 000000f0
0000000000000180 0000000000000018 11 10 8
[11] .strtab STRTAB 0000000000000000 00000270
0000000000000060 0000000000000000 0 0 1
[12] .shstrtab STRTAB 0000000000000000 00000348
0000000000000068 0000000000000000 0 0 1
readelf -s SimpleSection.o
Symbol table '.symtab' contains 16 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
1: 0000000000000000 0 FILE LOCAL DEFAULT ABS SimpleSection.c
2: 0000000000000000 0 SECTION LOCAL DEFAULT 1
3: 0000000000000000 0 SECTION LOCAL DEFAULT 3
4: 0000000000000000 0 SECTION LOCAL DEFAULT 4
5: 0000000000000000 0 SECTION LOCAL DEFAULT 5
6: 0000000000000000 0 SECTION LOCAL DEFAULT 7
7: 0000000000000000 0 SECTION LOCAL DEFAULT 8
8: 0000000000000000 0 NOTYPE LOCAL DEFAULT 5 .LC0
9: 0000000000000000 0 SECTION LOCAL DEFAULT 6
10: 0000000000000000 28 FUNC GLOBAL DEFAULT 1 func1
11: 0000000000000000 0 NOTYPE GLOBAL DEFAULT UND _GLOBAL_OFFSET_TABLE_
12: 0000000000000000 0 NOTYPE GLOBAL DEFAULT UND printf
13: 000000000000001c 24 FUNC GLOBAL DEFAULT 1 main
14: 0000000000000004 4 OBJECT GLOBAL DEFAULT COM global_uninit_var
15: 0000000000000000 4 OBJECT GLOBAL DEFAULT 3 global_init_var
#SimpleSection.o中的重定位记录
objdump -r SimpleSection.o
RELOCATION RECORDS FOR [.text]:
OFFSET TYPE VALUE
0000000000000009 R_X86_64_PC32 .LC0-0x0000000000000004
0000000000000013 R_X86_64_PLT32 printf-0x0000000000000004
0000000000000026 R_X86_64_PC32 func1-0x0000000000000004
示例2 以main.c
和sum.c
为例进行说明
############main.c###############
int sum(int *a, int n);
int array[2] = {1, 2};
int main()
{
int val = sum(array, 2);
return val;
}
############sum.c###############
int sum(int *a, int n)
{
int i, s = 0;
for(int i = 0; i < n; i++){
s += a[i];
}
return s;
}
在sum.o文件中没有的节:.data节、.rela.text节、.rela.data节;
在main.o文件中,由于main.c中调用了sum函数,所以需要重定位,即有.rela.text节;
#生成重定位文件
gcc -Og -c main.c sum.c
#查看sum.o的文件头
readelf -h sum.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: 528 (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: 11
Section header string table index: 10
#查看main.o的文件头
readelf -h main.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: 12
Section header string table index: 11
#查看sum.o的节头表
readelf -S sum.o
There are 11 section headers, starting at offset 0x210:
Section Headers:
[Nr] Name Type Address Offset
Size EntSize Flags Link Info Align
[ 0] NULL 0000000000000000 00000000
0000000000000000 0000000000000000 0 0 0
[ 1] .text PROGBITS 0000000000000000 00000040
000000000000001b 0000000000000000 AX 0 0 1
[ 2] .data PROGBITS 0000000000000000 0000005b
0000000000000000 0000000000000000 WA 0 0 1
[ 3] .bss NOBITS 0000000000000000 0000005b
0000000000000000 0000000000000000 WA 0 0 1
[ 4] .comment PROGBITS 0000000000000000 0000005b
000000000000002c 0000000000000001 MS 0 0 1
[ 5] .note.GNU-stack PROGBITS 0000000000000000 00000087
0000000000000000 0000000000000000 0 0 1
[ 6] .eh_frame PROGBITS 0000000000000000 00000088
0000000000000030 0000000000000000 A 0 0 8
[ 7] .rela.eh_frame RELA 0000000000000000 000001a0
0000000000000018 0000000000000018 I 8 6 8
[ 8] .symtab SYMTAB 0000000000000000 000000b8
00000000000000d8 0000000000000018 9 8 8
[ 9] .strtab STRTAB 0000000000000000 00000190
000000000000000b 0000000000000000 0 0 1
[10] .shstrtab STRTAB 0000000000000000 000001b8
0000000000000054 0000000000000000 0 0 1
#查看main.o的节头表
There are 12 section headers, starting at offset 0x2c0:
Section Headers:
[Nr] Name Type Address Offset
Size EntSize Flags Link Info Align
[ 0] NULL 0000000000000000 00000000
0000000000000000 0000000000000000 0 0 0
[ 1] .text PROGBITS 0000000000000000 00000040
000000000000001a 0000000000000000 AX 0 0 1
[ 2] .rela.text RELA 0000000000000000 00000218
0000000000000030 0000000000000018 I 9 1 8
[ 3] .data PROGBITS 0000000000000000 00000060
0000000000000008 0000000000000000 WA 0 0 8
[ 4] .bss NOBITS 0000000000000000 00000068
0000000000000000 0000000000000000 WA 0 0 1
[ 5] .comment PROGBITS 0000000000000000 00000068
000000000000002c 0000000000000001 MS 0 0 1
[ 6] .note.GNU-stack PROGBITS 0000000000000000 00000094
0000000000000000 0000000000000000 0 0 1
[ 7] .eh_frame PROGBITS 0000000000000000 00000098
0000000000000030 0000000000000000 A 0 0 8
[ 8] .rela.eh_frame RELA 0000000000000000 00000248
0000000000000018 0000000000000018 I 9 7 8
[ 9] .symtab SYMTAB 0000000000000000 000000c8
0000000000000120 0000000000000018 10 8 8
[10] .strtab STRTAB 0000000000000000 000001e8
000000000000002d 0000000000000000 0 0 1
[11] .shstrtab STRTAB 0000000000000000 00000260
0000000000000059 0000000000000000 0
#查看sum.o的代码节
objdump -j .text -S sum.o
sum.o: file format elf64-x86-64
Disassembly of section .text:
0000000000000000 :
0: ba 00 00 00 00 mov $0x0,%edx
5: b8 00 00 00 00 mov $0x0,%eax
a: eb 09 jmp 15
c: 48 63 ca movslq %edx,%rcx
f: 03 04 8f add (%rdi,%rcx,4),%eax
12: 83 c2 01 add $0x1,%edx
15: 39 f2 cmp %esi,%edx
17: 7c f3 jl c
19: f3 c3 repz retq
#查看main.o的代码节
objdump -j .text -S main.o
Disassembly of section .text:
0000000000000000 :
0: 48 83 ec 08 sub $0x8,%rsp
4: be 02 00 00 00 mov $0x2,%esi
9: 48 8d 3d 00 00 00 00 lea 0x0(%rip),%rdi # 10
10: e8 00 00 00 00 callq 15
15: 48 83 c4 08 add $0x8,%rsp
19: c3 retq
#`sum.o`没有数据节
#查看`main.o`的数据节
objdump -j .data -S main.o
Disassembly of section .data:
0000000000000000 :
0: 01 00 00 00 02 00 00 00
#查看main.o中的`rela.text`节
objdump -r main.o
RELOCATION RECORDS FOR [.text]:
OFFSET TYPE VALUE
000000000000000c R_X86_64_PC32 array-0x0000000000000004
0000000000000011 R_X86_64_PLT32 sum-0x0000000000000004
#查看sum.o中的`rela.text`节
objdump -r sum.o
sum.o: file format elf64-x86-64
RELOCATION RECORDS FOR [.eh_frame]:
OFFSET TYPE VALUE
0000000000000020 R_X86_64_PC32 .text
readelf -x .strtab main.o
Hex dump of section '.strtab':
0x00000000 006d6169 6e2e6300 6d61696e 00617272 .main.c.main.arr
0x00000010 6179005f 474c4f42 414c5f4f 46465345 ay._GLOBAL_OFFSE
0x00000020 545f5441 424c455f 0073756d 00 T_TABLE_.sum.
readelf -x .shstrtab main.o
Hex dump of section '.shstrtab':
0x00000000 002e7379 6d746162 002e7374 72746162 ..symtab..strtab
0x00000010 002e7368 73747274 6162002e 72656c61 ..shstrtab..rela
0x00000020 2e746578 74002e64 61746100 2e627373 .text..data..bss
0x00000030 002e636f 6d6d656e 74002e6e 6f74652e ..comment..note.
0x00000040 474e552d 73746163 6b002e72 656c612e GNU-stack..rela.
0x00000050 65685f66 72616d65 00 eh_frame.