我想知道如何在我的C源文件上使用海湾合作委员会来转储机器代码的助记符版本,这样我就可以看到我的代码被编译成什么。你可以用Java做到这一点,但我还没有找到一种方法与GCC。
我试图在汇编中重写一个C方法,看看GCC是如何做的,这将是一个很大的帮助。
使用-S(注意:大写S)切换到GCC,它将把程序集代码发送到扩展名为. S的文件中。例如,命令如下: gcc -O2 -S foo.c 将生成的程序集代码保留在文件foo.s上。
使用-S(注意:大写S)切换到GCC,它将把程序集代码发送到扩展名为. S的文件中。例如,命令如下:
gcc -O2 -S foo.c
将生成的程序集代码保留在文件foo.s上。
直接从http://www.delorie.com/djgpp/v2faq/faq8_20.html中复制(但删除了错误的-c)
-c
gcc -O2 -S -c foo.c
-g
-O3
objdump -S
>objdump --help [...] -S, --source Intermix source code with disassembly -l, --line-numbers Include line numbers and filenames in output
objdump -drwC -Mintel很好:
objdump -drwC -Mintel
-r
call
puts
-R
-C
-w
-Mintel
.intel_syntax noprefix
-S
你可以在你的~/.bashrc中放入类似alias disas="objdump -drwCS -Mintel"的东西。如果不是在x86上,或者如果你喜欢AT&T语法,省略-Mintel。
~/.bashrc
alias disas="objdump -drwCS -Mintel"
例子:
> 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
注意,这个不是使用了-r,所以call rel32=-4没有标注puts符号名。并且看起来像一个坏掉的call,跳到main中的调用指令中间。记住,调用编码中的rel32位移只是一个占位符,直到链接器填充一个真正的偏移量(在这种情况下,到PLT存根,除非你静态链接libc)。
call rel32=-4
rel32
脚注1:交错源代码可能是混乱的,在优化构建中不是很有帮助;为此,可以考虑https://godbolt.org/或其他方法来可视化哪些指令对应哪些源行。在优化的代码中有并不总是一个单独的源行来说明一条指令,但调试信息将为每个asm指令选择一个源行。
如果你给海湾合作委员会一个标志-fverbose-asm,它会
-fverbose-asm
在生成的程序集代码中添加额外的注释信息,使其更具可读性。 […新增的评论包括: 编译器版本和命令行选项的信息, 与汇编指令相关联的源代码行,格式为FILENAME:LINENUMBER:CONTENT OF LINE, 提示哪些高级表达式对应于各种汇编指令操作数。
在生成的程序集代码中添加额外的注释信息,使其更具可读性。
[…新增的评论包括:
在基于x86的系统上使用-S开关到GCC,默认情况下会生成一个at&t语法转储,可以通过-masm=att开关指定,如下所示:
-masm=att
gcc -S -masm=att code.c
然而,如果你想用英特尔语法生成一个转储,你可以使用-masm=intel开关,如下所示:
-masm=intel
gcc -S -masm=intel code.c
(两者都将code.c转储到各自的语法中,分别转储到文件code.s中)
code.c
code.s
为了用objdump产生类似的效果,你需要使用--disassembler-options= intel/att开关,这是一个示例(使用代码转储来说明语法上的差异):
--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
你可以像objdump一样使用gdb。
此节选自http://sources.redhat.com/gdb/current/onlinedocs/gdb_9.html#SEC64
下面是英特尔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.
你有没有尝试gcc -S -fverbose-asm -O source.c,然后查看生成的source.s汇编器文件?
gcc -S -fverbose-asm -O source.c
source.s
生成的汇编程序代码进入source.s(你可以用-o assembler-filename覆盖它);-fverbose-asm选项要求编译器发出一些汇编注释来“解释”生成的汇编代码。-O选项要求编译器优化一点(它可以用-O2或-O3优化更多)。
-o
-O
-O2
如果你想了解gcc在做什么,尝试传递-fdump-tree-all,但要小心:你会得到数百个转储文件。
gcc
-fdump-tree-all
顺便说一句,GCC可以通过插件或融化(扩展GCC的高级域特定语言;我在2017年放弃了它)
godbolt是一个非常有用的工具,他们的列表只有c++编译器,但你可以使用-x c标志,以便让它把代码视为C。它会为你的代码并排生成一个程序集列表,你可以使用Colourise选项生成彩色条,以直观地表明哪些源代码映射到生成的程序集。例如下面的代码:
-x c
Colourise
#include <stdio.h> void func() { printf( "hello world\n" ) ; }
使用以下命令行:
-x c -std=c99 -O3
和Colourise将生成以下内容:
我还没有尝试gcc,但在g++的情况下,下面的命令对我有用。
g++
-Wa,-adhln
g++ -g -Wa,-adhln src.cpp
在gcc或g++上使用佤邦,-adhln作为选项来生成一个清单输出到stdout。
在——的帮助
作为命令行查看GCC内部汇编工具的更多帮助