Cソースファイルで GCC を使用して、ニーモニックバージョンのマシンコードをダンプして、コードが何にコンパイルされているかを確認する方法を知りたいと思いました。 Javaでこれを行うことができますが、GCCでの方法を見つけることができませんでした。
AssemblyでCメソッドを書き直そうとしていますが、GCCがそれをどのように行うかを見るのは大きな助けになるでしょう。
デバッグシンボルを使用してコンパイルする場合は、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
これらの答えに加えたいのは、gccに-fverbose-asm
フラグを指定すると、gccが発行するアセンブラーが読みやすくなるということです。
-S(注:大文字のS)スイッチをGCCに使用すると、.s拡張子を持つファイルにアセンブリコードが出力されます。たとえば、次のコマンド:
gcc -O2 -S foo.c
生成されたアセンブリコードをファイルfoo.sに残します。
http://www.delorie.com/djgpp/v2faq/faq8_20.html から直接リッピング(ただし、誤った-c
を削除)
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
godbolt は非常に便利なツールです。リストにはC++コンパイラしかありませんが、-x c
フラグを使用してコードをCとして扱うことができます。その後、コードのアセンブリリストを並べて生成します。また、Colourise
オプションを使用して色付きバーを生成し、生成されたアセンブリにどのソースコードがマップされているかを視覚的に示すことができます。たとえば、次のコード:
#include <stdio.h>
void func()
{
printf( "hello world\n" ) ;
}
次のコマンドラインを使用します。
-x c -std=c99 -O3
Colourise
は次を生成します。
gcc -S -fverbose-asm -O source.c
を試してから、生成されたsource.s
アセンブラーファイルを調べましたか?
生成されたアセンブラコードはsource.s
に入ります(-o
assembler-filenameでオーバーライドできます); -fverbose-asm
オプションは、生成されたアセンブラコードを「説明する」アセンブラコメントを発行するようコンパイラに要求します。 -O
オプションは、コンパイラにビットを最適化するように要求します(-O2
または-O3
でさらに最適化できます)。
gcc
が何をしているのかを理解したい場合は、-fdump-tree-all
を渡してみてください。ただし、注意してください。数百のダンプファイルを取得します。
ところで、GCCは plugins または MELT で拡張可能です(GCCを拡張するための高レベルのドメイン固有言語。2017年に廃止しました)
これには、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アセンブラダンプの。
-S(注:大文字のS)スイッチをGCCに使用すると、.s拡張子を持つファイルにアセンブリコードが出力されます。たとえば、次のコマンド:
gcc -O2 -S -c foo.c
私はgccにショットを与えていませんが、g ++の場合。以下のコマンドは私のために機能します。デバッグビルドの場合は-g、ソースコードを使用してリストする場合は-Wa、-adhlnがアセンブラーに渡されます
g ++ -g -Wa、-adhln src.cpp