首页 > 解决方案 > 堆栈写入顺序和代码执行顺序

问题描述

我正在阅读一本 1980 年代由 Peter Norton 和 John Sohna 撰写的名著,他们至少在意大利语版本中说:

给定一个没有为 STACK 保留的空间定义的汇编代码(因此代码中没有 .STACK 指令),通过汇编它,链接它,然后用 DEBUG 观察它的寄存器状态(直接来自 .EXE 文件),我们有以下:

A> DEBUG TEST_SEG.EXE
-R
AX = OOOO BX = OOOO CX = 0004 DX = OOOO SP = OOOO BP = OOOO SI = OOOO DI = OOOO
DS = 3985 ES = 3985 SS = 3995 CS = 3995 IP = OOOO NV UP EI PL NZ NA PO NC
3995:0000 B44C           MOV       AH, 4C
-

书上还说:堆栈现在在 3995:0,这是程序的开始(CS:O)。这绝对不好。堆栈绝不能靠近程序代码。此外,由于堆栈指针位于 SS:O 中,因此它没有增长空间(随着堆栈向下增长)。由于这些原因,您必须为 .EXE 程序定义一个堆栈段。

现在,我做了一些测试,我了解到堆栈是向下增长的(例如,从 0000h、FFFEh、FFFCh、FFFA 等),然后从最高地址到底部(最低地址)。相反,指令指针 (IP) 从最低地址(在示例中从 0000h)向更高地址增长。通过将数据插入堆栈并将代码添加到程序中,这两者将不会满足(至少在一段时间内),因为存在 64K 内存余量。

因此,在我看来,这个 .EXE 程序的行为或多或少就好像它是一个 .COM。

书中写的是正确的(在这种情况下我遗漏了一些东西),还是我所经历的实际上符合事实,因此在书中(至少在意大利语版本中)有错误?

标签: assemblystackdosx86-16real-mode

解决方案


堆栈现在位于 3995:0,这是程序的开始 (CS:0)。这绝对不好。堆栈绝不能靠近程序代码。

只要堆栈在代码之前,这绝对不是问题:

栈向下增长,栈指针先递减。(有些 CPU 类型push首先写入值然后更改 SP;在此类 CPU 上会出现问题。)

所以如果初始的 SS:SP 和初始的 CS:IP 都是 0:7C00 就没有问题了。(这是引导扇区的典型组合。)

此外,由于堆栈指针位于 SS:0 中,因此它没有增长空间。

这是对的:

在某些操作模式下,如果 SP 为 0,x86 CPU 不允许push(或call...)。

程序可能会简单地崩溃,而不是包装到 0xFFFE。

当然还有另一个问题:如果程序长于 64K 且 CS=SS,push如果 SP 从 SS:0 回绕到 SS:0xFFFE,则操作将覆盖程序代码。


推荐阅读