tags:

views:

2086

answers:

3

I have the following asm code:

; 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

From what I read, you have 3 types of return instruction: ret, retn and retf, meaning return, return near and return far. They allow an optional argument nBytes, that I guess it's the number of bytes to pop, from the defined variables. When should I use retn or retf instead of ret? How can I calculate the optional parameter, nBytes?

+5  A: 

There are actually only two different returns, retn and retf. When you just use ret, the assembler or compiler is smart enough to pick which one is necessary. A near return is a jump to within the existing code segment, a far return is a jump to a different code segment. On Windows you only have a single code segment, and thus ret should just be a mnemonic for retn. Separate retn and retf instructions are a throwback to older days when segmented memory models were common. Pretty much all 32-bit x86 systems running today uses a flat, not segmented, memory model.

Ret with no argument pops the return address off of the stack and jumps to it. Some calling conventions (like __stdcall) specify that the callee function cleans up the stack. In this case, they call ret with number of bytes to pop those parameters off of the stack. The 16 bytes are the parameters to the winmain function.

Michael
Sorry, I didn't get this last part. When using retn <something> I should be clearing what? Those 2 variables + the ebp(4 bytes)? As you say that makes 8 + 4 = 12, but the code shows 16. What are those 4 bytes left?
devoured elysium
Sorry, forget the calling convention was __stdcall. I'll update my answer.
Michael
If you substitute the function epilog with ret 0ch, then the content of ebp will be incorrect in the calling function.
Max
+3  A: 

It's actually two types: retn and retf. The third one ret is coded by the assembler into one of the first two.

The difference is that retn (return near) will pop the instruction pointer (IP) only. While the retf (return far) will pop both the instruction pointer (IP) and the code segment (CS).

Aziz
+3  A: 

In the mnemonic ret N, N is the size of parameters on the stack. In this case it is 4 * 4 = 16 (10h) for 4 DWORDs.
But this only applies to calling conventions when the callee is responsible for stack cleanup. In case of cdecl convention the ret should be without any numbers, as the caller is responsible for stack cleanup.

Max
Ah so the N in ret N refers to the number of pushed arguments passed by the caller, and not the local variables as I thought. Is that it?
devoured elysium
Yes. It's the number of pushed arguments. Locals are poped by mov esp, ebp command at the end
Max