使用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