x86 asm - 12 bytes subtracted from esp. Only 8 needed

475 Views Asked by At

I've compiled this code with gcc (gcc -ggdb -mpreferred-stack-boundary=2 -o demo demo.c) and decompiled it to look at the assembly (I know it's using unsafe functions, this was for an exercise into buffer overflows):

#include<stdio.h>

CanNeverExecute()
{
        printf("I can never execute\n");
        exit(0);
}

GetInput()
{
        char buffer[8];

        gets(buffer);
        puts(buffer);
}

main()
{
        GetInput();

        return 0;
}

Here is the assembly for the GetInput() Function:

(gdb) disas GetInput
Dump of assembler code for function GetInput:
   0x08048432 <+0>: push   ebp
   0x08048433 <+1>: mov    ebp,esp
   0x08048435 <+3>: sub    esp,0xc
=> 0x08048438 <+6>: lea    eax,[ebp-0x8]
   0x0804843b <+9>: mov    DWORD PTR [esp],eax
   0x0804843e <+12>:    call   0x8048320 <gets@plt>
   0x08048443 <+17>:    lea    eax,[ebp-0x8]
   0x08048446 <+20>:    mov    DWORD PTR [esp],eax
   0x08048449 <+23>:    call   0x8048340 <puts@plt>
   0x0804844e <+28>:    leave  
   0x0804844f <+29>:    ret    
End of assembler dump.

Here is the assembly for the Main() Function:

(gdb) disas main
Dump of assembler code for function main:
   0x08048450 <+0>: push   ebp
   0x08048451 <+1>: mov    ebp,esp
   0x08048453 <+3>: call   0x8048432 <GetInput>
   0x08048458 <+8>: mov    eax,0x0
   0x0804845d <+13>:    pop    ebp
   0x0804845e <+14>:    ret    
End of assembler dump.

I've set a breakpoint at line 13 (gets(buffer))

From Main(), I can see that the ebp value is pushed onto the stack. Then when GetInput() function is called the ret address is also pushed onto the stack. Once entered the GetInput function, the ebp value is pushed onto the stack again. Now this is where I get confused:

0x08048435 <+3>: sub esp,0xc

The buffer variable is only 8 bytes, so 8 bytes should be subtracted from esp to allow for the buffer local variable.

The stack:

    (gdb) x/8xw $esp
    0xbffff404: 0x08048360  0x0804847b  0x002c3ff4  0xbffff418
    0xbffff414: 0x08048458  0xbffff498  0x00147d36  0x00000001
    (gdb) x/x &buffer
    0xbffff408: 0x0804847b

0x08048458 is the ret address, 0xbffff418 is the old value of ebp, and 4 bytes of the buffer variable is in 0x0804847b, so I guess the other 4 bytes is 0x002c3ff4. But there seems to be another 4 bytes on the stack.

So my question is, why is it subtracting 12 bytes if only 8 bytes is needed? What's the extra 4 bytes for?

Thank you

1

There are 1 best solutions below

1
On BEST ANSWER

It's because of the

mov    DWORD PTR [esp],eax

Apparently, your puts and gets implementations require the argument to be pushed onto the stack.

Value [ebp-0xc] is actually [esp] now, that's why that dword is reserved ahead.

Why is it so? Doing it this way is more efficient, as you don't have to pop and push, but just move eax on [esp], so you spare at least one instruction. However, I guess this code has gone through some optimiation, because this one is clever.