什么是基指针和堆栈指针? 他们指的是什么?
使用来自维基百科的这个例子,其中DrawSquare()调用DrawLine(),
(请注意,此图在顶部有高地址,在顶部有低地址。)
任何人都可以解释我在这种情况下的ebp
和esp
是什么?
从我看到的情况来看,我会说堆栈指针始终指向堆栈顶部,而基指针指向当前函数的开始位置? 或者是什么?
编辑:我的意思是在Windows程序的上下文中
edit2: eip
也是如何工作的?
编辑3:我从MSVC ++有以下代码:
var_C= dword ptr -0Ch
var_8= dword ptr -8
var_4= dword ptr -4
hInstance= dword ptr 8
hPrevInstance= dword ptr 0Ch
lpCmdLine= dword ptr 10h
nShowCmd= dword ptr 14h
所有这些似乎都是双字,因此每个字节需要4个字节。 所以我可以看到从hInstance到4个字节的var_4有差距。 他们是什么? 我认为这是返回地址,可以在维基百科的图片中看到?
(编者按:从迈克尔的回答中删除了很长的一段话,这不属于问题的范围,但后续的问题被编辑了):
这是因为函数调用的流程是:
* Push parameters (hInstance, etc.)
* Call function, which pushes return address
* Push ebp
* Allocate space for locals
我的问题(最后,我希望!)现在是,从即时弹出函数的参数,我想调用到序言的结尾,究竟发生了什么? 我想知道ebp,esp在那些时刻是如何演变的(我已经理解了序言的作用,我只是想知道在将参数推入堆栈之前和序言之前发生了什么)。
esp
就像你说的那样,是堆栈的顶部。
ebp
通常设置为esp
在函数的开始。 函数参数和局部变量分别通过加减ebp
的常量偏移量来访问。 所有x86调用约定都将ebp
定义为在函数调用中保留。 ebp
本身实际上指向前一帧的基址指针,这使得堆栈可以在调试器中行走并查看其他帧局部变量的工作。
大多数函数序言看起来像这样:
push ebp ; Preserve current frame pointer
mov ebp, esp ; Create new frame pointer pointing to current stack top
sub esp, 20 ; allocate 20 bytes worth of locals on stack.
然后在函数后面可能会有类似的代码(假设两个局部变量都是4个字节)
mov [ebp-4], eax ; Store eax in first local
mov ebx, [ebp - 8] ; Load ebx from second local
您可以启用的FPO或帧指针省略优化实际上将消除这种情况,并将ebp
用作另一个寄存器并直接访问esp
本地语言,但这会使调试更加困难,因为调试器不能再直接访问早期函数的堆栈帧调用。
编辑:
对于您更新的问题,堆栈中缺少的两个条目是:
var_C = dword ptr -0Ch
var_8 = dword ptr -8
var_4 = dword ptr -4
*savedFramePointer = dword ptr 0*
*return address = dword ptr 4*
hInstance = dword ptr 8h
PrevInstance = dword ptr 0C
hlpCmdLine = dword ptr 10h
nShowCmd = dword ptr 14h
这是因为函数调用的流程是:
hInstance
等) ebp
ESP是当前的堆栈指针,当任何时候一个字或地址被压入或弹出堆栈时,这个指针都会改变。 EBP是编译器跟踪函数参数和局部变量比直接使用ESP更方便的一种方式。
一般来说(这可能会因编译器而异),被调用的函数的所有参数都会被压入堆栈(通常按照它们在函数原型中声明的相反顺序),但这会有所不同。 然后调用该函数,将返回地址(EIP)压入堆栈。
进入该功能后,将旧的EBP值压入堆栈,并将EBP设置为ESP的值。 然后ESP减少(因为堆栈在内存中向下增长)为函数的局部变量和临时对象分配空间。 从这一点开始,在函数执行过程中,函数的参数位于堆栈上与EBP成正偏移(因为它们是在函数调用之前被推送的),并且局部变量位于EBP的负偏移处(因为它们是在函数入口之后在堆栈上分配的)。 这就是为什么EBP被称为帧指针的原因,因为它指向函数调用帧的中心。
退出时,所有函数所要做的就是将ESP设置为EBP的值(从堆栈中释放本地变量,并将堆栈顶部的条目EBP公开),然后从堆栈中弹出旧的EBP值,然后函数返回(将返回地址弹出到EIP中)。
你说得对。 堆栈指针指向堆栈中的顶层项目,并且在调用该函数之前,基址指针指向堆栈的“上一个”顶端。
当你调用一个函数时,任何局部变量将被存储在堆栈上,并且堆栈指针将被增加。 从函数返回时,堆栈中的所有局部变量超出范围。 您可以通过将堆栈指针设置回基本指针(这是函数调用之前的“上一个”顶部)来完成此操作。
以这种方式进行内存分配非常非常快速和高效。
链接地址: http://www.djcxy.com/p/14019.html上一篇: What is exactly the base pointer and stack pointer? To what do they point?