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

How do you get assembler output from C/C++ source in gcc?

怎么做到的?

如果我想分析什么是如何编译的,我将如何获得发出的汇编代码?


使用gcc(或g++)的-S选项。

1
gcc -S helloworld.c

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

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

1
gcc -S -o my_asm_output.s helloworld.c

当然,只有当您有原始的源代码时,这才有效。如果只有结果对象文件,则另一种选择是使用objdump,方法是设置--disassemble选项(或-d作为缩写形式)。

1
objdump -S --disassemble helloworld > helloworld.dump

如果对对象文件(编译时的-g启用了调试选项)并且该文件未被剥离,则此选项最有效。

运行file helloworld将向您提供一些关于使用objdump将获得的详细级别的指示。


这将生成与C代码+行号交织的ASM代码,以便更容易地看到哪些行生成了什么代码。

1
2
3
4
# 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

在程序员算法中,第3页(这是PDF的第15页)。


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

1
g++ -g -O -Wa,-aslh horton_ex2_05.cpp >list.txt

我在Win XP的DOS窗口中运行g++,与包含隐式强制转换的例程进行比较

1
2
3
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'

输出是用原始C++代码迭加的生成代码(C++代码在生成的ASM流中显示为注释)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
  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)


使用-s开关

1
g++ -S main.cpp

或与GCC一起

1
gcc -S main.c

也看到这个


如果您希望看到的内容取决于输出的链接,那么输出对象文件/可执行文件上的objdump除了前面提到的gcc-s之外可能也很有用。下面是loren merritt的一个非常有用的脚本,它将默认的objdump语法转换为更可读的nasm语法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#!/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;

我怀疑这也可以用于gcc-s的输出。


好吧,正如大家所说,使用-s选项。如果使用-save temps选项,还可以获取预处理文件(.i)、程序集文件(.s)和对象文件(*.o)。(使用-e、-s和-c获取每一个。)


如前所述,查看-s标志。

还值得一看"-fdump tree"标记族,特别是"-fdump tree all",这让您可以看到GCC的一些中间形式。这些通常比汇编程序(至少对我来说)更易读,让您看看优化过程是如何执行的。


正如大家所指出的,使用GCC的-S选项。我还想补充一点,结果可能会有很大的变化。取决于是否添加优化选项(-O0表示无,-O2表示主动优化)。

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


使用-s选项:

1
gcc -S program.c

如果要查找llvm程序集:

1
llvm-gcc -emit-llvm -S hello.c


我在答案中没有看到这种可能性,可能是因为问题来自2008年,但在2018年,你可以使用马特·戈德博尔特的在线网站https://godbolt.org。

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


发件人:http://www.delorie.com/djgpp/v2faq/faq8_20.html

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

代替菲利普霍夫的回答或者像大家说的那样使用-s。


Output of these commnads

以下是在Windows上查看/打印任何C程序的汇编代码的步骤

控制台/终端/命令提示:

  • 在C代码编辑器(如代码块)中编写C程序,并用扩展名保存它。

  • 编译并运行它。

  • 一旦成功运行,转到安装了gcc编译器的文件夹,并给出

    下面的命令获取".c"文件的".s"文件

    c:gcc>gcc-s输入c文件的完整路径

    一个示例命令(在我的例子中)

    c:gcc>gcc-s d:aa_c_certifiedalternate_letters.c

    这将输出原始".c"文件的".s"文件

  • 4。在此之后,键入以下命令

    c;gcc>cpp文件名.s输入

    示例命令(在我的例子中)

    c;gcc>cpp替换字母.s

    这将打印/输出C程序的整个汇编语言代码。


    最近我想知道程序中每个函数的组装我就是这样做的。

    1
    2
    3
    4
    $ gcc main.c                      // main.c source file
    $ gdb a.exe                       // gdb a.out in linux
      (gdb) disass main               // note here main is a function
                                      // similary it can be done for other functions

    使用"-s"作为选项。它在终端中显示部件输出。


    下面是一个使用GCC的C解决方案:

    1
    gcc -S program.c && gcc program.c -o output
  • 在这里,第一部分以与程序相同的文件名存储程序的程序集输出,但扩展名已更改,您可以将其作为任何普通文本文件打开。

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

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

    顺便说一句,这是我在StackOverflow上的第一篇帖子:—