objdump
objdump是在類Unix作業系統上顯示關於目的檔的各種資訊的命令列程式。例如,它可用作反組譯器來以組譯代碼形式檢視可執行檔。它是GNU Binutils的一部分,用於在可執行檔和其他二進制資料上進行精細粒度控制。objdump使用BFD庫來讀取目的檔的內容。類似工具還有readelf、Microsoft DUMPBIN和Borland TDUMP。
作業系統 | Unix和類Unix |
---|---|
類型 | 命令 |
許可協定 | GNU GPL |
注意在特定平台(比如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
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
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
指示全域偏移量表。
反組譯並提取其中的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
的位址也是這個位址。