GCCを使用して読み取り可能なアセンブリを生成しますか?


256

CのソースファイルでGCCを使用して、ニーモニックバージョンのマシンコードをダンプし、コードのコンパイル先を確認する方法を考えていました。あなたはJavaでこれを行うことができますが、私はGCCで方法を見つけることができませんでした。

私はアセンブリでCメソッドを書き直そうとしていますが、GCCがそれをどのように行うかを確認すると、大きな助けになります。


25
「バイトコード」は通常、JVMや.NETのCLRなどのVMによって消費されるコードを意味することに注意してください。GCCの出力は、「マシンコード」、「マシン言語」、または「アセンブリ言語」と呼ばれます
Javier

2
godboltを使用して回答を追加しました。これは、さまざまなオプションがコード生成にどのように影響するかをすばやく試すための非常に強力なツールであるためです。
Shafik Yaghmour 2014



asm出力を人間が読めるようにする
Peter Cordes

回答:


335

デバッグシンボルを使用objdumpしてコンパイルする場合は、を使用して、より読みやすい逆アセンブリを生成できます。

>objdump --help
[...]
-S, --source             Intermix source code with disassembly
-l, --line-numbers       Include line numbers and filenames in output

objdump -drwC -Mintel いいです:

  • -r再配置のシンボル名を表示putsします(call以下の手順で確認できます)
  • -R ダイナミックリンクの再配置/シンボル名を示します(共有ライブラリで役立ちます)
  • -C C ++シンボル名をデマングルする
  • -w 「ワイド」モード:マシンコードのバイトを改行しない
  • -Mintel.intel_syntax noprefixAT&Tの代わりにGAS / binutils MASMのような構文を使用
  • -S:ソース行を逆アセンブリでインターリーブします。

あなたのようなものを置くことができalias disas="objdump -drwCS -Mintel"ます~/.bashrc


例:

> gcc -g -c test.c
> objdump -d -M intel -S test.o

test.o:     file format elf32-i386


Disassembly of section .text:

00000000 <main>:
#include <stdio.h>

int main(void)
{
   0:   55                      push   ebp
   1:   89 e5                   mov    ebp,esp
   3:   83 e4 f0                and    esp,0xfffffff0
   6:   83 ec 10                sub    esp,0x10
    puts("test");
   9:   c7 04 24 00 00 00 00    mov    DWORD PTR [esp],0x0
  10:   e8 fc ff ff ff          call   11 <main+0x11>

    return 0;
  15:   b8 00 00 00 00          mov    eax,0x0
}
  1a:   c9                      leave  
  1b:   c3                      ret

3
Intelの命令のみを取得するスイッチはありますか?
ジェームズ

3
これらはすべてIntelプロセッサで実行されるため、Intelの命令です:D。
-toto

12
@toto彼はAT&T構文ではなくIntel構文を意味すると思います
Amok

7
スイッチシーケンスを使用して、中間オブジェクトファイルを無視できます-Wa,-adhln -g to gcc。これは、アセンブラがガスであることを前提としており、常にそうであるとは限りません。
マークバトラー

8
@ジェームスはい、供給し-Mintelます。
fuz

106

GCCにフラグを付ける-fverbose-asmと、

生成されたアセンブリコードにコメント情報を追加して、読みやすくします。

[...]追加されたコメントは次のとおりです。

  • コンパイラのバージョンとコマンドラインオプションに関する情報
  • FILENAME:LINENUMBER:CONTENT OF LINEの形式の、アセンブリ命令に関連付けられたソースコード行
  • 高レベルの式がさまざまなアセンブリ命令のオペランドに対応するヒント。

しかし、その後、objdump- objdump -drwCS -Mintelに使用されていたすべてのスイッチが失われるので、どうすればverbosewith などを使用できobjdumpますか?それで-fverbose-asm、gccのように、asmコードでコメントを付けることができますか?
牧夫

1
@Herdsman:できません。余分なものは-fverbose-asm、出力のASM構文のコメントの形ではなく、中に何も余分を置くディレクティブにされる追加.oファイル。組み立て時にすべて破棄されます。逆アセンブリの代わりにコンパイラのasm出力を確認します。たとえば、godbolt.orgで、マウスオーバーを介してソース行と簡単に一致させ、対応するソース/ asm行の色を強調表示できます。 GCC / clangアセンブリの出力から「ノイズ」を取り除く方法は?
Peter Cordes

75

-S(注:大文字のS)スイッチをGCCに使用すると、アセンブリコードが拡張子.sのファイルに出力されます。たとえば、次のコマンド:

gcc -O2 -S foo.c

生成されたアセンブリコードをファイルfoo.sに残します。

http://www.delorie.com/djgpp/v2faq/faq8_20.htmlから直接取り込んだ(ただし、誤ったものを削除した-c


35
-cと-Sを混在させないでください。そのうちの1つだけを使用してください。この場合、おそらく使用される順序に応じて、一方が他方をオーバーライドします。
Adam Rosenfield、

