在x86程序集中,esp
是否为堆栈指针而ebp
是堆指针?为什么我们有两个数据结构而不只是一个?
esi
/ edi
代表什么?
答案 0 :(得分:10)
通常,机器架构上的寄存器不需要专用于任何目的。实际上,通过指定一个支持常用功能的寄存器,该寄存器成为该功能的特殊用途。
在x86上,ESP指针由PUSH / CALL指令和各种中断/陷阱用于存储可恢复状态,例如返回地址。这些在支持编程方面非常有吸引力,因此由编译器和操作系统供应商承诺,ESP基本上不能用于任何其他目的。因为可以从ESP的任意索引引用内存,所以它可以用于管理“堆栈”和当前函数堆栈帧。
然而,变量(当前堆栈帧的本地)相对于ESP的索引偏移量随着程序将值推入并弹出到堆栈并且ESP改变而变化。编译器可以跟踪所有这些,因此可以使用正确的索引偏移量。但是如果你手工编写程序集,你实际上不能可靠地做到这一点,并且更容易拥有一个堆栈框架指针;那么变量的索引偏移量可以是相对于堆栈帧指针的常量。英特尔早期为此目的指定了EBP,甚至还有特殊的索引模式来支持这一点,以及用于构建显示的特殊EBP相关指令(一组指向词法封装堆栈帧的指针,在Algol风格)。
但您/编译器不必为此目的使用EBP。在具有少量寄存器(x86)的机器中,具有另一个空闲寄存器可以帮助生成更小/更紧密的代码。在较旧的CPU上,不使用EBP有一个不同的惩罚:局部变量ESP的索引偏移量往往大于堆栈帧基数的索引偏移量,因此使用EBP作为自由寄存器可以通过更大的偏移量获得更大的程序用于ESP。这在获取指令时很重要。随着指令缓存尽可能好,这几乎不再是一个问题。微软的C编译器(我怀疑是GCC)有一个不使用帧指针的开关,从而放弃了一些程序大小以便更快地编写代码。
堆变量只是那些不在堆栈帧中的变量。您可以使用任何寄存器来访问它们。
某些语言(例如我们的PARLANSE编译器)仅使用堆分配;甚至堆栈帧都是从堆中获取的(并且ESP被设置为分配的空间块的顶部)。
答案 1 :(得分:6)
通常,ESP指向堆栈顶部,EBP指向堆栈框架的底部,因此它们都指向堆栈上的地址,而不是堆上的地址。在大多数情况下,并不是完全有必要保持指向堆栈框架底部的指针,因此一些编译器可能只是使用EBP作为另一个通用寄存器。
ESI和EDI是通用寄存器,但有一个例外:字符串指令(例如movs,lods)分别将它们视为源地址和目标地址。
答案 2 :(得分:1)
整个内存分为4个部分。代码,数据,堆栈和额外。堆用于多用途存储(如动态分配(malloc等)),而堆栈专门用于指令指针和在调用另一个过程时存储变量(如递归过程中)。数据段用于全局变量和静态变量。
对于ESI / EDI请参阅SO:Purpose of ESI & EDI registers?
上的这个问题编辑:也看到了这一点:heap vs data segment vs stack allocation
答案 3 :(得分:1)
虽然有些内容和行为特定于寄存器xBP
,xSI
和xDI
,但它们并未绑定到任何一个函数。您可以在汇编代码中使用它们。