Behaviour of ebp and esp in stacks using function

2019-02-20 10:04发布

问题:

i want to learn more about stack. Especially, what happens when a function with parameter are called. For this, i write the following code:

    #include <stdio.h>
    int sum(int d, int e, int f){
        int result = d + e + f;
        return result;
    }

   int main(void){
   int a = 5;
   int b = 4;
   int c = 2;

   int erg = sum(a,b,c);
   printf("Result is: %d", erg);

   }

and I get the following Assembly-Code(I will only add the part of the main function, because first I want to understand this section):

    push ebp,
    mov ebp, esp
    and esp, -16
    sub esp, 32
    mov DWORD PTR[esp+28], 5
    mov DWORD PTR[esp+24], 4
    mov DWORD PTR[esp+20], 2
    mov eax, DWORD PTR[esp+20]
    mov DWORD PTR[esp+8], eax
    mov eax, DWORD PTR[esp+24]
    mov DWORTD PTR[esp+4], eax
    mov eax, DWORD PTR[esp+28]
    mov DWORD PTR[esp], eax
    call sum
    ........
    ........

So, for this part I draw a little sketch to for myself. Please take a look :) My question : Where is at that point my ebp? Because of line 2 of my assembler code, it must be at the same place like [esp], right ?

Now, the part of sum function which follows to my second question.

so here is the assembly-code of that:

    push ebp
    mov ebp, esp
    sub esp, 16
    mov eax, DWORD PTR[ebp+12]
    mov edx, DWORD PTR[ebp+8]
    mov edx, eax
    ------------

so, I had learned that we can find our parameters always in [eb+12] and [ebp+8]. (I skipped the third parameter because I want to keep it simple) So my question is now: If I assume that esp=ebp and I look at my sketch, then I see that there is nothing in [esp+12] or now [ebp+12]. But nevertheless, it is used. How can I imagine that?

Can someone help me? I've read so many papers, but nobody seems to sketch these things. Because of that, it is very hard to understand that.

Thank you!

Here is my sketch:

回答1:

During the first function execution esp and ebp have the same value only immediately after the instruction mov ebp, esp. After that and esp, -16 zeroes the lowest 4 bits (the lowest nibble) of esp, and esp and ebp diverge, unless the lowest bits of esp were zeroes already. Then sub esp, 32 subtracts 32 from esp and here esp and ebp diverge for sure.

push ebp                   ; esp = esp - 4; [esp] = ebp.
mov ebp, esp               ; ebp = esp. create the stack frame. 
and esp, -16               ; make lowest 4 bits of esp zeros, for alignment.
sub esp, 32                ; esp = esp - 32. make space for local variables.
mov DWORD PTR[esp+28], 5   ; a = 5
mov DWORD PTR[esp+24], 4   ; b = 4
mov DWORD PTR[esp+20], 2   ; c = 2
mov eax, DWORD PTR[esp+20] ; eax = c (eax = 2)
mov DWORD PTR[esp+8], eax  ; [esp+8] = dword 2
mov eax, DWORD PTR[esp+24] ; eax = b (eax = 4)
mov DWORTD PTR[esp+4], eax ; [esp+4] = dword 4
mov eax, DWORD PTR[esp+28] ; eax = a (eax = 5)
mov DWORD PTR[esp], eax    ; [esp] = dword 5
call sum                   ; the above lines define the parameters for the
                           ; function sum, that is called now.

Then regarding your second question:

push ebp                   ; esp = esp - 4; [esp] = ebp.
mov ebp, esp               ; ebp = esp.
sub esp, 16                ; esp = esp - 16. create space for local variables.
                           ; at this point:
                           ; [ebp]    == old value of ebp.
                           ; [ebp+4]  == return address pushed by call,
                           ;             to be used by the next ret.
                           ; [ebp+8]  == dword 5 (a)
                           ; [ebp+12] == dword 4 (b)
                           ; [ebp+16] == dword 2 (c)
mov eax, DWORD PTR[ebp+12] ; eax = 4
mov edx, DWORD PTR[ebp+8]  ; edx = 5. gets overwritten by the next instruction.          
mov edx, eax               ; edx = eax = 4

Don't assume esp == ebp. In this second function too esp and ebp diverge upon execution of the instruction sub esp,16. Learn to use a debugger, for example GDB and single-step through the code and follow the values of registers (especially esp) and memory after each instruction. You can also debug the code in your head as I did above, but if you are a beginner in assembly, using a debugger is usually a lot easier and a lot less error-prone.



回答2:

The following has fairly decent explanation of what is going on with the stack, stack frame, ebp and esp when calling a routine with parameters. I hope it is helpful. What is stack frame in assembly?