为什么某些 Windows 引导加载程序使用 `sub` 而不是 `xor` 来编码零寄存器?

Why does some Windows booloader code zero registers with `sub` instead of `xor`?

鉴于 中详述的考虑因素,xor reg, reg 似乎是将寄存器归零的最佳方法。但是当我检查真实世界的汇编代码(例如 Windows 引导加载程序代码,IIRC)时,我看到 xor reg, regsub reg, reg 都被使用了。

为什么 sub 完全用于此目的?在某些特殊情况下有什么理由更喜欢 sub 吗?例如,它设置的标志是否与 xor 不同?

在许多现代 x86 处理器上,xor reg, regsub reg, reg 都被识别为 归零习语 。两者的效果是一样的,使用一个比另一个没有优势。

差异:

  • sub reg,reg is documented to set AF=0 (the BCD half-carry flag, from bit 3 to bit 4). XOR 未定义 AF。架构效果在其他方面完全相同,只留下可能的性能差异。 AF 几乎无关紧要,通常只有在下一条指令是 aaa 或其他指令时才如此。
  • sub-归零在一些 CPU 上比异或归零慢(例如 Silvermont,正如 中指出的那样),但在大多数情况下性能相同。当然,两者都具有相同的 2 字节大小。

我猜这只是手写 asm 的不同作者,他们中的一些人更喜欢 sub 可能没有意识到有些 CPUs特例异或。除非他们想保证清除 AF 标志,否则 sub 可能是有意的。就像在可能使用 pushf.

之前初始化事物并希望 EFLAGS 的完全已知状态一样

使 AF 未定义的 XOR 仍然意味着它将是 0 或 1,您只是不知道是哪个。 (不像 C 未定义的行为)。实际结果可能取决于 CPU 模型、输入值,甚至可能是某处的一些杂散位。

在将 sub 识别为归零习语的现代 CPUs 中,它将为零,因此 CPU 可以完全相同地处理异或归零和子归零,包括FLAGS 结果。