4
@AdamRosenfield「-cと-Sを混在させるべきではない」についての参照はありますか?それが本当なら、著者に思い出させて、それを編集するべきです。
2014

5
@Tony:gcc.gnu.org/onlinedocs/gcc/Overall-Options.html#Overall-Optionsは、「あなたは使用することができます... 1 -cオプションの、-S、または-Eをgccが停止している場所を言うこと。 」
Nate Eldredge

1
すべての中間出力が必要な場合は、を使用しますgcc -march=native -O3 -save-temps。を使用-cして、リンクなどを試みなくても、オブジェクトファイルの作成を停止できます。
Peter Cordes

2
-save-temps興味深いのは、コードが生成したコードを1つに-Sまとめてダンプするので興味深いです。しかし -save-temps、現在のディレクトリにすべてをダンプしますが、これは面倒です。コードを検査するツールというよりは、GCCのデバッグオプションとして意図されているようです。
ステフェイン・グーリッホン

50

-Sx86ベースのシステムでGCCへのスイッチを使用すると、デフォルトでAT&T構文のダンプが生成されます。これは、-masm=attスイッチで次のように指定できます。

gcc -S -masm=att code.c

一方、Intel構文でダンプを生成する場合は-masm=intel、次のようにスイッチを使用できます。

gcc -S -masm=intel code.c

(両方ともcode.ccode.sそれぞれの構文、ファイルにダンプを生成します)

objdumpで同様の効果を生み出すには、--disassembler-options= intel/ attスイッチの例を使用します(構文の違いを示すコードダンプを使用)。

 $ objdump -d --disassembler-options=att code.c
 080483c4 <main>:
 80483c4:   8d 4c 24 04             lea    0x4(%esp),%ecx
 80483c8:   83 e4 f0                and    $0xfffffff0,%esp
 80483cb:   ff 71 fc                pushl  -0x4(%ecx)
 80483ce:   55                      push   %ebp
 80483cf:   89 e5                   mov    %esp,%ebp
 80483d1:   51                      push   %ecx
 80483d2:   83 ec 04                sub    $0x4,%esp
 80483d5:   c7 04 24 b0 84 04 08    movl   $0x80484b0,(%esp)
 80483dc:   e8 13 ff ff ff          call   80482f4 <puts@plt>
 80483e1:   b8 00 00 00 00          mov    $0x0,%eax
 80483e6:   83 c4 04                add    $0x4,%esp 
 80483e9:   59                      pop    %ecx
 80483ea:   5d                      pop    %ebp
 80483eb:   8d 61 fc                lea    -0x4(%ecx),%esp
 80483ee:   c3                      ret
 80483ef:   90                      nop

そして

$ objdump -d --disassembler-options=intel code.c
 080483c4 <main>:
 80483c4:   8d 4c 24 04             lea    ecx,[esp+0x4]
 80483c8:   83 e4 f0                and    esp,0xfffffff0
 80483cb:   ff 71 fc                push   DWORD PTR [ecx-0x4]
 80483ce:   55                      push   ebp
 80483cf:   89 e5                   mov    ebp,esp
 80483d1:   51                      push   ecx
 80483d2:   83 ec 04                sub    esp,0x4
 80483d5:   c7 04 24 b0 84 04 08    mov    DWORD PTR [esp],0x80484b0
 80483dc:   e8 13 ff ff ff          call   80482f4 <puts@plt>
 80483e1:   b8 00 00 00 00          mov    eax,0x0
 80483e6:   83 c4 04                add    esp,0x4
 80483e9:   59                      pop    ecx
 80483ea:   5d                      pop    ebp
 80483eb:   8d 61 fc                lea    esp,[ecx-0x4]
 80483ee:   c3                      ret    
 80483ef:   90                      nop

何が... gcc -S -masm=intel test.c私にとって正確に機能しなかったので、次のようなIntelとAT&Tの構文の雑種を手に入れました:のmov %rax, QWORD PTR -24[%rbp]代わりに:movq -24(%rbp), %rax
L̲̳o̲̳̳n̲̳̳g̲̳̳p̲̳o̲̳̳k̲̳̳e̲̳̳ 09/11/22

1
いいヒント。これは.o、ASMファイルの並列出力を実行するときにも機能することに注意してください。つまり、-Wa,-ahls -o yourfile.o yourfile.cpp>yourfile.asm
underscore_d

-Mオプションを使用できますが、それは同じですが--disassembler-options、はるかに短いです。たとえばobjdump -d -M intel a.out | less -N
Eric Wang

34

godboltは非常に便利なツールです。リストにはC ++コンパイラしかありませんが、-x cフラグを使用してコードをCとして扱うことができます。コードのアセンブリリストが並べColouriseて生成され、オプションを使用して生成できます。生成されたアセンブリにマップするソースコードを視覚的に示す色付きのバー。たとえば、次のコード:

