1. EIP、EBP、ESP
- EIP寄存器里存储的是CPU下次要执行的指令的地址。
- EBP寄存器里存储的是栈的栈底地址,通常叫栈基址。
- ESP寄存器里存储的是栈的栈顶地址,始终指向栈顶。
2. 函数调用
- 源程序
int foo(int a, int b)
{
int c = a + b;
return c;
}
int main()
{
foo(2, 3);
return 0;
}
- 对应的汇编程序
$gcc –g main.c
$objdump –D a.out
080482f4 <foo>:
80482f4: 55 push %ebp
80482f5: 89 e5 mov %esp,%ebp
80482f7: 83 ec 04 sub $0x4,%esp
80482fa: 8b 45 0c mov 0xc(%ebp),%eax
80482fd: 03 45 08 add 0x8(%ebp),%eax
8048300: 89 45 fc mov %eax,0xfffffffc(%ebp)
8048303: 8b 45 fc mov 0xfffffffc(%ebp),%eax
8048306: c9 leave
8048307: c3 ret
08048308 <main>:
8048308: 55 push %ebp
8048309: 89 e5 mov %esp,%ebp
804830b: 83 ec 08 sub $0x8,%esp
804830e: 83 e4 f0 and $0xfffffff0,%esp
8048311: b8 00 00 00 00 mov $0x0,%eax
8048316: 29 c4 sub %eax,%esp
8048318: 83 ec 08 sub $0x8,%esp
804831b: 6a 03 push $0x3
804831d: 6a 02 push $0x2
804831f: e8 d0 ff ff ff call 80482f4 <foo>
8048324: 83 c4 10 add $0x10,%esp
8048327: b8 00 00 00 00 mov $0x0,%eax
804832c: c9 leave
804832d: c3 ret
- 函数调用过程
1) 调用foo
804831f: e8 d0 ff ff ff call 80482f4 <foo>
main函数中的call指令调用函数foo,此时EIP压栈,存下函数返回时要执行的下一条指令的地址(这里也就是存下8048324)。
call addr 指令所做的操作相当于push eip 然后 jmp addr;机器指令4字节。
jmp addr 执行所做的操作相当于 mov addr, eip;机器指令2字节。
2) 进入foo
80482f4: 55 push %ebp
80482f5: 89 e5 mov %esp,%ebp
80482f7: 83 ec 04 sub $0x4,%esp
将ebp压栈,即将main函数栈帧的栈底地址压栈。
将esp的值传给ebp,此时的ebp指向foo函数栈帧的栈底地址。
为foo栈帧分配栈空间
3) 离开foo
8048306: c9 leave
8048307: c3 ret
恢复到main函数的栈底地址(ebp)、栈顶地址(esp)、下一条指令地址(eip).
leave 指令所做的操作相当于mov ebp, esp 然后 popebp;机器指令1字节。
ret 指令所做的操作相当于pop eip;机器指令1字节。
3. 验证- gdb调试
$gdb a.out
(gdb) disassemble
Dump ofassembler code for function foo:
0x080482f4 <foo+0>: push %ebp
0x080482f5 <foo+1>: mov %esp,%ebp
0x080482f7 <foo+3>: sub $0x4,%esp
0x080482fa <foo+6>: mov 0xc(%ebp),%eax
0x080482fd <foo+9>: add 0x8(%ebp),%eax
0x08048300 <foo+12>: mov %eax,0xfffffffc(%ebp)
0x08048303 <foo+15>: mov 0xfffffffc(%ebp),%eax
0x08048306 <foo+18>: leave
0x08048307 <foo+19>: ret
End ofassembler dump.
(gdb) nexti
0x080482fd 3 int c = a + b;
(gdb) info registers
ebx 0x42130a14 1108544020
esp 0xbfffeb14 0xbfffeb14
ebp 0xbfffeb18 0xbfffeb18
eip 0x80482fd 0x80482fd
(gdb) x/20 $esp
0xbfffeb14: 0x42130a14 0xbfffeb38 0x08048324 0x00000002
0xbfffeb24: 0x00000003 0xbfffeb38 0x0804833a 0x42130a14
0xbfffeb34: 0x40015360 0xbfffeb58 0x42015574 0x00000001
0xbfffeb44: 0xbfffeb84 0xbfffeb8c 0x4001582c 0x00000001
0xbfffeb54: 0x08048244 0x00000000 0x08048265 0x08048308
0xbfffeb14: 0x42130a14 0xbfffeb38(ebp) ---- foo栈帧
0x08048324 0x00000002
0xbfffeb24: 0x00000003 0xbfffeb38 0x0804833a 0x42130a14
0xbfffeb34: 0x40015360 0xbfffeb58(ebp) ---- main栈帧