首页 > 代码库 > 函数调用的过程-栈

函数调用的过程-栈

根据不同的操作系统,一个进程可能被分配到不同的内存区域去执行。但是不管什么样的操作系统、什么样的计算机架构,进程使用的内存都可以按照功能大致分为以下4个部分:

  (1)代码区:这个区域存储着被装入执行的二进制机器代码,处理器会到这个区域取指并执行。

  (2)数据区:用于存储全局变量等。

  (3)堆区:进程可以在堆区动态地请求一定大小的内存,并在用完之后归还给堆区。动态分配和回收是堆区的特点。

  (4)栈区:用于动态地存储函数之间的关系,以保证被调用函数在返回时恢复到母函数中继续执行。

 

对于_stdcall调用约定,函数调用时用到的指令序列大致如下:

      push 参数3      ;假设该函数有3个参数,将从右向做依次入栈

      push 参数2

      push 参数1

      call 函数地址   ;call指令将同时完成两项工作:a)向栈中压入当前指令地址的下一个指令地址,即保存返回地址。 b)跳转到所调用函数的入口处。

      push  ebp        ;保存旧栈帧的底部

      mov  ebp,esp     ;设置新栈帧的底部 (栈帧切换)

      sub   esp,xxx     ;设置新栈帧的顶部 (抬高栈顶,为新栈帧开辟空间)

c语言和Win32平台为例,函数返回时的相关的指令序列如下:

   add esp,xxx     ;降低栈顶,回收当前的栈帧

   pop ebp         ;将上一个栈帧底部位置恢复到ebp

   retn            ;a)弹出当前栈顶元素,即弹出栈帧中的返回地址,至此,栈帧恢复到上一个栈帧工作完成。b)让处理器跳转到弹出的返回地址,恢复调用前代码区

 

寄存器

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

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

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

函数栈帧:ESP和EBP之间的内存空间为当前栈帧,EBP标识了当前栈帧的底部,ESP标识了当前栈帧的顶部。

函数调用的过程-栈