#include <stdio.h>

void func()
{
  printf( "hello world\n" ) ;
}

次のコマンドラインを使用します。

-x c -std=c99 -O3

そしてColourise以下を生成します:

ここに画像の説明を入力してください


godboltフィルターがどのように機能するかを知っておくとよいでしょう:.LC0、.text、//、およびIntel。インテルは簡単です-masm=intelが、残りはどうですか?
Zボソン

ここで説明されていると思いますstackoverflow.com/a/38552509/2542702
Zボソン

godboltはCをサポートしています(Rust、D、Pascalなどの他の多くの言語とともに)。それはそれがでC ++コンパイラを使用することがまだ良いですが、非常に少数のCコンパイラがあることだけだ-x c
phuclv

23

あなたは試すでしgcc -S -fverbose-asm -O source.c生成に見て、その後source.sアセンブラファイル?

生成されたアセンブラコードが入りsource.sます(-o アセンブラファイル名でオーバーライドできます)。この-fverbose-asmオプションは、生成されたアセンブラコードを「説明する」アセンブラコメントを発行するようにコンパイラに要求します。この-Oオプションは、コンパイラーにビットを最適化するように要求します(-O2またはでさらに最適化できます-O3)。

gccが行われているのかを理解したい場合は、渡してみてください。-fdump-tree-allただし、注意が必要です。何百ものダンプファイルが取得されます。

ところで、GCCはプラグインまたはMELT(GCCを拡張するための高レベルのドメイン固有の言語です。私は2017年に放棄しました)を介して拡張可能です。


source.s多くの人がコンソールでのプリントアウトを期待するので、出力はになるだろうと多分言及します。
RubenLaguna

1
@ecerulm:-S -o-stdoutにダンプします。 -masm=intelNASM / YASM構文を使用する場合に役立ちます。(しかし、それqword ptr [mem]だけではなくを使用しているqwordため、NASM / YASMよりもIntel / MASMに似ています)。 gcc.godbolt.orgはダンプを整理するという素晴らしい仕事をします:オプションでコメントのみの行、未使用のラベル、アセンブラディレクティブを削除します。
Peter Cordes

2
言及を忘れた:「ソースに似ているが、すべてのソース行の後にストア/リロードのノイズがない」を探している場合-Ogは、さらに優れてい-O1ます。これは、「デバッグ用に最適化する」ことを意味し、ソースが言うことをすべて行う、トリッキーでわかりにくい最適化をあまり行わずにasmを作成します。それはgcc4.8から利用可能ですが、clang 3.7にはまだありません。IDKは、それに対して何を反対するか決定しました。
Peter Cordes

19

これには、objdumpのようにgdbを使用できます。

この抜粋は、http://sources.redhat.com/gdb/current/onlinedocs/gdb_9.html#SEC64から取得されます


以下は、Intel x86のソース+アセンブリの混合を示す例です。

  (gdb)disas / m main
関数mainのアセンブラコードのダンプ:
5 {
0x08048330:%ebpをプッシュ
0x08048331:mov%esp、%ebp
0x08048333:サブ$ 0x8、%esp
0x08048336:および$ 0xfffffff0、%esp
0x08048339:サブ$ 0x10、%esp

6 printf( "Hello。\ n");
0x0804833c:movl $ 0x8048440、(%esp)
0x08048343:0x8048284を呼び出します 

7は0を返します。
8}
0x08048348:mov $ 0x0、%eax
0x0804834d:残す
0x0804834e:ret

アセンブラーダンプの終わり。

1
アーカイブされたリンク:web.archive.org/web/20090412112833/http
vlad4378

GDBの逆アセンブラをIntel構文に切り替えるには、set disassembly-flavor intelコマンドを使用します。
ルスラン

13

-S(注:大文字のS)スイッチをGCCに使用すると、アセンブリコードが拡張子.sのファイルに出力されます。たとえば、次のコマンド:

gcc -O2 -S -c foo.c


4

私はgccにショットを与えていませんが、g ++の場合です。以下のコマンドは私にとってはうまくいきます。-gはデバッグビルド用で、-Wa、-adhlnはソースコードをリストするためにアセンブラに渡されます。

g ++ -g -Wa、-adhln src.cpp


gccでも動作します!-Wa、...は、アセンブラパーツのコマンドラインオプション用です(C / ++コンパイル後にgcc / g ++で実行)。内部的に起動します(Windowsではas.exe)。> as --help as command line as more help
Hartmut Schorrig

0

stdoutへのリスト出力を生成するには、gccまたはg ++のオプションとして-Wa、-adhlnを使用します。

-Wa、...は、アセンブラパーツのコマンドラインオプション用です(C / ++コンパイル後にgcc / g ++で実行)。これは、呼び出しとして内部的に(Windowsの場合as.exe)。見る

> --helpとして

コマンドラインとして、gcc内のアセンブラツールの詳細ヘルプを表示します

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.