关于IA32的过程调用

来源:互联网 发布:mac桌面卡机了怎么办 编辑:程序博客网 时间:2024/06/06 02:00

在IA32的机器上,只提供了控制转移的指令。至于一些局部变量以及数据传递则要靠栈来实现。

为每一个过程分配的内存空间叫做栈帧,它包含两个特殊的参数,栈指针和帧指针。一个指向栈顶一个指向栈低。

栈是向低地址增长的,也就是说,栈的底部在内存的高地址部分。

调用者栈的结束边界是在执行call指令的时候将返回地址压入栈中,被调用者栈的起始边界是在保存祯指针ebp的值之后。

一般来说,数组等需要连续内存存储的数据结构都需要在栈中进行存储。在栈中扩展和回收空间其实都是靠移动栈指针来进行的。所谓的扩展空间,扩展的可能是其他程序刚刚用过的栈空间,但是现在可以进行覆盖,回收空间只是把栈指针向高地址段移动,有数据仍然在你刚刚释放的空间里面。


1、关于IA32提供的转移控制指令:

call

leave

ret

这三个指令是在每一次调用过程中都必须存在的,如果三个指令缺少其中一个,那么很可能就不算是一个 调用过程。

call指令的具体 效果,是将返回地址压入调用者的栈中,作为它的栈里面的最后一个元素,并且将程序计数器eip里面的数值改变为被调用者的地址。

ret指令是从栈中弹出这个返回地址,让程序回到调用之前被调用函数下一条指令继续进行。

leave指令一般在ret指令之前进行,它是为回到返回地址进行一些准备工作,比如回收栈空间,并且重置栈指针和帧指针,因为你调用完成之后是需要把两个重要的指针复位的。

leave的指令 等价于这两条指令 movl ebp esp , popl ebp。第一条指令的作用就是回收栈空间,把栈顶指针向上移动,和ebp指向同一条指令,ebp现在所指向的内存空间存储的是调用者的 ebp,也就是旧的ebp的值。第二条指令,将旧的ebp值恢复到ebp的寄存器,也就是将帧指针 重新指向调用者的栈底,此时esp因为弹出一个元素的原因 ,向上移动栈指针,正好指向了返回地址的那一块内存空间,此时就可以利用ret命令进行返回了。


2、过程调用

首先要明确一点的就是,向被调用者传递的参数是存储在调用者的栈中的。一般来说,一个被调用者的栈的起始点都是调用者ebp的值,为了以后恢复方便。过程调用期间,会通过栈来分配一些自由的内存空间用于存储一些临时的变量,但是在这种类型的分配方式下,是要遵循分配的空间 必须是16字节整数倍这样的 一个规定 ,这是X86编程的一个规定。所以你就会看到,在很多时候,明明分配了很多空间,但是都没用到。


被调用过程在进行的时候,要先将旧的ebp压入栈中,并且初始化两个栈指针,之后要将一些被调用者保存的寄存器里面的值压入栈中保存,防止在之后的代码中会覆盖这些数据。



0 0