首页 > 代码库 > 函数调用的过程-栈
函数调用的过程-栈
根据不同的操作系统,一个进程可能被分配到不同的内存区域去执行。但是不管什么样的操作系统、什么样的计算机架构,进程使用的内存都可以按照功能大致分为以下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标识了当前栈帧的顶部。
函数调用的过程-栈