Objdump

objdump是在類Unix作業系統上顯示關於目標文件的各種資訊的命令行程序。例如，它可用作反彙編器來以彙編代碼形式查看可執行文件。它是GNU Binutils的一部分，用於在可執行文件和其他二進位數據上進行精細粒度控制。objdump使用BFD庫來讀取目標文件的內容。類似工具還有readelf、Microsoft DUMPBIN和Borland TDUMP。

注意在特定平台（比如Mac OS X）上，objdump二進位文件可能實際上被連接到LLVM的objdump，它有著不同的命令選項和表現。

## 例子

下面的例子展示了變量和函數在全局、局部、外部、靜態、自動和初始化的不同情況下的不同符號類型。將其存入文件`test.c`中，對這個C代碼如下編譯：`gcc -c test.c`；或者將其存入文件`test.cpp`中，對這個C++代碼如下編譯：`g++ -c test.cpp`。

```c
int global_var;
int global_var_init = 26;
static int static_var;
static int static_var_init = 25;

static int static_function()
{
    return 0;
}

int global_function(int p)
{
    static int local_static_var;
    static int local_static_var_init=5;
    local_static_var = p;
    return local_static_var_init + local_static_var;
}

int global_function2()
{
    int x;
    int y;
    return x+y;
}

#ifdef __cplusplus
extern "C" {
#endif
void non_mangled_function()
{
    // I do nothing
}
#ifdef __cplusplus
}
#endif

int main(void)
{
    global_var = 1;
    static_var = 2;
    return 0;
}
```

### 符號表

將上述例子代碼編譯成目標文件`test.o`：

```console
$ gcc -c test.c
```

執行如下命令：

```console
$ objdump -t test.o
```

顯示符號表的內容：

```objdump
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列為大小。

接著執行如下命令：

```console
$ objdump -t test.o | awk '$3=="O" {print $0}' | sort -k4,4
```

從符號表中檢索出同BSS節和數據節有關的內容：

```objdump
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
```

### 重定位記錄

接著執行如下命令：

```console
$ objdump -r -j.text test.o
```

顯示正文節的重定位記錄：

```objdump
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`指示程序計數器。

接著執行如下命令：

```console
 $ objdump -d -r -M intel test.o 
```

這裡的`-d`選項指定反彙編包含指令的章節，而`-r`選項在此指定在需要重定位的空位處，標示出對應的重定位項目。這裡使用`-M intel`選項選用intel語法展示彙編代碼，默認將用AT&T語法展示。結果輸出為：

```objdump-nasm
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`。

### 位置無關代碼

將例子源文件編譯為位置無關代碼：

```console
$ gcc -fPIC -c test.c
```

接著執行如下命令：

```console
$ objdump -r -j.text test.o
```

顯示正文節的重定位記錄：

```objdump
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`函數部份：

```console
$ objdump -d -r -M intel  test.o | grep '<main>' -A12
```

結果為：

```objdump-nasm
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
```

### 共享庫

將上述目標文件連結為共享庫：

```console
$ gcc -shared -o test.so test.o
```

接著查看GOT節的位置及其內容：

```console
$ objdump -s -j.got test.so
```

結果為：

```objdump
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`函數部份：

```console
$ objdump -d -M intel test.so | grep '<main>' -A10
```

結果為：

```objdump-nasm
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`，它是全局偏移量表的第一個項目的地址。

接著查看動態重定位記錄：

```console
$ objdump -R test.so
```

結果為：

```objdump
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`的實際地址。

接著查看動態符號表：

```console
$ objdump -T test.so
```

結果為：

```objdump
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`。

接著執行如下命令：

```console
$ objdump -t test.so | grep 'global_var$'
```

從符號表中檢視`global_var`的實際地址：

```objdump
0000000000004018 g     O .bss	0000000000000004 global_var
```

動態符號表中`global_var`的地址也是這個地址。

## 外部連結

- 1
- 1
- Binutils::Objdump - Perl interface to objdump

## 基本資料

- 日語原文：objdump
- 作業系統：Unix和類Unix
- 類型：命令
- 許可協議：GNU GPL