3

我正在学习汇编,想知道当你弹出一个空堆栈或增加 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。谢谢你。

4

3 回答 3

4

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

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

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

于 2015-10-05T08:38:42.613 回答
3

SP 是 16 位寄存器。

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

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

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

于 2015-10-05T08:39:33.613 回答
2

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

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

于 2015-10-05T08:38:32.707 回答