Assembly ESP和EBP寄存器是什么?

Assembly ESP和EBP寄存器是什么?,assembly,x86,callstack,stack-frame,Assembly,X86,Callstack,Stack Frame,我发现ESP寄存器是当前堆栈指针,EBP是当前堆栈帧的基指针。然而,我不理解这些定义(我刚刚开始学习如何在汇编程序中编写代码) 据我所知,ESP指向堆栈本身,EBP指向堆栈顶部的任何对象1。但这些只是我的猜测,很可能是不正确的。否则,下面这样的语句是什么意思 MOV EBP, ESP 脚注1:编者按:是的,这是错误的。在标准术语中,“堆栈顶部”是ESP指向的位置,即使它是堆栈框架中的最低地址。与向上增长的堆栈数据结构类似,即使x86上的调用堆栈(与大多数ISA一样)向下增长。通常EBP

我发现ESP寄存器是当前堆栈指针,EBP是当前堆栈帧的基指针。然而,我不理解这些定义(我刚刚开始学习如何在汇编程序中编写代码)

据我所知,ESP指向堆栈本身,EBP指向堆栈顶部的任何对象1。但这些只是我的猜测,很可能是不正确的。否则,下面这样的语句是什么意思

MOV EBP, ESP    

脚注1:编者按:是的,这是错误的。在标准术语中,“堆栈顶部”是ESP指向的位置,即使它是堆栈框架中的最低地址。与向上增长的堆栈数据结构类似,即使x86上的调用堆栈(与大多数ISA一样)向下增长。

通常EBP用于备份ESP,因此如果函数中的代码更改了ESP,则恢复ESP所需的全部是mov ESP,EBP。此外,由于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
也通过堆栈段(SS)指向内存,就像
ESP
一样。其他寻址模式(不以ESP/EBP为基础)默认为DS段。(16位模式下的绝对、DI、SI和/或BX,以及32位寻址模式下的任何寄存器都可以是寻址模式下的基址)。

esp是堆栈指针,ebp是/曾经是堆栈帧,因此当您输入函数ebp时,可以在该点获取esp的副本,在此之前堆栈上的所有内容,返回地址,传入参数,etc和该函数的全局变量(局部变量)现在将是在函数期间与堆栈帧指针的静态距离。esp现在可以根据编译器的需要自由漫游,并且可以在嵌套到其他函数时使用(每个函数都需要自然地保留ebp)


这是一种懒惰的方法来管理堆栈。使编译器调试更容易,使理解编译器生成的代码更容易,但会烧掉一个寄存器,否则该寄存器可能是通用的。

ESP寄存器是系统堆栈的堆栈指针。它很少由程序直接更改,但会被更改 当数据被推送到堆栈上或从堆栈中弹出时。堆栈的一个用途是过程调用。过程调用指令之后的指令地址存储在堆栈上。EBP寄存器指向基址的指针。 通常,在堆栈中访问的唯一数据项是位于堆栈顶部的数据项。尽管EBP寄存器通常用于标记堆栈中除堆栈顶部以外的固定点,例如,此类数据的参数。它们在返回地址之后从基指针的堆栈EBP顶部偏移。您将看到类似于EBP+0x8、EBP+0xC的内容,这是分别在1和2中显示的参数


理解堆栈在汇编语言编程中非常重要,因为这会影响您将要使用的调用约定,而不管类型如何。例如,甚至cdecl或_stdcall也依赖于ESP和EBP寄存器,而其他寄存器也以某种方式依赖于某些寄存器和堆栈

EBX和EBP是不同的寄存器。我发现你的答案非常有用,但我不确定你最后一句话的意思:“EBX和BX使用DS。”?历史上IA有段寄存器;CS表示代码,DS/ES表示数据,SS表示堆栈。每个段一次只能访问64kb的内存。386具有相同的体系结构,添加了FS和GS,但现在每个段都可以配置为访问1字节到4GB内存之间的任何位置。每个指令或寻址模式都有一个隐式段寄存器,通过它访问内存。甚至在后来,“扁平”内存模型成为了事实上的标准,每个段寄存器都可以看到所有内容(除了保留GS寄存器的内核)。谢谢。对于所有仍在努力理解的人,对我来说,关键是告诉自己:推动ebp