assembly 从堆栈底部弹出

vngu2lb8  于 2022-11-13  发布在  其他
关注(0)|答案(2)|浏览(145)

我正在开发一个操作系统,同时还在学习更多的汇编语言。我学习了推入和弹出,正如我所理解的,弹出取栈中任何其他值的顶部,所以它得到最后一个推入的值。但我想知道,我们真的能直接弹出栈底的值吗(即第一个推入的值)?
如:

push 'A'
push 'B'
push 'C'

pop bx ; Gets C

我想用A而不是C作为例子。(我在16位模式下,汇编程序是NASM,也在标记中指定。)

mf98qq94

mf98qq941#

试着写下堆栈在内存中的布局。你会发现,“弹出”堆栈中间的任何元素都需要在内存中移动大量的堆栈元素。处理器不支持这一点。然而,你可以在任何时候将堆栈上的任何元素加载到寄存器中,而不弹出它(也就是说,它以后仍然在堆栈上)。
为此,首先将堆栈指针复制到某个可用于寻址内存的寄存器(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。

unftdfkk

unftdfkk2#

在16位模式下,没有sp相对寻址模式,但是你可以将sp中的值复制到bp中,然后使用bp相对寻址来访问A的位置,当然这不会弹出A,但是你可以读或写A。
这就是为什么x86函数在其序言(函数启动代码)中经常包含mov bp,sp的原因之一。一旦bp被设置为引用其堆栈,函数就可以使用bp相对寻址(bp +位移)来访问其调用者推送的参数。

相关问题