你如何在gcc中从C/C++源获得汇编程序输出?

Dou*_* T. 340 c c++ debugging assembly gcc

怎么做到这一点?

如果我想分析如何编译某些内容,我将如何获得发出的汇编代码?

And*_*mbe 389

使用-Sgcc(或g ++)选项.

gcc -S helloworld.c
Run Code Online (Sandbox Code Playgroud)

这将在helloworld.c上运行预处理器(cpp),执行初始编译,然后在运行汇编程序之前停止.

默认情况下,这将输出一个文件helloworld.s.仍然可以使用该-o选项设置输出文件.

gcc -S -o my_asm_output.s helloworld.c
Run Code Online (Sandbox Code Playgroud)

当然,只有拥有原始资源才能使用.如果您只使用生成的目标文件,则可以objdump通过设置--disassemble选项(或-d缩写形式)来使用.

objdump -S --disassemble helloworld > helloworld.dump
Run Code Online (Sandbox Code Playgroud)

如果为目标文件启用了调试选项,则此选项最有效(-g在编译时)并且文件尚未被剥离,.

运行file helloworld将为您提供使用objdump获得的详细程度的一些指示.

  • @touchStone:**GAS `.intel_syntax` 与 NASM 不兼容**。它更像是 MASM(例如,`mov eax, symbol` 是一个负载,不像在 NASM 中它是地址的 `mov r32, imm32`),但也不完全与 MASM 兼容。我强烈推荐它作为一种很好的阅读格式,特别是如果你喜欢用 NASM 语法编写。`objdump -drwC -Mintel | less` 或 `gcc foo.c -O1 -fverbose-asm -masm=intel -S -o- | less` 很有用。(另请参阅[如何从 GCC/clang 程序集输出中去除“噪音”?](http://stackoverflow.com/questions/38552116))。`-masm=intel` 也适用于 clang。 (4认同)
  • 虽然这是正确的,但我发现Cr McDonough的答案结果更有用. (3认同)
  • 另外一个用途:objdump -M intel -S --disassemble helloworld> helloworld.dump来获取与linux上的nasm兼容的intel语法中的对象转储. (3认同)
  • 如果你有一个功能来优化/检查,那么你可以尝试在线交互式C++编译器,即[godbolt](http://gcc.godbolt.org/) (2认同)
  • 最好使用`gcc -O -fverbose-asm -S` (2认同)

Phi*_*hly 165

这将生成asm代码,其中C代码+行号交织在一起,以便更容易地看到哪些行生成了什么代码.

# create assembler code:
c++ -S -fverbose-asm -g -O2 test.cc -o test.s
# create asm interlaced with source lines:
as -alhnd test.s > test.lst
Run Code Online (Sandbox Code Playgroud)

程序员的算法中找到,第3页(这是PDF的整体第15页).

  • `g ++ -g -O0 -c -fverbose-asm -Wa,-adhln test.cpp> test.lst`将是这个的简写版本. (21认同)
  • 您也可以使用`gcc -c -g -Wa,-ahl = test.s test.c`或`gcc -c -g -Wa,-a,-ad test.c> test.txt` (4认同)
  • (实际上是在页面上(编号)3(这是PDF的第15页)) (3认同)
  • 遗憾的是,OS X 上的“as”不知道这些标志。不过,如果确实如此,您可能可以使用“-Wa”将选项传递给“as”一行。 (3认同)
  • 一篇[博客文章](http://www.systutorials.com/240/generate-a-mixed-source-and-assemble-listing-using-gcc/)更详细地解释了这一点,包括单命令版本,例如传说和Lu'u发帖。但为什么是“-O0”?其中充满了加载/存储,这使得跟踪值变得困难,并且不会告诉您有关优化代码的效率的任何信息。 (2认同)

小智 47

以下命令行来自Christian Garbin的博客

g++ -g -O -Wa,-aslh horton_ex2_05.cpp >list.txt
Run Code Online (Sandbox Code Playgroud)

我在Win-XP的DOS窗口中运行G ++,对着包含隐式转换的例程

c:\gpp_code>g++ -g -O -Wa,-aslh horton_ex2_05.cpp >list.txt
horton_ex2_05.cpp: In function `int main()':
horton_ex2_05.cpp:92: warning: assignment to `int' from `double'
Run Code Online (Sandbox Code Playgroud)

输出是用原始C++代码分配的生成代码(C++代码在生成的asm流中显示为注释)

  16:horton_ex2_05.cpp **** using std::setw;
  17:horton_ex2_05.cpp ****
  18:horton_ex2_05.cpp **** void disp_Time_Line (void);
  19:horton_ex2_05.cpp ****
  20:horton_ex2_05.cpp **** int main(void)
  21:horton_ex2_05.cpp **** {
 164                    %ebp
 165                            subl $128,%esp
?GAS LISTING C:\DOCUME~1\CRAIGM~1\LOCALS~1\Temp\ccx52rCc.s
166 0128 55                    call ___main
167 0129 89E5          .stabn 68,0,21,LM2-_main
168 012b 81EC8000      LM2:
168      0000
169 0131 E8000000      LBB2:
169      00
170                    .stabn 68,0,25,LM3-_main
171                    LM3:
172                            movl $0,-16(%ebp)
Run Code Online (Sandbox Code Playgroud)

  • @PeterCordes有一种更简单的方法,请参阅[这个问题](/sf/ask/4104501411/) (2认同)

Dou*_* T. 24

使用-S开关

g++ -S main.cpp
Run Code Online (Sandbox Code Playgroud)

或者与gcc

gcc -S main.c
Run Code Online (Sandbox Code Playgroud)

也看到这个

  • 查看常见问题解答:"询问和回答您自己的编程问题也很完美".关键是现在StackOverflow包含Q&A作为其他人的资源. (7认同)

Cir*_*四事件 15

-save-temps

这是在/sf/answers/1195810661/中提到的,但让我进一步举例说明。

这个选项的一大优点-S是可以很容易地将它添加到任何构建脚本中,而不会对构建本身造成太多干扰。

当你这样做时:

gcc -save-temps -c -o main.o main.c
Run Code Online (Sandbox Code Playgroud)

主文件

#define INC 1

int myfunc(int i) {
    return i + INC;
}
Run Code Online (Sandbox Code Playgroud)

现在,除了正常输出之外main.o,当前工作目录还包含以下文件:

  • main.i 是一个奖励,包含预先处理的文件:

    # 1 "main.c"
    # 1 "<built-in>"
    # 1 "<command-line>"
    # 31 "<command-line>"
    # 1 "/usr/include/stdc-predef.h" 1 3 4
    # 32 "<command-line>" 2
    # 1 "main.c"
    
    
    int myfunc(int i) {
        return i + 1;
    }
    
    Run Code Online (Sandbox Code Playgroud)
  • main.s 包含所需的生成程序集:

        .file   "main.c"
        .text
        .globl  myfunc
        .type   myfunc, @function
    myfunc:
    .LFB0:
        .cfi_startproc
        pushq   %rbp
        .cfi_def_cfa_offset 16
        .cfi_offset 6, -16
        movq    %rsp, %rbp
        .cfi_def_cfa_register 6
        movl    %edi, -4(%rbp)
        movl    -4(%rbp), %eax
        addl    $1, %eax
        popq    %rbp
        .cfi_def_cfa 7, 8
        ret
        .cfi_endproc
    .LFE0:
        .size   myfunc, .-myfunc
        .ident  "GCC: (Ubuntu 8.3.0-6ubuntu1) 8.3.0"
        .section    .note.GNU-stack,"",@progbits
    
    Run Code Online (Sandbox Code Playgroud)

如果要对大量文件执行此操作,请考虑改用:

 -save-temps=obj
Run Code Online (Sandbox Code Playgroud)

它将中间文件保存到与-o对象输出相同的目录而不是当前工作目录,从而避免潜在的基名冲突。

这个选项的另一个很酷的事情是如果你添加-v

gcc -save-temps -c -o main.o -v main.c
Run Code Online (Sandbox Code Playgroud)

它实际上显示了正在使用的显式文件而不是丑陋的临时文件/tmp,因此很容易确切地知道发生了什么,其中包括预处理/编译/组装步骤:

/usr/lib/gcc/x86_64-linux-gnu/8/cc1 -E -quiet -v -imultiarch x86_64-linux-gnu main.c -mtune=generic -march=x86-64 -fpch-preprocess -fstack-protector-strong -Wformat -Wformat-security -o main.i
/usr/lib/gcc/x86_64-linux-gnu/8/cc1 -fpreprocessed main.i -quiet -dumpbase main.c -mtune=generic -march=x86-64 -auxbase-strip main.o -version -fstack-protector-strong -Wformat -Wformat-security -o main.s
as -v --64 -o main.o main.s
Run Code Online (Sandbox Code Playgroud)

在 Ubuntu 19.04 amd64、GCC 8.3.0 中测试。

CMake 预定义目标

CMake 自动为预处理文件提供一个目标:

make help
Run Code Online (Sandbox Code Playgroud)

向我们展示了我们可以做到:

make main.s
Run Code Online (Sandbox Code Playgroud)

该目标运行:

Compiling C source to assembly CMakeFiles/main.dir/main.c.s
/usr/bin/cc    -S /home/ciro/hello/main.c -o CMakeFiles/main.dir/main.c.s
Run Code Online (Sandbox Code Playgroud)

所以文件可以在 CMakeFiles/main.dir/main.c.s

在 cmake 3.16.1 上测试。


Dar*_*ari 12

如果你想看到的东西取决于输出的链接,那么除了前面提到的gcc -S之外,对输出目标文件/可执行文件的objdump也可能是有用的.这是Loren Merritt的一个非常有用的脚本,它将默认的objdump语法转换为更易读的nasm语法:

#!/usr/bin/perl -w
$ptr='(BYTE|WORD|DWORD|QWORD|XMMWORD) PTR ';
$reg='(?:[er]?(?:[abcd]x|[sd]i|[sb]p)|[abcd][hl]|r1?[0-589][dwb]?|mm[0-7]|xmm1?[0-9])';
open FH, '-|', '/usr/bin/objdump', '-w', '-M', 'intel', @ARGV or die;
$prev = "";
while(<FH>){
    if(/$ptr/o) {
        s/$ptr(\[[^\[\]]+\],$reg)/$2/o or
        s/($reg,)$ptr(\[[^\[\]]+\])/$1$3/o or
        s/$ptr/lc $1/oe;
    }
    if($prev =~ /\t(repz )?ret / and
       $_ =~ /\tnop |\txchg *ax,ax$/) {
       # drop this line
    } else {
       print $prev;
       $prev = $_;
    }
}
print $prev;
close FH;
Run Code Online (Sandbox Code Playgroud)

我怀疑这也可以用在gcc -S的输出上.

  • 尽管如此,这个脚本是一个肮脏的黑客,它没有完全转换语法。例如,`mov eax,ds:0x804b794` 不是很NASMish。此外,有时它只是剥离有用的信息:`movzx eax,[edx+0x1]` 让读者猜测内存操作数是 `byte` 还是 `word`。 (2认同)

小智 8

好吧,正如大家所说,使用-S选项.如果使用-save-temps选项,还可以获得预处理文件(.i),汇编文件( .s)和目标文件(*.o).(使用-E,-S和-c获取每个.)


小智 8

这是使用 GCC 的 C 解决方案:

gcc -S program.c && gcc program.c -o output
Run Code Online (Sandbox Code Playgroud)
  1. 这里,第一部分将程序的汇编输出存储在与程序相同的文件名中,但使用更改后的.s扩展名,您可以将其作为任何普通文本文件打开。

  2. 这里的第二部分编译您的程序以供实际使用,并为您的程序生成具有指定文件名的可执行文件。

上面使用的program.c是您的程序的名称,输出是您要生成的可执行文件名称。

  • 您还可以使用 gcc -O2 -save-temps foo.c 来编译+汇编+链接,但保存中间的 .s 和 .o 文件,而不是单独运行仅编译为 asm 的构建。(也是一个‘.i’预处理的C文件)。因此步骤较少,但会生成您不需要的文件。 (2认同)

Dan*_*ski 7

正如大家所指出的,使用-SGCC选项.我还想补充一点,结果可能会有所不同(非常!),具体取决于您是否添加优化选项(-O0对于没有优化选项-O2).

特别是在RISC体系结构中,编译器通常会在进行优化时将代码转换为几乎无法识别.看结果令人印象深刻,令人着迷!


Chr*_*son 7

如前所述,请查看-S标志.

它还值得查看'-fdump-tree'标志系列,特别是'-fdump-tree-all',它可以让你看到一些gcc的中间形式.这些通常比汇编程序更具可读性(至少对我而言),并让您了解优化通过的执行方式.


mca*_*dre 7

如果您正在寻找LLVM组装:

llvm-gcc -emit-llvm -S hello.c
Run Code Online (Sandbox Code Playgroud)


Jer*_*ten 6

使用-S选项:

gcc -S program.c
Run Code Online (Sandbox Code Playgroud)


小智 6

来自:http : //www.delorie.com/djgpp/v2faq/faq8_20.html

gcc -c -g -Wa,-a,-ad [其他 GCC 选项] foo.c > foo.lst

替代 PhirePhly 的答案或者像大家说的那样使用 -S 。


Ant*_*REL 6

我没有在答案中看到这种可能性,可能是因为问题是从2008年开始,但在2018年你可以使用Matt Goldbolt的在线网站https://godbolt.org

你也可以在本地git克隆并运行他的项目https://github.com/mattgodbolt/compiler-explorer