使用GCC生成可读组件?

Jam*_*mes 238 c assembly gcc

我想知道如何在我的C源文件中使用GCC来转储机器代码的助记符版本,以便我可以看到我的代码被编译成什么.您可以使用Java执行此操作,但我无法找到GCC的方法.

我试图在汇编中重新编写一个C方法,看看GCC是如何做的,这将是一个很大的帮助.

Bas*_*ard 321

如果使用调试符号进行编译,则可以使用它objdump来生成更易读的反汇编.

>objdump --help
[...]
-S, --source             Intermix source code with disassembly
-l, --line-numbers       Include line numbers and filenames in output
Run Code Online (Sandbox Code Playgroud)

objdump -drwC -Mintel 很好:

  • -r在重定位上显示符号名称(因此您将putscall下面的说明中看到)
  • -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
Run Code Online (Sandbox Code Playgroud)

  • @toto我认为他的意思是英特尔语法,而不是AT&T语法 (11认同)
  • @James是的,供应`-Mintel`. (8认同)
  • 通过使用切换序列`-Wa,-adhln -g到gcc`可以放弃中间对象文件.这假设汇编程序是气体,并非总是如此. (7认同)
  • 是否有转换只能获取英特尔指令? (3认同)
  • 所有这些都是英特尔指令,因为它们运行在英特尔处理器上:D. (3认同)
  • Mac 用户使用 `otool -tV` :) (2认同)

kmm*_*kmm 97

我想补充一下这些答案,如果你给gcc一个标志-fverbose-asm,它发出的汇编程序将会更加清晰.

  • @Herdsman:你不能。`-fverbose-asm` 添加的额外内容是以输出的 asm 语法中的注释形式出现的,而不是在 `.o` 文件中添加任何额外内容的指令。它们在组装时全部被丢弃。查看编译器 asm 输出*而不是反汇编,例如在 https://godbolt.org/ 上,您可以通过鼠标悬停和相应源/asm 行的颜色突出显示轻松地将其与源行匹配。[如何从 GCC/clang 程序集输出中消除“噪音”?](/sf/ask/2698648151/) (3认同)

And*_*ton 74

使用-S(注意:大写S)切换到GCC,它会将汇编代码发送到扩展名为.s的文件.例如,以下命令:

gcc -O2 -S foo.c

将生成的汇编代码保留在文件foo.s.

直接从http://www.delorie.com/djgpp/v2faq/faq8_20.html中删除(但删除错误-c)

  • 你不应该混合-c和-S,只使用其中一个.在这种情况下,一个覆盖另一个,可能取决于它们的使用顺序. (35认同)
  • @AdamRosenfield有关'不应该混合-c和-S'的任何参考?如果是真的,我们可能应该提醒作者并对其进行编辑. (4认同)
  • @Tony:https://gcc.gnu.org/onlinedocs/gcc/Overall-Options.html#Overall-Options"您可以使用...***一***-c选项,-S,或-E说gcc要停止的地方." (4认同)
  • 如果您想要所有中间输出,请使用“gcc -march=native -O3 -save-temps”。您仍然可以使用“-c”在对象文件创建时停止,而无需尝试链接或其他任何操作。 (2认同)
  • “-save-temps”很有趣,因为它一次性转储了确切的代码生成的代码,而使用“-S”调用编译器的另一种选项意味着编译两次,并且可能使用不同的选项。**但是** `-save-temps` 将所有内容转储到当前目录中,这有点混乱。看起来它更适合作为 GCC 的调试选项,而不是检查代码的工具。 (2认同)
  • @StéphaneGourichon:这是正确的;与此用例相比,更多的是用于调试/创建编译器错误报告。我从不使用 `-save-temps` 来查看某些源代码如何编译为 asm,或者 `-masm=intel -S -o- | less`,反汇编 `.o` 或可执行文件,或者将其放在 https://godbolt.org/ 上。 (2认同)

小智 49

-S在基于x86的系统上使用切换到GCC会产生AT&T语法转储,默认情况下可以使用-masm=att交换机指定,如下所示:

gcc -S -masm=att code.c
Run Code Online (Sandbox Code Playgroud)

如果您想以英特尔语法生成转储,则可以使用该-masm=intel开关,如下所示:

gcc -S -masm=intel code.c
Run Code Online (Sandbox Code Playgroud)

(两者分别生成code.c转换为各种语法的转储code.s)

为了使用objdump产生类似的效果,您需要使用--disassembler-options= intel/ attswitch,一个示例(使用代码转储来说明语法上的差异):

 $ objdump -d --disassembler-options=att code.c
Run Code Online (Sandbox Code Playgroud)
 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
Run Code Online (Sandbox Code Playgroud)

$ objdump -d --disassembler-options=intel code.c
Run Code Online (Sandbox Code Playgroud)
 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
Run Code Online (Sandbox Code Playgroud)


Sha*_*our 34

godbolt是一个非常有用的工具,他们列出的只有C++编译器,但是你可以使用-x cflag来让它将代码视为C.然后它将为你的代码并排生成一个汇编列表,你可以使用该Colourise选项来生成彩色条可视地指示哪个源代码映射到生成的程序集.例如,以下代码:

#include <stdio.h>

void func()
{
  printf( "hello world\n" ) ;
}
Run Code Online (Sandbox Code Playgroud)

使用以下命令行:

-x c -std=c99 -O3
Run Code Online (Sandbox Code Playgroud)

Colourise会生成以下:

在此输入图像描述


Bas*_*tch 22

您是否尝试过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年放弃)扩展

  • 忘了提一下:如果你正在寻找"类似于源,但没有每个源代码行之后存储/重载的噪音",那么`-Og`甚至比`-O1`更好.这意味着"优化调试"并使asm不需要太多棘手/难以理解的优化,而这些优化可以完成消息来源所说的一切.它从gcc4.8开始就可以使用,但是clang 3.7仍然没有它.IDK,如果他们决定反对它或什么. (2认同)

Vis*_*gar 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.


cod*_*nix 13

使用-S(注意:大写S)切换到GCC,它会将汇编代码发送到扩展名为.s的文件.例如,以下命令:

gcc -O2 -S -c foo.c


DAG*_*DAG 6

我还没有尝试过gcc,但如果是的话g++,下面的命令对我有用。

  • -g用于调试构建
  • -Wa,-adhln传递给汇编器以与源代码一起列出
g++ -g -Wa,-adhln src.cpp
Run Code Online (Sandbox Code Playgroud)