web-dev-qa-db-ja.com

ret、retn、retf-使用方法

次のasmコードがあります。

; int __stdcall wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nShowCmd)
_wWinMain@16 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、return、return near、far far returnを意味します。これらは、オプションの引数nBytesを許可します。これは、定義された変数から、ポップするバイト数だと思います。 retの代わりにretnまたはretfを使用する必要があるのはいつですか?オプションのパラメーターnBytesを計算するにはどうすればよいですか?

33

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

28
Max

実際には、retn(リターンに近い)とretf(ファーリターン)の2つの異なるリターンしかありません。 retを使用するだけの場合、アセンブラーまたはコンパイラーはどちらが必要かを選択するのに十分賢いです。近いリターンは既存のコードセグメント内へのジャンプであり、遠いリターンは別のコードセグメントへのジャンプです。 Windowsでは、コードセグメントは1つしかないため、retはretnのニーモニックである必要があります。 retn命令とretf命令を別々にすると、セグメント化されたメモリモデルが一般的だった昔の時代に戻ります。現在実行されているほとんどすべての32ビットx86システムは、セグメント化されていないフラットなメモリモデルを使用しています。

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

60
Michael

実際には、2つのタイプ:retnおよびretf。 3番目のretは、アセンブラによって最初の2つのいずれかにコーディングされます。

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

23
Aziz