4

我最近发现 64 位窗口不会运行 16 位应用程序(在这种情况下是 .com),因为 64 位窗口没有 16 位子系统(或者互联网上这样说)。我在尝试执行需要 EDIT 的 .bat 文件时遇到了这个问题。

我在 x86 汇编方面有相当多的经验,但从未编写过在 Windows(或任何其他操作系统)下运行的程序。由于 x86 系列的向后兼容性,我从来没有真正关注过我的程序有多少位。只要它不使用未引入程序必须运行的 CPU 的指令,就可以了。

我的问题是:究竟是什么使代码成为 16、32 或 64 位,是什么触发了 16 位应用程序显然存在的不兼容问题?

是否可以拆卸小型 16 位应用程序并进行一些更改以使其正常工作,或者这真的不明智吗?

更新:我不是在寻找一种方法来运行这些类型的应用程序,即通过模拟器或其他程序,我可以自己解决。我只想了解使 Windows 接受或拒绝程序的基本机制。

4

6 回答 6

6

要运行“16 位应用程序”,在本例中是指 DOS 应用程序,Windows® 需要在 VM86 模式下设置任务。问题在于,当 CPU 处于 i386 操作系统所使用的 32 位 VPAM(虚拟保护地址模式)时,此方法有效,但当 CPU 处于 AMD 引入的所谓“长模式”时则无效。amd64 CPU“长模式”只支持运行32位和64位任务。

因此,64 位操作系统内核无法直接在 CPU 上运行 16 位任务,您始终必须使用某种仿真。如果你找到一个可以做到这一点的操作系统,它要么具有内置的仿真,要么运行在 32 位模式而不是 64 位模式下,或者同时运行在 32 位和 64 位模式下并在两者之间愉快地切换我在某处读到过一些邪恶的、扭曲的黑客行为。

根据经验,使用 DOSBOX 是您最好的选择。

编辑:Windows® 如何检测到它无法运行您的代码?

这在很大程度上取决于检测到的程序类型。有它知道要处理的批处理文件( BAT, ),文件(我认为它们仍然没有杀死它们),最后还有可执行文件。案例很简单:最大 65280 字节。16 位 MS-DOS® 程序,输出。另一方面,文件具有某些文件头:一个用于 16 位 DOS(或 Win3.x)部分(关键字:MZ),一个用于 32 位/64 位部分(LE、LX、PE(至少),a.out 和 COFF 是这里的关键字,其中一些用于 OS/2 兼容性或仅由它使用,一些用于各种 NT 变体)。CMDPIFCOMEXECOMEXE

于 2013-12-06T20:54:04.737 回答
2

其实问题不止一个。首先,处理器对每个“位数”都有不同的操作模式。但是每种类型的应用程序都需要一个超越位数的执行环境。它被称为应用程序二进制接口(ABI)。例如,.com 文件包含需要实模式 DOS 环境的代码,包括某些硬件。早期版本的 windows 需要启动类似于 DosBox 的东西才能运行它们。每种类型的可执行文件可能不需要完整的硬件仿真,但需要大量代码来与主操作系统交互。因此,对于每种类型的可执行文件,操作系统都会检查需要什么样的运行时环境,并拒绝运行可执行文件,除非它可以提供正确的环境。

于 2013-10-15T02:32:29.780 回答
1

我的问题是:究竟是什么使代码成为 16、32 或 64 位,是什么触发了 16 位应用程序显然存在的不兼容问题?

好吧:显而易见的答案是:取决于使用 8、16、32 或 64 位寄存器的程序。显而易见但不正确:如果处理器支持,在 MS DOS 中运行的程序可以使用 8,16 或 32 位寄存器。或者,除了使用 32 位寄存器和(如果处理器和操作系统支持)64 位寄存器之外,Windows 程序还可以使用(并且确实使用)8 位和 16 位寄存器。

我认为问题应该是:究竟是什么让程序能够在 DOS 或 Windows 32 位或 Windows 64 位下运行。

首先,可执行文件的结构。32 位或 64 位 Windows 可执行文件与 16 位可执行文件不同。Windows 使用所谓的“Portable Executable”(PE 的缩写)。MS DOS 使用 .COM 文件(继承自 CP/M)和 .EXE 文件(也称为 MZ 可执行文件)。

第二:程序存储在内存中并开始执行,程序期望存在一些环境,例如,由特殊指令(如 INT)访问的一组函数调用,它们负责执行不同的任务,从将字符输出到控制台,打开和读取文件等等。

第三:MS DOS 应用程序期望内存中的某些结构位于特定的内存地址;例如屏幕内存。它还期望某些 I/O 设备存在于特定的 I/O 地址。许多所谓的“不良行为”应用程序不使用 BIOS 或 DOS 在屏幕上打印,而是直接写入屏幕内存,以获得更快的输出。我记得 Turbo Pascal、Turbo Basic 或 Turbo C 编译器中的一个设置,让程序员选择控制台输出功能通过 BIOS,或直接进入硬件。

