【问题标题】:Is the i386 instruction "div ah" pointless?i386指令“div ah”没有意义吗?
【发布时间】:2020-11-26 03:23:27
【问题描述】:

来自https://www.felixcloutier.com/x86/div

    ...
    temp ← AX / SRC;
    IF temp > FFH
        THEN #DE; (* Divide error *)
        ELSE
            AL ← temp;
            AH ← AX MOD SRC;
    FI;
    ...

对于div ahSRC 将是ah。恕我直言,temp 将始终大于 FFH,因此将引发异常,因为:

  1. AX = 256*AH+AL
  2. 温度 = AX / AH = (256*AH+AL)/AH = 256 + AL/AH
  3. 温度超过FFH

我错过了什么吗?

【问题讨论】:

  • 你的推理似乎是正确的。
  • 是的。但这不像他们为每个操作数制作单独的指令(尽管某些指令确实对特定操作数有特殊编码)。仅仅因为您可以使用毫无意义的操作数并不意味着他们专门实现了该行为。

标签: assembly x86 i386


【解决方案1】:

没错,就像div edx 一样,它永远不会在没有故障的情况下使用。正如您所展示的,2N/N => N 位 div 不溢出其商的标准是 high_half(dividend) < divisor,因此使用 divisor = high(dividend) 将始终溢出(或除以零)。 Why "DIV EDX" in MASM always generates processor exception? 用另一种方式解释了同样的事情。

有趣的是,这是一种保证单指令的方式来提高 #DE,但不需要任何指令将值放入寄存器。

(在保护模式下,int 0 完全相同。例如,在 Linux 下,在用户空间中 int 0#GP -> SIGSEGV 因为对 IDT 条目的权限, 而实际的除法异常将#DE -> SIGFPE)。


正如 Jester 所指出的,编码仅占 F6 /6 div r/m8 的 2^5 种可能编码中的一种,仅计算 ModRM 字节(不是寻址模式可以使用的额外字节的巨大可能性)。

使其不可编码将在解码器中占用额外的晶体管。然后你如何处理这个 2 字节序列? #UD非法指令异常?这很愚蠢,只需让它在正常解码后引发#DE,并像任何其他div 指令一样到达执行单元。或者将它用于其他一些特殊的事情,比如mfence

div ah 的 2 字节机器码实际上意味着一些完全不同的单条指令,这可能不是一个明智的设计决定。无论如何,那艘船以 8086 航行,它将提高#DE,而不是#UD;任何改变都会打破这种向后兼容。由于为新操作码寻找新编码空间的侵入性较小(例如the illegal encodings of lds and les or whatever that VEX prefixes borrow),英特尔和 AMD 还没有陷入这种疯狂。那些 LES / LDS 32 位模式编码已经引发 #ud 而不是另一个例外,更重要的是有更多的备用位,因此 VEX 前缀有空间实际编码那些 2 或 3 字节前缀中的某些字段。

【讨论】:

  • (我可能应该提一下,8086 本身没有#UD 异常;每个字节序列都解码为something。另外有趣的事实是,异常地址始终是end 错误指令的结束,即使对于#DE,也不像后来的 CPU,错误地址是 div / idiv 的开头。所以 8086 可能甚至没有跟踪指令的开始位置,并且它可以在操作码之前处理无限数量的前缀。不像后来的 CPU 将指令长度限制为最大 15 个字节,否则 #UD)
猜你喜欢
  • 2011-07-16
  • 2014-05-28
  • 1970-01-01
  • 2021-06-20
  • 1970-01-01
  • 1970-01-01
  • 2011-02-17
  • 2010-11-12
  • 2022-12-11
相关资源
最近更新 更多