web-dev-qa-db-ja.com

gccのC / C ++ソースからアセンブラ出力を取得する方法

どのようにこれをするのですか?

コンパイルされているものを分析したいのであれば、どのようにして発行されたアセンブリコードを入手すればよいのでしょうか。

322
Doug T.

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を使用して得られる詳細レベルについての指示がいくつかあります。

371

これにより、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ページにあります(これはPDFの15ページ全体です)。

163
PhirePhly

次のコマンドラインは Christian Garbinさんのブログ からのものです

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 $0,-16(%ebp)
44
Cr McDonough

-Sスイッチを使う

g++ -S main.cpp

またはgccと一緒に

gcc -S main.c

this もご覧ください。

22
Doug T.

あなたが見たいものが出力のリンクに依存しているなら、出力オブジェクトファイル/実行可能ファイルのobjdumpも前述のgcc -Sに加えて役に立つかもしれません。これは、デフォルトの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
       $_ =~ /\tnop |\txchg *ax,ax$/) {
       # drop this line
    } else {
       print $prev;
       $prev = $_;
    }
}
print $prev;
close FH;

これはgcc -Sの出力にも使用できると思います。

12
Dark Shikari

まあ、みんなが言ったように、-Sオプションを使ってください。 -save-tempsオプションを使用すると、前処理済みファイル(。i)、アセンブリファイル(。s)およびオブジェクトファイル(*。o)も取得できます。 (-E、-S、および-cを使用してそれぞれを入手してください。)

8
METADATA

皆さんが指摘したように、GCCには-Sオプションを使用してください。また、最適化オプションを追加するかどうかによって結果が変わる可能性があることを付け加えたいと思います(なしの場合は-O0、積極的な最適化の場合は-O2)。

特にRISCアーキテクチャーでは、コンパイラーは最適化を行う際に認識をはるかに超えてコードを変換することがよくあります。結果を見るのは印象的で魅力的です。

7
Dan Lenski

前述のように、-Sフラグを見てください。

また、 ' - fdump-tree'ファミリーのフラグ、特に ' - fdump-tree-all'を見る価値があります。これは、gccの中間形式のいくつかを見ることができます。これらは、(少なくとも私にとっては)アセンブラよりも読みやすくなることが多く、最適化パスがどのように実行されるのかを確認できます。

7
Chris Jefferson

おそらく質問が2008年からのものであるために、私は答えの中でこの可能性を見ません、しかし2018年にあなたはMatt Goldboltのオンラインウェブサイトを使うことができます https://godbolt.org

ローカルでクローンをgitして彼のプロジェクトを実行することもできます https://github.com/mattgodbolt/compiler-Explorer

6
Antonin GAVREL

-Sオプションを使用してください。

gcc -S program.c
6
Jeremy Ruten

あなたがLLVMアセンブリを探しているなら:

llvm-gcc -emit-llvm -S hello.c
6
mcandre

から: http://www.delorie.com/djgpp/v2faq/faq8_20.html

gcc -c -g -Wa、-a、-ad [その他のGCCオプション] foo.c> foo.lst

phirePhlyの答えに代わるものとして、または皆が言ったように単に-Sを使用する。

4
Anonymous

Output of these commnads

これはあなたのウィンドウズ上の任意のCプログラムのアセンブリコードを見る/印刷するためのステップです。

console/terminal/commandプロンプト:

  1. コードブロックなどのCコードエディタでCプログラムを作成し、拡張子.cを付けて保存します。

  2. コンパイルして実行します。

  3. 正常に実行されたら、gccコンパイラをインストールしたフォルダに移動して、

    '.c'ファイルの '.s'ファイルを取得する次のコマンド

    C:\ gcc> gcc -S Cファイルの完全パスENTER

    コマンド例(私の場合のように)

    C:\ gcc> gcc -S D:\ Aa_C_Certified\alternate_letters.c

    元の '.c'ファイルの '.s'ファイルを出力します

4。その後、次のコマンドを入力してください。

C;\gcc> cpp filename.s ENTER

コマンド例(私の場合のように)

C;\gcc> cpp alternate_letters.s

これはあなたのCプログラムのアセンブリ言語コード全体を印刷/出力します。

2

-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はボーナスであり、containsは望ましいprepossessedファイルです:

    # 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の下の見苦しい一時ファイルの代わりに使用されている明示的なファイルを実際に示しているため、前処理/コンパイル/アセンブリ手順を含む、何が起こっているかを正確に把握するのは簡単です。

/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でテスト済み。

オプションとして "-S"を使用してください。ターミナルにアセンブリ出力を表示します。

1
Pizearke

最近私はプログラム内の各機能のアセンブリを知りたいと思いました
これが私のやり方です。

$ 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
1
Abhishek D K

これがgccを使ったCの解決策です。

gcc -S program.c && gcc program.c -o output
  1. ここで、最初の部分はプログラムのアセンブリ出力をProgramと同じファイル名で保存しますが、拡張子。sを変更したもので、通常のテキストファイルとして開くことができます。

  2. ここでの2番目の部分は、実際の使用法に合わせてプログラムをコンパイルし、指定されたファイル名でプログラムの実行可能ファイルを生成します。

上記で使用されているprogram.cは、プログラムの名前と出力です。生成したい実行ファイルの名前です。

ところでStackOverFlowの私の最初の投稿です: - }

0
Himanshu Pal