UNIX 目标文件初探

Unix(R) 系统中运行的程序遵守一种称为目标文件格式的精心设计 。了解更多关于目标文件格式的内容,以及可以用来研究系统中目标文件的工具 。
计算机编程的最新技术将一种特殊的人性与一组特殊的工具结合在一起,用以生产出对其他人非常有帮助的一种神奇的产品,即软件 。计算机程序员是一群注重细节的人,他们可以处理计算机中各种各样的困难 。计算机的要求非常苛刻,并且不能容忍其中存在任何的偏差 。毫无疑问,无论您的个性如何以及在工作中使用了何种辅助工具,计算机程序的编写都是非常困难的 。
在 UNIX?和 Linux?中,任何事物都是文件 。您可以认为,UNIX 和 Linux 编程实际上是编写处理各种文件的代码 。系统由许多类型的文件组成,但目标文件具有一种特殊的设计,提供了灵活和多样的用途 。
目标文件是包含带有附加地址和值的助记符号的路线图 。这些符号可以用来对各种代码段和数据段进行命名,包括经过初始化的和未初始化的 。它们也可以用来定位嵌入的调试信息,就像语义 Web,非常适合由程序进行阅读 。
行业工具
【UNIX 目标文件初探】计算机编程中使用的工具包括代码编辑器,如 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 。
清单 1. hw.c 程序#include
int main(void)
{
 printf("Hello World!
");
 return 0;
}
要使用 UNIX 工具库中提供的各种工具,可以将这个简单的“Hello World程序作为研究的对象 。您将学习构建和查看目标文件的输出,而不是使用任何快捷方法直接创建可执行文件(的确有许多这样的快捷方法) 。
文件格式
C 编译器的正常输出是用于您所指定的目标处理器的汇编代码 。汇编代码是汇编器的输入,在缺省情况下,汇编器将生成所有目标文件的祖先,即 a.out 文件 。这个名称本身表示汇编输出 (Assembler Output) 。要创建 a.out 文件,可以在 xterm 窗口中输入下面的命令:
cc hw.c
注意:如果出现了任何错误或者没有创建 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:列出目标文件中的符号 。objdump:显示目标文件中的详细信息 。readelf:显示关于 ELF 目标文件的信息 。列表中的第一个工具是 nm,它可以列出目标文件中的符号 。如果您输入 nm 命令,您将注意到在缺省情况下,它会寻找一个名为 a.out 的文件 。如果没有找到该文件,这个工具会给出相应的提示 。然而,如果该工具找到了编译器创建的 a.out 文件,它将显示类似清单 2 的清单 。
清单 2. nm 命令的输出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 所示 。每个可执行代码段将在需要特定的事件时执行,这些事件包括库的初始化和该程序本身主入口点 。
清单 3. objdump 命令的输出a.out: file format elf32-i386
Disassembly of section .init:
08048278 <_init>:
8048278:55 push雙
8048279:89 e5mov%esp,雙
804827b:83 ec 08sub$0x8,%esp
804827e:e8 61 00 00 00 call80482e4
8048283:e8 b3 00 00 00 call804833b
8048288:e8 9f 01 00 00 call804842c <__do_global_ctors_aux>
804828d:c9 leave
804828e:c3 ret
Disassembly of section .plt:
08048290 :
8048290:ff 35 78 95 04 08pushl 0x8049578
8048296:ff 25 7c 95 04 08jmp*0x804957c
804829c:00 00add%al,(陎)
...
080482a0 :
80482a0:ff 25 80 95 04 08jmp*0x8049580
80482a6:68 00 00 00 00 push$0x0
80482ab:e9 e0 ff ff ff jmp8048290 <_init 0x18>
080482b0 <__libc_start_main@plt>:
80482b0:ff 25 84 95 04 08jmp*0x8049584
80482b6:68 08 00 00 00 push$0x8
80482bb:e9 d0 ff ff ff jmp8048290 <_init 0x18>
Disassembly of section .text:
080482c0 <_start>:
80482c0:31 edxor雙,雙
80482c2:5e pop%esi
80482c3:89 e1mov%esp,靫
80482c5:83 e4 f0and$0xfffffff0,%esp
80482c8:50 push陎
80482c9:54 push%esp
80482ca:52 push韝
80482cb:68 e1 83 04 08 push$0x80483e1
80482d0:68 90 83 04 08 push$0x8048390
80482d5:51 push靫
80482d6:56 push%esi
80482d7:68 60 83 04 08 push$0x8048360
80482dc:e8 cf ff ff ff call80482b0 <__libc_start_main@plt>
80482e1:f4 hlt
80482e2:90 nop
80482e3:90 nop
080482e4 :
80482e4:55 push雙
80482e5:89 e5mov%esp,雙
80482e7:53 push離
80482e8:e8 1b 00 00 00 call8048308 <__i686.get_pc_thunk.bx>
80482ed:81 c3 87 12 00 00add$0x1287,離
80482f3:83 ec 04sub$0x4,%esp
80482f6:8b 83 fc ff ff ffmov0xfffffffc(離),陎
80482fc:85 c0test陎,陎
80482fe:74 02je 8048302
8048300:ff d0call*陎
8048302:83 c4 04add$0x4,%esp
8048305:5b pop離
8048306:5d pop雙
8048307:c3 ret
08048308 <__i686.get_pc_thunk.bx>:
8048308:8b 1c 24mov(%esp),離
804830b:c3 ret
0804830c <__do_global_dtors_aux>:
804830c:55 push雙
804830d:89 e5mov%esp,雙
804830f:83 ec 08sub$0x8,%esp
8048312:80 3d 94 95 04 08 00cmpb$0x0,0x8049594
8048319:74 0cje 8048327 <__do_global_dtors_aux 0x1b>
804831b:eb 1cjmp8048339 <__do_global_dtors_aux 0x2d>
804831d:83 c0 04add$0x4,陎
8048320:a3 90 95 04 08 mov陎,0x8049590
8048325:ff d2call*韝
8048327:a1 90 95 04 08 mov0x8049590,陎
804832c:8b 10mov(陎),韝
804832e:85 d2test韝,韝
8048330:75 ebjne804831d <__do_global_dtors_aux 0x11>
8048332:c6 05 94 95 04 08 01movb$0x1,0x8049594
8048339:c9 leave
804833a:c3 ret
0804833b :
804833b:55 push雙
804833c:89 e5mov%esp,雙
804833e:83 ec 08sub$0x8,%esp
8048341:a1 a4 94 04 08 mov0x80494a4,陎
8048346:85 c0test陎,陎
8048348:74 12je 804835c
804834a:b8 00 00 00 00 mov$0x0,陎
804834f:85 c0test陎,陎
8048351:74 09je 804835c
8048353:c7 04 24 a4 94 04 08movl$0x80494a4,(%esp)
804835a:ff d0call*陎
804835c:c9 leave
804835d:c3 ret
804835e:90 nop
804835f:90 nop
08048360

:
8048360:55 push雙
8048361:89 e5mov%esp,雙
8048363:83 ec 08sub$0x8,%esp
8048366:83 e4 f0and$0xfffffff0,%esp
8048369:b8 00 00 00 00 mov$0x0,陎
804836e:83 c0 0fadd$0xf,陎
8048371:83 c0 0fadd$0xf,陎
8048374:c1 e8 04shr$0x4,陎
8048377:c1 e0 04shl$0x4,陎
804837a:29 c4sub陎,%esp
804837c:c7 04 24 80 84 04 08movl$0x8048480,(%esp)
8048383:e8 18 ff ff ff call80482a0
8048388:b8 00 00 00 00 mov$0x0,陎
804838d:c9 leave
804838e:c3 ret
804838f:90 nop
08048390 <__libc_csu_init>:
8048390:55 push雙
8048391:89 e5mov%esp,雙
8048393:57 push韎
8048394:56 push%esi
8048395:31 f6xor%esi,%esi
8048397:53 push離
8048398:e8 6b ff ff ff call8048308 <__i686.get_pc_thunk.bx>
804839d:81 c3 d7 11 00 00add$0x11d7,離
80483a3:83 ec 0csub$0xc,%esp
80483a6:e8 cd fe ff ff call8048278 <_init>
80483ab:8d 83 20 ff ff fflea0xffffff20(離),陎
80483b1:8d 93 20 ff ff fflea0xffffff20(離),韝
80483b7:89 45 f0mov陎,0xfffffff0(雙)
80483ba:29 d0sub韝,陎
80483bc:c1 f8 02sar$0x2,陎
80483bf:39 c6cmp陎,%esi
80483c1:73 16jae80483d9 <__libc_csu_init 0x49>
80483c3:89 d7mov韝,韎
80483c5:ff 14 b2call*(韝,%esi,4)
80483c8:8b 45 f0mov0xfffffff0(雙),陎
80483cb:83 c6 01add$0x1,%esi
80483ce:29 f8sub韎,陎
80483d0:89 famov韎,韝
80483d2:c1 f8 02sar$0x2,陎
80483d5:39 c6cmp陎,%esi
80483d7:72 ecjb 80483c5 <__libc_csu_init 0x35>
80483d9:83 c4 0cadd$0xc,%esp
80483dc:5b pop離
80483dd:5e pop%esi
80483de:5f pop韎
80483df:5d pop雙
80483e0:c3 ret
080483e1 <__libc_csu_fini>:
80483e1:55 push雙
80483e2:89 e5mov%esp,雙
80483e4:83 ec 18sub$0x18,%esp
80483e7:89 5d f4mov離,0xfffffff4(雙)
80483ea:e8 19 ff ff ff call8048308 <__i686.get_pc_thunk.bx>
80483ef:81 c3 85 11 00 00add$0x1185,離
80483f5:89 75 f8mov%esi,0xfffffff8(雙)
80483f8:89 7d fcmov韎,0xfffffffc(雙)
80483fb:8d b3 20 ff ff fflea0xffffff20(離),%esi
8048401:8d bb 20 ff ff fflea0xffffff20(離),韎
8048407:29 fesub韎,%esi
8048409:c1 fe 02sar$0x2,%esi
804840c:eb 03jmp8048411 <__libc_csu_fini 0x30>
804840e:ff 14 b7call*(韎,%esi,4)
8048411:83 ee 01sub$0x1,%esi
8048414:83 fe ffcmp$0xffffffff,%esi
8048417:75 f5jne804840e <__libc_csu_fini 0x2d>
8048419:e8 3a 00 00 00 call8048458 <_fini>
804841e:8b 5d f4mov0xfffffff4(雙),離
8048421:8b 75 f8mov0xfffffff8(雙),%esi
8048424:8b 7d fcmov0xfffffffc(雙),韎
8048427:89 ecmov雙,%esp
8048429:5d pop雙
804842a:c3 ret
804842b:90 nop
0804842c <__do_global_ctors_aux>:
804842c:55 push雙
804842d:89 e5mov%esp,雙
804842f:53 push離
8048430:83 ec 04sub$0x4,%esp
8048433:a1 94 94 04 08 mov0x8049494,陎
8048438:83 f8 ffcmp$0xffffffff,陎
804843b:74 12je 804844f <__do_global_ctors_aux 0x23>
804843d:bb 94 94 04 08 mov$0x8049494,離
8048442:ff d0call*陎
8048444:8b 43 fcmov0xfffffffc(離),陎
8048447:83 eb 04sub$0x4,離
804844a:83 f8 ffcmp$0xffffffff,陎
804844d:75 f3jne8048442 <__do_global_ctors_aux 0x16>
804844f:83 c4 04add$0x4,%esp
8048452:5b pop離
8048453:5d pop雙
8048454:c3 ret
8048455:90 nop
8048456:90 nop
8048457:90 nop
Disassembly of section .fini:
08048458 <_fini>:
8048458:55 push雙
8048459:89 e5mov%esp,雙
804845b:53 push離
804845c:e8 a7 fe ff ff call8048308 <__i686.get_pc_thunk.bx>
8048461:81 c3 13 11 00 00add$0x1113,離
8048467:83 ec 04sub$0x4,%esp
804846a:e8 9d fe ff ff call804830c <__do_global_dtors_aux>
804846f:83 c4 04add$0x4,%esp
8048472:5b pop離
8048473:5d pop雙
8048474:c3 ret
正如从该输出中看到的,简单的 a.out Hello World 文件中包含了大量有价值的细节信息,包括版本信息、柱状图、各种符号类型的表格,等等 。通过使用本文中介绍的这几种工具分析目标文件,您可以慢慢地对可执行程序进行研究 。
除了所有这些段之外,编译器可以将调试信息放入到目标文件中,并且还可以显示这些信息 。输入下面的命令,仔细分析编译器的输出(假设您扮演了调试程序的角色):
readelf --debug-dump a.out | less
这个命令生成的输出如清单 5 所示 。调试工具,如 GDB,可以读取这些调试信息,并且当程序在调试器中运行的同时,您可以使用该工具显示更具描述性的标记,而不是对代码进行反汇编时的原始地址值 。
清单 5. 该程序中的调试信息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>: 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>: 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>: 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>: 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>: 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>: 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>: Abbrev Number: 3 (DW_TAG_base_type)
DW_AT_name: int
DW_AT_byte_size: 4
DW_AT_encoding: 5 (signed)
<1>: 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>: 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>: 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>: 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>: 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>: 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:
 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)
