扫一扫
分享文章到微信
扫一扫
关注官方公众号
至顶头条
计算机编程的最新技术将一种特殊的人性与一组特殊的工具结合在一起,用以生产出对其他人非常有帮助的一种神奇的产品,即软件。计算机程序员是一群注重细节的人,他们可以处理计算机中各种各样的困难。计算机的要求非常苛刻,并且不能容忍其中存在任何的偏差。毫无疑问,无论您的个性如何以及在工作中使用了何种辅助工具,计算机程序的编写都是非常困难的。
在 UNIX® 和 Linux® 中,任何事物都是文件。您可以认为,UNIX 和 Linux 编程实际上是编写处理各种文件的代码。系统由许多类型的文件组成,但目标文件具有一种特殊的设计,提供了灵活和多样的用途。
目标文件是包含带有附加地址和值的助记符号的路线图。这些符号可以用来对各种代码段和数据段进行命名,包括经过初始化的和未初始化的。它们也可以用来定位嵌入的调试信息,就像语义 Web,非常适合由程序进行阅读。
行业工具
计算机编程中使用的工具包括代码编辑器,如 vi 或 Emacs,您可以使用这些工具输入和编辑希望计算机在完成所需任务时执行的指令,以及编译器和连接器,它们可以生成真正实现这些目标的机器代码。
高级的工具,称为集成调试环境 (IDE),它以统一的外观集成了不同工具的功能。IDE 使得编辑器、编译器、连接器和调试器之间的界限变得很模糊。因此,为了更深入地研究和了解系统,在使用集成的套件之前,最好先单独地使用这些工具。(注意:IDE 也通常被称为集成开发环境。)
编译器可以将您在代码编辑器中创建的文本转换为目标文件。最初,目标文件被称为代码的中间表示形式,因为它用作连接编辑器(即连接器)的输入,而连接编辑器最终完成整个任务并生成可执行的程序作为输出。
从代码到可执行代码的转换过程经过了良好的定义并实现了自动化,而目标文件是这个链中有机的连接性环节。在这个转换过程中,目标文件作为连接编辑器所使用的映象,使得它们能够解析各种符号并将不同的代码和数据段连接在一起形成统一的整体。
历史
计算机编程领域中存在许多著名的目标文件格式。DOS 系列包括 COM、OBJ 和 EXE 格式。UNIX 和 Linux 使用 a.out、COFF 和 ELF。Microsoft® Windows® 使用可移植的执行文件 (PE) 格式,而 Macintosh 使用 PEF、Mach-O 和其他文件格式。
最初,各种类型的计算机具有自己独特的目标文件格式,但随着 UNIX 和其他在不同硬件平台上提供可移植性的操作系统的出现,一些常用的文件格式上升为通用的标准。其中包括 a.out、COFF 和 ELF 格式。
要了解目标文件,需要一组可以读取目标文件中不同部分并以更易于读取的格式显示这些内容的工具。本文将讨论这些工具中比较重要的方面。但首先,您必须创建一个工作台,并在其中建立一个研究对象。
工作台
启动一个 xterm 会话,让我们先创建一个空白的工作台,并开始对目标文件进行研究。下面的命令创建了一个目录,可以将目标文件放到该目录中进行研究:
cd mkdir src cd src mkdir hw cd hw |
然后,使用您最喜欢的代码编辑器,在 $HOME/src/hw 目录中输入清单 1 中的程序,并命名为 hw.c。
要使用 UNIX 工具库中提供的各种工具,可以将这个简单的“Hello World”程序作为研究的对象。您将学习构建和查看目标文件的输出,而不是使用任何快捷方法直接创建可执行文件(的确有许多这样的快捷方法)。
文件格式
C 编译器的正常输出是用于您所指定的目标处理器的汇编代码。汇编代码是汇编器的输入,在缺省情况下,汇编器将生成所有目标文件的祖先,即 a.out 文件。这个名称本身表示汇编输出 (Assembler Output)。要创建 a.out 文件,可以在 xterm 窗口中输入下面的命令:
注意:如果出现了任何错误或者没有创建 a.out 文件,那么您可能需要检查自己的系统或源文件 (hw.c),以找出其中的错误。还需要检查是否已将 cc 定义为运行您的 C/C++ 编译器。
最新的 C 编译器将编译和汇编步骤组合成一个步骤。您可以指定不同开关选项以查看 C 编译器的汇编输出。通过输入下面的命令,您可以看到 C 编译器的汇编输出:
cc -S hw.c |
这个命令生成了一个新的文件 hw.s,其中包含您通常无法看到的汇编输入文本,因为编译器在缺省情况下将生成 a.out 文件。正如所预期的,UNIX 汇编程序可以对这种输入文件进行汇编,以生成 a.out 文件。
UNIX 特定的工具
假定编译过程一切顺利,那么在该目录中就有了一个 a.out 文件,下面让我们来对其进行研究。有许多可用于研究目标文件的有价值的工具,下面便是其中一组:
列表中的第一个工具是 nm,它可以列出目标文件中的符号。如果您输入 nm 命令,您将注意到在缺省情况下,它会寻找一个名为 a.out 的文件。如果没有找到该文件,这个工具会给出相应的提示。然而,如果该工具找到了编译器创建的 a.out 文件,它将显示类似清单 2 的清单。
08049594 A __bss_start 080482e4 t call_gmon_start 08049594 b completed.4463 08049498 d __CTOR_END__ 08049494 d __CTOR_LIST__ 08049588 D __data_start 08049588 W data_start 0804842c t __do_global_ctors_aux 0804830c t __do_global_dtors_aux 0804958c D __dso_handle 080494a0 d __DTOR_END__ 0804949c d __DTOR_LIST__ 080494a8 d _DYNAMIC 08049594 A _edata 08049598 A _end 08048458 T _fini 08049494 a __fini_array_end 08049494 a __fini_array_start 08048478 R _fp_hw 0804833b t frame_dummy 08048490 r __FRAME_END__ 08049574 d _GLOBAL_OFFSET_TABLE_ w __gmon_start__ 08048308 T __i686.get_pc_thunk.bx 08048278 T _init 08049494 a __init_array_end 08049494 a __init_array_start 0804847c R _IO_stdin_used 080494a4 d __JCR_END__ 080494a4 d __JCR_LIST__ w _Jv_RegisterClasses 080483e1 T __libc_csu_fini 08048390 T __libc_csu_init U __libc_start_main@@GLIBC_2.0 08048360 T main 08049590 d p.4462 U puts@@GLIBC_2.0 080482c0 T _start |
这些包含可执行代码的段称为正文段。同样地,数据段包含了不可执行的信息或数据。另一种类型的段,称为 BSS 段,它包含以符号数据开头的块。
对于 nm 命令列出的每个符号,它们的值使用十六进制来表示(缺省行为),并且在该符号前面加上了一个表示符号类型的编码字符。常见的各种编码包括:A 表示绝对 (absolute),这意味着不能将该值更改为其他的连接;B 表示 BSS 段中的符号;而 C 表示引用未初始化的数据的一般符号。
可以将目标文件中所包含的不同的部分划分为段。段可以包含可执行代码、符号名称、初始数据值和许多其他类型的数据。有关这些类型的数据的详细信息,可以阅读 UNIX 中 nm 的 man 页面,其中按照该命令输出中的字符编码分别对每种类型进行了描述。
细节,细节…
在目标文件阶段,即使是一个简单的 Hello World 程序,其中也包含了大量的细节信息。nm 程序可用于列举符号及其类型和值,但是,要更仔细地研究目标文件中这些命名段的内容,需要使用功能更强大的工具。
其中两种功能强大的工具是 objdump 和 readelf 程序。通过输入下面的命令,您可以看到目标文件中包含可执行代码的每个段的汇编清单。对于这么一个小的程序,编译器生成了这么多的代码,真的很令人惊异!
objdump -d a.out |
这个命令生成的输出如清单 3 所示。每个可执行代码段将在需要特定的事件时执行,这些事件包括库的初始化和该程序本身主入口点。
a.out: file format elf32-i386 Disassembly of section .init: 08048278 <_init>: 8048278: 55 push %ebp 8048279: 89 e5 mov %esp,%ebp 804827b: 83 ec 08 sub $0x8,%esp 804827e: e8 61 00 00 00 call 80482e4 <call_gmon_start> 8048283: e8 b3 00 00 00 call 804833b <frame_dummy> 8048288: e8 9f 01 00 00 call 804842c <__do_global_ctors_aux> 804828d: c9 leave 804828e: c3 ret Disassembly of section .plt: 08048290 <puts@plt-0x10>: 8048290: ff 35 78 95 04 08 pushl 0x8049578 8048296: ff 25 7c 95 04 08 jmp *0x804957c 804829c: 00 00 add %al,(%eax) ... 080482a0 <puts@plt>: 80482a0: ff 25 80 95 04 08 jmp *0x8049580 80482a6: 68 00 00 00 00 push $0x0 80482ab: e9 e0 ff ff ff jmp 8048290 <_init+0x18> 080482b0 <__libc_start_main@plt>: 80482b0: ff 25 84 95 04 08 jmp *0x8049584 80482b6: 68 08 00 00 00 push $0x8 80482bb: e9 d0 ff ff ff jmp 8048290 <_init+0x18> Disassembly of section .text: 080482c0 <_start>: 80482c0: 31 ed xor %ebp,%ebp 80482c2: 5e pop %esi 80482c3: 89 e1 mov %esp,%ecx 80482c5: 83 e4 f0 and $0xfffffff0,%esp 80482c8: 50 push %eax 80482c9: 54 push %esp 80482ca: 52 push %edx 80482cb: 68 e1 83 04 08 push $0x80483e1 80482d0: 68 90 83 04 08 push $0x8048390 80482d5: 51 push %ecx 80482d6: 56 push %esi 80482d7: 68 60 83 04 08 push $0x8048360 80482dc: e8 cf ff ff ff call 80482b0 <__libc_start_main@plt> 80482e1: f4 hlt 80482e2: 90 nop 80482e3: 90 nop |
080482e4 <call_gmon_start>: 80482e4: 55 push %ebp 80482e5: 89 e5 mov %esp,%ebp 80482e7: 53 push %ebx 80482e8: e8 1b 00 00 00 call 8048308 <__i686.get_pc_thunk.bx> 80482ed: 81 c3 87 12 00 00 add $0x1287,%ebx 80482f3: 83 ec 04 sub $0x4,%esp 80482f6: 8b 83 fc ff ff ff mov 0xfffffffc(%ebx),%eax 80482fc: 85 c0 test %eax,%eax 80482fe: 74 02 je 8048302 <call_gmon_start+0x1e> 8048300: ff d0 call *%eax 8048302: 83 c4 04 add $0x4,%esp 8048305: 5b pop %ebx 8048306: 5d pop %ebp 8048307: c3 ret 08048308 <__i686.get_pc_thunk.bx>: 8048308: 8b 1c 24 mov (%esp),%ebx 804830b: c3 ret 0804830c <__do_global_dtors_aux>: 804830c: 55 push %ebp 804830d: 89 e5 mov %esp,%ebp 804830f: 83 ec 08 sub $0x8,%esp 8048312: 80 3d 94 95 04 08 00 cmpb $0x0,0x8049594 8048319: 74 0c je 8048327 <__do_global_dtors_aux+0x1b> 804831b: eb 1c jmp 8048339 <__do_global_dtors_aux+0x2d> 804831d: 83 c0 04 add $0x4,%eax 8048320: a3 90 95 04 08 mov %eax,0x8049590 8048325: ff d2 call *%edx 8048327: a1 90 95 04 08 mov 0x8049590,%eax 804832c: 8b 10 mov (%eax),%edx 804832e: 85 d2 test %edx,%edx 8048330: 75 eb jne 804831d <__do_global_dtors_aux+0x11> 8048332: c6 05 94 95 04 08 01 movb $0x1,0x8049594 8048339: c9 leave 804833a: c3 ret 0804833b <frame_dummy>: 804833b: 55 push %ebp 804833c: 89 e5 mov %esp,%ebp 804833e: 83 ec 08 sub $0x8,%esp 8048341: a1 a4 94 04 08 mov 0x80494a4,%eax 8048346: 85 c0 test %eax,%eax 8048348: 74 12 je 804835c <frame_dummy+0x21> 804834a: b8 00 00 00 00 mov $0x0,%eax 804834f: 85 c0 test %eax,%eax 8048351: 74 09 je 804835c <frame_dummy+0x21> 8048353: c7 04 24 a4 94 04 08 movl $0x80494a4,(%esp) 804835a: ff d0 call *%eax 804835c: c9 leave 804835d: c3 ret 804835e: 90 nop 804835f: 90 nop 08048360 <main>: 8048360: 55 push %ebp 8048361: 89 e5 mov %esp,%ebp 8048363: 83 ec 08 sub $0x8,%esp 8048366: 83 e4 f0 and $0xfffffff0,%esp 8048369: b8 00 00 00 00 mov $0x0,%eax 804836e: 83 c0 0f add $0xf,%eax 8048371: 83 c0 0f add $0xf,%eax 8048374: c1 e8 04 shr $0x4,%eax 8048377: c1 e0 04 shl $0x4,%eax 804837a: 29 c4 sub %eax,%esp 804837c: c7 04 24 80 84 04 08 movl $0x8048480,(%esp) 8048383: e8 18 ff ff ff call 80482a0 <puts@plt> 8048388: b8 00 00 00 00 mov $0x0,%eax 804838d: c9 leave 804838e: c3 ret 804838f: 90 nop 08048390 <__libc_csu_init>: 8048390: 55 push %ebp 8048391: 89 e5 mov %esp,%ebp 8048393: 57 push %edi 8048394: 56 push %esi 8048395: 31 f6 xor %esi,%esi 8048397: 53 push %ebx 8048398: e8 6b ff ff ff call 8048308 <__i686.get_pc_thunk.bx> 804839d: 81 c3 d7 11 00 00 add $0x11d7,%ebx 80483a3: 83 ec 0c sub $0xc,%esp 80483a6: e8 cd fe ff ff call 8048278 <_init> 80483ab: 8d 83 20 ff ff ff lea 0xffffff20(%ebx),%eax 80483b1: 8d 93 20 ff ff ff lea 0xffffff20(%ebx),%edx 80483b7: 89 45 f0 mov %eax,0xfffffff0(%ebp) 80483ba: 29 d0 sub %edx,%eax 80483bc: c1 f8 02 sar $0x2,%eax 80483bf: 39 c6 cmp %eax,%esi 80483c1: 73 16 jae 80483d9 <__libc_csu_init+0x49> 80483c3: 89 d7 mov %edx,%edi 80483c5: ff 14 b2 call *(%edx,%esi,4) 80483c8: 8b 45 f0 mov 0xfffffff0(%ebp),%eax 80483cb: 83 c6 01 add $0x1,%esi 80483ce: 29 f8 sub %edi,%eax 80483d0: 89 fa mov %edi,%edx 80483d2: c1 f8 02 sar $0x2,%eax 80483d5: 39 c6 cmp %eax,%esi 80483d7: 72 ec jb 80483c5 <__libc_csu_init+0x35> 80483d9: 83 c4 0c add $0xc,%esp 80483dc: 5b pop %ebx 80483dd: 5e pop %esi 80483de: 5f pop %edi 80483df: 5d pop %ebp 80483e0: c3 ret 080483e1 <__libc_csu_fini>: 80483e1: 55 push %ebp 80483e2: 89 e5 mov %esp,%ebp 80483e4: 83 ec 18 sub $0x18,%esp 80483e7: 89 5d f4 mov %ebx,0xfffffff4(%ebp) 80483ea: e8 19 ff ff ff call 8048308 <__i686.get_pc_thunk.bx> 80483ef: 81 c3 85 11 00 00 add $0x1185,%ebx 80483f5: 89 75 f8 mov %esi,0xfffffff8(%ebp) 80483f8: 89 7d fc mov %edi,0xfffffffc(%ebp) 80483fb: 8d b3 20 ff ff ff lea 0xffffff20(%ebx),%esi 8048401: 8d bb 20 ff ff ff lea 0xffffff20(%ebx),%edi 8048407: 29 fe sub %edi,%esi 8048409: c1 fe 02 sar $0x2,%esi 804840c: eb 03 jmp 8048411 <__libc_csu_fini+0x30> 804840e: ff 14 b7 call *(%edi,%esi,4) 8048411: 83 ee 01 sub $0x1,%esi 8048414: 83 fe ff cmp $0xffffffff,%esi 8048417: 75 f5 jne 804840e <__libc_csu_fini+0x2d> 8048419: e8 3a 00 00 00 call 8048458 <_fini> 804841e: 8b 5d f4 mov 0xfffffff4(%ebp),%ebx 8048421: 8b 75 f8 mov 0xfffffff8(%ebp),%esi 8048424: 8b 7d fc mov 0xfffffffc(%ebp),%edi 8048427: 89 ec mov %ebp,%esp 8048429: 5d pop %ebp 804842a: c3 ret 804842b: 90 nop 0804842c <__do_global_ctors_aux>: 804842c: 55 push %ebp 804842d: 89 e5 mov %esp,%ebp 804842f: 53 push %ebx 8048430: 83 ec 04 sub $0x4,%esp 8048433: a1 94 94 04 08 mov 0x8049494,%eax 8048438: 83 f8 ff cmp $0xffffffff,%eax 804843b: 74 12 je 804844f <__do_global_ctors_aux+0x23> 804843d: bb 94 94 04 08 mov $0x8049494,%ebx 8048442: ff d0 call *%eax 8048444: 8b 43 fc mov 0xfffffffc(%ebx),%eax 8048447: 83 eb 04 sub $0x4,%ebx 804844a: 83 f8 ff cmp $0xffffffff,%eax 804844d: 75 f3 jne 8048442 <__do_global_ctors_aux+0x16> 804844f: 83 c4 04 add $0x4,%esp 8048452: 5b pop %ebx 8048453: 5d pop %ebp 8048454: c3 ret 8048455: 90 nop 8048456: 90 nop 8048457: 90 nop Disassembly of section .fini:
08048458 <_fini>: 8048458: 55 push %ebp 8048459: 89 e5 mov %esp,%ebp 804845b: 53 push %ebx 804845c: e8 a7 fe ff ff call 8048308 <__i686.get_pc_thunk.bx> 8048461: 81 c3 13 11 00 00 add $0x1113,%ebx 8048467: 83 ec 04 sub $0x4,%esp 804846a: e8 9d fe ff ff call 804830c <__do_global_dtors_aux> 804846f: 83 c4 04 add $0x4,%esp 8048472: 5b pop %ebx 8048473: 5d pop %ebp 8048474: c3 ret
对于那些着迷于底层编程细节的程序员来说,这是一个功能非常强大的工具,可用于研究编译器和汇编器的输出。细节信息,比如这段代码中所显示的这些信息,可以揭示有关本地处理器本身运行方式的很多内容。对该处理器制造商提供的技术文档进行深入的研究,您可以收集关于一些有价值的信息,通过这些信息可以深入地了解内部的运行机制,因为功能程序提供了清晰的输出。
类似地,readelf 程序也可以清楚地列出目标文件中的内容。输入下面的命令,您将可以看到这一点:
readelf -all a.out |
这个命令生成的输出如清单 4 所示。ELF Header 为该文件中所有段入口显示了详细的摘要。在列举出这些 Header 中的内容之前,您可以看到 Header 的具体数目。在研究一个较大的目标文件时,该信息可能非常有用。
ELF Header: Magic: 7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00 Class: ELF32 Data: 2's complement, little endian Version: 1 (current) OS/ABI: UNIX - System V ABI Version: 0 Type: EXEC (Executable file) Machine: Intel 80386 Version: 0x1 Entry point address: 0x80482c0 Start of program headers: 52 (bytes into file) Start of section headers: 3504 (bytes into file) Flags: 0x0 Size of this header: 52 (bytes) Size of program headers: 32 (bytes) Number of program headers: 7 Size of section headers: 40 (bytes) Number of section headers: 34 Section header string table index: 31 Section Headers: [Nr] Name Type Addr Off Size ES Flg Lk Inf Al [ 0] NULL 00000000 000000 000000 00 0 0 0 [ 1] .interp PROGBITS 08048114 000114 000013 00 A 0 0 1 [ 2] .note.ABI-tag NOTE 08048128 000128 000020 00 A 0 0 4 [ 3] .hash HASH 08048148 000148 00002c 04 A 4 0 4 [ 4] .dynsym DYNSYM 08048174 000174 000060 10 A 5 1 4 [ 5] .dynstr STRTAB 080481d4 0001d4 00005e 00 A 0 0 1 [ 6] .gnu.version VERSYM 08048232 000232 00000c 02 A 4 0 2 [ 7] .gnu.version_r VERNEED 08048240 000240 000020 00 A 5 1 4 [ 8] .rel.dyn REL 08048260 000260 000008 08 A 4 0 4 [ 9] .rel.plt REL 08048268 000268 000010 08 A 4 11 4 [10] .init PROGBITS 08048278 000278 000017 00 AX 0 0 1 [11] .plt PROGBITS 08048290 000290 000030 04 AX 0 0 4 [12] .text PROGBITS 080482c0 0002c0 000198 00 AX 0 0 4 [13] .fini PROGBITS 08048458 000458 00001d 00 AX 0 0 1 [14] .rodata PROGBITS 08048478 000478 000015 00 A 0 0 4 [15] .eh_frame PROGBITS 08048490 000490 000004 00 A 0 0 4 [16] .ctors PROGBITS 08049494 000494 000008 00 WA 0 0 4 [17] .dtors PROGBITS 0804949c 00049c 000008 00 WA 0 0 4 [18] .jcr PROGBITS 080494a4 0004a4 000004 00 WA 0 0 4 [19] .dynamic DYNAMIC 080494a8 0004a8 0000c8 08 WA 5 0 4 [20] .got PROGBITS 08049570 000570 000004 04 WA 0 0 4 [21] .got.plt PROGBITS 08049574 000574 000014 04 WA 0 0 4 [22] .data PROGBITS 08049588 000588 00000c 00 WA 0 0 4 [23] .bss NOBITS 08049594 000594 000004 00 WA 0 0 4 [24] .comment PROGBITS 00000000 000594 000126 00 0 0 1 [25] .debug_aranges PROGBITS 00000000 0006c0 000088 00 0 0 8 [26] .debug_pubnames PROGBITS 00000000 000748 000025 00 0 0 1 [27] .debug_info PROGBITS 00000000 00076d 00022b 00 0 0 1 [28] .debug_abbrev PROGBITS 00000000 000998 000076 00 0 0 1 [29] .debug_line PROGBITS 00000000 000a0e 0001bb 00 0 0 1 [30] .debug_str PROGBITS 00000000 000bc9 0000bf 01 MS 0 0 1 [31] .shstrtab STRTAB 00000000 000c88 000127 00 0 0 1 [32] .symtab SYMTAB 00000000 001300 000520 10 33 63 4 [33] .strtab STRTAB 00000000 001820 0002d2 00 0 0 1 Key to Flags: W (write), A (alloc), X (execute), M (merge), S (strings) I (info), L (link order), G (group), x (unknown) O (extra OS processing required) o (OS specific), p (processor specific) There are no section groups in this file. Program Headers: Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align PHDR 0x000034 0x08048034 0x08048034 0x000e0 0x000e0 R E 0x4 INTERP 0x000114 0x08048114 0x08048114 0x00013 0x00013 R 0x1 [Requesting program interpreter: /lib/ld-linux.so.2] LOAD 0x000000 0x08048000 0x08048000 0x00494 0x00494 R E 0x1000 LOAD 0x000494 0x08049494 0x08049494 0x00100 0x00104 RW 0x1000 DYNAMIC 0x0004a8 0x080494a8 0x080494a8 0x000c8 0x000c8 RW 0x4 NOTE 0x000128 0x08048128 0x08048128 0x00020 0x00020 R 0x4 GNU_STACK 0x000000 0x00000000 0x00000000 0x00000 0x00000 RW 0x4 Section to Segment mapping: Segment Sections... 00 01 .interp 02 .interp .note.ABI-tag .hash .dynsym .dynstr .gnu.version .gnu.version_r .rel.dyn .rel.plt .init .plt .text .fini .rodata .eh_frame 03 .ctors .dtors .jcr .dynamic .got .got.plt .data .bss 04 .dynamic 05 .note.ABI-tag 06 |
Dynamic section at offset 0x4a8 contains 20 entries: Tag Type Name/Value 0x00000001 (NEEDED) Shared library: [libc.so.6] 0x0000000c (INIT) 0x8048278 0x0000000d (FINI) 0x8048458 0x00000004 (HASH) 0x8048148 0x00000005 (STRTAB) 0x80481d4 0x00000006 (SYMTAB) 0x8048174 0x0000000a (STRSZ) 94 (bytes) 0x0000000b (SYMENT) 16 (bytes) 0x00000015 (DEBUG) 0x0 0x00000003 (PLTGOT) 0x8049574 0x00000002 (PLTRELSZ) 16 (bytes) 0x00000014 (PLTREL) REL 0x00000017 (JMPREL) 0x8048268 0x00000011 (REL) 0x8048260 0x00000012 (RELSZ) 8 (bytes) 0x00000013 (RELENT) 8 (bytes) 0x6ffffffe (VERNEED) 0x8048240 0x6fffffff (VERNEEDNUM) 1 0x6ffffff0 (VERSYM) 0x8048232 0x00000000 (NULL) 0x0 Relocation section '.rel.dyn' at offset 0x260 contains 1 entries: Offset Info Type Sym.Value Sym. Name 08049570 00000506 R_386_GLOB_DAT 00000000 __gmon_start__ Relocation section '.rel.plt' at offset 0x268 contains 2 entries: Offset Info Type Sym.Value Sym. Name 08049580 00000107 R_386_JUMP_SLOT 00000000 puts 08049584 00000207 R_386_JUMP_SLOT 00000000 __libc_start_main There are no unwind sections in this file. Symbol table '.dynsym' contains 6 entries: Num: Value Size Type Bind Vis Ndx Name 0: 00000000 0 NOTYPE LOCAL DEFAULT UND 1: 00000000 378 FUNC GLOBAL DEFAULT UND puts@GLIBC_2.0 (2) 2: 00000000 230 FUNC GLOBAL DEFAULT UND __libc_start_main@GLIBC_2.0 (2) 3: 0804847c 4 OBJECT GLOBAL DEFAULT 14 _IO_stdin_used 4: 00000000 0 NOTYPE WEAK DEFAULT UND _Jv_RegisterClasses 5: 00000000 0 NOTYPE WEAK DEFAULT UND __gmon_start__ Symbol table '.symtab' contains 82 entries: Num: Value Size Type Bind Vis Ndx Name 0: 00000000 0 NOTYPE LOCAL DEFAULT UND 1: 08048114 0 SECTION LOCAL DEFAULT 1 2: 08048128 0 SECTION LOCAL DEFAULT 2 3: 08048148 0 SECTION LOCAL DEFAULT 3 4: 08048174 0 SECTION LOCAL DEFAULT 4 5: 080481d4 0 SECTION LOCAL DEFAULT 5 6: 08048232 0 SECTION LOCAL DEFAULT 6 7: 08048240 0 SECTION LOCAL DEFAULT 7 8: 08048260 0 SECTION LOCAL DEFAULT 8 9: 08048268 0 SECTION LOCAL DEFAULT 9 10: 08048278 0 SECTION LOCAL DEFAULT 10 11: 08048290 0 SECTION LOCAL DEFAULT 11 12: 080482c0 0 SECTION LOCAL DEFAULT 12 13: 08048458 0 SECTION LOCAL DEFAULT 13 14: 08048478 0 SECTION LOCAL DEFAULT 14 15: 08048490 0 SECTION LOCAL DEFAULT 15 16: 08049494 0 SECTION LOCAL DEFAULT 16 17: 0804949c 0 SECTION LOCAL DEFAULT 17 18: 080494a4 0 SECTION LOCAL DEFAULT 18 19: 080494a8 0 SECTION LOCAL DEFAULT 19 20: 08049570 0 SECTION LOCAL DEFAULT 20 21: 08049574 0 SECTION LOCAL DEFAULT 21 22: 08049588 0 SECTION LOCAL DEFAULT 22 23: 08049594 0 SECTION LOCAL DEFAULT 23 24: 00000000 0 SECTION LOCAL DEFAULT 24 25: 00000000 0 SECTION LOCAL DEFAULT 25 26: 00000000 0 SECTION LOCAL DEFAULT 26 27: 00000000 0 SECTION LOCAL DEFAULT 27 28: 00000000 0 SECTION LOCAL DEFAULT 28 29: 00000000 0 SECTION LOCAL DEFAULT 29 30: 00000000 0 SECTION LOCAL DEFAULT 30 31: 00000000 0 SECTION LOCAL DEFAULT 31 32: 00000000 0 SECTION LOCAL DEFAULT 32 33: 00000000 0 SECTION LOCAL DEFAULT 33 34: 00000000 0 FILE LOCAL DEFAULT ABS abi-note.S 35: 00000000 0 FILE LOCAL DEFAULT ABS ../sysdeps/i386/elf/start 36: 00000000 0 FILE LOCAL DEFAULT ABS init.c 37: 00000000 0 FILE LOCAL DEFAULT ABS initfini.c 38: 00000000 0 FILE LOCAL DEFAULT ABS /build/buildd/glibc-2.3.6 39: 080482e4 0 FUNC LOCAL DEFAULT 12 call_gmon_start 40: 00000000 0 FILE LOCAL DEFAULT ABS crtstuff.c 41: 08049494 0 OBJECT LOCAL DEFAULT 16 __CTOR_LIST__ 42: 0804949c 0 OBJECT LOCAL DEFAULT 17 __DTOR_LIST__ 43: 080494a4 0 OBJECT LOCAL DEFAULT 18 __JCR_LIST__ 44: 08049594 1 OBJECT LOCAL DEFAULT 23 completed.4463 45: 08049590 0 OBJECT LOCAL DEFAULT 22 p.4462 46: 0804830c 0 FUNC LOCAL DEFAULT 12 __do_global_dtors_aux 47: 0804833b 0 FUNC LOCAL DEFAULT 12 frame_dummy 48: 00000000 0 FILE LOCAL DEFAULT ABS crtstuff.c 49: 08049498 0 OBJECT LOCAL DEFAULT 16 __CTOR_END__ 50: 080494a0 0 OBJECT LOCAL DEFAULT 17 __DTOR_END__ 51: 08048490 0 OBJECT LOCAL DEFAULT 15 __FRAME_END__ 52: 080494a4 0 OBJECT LOCAL DEFAULT 18 __JCR_END__ 53: 0804842c 0 FUNC LOCAL DEFAULT 12 __do_global_ctors_aux 54: 00000000 0 FILE LOCAL DEFAULT ABS initfini.c 55: 00000000 0 FILE LOCAL DEFAULT ABS /build/buildd/glibc-2.3.6 56: 00000000 0 FILE LOCAL DEFAULT ABS hw.c 57: 080494a8 0 OBJECT LOCAL HIDDEN 19 _DYNAMIC 58: 08049494 0 NOTYPE LOCAL HIDDEN ABS __fini_array_end 59: 08049494 0 NOTYPE LOCAL HIDDEN ABS __fini_array_start 60: 08049494 0 NOTYPE LOCAL HIDDEN ABS __init_array_end 61: 08049574 0 OBJECT LOCAL HIDDEN 21 _GLOBAL_OFFSET_TABLE_ 62: 08049494 0 NOTYPE LOCAL HIDDEN ABS __init_array_start 63: 08048478 4 OBJECT GLOBAL DEFAULT 14 _fp_hw 64: 0804958c 0 OBJECT GLOBAL HIDDEN 22 __dso_handle 65: 080483e1 74 FUNC GLOBAL DEFAULT 12 __libc_csu_fini 66: 00000000 378 FUNC GLOBAL DEFAULT UND puts@@GLIBC_2.0 67: 08048278 0 FUNC GLOBAL DEFAULT 10 _init 68: 080482c0 0 FUNC GLOBAL DEFAULT 12 _start 69: 08048390 81 FUNC GLOBAL DEFAULT 12 __libc_csu_init 70: 08049594 0 NOTYPE GLOBAL DEFAULT ABS __bss_start 71: 08048360 47 FUNC GLOBAL DEFAULT 12 main 72: 00000000 230 FUNC GLOBAL DEFAULT UND __libc_start_main@@GLIBC_ 73: 08049588 0 NOTYPE WEAK DEFAULT 22 data_start 74: 08048458 0 FUNC GLOBAL DEFAULT 13 _fini 75: 08049594 0 NOTYPE GLOBAL DEFAULT ABS _edata 76: 08048308 0 FUNC GLOBAL HIDDEN 12 __i686.get_pc_thunk.bx 77: 08049598 0 NOTYPE GLOBAL DEFAULT ABS _end 78: 0804847c 4 OBJECT GLOBAL DEFAULT 14 _IO_stdin_used 79: 08049588 0 NOTYPE GLOBAL DEFAULT 22 __data_start 80: 00000000 0 NOTYPE WEAK DEFAULT UND _Jv_RegisterClasses 81: 00000000 0 NOTYPE WEAK DEFAULT UND __gmon_start__ Histogram for bucket list length (total of 3 buckets): Length Number % of total Coverage 0 0 ( 0.0%) 1 1 ( 33.3%) 20.0% 2 2 ( 66.7%) 100.0% Version symbols section '.gnu.version' contains 6 entries: Addr: 0000000008048232 Offset: 0x000232 Link: 4 (.dynsym) 000: 0 (*local*) 2 (GLIBC_2.0) 2 (GLIBC_2.0) 1 (*global*) 004: 0 (*local*) 0 (*local*) Version needs section '.gnu.version_r' contains 1 entries: Addr: 0x0000000008048240 Offset: 0x000240 Link to section: 5 (.dynstr) 000000: Version: 1 File: libc.so.6 Cnt: 1 0x0010: Name: GLIBC_2.0 Flags: none Version: 2 Notes at offset 0x00000128 with length 0x00000020: Owner Data size Description GNU 0x00000010 NT_VERSION (version)
除了所有这些段之外,编译器可以将调试信息放入到目标文件中,并且还可以显示这些信息。输入下面的命令,仔细分析编译器的输出(假设您扮演了调试程序的角色):
readelf --debug-dump a.out | less |
这个命令生成的输出如清单 5 所示。调试工具,如 GDB,可以读取这些调试信息,并且当程序在调试器中运行的同时,您可以使用该工具显示更具描述性的标记,而不是对代码进行反汇编时的原始地址值。
The section .debug_aranges contains: Length: 28 Version: 2 Offset into .debug_info: 0 Pointer Size: 4 Segment Size: 0 Address Length 080482c0 34 Length: 52 Version: 2 Offset into .debug_info: 10b Pointer Size: 4 Segment Size: 0 Address Length 08048308 4 08048458 18 08048278 11 080482e4 36 Length: 44 Version: 2 Offset into .debug_info: 19b Pointer Size: 4 Segment Size: 0 Address Length 08048308 4 0804846f 6 0804828d 2 Contents of the .debug_pubnames section: Length: 33 Version: 2 Offset into .debug_info section: 122 Size of area in .debug_info section: 145 Offset Name 121 _IO_stdin_used The section .debug_info contains: Compilation Unit @ offset 0x0: Length: 118 Version: 2 Abbrev Offset: 0 Pointer Size: 4 <0><b>: Abbrev Number: 1 (DW_TAG_compile_unit) DW_AT_stmt_list : 0 DW_AT_low_pc : 0x80482c0 DW_AT_high_pc : 0x80482e2 DW_AT_name : ../sysdeps/i386/elf/start.S DW_AT_comp_dir : /build/buildd/glibc-2.3.6/build-tree/glibc-2.3.6/csu DW_AT_producer : GNU AS 2.16.91 DW_AT_language : 32769 (MIPS assembler) Compilation Unit @ offset 0x7a: Length: 141 Version: 2 Abbrev Offset: 20 Pointer Size: 4 <0><85>: Abbrev Number: 1 (DW_TAG_compile_unit) DW_AT_stmt_list : 0x5b DW_AT_high_pc : 0x80482e4 DW_AT_low_pc : 0x80482e4 DW_AT_producer : (indirect string, offset: 0x62): GNU C 3.4.6 DW_AT_language : 1 (ANSI C) DW_AT_name : (indirect string, offset: 0x0): init.c DW_AT_comp_dir : (indirect string, offset: 0x11): /build/buildd/... <1><9f>: Abbrev Number: 2 (DW_TAG_base_type) DW_AT_name : (indirect string, offset: 0x90): unsigned int DW_AT_byte_size : 4 DW_AT_encoding : 7 (unsigned) <1><a6>: Abbrev Number: 2 (DW_TAG_base_type) DW_AT_name : (indirect string, offset: 0x54): unsigned char DW_AT_byte_size : 1 DW_AT_encoding : 8 (unsigned char) <1><ad>: Abbrev Number: 2 (DW_TAG_base_type) DW_AT_name : (indirect string, offset: 0x9d): short unsigned int DW_AT_byte_size : 2 DW_AT_encoding : 7 (unsigned) <1><b4>: Abbrev Number: 2 (DW_TAG_base_type) DW_AT_name : (indirect string, offset: 0x8b): long unsigned int DW_AT_byte_size : 4 DW_AT_encoding : 7 (unsigned) <1><bb>: Abbrev Number: 2 (DW_TAG_base_type) DW_AT_name : (indirect string, offset: 0x56): signed char DW_AT_byte_size : 1 DW_AT_encoding : 6 (signed char) <1><c2>: Abbrev Number: 2 (DW_TAG_base_type) DW_AT_name : (indirect string, offset: 0x7): short int DW_AT_byte_size : 2 DW_AT_encoding : 5 (signed) <1><c9>: Abbrev Number: 3 (DW_TAG_base_type) DW_AT_name : int DW_AT_byte_size : 4 DW_AT_encoding : 5 (signed) <1><d0>: Abbrev Number: 2 (DW_TAG_base_type) DW_AT_name : (indirect string, offset: 0x46): long long int DW_AT_byte_size : 8 DW_AT_encoding : 5 (signed) <1><d7>: Abbrev Number: 2 (DW_TAG_base_type) DW_AT_name : (indirect string, offset: 0x86): long long unsigned int DW_AT_byte_size : 8 DW_AT_encoding : 7 (unsigned) <1><de>: Abbrev Number: 2 (DW_TAG_base_type) DW_AT_name : (indirect string, offset: 0x4b): long int DW_AT_byte_size : 4 DW_AT_encoding : 5 (signed) <1><e5>: Abbrev Number: 2 (DW_TAG_base_type) DW_AT_name : (indirect string, offset: 0x90): unsigned int DW_AT_byte_size : 4 DW_AT_encoding : 7 (unsigned) <1><ec>: Abbrev Number: 2 (DW_TAG_base_type) DW_AT_name : (indirect string, offset: 0x5d): char DW_AT_byte_size : 1 DW_AT_encoding : 6 (signed char) <1><f3>: Abbrev Number: 4 (DW_TAG_variable) DW_AT_name : (indirect string, offset: 0xb0): _IO_stdin_used DW_AT_decl_file : 1 DW_AT_decl_line : 25 DW_AT_type : <105> DW_AT_external : 1 DW_AT_location : 5 byte block: 3 7c 84 4 8 (DW_OP_addr: 804847c) <1><105>: Abbrev Number: 5 (DW_TAG_const_type) DW_AT_type : <c9> Compilation Unit @ offset 0x10b: Length: 140 Version: 2 Abbrev Offset: 86 Pointer Size: 4 <0><116>: Abbrev Number: 1 (DW_TAG_compile_unit) DW_AT_stmt_list : 0x82 DW_AT_name : /build/buildd/glibc-2.3.6/build-tree/i386-libc/csu/crti.S DW_AT_comp_dir : /build/buildd/glibc-2.3.6/build-tree/glibc-2.3.6/csu DW_AT_producer : GNU AS 2.16.91 DW_AT_language : 32769 (MIPS assembler) Compilation Unit @ offset 0x19b: Length: 140 Version: 2 Abbrev Offset: 102 Pointer Size: 4 <0><1a6>: Abbrev Number: 1 (DW_TAG_compile_unit) DW_AT_stmt_list : 0x12f DW_AT_name : /build/buildd/glibc-2.3.6/build-tree/i386-libc/csu/crtn.S DW_AT_comp_dir : /build/buildd/glibc-2.3.6/build-tree/glibc-2.3.6/csu DW_AT_producer : GNU AS 2.16.91 DW_AT_language : 32769 (MIPS assembler) |
可执行文件是目标文件
在 UNIX 中,可执行文件是 目标文件,并且您可以像对 a.out 文件那样对它们进行分析。可以进行一次有益的练习,更改到 /bin 或 /local/bin 目录,然后针对一些您最常用的命令,如 pwd、ps、cat 或 rm,运行 nm、objdump 和 readelf。通常,在您编写需要某种功能的程序时,如果标准的工具已经提供了这个功能,那么通过运行 objdump -d <command>,可以查看这些工具究竟如何完成这项任务。
如果您倾向于使用编译器和其他的语言工具,那么您可以对组成计算机系统的各种目标文件进行仔细研究,并且您将会发现这项工作是非常值得的。UNIX 操作系统具有许多层次,那些通过工具查看目标文件所公开的层次,非常接近底层硬件。通过这种方式,您可以真实地接触到系统。
结束语
研究目标文件可以极大地加深您对 UNIX 操作系统的认识,并且可以更深入地了解如何对软件的源代码进行汇编。我鼓励您使用本文中介绍的目标文件工具对系统中 /bin 或 /local/bin 目录中的程序进行分析,仔细研究其输出结果,并找出您的硬件制造商所提供的系统文档。
如果您非常迫切的想了解IT领域最新产品与技术信息,那么订阅至顶网技术邮件将是您的最佳途径之一。
5G已至 转型当时——服务提供商如何把握转型的绝佳时机
去集群 更超群——大容量网络演进之路
2019 IBM 中国论坛
H3C 2019 Navigate 领航者峰会
助推数据中心网络现代化转型 打造灵活可靠基础架构平台