When I compile
#include <stdio.h>
int
main () {
return 0;
}
to x86 assembly the result is plain and expected:
$> cc -m32 -S main.c -o -|sed -r "/\s*\./d"
main:
pushl %ebp
movl %esp, %ebp
movl $0, %eax
popl %ebp
ret
But when studying different disassembled binaries, the function prologue is never that simple. Indeed, changing the C source above into
#include <stdio.h>
int
main () {
printf("Hi");
return 0;
}
the result is
$> cc -m32 -S main.c -o -|sed -r "/\s*\./d"
main:
leal 4(%esp), %ecx
andl $-16, %esp
pushl -4(%ecx)
pushl %ebp
movl %esp, %ebp
pushl %ecx
subl $4, %esp
subl $12, %esp
call printf
addl $16, %esp
movl $0, %eax
movl -4(%ebp), %ecx
leave
leal -4(%ecx), %esp
ret
In particular, I don't get why these instructions
leal 4(%esp), %ecx
andl $-16, %esp
pushl -4(%ecx)
are generated -- specifically why not directly storing %esp
into %ecx
, instead of into%esp+4
?