Contents of the .debug_abbrev section:
 Number TAG
1 DW_TAG_compile_unit[no children]
DW_AT_stmt_listDW_FORM_data4
DW_AT_low_pcDW_FORM_addr
DW_AT_high_pc DW_FORM_addr
DW_AT_name DW_FORM_string
DW_AT_comp_dir DW_FORM_string
DW_AT_producer DW_FORM_string
DW_AT_language DW_FORM_data2
 Number TAG
1 DW_TAG_compile_unit[has children]
DW_AT_stmt_listDW_FORM_data4
DW_AT_high_pc DW_FORM_addr
DW_AT_low_pcDW_FORM_addr
DW_AT_producer DW_FORM_strp
DW_AT_language DW_FORM_data1
DW_AT_name DW_FORM_strp
DW_AT_comp_dir DW_FORM_strp
2 DW_TAG_base_type[no children]
DW_AT_name DW_FORM_strp
DW_AT_byte_sizeDW_FORM_data1
DW_AT_encoding DW_FORM_data1
3 DW_TAG_base_type[no children]
DW_AT_name DW_FORM_string
DW_AT_byte_sizeDW_FORM_data1
DW_AT_encoding DW_FORM_data1
4 DW_TAG_variable[no children]
DW_AT_name DW_FORM_strp
DW_AT_decl_fileDW_FORM_data1
DW_AT_decl_lineDW_FORM_data1
DW_AT_type DW_FORM_ref4
DW_AT_external DW_FORM_flag
DW_AT_location DW_FORM_block1
5 DW_TAG_const_type[no children]
DW_AT_type DW_FORM_ref4
 Number TAG
1 DW_TAG_compile_unit[no children]
DW_AT_stmt_listDW_FORM_data4
DW_AT_name DW_FORM_string
DW_AT_comp_dir DW_FORM_string
DW_AT_producer DW_FORM_string
DW_AT_language DW_FORM_data2
 Number TAG
1 DW_TAG_compile_unit[no children]
DW_AT_stmt_listDW_FORM_data4
DW_AT_name DW_FORM_string
DW_AT_comp_dir DW_FORM_string
DW_AT_producer DW_FORM_string
DW_AT_language DW_FORM_data2
Dump of debug contents of section .debug_line:
 Length: 87
 DWARF Version:2
 Prologue Length: 50
 Minimum Instruction Length: 1
 Initial value of 'is_stmt': 1
 Line Base:-5
 Line Range: 14
 Opcode Base: 13
 (Pointer size:4)
Opcodes:
 Opcode 1 has 0 args
 Opcode 2 has 1 args
 Opcode 3 has 1 args
 Opcode 4 has 1 args
 Opcode 5 has 1 args
 Opcode 6 has 0 args
 Opcode 7 has 0 args
 Opcode 8 has 0 args
 Opcode 9 has 1 args
 Opcode 10 has 0 args
 Opcode 11 has 0 args
 Opcode 12 has 1 args
