【问题标题】:Why run 16-bit programs on x86 operating systems get slower?为什么在 x86 操作系统上运行 16 位程序会变慢?
【发布时间】:2013-11-22 13:18:05
【问题描述】:

我正在研究一些关于汇编的东西,我正在阅读的材料,作者说为16位编译的程序在x86操作系统上旋转更慢,x64也是如此,32位编译的程序运行更慢x64...

为什么会这样? 在计算机内存和处理器中发生了什么,使 16 位或 32 位机器的程序分别在 32 位和 64 位中旋转得更慢?

【问题讨论】:

  • 简短回答:因为 CPU 已针对最近构建的代码进行了优化,而牺牲了旧的遗留代码。

标签: memory memory-management assembly


【解决方案1】:

关于 16 位程序在 32 位系统中运行速度较慢,我可以告诉你。 当 Intel 从 16 位到 32 位时,他们不得不扩展指令集以应对新的 32 位寄存器,但要保持与 16 位程序的二进制兼容性。

为了实现这一点,他们添加了一个前缀 66h,如果我没记错的话,当应用于任何使用 16 位寄存器的指令时,会使该指令使用 32 位寄存器。

例如,一个 16 位指令,如 MOV AX,BX,以 66h 为前缀,变成 MOV EAX,EBX

但这会对新的 32 位指令施加惩罚,因为它们至少需要一个额外的内存获取周期才能执行。英特尔随后创建了所谓的 32 位段和 16 位段。

基本上,任何一段代码都必须驻留在代码段中。在80386之前,所有段都使用16位指令,并且假设所有指令都使用16位寄存器。

Intel 的 32-segment 也包含代码,但是这次假设每条指令都使用 32 位寄存器,所以在 32 位段中,MOV EAX,EBX 的操作码与 MOV AX 的操作码相同, 16 位段中的 BX。

这允许程序不必为每条 32 位指令使用 66h 前缀。不再有任何处罚。

但是...如果我必须在包含在 32 位段中的程序中使用 16 位寄存器怎么办?那些使用 16 位寄存器的指令必须使用前缀 66h。

所以:使用 16 位寄存器的指令在 16 位段中没有前缀,在 32 位段中没有前缀。使用 32 位寄存器的指令在 32 位段中不加前缀,在 16 位段中加前缀。

此外:从 Pentium 处理器开始,我们有两条用于并行执行指令的管道。要使用这些管道,进入它们的指令必须属于 Intel 命名的“RISC 核”:指令的子集,不再作为 CPU 内部的微程序执行,而是使用有线逻辑。你猜怎么了?带前缀的指令和使用 16 位寄存器在 16 位段中执行的代码不属于该组,因此不能与另一组并行执行。当一条带前缀的指令成功进入其中一条流水线时,另一条流水线就会停止,从而影响 CPU 的性能。

【讨论】:

    【解决方案2】:

    关于“程序旋转得更慢”……嗯……程序不是“旋转”,而是“被执行”。如果你在谈论位旋转指令......好吧。碰巧 8086 有两种版本的位旋转指令:一种使用中间参数指定要旋转的位数,另一种使用寄存器(通常为 CX / ECX)来指定。

    问题是 8086 处理器不允许中间参数为 1 以外的任何其他值(但 CX/ECX 中的值可以大于 1)。 80386 和更高版本的处理器允许使用任何其他值作为中间操作数。此外,32 位处理器仅使用指定旋转量的操作数的低 5 位,因此操作不会超过 31(将 32 位寄存器旋转超过 31 次是没有意义的)。 8086 处理器不会施加此限制,因此会花费更多时间进行操作。

    我真的不知道这是否是您的书所说的“旋转得更慢”的意思。我记得旋转操作只能在其中一个管道中执行,不能同时在两个管道中执行,所以两个连续的旋转指令不能配对。

    【讨论】:

      【解决方案3】:

      我不确定您所说的旋转(装配操作?)是什么意思,但总的来说这里可能有几个因素 -

      1. CPU 公司并没有真正致力于支持旧的遗留模式和 ISA 子集。 x87 就是一个很好的例子,任何不需要这种精度水平的东西最好使用 SSE/AVX 来处理性能关键任务,而不仅仅是因为矢量化。

      2. 每次 x86 CPU 公司增加其寄存器大小时,他们都会保留旧的寄存器集,并为更长的版本添加逻辑名称。兼容性需要要求旧操作仍然可以在相同的寄存器上工作,因此您现在可以在同一程序中写入 ah/al、ax、eax 和 rax。在其中一些情况下(即 8 位/16 位部分),这种兼容性将要求您的 CPU 在仅写入较低部分时保持寄存器的上部分完整,这样做会隐式引入合并操作,这可能会导致减速。更糟糕的是,您可能会引入错误的依赖关系,因为每次写入 16 位寄存器都需要您合并早期操作留下的上部。

      参见此处 - Why do most x64 instructions zero the upper part of a 32 bit register

      【讨论】:

        猜你喜欢
        • 2023-03-12
        • 2017-02-02
        • 2011-06-01
        • 2011-01-08
        • 2010-12-11
        • 2015-09-26
        • 2013-10-01
        • 2012-11-17
        • 2010-09-05
        相关资源
        最近更新 更多