There's no requirement to use a stack frame, but there are certainly some advantages:
Firstly, if every function has uses this same process, we can use this knowledge to easily determine a sequence of calls (the call stack) by reversing the process. We know that after a call
instruction, ESP
points to the return address, and that the first thing the called function will do is push
the current EBP
and then copy ESP
into EBP
. So, at any point we can look at the data pointed to by EBP
which will be the previous EBP
and that EBP+4
will be the return address of the last function call. We can therefore print the call stack (assuming 32bit) using something like (excuse the rusty C++):
void LogStack(DWORD ebp)
{
DWORD prevEBP = *((DWORD*)ebp);
DWORD retAddr = *((DWORD*)(ebp+4));
if (retAddr == 0) return;
HMODULE module;
GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, (const char*)retAddr, &module);
char* fileName = new char[256];
fileName[255] = 0;
GetModuleFileNameA(module, fileName, 255);
printf("0x%08x: %s\n", retAddr, fileName);
delete [] fileName;
if (prevEBP != 0) LogStack(prevEBP);
}
This will then print out the entire sequence of calls (well, their return addresses) up until that point.
Furthermore, since EBP
doesn't change unless you explicitly update it (unlike ESP
, which changes when you push
/pop
), it's usually easier to reference data on the stack relative to EBP
, rather than relative to ESP
, since with the latter, you have to be aware of any push
/pop
instructions that might have been called between the start of the function and the reference.
As others have mentioned, you should avoid using stack addresses below ESP
as any call
s you make to other functions are likely to overwrite the data at these addresses. You should instead reserve space on the stack for use by your function by the usual:
sub esp, [number of bytes to reserve]
After this, the region of the stack between the initial ESP
and ESP - [number of bytes reserved]
is safe to use.
Before exiting your function you must release the reserved stack space using a matching:
add esp, [number of bytes reserved]