我想知道如何在我的C源文件中使用GCC来转储机器代码的助记符版本,以便我可以看到我的代码被编译成什么。您可以使用Java执行此操作,但我无法找到GCC的方法。
我正在尝试在汇编中重新编写一个C方法,看看GCC是如何做的,这将是一个很大的帮助。
答案 0 :(得分:309)
如果使用调试符号进行编译,则可以使用objdump
生成更易读的反汇编。
>objdump --help
[...]
-S, --source Intermix source code with disassembly
-l, --line-numbers Include line numbers and filenames in output
objdump -drwC -Mintel
很不错:
-r
在重定位时显示符号名称(因此,您可以在下面的puts
说明中看到call
)-R
显示动态链接重定位/符号名称(对共享库有用)-C
demangles C ++符号名称-w
是“宽”模式:它不包装机器码字节-Mintel
:使用GAS / binutils MASM类.intel_syntax noprefix
语法代替AT& T -S
:使用反汇编交错源代码行。您可以在alias disas="objdump -drwCS -Mintel"
~/.bashrc
之类的内容
示例:
> 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
答案 1 :(得分:93)
我想补充一下这些答案,如果你给gcc标志-fverbose-asm
,它发出的汇编程序将会更加清晰。
答案 2 :(得分:72)
使用-S(注意:大写S)切换到GCC,它会将汇编代码发送到扩展名为.s的文件。例如,以下命令:
gcc -O2 -S foo.c
将生成的汇编代码保留在文件foo.s。
上
直接从http://www.delorie.com/djgpp/v2faq/faq8_20.html翻录(但删除了错误的-c
)
答案 3 :(得分:48)
在基于x86的系统上使用-S
切换到GCC会产生AT&amp; 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 <main>:
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 <puts@plt>
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 <main>:
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 <puts@plt>
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
答案 4 :(得分:34)
godbolt是一个非常有用的工具,他们列出的只有C ++编译器,但你可以使用-x c
标志,以便将代码视为C.然后它会为你生成一个汇编列表代码并排,您可以使用Colourise
选项生成彩色条,以直观地指示哪个源代码映射到生成的程序集。例如,以下代码:
#include <stdio.h>
void func()
{
printf( "hello world\n" ) ;
}
使用以下命令行:
-x c -std=c99 -O3
和Colourise
将生成以下内容:
答案 5 :(得分:21)
您是否尝试gcc -S -fverbose-asm -O source.c
然后查看生成的source.s
汇编程序文件?
生成的汇编程序代码进入source.s
(您可以使用-o
汇编程序文件名来覆盖它; -fverbose-asm
选项要求编译器发出一些汇编语句“解释”生成的汇编代码。 -O
选项要求编译器优化一点(可以使用-O2
或-O3
优化更多。)
如果您想了解gcc
正在做什么,请尝试传递-fdump-tree-all
但要小心:您将获得数百个转储文件。
答案 6 :(得分:19)
您可以像使用objdump一样使用gdb。
摘录摘自http://sources.redhat.com/gdb/current/onlinedocs/gdb_9.html#SEC64
以下是显示Intel x86的混合源+程序集的示例:
(gdb) disas /m main Dump of assembler code for function main: 5 { 0x08048330 : push %ebp 0x08048331 : mov %esp,%ebp 0x08048333 : sub $0x8,%esp 0x08048336 : and $0xfffffff0,%esp 0x08048339 : sub $0x10,%esp 6 printf ("Hello.\n"); 0x0804833c : movl $0x8048440,(%esp) 0x08048343 : call 0x8048284 7 return 0; 8 } 0x08048348 : mov $0x0,%eax 0x0804834d : leave 0x0804834e : ret End of assembler dump.
答案 7 :(得分:13)
使用-S(注意:大写S)切换到GCC,它会将汇编代码发送到扩展名为.s的文件。例如,以下命令:
gcc -O2 -S -c foo.c
答案 8 :(得分:4)
我没有给gcc一个镜头,但是在g ++的情况下。以下命令对我有用。 -g用于调试构建和-Wa,-adhln传递给汇编程序以列出源代码
g ++ -g -Wa,-adhln src.cpp
答案 9 :(得分:0)
在gcc或g ++上使用 -Wa,-adhln 作为选项,以生成标准输出的列表输出。
-Wa,...用于汇编器部分的命令行选项(在C / ++编译后在gcc / g ++中执行)。它在内部(在Windows中为as.exe)调用 as 。 参见
>为--help
作为命令行以查看gcc内的汇编器工具的更多帮助