1

I am having trouble grasping the answer in this stackoverflow thread. https://stackoverflow.com/a/1395646

In the middle of the answer it says Most function prologs look something like:...

As I understand the instructions in the mentioned answer --> The first instruction pushes ebp on to the stack. Then we move esp into ebp. And lastly we subract 20 from esp, making esp point 20 addresses down from where it was.

From the instructions above I visualize the stack as this.

high address
__________________________
|     (an address)       |    <-- ebp
..........................
..........................
|                        |    <-- esp points to an address 20 
|                        |        bytes lower
|                        |
|                        |
|                        |
|________________________|
low address

If this visualization is correct, how can you then push anything on the stack when you dont even have any reference to where the next local variable can be placed?

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
Mr Krisey
  • 109
  • 2
  • 10

1 Answers1

4

The 'low address' is where the stackpointer ESP is. Pushing anything to the stack stores it beneath this address.

Storing a local variable would use a EBP relative addressing mode with a negative offset.

In your example there's a 20 byte difference between EBP and ESP.
In the absense of any pushes, MOVing to where ESPpoints fills the lowest 4 bytes of that 20-byte area. On the contrary, the first PUSH will store beneath that 20-byte area. Only the PUSH instruction will lower the stackpointer beforehand. MOV uses ESP as is.

The following store to the same address in memory:

mov [ebp-20], eax
mov [esp], eax

Now, if we push some new datum to the stack, then ESP changes but EBP remains, and so the following is true:

push ebx              <<< The first push
mov  eax, [ebp-20]    <<< Still at -20
mov  edx, [esp+4]     <<< Now at +4

EAXand EDX are equal to each other.

Sep Roland
  • 33,889
  • 7
  • 43
  • 76
  • So, moving a value from eax to where esp points to will be stored beneath where esp is pointing to in the illustration I made? Wouldnt that leave the 20 bytes between ebp and esp un touched? – Mr Krisey Feb 07 '21 at 19:59
  • 1
    `Mov`ing to where `ESP`points fills the lowest 4 bytes of that 20-byte area. On the contrary, the first `push` will store beneath that 20-byte area. – Sep Roland Feb 07 '21 at 20:01
  • So if I push ebx on to the stack, the lowest 4 bytes will be filled and esp will now be pointing to ebp-16? – Mr Krisey Feb 07 '21 at 20:09
  • 1
    No, `PUSH` **decreases** the stackpointer! The first pushed dword will be at `[ebp-24] `. See the edited answer. – Sep Roland Feb 07 '21 at 20:12
  • I see, but why then have this 20 byte area? What is its use if everything pushed onto the stack goes below the allocated 20 bytes? – Mr Krisey Feb 07 '21 at 20:15
  • 1
    The 20-byte area (in this case) is set aside to store the local variables. Your program will refer to the items in it via easy to remember names. The offsets (small negative numbers) are known by the assembler. Pushing is still possible but is somewhat less 'organized' as well as the `PUSH` instruction being slower than a mere `MOV`. – Sep Roland Feb 07 '21 at 20:19
  • What would happen if there are more than 20 bytes needed to store local variables? Would a compiler then allocate more space? – Mr Krisey Feb 07 '21 at 20:27
  • 1
    Sure, that's what compilers do best, organizing the stuff that we submit in symbolic form. If your code were to use 7 local variables (dword), then the compiler would encode `sub esp, 28`. (7 * 4) – Sep Roland Feb 07 '21 at 20:33
  • 1
    Yes, that makes sense. This has been very informative. Thank you for your time. – Mr Krisey Feb 07 '21 at 20:35
  • 1
    Glad to have been of assistance. – Sep Roland Feb 07 '21 at 20:36