Objdump

objdump是在类Unix操作系统上显示关于目标文件的各种信息的命令行程序。例如，它可用作反汇编器来以汇编代码形式查看可执行文件。它是GNU Binutils的一部分，用于在可执行文件和其他二进制数据上进行精细粒度控制。objdump使用BFD库来读取目标文件的内容。类似工具还有readelf、Microsoft DUMPBIN和Borland TDUMP。 注意在特定平台（比如Mac OS X）上，objdump二进制文件可能实际上被连接到LLVM的objdump，它有着不同的命令选项和表现。 比如对nm条目的例子代码编译成的目标文件test.o： $ gcc -c test.c 执行如下命令： $ objdump -t test.o 显示符号表的内容： test.o: file format elf64-x86-64 SYMBOL TABLE: 0000000000000000 l df *ABS* 0000000000000000 test.c 0000000000000000 l d .text 0000000000000000 .text 0000000000000000 l d .data 0000000000000000 .data 0000000000000000 l d .bss 0000000000000000 .bss 0000000000000004 l O .bss 0000000000000004 static_var 0000000000000004 l O .data 0000000000000004 static_var_init 0000000000000000 l F .text 000000000000000f static_function 0000000000000008 l O .bss 0000000000000004 local_static_var.1 0000000000000008 l O .data 0000000000000004 local_static_var_init.0 0000000000000000 g O .bss 0000000000000004 global_var 0000000000000000 g O .data 0000000000000004 global_var_init 000000000000000f g F .text 0000000000000024 global_function 0000000000000033 g F .text 0000000000000012 global_function2 0000000000000045 g F .text 000000000000000b non_mangled_function 0000000000000050 g F .text 0000000000000023 main 当第3列为O时第5列为对齐，当第3列为F时第5列为大小。 接着执行如下命令： $ objdump -t test.o | awk '$3=="O" {print $0}' | sort -k4,4 从符号表中检索出同BSS节和数据节有关的内容： 0000000000000000 g O .bss 0000000000000004 global_var 0000000000000004 l O .bss 0000000000000004 static_var 0000000000000008 l O .bss 0000000000000004 local_static_var.1 0000000000000000 g O .data 0000000000000004 global_var_init 0000000000000004 l O .data 0000000000000004 static_var_init 0000000000000008 l O .data 0000000000000004 local_static_var_init.0 接着执行如下命令： $ objdump -r -j.text test.o 显示正文节的重定位（英语：Relocation (computing)）记录： test.o: file format elf64-x86-64 RELOCATION RECORDS FOR [.text]: OFFSET TYPE VALUE 000000000000001f R_X86_64_PC32 .bss+0x0000000000000004 0000000000000025 R_X86_64_PC32 .data+0x0000000000000004 000000000000002b R_X86_64_PC32 .bss+0x0000000000000004 000000000000005a R_X86_64_PC32 global_var-0x0000000000000008 0000000000000064 R_X86_64_PC32 .bss-0x0000000000000004 这里重定位类型中的PC指示程序计数器。 接着执行如下命令： $ objdump -d -r -M intel test.o 这里的-d选项指定反汇编包含指令的章节，而-r选项在此指定在需要重定位的空位处，标示出对应的重定位项目。这里使用-M intel选项选用intel语法展示汇编代码，默认将用AT&T语法展示。结果输出为： test.o: file format elf64-x86-64 Disassembly of section .text: 0000000000000000 <static_function>: 0: f3 0f 1e fa endbr64 4: 55 push rbp 5: 48 89 e5 mov rbp,rsp 8: b8 00 00 00 00 mov eax,0x0 d: 5d pop rbp e: c3 ret 000000000000000f <global_function>: f: f3 0f 1e fa endbr64 13: 55 push rbp 14: 48 89 e5 mov rbp,rsp 17: 89 7d fc mov DWORD PTR [rbp-0x4],edi 1a: 8b 45 fc mov eax,DWORD PTR [rbp-0x4] 1d: 89 05 00 00 00 00 mov DWORD PTR [rip+0x0],eax # 23 <global_function+0x14> 1f: R_X86_64_PC32 .bss+0x4 23: 8b 15 00 00 00 00 mov edx,DWORD PTR [rip+0x0] # 29 <global_function+0x1a> 25: R_X86_64_PC32 .data+0x4 29: 8b 05 00 00 00 00 mov eax,DWORD PTR [rip+0x0] # 2f <global_function+0x20> 2b: R_X86_64_PC32 .bss+0x4 2f: 01 d0 add eax,edx 31: 5d pop rbp 32: c3 ret 0000000000000033 <global_function2>: 33: f3 0f 1e fa endbr64 37: 55 push rbp 38: 48 89 e5 mov rbp,rsp 3b: 8b 55 f8 mov edx,DWORD PTR [rbp-0x8] 3e: 8b 45 fc mov eax,DWORD PTR [rbp-0x4] 41: 01 d0 add eax,edx 43: 5d pop rbp 44: c3 ret 0000000000000045 <non_mangled_function>: 45: f3 0f 1e fa endbr64 49: 55 push rbp 4a: 48 89 e5 mov rbp,rsp 4d: 90 nop 4e: 5d pop rbp 4f: c3 ret 0000000000000050 <main>: 50: f3 0f 1e fa endbr64 54: 55 push rbp 55: 48 89 e5 mov rbp,rsp 58: c7 05 00 00 00 00 01 mov DWORD PTR [rip+0x0],0x1 # 62 <main+0x12> 5f: 00 00 00 5a: R_X86_64_PC32 global_var-0x8 62: c7 05 00 00 00 00 02 mov DWORD PTR [rip+0x0],0x2 # 6c <main+0x1c> 69: 00 00 00 64: R_X86_64_PC32 .bss-0x4 6c: b8 00 00 00 00 mov eax,0x0 71: 5d pop rbp 72: c3 ret 由于需要加上当前指令长度，这里的.text+0x1f和.text+0x2b处空位重定位为.bss+0x00000004，它加上0x04对应.bss+0x00000008处的local_static_var.1；.text+0x25处空位重定位为.data+0x00000004，它加上0x04对应.data+0x00000008处的local_static_var_init.0；.text+0x5a处空位重定位为global_var-0x00000008，它加上0x08对应.bss+0x00000000处的global_var；.text+0x64处空位重定位为.bss-0x00000004，它加上0x08对应.bss+0x00000004处的static_var。 将例子源文件编译为位置无关代码： $ gcc -fPIC -c test.c 接着执行如下命令： $ objdump -r -j.text test.o 显示正文节的重定位记录： test.o: file format elf64-x86-64 RELOCATION RECORDS FOR [.text]: OFFSET TYPE VALUE 000000000000001f R_X86_64_PC32 .bss+0x0000000000000004 0000000000000025 R_X86_64_PC32 .data+0x0000000000000004 000000000000002b R_X86_64_PC32 .bss+0x0000000000000004 000000000000005b R_X86_64_REX_GOTPCRELX global_var-0x0000000000000004 0000000000000067 R_X86_64_PC32 .bss-0x0000000000000004 这里重定位类型中的GOT指示全局偏移量表（英语：Global Offset Table）。 反汇编并提取其中的main函数部份： $ objdump -d -r -M intel test.o | grep '<main>' -A12 结果为： 0000000000000050 <main>: 50: f3 0f 1e fa endbr64 54: 55 push rbp 55: 48 89 e5 mov rbp,rsp 58: 48 8b 05 00 00 00 00 mov rax,QWORD PTR [rip+0x0] # 5f <main+0xf> 5b: R_X86_64_REX_GOTPCRELX global_var-0x4 5f: c7 00 01 00 00 00 mov DWORD PTR [rax],0x1 65: c7 05 00 00 00 00 02 mov DWORD PTR [rip+0x0],0x2 # 6f <main+0x1f> 6c: 00 00 00 67: R_X86_64_PC32 .bss-0x4 6f: b8 00 00 00 00 mov eax,0x0 74: 5d pop rbp 75: c3 ret 将上述目标文件链接为共享库： $ gcc -shared -o test.so test.o 接着查看GOT节的位置及其内容： $ objdump -s -j.got test.so 结果为： test.so: file format elf64-x86-64 Contents of section .got: 3fc0 00000000 00000000 00000000 00000000 ................ 3fd0 00000000 00000000 00000000 00000000 ................ 3fe0 00000000 00000000 ........ 这里的全局偏移量表的位置在0x00003fc0，它有5个项目并且其内容在未运行时都为空。 反汇编并提取其中的main函数部份： $ objdump -d -M intel test.so | grep '<main>' -A10 结果为： 0000000000001149 <main>: 1149: f3 0f 1e fa endbr64 114d: 55 push rbp 114e: 48 89 e5 mov rbp,rsp 1151: 48 8b 05 68 2e 00 00 mov rax,QWORD PTR [rip+0x2e68] # 3fc0 <global_var-0x58> 1158: c7 00 01 00 00 00 mov DWORD PTR [rax],0x1 115e: c7 05 b4 2e 00 00 02 mov DWORD PTR [rip+0x2eb4],0x2 # 401c <static_var> 1165: 00 00 00 1168: b8 00 00 00 00 mov eax,0x0 116d: 5d pop rbp 116e: c3 ret 这里的0x1151+0x07+0x00002e68得到0x00003fc0，它是全局偏移量表的第一个项目的地址。 接着查看动态重定位记录： $ objdump -R test.so 结果为： test.so: file format elf64-x86-64 DYNAMIC RELOCATION RECORDS OFFSET TYPE VALUE 0000000000003e60 R_X86_64_RELATIVE *ABS*+0x00000000000010f0 0000000000003e68 R_X86_64_RELATIVE *ABS*+0x00000000000010b0 0000000000004000 R_X86_64_RELATIVE *ABS*+0x0000000000004000 0000000000003fc0 R_X86_64_GLOB_DAT global_var 0000000000003fc8 R_X86_64_GLOB_DAT __cxa_finalize 0000000000003fd0 R_X86_64_GLOB_DAT _ITM_registerTMCloneTable 0000000000003fd8 R_X86_64_GLOB_DAT _ITM_deregisterTMCloneTable 0000000000003fe0 R_X86_64_GLOB_DAT __gmon_start__ 这里指定了GOT表项目对应的动态符号。这里的处在0x00003fc0的全局偏移量表的第一个项目，在运行时需要重定位为global_var的实际地址。 接着查看动态符号表： $ objdump -T test.so 结果为： test.so: file format elf64-x86-64 DYNAMIC SYMBOL TABLE: 0000000000000000 w D *UND* 0000000000000000 __cxa_finalize 0000000000000000 w D *UND* 0000000000000000 _ITM_registerTMCloneTable 0000000000000000 w D *UND* 0000000000000000 _ITM_deregisterTMCloneTable 0000000000000000 w D *UND* 0000000000000000 __gmon_start__ 000000000000112c g DF .text 0000000000000012 global_function2 000000000000113e g DF .text 000000000000000b non_mangled_function 0000000000004008 g DO .data 0000000000000004 global_var_init 0000000000001149 g DF .text 0000000000000026 main 0000000000001108 g DF .text 0000000000000024 global_function 0000000000004018 g DO .bss 0000000000000004 global_var 这里指定了实际地址对应的动态符号。这里的global_var的地址是0x0000000000004018。 接着执行如下命令： $ objdump -t test.so | grep 'global_var$' 从符号表中检视global_var的实际地址： 0000000000004018 g O .bss 0000000000000004 global_var 动态符号表中global_var的地址也是这个地址。 GNU Binutils objdump(1) – Linux用户命令（User Commands）手册页 readelf(1) – Linux用户命令（User Commands）手册页 Binutils::Objdump（页面存档备份，存于互联网档案馆） - Perl interface to objdump