gccでC / C ++ソースからアセンブラ出力を取得するにはどうすればよいですか?
質問
これをどのように行うのですか?
何かがどのようにコンパイルされているかを分析したい場合、出力されたアセンブリコードをどのように取得しますか?
解決
gcc(またはg ++)に -S
オプションを使用します。
gcc -S helloworld.c
これにより、helloworld.cでプリプロセッサ(cpp)が実行され、初期コンパイルが実行され、アセンブラが実行される前に停止します。
デフォルトでは、これはファイル helloworld.s
を出力します。出力ファイルは、 -o
オプションを使用して設定できます。
gcc -S -o my_asm_output.s helloworld.c
もちろん、これは元のソースがある場合にのみ機能します。
結果のオブジェクトファイルのみがある場合の代替方法は、-disassemble
オプション(または省略形の -d
を設定して、 objdump
を使用することです。フォーム)。
objdump -S --disassemble helloworld > helloworld.dump
このオプションは、オブジェクトファイルに対してデバッグオプションが有効になっており(コンパイル時に -g
)、ファイルが削除されていない場合に最適に機能します。
file helloworld
を実行すると、objdumpを使用することで得られる詳細レベルに関するいくつかの指標が得られます。
他のヒント
これにより、Cコードと行番号を組み合わせたasmコードが生成され、どの行がどのコードを生成するかをより簡単に確認できます。
# 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ページ目(全体の15ページ目) PDF)。
次のコマンドラインは、 Christian Garbin'sブログ
g++ -g -O -Wa,-aslh horton_ex2_05.cpp >list.txt
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'
出力は、元の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 <*>,-16(%ebp)
見たいものが出力のリンクに依存している場合、前述のgcc -Sに加えて、出力オブジェクトファイル/実行可能ファイルのobjdumpも役立つ場合があります。デフォルトのobjdump構文をより読みやすいnasm構文に変換するLoren Merrittによる非常に便利なスクリプトを次に示します。
#!/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
見たいものが出力のリンクに依存している場合、前述のgcc -Sに加えて、出力オブジェクトファイル/実行可能ファイルのobjdumpも役立つ場合があります。デフォルトのobjdump構文をより読みやすいnasm構文に変換するLoren Merrittによる非常に便利なスクリプトを次に示します。
<*>
これはgcc -Sの出力でも使用できると思われます。
=~ /\tnop |\txchg *ax,ax$/) {
# drop this line
} else {
print $prev;
$prev = 見たいものが出力のリンクに依存している場合、前述のgcc -Sに加えて、出力オブジェクトファイル/実行可能ファイルのobjdumpも役立つ場合があります。デフォルトのobjdump構文をより読みやすいnasm構文に変換するLoren Merrittによる非常に便利なスクリプトを次に示します。
<*>
これはgcc -Sの出力でも使用できると思われます。
;
}
}
print $prev;
close FH;
これはgcc -Sの出力でも使用できると思われます。
さて、みんなが言ったように、-Sオプションを使用します。 -save-tempsオプションを使用すると、前処理済みファイル( .i)、アセンブリファイル( .s)、およびオブジェクトファイル(* .o)も取得できます。 (-E、-S、および-cを使用してそれぞれを取得します。)
誰もが指摘したように、GCCの -S
オプションを使用します。また、最適化オプション(なしの場合は -O0
、積極的な最適化の場合は -O2
)を追加するかどうかによって、結果が(大幅に!)異なる可能性があることも付け加えます。 。
特にRISCアーキテクチャでは、コンパイラは最適化を行う際に認識をほとんど超えてコードを変換することがよくあります。結果を見るのは印象的で魅力的です!
前述のように、-Sフラグを見てください。
また、フラグの「-fdump-tree」ファミリー、特に「-fdump-tree-all」を確認する価値があります。これにより、gccの中間形式の一部を確認できます。多くの場合、これらはアセンブラよりも読みやすく(少なくとも私にとっては)、最適化パスの実行方法を確認できます。
-Sオプションを使用します。
gcc -S program.c
LLVMアセンブリを探している場合:
llvm-gcc -emit-llvm -S hello.c
回答にはこの可能性はありません。おそらく質問は2008年のものでしょうが、2018年にはMatt GoldboltのオンラインWebサイトを使用できますhttps://godbolt.org
ローカルでgit cloneしてプロジェクトを実行することもできます https://github.com/mattgodbolt/compiler-エクスプローラー
差出人: http://www.delorie.com/djgpp/v2faq/faq8_20 .html
gcc -c -g -Wa、-a、-ad [その他のGCCオプション] foo.c&gt; foo.lst
PhirePhlyの答えの代わりに または、皆が言ったように-Sを使用します。
Windows上のCプログラムのアセンブリコードを表示/印刷する手順は次のとおりです
console / terminal /コマンドプロンプト:
-
codeblocksなどのCコードエディタでCプログラムを作成し、拡張子.c
で保存します。
-
コンパイルして実行します。
-
正常に実行されたら、gccコンパイラをインストールしたフォルダーに移動して、
「。c」ファイルの「.s」ファイルを取得する次のコマンド
C:\ gcc&gt; gcc -S Cファイルの完全なパスENTER
コマンドの例(私の場合のように)
C:\ gcc&gt; gcc -S D:\ Aa_C_Certified \ alternate_letters.c
これは、元の「.c」ファイルの「.s」ファイルを出力します
4。この後、次のコマンドを入力します
C; \ gcc&gt; cpp filename.s ENTER
コマンドの例(私の場合)
C; \ gcc&gt; cpp alternate_letters.s
これにより、Cプログラムのアセンブリ言語コード全体が印刷/出力されます。
&quot; -S&quot;を使用オプションとして。端末にアセンブリ出力を表示します。
最近、プログラム内の各関数のアセンブリを知りたい
これは私がやった方法です。
$ 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
-save-temps
これは https://stackoverflow.com/a/17083009/895245 で言及されましたが、それをさらに例示させてください。実行する場合:
gcc -save-temps -c -o main.o main.c
main.c
#define INC 1
int myfunc(int i) {
return i + INC;
}
そして今、通常の出力 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; }
-
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
多数のファイルに対して実行する場合は、代わりに使用することを検討してください:
-save-temps=obj
現在の作業ディレクトリではなく、 -o
オブジェクトの出力と同じディレクトリに中間ファイルを保存し、潜在的なベース名の競合を回避します。
-S
に対するこのオプションの利点は、ビルド自体に大きな影響を与えることなく、ビルドスクリプトに簡単に追加できることです。
このオプションのもう1つの素晴らしい点は、 -v
を追加する場合です:
gcc -save-temps -c -o main.o -v main.c
実際には、 / tmp
の下にある見苦しい一時ファイルの代わりに使用されている明示的なファイルが表示されます。 p>
/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 amd64、GCC 8.3.0でテスト済み。
gccを使用したCのソリューションは次のとおりです。
gcc -S program.c && gcc program.c -o output
-
ここでは、最初の部分はプログラムのアセンブリ出力をProgramと同じファイル名で保存しますが、拡張子 .s を変更すると、通常のテキストファイルとして開くことができます。
-
ここの2番目の部分は、実際に使用するためにプログラムをコンパイルし、指定されたファイル名でプログラムの実行可能ファイルを生成します。
上記で使用した program.c はプログラムの名前で、 output は生成する実行可能ファイルの名前です。
ところで、それはStackOverFlowの最初の投稿です:-}