EBP was designed to provide a “Base Pointer” for the current function so that all parameters and local variables would be at a fixed offset from the base pointer even as the stack pointer moved with push and pop instructions. This made it easier to generate assembly and was very beneficial for debugging because it made it easier to trace backwards up the stack and see what path of function calls led to the current instruction. However, due to compiler improvements EBP is used less often so back tracing up the stack is more difficult.
Function arguments and local variables are stored on the stack. Traditionally, two registers stored stack location information. The first is the stack pointer (ESP) which stores the current top of the stack. Function arguments and local variables are stored at an offset from where the stack is when the function starts. As the stack grows and shrinks during a function the offset of local variables and function parameters relative to ESP changes. To simplify things Intel uses a base pointer (sometimes called a frame pointer) that is stored in EBP. EBP is a pointer to the top of the stack when the function is first called.
By using a base pointer the return address will always be at ebp+4, the first parameter will always be at ebp+8, and the first local variable will always be at ebp-4. Even as the stack size grows and shrinks those offsets do not change. This also makes it easier for disassemblers because it’s easy to track the parameters and local variables being access throughout the function because their addresses never change.
At ebp is a pointer to ebp for the previous frame (this is why push ebp; mov ebp, esp is such a common way to start a function). This effectively creates a linked list of base pointers. This linked list makes it very easy to trace backwards up the stack. For example if foo() calls bar() and bar() calls baz() and you’re debugging baz() you can easily find the parameters and local variables for foo() and bar().
At some point compiler writers realized that you could generate functions that don’t need to use EBP without any memory or performance penalties. The compiler can simply always track the locations of values relative to ESP even as ESP changes throughout the functions. This is difficult if generating assembly by hand, but is relatively straightforward for compilers. Compilers still sometimes use EBP, and functions that use EBP to maintain a frame pointer are called “frame based.” Functions that are not frame based can use EBP as another general purpose register and use it for calculations just like any other register.
There are a few implications of non-frame based functions that you should understand. The first is that automatically tracing backward up the stack may not work. This makes it harder to trace backward through code. The second implication is that accesses to local variables and function parameters will look different. For example consider the following code snippet (which hasn’t been analyzed by IDA Pro)
mov eax, [esp+4] pop ecx add eax, ecx mov [esp], eax
At first glance, you might conclude that the first line reads a local variable (stored at esp+4) and that the last line writes a different local variable (stored at esp). However, that’s incorrect because esp changes in between. Therefore the first line and the last line access the same local variable. If you’re looking at assembly listings created by OllyDbg or Windbg, you have to pay attention to changes to esp in order to track local variable and function parameter accesses.
If you’re looking at a listing in IDA Pro, it will actually perform the tracking for you as shown in the below listing.
mov eax, [esp+10+var_4] pop ecx add eax, ecx mov [esp+c+var_4], eax
The first line and the last line both access the first local variable and IDA Pro has labeled both accesses var_4. The values c and 10 represent the difference between the value of the stack pointer at the function start and at the current instruction. In Chapter 15 of our book we discuss an anti-disassembly technique that disrupts IDA Pro’s stack analysis. Now that you understand how EBP works you can understand IDA Pro’s stack analysis and know what to do when IDA Pro’s analysis fails you.