Programming
c assembly x86 stack-frame stack-pointer
Updated Tue, 02 Aug 2022 01:50:00 GMT

What is exactly the base pointer and stack pointer? To what do they point?


Using this example coming from wikipedia, in which DrawSquare() calls DrawLine(),

alt text

(Note that this diagram has high addresses at the bottom and low addresses at the top.)

Could anyone explain me what ebp and esp are in this context?

From what I see, I'd say the stack pointer points always to the top of the stack, and the base pointer to the beginning of the the current function? Or what?


edit: I mean this in the context of windows programs

edit2: And how does eip work, too?

edit3: I have the following code from MSVC++:

var_C= dword ptr -0Ch
var_8= dword ptr -8
var_4= dword ptr -4
hInstance= dword ptr  8
hPrevInstance= dword ptr  0Ch
lpCmdLine= dword ptr  10h
nShowCmd= dword ptr  14h

All of them seem to be dwords, thus taking 4 bytes each. So I can see there is a gap from hInstance to var_4 of 4 bytes. What are they? I assume it is the return address, as can be seen in wikipedia's picture?


(editor's note: removed a long quote from Michael's answer, which doesn't belong in the question, but a followup question was edited in):

This is because the flow of the function call is:

* Push parameters (hInstance, etc.)
* Call function, which pushes return address
* Push ebp
* Allocate space for locals

My question (last, i hope!) now is, what is exactly what happens from the instant I pop the arguments of the function i want to call up to the end of the prolog? I want to know how the ebp, esp evolve during those moments(I already understood how the prolog works, I just want to know what is happening after i pushed the arguments on the stack and before the prolog).




Solution

esp is as you say it is, the top of the stack.

ebp is usually set to esp at the start of the function. Function parameters and local variables are accessed by adding and subtracting, respectively, a constant offset from ebp. All x86 calling conventions define ebp as being preserved across function calls. ebp itself actually points to the previous frame's base pointer, which enables stack walking in a debugger and viewing other frames local variables to work.

Most function prologs look something like:

push ebp      ; Preserve current frame pointer
mov ebp, esp  ; Create new frame pointer pointing to current stack top
sub esp, 20   ; allocate 20 bytes worth of locals on stack.

Then later in the function you may have code like (presuming both local variables are 4 bytes)

mov [ebp-4], eax    ; Store eax in first local
mov ebx, [ebp - 8]  ; Load ebx from second local

FPO or frame pointer omission optimization which you can enable will actually eliminate this and use ebp as another register and access locals directly off of esp, but this makes debugging a bit more difficult since the debugger can no longer directly access the stack frames of earlier function calls.

EDIT:

For your updated question, the missing two entries in the stack are:

var_C = dword ptr -0Ch
var_8 = dword ptr -8
var_4 = dword ptr -4
*savedFramePointer = dword ptr 0*
*return address = dword ptr 4*
hInstance = dword ptr  8h
PrevInstance = dword ptr  0C
hlpCmdLine = dword ptr  10h
nShowCmd = dword ptr  14h

This is because the flow of the function call is:

  • Push parameters (hInstance, etc.)
  • Call function, which pushes return address
  • Push ebp
  • Allocate space for locals




Comments (5)

  • +1 – Thanks for the explanation! But I am now kinda confused. Let's assume I call a function and I am in the first line of its prolog, still without having executed a single line from it. At that point, what is ebp's value? Does the stack have anything at that point besides the pushed arguments? Thanks! — Sep 09, 2009 at 12:33  
  • +3 – EBP is not magically changed, so until you've established a new EBP for your function you'll still have the callers value. And besides arguments, the stack will also hold the old EIP (return address) — Sep 09, 2009 at 13:34  
  • +3 – Nice answer. Though it cannot be complete without mentioning what's in the epilog: "leave" and "ret" instructions. — Jul 04, 2013 at 07:01  
  • +2 – I think this image will help clarify some things on what the flow is. Also keep in mind the stack grows downwards. ocw.cs.pub.ro/courses/_media/so/laboratoare/call_stack.png — Oct 05, 2013 at 15:06  
  • +0 – Is it me, or all the minus signs are missing from the code snippet above? — Jan 20, 2017 at 04:09  


External Links

External links referenced by this document: