2009-09-08 8 views
31

を使用するには:RET、RETN、RETF - 私は、次のasmコードを持っているか、彼らに

; int __stdcall wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nShowCmd) 
[email protected] proc near 

var_8= dword ptr -8 
var_4= dword ptr -4 
hInstance= dword ptr 8 
hPrevInstance= dword ptr 0Ch 
lpCmdLine= dword ptr 10h 
nShowCmd= dword ptr 14h 

push ebp 
mov  ebp, esp 
sub  esp, 8 
mov  [ebp+var_4], 5 
mov  eax, [ebp+var_4] 
add  eax, 1 
mov  [ebp+var_8], eax 
xor  eax, eax 
mov  esp, ebp 
pop  ebp 
retn 10h 

私が読んだものから、あなたはリターン命令の3種類があります:リターンを意味し、RET、RETNとRETFを、リターン近くに戻ります。彼らはオプションの引数nBytesを許可します。これは、定義された変数からポップするバイト数を推測します。 retの代わりにretnまたはretfを使用する必要があるのはいつですか?オプションのパラメータnBytesはどのようにして計算できますか?

答えて

23

ニーモニックret Nでは、Nはスタック上のパラメータのサイズです。この場合、4つのDWORDに対して4 * 4 = 16(10h)です。
これは、呼び出し先がスタックのクリーンアップを担当している場合にのみ呼び出し規約に適用されます。 cdecl規則の場合、呼び出し元がスタッククリーンアップを担当しているので、retは数字なしでなければなりません。

+0

ああ、ret NのNは、呼び出し元が渡したプッシュされた引数の数を指し、私が思ったようにローカル変数は参照しません。それですか? –

+1

はい。これはプッシュされた引数の数です。ローカルにはmov esp、最後にebpコマンドがポップされます – Max

50

実際には、retn(ニアリターン)とretf(farリターン)の2つの異なるリターンしかありません。あなたがちょうどretを使うとき、アセンブラかコンパイラはどちらが必要なのかを知るのに十分なほどスマートです。近いリターンは既存のコードセグメント内へのジャンプです。遠いリターンは別のコードセグメントへのジャンプです。 Windowsでは、1つのコードセグメントしか持たないため、retはretnのニーモニックでなければなりません。別々のretnおよびretf命令は、セグメント化されたメモリモデルが一般的であった古い年代への後戻りです。今日実行されているほとんどすべての32ビットx86システムでは、セグメント化されていないフラットなメモリモデルが使用されています。

引数を指定しないでリターンすると、スタックの戻りアドレスがポップされ、スタックにジャンプします。いくつかの呼び出し規約(__stdcallなど)では、呼び出し先関数がスタックをクリーンアップするように指定しています。この場合、スタックからそれらのパラメータをポップするために、バイト数でretを呼び出します。 16バイトはwinmain関数のパラメータです。 retnretf

+0

申し訳ありませんが、私はこの最後の部分を取得しませんでした。 retnを使用するとき私は何をクリアする必要がありますか?それらの2つの変数+ ebp(4バイト)?あなたが言うように、8 + 4 = 12となりますが、コードには16が表示されます。 –

+0

申し訳ありませんが、呼び出し規約は__stdcallでした。私は私の答えを更新します。 – Michael

+0

関数epilogをret 0chに置き換えた場合、ebpの内容は呼び出し関数で不正確になります。 – Max

20

これは、実際には2種類あります。 3番目のものretは、アセンブラによって最初の2つのうちの1つにコード化されます。

違いはretn(復帰近く)は命令ポインタ(IP)のみをポップすることです。 retf(return far)は、命令ポインタ(IP)とコードセグメント(CS)の両方をポップします。

関連する問題