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

dev*_*ium 33 x86 assembly

我有以下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
Run Code Online (Sandbox Code Playgroud)

从我读到的,你有3种类型的返回指令:ret,retn和retf,意思是返回,返回附近和返回远.它们允许一个可选的参数nBytes,我想这是从定义的变量中弹出的字节数.什么时候应该使用retn或retf而不是ret?如何计算可选参数nBytes?

Mic*_*ael 60

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

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


Max*_*Max 28

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

  • 是。这是推送参数的数量。最后通过mov esp,ebp命令弹出本地 (2认同)

Azi*_*ziz 24

它实际上有两种类型:retnretf.第三个ret由汇编程序编码为前两个中的一个.

不同之处在于retn(返回附近)将仅弹出指令指针(IP).而retf(返回far)将弹出指令指针(IP)和代码段(CS).