The Directory Table:
 ../sysdeps/i386/elf
The File Name Table:
 Entry Dir TimeSizeName
 1 100start.S
Line Number Statements:
 Extended opcode 2: set Address to 0x80482c0
 Advance Line by 64 to 65
 Copy
 Special opcode 38: advance Address by 2 to 0x80482c2 and Line by 5 to 70
 Special opcode 20: advance Address by 1 to 0x80482c3 and Line by 1 to 71
 Special opcode 39: advance Address by 2 to 0x80482c5 and Line by 6 to 77
 Special opcode 48: advance Address by 3 to 0x80482c8 and Line by 1 to 78
 Special opcode 24: advance Address by 1 to 0x80482c9 and Line by 5 to 83
 Special opcode 21: advance Address by 1 to 0x80482ca and Line by 2 to 85
 Advance Line by 24 to 109
 Special opcode 19: advance Address by 1 to 0x80482cb and Line by 0 to 109
 Special opcode 76: advance Address by 5 to 0x80482d0 and Line by 1 to 110
 Special opcode 77: advance Address by 5 to 0x80482d5 and Line by 2 to 112
 Special opcode 20: advance Address by 1 to 0x80482d6 and Line by 1 to 113
 Special opcode 21: advance Address by 1 to 0x80482d7 and Line by 2 to 115
 Special opcode 79: advance Address by 5 to 0x80482dc and Line by 4 to 119
 Special opcode 78: advance Address by 5 to 0x80482e1 and Line by 3 to 122
 Advance PC by 1 to 0x80482e2
 Extended opcode 1: End of Sequence
 Length: 35
 DWARF Version:2
 Prologue Length: 29
 Minimum Instruction Length: 1
 Initial value of 'is_stmt': 1
 Line Base:-5
 Line Range: 14
 Opcode Base: 13
 (Pointer size:4)
