次の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を計算するにはどうすればよいですか?
ニーモニックret Nでは、Nはスタック上のパラメーターのサイズです。この場合、4 DWORDの場合は4 * 4 = 16(10h)です。
ただし、これは、呼び出し先がスタックのクリーンアップを担当する場合の呼び出し規則にのみ適用されます。 cdecl規約の場合、呼び出し元がスタックのクリーンアップを担当するため、retには数字を含めないでください。
実際には、retn(リターンに近い)とretf(ファーリターン)の2つの異なるリターンしかありません。 retを使用するだけの場合、アセンブラーまたはコンパイラーはどちらが必要かを選択するのに十分賢いです。近いリターンは既存のコードセグメント内へのジャンプであり、遠いリターンは別のコードセグメントへのジャンプです。 Windowsでは、コードセグメントは1つしかないため、retはretnのニーモニックである必要があります。 retn命令とretf命令を別々にすると、セグメント化されたメモリモデルが一般的だった昔の時代に戻ります。現在実行されているほとんどすべての32ビットx86システムは、セグメント化されていないフラットなメモリモデルを使用しています。
引数なしのRetは、スタックから戻りアドレスをポップし、そこにジャンプします。一部の呼び出し規約(__stdcallなど)は、呼び出し先関数がスタックをクリーンアップすることを指定します。この場合、これらのパラメーターをスタックからポップするために、バイト数でretを呼び出します。 16バイトは、winmain関数のパラメーターです。
実際には、2つのタイプ:retn
およびretf
。 3番目のret
は、アセンブラによって最初の2つのいずれかにコーディングされます。
違いは、retn
(近くに戻る)が命令ポインタ(IP)のみをポップすることです。 retf
(return far)は、命令ポインター(IP)とコードセグメント(CS)の両方をポップします。