龙空技术网

C|主调函数调用被调函数时,编译器的一系列的动作

小智雅汇 547

前言:

现时我们对“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函数时 寄存器操作