一、相同的文件格式:ELF
- 目标文件:代码编译后未链接的文件(Linux的.o)
- 可执行文件
- 静态链接库(Linux的.a)
- 动态链接库(Linux的.so)
二、ELF文件的结构
示例代码:simple.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(void){
static int static_var = 85;
static int static_var2;
int a = 1;
int b;
func1(static_var + static_var2 + a + b);
return a;
}
为什么要将程序的指令和数据进行分段呢?
- 当程序被装载后,数据和指令被映射到两个不同的虚存区域。数据区域对进程是可写可读的,而指令区只是可读的,这样就避免了进程修改指令带来的问题。
- 当系统中运行着多个该程序的副本时,它们的指令是相同的,数据可能不同。因此在内存中只需保存一份该程序的指令,这样就节省了大量的存储空间。
- 为了提高缓存的命中率。将数据和指令分离有助于提高程序的局部性;
1. 文件头
ELF文件头描述了整个文件的文件属性,包括文件是否可以执行、是静态链接还是动态链接、入口地址、目标硬件、目标操作系统等信息。
zhoumeng.2019@n224-024-082:~/hello$ readelf -h simple.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: 1104 (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
Entry point address:程序的入口虚拟地址,加载完程序后从这地址开始执行程序的指令。可重定位文件一般没有,为0;
Start of section headers:段表在文件中的偏移;
Start of program headers:segment,装载时的段;
2. 段表
描述了文件中各个段的段名、段大小、偏移位置、读写权限以及段的其他属性等。
zhoumeng.2019@n224-024-082:~/hello$ objdump -h simple.o
simple.o: file format elf64-x86-64
Sections:
Idx Name Size VMA LMA File off Algn
0 .text 00000057 0000000000000000 0000000000000000 00000040 2**0
CONTENTS, ALLOC, LOAD, RELOC, READONLY, CODE
1 .data 00000008 0000000000000000 0000000000000000 00000098 2**2
CONTENTS, ALLOC, LOAD, DATA
2 .bss 00000004 0000000000000000 0000000000000000 000000a0 2**2
ALLOC
3 .rodata 00000004 0000000000000000 0000000000000000 000000a0 2**0
CONTENTS, ALLOC, LOAD, READONLY, DATA
4 .comment 0000002e 0000000000000000 0000000000000000 000000a4 2**0
CONTENTS, READONLY
5 .note.GNU-stack 00000000 0000000000000000 0000000000000000 000000d2 2**0
CONTENTS, READONLY
6 .eh_frame 00000058 0000000000000000 0000000000000000 000000d8 2**3
CONTENTS, ALLOC, LOAD, RELOC, READONLY, DATA
- VMA和LMA和虚拟地址有关,装载时才会确定;
- CONTENTS 该段在文件中存在,.bss就不存在内容;
- ALLOC 该段在进程空间总要分配空间;
3. 代码段.text
zhoumeng.2019@n224-024-082:~/hello$ objdump -d simple.o
simple.o: file format elf64-x86-64
Disassembly of section .text:
0000000000000000 <func1>:
0: 55 push %rbp
1: 48 89 e5 mov %rsp,%rbp
4: 48 83 ec 10 sub $0x10,%rsp
8: 89 7d fc mov %edi,-0x4(%rbp)
b: 8b 45 fc mov -0x4(%rbp),%eax
e: 89 c6 mov %eax,%esi
10: 48 8d 3d 00 00 00 00 lea 0x0(%rip),%rdi # 17 <func1+0x17>
17: b8 00 00 00 00 mov $0x0,%eax
1c: e8 00 00 00 00 callq 21 <func1+0x21>
21: 90 nop
22: c9 leaveq
23: c3 retq
0000000000000024 <main>:
24: 55 push %rbp
25: 48 89 e5 mov %rsp,%rbp
28: 48 83 ec 10 sub $0x10,%rsp
2c: c7 45 fc 01 00 00 00 movl $0x1,-0x4(%rbp)
33: 8b 15 00 00 00 00 mov 0x0(%rip),%edx # 39 <main+0x15>
39: 8b 05 00 00 00 00 mov 0x0(%rip),%eax # 3f <main+0x1b>
3f: 01 c2 add %eax,%edx
41: 8b 45 fc mov -0x4(%rbp),%eax
44: 01 c2 add %eax,%edx
46: 8b 45 f8 mov -0x8(%rbp),%eax
49: 01 d0 add %edx,%eax
4b: 89 c7 mov %eax,%edi
4d: e8 00 00 00 00 callq 52 <main+0x2e>
52: 8b 45 fc mov -0x4(%rbp),%eax
55: c9 leaveq
56: c3 retq
4. 数据段
已经初始化的全局变量和局部静态变量保存在.data段;
未初始化的全局变量和局部静态变量保存在.bss段(默认都是0,预留位置不占据空间);
$ objdump -x -s -d simple.o
......
Contents of section .data:
0000 54000000 55000000 T...U... //global_init_var和static_var
......
5. 只读数据段.rodata
存放只读数据,一般是程序中的只读变量(如const修饰的变量)和字符串常量;
$ objdump -x -s -d simple.o
......
Contents of section .rodata:
0000 25640a00 %d.. (prinf中的%d)
......
6. 注释信息段.comment
7. 符号表.symtab
记录了目标文件中所用到的所有符号,例如定义的全局和局部符号,引用的全局符号,段名;
每个符号都有个对应的值,对于变量和函数来说,符号值就是他们的地址;
zhoumeng.2019@n224-024-082:~/hello$ readelf -s simple.o
Symbol table '.symtab' contains 17 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
1: 0000000000000000 0 FILE LOCAL DEFAULT ABS simple.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: 0000000000000004 4 OBJECT LOCAL DEFAULT 3 static_var.1765
7: 0000000000000000 4 OBJECT LOCAL DEFAULT 4 static_var2.1766
8: 0000000000000000 0 SECTION LOCAL DEFAULT 7
9: 0000000000000000 0 SECTION LOCAL DEFAULT 8
10: 0000000000000000 0 SECTION LOCAL DEFAULT 6
11: 0000000000000000 4 OBJECT GLOBAL DEFAULT 3 global_init_var
12: 0000000000000004 4 OBJECT GLOBAL DEFAULT COM global_uninit_var
13: 0000000000000000 36 FUNC GLOBAL DEFAULT 1 func1
14: 0000000000000000 0 NOTYPE GLOBAL DEFAULT UND _GLOBAL_OFFSET_TABLE_
15: 0000000000000000 0 NOTYPE GLOBAL DEFAULT UND printf
16: 0000000000000024 51 FUNC GLOBAL DEFAULT 1 main
8. 字符串表 .strtab
存储ELF文件中用到的各种字符串,比如段名、变量名等;
如此,引用字符串时只需用表中的偏移即可,而不用考虑字符串长度不定的问题;
9. 重定位段 .rel.text .rel.data
链接器处理目标文件时,需要对目标文件中的某些代码和数据进行重定位,这些信息都会记录在重定位表中;
zhoumeng.2019@n224-024-082:~/hello$ objdump -r simple.o
simple.o: file format elf64-x86-64
RELOCATION RECORDS FOR [.text]:
OFFSET TYPE VALUE
0000000000000013 R_X86_64_PC32 .rodata-0x0000000000000004
000000000000001d R_X86_64_PLT32 printf-0x0000000000000004
0000000000000035 R_X86_64_PC32 .data
000000000000003b R_X86_64_PC32 .bss-0x0000000000000004
000000000000004e R_X86_64_PC32 func1-0x0000000000000004
10. 动态链接信息.dynamic
ELF文件头存储的是静态链接时的相关内容,而.dynamic段可以被视为动态链接下的elf文件头。
保存了依赖于哪些共享对象、动态链接符号表的位置、动态链接重定位表、共享对象初始化代码的地址等;
zhoumeng.2019@n224-024-082:~/dynamix$ readelf -d P1
Dynamic section at offset 0xde0 contains 27 entries:
Tag Type Name/Value
0x0000000000000001 (NEEDED) Shared library: [./Lib.so]
0x0000000000000001 (NEEDED) Shared library: [libc.so.6]
0x000000000000000c (INIT) 0x5f8
0x000000000000000d (FINI) 0x804
0x0000000000000019 (INIT_ARRAY) 0x200dc8
0x000000000000001b (INIT_ARRAYSZ) 8 (bytes)
0x000000000000001a (FINI_ARRAY) 0x200dd0
0x000000000000001c (FINI_ARRAYSZ) 8 (bytes)
0x000000006ffffef5 (GNU_HASH) 0x298
0x0000000000000005 (STRTAB) 0x408
0x0000000000000006 (SYMTAB) 0x2d0
0x000000000000000a (STRSZ) 197 (bytes)
0x000000000000000b (SYMENT) 24 (bytes)
0x0000000000000015 (DEBUG) 0x0
0x0000000000000003 (PLTGOT) 0x201000
0x0000000000000002 (PLTRELSZ) 24 (bytes)
0x0000000000000014 (PLTREL) RELA
0x0000000000000017 (JMPREL) 0x5e0
0x0000000000000007 (RELA) 0x508
0x0000000000000008 (RELASZ) 216 (bytes)
0x0000000000000009 (RELAENT) 24 (bytes)
0x000000006ffffffb (FLAGS_1) Flags: PIE
0x000000006ffffffe (VERNEED) 0x4e8
0x000000006fffffff (VERNEEDNUM) 1
0x000000006ffffff0 (VERSYM) 0x4ce
0x000000006ffffff9 (RELACOUNT) 3
0x0000000000000000 (NULL) 0x0
网友评论