在C/C++程序开发过程中,链接和反汇编是两个非常重要的步骤。链接是将多个目标文件合并成一个可执行文件的过程,而反汇编则是将机器码转换回汇编代码的过程。objdump
是一个强大的工具,可以帮助我们进行这些操作。本文将详细介绍如何使用objdump
工具进行C/C++程序的链接与反汇编。
objdump
是GNU Binutils工具集中的一个工具,主要用于显示目标文件的信息。它可以用来反汇编目标文件、查看符号表、段信息等。objdump
支持多种目标文件格式,包括ELF、COFF、Mach-O等。
在大多数Linux发行版中,objdump
已经包含在binutils
包中。如果系统中没有安装objdump
,可以通过以下命令安装:
sudo apt-get install binutils
在macOS上,可以通过Homebrew安装:
brew install binutils
反汇编是将机器码转换回汇编代码的过程。通过反汇编,我们可以查看程序的底层实现,分析程序的执行流程。
假设我们有一个简单的C程序hello.c
:
#include <stdio.h>
int main() {
printf("Hello, World!\n");
return 0;
}
首先,我们需要编译这个程序并生成目标文件:
gcc -c hello.c -o hello.o
然后,使用objdump
反汇编目标文件:
objdump -d hello.o
输出结果如下:
hello.o: file format elf64-x86-64
Disassembly of section .text:
0000000000000000 <main>:
0: 55 push %rbp
1: 48 89 e5 mov %rsp,%rbp
4: 48 8d 3d 00 00 00 00 lea 0x0(%rip),%rdi # b <main+0xb>
b: e8 00 00 00 00 callq 10 <main+0x10>
10: b8 00 00 00 00 mov $0x0,%eax
15: 5d pop %rbp
16: c3 retq
我们也可以直接反汇编可执行文件。首先,编译并链接生成可执行文件:
gcc hello.c -o hello
然后,使用objdump
反汇编可执行文件:
objdump -d hello
输出结果如下:
hello: file format elf64-x86-64
Disassembly of section .init:
0000000000401000 <_init>:
401000: 48 83 ec 08 sub $0x8,%rsp
401004: 48 8b 05 ed 2f 00 00 mov 0x2fed(%rip),%rax # 403ff8 <__gmon_start__>
40100b: 48 85 c0 test %rax,%rax
40100e: 74 02 je 401012 <_init+0x12>
401010: ff d0 callq *%rax
401012: 48 83 c4 08 add $0x8,%rsp
401016: c3 retq
Disassembly of section .plt:
0000000000401020 <.plt>:
401020: ff 35 e2 2f 00 00 pushq 0x2fe2(%rip) # 404008 <_GLOBAL_OFFSET_TABLE_+0x8>
401026: ff 25 e4 2f 00 00 jmpq *0x2fe4(%rip) # 404010 <_GLOBAL_OFFSET_TABLE_+0x10>
40102c: 0f 1f 40 00 nopl 0x0(%rax)
...
Disassembly of section .text:
0000000000401040 <main>:
401040: 55 push %rbp
401041: 48 89 e5 mov %rsp,%rbp
401044: 48 8d 3d b9 0f 00 00 lea 0xfb9(%rip),%rdi # 402004 <_IO_stdin_used+0x4>
40104b: e8 e0 ff ff ff callq 401030 <puts@plt>
401050: b8 00 00 00 00 mov $0x0,%eax
401055: 5d pop %rbp
401056: c3 retq
如果我们只想反汇编某个特定的函数,可以使用-j
选项指定段名,并结合-d
选项:
objdump -d -j .text hello
这将只反汇编.text
段中的代码。
符号表包含了程序中定义的函数和变量的信息。通过查看符号表,我们可以了解程序中定义的符号及其地址。
使用objdump
查看符号表:
objdump -t hello
输出结果如下:
hello: file format elf64-x86-64
SYMBOL TABLE:
0000000000401000 l d .init 0000000000000000 .init
0000000000401020 l d .plt 0000000000000000 .plt
0000000000401040 l d .text 0000000000000000 .text
0000000000401058 l d .fini 0000000000000000 .fini
0000000000402000 l d .rodata 0000000000000000 .rodata
0000000000402004 l d .eh_frame 0000000000000000 .eh_frame
0000000000403ff0 l d .data 0000000000000000 .data
0000000000404000 l d .bss 0000000000000000 .bss
0000000000000000 l df *ABS* 0000000000000000 crtstuff.c
0000000000401040 g F .text 0000000000000017 main
0000000000402000 g O .rodata 0000000000000004 _IO_stdin_used
0000000000403ff0 g O .data 0000000000000000 __data_start
0000000000403ff0 g O .data 0000000000000000 __dso_handle
0000000000404000 g O .bss 0000000000000000 __bss_start
0000000000404000 g O .bss 0000000000000000 _end
0000000000401000 g F .init 0000000000000016 _init
0000000000401058 g F .fini 0000000000000009 _fini
动态符号表包含了动态链接库中的符号信息。使用-T
选项查看动态符号表:
objdump -T hello
输出结果如下:
hello: file format elf64-x86-64
DYNAMIC SYMBOL TABLE:
0000000000000000 w D *UND* 0000000000000000 __gmon_start__
0000000000000000 DF *UND* 0000000000000000 GLIBC_2.2.5 puts
0000000000000000 DF *UND* 0000000000000000 GLIBC_2.2.5 __libc_start_main
0000000000000000 DF *UND* 0000000000000000 GLIBC_2.2.5 __cxa_finalize
段信息包含了程序中各个段的大小、地址等信息。通过查看段信息,我们可以了解程序的内存布局。
使用objdump
查看段信息:
objdump -h hello
输出结果如下:
hello: file format elf64-x86-64
Sections:
Idx Name Size VMA LMA File off Algn
0 .interp 0000001c 0000000000400238 0000000000400238 00000238 2**0
CONTENTS, ALLOC, LOAD, READONLY, DATA
1 .note.ABI-tag 00000020 0000000000400254 0000000000400254 00000254 2**2
CONTENTS, ALLOC, LOAD, READONLY, DATA
2 .note.gnu.build-id 00000024 0000000000400274 0000000000400274 00000274 2**2
CONTENTS, ALLOC, LOAD, READONLY, DATA
3 .gnu.hash 0000001c 0000000000400298 0000000000400298 00000298 2**3
CONTENTS, ALLOC, LOAD, READONLY, DATA
4 .dynsym 00000060 00000000004002b8 00000000004002b8 000002b8 2**3
CONTENTS, ALLOC, LOAD, READONLY, DATA
5 .dynstr 0000003a 0000000000400318 0000000000400318 00000318 2**0
CONTENTS, ALLOC, LOAD, READONLY, DATA
6 .gnu.version 00000008 0000000000400352 0000000000400352 00000352 2**1
CONTENTS, ALLOC, LOAD, READONLY, DATA
7 .gnu.version_r 00000020 0000000000400360 0000000000400360 00000360 2**3
CONTENTS, ALLOC, LOAD, READONLY, DATA
8 .rela.dyn 00000018 0000000000400380 0000000000400380 00000380 2**3
CONTENTS, ALLOC, LOAD, READONLY, DATA
9 .rela.plt 00000030 0000000000400398 0000000000400398 00000398 2**3
CONTENTS, ALLOC, LOAD, READONLY, DATA
10 .init 00000017 0000000000401000 0000000000401000 00001000 2**2
CONTENTS, ALLOC, LOAD, READONLY, CODE
11 .plt 00000030 0000000000401020 0000000000401020 00001020 2**4
CONTENTS, ALLOC, LOAD, READONLY, CODE
12 .text 00000117 0000000000401040 0000000000401040 00001040 2**4
CONTENTS, ALLOC, LOAD, READONLY, CODE
13 .fini 00000009 0000000000401058 0000000000401058 00001058 2**2
CONTENTS, ALLOC, LOAD, READONLY, CODE
14 .rodata 00000004 0000000000402000 0000000000402000 00002000 2**2
CONTENTS, ALLOC, LOAD, READONLY, DATA
15 .eh_frame 00000038 0000000000402004 0000000000402004 00002004 2**3
CONTENTS, ALLOC, LOAD, READONLY, DATA
16 .data 00000010 0000000000403ff0 0000000000403ff0 00002ff0 2**3
CONTENTS, ALLOC, LOAD, DATA
17 .bss 00000008 0000000000404000 0000000000404000 00003000 2**0
ALLOC
18 .comment 0000002a 0000000000000000 0000000000000000 00003000 2**0
CONTENTS, READONLY
重定位信息包含了程序中需要重定位的符号及其地址。通过查看重定位信息,我们可以了解程序在链接时需要进行哪些重定位操作。
使用objdump
查看重定位信息:
objdump -r hello
输出结果如下:
hello: file format elf64-x86-64
RELOCATION RECORDS FOR [.rela.dyn]:
OFFSET TYPE VALUE
0000000000403ff0 R_X86_64_RELATIVE *ABS*+0x0000000000403ff0
0000000000403ff8 R_X86_64_RELATIVE *ABS*+0x0000000000403ff8
RELOCATION RECORDS FOR [.rela.plt]:
OFFSET TYPE VALUE
0000000000404018 R_X86_64_JUMP_SLOT puts
0000000000404020 R_X86_64_JUMP_SLOT __libc_start_main
0000000000404028 R_X86_64_JUMP_SLOT __cxa_finalize
objdump
是一个功能强大的工具,可以帮助我们进行C/C++程序的链接与反汇编。通过objdump
,我们可以查看目标文件的反汇编代码、符号表、段信息以及重定位信息。这些信息对于理解程序的底层实现、调试程序以及分析程序的内存布局非常有帮助。
在实际开发中,objdump
常常与其他工具(如gdb
、nm
等)结合使用,以更全面地分析和调试程序。希望本文的介绍能够帮助你更好地理解和使用objdump
工具。
亿速云「云服务器」,即开即用、新一代英特尔至强铂金CPU、三副本存储NVMe SSD云盘,价格低至29元/月。点击查看>>
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。