【发布时间】:2020-12-25 14:36:33
【问题描述】:
我正在阅读 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、FFFFh、FFFA 等),然后从最高地址到底部(最低地址)。相反,指令指针 (IP) 从最低地址(在示例中从 0000h)向更高地址增长。 通过将数据插入堆栈并在程序中添加代码,这两者将不会相遇(至少在一段时间内),因为有 64K 的内存余量。
所以,在我看来,这个 .EXE 程序的行为或多或少就好像它是一个 .COM。
书上写的是正确的(在这种情况下我遗漏了一些东西),还是我所经历的实际上符合事实,因此在书中(至少在意大利语版本中)有错误?
【问题讨论】:
-
你是对的:堆栈就在代码段的下方。我不记得 DOS 是如何初始化 EXE 的,堆栈可能靠近 PSP 或在“未保留”区域。作为旁注,请注意非常古老的书籍及其翻译。
-
@MargaretBloom 与 .COM 文件(没有标题)不同,堆栈指针的初始位置在每个 .EXE 文件的标题中指定。
-
堆栈增长到较低的地址,并收缩到较高的地址,随着程序的运行而动态。然而,代码只在编译/链接时“增长”,而不是在运行时:一旦运行,程序代码的大小是固定的。 IP 寄存器动态地跟踪处理器正在运行的指令。有时我们将代码的当前结尾称为位置计数器,以区分增长代码的编译时间概念和指令指针的动态概念。
-
我不记得DOS内存分配的细节了,但是我们能确定3995:FFFE确实可供这个程序使用,而不是分配给另一个程序吗?如果没有,您可能刚刚覆盖了其他人的代码或数据。
-
@NateEldredge EXE 标头中的字段可以保证空间已分配给程序。如果链接器按照 rcgldr 的回答建议为堆栈分配空间,那么这些字段可能会设置为分配该空间。但是,我不确定这是否真的是 MS-DOS 链接器实际所做的。
标签: assembly stack dos x86-16 real-mode