Why use ebp in function prolog / epilogue?

Some time ago I experimented with writing a subroutine assembly and associating it with C programs, and I found that I could just skip the standard C-call prolog prolog

push ebp mov ebp, esp (sub esp, 4 ... mov esp, ebp) pop ebp 

just skip it all and hit esp only, like

  mov eax, [esp+4] ;; take argument mov [esp-4], eax ;; use some local variable storage 

It seems to work pretty well. Why is this ebp being used - maybe addressing via ebp faster or what?

+6
optimization c assembly x86
Mar 27 '13 at 9:34
source share
3 answers

There is no need to use a stack frame, but there are certain advantages:

First, if every function uses the same process, we can use this knowledge to easily determine the call sequence (call stack) by changing the process. We know that after the call command, the ESP points to the return address and the first thing the call function will call is push current EBP , and then copy the ESP to the EBP . So, at any time, we can look at the data indicated by the EBP , which will be the previous EBP , and that EBP+4 will be the return address of the last function call. Therefore, we can print the call stack (suppose 32 bits) using something like (sorry 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); } 

Then the entire sequence of calls (well, their return address) to this point will be printed.

Also, since EBP does not change unless you explicitly update it (as opposed to ESP , which changes when you push / pop ), it is usually easier to refer to the data on the stack relative to EBP and not relative to ESP , since with the latter you must know any push / pop statements that might be called between the start of the function and the link.

As mentioned above, you should avoid using stack addresses below ESP , since any call you make to other functions will most likely overwrite data at these addresses. Instead, you should reserve a stack space for your function to use as normal:

 sub esp, [number of bytes to reserve] 

After that, the stack area between the initial ESP and ESP - [number of bytes reserved] safe to use. Before exiting your function, you must free the reserved stack space using the match:

 add esp, [number of bytes reserved] 
+9
Mar 27 '13 at 9:58
source share

Using EBP very useful when debugging code, as it allows debuggers to move through the stacks in the call chain.

It creates its own list associated with the frame pointer for each of the calling functions. From EBP for a procedure, you can restore the entire call stack for a function.

See http://en.wikibooks.org/wiki/X86_Disassembly/Functions_and_Stack_Frames
And in particular, the page to which it refers covers your question: http://blogs.msdn.com/b/larryosterman/archive/2007/03/12/fpo.aspx

+9
Mar 27 '13 at 9:47
source share

It works. However, as soon as you get an interrupt, the processor will push all the registers and flags onto the stack, overwriting your value. There is a stack for some reason, use it ...

+4
Mar 27 '13 at 9:35
source share



All Articles