每个过程(函数)都有一块内存区域用来保存参数、返回地址、局部变量、寄存器值等信息,这块内存叫
栈帧
。栈帧由两个指针来界定:帧指针(%esp)和栈指针(%ebp)。帧指针固定指向栈底,栈指针则始终指向栈顶。
当P调用Q时,传给Q的参数和P的返回地址都保存在过程P的栈帧中(P149),过程Q从过程P的栈帧中取参数和返回地址。这就是为什么带参数的函数的汇编代码开头会有类似语句:
movl 8(%ebp),%ecx
%ebp的值是过程Q的栈帧起始地址,向高地址方向走的区域属于过程P的栈帧,%ebp+4是过程P的返回地址,%ebp+8是参数1,%ebp+12是参数2...
执行call指令时:
call指令的下一条指令的地址作为返回地址入栈,PC被修改,程序跳到call指令的操作数指示的地址去执行。
执行ret指令时:
从栈中弹出刚才保存的返回地址,PC被恢复,程序继续从刚才被中断处开始执行。
但还有个问题,要弹出返回地址时,栈指针并不指向保存有返回地址的位置,这就需要在ret之前为它做好准备,即调用leave指令使栈做好返回的准备,它等效于:
1、恢复调用函数原来的帧指针值%ebp。
2、使栈指针指向保存有返回地址的位置。
注意,leave指令不一定会使用,有时是用几条pop指令代替。