Luc*_*nis 33 x86 assembly callstack stack-frame
我发现ESP寄存器是当前的堆栈指针,而EBP是当前堆栈帧的基本指针.但是,我不明白这些定义(我刚开始学习如何在汇编程序中编写代码).
据我所知,ESP指向堆栈本身,EBP指向堆栈顶部的任何东西.但这些只是我的猜测而且很可能是不正确的.否则,如下所述的声明是什么意思?
MOV EBP, ESP
Run Code Online (Sandbox Code Playgroud)
编辑:我认为上面的陈述是我书的错字.我认为它应该是EBX而不是EBP
old*_*mer 35
esp是堆栈指针,ebp是/是堆栈帧的,所以当你输入一个函数时,ebp可以获得esp的副本,在那之前堆栈上的所有内容,返回地址,传入参数等等对于该函数的全局函数(局部变量)现在将在函数持续时间内远离堆栈帧指针.esp现在可以像编译器一样随意漫游,并且可以在嵌套到其他函数时使用(每个函数都需要自然保留ebp).
这是一种管理堆栈的懒惰方式.使编译器调试变得更加容易,使得理解编译器生成的代码更容易,但是烧掉了一个可能是通用的寄存器.
rcg*_*ldr 15
通常EBP用于备份ESP,因此如果ESP由函数中的代码更改,则恢复ESP所需的全部是移动ESP,EBP.此外,由于EBP通常由函数中的代码保持不变,因此可以使用它来访问传递的参数或局部变量,而无需调整偏移量.
对于"堆栈帧"使用,EBP在任何函数的开头被压入堆栈,因此推入堆栈的EBP的值是来自调用当前函数的函数的EBP的值.这使得代码或调试器可以"回溯"通过EBP被推送到堆栈的所有实例,并且堆栈上的每个EBP值实例都可以被认为是堆栈帧的基指针.
请注意,某些编译器具有"省略帧指针"选项,在这种情况下,EBP不用于保存ESP或作为堆栈帧指针.相反,编译器会跟踪ESP,并且所有本地偏移都是与ESP当前值的偏移量.
EBP和ESP是这个时代的遗留物,编译器没有例如静态分析来检测函数调用中需要多少字节的堆栈.此外,堆栈应该在执行函数期间动态增长和缩小,中断允许将所有堆栈从0丢弃到SP,而意大利面条代码是事实上的标准.实际上,中断(以及仅通过寄存器传递参数)是调用内核函数的设计方法.
在这些环境中,需要具有堆栈的固定点,其中始终找到调用者的返回地址,局部变量和函数的参数.因此bp登记册是合理的.在这个架构中bp被允许索引([bp - 300h]),但sp不是.可能被解释为的那些操作码/指令编码mov ax, [sp + 1111h]被重用于其他目的.
在386+中,通过引入'E',ESP获得了抵消的属性.此时EBP脱离了唯一的目的,因为esp能够处理这两项任务.
注意,即使现在EBP指向通过堆栈段的内存,就像ESP.EBX和BX使用DS.
ESP 寄存器是系统堆栈的堆栈指针。它很少被程序直接改变,但是当数据被压入堆栈或从堆栈中弹出时会被改变。堆栈的一种用途是在过程调用中。过程调用指令之后的指令地址存储在堆栈中。EBP 寄存器指向基址。通常,在堆栈中访问的唯一数据项是位于堆栈顶部的数据项。尽管 EBP 寄存器通常用于标记堆栈中除堆栈顶部以外的固定点,但例如此类数据是参数。它们在返回地址之后从基指针的堆栈 EBP 顶部偏移。所以你会看到像 EBP+0x8、EBP+0xC 这样的东西,这分别是 1 和 2 中的参数。
理解堆栈在汇编语言编程中非常重要,因为这会影响您将使用的调用约定,而不管类型如何。例如,即使是 cdecl 或 __stdcall 也依赖于 ESP 和 EBP 寄存器,而其他的也以某种方式依赖于某些寄存器和堆栈。