web-dev-qa-db-ja.com

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

Cソースファイルで GCC を使用して、ニーモニックバージョンのマシンコードをダンプして、コードが何にコンパイルされているかを確認する方法を知りたいと思いました。 Javaでこれを行うことができますが、GCCでの方法を見つけることができませんでした。

AssemblyでCメソッドを書き直そうとしていますが、GCCがそれをどのように行うかを見るのは大きな助けになるでしょう。

228
James

デバッグシンボルを使用してコンパイルする場合は、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:AT&Tの代わりにGAS/binutils MASMのような.intel_syntax noprefix構文を使用します
  • -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
309

これらの答えに加えたいのは、gccに-fverbose-asmフラグを指定すると、gccが発行するアセンブラーが読みやすくなるということです。

93
kmm

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

gcc -O2 -S foo.c

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

http://www.delorie.com/djgpp/v2faq/faq8_20.html から直接リッピング(ただし、誤った-cを削除)

72
Andrew Keeton

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

gcc -S -masm=att code.c

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

gcc -S -masm=intel code.c

(どちらもcode.cのダンプをさまざまな構文に、それぞれファイルcode.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
48
amaterasu

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

#include <stdio.h>

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

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

-x c -std=c99 -O3

Colouriseは次を生成します。

enter image description here

34
Shafik Yaghmour

gcc -S -fverbose-asm -O source.cを試してから、生成されたsource.sアセンブラーファイルを調べましたか?

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

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

ところで、GCCは plugins または MELT で拡張可能です(GCCを拡張するための高レベルのドメイン固有言語。2017年に廃止しました)

21

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

この抜粋は http://sources.redhat.com/gdb/current/onlinedocs/gdb_9.html#SEC64


Intel x86のソース+アセンブリの混合を示す例を次に示します。

(gdb)disas/m main 
 main関数のアセンブラーコードのダンプ:
 5 {
 0x08048330:Push%ebp 
 0x08048331:mov %esp、%ebp 
 0x08048333:sub $ 0x8、%esp 
 0x08048336:および$ 0xfffffff0、%esp 
 0x08048339:sub $ 0x10、%esp 
 
 6 printf( "Hello。\ n"); 
 0x0804833c:movl $ 0x8048440、(%esp)
 0x08048343:call 0x8048284 
 
 7 return 0; 
 8} 
 0x08048348:mov $ 0x0、%eax 
 0x0804834d:leave 
 0x0804834e:ret 
 
 Endアセンブラダンプの。
19
Vishal Sagar

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

gcc -O2 -S -c foo.c

13
codymanix

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

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

4
DAG