【问题标题】:Assembly popping an empty stack汇编弹出一个空堆栈
【发布时间】:2015-10-05 07:51:34
【问题描述】:

我正在学习汇编,想知道当你弹出一个空堆栈或增加 SP(堆栈指针)时会发生什么,例如它已经是 FFFE:

seg1 segment 
       org 100h 
       pop ax
       mov ah,4ch 
       int 21h
seg1 ends

当我通过调试器运行程序时,我看到 SP 在执行 pop 命令后将指向 SP = 0000。为什么SP指向0000?是因为内存中的最大 SP 是 FFFF 并且它只是循环到第一点吗? (我知道SP只会增加或减少2,因为push和pop总是2字节) 执行命令时程序会在 SP = 0000 处弹出任何内容吗?

我正在使用 a86 宏汇编器,Oracle VM VirtualBox。 谢谢。

【问题讨论】:

    标签: assembly x86 a86


    【解决方案1】:

    这种效果称为“环绕”。 FFFE 加 2 就是 10000,但是第一个位被切掉了,所以结果是 0000。

    这对于签名操作非常有用:FFFE 等价于 -2。 -2 + 2 = 0。

    是的,下一个 pop 将加载 SS:0000 处的值并增加 SP,而 push 也会导致回绕并将值存储在 SS:FFFE。

    【讨论】:

      【解决方案2】:

      SP 是 16 位寄存器。

      当你 POP 时,SP 会添加“2”。 FFFE+2 产生值 0。

      这在旧架构(例如 X8086)上不会出错,并且可能 在 x86-32 中以 16 位实模式运行(我必须查看手册)。虽然它确实发生了,但您应该认为这是您的编程错误,因为它违反了堆栈指针的意图,即线性扫描堆栈区域。

      在保护模式下的 x86-32 或 -64 上,堆栈区域边缘的下降通常会产生非法内存访问,这是由于操作系统非常小心地将有效堆栈之外的区域标记为“无效”而引起的。

      【讨论】:

        【解决方案3】:

        您应该真正养成查阅 CPU 文档的习惯。应该都在里面。

        简而言之,在 16 位和 32 位 CPU 模式下,push 和 pop 通常不太关心堆栈指针寄存器的值,以用于递增或递减。寄存器值简单地环绕 0,与在任何其他通用寄存器中添加或减去值时的方式相同。唯一重要的是当访问堆栈内存时堆栈指针寄存器中的地址是否在堆栈段限制内。在实模式下,似乎是这种情况,所有段的大小为 64KB,并且从 0 到 0xFFFF 的所有偏移量都是有效的。因此,如果您的 SP 始终正确对齐(即,它是 2 的倍数),则压入或弹出单个 16 位字不会导致任何问题。但是,您应该记住,在实模式下,当前堆栈由中断服务例程使用,并且您应该始终为它们提供足够的空间(除非您在禁用中断的情况下进行操作)。您应该记住,代码中的错误可能会使堆栈指针指向代码或程序的数据,从而破坏它。

        【讨论】:

          猜你喜欢
          • 2019-08-08
          • 1970-01-01
          • 2020-11-28
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2016-10-20
          • 2021-07-15
          • 2012-04-05
          相关资源
          最近更新 更多