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 ?

Original source

Related problems