前言:
现时我们对“call函数时 寄存器操作”可能比较讲究,小伙伴们都需要剖析一些“call函数时 寄存器操作”的相关知识。那么小编在网络上搜集了一些对于“call函数时 寄存器操作””的相关文章,希望我们能喜欢,各位老铁们一起来学习一下吧!当主调函数调用被调函数及返回时,编译器会有一系列的动作,主要由参数传递、地址跳转、局部变量分配和赋初值、执行函数体、结果返回、堆栈平衡等几个步骤组成。
1 主调函数调用被调函数
a 如果被调返回复合类型(如结构体),需要在主调函数的栈空间中开辟一块空间用于保存返回值(一个寄存器无法保存的数据)。
b 参数入栈:将实参值从右向左依次压入系统栈中;c 返回地址入栈:将当前代码区调用指令的下一条指令地址压入栈中,供函数返回时继续执行,一般由call指令完成;
d 代码区跳转:处理器从当前代码区跳转到被调用函数的入口处,一般也是由call指令完成;
e 栈帧调整:具体包括:
① 保存当前栈帧状态值,以便在后面恢复本栈帧时使用(EBP入栈);
② 将当前栈帧切换到新栈帧。(将ESP值装入EBP,更新栈帧底部);
③ 给新栈帧分配空间。(把ESP减去所需空间的大小,抬高栈顶);
f 相关寄存器压栈,编译器计算并分配函数所需栈帧空间并将空间进行初始化。
e 执行被调用函数,如果有局部变量,则在栈内分配空间。
f 值返回。
return语句将返回值返回到主调函数。在底层,参数是通过EAX寄存器或EDX寄存器传递给主调函数。或浮点计算单元的寄存器(浮点数返回值),或在主调函数中预先开辟栈空间来保存被调函数的返回值(如结构体变量返回值)。
类似于下图的操作:
2 返回后的堆栈平衡
函数的"}"被解释为函数体已经执行完。遇到"}"时,会将堆栈中的局部变量、程序中压入堆栈的寄存器的值全部弹出,将之前CALL指令执行时压入堆栈的函数返回地址弹到指令指针寄存器EIP,从而返回到主调函数。
当函数运行结束时,系统内部又一系列的动作,这些恰巧与调用函数时的动作顺序相反。
(1) 释放栈内局部变量空间
(2) 释放栈内参数空间
(3) 退栈,得到返回地址,程序跳转到调用函数处等待继续执行
(4) 退栈,得到程序运行状态,恢复调用函数前的状态。
(5) 释放该函数的栈空间
以下区分返回基本变量值与返回复合类型(如结构体变量)的汇编代码:
-End-
标签: #call函数时 寄存器操作