Question

In an article about the _cdecl calling convention, the writer mentioned:

Release local storage When the function allocates local, temporary space, it does so by decrementing from the stack point the amount of space needed, and this process must be reversed to reclaim that space. It's usually done by adding to the stack pointer the same amount which was subtracted previously, though a series of POP instructions could achieve the same thing.

My question is: could I simply set ESP to the current EBP value instead of "adding to the stack pointer the same amount which was subtracted" or a "series of POP instructions"?

Like:

mov esp, ebp

Seems like a better way to me, because if I later change the number of local variables of this function, I won't have to bother about incrementing the value afterwards.

Was it helpful?

Solution

Actually, that's exactly what the leave instruction does, and it was introduced to support high-level languages. However, it's not used very often; most compilers just do explicit mov esp, ebp; pop ebp sequence. See also this question.

However, sometimes you can do the "omit frame pointer" optimization. This frees up EBP to be used as a general-purpose register, but you (or the compiler) then have to track the ESP changes during the whole function and use possibly changing offsets to address local variables or incoming arguments. If you do that, you'll have to use pops or explicit add to restore ESP to its original value before returning.

Note that the above concerns the whole function (i.e. prolog/epilog); when you need to call a specific __cdecl function in the middle of the function, you cannot just restore ESP to the EBP value, because that value is only valid at the very beginning of the function, before any space is allocated for local variables. There are two approaches here:

1) push arguments, restore ESP after the call:

push offset msg
call _printf
pop ecx ; clobbers ECX but shorter than add esp, 4

2) move arguments to reserved stack slots; you don't need to restore ESP in that case:

mov dword ptr [esp+0], offset msg
call _printf
; no need to change ESP

If you choose the second option, you'll need to make sure that you don't store any local variables in those slots. Also, such mov instructions are usually quite longer than pushes, so you might need to consider that if the code size is a concern.

OTHER TIPS

Technically this would be an abuse of stack frames, which are there to catch errors arising from stack imbalance, but it would be perfectly legal.

There are a few things to note though, if you have very limited stack space, due to a large alloc or an embedded device, its worth while to clean up the stack after every call. It also makes debugging a bit easier, because then you know something is using the wrong amount of args.

Also if anyone is going to maintain your code, they will find it very confusing.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top