内存中的栈模型

来源:互联网 发布:蓝科门窗软件 编辑:程序博客网 时间:2024/06/18 12:56
最近看完了Assembly Language For x86 Processors Sixth Edition By Kip R.Irvine中第8章对runtime stack的介绍,脑中对子程序调用时stack的过程有了一个完整的概念,现在来总结一下。

  

  首先一上来作者用了这么一段话非常精炼的总结了stack的几乎所有功能,其实要想完全掌握这个概念,脑中只要把调用子程序时生成stack的动态模型给记住即可。 


1. EBP之下的空间

1.1 ENTER&Prologue

ENTER指令首先保存ebp的值,然后将ebp指向esp,它有两个参数,第一个表示初创建栈的时候stack为local variables和registers needed to be saved预留的空间,即esp向下移动的字节数。总的来说,ENTER就是prologue的“一键化设置”

1.2 LEAVE&epilogue

leave指令没有任何参数,只是在ret前执行一下即可,它的作用等价于:

在runtime stack中为local variable和一些要保存的register预留了空间,在子程序调用结束后,这些空间必须要被释放出来,如果不释放,那么当pop ebp时,ebp就不能得到stack为他保留的值了。因此epilogue的作用可以总结为释放stack中ebp和esp之间的空间,从而使得ret指令在调用结束后能将程序返回到正确的地址。

 

2. EBP之上的空间

2.1 基本空间模型

上述程序的调用会产生下面的stack:

首先将参数压栈,然后执行call语句的时候将return address压栈

2.2 参数空间的释放

我们看这样一个例子,在main函数中调用Example1函数,再在Example1中调用AddTwo函数,然后ret,通过这个例子来说明子程序返回时释放参数空间的重要性

我们先看一下程序的栈模型:

在AddTwo子程序调用结束后,ret指令会返回到当前ESP所指向的地址,这就导致了错误的产生,解决这种错误有两种方法,一是在caller中释放该调用的空间,另一个是在子程序中自行完成,二者的实现分别如下:

在caller中释放参数空间:

在子程序中释放空间:

这种方法也被称为STDCALL Calling Convention)

通常情况下也就是子程序的循环调用可能会出现此种错误,需要注意

 

0 0