How do you get assembler output from C/C++ source in gcc?
怎么做到的?
如果我想分析什么是如何编译的,我将如何获得发出的汇编代码?
使用gcc(或g++)的
1 | gcc -S helloworld.c |
这将在helloworld.c上运行预处理器(cpp),执行初始编译,然后在运行汇编程序之前停止。
默认情况下,它将输出一个文件
1 | gcc -S -o my_asm_output.s helloworld.c |
当然,只有当您有原始的源代码时,这才有效。如果只有结果对象文件,则另一种选择是使用
1 | objdump -S --disassemble helloworld > helloworld.dump |
如果对对象文件(编译时的
运行
这将生成与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的
尤其是在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。
以下是在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上的第一篇帖子:—