我知道我可以使用以下方法获取编译器生成的汇编源代码:
gcc -S ...
即使这很烦人并没有给我一个目标文件作为过程的一部分。
但是我怎样才能得到关于编译代码的所有信息呢?我的意思是地址,生成的字节等等。
输出的指令gcc -S
没有告诉我任何关于指令长度或编码的信息,这是我想看到的。
我喜欢objdump
这个,但最有用的选项并不明显——特别是如果你在包含重定位的目标文件上使用它,而不是最终的二进制文件。
objdump -d some_binary
做一个合理的工作。
objdump -d some_object.o
不太有用,因为对外部函数的调用不会被反汇编:
...
00000005 <foo>:
5: 55 push %ebp
6: 89 e5 mov %esp,%ebp
8: 53 push %ebx
...
29: c7 04 24 00 00 00 00 movl $0x0,(%esp)
30: e8 fc ff ff ff call 31 <foo+0x2c>
35: 89 d8 mov %ebx,%eax
...
call
实际上是printf()
......添加-r
标志有助于解决这个问题;它标志着搬迁。 objdump -dr some_object.o
给出:
...
29: c7 04 24 00 00 00 00 movl $0x0,(%esp)
2c: R_386_32 .rodata.str1.1
30: e8 fc ff ff ff call 31 <foo+0x2c>
31: R_386_PC32 printf
...
然后,我发现将每一行注释为<symbol+offset>
. objdump
有一个方便的选项,但它有关闭实际字节转储的烦人副作用 -objdump --prefix-addresses -dr some_object.o
给出:
...
00000005 <foo> push %ebp
00000006 <foo+0x1> mov %esp,%ebp
00000008 <foo+0x3> push %ebx
...
但事实证明,你可以通过提供另一个晦涩的选项来撤销它,最终得到我最喜欢的objdump
咒语:
objdump --prefix-addresses --show-raw-insn -dr file.o
它给出了这样的输出:
...
00000005 <foo> 55 push %ebp
00000006 <foo+0x1> 89 e5 mov %esp,%ebp
00000008 <foo+0x3> 53 push %ebx
...
00000029 <foo+0x24> c7 04 24 00 00 00 00 movl $0x0,(%esp)
2c: R_386_32 .rodata.str1.1
00000030 <foo+0x2b> e8 fc ff ff ff call 00000031 <foo+0x2c>
31: R_386_PC32 printf
00000035 <foo+0x30> 89 d8 mov %ebx,%eax
...
如果您使用调试符号构建(即用 编译-g
),并且将 替换为-dr
,-Srl
它将尝试用相应的源代码行注释输出。
获得快速列表的最简单方法是使用-a
汇编程序的选项,您可以通过-Wa,-a
在gcc
命令行中执行此操作。您可以对 a 选项使用各种修饰符来准确影响结果——参见 as(1) 手册页。
听起来你想要一个反汇编程序。 objdump
几乎是标准(otool
在 Mac OS X 上);与链接器为您提供的任何映射文件信息相一致,目标文件的反汇编应该为您提供所需的一切。
gcc 将生成一个汇编语言源文件。然后,您可以使用as -a yourfile.S
生成一个列表,其中包括每条指令的偏移量和编码字节。-a
还有一些子选项来控制列表文件中显示的内容(as --help
将给出它们的列表以及其他可用选项)。
nasm -f elf xx.asm -l x.lst
gcc xx.c xx.o -o xx
生成仅用于 xx.asm 的“列表”文件 x.lst
对于 xx.c 和 xx.asm,您可以同时编译它们,然后使用 'gdb' - gnu 调试器