使用GCC生成可读的程序集?
我想知道如何在我的C源文件上使用GCC来转储机器代码的助记符版本,这样我就可以看到我的代码被编译进了什么程序。 你可以用Java来做到这一点,但是我一直无法找到GCC的方法。
我正在尝试在汇编中重新编写一个C方法,并且看看GCC是如何提供帮助的。
如果使用调试符号进行编译,则可以使用objdump
来产生更易读的反汇编。
>objdump --help [...] -S, --source Intermix source code with disassembly -l, --line-numbers Include line numbers and filenames in output
例:
> gcc -g -c test.c > objdump -d -M intel -S test.o test.o: file format elf32-i386 Disassembly of section .text: 00000000 <main>: #include <stdio.h> int main(void) { 0: 55 push ebp 1: 89 e5 mov ebp,esp 3: 83 e4 f0 and esp,0xfffffff0 6: 83 ec 10 sub esp,0x10 puts("test"); 9: c7 04 24 00 00 00 00 mov DWORD PTR [esp],0x0 10: e8 fc ff ff ff call 11 <main+0x11> return 0; 15: b8 00 00 00 00 mov eax,0x0 } 1a: c9 leave 1b: c3 ret
我想补充一下这些答案,如果你给gcc flag -fverbose-asm
,它发出的汇编器将会更清晰地阅读。
使用-S(注意:大写字母S)切换到GCC,它会将汇编代码发送到扩展名为.s的文件。 例如,下面的命令:
gcc -O2 -S foo.c
会将生成的汇编代码留在文件foo.s.
直接从http://www.delorie.com/djgpp/v2faq/faq8_20.html (但删除错误的-c
)
让其他人知道,在基于x86的系统上-S切换到GCC产生AT&T语法的转储,默认情况下,可以通过-masm = att开关指定,如下所示:
gcc -S -masm=att code.c
而如果你想产生一个英特尔语法转储,你可以使用-masm = intel开关,如下所示:
gcc -S -masm=intel code.c
(都将code.c转储成各种语法,分别转换成文件code.s)
为了用objdump产生类似的效果,你需要使用disassembler-options = intel / att开关,一个例子(用代码转储来说明语法上的差异):
$ objdump -d --disassembler-options=att code.c ... 080483c4 : 80483c4: 8d 4c 24 04 lea 0x4(%esp),%ecx 80483c8: 83 e4 f0 and $0xfffffff0,%esp 80483cb: ff 71 fc pushl -0x4(%ecx) 80483ce: 55 push %ebp 80483cf: 89 e5 mov %esp,%ebp 80483d1: 51 push %ecx 80483d2: 83 ec 04 sub $0x4,%esp 80483d5: c7 04 24 b0 84 04 08 movl $0x80484b0,(%esp) 80483dc: e8 13 ff ff ff call 80482f4 80483e1: b8 00 00 00 00 mov $0x0,%eax 80483e6: 83 c4 04 add $0x4,%esp 80483e9: 59 pop %ecx 80483ea: 5d pop %ebp 80483eb: 8d 61 fc lea -0x4(%ecx),%esp 80483ee: c3 ret 80483ef: 90 nop
和
$ objdump -d --disassembler-options=intel code.c ... 080483c4 : 80483c4: 8d 4c 24 04 lea ecx,[esp+0x4] 80483c8: 83 e4 f0 and esp,0xfffffff0 80483cb: ff 71 fc push DWORD PTR [ecx-0x4] 80483ce: 55 push ebp 80483cf: 89 e5 mov ebp,esp 80483d1: 51 push ecx 80483d2: 83 ec 04 sub esp,0x4 80483d5: c7 04 24 b0 84 04 08 mov DWORD PTR [esp],0x80484b0 80483dc: e8 13 ff ff ff call 80482f4 80483e1: b8 00 00 00 00 mov eax,0x0 80483e6: 83 c4 04 add esp,0x4 80483e9: 59 pop ecx 80483ea: 5d pop ebp 80483eb: 8d 61 fc lea esp,[ecx-0x4] 80483ee: c3 ret
80483ef: 90 nop
godbolt是一个非常有用的工具,他们列表只有C ++编译器,但是你可以使用-xc
标志来获得它作为C的代码。然后它会为你的代码并排生成一个汇编列表,你可以使用Colourise
选项来生成彩色条以直观地指示哪个源代码映射到生成的程序集。 例如下面的代码:
#include <stdio.h> void func() { printf( "hello world\n" ) ; }
使用以下命令行:
-xc -std=c99 -O3
和Colourise
会产生以下内容:
你可以像使用objdump一样使用gdb。
摘录摘自http://sources.redhat.com/gdb/current/onlinedocs/gdb_9.html#SEC64
下面是一个示例,显示Intel x86的混合源代码+程序集:
(gdb)disas / m main 功能主汇编代码的转储: 5 { 0x08048330:推入%ebp 0x08048331:mov%esp,%ebp 0x08048333:sub $ 0x8,%esp 0x08048336:和$ 0xfffffff0,%esp 0x08048339:sub $ 0x10,%esp 6 printf(“你好。\ n”); 0x0804833c:movl $ 0x8048440,(%esp) 0x08048343:调用0x8048284 7返回0; 8} 0x08048348:mov $ 0x0,%eax 0x0804834d:离开 0x0804834e:ret 汇编器转储结束。
你试过gcc -S -fverbose-asm -O source.c
然后查看生成的source.s
汇编程序文件吗?
生成的汇编代码进入source.s
(可以用-o
汇编程序文件名覆盖)。 -fverbose-asm
选项要求编译器发出一些汇编注释来“解释”生成的汇编代码。 -O
选项要求编译器优化一点(可以使用-O2
或-O3
进行优化)。
如果您想了解gcc
在做什么,请尝试传递-fdump-tree-all
但谨慎:您将获得数百个转储文件。
顺便说一句,海湾合作委员会是可扩展的插件或MELT (一个高级领域特定的语言来扩展GCC)。
使用-S(注意:大写字母S)切换到GCC,它会将汇编代码发送到扩展名为.s的文件。 例如,下面的命令:
gcc -O2 -S -c foo.c
我还没有给gcc一个镜头,但在g ++的情况下。 下面的命令适用于我。 -g用于调试编译和-Wa,-adhln传递给汇编程序以便与源代码一起列表
g ++ -g -Wa,-adhln src.cpp