【问题标题】:16-bit assembly incompatibility with 64-bit windows 716 位程序集与 64 位 windows 7 不兼容
【发布时间】:2013-10-04 01:32:40
【问题描述】:

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

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

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

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

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

【问题讨论】:

标签: assembly compatibility windows-7-x64 16-bit


【解决方案1】:

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

【讨论】:

  • 这并不是一个真正不同的指令集,是吗?它都在 x86 intel CPU 上运行。
  • 是的,它是不同的指令集。 32 位和 64 位各有一组不同的(更宽的)寄存器和用于操作它们的不同指令。在某些情况下,指令的实际操作码是相似的,但它们的工作方式不同,例如,它们现在支持访问更广泛的寄存器。
  • 在不评论为什么的情况下投反对票是不礼貌的……想解释一下这个答案有什么问题吗?
  • 好吧,我还没有完全明白,但为了推动讨论,我将把细节放在后面。假设我有源代码,我应该寻找什么来确保被 windows 接受?
  • 您必须使用针对 32 位或 64 位指令集的编译器进行编译。
【解决方案2】:

安装 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 程序,而这些程序是不同的。不是直截了当的翻译——更像是移植。

【讨论】:

  • 这不是操作数和精度大小覆盖前缀的目的吗?
  • 如果您以 32 位机器为目标但使用 16 位寄存器,汇编器将生成它们。默认情况下,它们不会出现在已编译的 16 位代码中。
【解决方案3】:

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

【讨论】:

    【解决方案4】:

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

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

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

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

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

    【讨论】:

    • 虽然这是一个明确的解释,但它并不能完全回答我关于 Windows 如何检测它无法运行代码的问题。毕竟,它只是一组十六进制值。
    • @Erik:好的,修改了答案,希望这是你现在要找的。​​span>
    • 谢谢,你是第一个真正回答我问题的人。
    【解决方案5】:

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

    Microsoft 显然拥有可用的技术 - 它被描述为 HERE,但不允许它在 Home* 版本上运行。

    【讨论】:

      【解决方案6】:

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

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

      我认为问题应该是:究竟是什么让程序可以在 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 位寄存器的代码,采用了另一种保护模式,称为 long 模式。我对这种长模式了解不多,但据我阅读,这种模式不允许处理器使用 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 位,必须设计(或购买)一个全新的 DOS 子系统。

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

      【讨论】:

      • 感谢您花时间更改我的问题并回答该问题。但是,如果我了解 stackoverflow 的工作方式;你应该回答提出的问题,而不是把它改写成更方便的问题。
      • 即便如此,我已经回答了您最初的问题。是什么使代码成为 16,32 或 64 位:它使用的寄存器集。导致不兼容的原因:缺少 DOS 子系统/个性。
      猜你喜欢
      • 1970-01-01
      • 2013-03-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-06-12
      • 1970-01-01
      相关资源
      最近更新 更多