DOS 在运行时插入段地址

标签 dos x86-16 portable-executable relocation memory-segmentation

我注意到我正在编写的一些代码中存在潜在的错误。

我认为,如果我使用mov ax, segegment_name,该程序可能是不可移植的,并且只能在特定配置的一台计算机上运行,​​因为加载位置可能因计算机而异。

所以我决定在两台运行 DOS 的不同机器上反汇编一个只包含一条指令的程序,我发现问题神奇地解决了。

第一台机器上的调试输出:0C7A:014C B8BB0C MOV AX,0CBB

机器二上的调试输出:06CA:014C B80B07 MOV AX,070B

在十六进制转储程序后,我发现未改变的字节实际上是B84200

手动将这些字节插入到程序中会产生 mov ax, 0042

那么 PE 格式是否存储对这些指令的引用并在运行时更新它们?

最佳答案

正如 Peter Cordes 所指出的,MS-DOS 不使用 Windows 使用的 PECOFF 可执行格式。它有自己的"MZ" executable format ,以标识为这种格式的可执行文件的前两个字节命名。

MZ 格式通过包含重定位的重定位表支持使用多个段。这些重定位只是简单的段:偏移值,指示需要根据可执行文件在内存中加载的位置进行调整的 16 位段值的位置。 MS-DOS 通过简单地将程序的实际加载段添加到可执行文件中包含的值来执行这些调整。这意味着,如果不应用重定位,则可执行文件仅在加载到段 0 时才起作用,而这恰好是不可能的。

请注意,这不仅是程序在多台机器上运行所必需的,也是同一程序在同一台机器上可靠运行所必需的。加载地址可以根据各种配置详细信息以及已加载到内存中的其他程序和驱动程序进行更改,因此 MS-DOS 可执行文件的加载地址本质上是不可预测的。

从您的示例开始,我们可以知道您的示例程序在两台机器上加载到内存中的位置。由于 0042h 在第一台机器上被重定位到 0CBBh,在第二台机器上被重定位到 070Bh,因此我们知道 MS-DOS 分别在两台机器上的段 0C79h 和 06C9h 加载了您的程序:

0CBB - 0042 = 0C79
070B - 0042 = 06C9

据此,我们可以确定您的示例可执行文件在其重定位表中具有条目 0001:014D 或等效的段:偏移值:

0C7A:014D - 0C79:0000 = 0001:014D
06CA:014D - 06C9:0000 = 0001:014D

该条目指示需要调整的mov ax, seg segname指令的16位立即数操作数的未重定位位置。

关于DOS 在运行时插入段地址,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61862626/

相关文章:

linux - MS-DOS 设备的 MacOS 点文件删除

windows - 如何调试 .BAT 脚本?

c - 尝试在 borland C 中设置鼠标光标位置

assembly - intel 8086处理器标志寄存器中保留位和未定义位之间的区别

assembly - 如何在汇编中查找数组中的最小有符号值

windows - PE 文件格式 - 节表和第一节之间是什么?

batch-file - 在批处理 : Read only the filename from a variable with path and filename

assembly - 如何修复 “error:cannot generate COM file, stack segment present”?

通过将静态构建转换为特定于操作系统的二进制文件来跨操作系统构建

go - 在golang中打开超时的PE文件