Opcodes:
 Opcode 1 has 0 args
 Opcode 2 has 1 args
 Opcode 3 has 1 args
 Opcode 4 has 1 args
 Opcode 5 has 1 args
 Opcode 6 has 0 args
 Opcode 7 has 0 args
 Opcode 8 has 0 args
 Opcode 9 has 1 args
 Opcode 10 has 0 args
 Opcode 11 has 0 args
 Opcode 12 has 1 args
The Directory Table is empty.
The File Name Table:
 Entry Dir TimeSizeName
 1 000init.c
Line Number Statements:
 Length: 169
 DWARF Version:2
 Prologue Length: 80
 Minimum Instruction Length: 1
 Initial value of 'is_stmt': 1
 Line Base:-5
 Line Range: 14
 Opcode Base: 13
 (Pointer size:4)
Opcodes:
 Opcode 1 has 0 args
 Opcode 2 has 1 args
 Opcode 3 has 1 args
 Opcode 4 has 1 args
 Opcode 5 has 1 args
 Opcode 6 has 0 args
 Opcode 7 has 0 args
 Opcode 8 has 0 args
 Opcode 9 has 1 args
 Opcode 10 has 0 args
 Opcode 11 has 0 args
 Opcode 12 has 1 args
The Directory Table:
 /build/buildd/glibc-2.3.6/build-tree/i386-libc/csu
The File Name Table:
 Entry Dir TimeSizeName
 1 100crti.S
Line Number Statements:
 Extended opcode 2: set Address to 0x8048308
 Advance Line by 64 to 65
 Copy
 Special opcode 48: advance Address by 3 to 0x804830b and Line by 1 to 66
 Advance PC by 1 to 0x804830c
 Extended opcode 1: End of Sequence
 Extended opcode 2: set Address to 0x8048458
 Advance Line by 46 to 47
 Copy
 Special opcode 20: advance Address by 1 to 0x8048459 and Line by 1 to 48
 Special opcode 34: advance Address by 2 to 0x804845b and Line by 1 to 49
 Special opcode 20: advance Address by 1 to 0x804845c and Line by 1 to 50
 Special opcode 76: advance Address by 5 to 0x8048461 and Line by 1 to 51
 Special opcode 90: advance Address by 6 to 0x8048467 and Line by 1 to 52
 Advance PC by 3 to 0x804846a
 Extended opcode 1: End of Sequence
 Extended opcode 2: set Address to 0x8048278
 Advance Line by 31 to 32
 Copy
 Special opcode 20: advance Address by 1 to 0x8048279 and Line by 1 to 33
 Special opcode 34: advance Address by 2 to 0x804827b and Line by 1 to 34
 Special opcode 48: advance Address by 3 to 0x804827e and Line by 1 to 35
 Advance PC by 5 to 0x8048283
 Extended opcode 1: End of Sequence
 Extended opcode 2: set Address to 0x80482e4
 Advance Line by 10 to 11
 Copy
 Special opcode 20: advance Address by 1 to 0x80482e5 and Line by 1 to 12
 Special opcode 34: advance Address by 2 to 0x80482e7 and Line by 1 to 13
 Special opcode 20: advance Address by 1 to 0x80482e8 and Line by 1 to 14
 Special opcode 76: advance Address by 5 to 0x80482ed and Line by 1 to 15
 Special opcode 90: advance Address by 6 to 0x80482f3 and Line by 1 to 16
 Special opcode 48: advance Address by 3 to 0x80482f6 and Line by 1 to 17
 Special opcode 90: advance Address by 6 to 0x80482fc and Line by 1 to 18
 Special opcode 34: advance Address by 2 to 0x80482fe and Line by 1 to 19
 Special opcode 34: advance Address by 2 to 0x8048300 and Line by 1 to 20
 Special opcode 35: advance Address by 2 to 0x8048302 and Line by 2 to 22
 Special opcode 48: advance Address by 3 to 0x8048305 and Line by 1 to 23
 Special opcode 20: advance Address by 1 to 0x8048306 and Line by 1 to 24
 Special opcode 20: advance Address by 1 to 0x8048307 and Line by 1 to 25
 Advance PC by 1 to 0x8048308
 Extended opcode 1: End of Sequence
 Length: 136
 DWARF Version:2
 Prologue Length: 80
 Minimum Instruction Length: 1
 Initial value of 'is_stmt': 1
 Line Base:-5
 Line Range: 14
 Opcode Base: 13
 (Pointer size:4)
