如何做到这一点呢?

如果我想分析某些东西是如何编译的,我该如何获得发出的程序集代码?


当前回答

-save-temps

元数据的回答中提到了这一点,但让我进一步举例说明。

与-S相比,这个选项的最大优点是可以很容易地将其添加到任何构建脚本中,而不会过多地干扰构建本身。

当你这样做时:

gcc -save-temps -c -o main.o main.c

文件c

#define INC 1

int myfunc(int i) {
    return i + INC;
}

现在,除了正常的主输出。O,当前工作目录还包含以下文件:

main.i is a bonus and contains the preprocessed file: # 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; } main.s contains the desired generated assembly: .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

如果你想对大量的文件执行此操作,可以考虑使用:

-save-temps=obj

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

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

gcc -save-temps -c -o main.o -v main.c

它实际上显示了正在使用的显式文件,而不是/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

它在Ubuntu 19.04 (Disco Dingo) amd64, GCC 8.3.0中进行了测试。

制定预定义目标

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

make help

告诉我们可以这样做:

make main.s

这个目标运行:

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

所以这个文件可以在CMakeFiles/main.dir/main.c.s目录下找到。

它在CMake 3.16.1上进行了测试。

其他回答

如果您希望看到的内容依赖于输出的链接,那么除了前面提到的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;

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

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

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

我从Windows XP上的DOS窗口运行g++,针对的是一个包含隐式强制转换的例程

cd 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++代码在生成的汇编语言流中显示为注释)。

  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)

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

在控制台/终端命令提示符中:

Write a C program in a C code editor like Code::Blocks and save it with filename extension .c Compile and run it. Once run successfully, go to the folder where you have installed your GCC compiler and enter the following command to get a ' .s ' file of the ' .c' file cd C:\gcc gcc -S complete path of the C file ENTER An example command (as in my case) gcc -S D:\Aa_C_Certified\alternate_letters.c This outputs a '.s' file of the original '.c' file. After this, type the following command cpp filename.s ENTER Example command (as in my case) cpp alternate_letters.s <enter>

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

使用-S开关:

g++ -S main.cpp

或者也可以用gcc:

gcc -S main.c

还有这个。

这将生成C代码+行号交织的汇编代码,以便更容易地查看哪些行生成了什么代码(-S -fverbose-asm -g -O2):

# Create assembler code:
g++ -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页)中找到了它。