在 UNIX® 和 Linux® 中,任何事物都是文件。UNIX 和 Linux 编程实际上是编写处理各种文件的代码。系统由许多类型的文件组成,但目标文件具有一种特殊的设计,提供了灵活和多样的用途。
目标文件是包含带有附加地址和值的助记符号的路线图。这些符号可以用来对各种代码段和数据段进行命名,包括经过初始化的和未初始化的。它们也可以用来定位嵌入的调试信息,就像语义 Web,非常适合由程序进行阅读。
编译器可以将我们在代码编辑器中创建的文本转换为目标文件。最初,目标文件被称为代码的中间表示形式,因为它用作连接编辑器(即连接器)的输入,而连接编辑器最终完成整个任务并生成可执行的程序作为输出。
从代码到可执行代码的转换过程经过了良好的定义并实现了自动化,而目标文件是这个链中有机的连接性环节。在这个转换过程中,目标文件作为连接编辑器所使用的映象,使得它们能够解析各种符号并将不同的代码和数据段连接在一起形成统一的整体。
1.1 目标文件的格式
计算机编程领域中存在许多著名的目标文件格式。DOS 系列包括 COM、OBJ 和 EXE 格式。UNIX 和 Linux 使用 a.out、COFF 和 ELF。Microsoft® Windows® 使用可移植的执行文件 (PE) 格式,而 Macintosh 使用 PEF、Mach-O 和其他文件格式。
最初,各种类型的计算机具有自己独特的目标文件格式,但随着 UNIX 和其他在不同硬件平台上提供可移植性的操作系统的出现,一些常用的文件格式上升为通用的标准。其中包括 a.out、COFF 和 ELF 格式。
要了解目标文件,需要一组可以读取目标文件中不同部分并以更易于读取的格式显示这些内容的工具。
1.2 UNIX 目标文件
写一个简单的程序:hello.c
C 编译器的正常输出是用于所指定的目标处理器的汇编代码。汇编代码是汇编器的输入,在缺省情况下,汇编器将生成所有目标文件的祖先,即 a.out 文件。这个名称本身表示汇编输出 (Assembler Output)。要创建 a.out 文件,可以在 shell 窗口中输入下面的命令:gcc hello.c
最新的 C 编译器将编译和汇编步骤组合成一个步骤。我们可以指定不同开关选项以查看 C 编译器的汇编输出。通过输入下面的命令,我们可以看到 C 编译器的汇编输出:gcc -S hello.c
在当前目录下会生成 hello.s 文件,即为汇编输入文本。
-
接下来研究目标文件,其中使用的有价值的工具有:
- nm:列出目标文件中的符号。
- objdump:显示目标文件中的详细信息。
- readelf:显示关于 ELF 目标文件的信息。
1.2.1 nm:列出目标文件中的符号
执行命令:nm a.out
这些包含可执行代码的段称为正文段。同样地,数据段包含了不可执行的信息或数据。另一种类型的段,称为 BSS 段,它包含以符号数据开头的块。
对于 nm 命令列出的每个符号,它们的值使用十六进制来表示(缺省行为),并且在该符号前面加上了一个表示符号类型的编码字符。
-
常见的各种编码包括:
- A 表示绝对 (absolute),这意味着不能将该值更改为其他的连接;
- B 表示 BSS 段中的符号;
- C 表示引用未初始化的数据的一般符号。
可以将目标文件中所包含的不同的部分划分为段。段可以包含可执行代码、符号名称、初始数据值和许多其他类型的数据。
1.2.2 objdump:显示目标文件中的详细信息
通过输入下面的命令,可以看到目标文件中包含可执行代码的每个段的汇编清单。
objdump -d a.out
命令生成的代码如下所示:
1 a.out: file format elf64-x86-64 2 3 4 Disassembly of section .init: 5 6 00000000004003c8 <_init>: 7 4003c8: 48 83 ec 08 sub $0x8,%rsp 8 4003cc: 48 8b 05 25 0c 20 00 mov 0x200c25(%rip),%rax # 600ff8 <_DYNAMIC+0x1d0> 9 4003d3: 48 85 c0 test %rax,%rax 10 4003d6: 74 05 je 4003dd <_init+0x15> 11 4003d8: e8 43 00 00 00 callq 400420 <__libc_start_main@plt+0x10> 12 4003dd: 48 83 c4 08 add $0x8,%rsp 13 4003e1: c3 retq 14 15 Disassembly of section .plt: 16 17 00000000004003f0 <puts@plt-0x10>: 18 4003f0: ff 35 12 0c 20 00 pushq 0x200c12(%rip) # 601008 <_GLOBAL_OFFSET_TABLE_+0x8> 19 4003f6: ff 25 14 0c 20 00 jmpq *0x200c14(%rip) # 601010 <_GLOBAL_OFFSET_TABLE_+0x10> 20 4003fc: 0f 1f 40 00 nopl 0x0(%rax) 21 22 0000000000400400 <puts@plt>: 23 400400: ff 25 12 0c 20 00 jmpq *0x200c12(%rip) # 601018 <_GLOBAL_OFFSET_TABLE_+0x18> 24 400406: 68 00 00 00 00 pushq $0x0 25 40040b: e9 e0 ff ff ff jmpq 4003f0 <_init+0x28> 26 27 0000000000400410 <__libc_start_main@plt>: 28 400410: ff 25 0a 0c 20 00 jmpq *0x200c0a(%rip) # 601020 <_GLOBAL_OFFSET_TABLE_+0x20> 29 400416: 68 01 00 00 00 pushq $0x1 30 40041b: e9 d0 ff ff ff jmpq 4003f0 <_init+0x28> 31 32 Disassembly of section .plt.got: 33 34 0000000000400420 <.plt.got>: 35 400420: ff 25 d2 0b 20 00 jmpq *0x200bd2(%rip) # 600ff8 <_DYNAMIC+0x1d0> 36 400426: 66 90 xchg %ax,%ax 37 38 Disassembly of section .text: 39 40 0000000000400430 <_start>: 41 400430: 31 ed xor %ebp,%ebp 42 400432: 49 89 d1 mov %rdx,%r9 43 400435: 5e pop %rsi 44 400436: 48 89 e2 mov %rsp,%rdx 45 400439: 48 83 e4 f0 and $0xfffffffffffffff0,%rsp 46 40043d: 50 push %rax 47 40043e: 54 push %rsp 48 40043f: 49 c7 c0 c0 05 40 00 mov $0x4005c0,%r8 49 400446: 48 c7 c1 50 05 40 00 mov $0x400550,%rcx 50 40044d: 48 c7 c7 26 05 40 00 mov $0x400526,%rdi 51 400454: e8 b7 ff ff ff callq 400410 <__libc_start_main@plt> 52 400459: f4 hlt 53 40045a: 66 0f 1f 44 00 00 nopw 0x0(%rax,%rax,1) 54 55 0000000000400460 <deregister_tm_clones>: 56 400460: b8 3f 10 60 00 mov $0x60103f,%eax 57 400465: 55 push %rbp 58 400466: 48 2d 38 10 60 00 sub $0x601038,%rax 59 40046c: 48 83 f8 0e cmp $0xe,%rax 60 400470: 48 89 e5 mov %rsp,%rbp 61 400473: 76 1b jbe 400490 <deregister_tm_clones+0x30> 62 400475: b8 00 00 00 00 mov $0x0,%eax 63 40047a: 48 85 c0 test %rax,%rax 64 40047d: 74 11 je 400490 <deregister_tm_clones+0x30> 65 40047f: 5d pop %rbp 66 400480: bf 38 10 60 00 mov $0x601038,%edi 67 400485: ff e0 jmpq *%rax 68 400487: 66 0f 1f 84 00 00 00 nopw 0x0(%rax,%rax,1) 69 40048e: 00 00 70 400490: 5d pop %rbp 71 400491: c3 retq 72 400492: 0f 1f 40 00 nopl 0x0(%rax) 73 400496: 66 2e 0f 1f 84 00 00 nopw %cs:0x0(%rax,%rax,1) 74 40049d: 00 00 00 75 76 00000000004004a0 <register_tm_clones>: 77 4004a0: be 38 10 60 00 mov $0x601038,%esi 78 4004a5: 55 push %rbp 79 4004a6: 48 81 ee 38 10 60 00 sub $0x601038,%rsi 80 4004ad: 48 c1 fe 03 sar $0x3,%rsi 81 4004b1: 48 89 e5 mov %rsp,%rbp 82 4004b4: 48 89 f0 mov %rsi,%rax 83 4004b7: 48 c1 e8 3f shr $0x3f,%rax 84 4004bb: 48 01 c6 add %rax,%rsi 85 4004be: 48 d1 fe sar %rsi 86 4004c1: 74 15 je 4004d8 <register_tm_clones+0x38> 87 4004c3: b8 00 00 00 00 mov $0x0,%eax 88 4004c8: 48 85 c0 test %rax,%rax 89 4004cb: 74 0b je 4004d8 <register_tm_clones+0x38> 90 4004cd: 5d pop %rbp 91 4004ce: bf 38 10 60 00 mov $0x601038,%edi 92 4004d3: ff e0 jmpq *%rax 93 4004d5: 0f 1f 00 nopl (%rax) 94 4004d8: 5d pop %rbp 95 4004d9: c3 retq 96 4004da: 66 0f 1f 44 00 00 nopw 0x0(%rax,%rax,1) 97 98 00000000004004e0 <__do_global_dtors_aux>: 99 4004e0: 80 3d 51 0b 20 00 00 cmpb $0x0,0x200b51(%rip) # 601038 <__TMC_END__> 100 4004e7: 75 11 jne 4004fa <__do_global_dtors_aux+0x1a> 101 4004e9: 55 push %rbp 102 4004ea: 48 89 e5 mov %rsp,%rbp 103 4004ed: e8 6e ff ff ff callq 400460 <deregister_tm_clones> 104 4004f2: 5d pop %rbp 105 4004f3: c6 05 3e 0b 20 00 01 movb $0x1,0x200b3e(%rip) # 601038 <__TMC_END__> 106 4004fa: f3 c3 repz retq 107 4004fc: 0f 1f 40 00 nopl 0x0(%rax) 108 109 0000000000400500 <frame_dummy>: 110 400500: bf 20 0e 60 00 mov $0x600e20,%edi 111 400505: 48 83 3f 00 cmpq $0x0,(%rdi) 112 400509: 75 05 jne 400510 <frame_dummy+0x10> 113 40050b: eb 93 jmp 4004a0 <register_tm_clones> 114 40050d: 0f 1f 00 nopl (%rax) 115 400510: b8 00 00 00 00 mov $0x0,%eax 116 400515: 48 85 c0 test %rax,%rax 117 400518: 74 f1 je 40050b <frame_dummy+0xb> 118 40051a: 55 push %rbp 119 40051b: 48 89 e5 mov %rsp,%rbp 120 40051e: ff d0 callq *%rax 121 400520: 5d pop %rbp 122 400521: e9 7a ff ff ff jmpq 4004a0 <register_tm_clones> 123 124 0000000000400526 <main>: 125 400526: 55 push %rbp 126 400527: 48 89 e5 mov %rsp,%rbp 127 40052a: 48 83 ec 10 sub $0x10,%rsp 128 40052e: 89 7d fc mov %edi,-0x4(%rbp) 129 400531: 48 89 75 f0 mov %rsi,-0x10(%rbp) 130 400535: bf d4 05 40 00 mov $0x4005d4,%edi 131 40053a: e8 c1 fe ff ff callq 400400 <puts@plt> 132 40053f: b8 00 00 00 00 mov $0x0,%eax 133 400544: c9 leaveq 134 400545: c3 retq 135 400546: 66 2e 0f 1f 84 00 00 nopw %cs:0x0(%rax,%rax,1) 136 40054d: 00 00 00 137 138 0000000000400550 <__libc_csu_init>: 139 400550: 41 57 push %r15 140 400552: 41 56 push %r14 141 400554: 41 89 ff mov %edi,%r15d 142 400557: 41 55 push %r13 143 400559: 41 54 push %r12 144 40055b: 4c 8d 25 ae 08 20 00 lea 0x2008ae(%rip),%r12 # 600e10 <__frame_dummy_init_array_entry> 145 400562: 55 push %rbp 146 400563: 48 8d 2d ae 08 20 00 lea 0x2008ae(%rip),%rbp # 600e18 <__init_array_end> 147 40056a: 53 push %rbx 148 40056b: 49 89 f6 mov %rsi,%r14 149 40056e: 49 89 d5 mov %rdx,%r13 150 400571: 4c 29 e5 sub %r12,%rbp 151 400574: 48 83 ec 08 sub $0x8,%rsp 152 400578: 48 c1 fd 03 sar $0x3,%rbp 153 40057c: e8 47 fe ff ff callq 4003c8 <_init> 154 400581: 48 85 ed test %rbp,%rbp 155 400584: 74 20 je 4005a6 <__libc_csu_init+0x56> 156 400586: 31 db xor %ebx,%ebx 157 400588: 0f 1f 84 00 00 00 00 nopl 0x0(%rax,%rax,1) 158 40058f: 00 159 400590: 4c 89 ea mov %r13,%rdx 160 400593: 4c 89 f6 mov %r14,%rsi 161 400596: 44 89 ff mov %r15d,%edi 162 400599: 41 ff 14 dc callq *(%r12,%rbx,8) 163 40059d: 48 83 c3 01 add $0x1,%rbx 164 4005a1: 48 39 eb cmp %rbp,%rbx 165 4005a4: 75 ea jne 400590 <__libc_csu_init+0x40> 166 4005a6: 48 83 c4 08 add $0x8,%rsp 167 4005aa: 5b pop %rbx 168 4005ab: 5d pop %rbp 169 4005ac: 41 5c pop %r12 170 4005ae: 41 5d pop %r13 171 4005b0: 41 5e pop %r14 172 4005b2: 41 5f pop %r15 173 4005b4: c3 retq 174 4005b5: 90 nop 175 4005b6: 66 2e 0f 1f 84 00 00 nopw %cs:0x0(%rax,%rax,1) 176 4005bd: 00 00 00 177 178 00000000004005c0 <__libc_csu_fini>: 179 4005c0: f3 c3 repz retq 180 181 Disassembly of section .fini: 182 183 00000000004005c4 <_fini>: 184 4005c4: 48 83 ec 08 sub $0x8,%rsp 185 4005c8: 48 83 c4 08 add $0x8,%rsp 186 4005cc: c3 retq