我想知道如何在我的C源文件上使用GCC转储机器代码的助记符版本,以便可以看到我的代码被编译成什么。您可以使用Java来做到这一点,但我找不到GCC的方法。

我试图在汇编中重新编写C方法,看看GCC如何做到这一点很大帮助。

评论

请注意,“字节码”通常表示VM使用的代码,例如JVM或.NET的CLR。最好将GCC的输出称为“机器代码”,“机器语言”或“汇编语言”

我添加了一个使用Godbolt的答案,因为它是用于快速试验不同选项如何影响代码生成的非常强大的工具。

stackoverflow.com/a/19083877/995714

如何从gcc中的C / C ++源获取汇编程序输出的可能重复项?

在这里回答:stackoverflow.com/questions/137038/…使用-S选项来gcc(或g ++)。

#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