2010-11-19 9 views
8

いくつかのアセンブリコードを理解しようとしていて、数行を除いてそのほとんどを処理することができました。私は内部で起こっていることのほとんどを理解することができますが、コードの始めと終わりに何が起きているのか(そしてなぜそれが)起こっているのかを完全に理解することはできません。誰かがこれにいくつかの光を当てることができますか?一部のアセンブリステートメントの目的の理解

int main() { 
    int a, b; 
    a = 12; 
    b = 20; 
    b = a + 123; 
    return 0; 
} 

逆アセンブルバージョン:

8048394:8d 4c 24 04   lea 0x4(%esp),%ecx    ; ?? 
8048398:83 e4 f0    and $0xfffffff0,%esp   ; ?? 
804839b:ff 71 fc    pushl -0x4(%ecx)     ; ?? 
804839e:55     push %ebp      ; Store the Base pointer 
804839f:89 e5    mov %esp,%ebp     ; Initialize the Base pointer with the stack pointer 
80483a1:51     push %ecx      ; ?? 
80483a2:83 ec 4c    sub $0x4c,%esp     ; ?? 
80483a5:c7 45 f8 0c 00 00 00 movl $0xc,-0x8(%ebp)    ; Move 12 into -0x8(%ebp) 
80483ac:c7 45 f4 14 00 00 00 movl $0x14,-0xc(%ebp)   ; Move 20 into -0xc(%ebp) 
80483b3:8b 45 f8    mov -0x8(%ebp),%eax    ; Move [email protected](%ebp) into eax 
80483b6:83 c0 7b    add $0x7b,%eax     ; Add 123 to [email protected] 
80483b9:89 45 f4    mov %eax,-0xc(%ebp)    ; Store the result into [email protected](%ebp) 
80483bc:b8 00 00 00 00  mov $0x0,%eax     ; Move 0 into eax 
80483c1:83 c4 10    add $0x10,%esp     ; ?? 
80483c4:59     pop %ecx      ; ?? 
80483c5:5d     pop %ebp      ; ?? 
80483c6:8d 61 fc    lea -0x4(%ecx),%esp    ; ?? 
+0

スタックのどこにあるのかを描画すると便利です。 –

+0

コメント内のオペコードの英語名を書くだけではあまり役に立ちません。それらをもっと「高いレベル」にしてみてください。そして、あなたが実際に解体から何かを学びたいなら、コンパイラのものではなく人間のコードを試してみてください。 – ruslik

+1

通常、最初と最後のものは一般的なスタック設定コードです。割当と整列など。 – zdav

答えて

26

スタックは下向きを成長します。 pushはスタックポインタ(esp)から減算し、popはespに加算します。あなたはこれをたくさん理解するためにそれを念頭に置いておく必要があります。

8048394:8d 4c 24 04   lea 0x4(%esp),%ecx    ; ?? 

リー=ロード実効アドレス

これはスタックに4バイトのあるもののアドレスが保存されます。これはスタック上の2番目のアイテムを意味する32ビット(4バイトワード)のx86コードです。これは関数のコード(この場合はmain)なので、スタックの先頭にある4バイトが戻りアドレスです。

8048398:83 e4 f0    and $0xfffffff0,%esp   ; ?? 

このコードは、スタックが16バイトにアライメントされていることを確認します。この操作の後、espはこの操作の前と同じかそれ以下になるので、スタックが大きくなり、すでにスタック上にあるものはすべて保護されます。これは時々mainで行われますが、機能が整列されていないスタックで呼び出された場合、実際には遅くなることがあります(16バイトはx86ではキャッシュライン幅ですが、4バイト整列はここでは本当に重要です)。 mainに整列されていないスタックがある場合、残りのプログラムも同様です。この-4率を有するので、これはリターンアドレスをバックアップする意味にECXは、スタックの前頂部からリターンアドレスの他方の側のものへのポインタとして、前にロードされたので

804839b:ff 71 fc    pushl -0x4(%ecx)     ; ?? 

現在の関数がスタックの先頭にプッシュバックされ、メインが正常に戻ることができるようにします。 (プッシュは魔法であり、同じ命令でRAM内の別の場所にロードしてから格納することができるようです)。

