我试图在汇编中重新编写C方法,看看GCC如何做到这一点很大帮助。
#1 楼
如果使用调试符号进行编译,则可以使用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
将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
评论
是否可以仅使用Intel指令进行切换?
–詹姆斯
09年8月17日在19:39
所有这些都是Intel指令,因为它们在Intel处理器:D上运行。
–toto
09年8月18日在4:01
@toto我认为他的意思是Intel语法而不是AT&T语法
– m
09-10-9 21:56
通过使用-Wa,-adhln -g到gcc的切换序列,可以放弃带有的中间目标文件。这假设组装者是气体,并且并非总是如此。
–马克·巴特勒
2010-09-08 16:45
@James是的,供应-Mintel。
– fuz
2015年9月26日15:42
#2 楼
如果给GCC标志-fverbose-asm
,它将在生成的汇编代码中添加额外的注释信息,以使其更具可读性。
[...]添加的注释包括:
有关编译器版本和命令行选项的信息,
与汇编指令关联的源代码行,格式为FILENAME:LINENUMBER:CONTENT OF LINE,
提示哪些高级表达式对应于各种汇编指令操作数。
评论
但是然后,我将丢失用于objdump的所有开关-objdump -drwCS -Mintel,那么如何在objdump中使用冗长的内容呢?这样我就可以在asm代码中添加注释,就像gcc中的-fverbose-asm一样?
–牧民
1月10日17:08
@牧民:你不能。 -fverbose-asm添加的额外内容是输出的asm语法中的注释形式,而不是会在.o文件中添加任何多余内容的指令。在组装时将其全部丢弃。查看编译器的asm输出,而不是反汇编,例如在godbolt.org上,您可以通过鼠标悬停和相应的源/ asm行的颜色突出显示轻松地将其与源行进行匹配。如何从GCC / c装配件输出中消除“噪音”?
– Peter Cordes
5月9日19:16
#3 楼
使用-S(注:大写S)开关到GCC,它将汇编代码发送到扩展名为.s的文件中。例如,以下命令:
gcc -O2 -S foo.c
会将生成的汇编代码保留在文件foo.s中。
直接从http://www.delorie.com/翻录djgpp / v2faq / faq8_20.html(但删除错误的
-c
)评论
您不应混合使用-c和-S,而只能使用其中之一。在这种情况下,一个可能会覆盖另一个,这可能取决于它们的使用顺序。
–亚当·罗森菲尔德
09年8月17日在19:28
@AdamRosenfield关于“不应该将-c和-S混合使用”的参考吗?如果是真的,我们应该提醒作者并进行编辑。
–托尼
2014年8月5日上午11:55
@Tony:gcc.gnu.org/onlinedocs/gcc/Overall-Options.html#Overall-Options“您可以使用...选项-c,-S或-E之一来说明gcc的停止位置。 ”
– Nate Eldredge
16年4月10日在0:32
如果需要所有中间输出,请使用gcc -march = native -O3 -save-temps。您仍然可以使用-c停止创建目标文件,而无需尝试进行链接或其他操作。
– Peter Cordes
18年6月2日在1:21
-save-temps很有趣,因为它一次转储了完全由代码生成的代码,而使用-S调用编译器的另一种方法是编译两次,并且可能使用不同的选项。但是-save-temps将所有内容转储到当前目录中,这有点混乱。看起来它更适合作为GCC的调试选项,而不是用于检查代码的工具。
–StéphaneGourichon
1月22日18:16
#4 楼
默认情况下,在基于x86的系统上将-S
切换到GCC会产生AT&T语法的转储,可以使用-masm=att
开关指定该转储,如下所示: gcc -S -masm=att code.c
如果要使用Intel语法生成转储,则可以使用
-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 $ objdump -d --disassembler-options=intel code.c
xfffffff0,%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 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
x4,%esp
80483d5: c7 04 24 b0 84 04 08 movl q4312079qx80484b0,(%esp)
80483dc: e8 13 ff ff ff call 80482f4 <puts@plt>
80483e1: b8 00 00 00 00 mov q4312079qx0,%eax
80483e6: 83 c4 04 add q4312079qx4,%esp
80483e9: 59 pop %ecx
80483ea: 5d pop %ebp
80483eb: 8d 61 fc lea -0x4(%ecx),%esp
80483ee: c3 ret
80483ef: 90 nop
和
q4312079q
q4312079q
评论
什么... gcc -S -masm = intel test.c不适用于我,我得到了Intel和AT&T语法的一些杂种,例如:mov%rax,QWORD PTR -24 [%rbp],而不是这:movq -24(%rbp),%rax。
– L̲̳o̲̳̳n̲̳̳g̲̳̳p̲̳o̲̳̳k̲̳̳e̲̳̳
09年11月22日在4:03
不错的提示。应该注意的是,这在执行.o和ASM文件的并行输出时也有效,例如通过-Wa,-ahls -o yourfile.o yourfile.cpp> yourfile.asm
– underscore_d
2015年12月20日在21:49
可以使用-M选项,它与--disassembler-options相同,但更短,例如objdump -d -M intel a.out |少-N
–王E
16年7月5日在4:57
#5 楼
godbolt是一个非常有用的工具,它们列出的仅是C ++编译器,但是您可以使用-x c
标志来将其视为C。它将随后为您的代码并排生成汇编列表,您可以使用Colourise
选项生成彩色条以直观地指示哪些源代码映射到生成的程序集。例如以下代码:使用以下命令行:#include <stdio.h>
void func()
{
printf( "hello world\n" ) ;
}
:
-x c -std=c99 -O3
,
Colourise
会生成以下内容:评论
很高兴知道Godbolt过滤器的工作原理:.LC0,.text,//和Intel。英特尔很容易-masm = intel,但是其余的呢?
–Z玻色子
17-2-22在8:01
我想这是在这里解释stackoverflow.com/a/38552509/2542702
–Z玻色子
17-2-22在8:02
godbolt确实支持C(以及大量其他语言,如Rust,D,Pascal等)。只是C编译器要少得多,所以最好将C ++编译器与-x c一起使用
–phuclv
19年4月27日在9:34
#6 楼
您是否尝试过gcc -S -fverbose-asm -O source.c
,然后查看生成的source.s
汇编程序文件?生成的汇编代码进入
source.s
(您可以使用-o
assembler-filename覆盖它); -fverbose-asm
选项要求编译器发出一些汇编注释,以“解释”生成的汇编代码。 -O
选项要求编译器进行优化(可以使用-O2
或-O3
进行更多优化)。如果您想了解
gcc
在做什么,请尝试传递-fdump-tree-all
,但要小心:您会得到数百个顺便说一句,GCC是可扩展的,可以通过插件或MELT(一种高级领域特定语言来扩展GCC;我在2017年放弃了)
评论
也许会提到输出将在source.s中,因为很多人希望在控制台上打印输出。
–RubenLaguna
15年7月2日在8:41
@ecerulm:-S -o-转储到stdout。如果要使用NASM / YASM语法,则-masm = intel很有帮助。 (但是它使用qword ptr [mem],而不只是qword,因此它更像是Intel / MASM,而不是NASM / YASM)。 gcc.godbolt.org在整理转储方面做得很好:可以选择剥离仅注释行,未使用的标签和汇编程序指令。
– Peter Cordes
16 Jan 30'23:06
忘了提及:如果您正在寻找“类似于源代码,但在每个源代码行之后都没有存储/重新加载的噪音”,那么-Og甚至比-O1好。这意味着“针对调试进行优化”,并且使asm没有太多棘手的/难以遵循的优化,而该优化无法完成消息来源所说的一切。它自gcc4.8起可用,但clang 3.7仍然没有。 IDK是否决定反对还是采取其他措施。
– Peter Cordes
16年1月31日,13:41
#7 楼
您可以像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 q4312078qx8,%esp 0x08048336 : and q4312078qxfffffff0,%esp 0x08048339 : sub q4312078qx10,%esp 6 printf ("Hello.\n"); 0x0804833c : movl q4312078qx8048440,(%esp) 0x08048343 : call 0x8048284 7 return 0; 8 } 0x08048348 : mov q4312078qx0,%eax 0x0804834d : leave 0x0804834e : ret End of assembler dump.
评论
归档链接:web.archive.org/web/20090412112833/http://sourceware.org:80/gdb/…
–vlad4378
17年5月10日在17:53
要将GDB的反汇编程序切换为Intel语法,请使用set disassembly-flavor intel命令。
–俄罗斯
18年5月30日在16:26
#8 楼
使用-S(注意:大写S)切换到GCC,它将把汇编代码发送到扩展名为.s的文件中。例如,以下命令:gcc -O2 -S -c foo.c
#9 楼
我还没有尝试过gcc,但是在使用g ++的情况下。下面的命令对我有用。 -g用于调试构建,-Wa,-adhln传递给汇编器以列出源代码g ++ -g -Wa,-adhln src.cpp
评论
它也适用于gcc! -Wa,...用于汇编器部分的命令行选项(在C / ++编译后在gcc / g ++中执行)。它作为内部调用(在Windows中为as.exe)。请参阅> as --help作为命令行以查看更多帮助
– Hartmut Schorrig
4月17日15:28
#10 楼
在gcc或g ++上使用-Wa,-adhln作为选项来生成标准输出的列表输出。-Wa,...用于汇编器部分的命令行选项(在gcc / g ++之后执行C / ++编译)。它以内部方式调用(在Windows中为as.exe)。
以--help
作为命令行,请参见
>作为命令行,以查看有关内部汇编工具的更多帮助。 gcc
评论
请注意,“字节码”通常表示VM使用的代码,例如JVM或.NET的CLR。最好将GCC的输出称为“机器代码”,“机器语言”或“汇编语言”我添加了一个使用Godbolt的答案,因为它是用于快速试验不同选项如何影响代码生成的非常强大的工具。
stackoverflow.com/a/19083877/995714
如何从gcc中的C / C ++源获取汇编程序输出的可能重复项?
在这里回答:stackoverflow.com/questions/137038/…使用-S选项来gcc(或g ++)。