Opcodes:
 Opcode 1 has 0 args
 Opcode 2 has 1 args
 Opcode 3 has 1 args
 Opcode 4 has 1 args
 Opcode 5 has 1 args
 Opcode 6 has 0 args
 Opcode 7 has 0 args
 Opcode 8 has 0 args
 Opcode 9 has 1 args
 Opcode 10 has 0 args
 Opcode 11 has 0 args
 Opcode 12 has 1 args
The Directory Table:
 /build/buildd/glibc-2.3.6/build-tree/i386-libc/csu
The File Name Table:
 Entry Dir TimeSizeName
 1 100crtn.S
Line Number Statements:
 Extended opcode 2: set Address to 0x8048308
 Advance Line by 33 to 34
 Copy
 Special opcode 48: advance Address by 3 to 0x804830b and Line by 1 to 35
 Advance PC by 1 to 0x804830c
 Extended opcode 1: End of Sequence
 Extended opcode 2: set Address to 0x804846f
 Advance Line by 18 to 19
 Copy
 Special opcode 48: advance Address by 3 to 0x8048472 and Line by 1 to 20
 Special opcode 20: advance Address by 1 to 0x8048473 and Line by 1 to 21
 Special opcode 20: advance Address by 1 to 0x8048474 and Line by 1 to 22
 Advance PC by 1 to 0x8048475
 Extended opcode 1: End of Sequence
 Extended opcode 2: set Address to 0x804828d
 Advance Line by 9 to 10
 Copy
 Special opcode 20: advance Address by 1 to 0x804828e and Line by 1 to 11
 Advance PC by 1 to 0x804828f
 Extended opcode 1: End of Sequence
Contents of the .debug_str section:
 0x00000000 696e6974 2e630073 686f7274 20696e74 init.c.short int
 0x00000010 002f6275 696c642f 6275696c 64642f67 ./build/buildd/g
 0x00000020 6c696263 2d322e33 2e362f62 75696c64 libc-2.3.6/build
 0x00000030 2d747265 652f676c 6962632d 322e332e -tree/glibc-2.3.
 0x00000040 362f6373 75006c6f 6e67206c 6f6e6720 6/csu.long long
 0x00000050 696e7400 756e7369 676e6564 20636861 int.unsigned cha
 0x00000060 7200474e 55204320 332e342e 36202855 r.GNU C 3.4.6 (U
 0x00000070 62756e74 7520332e 342e362d 31756275 buntu 3.4.6-1ubu
 0x00000080 6e747532 29006c6f 6e67206c 6f6e6720 ntu2).long long
 0x00000090 756e7369 676e6564 20696e74 0073686f unsigned int.sho
 0x000000a0 72742075 6e736967 6e656420 696e7400 rt unsigned int.
 0x000000b0 5f494f5f 73746469 6e5f7573 656400_IO_stdin_used.
可执行文件是目标文件
在 Unix 中,可执行文件是 目标文件,并且您可以像对 a.out 文件那样对它们进行分析 。可以进行一次有益的练习,更改到 /bin 或 /local/bin 目录,然后针对一些您最常用的命令,如 pwd、ps、cat 或 rm,运行 nm、objdump 和 readelf 。通常,在您编写需要某种功能的程序时,如果标准的工具已经提供了这个功能,那么通过运行 objdump -d ,可以查看这些工具究竟如何完成这项任务 。
如果您倾向于使用编译器和其他的语言工具,那么您可以对组成计算机系统的各种目标文件进行仔细研究,并且您将会发现这项工作是非常值得的 。UNIX 操作系统具有许多层次,那些通过工具查看目标文件所公开的层次,非常接近底层硬件 。通过这种方式,您可以真实地接触到系统 。
结束语
研究目标文件可以极大地加深您对 UNIX 操作系统的认识,并且可以更深入地了解如何对软件的源代码进行汇编 。我鼓励您使用本文中介绍的目标文件工具对系统中 /bin 或 /local/bin 目录中的程序进行分析,仔细研究其输出结果,并找出您的硬件制造商所提供的系统文档 。