assembly - 堆栈写入顺序和代码执行顺序
问题描述
我正在阅读一本 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。
书中写的是正确的(在这种情况下我遗漏了一些东西),还是我所经历的实际上符合事实,因此在书中(至少在意大利语版本中)有错误?
解决方案
堆栈现在位于 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,则操作将覆盖程序代码。
推荐阅读
- sql - 如何按包含 Presto 列表的列过滤数据框?
- php - Laravel 和 PostgreSQL 的行级安全性
- c# - 处理测试类中的依赖注入
- python - 自定义图像分割在不同的模型加载 Pixellib 上有不同的结果
- graphics - NVIDIA Geforce GT 540M 未出现在物理设备列表中
- direct3d - MPO(多平面叠加)合成和 DWM 合成有什么区别?
- c# - 如何在包含字符串中包含通用行为
- r - 基于一个标识符列的条件聚合(在 R 中)
- javascript - (react-router-dom)在子组件中渲染元素无法识别 BrowserRouter
- react-native - 神秘的反应本机获取行为