我有以下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?
答案 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)。