热门问题
时间线
聊天
视角
栈寄存器
来自维基百科,自由的百科全书
Remove ads
栈寄存器是微处理器中,处理调用堆栈的寄存器。在以累加器为基础的处理器中,栈寄存器可能是某个特定的寄存器。若是有多个通用寄存器的处理器架构,栈寄存器可能是某个依惯例保留的寄存器,像是IBM System/360、z/Architecture架构以及RISC架构,也有可能是用副程序调用或程序返回指令,硬编码的寄存器,例如PDP-11、VAX和Intel x86架构。有些处理器(像Data General Eclipse)没有专用的栈寄存器,而是用保留的硬件存储器位置来处理此功能。
在1960年末期以前的处理器(例如PDP-8和HP 2100)没有可以支持递归调用的编译器。其程序调用指令会将目前程序指针位置存储在跳跃地址,接着将程序指针设置为下一个位置[1]。此作法比维护栈简单,因为每一个副程序只会有一个返回地址,但除非程序作大幅相关更动,此作法无法支持递归调用。
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
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
注解
参考资料
Wikiwand - on
Seamless Wikipedia browsing. On steroids.
Remove ads