一个C过程的大致结构如下:
1. 准备阶段
- 形成帧底:push指令和move指令
- 生成栈帧(如果需要的话):sub指令或and指令
- 保存现场(如果有被调用者保存寄存器):mov指令
2. 过程(函数)体:
- 分配局部空间,并赋值
- 具体处理逻辑,如果遇到函数调用
- 准备参数:将实参送到栈帧入口参数处
- CALL指令:保存返回地址并转调用函数
- 在EAX中准备返回参数
3. 结束阶段:
- 退栈:leave指令或pop指令
- 取返回地址返回:ret指令
过程调用的机器表示
1. 调用者保存寄存器
当过程调用P调用过程Q时,Q可以直接使用这三个寄存器,不用将他们的值保存到栈中。如果P在从Q返回后还要用这三个寄存器的话,P应在转到Q之前先保存,并在Q返回后先恢复他们的值再使用。
2. 被调用者保存寄存器
Q必须先将他们的值保存到栈中再使用他们,并在返回P之前恢复他们的值
IA-32的寄存器使用约定
IA-32 :EBP和ESP分别是帧指针寄存器和栈指针寄存器,分别用来指向当前栈帧的底部和顶部。
问题:为减少准备阶段和结束阶段的开销,每个过程应先使用哪些寄存器?EAX ECX EDX
x86-64的寄存器使用约定
X86-64过程调用的参数传递
- 通过通用寄存器传送参数,很多过程不用访问栈,故执行时间比IA-32代码更短
- 最多可有6个整型或指针型参数通过寄存器传递
- 超过6个入口参数时,后面的通过栈来传递
- 在栈中传递的参数若是基本类型,则被分配8个字节
- call将64位返址保存到栈中之前,将执行R[rsp]<-R[rsp]-8
- ret将从栈中取出64位返回地址后,执行R[rsp]<-R[rsp]+8
在过程(函数)中尽量使用寄存器RAX,R10和R11.若使用RBX,R12,R13,R14和R15,则需要将他们先保存在栈中再使用,最后返回前再恢复其值.
输出结果:Why run here?