sav0h
sav0h

Reputation: 391

What is going on with the stack pointer in this simple (disassembled) C program?

By way of learning more about assembly language / computer architecture, I wrote the following C code:

int my_caller() {
    int a = my_callee(0xbaba);
    return a;
}

int my_callee(int a) {
    return a;
}

This disassembles (on my machine; with some added comments) to the following:

; my_caller function
push ebp
mov ebp,esp
sub esp,byte +0x18
sub esp,byte +0xc
push dword 0xbaba
call dword 0x1e
add esp,byte +0x10
mov [ebp-0xc],eax
mov eax,[ebp-0xc]
leave
ret

; my_callee function
push ebp
mov ebp,esp
mov eax,[ebp+0x8]
pop ebp
ret

Regarding treatment of esp in my_caller:

  1. Why do we sub esp by 0x18 and then 0xc; why not just a single sub of 0x24?
  2. After returning from my_callee, what is the point of add esp,byte 0x10? The leave instruction is going to annul this anyway with the implicit mov esp,ebp.

Thanks.

Upvotes: 2

Views: 179

Answers (1)

Peter Cordes
Peter Cordes

Reputation: 364200

You told the compiler you'd like it to compile fast, not to make good code, and to make code that was easy for a debugger like gdb to interact with. In -O0 mode, gcc doesn't optimize much between different parts of the same function, hence the add esp, 0x10 to pop the stack after the call, and then leave separately.

-O0 is terribly noisy (full of stores/reloads), so it sucks to read as a human.

You'll have better luck looking at functions that take a couple int args and return an int. You can use __attribute__((noinline)) on functions to stop them from inlining.

Have a look at a simple function on the Godbolt compiler explorer, for example. See also the tag wiki.

Upvotes: 2

Related Questions