您的位置:首页 > 其它

从汇编看函数调用

2016-09-14 21:00 246 查看
首先介绍几个名词:

栈帧:也叫过程活动记录,是编译器用来实现过程/函数调用的一种数据结构。栈帧中保存了该函数的返回地址和局部变量。

寄存器:CPU内部用来存放数据的一些小型存储区域,用来暂时存放参与运算的数据和运算结果。常用的寄存器有:

ESP:栈指针寄存器(extended stack pointer),其内存放着一个指针,该指针永远指向系统栈最上面一个栈帧的栈顶。

EBP:基址指针寄存器(extended base pointer),其内存放着一个指针,该指针永远指向系统栈最上面一个栈帧的底部。

EIP:指令寄存器(extended instruction pointer),其内存放着一个指针,该指针永远指向下一条等待执行的指令地址。

EAX:累加器(accumulator),一般用来保存函数的返回值。

函数调用过程中系统栈的变化可见另一篇博文数据结构之—栈和递归&函数调用

下面具体讲函数调用的步骤及汇编语言中的相关指令。

函数调用大概包括以下几个步骤:

参数入栈:将参数从从右向左依次压入系统栈中。

返回地址入栈:将当前代码区调用指令的下一条指令地址压入栈中,供函数返回时继续执行。

代码区跳转:处理器从当前代码区跳转到被调用函数的入口处。

栈帧调整:具体包括

(1)保存当前栈帧状态值,以备后面恢复本栈帧时使用(EBP入栈);

(2)将当前栈帧切换到新栈帧(将ESP值装入EBP,更新栈帧底部);

(3)给新栈帧分配空间(把ESP减去所需空间的大小,抬高栈顶);

以下附上《0day安全:软件漏洞分析技术》书中相关配图说明此过程



函数调用时用到的指令序列大致如下:

//....调用前

//调用开始
push 参数3       //假设函数有3个参数,将从右向左依次入栈
push 参数2
push 参数1
call 函数地址   //向栈中压入当前指令在内存中的位置,即保存返回地址;
//跳转到所调用函数的入口地址函数入口处
push ebp         //保存旧栈帧的底部
mov ebp,esp      //设置新栈帧的底部(栈帧切换)
sub esp,xxx      //设置新栈帧的顶部(抬高栈顶,为新栈帧开辟空间)


具体过程可参考下图:



函数返回时的相关指令序列如下:

addesp,xxx  //降低栈顶,回收当前的栈帧
pop ebp     //将上一个栈帧底部位置恢复到ebp
retn        //弹出当前栈顶元素,即弹出栈帧中的返回地址,完成栈帧恢复工作
//让处理器跳转到弹出的返回地址,恢复调用前的代码区


总的过程可参考下图:

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  汇编 函数调用