ret,retn,retf - 如何使用它们

时间:2009-09-08 23:40:07

标签: assembly x86

我有以下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,意思是返回,返回附近和返回远。它们允许一个可选的参数nBytes,我想这是从定义的变量中弹出的字节数。什么时候应该使用retn或retf而不是ret?如何计算可选参数nBytes?

3 个答案:

答案 0 :(得分:60)

实际上只有两种不同的回报,retn(接近return)和retf(far return)。当你只使用ret时,汇编器或编译器足够聪明,可以选择哪一个是必需的。 near return是在现有代码段内的跳转,far return是跳转到不同的代码段。在Windows上,您只有一个代码段,因此ret应该只是retn的助记符。当分段记忆模型很常见时,单独的retn和retf指令是旧时代的回归。几乎所有今天运行的32位x86系统都使用扁平的,而不是分段的内存模型。

Ret没有参数弹出堆栈的返回地址并跳转到它。一些调用约定(如__stdcall)指定被调用函数清除堆栈。在这种情况下,他们调用ret的字节数来从堆栈中弹出这些参数。 16个字节是winmain函数的参数。

答案 1 :(得分:27)

在助记符N中,N是堆栈上参数的大小。在这种情况下,对于4个DWORD,它是4 * 4 = 16(10h) 但这仅适用于被调用者负责堆栈清理时调用约定。在cdecl约定的情况下,ret应该没有任何数字,因为调用者负责堆栈清理。

答案 2 :(得分:22)

实际上有两种类型: retn retf 。第三个 ret 由汇编程序编码为前两个之一。

不同之处在于 retn (返回附近)将仅弹出指令指针(IP)。虽然 retf (返回远)将弹出指令指针(IP)和代码段(CS)。