why to use ebp in function prologue/epilogue?
assembly, c, optimization, x86
Solution
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]
Problem
Some time ago I was experimenting with writing assembly routines and linking it with C programs and I found that I just can skip standard C-call prologue epilogue ``` push ebp mov ebp, esp (sub esp, 4 ... mov esp, ebp) pop ebp ``` just skip it all and adress just by `esp`, like ``` mov eax, [esp+4] ;; take argument mov [esp-4], eax ;; use some local variable storage ``` It seem to work quite good. Why this ebp is used - is maybe addressing through `ebp` faster or what ?