从烟囱底部弹出



我正在制作一个有趣的操作系统,同时正在学习更多的Assembly。我学习了推送和弹出,正如我所理解的,弹出取堆栈上任何其他值之上的值,所以它得到最后一个推送的值。但我想知道,我们真的可以直接在堆栈底部弹出值吗(即第一个推送的值(?

类似:

push 'A'
push 'B'
push 'C'
pop bx ; Gets C

我想用A来代替C。(我处于16位模式,汇编程序是NASM,在标签中也有指定。(

试着在内存中写下堆栈的布局。您将看到,在堆栈中间"弹出"任何元素都需要在内存中打乱许多堆栈元素。处理器对此没有支持。但是,您可以在任何时候将堆栈上的任何元素加载到寄存器中,而无需弹出它(即,之后它仍将在堆栈上(。

为此,首先将堆栈指针复制到可用于寻址内存的某个寄存器中(bp是规范选择(,然后从中访问堆栈。

mov bp, sp      ; make the stack accessible
mov bx, [bp+4]  ; load stack element A into bx

通常,bp是作为为当前函数建立堆栈帧的一部分而设置的,因此它始终可用于访问堆栈。您也可以使用寄存器bxsidi,但请记住,在这种情况下需要ss段覆盖(这对于bp是隐式的(。

现在,为什么我们必须添加4才能获得项目A?回想一下,堆栈向存储器中较低的地址增长(即,随着每个pushsp减少(,并且在16位模式中,每个堆栈槽占用2字节的存储器。因此,假设sp = 1000h在您的推送序列之后,我们有以下内存布局:

1004h  A
1002h  B
1000h  C  <-- SP

所以通过简单的算术SP + 4指向堆栈时隙A,SP + 2指向堆栈时隙B。

在16位模式中,没有sp相对寻址模式,但您可以将sp中的值复制到bp中,并使用bp相对寻址来访问A的位置。当然,这不会弹出A,但你可以读或写A。

这就是为什么x86函数的序言(函数启动代码(中经常有mov bp,sp的原因之一。一旦bp被设置为引用其堆栈,函数就可以访问其调用方使用bp相对寻址(bp+位移(推送的参数。

最新更新