热门问题
时间线
聊天
视角

栈寄存器

来自维基百科,自由的百科全书

Remove ads

栈寄存器微处理器中,处理调用堆栈寄存器。在以累加器为基础的处理器中,栈寄存器可能是某个特定的寄存器。若是有多个通用寄存器的处理器架构,栈寄存器可能是某个依惯例保留的寄存器,像是IBM System/360z/Architecture英语z/Architecture架构以及RISC架构,也有可能是用副程序调用或程序返回指令,硬编码的寄存器,例如PDP-11VAXIntel x86架构。有些处理器(像Data General Eclipse英语Data General Eclipse)没有专用的栈寄存器,而是用保留的硬件存储器位置来处理此功能。

在1960年末期以前的处理器(例如PDP-8HP 2100英语HP 2100)没有可以支持递归调用的编译器。其程序调用指令会将目前程序指针位置存储在跳跃地址,接着将程序指针设置为下一个位置[1]。此作法比维护栈简单,因为每一个副程序只会有一个返回地址,但除非程序作大幅相关更动,此作法无法支持递归调用。

栈结构机器(Stack machine)可能会有二个或多个栈寄存器,其中有一个处理调用堆栈,其他寄存器则处理其他堆栈

Remove ads

x86的栈寄存器

x86架构16位的处理器里,主栈寄存器是16位的栈指针(Stack Pointer,SP), 32位的IA-32里,扩展为32位的扩展栈指针(Extended Stack Pointer, ESP),64位的X86-64里,扩展为64位的寄存器栈指针(Register Stack Pointer,RSP)。栈区段寄存器(stack segment register,SS)会存储目前执行程序调用堆栈存储器分段相关信息。SP会指向目前栈的最顶端。默认情形,栈会以存储器减少的方式成长,因此比较新的资料会放在较低的存储器位置。PUSH指令可以将值存在栈里,因此栈会增加一个资料,POP指令可以提取栈中的信息,并且栈会减少一笔资料。

假设SS = 1000h,SP = 0xF820,这表示目前的栈顶是在实体地址0x1F820(这是因为Intel 8086的存储器分区机制),接下来的二个机器代码是

PUSH AX
PUSH BX
  • 第一个指令会将AX(16位寄存器)的值放在栈内,SP数值会减2。
  • 新的SP值是0xF81E。CPU会将AX的值复制到0x1F81E.
  • 执行PUSH BX时,会设置SP为0xF81C,将BX的值复制到0x1F81C[2]

上述就是PUSH运作的原理。一般来说,程序将寄存器的资料PUSH到栈是有其目的,例如调用会更改寄存器值的副程序。若要提取栈中的程序,可以用以下的机器代码

POP BX
POP AX
  • POP BX将0x1F81C位置的字符(是BX原来的值)复制到BX,接着将SP加2,SP值是0xF81E。
  • POP AX将0x1F81E位置的字符复制到AX,接着将SP加2,SP值是0xF820[nb 1][nb 2]
Remove ads

栈机

较简单的处理器会将栈指针存储在一般的硬件寄存器,用算术逻辑单元(ALU)来处理其数值。一般来说push和pop会翻译为多个微指令,去增加或减少栈指针,处理存储器的读取和写入[3]

较新的处理器会有专用的栈机(stack engine)以优化栈操作。Intel的Pentium M是第一个有栈机的x86处理器,其实现方式是将栈指针分为两个寄存器:ESPO是32位的寄存器,ESPd是8位的偏移值,会依栈操作而更新其数值。PUSH、POP、CALL和RET微指令直接对ESPd运作。若If ESPd接近溢出,或是ESP寄存器被其他指令更新(而ESPd ≠ 0),此时会插入同步的微指令,用ALU更新ESPO,并且让ESPd为0。在后续的Intel处理器中,此机制大致保留,不过将ESPO扩展到64位[4]

AMD K8微处理器使用一种类似于Intel栈机的作法。在其推土机微架构中,不需要加入同步的微指令,但不清楚其栈机的内部设计[4]

Remove ads

注解

参考资料

Loading related searches...

Wikiwand - on

Seamless Wikipedia browsing. On steroids.

Remove ads