Considering this code:
int foo (int a, int b) {
return a + b;
}
int main (void) {
foo(3, 5);
return 0;
}
Compiling it with gcc foo.c -S
gives the assembly output:
foo:
pushl %ebp
movl %esp, %ebp
movl 12(%ebp), %eax
movl 8(%ebp), %edx
leal (%edx,%eax), %eax
popl %ebp
ret
main:
pushl %ebp
movl %esp, %ebp
subl $8, %esp
movl $5, 4(%esp)
movl $3, (%esp)
call foo
movl $0, %eax
leave
ret
So basically the caller (in this case main
) first allocates 8 bytes on the stack to accomodate the two arguments, then puts the two arguments on the stack at the corresponding offsets (4
and 0
), and then the call
instruction is issued which transfers the control to the foo
routine. The foo
routine reads its arguments from the corresponding offsets at the stack, restores it, and puts its return value in the eax
register so it's available to the caller.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…