804839e:55     push %ebp      ; Store the Base pointer 
804839f:89 e5    mov %esp,%ebp     ; Initialize the Base pointer with the stack pointer 
80483a1:51     push %ecx      ; ?? 
80483a2:83 ec 4c    sub $0x4c,%esp     ; ?? 

これは、ほとんどの場合、標準機能のプロローグです(これまでのものはメイン用に特別でした)。これは、ローカル変数が存在するスタックフレーム(ebpとespの間の領域)を作成しています。 ebpがプッシュされるので、古いスタックフレームは(現在の関数の最後の)エピローグで復元することができます。

80483a5:c7 45 f8 0c 00 00 00 movl $0xc,-0x8(%ebp)    ; Move 12 into -0x8(%ebp) 
80483ac:c7 45 f4 14 00 00 00 movl $0x14,-0xc(%ebp)   ; Move 20 into -0xc(%ebp) 
80483b3:8b 45 f8    mov -0x8(%ebp),%eax    ; Move [email protected](%ebp) into eax 
80483b6:83 c0 7b    add $0x7b,%eax     ; Add 123 to [email protected] 
80483b9:89 45 f4    mov %eax,-0xc(%ebp)    ; Store the result into [email protected](%ebp) 

80483bc:b8 00 00 00 00  mov $0x0,%eax     ; Move 0 into eax 

eaxは、整数の戻り値が格納される場所です。これはmainから0を返すように設定しています。

80483c1:83 c4 10    add $0x10,%esp     ; ?? 
80483c4:59     pop %ecx      ; ?? 
80483c5:5d     pop %ebp      ; ?? 
80483c6:8d 61 fc    lea -0x4(%ecx),%esp    ; ?? 

これは機能のエピローグです。最初は奇妙なスタックアライメントコードがあるため、理解することは難しくなります。私は、スタックがなぜプロローグよりも少ない量で調整されているのかを考え出すのに少し苦労しています。

この特定のコードが最適化を使用してコンパイルされていないことは明らかです。たとえそれがあなたのmainにリストされている数学を行わなかったとしても、プログラムの最終結果は同じであることをコンパイラが見ることができるので、そこに多分存在しないでしょう。実際に何か(副作用や結果がある)をするプログラムでは、軽度に最適化されたコード(gccの-O1または-0s引数)を読みやすくすることがあります。

コンパイラによって生成されたアセンブリの読み込みは、main以外の関数の方がずっと簡単です。コードを理解するために読んでみたい場合は、結果を出すためにいくつかの引数を取る関数を書くか、グローバル変数で動作する関数を書いてください。そうすれば、よりよく理解できるようになります。

もう1つのことは、アセンブリファイルを逆アセンブルするのではなく、gccで生成することだけです。 -Sフラグは、これを生成するように指示しますが、他のファイルは生成しません。最後に.sという名前のアセンブリファイルを指定します。これは、逆アセンブルされたバージョンよりも読みやすくなります。

+0

お時間をありがとう。非常に詳細な説明。ちょうど私が探していたもの。 – Legend

+0

Q1:最初に4バイトを追加してからマイナスにする理由。なぜ 'lea(%esp)、%ecx'と' pushl(%ecx) 'だけではないのですか? Q2:この種のアラインメントを無効にするフラグはありますか( '-fno-align-functions'は機能しません)。 – Tony

6

わからない理由コンパイラは、すべてこのようなものを行いますが、ここで私が解読できるものです:

8048394:8d 4c 24 04   lea 0x4(%esp),%ecx    ; ecx := esp+4 
8048398:83 e4 f0    and $0xfffffff0,%esp   ; align the stack to 16 bytes 
804839b:ff 71 fc    pushl -0x4(%ecx)     ; push [ecx-4] ([esp]) 
80483a1:51     push %ecx      ; push ecx 
80483a2:83 ec 4c    sub $0x4c,%esp     ; allocate 19 dwords on stack 
80483c1:83 c4 10    add $0x10,%esp     ; deallocate 4 dwords from stack 
80483c4:59     pop %ecx      ; restore ecx 
80483c5:5d     pop %ebp      ; and ebp 
80483c6:8d 61 fc    lea -0x4(%ecx),%esp    ; esp := [ecx-4] 
+1

ありがとうございます。 – Legend

関連する問題