第四:程序期望处理器以特定方式运行。16 位 DOS 程序被设计为使用所谓的 x86 处理器实模式,并且这种模式强加了其对内存地址的特定视觉,这是该模式最显着的特征。随着将处理器置于保护模式的 32 位操作系统的到来,实模式程序无法工作,因为内存地址在保护模式下的工作方式与实模式下的工作方式非常不同。

愿意运行 MZ 可执行文件的操作系统需要某种类型的文件加载器(以符合第一点)和必须模仿应用程序应该工作的环境(以符合其余点)。在 Linux 世界中,这些组件是他们所谓的个性的一部分(Linux 运行来自其他操作系统(如 FreeBSD)的代码的一种方式,前提是该代码适用于两个平台上的相同处理器)。在 Windows 世界中,这称为子系统。例如,Windows XP 和 Windows 7 具有Win32子系统和DOS子系统。古代版本的 Windows(可能是 Windows NT 3.5 或 NT 4.0)有一个OS/2个性太强,能够运行 OS/2 16 位文本模式应用程序。

因此,您的 Windows 操作系统需要适当的子系统来运行为其他操作系统(如 MS DOS)设计的代码。但是处理器必须以任何可能的方式提供帮助。这是因为 x86 平台在 80386 中引入了8086 虚拟模式:能够创建一个任务,其中处理器的行为很像 8086 实模式。

因此,在 CPU 本身的帮助下,适当的加载程序,一个能够将 DOS 请求转换为 Windows 请求的 INT 处理程序,一个能够捕获对特定内存部分的访问并将其转换为在屏幕上绘制字符的请求的智能页面处理程序,和一个 I/O 故障处理程序,能够模拟应用程序使用的设备,为 DOS 编写的程序可以在 Windows 或 Linux (DOSemu) 下运行

那么,64 位会发生什么?对于能够访问 64 位寄存器的代码,使用了另一种保护模式,称为长模式。我对这种长模式了解不多,但从我阅读的内容来看,这种模式不允许处理器使用 8086 虚拟模式创建任务。还有另一种称为兼容模式或类似模式的模式,它允许处理器创建 64 位和 32 位任务,但不能创建 8086 虚拟模式任务。

如果没有 CPU 帮助,DOS 子系统很难实现:您可以模仿内存映射,捕获对特殊内存区域或 I/O 的任何访问,捕获 INT 指令,但除此之外,您应该捕获任何更新段寄存器的尝试为了尝试模仿实模式寻址,我实际上不确定段是否在长模式下使用。这是可行的,像 DOSBox 这样的应用程序证明了这一点,但微软不再需要 DOS(它已经很长时间不需要它了,但是客户可能直到 Windows 2000/XP 的推出才分享他们的观点) . Windows 7 32 位可以使用与以前的 Windows 版本相同的 DOS 子系统(我什至前段时间读过关于将 OS/2 子系统带回 Windows 2000 或 Windows XP 的黑客攻击),但对于 Windows 7 64 位,

更多信息:http: //www.codeproject.com/Articles/45788/The-Real-Protected-Long-mode-assembly-tutorial-for#Main

于 2013-12-14T03:45:54.277 回答
0

安装 DOSBox 并玩得开心。它是免费的http://www.dosbox.com/

编辑:

代码的位数意味着对寄存器/操作数大小的假设。另一方面,CPU 的当前“位数”在实模式下为 16,而在保护模式下,它是内存结构中的一个标志,用于描述当前正在执行的代码段(段描述符和/或页条目) ,准确地说)。操作系统设置所述内存元数据并维护位数。根据后者,相同的命令位可能意味着

add ax, bx

或者

add eax, ebx

或者

add rax, rbx

CPU 的位数和代码的假设更好地匹配。如果他们不这样做,应用程序很快就会崩溃或行为不端。一旦代码试图从内存中加载一个寄存器,而 CPU 级别的寄存器大小不是代码认为的那样,CPU 就会加载垃圾(或无法加载寄存器的一部分)。想象一下在 32 位模式下会发生什么:

MyData dw 0x17 ;2 bytes of data
SomeOtherData dw 0x200 ;2 more
...
mov ax, [MyData] ;We think we mean AX, but the CPU thinks it's EAX

EAX 将加载 0x2000017 的值。绝对不是程序所期望的。现在想象程序将值与 0x17 进行比较,并基于此进行条件跳转。

可以手动将 16 位实模式汇编转换为 32 位保护模式,但它不仅仅是转换寄存器名称。您必须从 DOS 程序转到 Windows 程序,而这些程序是不同的。不是直截了当的翻译——更像是移植。

于 2013-09-27T17:11:43.870 回答
0

一般的方法是使用模拟器,例如DosBox。没有办法改变二进制文件以使其使用不同的指令集运行。这必须从源代码开始。

于 2013-09-27T17:11:07.353 回答
-1

这纯粹是一个商业决定——根本没有技术原因,事实证明,你的机器本身可以运行 64 位或 32 位版本的 windows7——你的选择,然后你可以运行微软的 XP 模拟器,它将运行.COM文件。

微软显然拥有可用的技术 - 它在此处进行了描述,但不允许它在Home*版本上运行。

于 2013-12-14T02:38:51.343 回答