objdump

    objdump命令 是用查看目标文件或者可执行的目标文件的构成的gcc工具。

    实例

    首先,在给出后面大部分测试所基于的源代码以及编译指令。 源代码如下:

    1. void printTest() {
    2. char a;
    3. a = 'a';
    4. }
    5. void printTest2() {
    6. int a = 2;
    7. a+=2;
    8. }

    对以上源代码进行编译,如下:

    1. [root@localhost test]# g++ -c -g mytest.cpp

    这里,生成的文件是mytest.o,为了方便测试包含了调试的信息,对可执行文件的测试,显示的结果类似。

    查看当前使用的objdump的版本号:

    1. [root@localhost test]# objdump -V
    2. GNU objdump 2.17.50.0.6-14.el5 20061020
    3. Copyright 2005 free Software Foundation, Inc.
    4. This program is free software; you may redistribute it under the terms of
    5. the GNU General Public License. This program has absolutely no warranty.

    查看档案库文件中的信息:

    这里,libmy2.a是一个使用ar命令将多个*.o目标文件打包而生成的静态库。命令的输出类似ar -tv,相比较ar -tv输出如下:

    1. [root@localhost test]# ar -tv libmy2.a
    2. rwxrwxrwx 0/0 2724 Nov 16 16:06 2009 myfile.o
    3. rw-r--r-- 0/0 727 Jul 13 15:32 2011 mytest.o
    1. [root@localhost test]# objdump -i
    2. BFD header file version 2.17.50.0.6-14.el5 20061020
    3. elf32-i386
    4. (header little endian, data little endian)
    5. i386
    6. a.out-i386-linux
    7. (header little endian, data little endian)
    8. i386
    9. efi-app-ia32
    10. (header little endian, data little endian)
    11. i386
    12. elf64-x86-64
    13. (header little endian, data little endian)
    14. i386
    15. elf64-little
    16. (header little endian, data little endian)
    17. i386
    18. elf64-big
    19. (header big endian, data big endian)
    20. i386
    21. elf32-little
    22. (header little endian, data little endian)
    23. i386
    24. elf32-big
    25. (header big endian, data big endian)
    26. i386
    27. srec
    28. (header endianness unknown, data endianness unknown)
    29. i386
    30. symbolsrec
    31. (header endianness unknown, data endianness unknown)
    32. i386
    33. tekhex
    34. (header endianness unknown, data endianness unknown)
    35. i386
    36. binary
    37. (header endianness unknown, data endianness unknown)
    38. i386
    39. ihex
    40. (header endianness unknown, data endianness unknown)
    41. i386
    42. trad-core
    43. (header endianness unknown, data endianness unknown)
    44. i386 elf32-i386 a.out-i386-linux efi-app-ia32 elf64-x86-64
    45. elf64-little elf64-big elf32-little elf32-big srec symbolsrec
    46. i386 elf64-little elf64-big elf32-little elf32-big srec symbolsrec
    47. tekhex binary ihex trad-core
    48. i386 tekhex binary ihex ---------

    这里,显示的信息是相对于 -b 或者 -m 选项可用的架构和目标格式列表。

    显示mytest.o文件中的text段的内容:

    1. [root@localhost test]# objdump --section=.text -s mytest.o
    2. mytest.o: file format elf32-i386
    3. Contents of section .text:
    4. 0000 5589e583 ec10c645 ff61c9c3 5589e583 U......E.a..U...
    5. 0010 ec10c745 fc020000 008345fc 02c9c3 ...E......E....

    这里注意,不能单独使用-j或者—section,例如objdump --section=.text mytest.o是不会运行成功的。

    反汇编mytest.o中的text段内容,并尽可能用源代码形式表示:

    1. [root@localhost test]# objdump -j .text -S mytest.o
    2. mytest.o: file format elf32-i386
    3. Disassembly of section .text:
    4. 00000000 <_Z9printTestv>:
    5. void printTest()
    6. 0: 55 push %ebp
    7. 1: 89 e5 mov %esp,%ebp
    8. 3: 83 ec 10 sub $0x10,%esp
    9. {
    10. char a;
    11. a = 'a';
    12. 6: c6 45 ff 61 movb $0x61,0xffffffff(%ebp)
    13. }
    14. a: c9 leave
    15. b: c3 ret
    16. 000000c <_Z10printTest2v>:
    17. void printTest2()
    18. c: 55 push %ebp
    19. d: 89 e5 mov %esp,%ebp
    20. f: 83 ec 10 sub $0x10,%esp
    21. {
    22. int a = 2;
    23. 12: c7 45 fc 02 00 00 00 movl $0x2,0xfffffffc(%ebp)
    24. a+=2;
    25. 19: 83 45 fc 02 addl $0x2,0xfffffffc(%ebp)
    26. }
    27. 1d: c9 leave
    28. 1e: c3 ret

    这里注意,不能单独使用-j或者—section,例如objdump -j .text mytest.o是不会运行成功的。另外-S命令对于包含调试信息的目标文件,显示的效果比较好,如果编译时没有指定g++的-g选项,那么目标文件就不包含调试信息,那么显示效果就差多了。

    反汇编出mytest.o的源代码:

    这里,尤其当编译的时候指定了-g这种调试参数时,反汇编的效果比较明显。隐含了-d参数。

    1. [root@localhost test]# objdump -t mytest.o
    2. mytest.o: file format elf32-i386
    3. SYMBOL TABLE:
    4. 00000000 l df *ABS* 00000000 mytest.cpp
    5. 00000000 l d .text 00000000 .text
    6. 00000000 l d .data 00000000 .data
    7. 00000000 l d .bss 00000000 .bss
    8. 00000000 l d .debug_abbrev 00000000 .debug_abbrev
    9. 00000000 l d .debug_info 00000000 .debug_info
    10. 00000000 l d .debug_line 00000000 .debug_line
    11. 00000000 l d .debug_frame 00000000 .debug_frame
    12. 00000000 l d .debug_loc 00000000 .debug_loc
    13. 00000000 l d .debug_pubnames 00000000 .debug_pubnames
    14. 00000000 l d .debug_aranges 00000000 .debug_aranges
    15. 00000000 l d .note.GNU-stack 00000000 .note.GNU-stack
    16. 00000000 l d .comment 00000000 .comment
    17. 00000000 g F .text 0000000c _Z9printTestv
    18. 00000000 *UND* 00000000 __gxx_personality_v0
    19. 0000000c g F .text 00000013 _Z10printTest2v

    这里,输出的信息类似nm -s命令的输出,相比较之下,nm命令的输出如下:

    1. [root@localhost test]# nm -s mytest.o
    2. 0000000c T _Z10printTest2v
    3. 00000000 T _Z9printTestv
    4. U __gxx_personality_v0

    显示文件的符号表入口,将底层符号解码并表示成用户级别:

    1. SYMBOL TABLE:
    2. 00000000 l df *ABS* 00000000 mytest.cpp
    3. 00000000 l d .text 00000000 .text
    4. 00000000 l d .data 00000000 .data
    5. 00000000 l d .bss 00000000 .bss
    6. 00000000 l d .debug_abbrev 00000000 .debug_abbrev
    7. 00000000 l d .debug_info 00000000 .debug_info
    8. 00000000 l d .debug_line 00000000 .debug_line
    9. 00000000 l d .debug_frame 00000000 .debug_frame
    10. 00000000 l d .debug_loc 00000000 .debug_loc
    11. 00000000 l d .debug_pubnames 00000000 .debug_pubnames
    12. 00000000 l d .debug_aranges 00000000 .debug_aranges
    13. 00000000 l d .note.GNU-stack 00000000 .note.GNU-stack
    14. 00000000 l d .comment 00000000 .comment
    15. 00000000 g F .text 0000000c printTest()
    16. 00000000 *UND* 00000000 __gxx_personality_v0
    17. 0000000c g F .text 00000013 printTest2()

    这里,和没-C相比,printTest2函数可读性增加了。

    反汇编目标文件的特定机器码段:

    1. [root@localhost test]# objdump -d mytest.o
    2. mytest.o: file format elf32-i386
    3. Disassembly of section .text:
    4. 00000000 <_Z9printTestv>:
    5. 0: 55 push %ebp
    6. 1: 89 e5 mov %esp,%ebp
    7. 3: 83 ec 10 sub $0x10,%esp
    8. 6: c6 45 ff 61 movb $0x61,0xffffffff(%ebp)
    9. a: c9 leave
    10. b: c3 ret
    11. 0000000c <_Z10printTest2v>:
    12. c: 55 push %ebp
    13. d: 89 e5 mov %esp,%ebp
    14. f: 83 ec 10 sub $0x10,%esp
    15. 12: c7 45 fc 02 00 00 00 movl $0x2,0xfffffffc(%ebp)
    16. 19: 83 45 fc 02 addl $0x2,0xfffffffc(%ebp)
    17. 1d: c9 leave
    18. 1e: c3 ret

    这里,对text段的内容进行了反汇编。

    反汇编特定段,并将汇编代码对应的文件名称和行号对应上:

    这里,项”-d”从objfile中反汇编那些特定指令机器码的section,而使用”-l”指定用文件名和行号标注相应的目标代码,仅仅和-d、-D或者-r一起使用,使用-ld和使用-d的区别不是很大,在源码级调试的时候有用,要求编译时使用了-g之类的调试编译选项。

    1. [root@localhost test]# objdump -h mytest.o
    2. mytest.o: file format elf32-i386
    3. Sections:
    4. Idx Name Size VMA LMA File off Algn
    5. 0 .text 0000001f 00000000 00000000 00000034 2**2
    6. CONTENTS, ALLOC, LOAD, readonly, CODE
    7. 1 .data 00000000 00000000 00000000 00000054 2**2
    8. CONTENTS, ALLOC, LOAD, DATA
    9. 2 .bss 00000000 00000000 00000000 00000054 2**2
    10. ALLOC
    11. 3 .debug_abbrev 00000046 00000000 00000000 00000054 2**0
    12. CONTENTS, READONLY, DEBUGGING
    13. 4 .debug_info 000000ed 00000000 00000000 0000009a 2**0
    14. CONTENTS, RELOC, READONLY, DEBUGGING
    15. 5 .debug_line 0000003e 00000000 00000000 00000187 2**0
    16. CONTENTS, RELOC, READONLY, DEBUGGING
    17. 6 .debug_frame 00000044 00000000 00000000 000001c8 2**2
    18. CONTENTS, RELOC, READONLY, DEBUGGING
    19. 7 .debug_loc 00000058 00000000 00000000 0000020c 2**0
    20. CONTENTS, READONLY, DEBUGGING
    21. 8 .debug_pubnames 0000002f 00000000 00000000 00000264 2**0
    22. CONTENTS, RELOC, READONLY, DEBUGGING
    23. 9 .debug_aranges 00000020 00000000 00000000 00000293 2**0
    24. CONTENTS, RELOC, READONLY, DEBUGGING
    25. 10 .comment 0000002e 00000000 00000000 000002b3 2**0
    26. CONTENTS, READONLY
    27. 11 .note.GNU-stack 00000000 00000000 00000000 000002e1 2**0

    这里,更多的内容参见man objdump中的这个选项。