1: 指令
call instruction
tempEIP <-- EIP + DEST; (* DEST is rel32 *)
IF tempEIP is not within code segment limit THEN #GP(0); FI;
IF stack not large enough for a 4-byte return address
THEN #SS(0); FI;
Push(EIP);
EIP <-- tempEIP; <==> pushl %eip
ret instruction
eip <-- pop <==> popl %eip
leave instruction
esp <-- ebp <==> movl %ebp, %esp
ebp <-- pop <==> popl %ebp
enter instruction
pushl %ebp
movl %esp, %ebp
...
...
2: 调用过程
- prepare to call ==> prepare the input parameters, put them into 8(%ebp), 12(%ebp), 16(%ebp), 20(%ebp) ...
- call function ==> pushl %eip
- create stack ==> enter
- ==> pushl %ebp
- ==> movl %esp, %ebp
- do something
- destory stack ==> leave
- ==> movl %ebp, %esp
- ==> popl %ebp
- ret ==> ret ==> popl %eip
3: 堆栈
main -- ebp
-4
-8 ==> ret = 28(%esp)
-c ==> second = 24(%esp)
-10 ==> first = 20(%esp)
-14
-18
-1c ==> second - in parameter - 4(%esp) ==> 12(%ebp)
esp --> -20 ==> first - in paramter - (%esp) ==> 8(%ebp)
call sum:
esp --> EIP ==> *(eip) = the instruction next to call sum
sum -- ebp ==> ebp = esp; *(ebp) = prev_ebp
-4 ==> ret = -4(%ebp)
-8
-c
-10
4: C源代码
#include <stdio.h>
int sum(int a, int b)
{
int ret;
ret = a + b;
return ret;
}
int main(int argc, char* argv[])
{
int first = 5;
int second = 6;
int ret ;
ret = sum(first, second);
printf("ret = %d\n", ret);
return 0;
}
5: 汇编代码
gcc -S -fno-asynchronous-unwind-tables stack.c
.file "stack.c"
.text
.globl sum
.type sum, @function
sum:
# 3. create the stack frame
pushl %ebp
movl %esp, %ebp
# 4. alloc the stack space ==> ret = -4(%ebp)
subl $16, %esp
# 5. get the parameters from the higher stack
movl 12(%ebp), %eax
movl 8(%ebp), %edx
# 6. calculation
addl %edx, %eax
# 7. put the result into ret
movl %eax, -4(%ebp)
# 8. call convention, $eax is the return value
movl -4(%ebp), %eax
# 9. destory stack frame
leave
# 10. popl %eip
ret
.size sum, .-sum
.section .rodata
.LC0:
.string "ret = %d\n"
.text
.globl main
.type main, @function
main:
# create the stack frame
pushl %ebp
movl %esp, %ebp
# 16 bytes alignment
andl $-16, %esp
# alloc stack space
subl $32, %esp
# initialize the input parameters
movl $5, 20(%esp)
movl $6, 24(%esp)
# 1. prepare the input parameters
movl 24(%esp), %eax
movl %eax, 4(%esp)
movl 20(%esp), %eax
movl %eax, (%esp)
# 2. call the function sum ==> push %eip
call sum
# 11. get the return value
movl %eax, 28(%esp)
# prepare the input parameters for printf
movl 28(%esp), %eax
movl %eax, 4(%esp)
movl $.LC0, (%esp)
# call the function printf
call printf
# set the return value
movl $0, %eax
# destroy the stack frame
leave
# popl %eip
ret
.size main, .-main
.ident "GCC: (Ubuntu/Linaro 4.7.3-1ubuntu1) 4.7.3"
.section .note.GNU-stack,"",@progbits
6: 二进制代码
objdump -d
0804841c <sum>:
804841c: 55 push %ebp
804841d: 89 e5 mov %esp,%ebp
804841f: 83 ec 10 sub $0x10,%esp
8048422: 8b 45 0c mov 0xc(%ebp),%eax
8048425: 8b 55 08 mov 0x8(%ebp),%edx
8048428: 01 d0 add %edx,%eax
804842a: 89 45 fc mov %eax,-0x4(%ebp)
804842d: 8b 45 fc mov -0x4(%ebp),%eax
8048430: c9 leave
8048431: c3 ret
08048432 <main>:
8048432: 55 push %ebp
8048433: 89 e5 mov %esp,%ebp
8048435: 83 e4 f0 and $0xfffffff0,%esp
8048438: 83 ec 20 sub $0x20,%esp
804843b: c7 44 24 14 05 00 00 movl $0x5,0x14(%esp)
8048442: 00
8048443: c7 44 24 18 06 00 00 movl $0x6,0x18(%esp)
804844a: 00
804844b: 8b 44 24 18 mov 0x18(%esp),%eax
804844f: 89 44 24 04 mov %eax,0x4(%esp)
8048453: 8b 44 24 14 mov 0x14(%esp),%eax
8048457: 89 04 24 mov %eax,(%esp)
804845a: e8 bd ff ff ff call 804841c <sum>
804845f: 89 44 24 1c mov %eax,0x1c(%esp)
8048463: 8b 44 24 1c mov 0x1c(%esp),%eax
8048467: 89 44 24 04 mov %eax,0x4(%esp)
804846b: c7 04 24 10 85 04 08 movl $0x8048510,(%esp)
8048472: e8 79 fe ff ff call 80482f0 <printf@plt>
8048477: b8 00 00 00 00 mov $0x0,%eax
804847c: c9 leave
804847d: c3 ret
804847e: 66 90 xchg %ax,%ax