2009-09-08 1232 views
31

我有以下的彙編代碼:RET,RETN,RETF - 如何使用它們

; int __stdcall wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nShowCmd) 
[email protected] 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?

回答

23

在助記符N中,N是棧上參數的大小。在這種情況下,4個DWORD是4 * 4 = 16(10h)。
但是,這隻適用於被調用者負責堆棧清理時調用約定。在cdecl約定的情況下,ret應該沒有任何數字,因爲調用者負責堆棧清理。

+0

啊,所以ret N中的N表示調用者傳遞的推送參數的數量,而不是我認爲的局部變量。是嗎? – 2009-09-09 00:12:31

+1

是的。這是推動參數的數量。當地人在最後通過mov esp,ebp命令行進 – Max 2009-09-09 00:22:41

50

實際上只有兩個不同的回報,retn(近迴歸)和retf(遠迴歸)。當你使用ret時,彙編器或編譯器足夠聰明,可以選擇哪一個是必要的。近似返回是跳轉到現有代碼段內,遠遠返回是跳轉到不同代碼段。在Windows上,您只有一個代碼段,因此ret應該只是retn的助記符。當分段存儲器模型很常見時,單獨的retn和retf指令是舊式日期的倒退。幾乎所有現在運行的32位x86系統都使用平坦的,不分段的內存模型。

沒有參數的Ret彈出堆棧的返回地址並跳轉到它。一些調用約定(如__stdcall)指定被調用函數清理堆棧。在這種情況下,他們調用ret以字節數從堆棧中彈出這些參數。這16個字節是winmain函數的參數。

+0

對不起,我沒有得到這最後一部分。當使用retn 我應該清除什麼?那2個變量+ ebp(4字節)?正如你所說的那樣,使8 + 4 = 12,但代碼顯示16.這4個字節剩下的是什麼? – 2009-09-09 00:01:10

+0

對不起,忘記調用約定是__stdcall。我會更新我的答案。 – Michael 2009-09-09 00:02:14

+0

如果用ret 0ch代替函數epilog,那麼調用函數中ebp的內容將不正確。 – Max 2009-09-09 00:02:23

20

它實際上是兩種類型:retnretf。第三個ret由彙編器編碼爲前兩個之一。

區別在於retn(return near)只會彈出指令指針(IP)。雖然(返回的遠程)會彈出指令指針(IP)和代碼段(CS)。

相關問題