0

在x86汇编中,esp堆栈指针ebp是堆指针吗?为什么我们有两种数据结构而不是只有一种?

什么esi/edi代表什么?

4

4 回答 4

12

一般来说,机器架构上的寄存器不需要专门用于任何目的。实际上,通过指定一个寄存器来支持常用功能,该寄存器成为那个/那些功能的特殊用途。

在 x86 上,ESP 指针被 PUSH/CALL 指令和各种中断/陷阱用来存储可恢复状态,例如返回地址。这些在支持编程方面非常有吸引力,因此由编译器和操作系统供应商承诺,ESP 基本上不能用于任何其他目的。因为可以从任意索引中引用内存,所以它可以用于管理“堆栈”和当前函数堆栈帧。

但是,变量(当前堆栈帧的局部变量)相对于 ESP 的索引偏移量会随着程序将值压入和弹出堆栈以及 ESP 的变化而变化。编译器可以跟踪所有这些,因此可以使用正确的索引偏移量。但是如果你是手工编写汇编代码,你实际上不能可靠地做到这一点,而且拥有一个基于堆栈帧的指针会更容易;那么变量的索引偏移量可以是相对于堆栈帧指针的常量。英特尔很早就为此目的指定了 EBP,甚至还有特殊的索引模式来支持这一点,以及用于构建显示的特殊 EBP 相关指令(一组指向词汇封闭堆栈帧的指针,采用 Algol 风格)。

但是您/编译器不必为此目的使用 EBP。在具有少量寄存器(x86)的机器中,拥有另一个空闲寄存器可以帮助生成更小/更紧凑的代码。在较旧的 CPU 上,不使用 EBP 有不同的惩罚:局部变量的 ESP 索引偏移量往往大于堆栈帧基数的索引偏移量,因此使用 EBP 作为空闲寄存器可以通过更大的偏移量为您提供更大的程序用于 ESP。当获取指令很昂贵时,这曾经很重要。由于指令缓存与它们一样好,这几乎不再是问题。微软的 C 编译器(我怀疑是 GCC)有一个不使用帧指针的开关,从而放弃了一些程序大小以获得更快的代码。

堆变量只是那些不在堆栈帧中的变量。您可以使用任何寄存器来访问它们。

一些语言(例如,我们的 PARLANSE 编译器)只使用堆分配;甚至堆栈帧都是从堆中获取的(并且 ESP 设置为分配的空间块的顶部)。

于 2012-10-22T18:11:27.257 回答
7

通常,ESP 指向堆栈的顶部,而 EBP 指向堆栈帧的底部,因此它们都将指向堆栈上的地址,而不是堆上的地址。在大多数情况下,并不完全需要保留指向堆栈帧底部的指针,因此一些编译器可能会简单地将 EBP 用作另一个通用寄存器。

ESI 和 EDI 是通用寄存器,但有一个例外:字符串指令(例如 movs、lods)分别将它们视为源地址和目标地址。

于 2012-10-22T17:50:03.687 回答
4

虽然有一些特定于寄存器和的事物和行为xBP,但它们并不绑定到任何一个函数。您可以在汇编代码中随意使用它们。xSIxDI

于 2012-10-22T17:44:51.380 回答
1

整个内存被组织成 4 个段。代码、数据、堆栈和其他。堆用于多用途存储(如动态分配(malloc 等)),而堆栈专门用于指令指针和在调用另一个过程时(如在递归期间)存储变量。数据段用于全局变量和静态变量。

对于 ESI/EDI 请参阅关于 SO 的此问题:ESI 和 EDI 寄存器的目的?

编辑:也看到这个:堆与数据段与堆栈分配

于 2012-10-22T17:44:16.220 回答