x86 汇编 16 位与 8 位立即数编码

x86 assembly 16 bit vs 8 bit immediate operand encoding

我正在编写自己的汇编程序并尝试对 ADC 指令进行编码,我对立即值有疑问,尤其是在将 8 位值添加到 AX 寄存器时。

添加 16 位值时:adc ax, 0xff33 被编码为 15 33 ff,这是正确的。 但是,如果 adc ax, 0x33 被编码为 15 33 00 会很重要吗?

Nasm 将其编码为 83 d0 33 这显然是正确的,但我的方法是否也正确?

x86 通常有不止一种有效的指令编码方式。例如大多数 op reg, reg 指令都可以通过 op r/m, regop reg, r/m 操作码选择编码。

是的,通常您希望汇编程序始终为指令选择最短的编码。 NASM 甚至将 mov rax, 1mov r64, sign_extended_imm32 的 7 个字节)优化为 x86-64 的 mov eax, 1(5 个字节),将 operand-size 更改为使用 zero-extension 从写入 32 位寄存器而不是 32 位立即数的显式 sign-extension。

在可用时使用 sign-extended-imm8 编码总是好的

16 位的长度相等,但 32 位的长度较短 operand-size,因此它简化了您的代码以始终选择 imm8

对于 32 位的 operand-size,op eax, imm32 是 5 个字节,而 op r/m32, imm8 仍然是 3 个字节。 (不计算设置 operand-size 或其他东西所需的任何前缀;两者都是相同的。)

imm8编码的性能优势

如果需要 operand-size 前缀(例如,在 adc ax, 0x33 的 32 位模式下),使用带有 operand-size 前缀的 adc ax/eax/rax, imm16/32/32 编码将创建一个 LCP stall on Intel CPUs (Length-Changing Prefix 意味着前缀改变指令的 rest 的长度。这不会发生imm8 编码因为它仍然是 (prefix) + opcode + modrm + imm8 而不管 operand-size.

请参阅 Agner Fog's microarch.pdf and other performance links in the x86 tag wiki. See also ,这是一个副本,除了 adc 是一个特例。


adc/sbb 的特定情况下,避免 ax, imm16 编码还有另一个好处:参见 On Sandybridge through Haswell,adc ax, 0 是 special-cased 作为 single-uop 指令,而不是 3 输入 uop(ax,标志,立即数)的正常 2。

但是这种特殊的大小写不适用于 no-ModRM 短格式编码,所以 3 字节 adc ax, imm16 仍然解码为 2 uops。只有 imm8 形式的解码器在解码为单个 uop 之前检查立即数是否为零。 (它仍然不适用于 adc al, imm8。)

所以尽可能选择 sign-extended-imm8 也是最佳选择, 即使在没有 operand-size 前缀的 16 位模式下也是如此adc ax,0 是必需的,因此 LCP-stall 问题不会发生。


大多数汇编器不提供覆盖以避免 no-ModRM 短格式。在设计它们时,除了故意延长指令以在不在循环顶部或其他分支目标之前添加 NOP 的情况下获得对齐外,没有性能 use-case:

如果您正在设计一种新风格的 asm 语法,您可能会考虑使用 override 关键字对编码进行更多控制。对于现有设计,请查看NASM的strictnosplit关键字,以及GAS的{vex2}{vex3}{disp32}等"prefixes"

  • for nosplit 为 LEA 强制进行更长更有效的编码。
  • (GAS {disp32} 等,{load}{store} 选择 op r/m, rop r, r/m 你喜欢的编码。)

  • 在 64 位模式下,a32 mov eax, [0x123456] 与 no-modrm moffs 编码会导致 Intel CPU 上的 LCP 停止。对于绝对寻址,它比 modrm+SIB+disp32 短,但可能更慢。

  • Why NASM on Linux changes registers in x86_64 assembly NASM mov rax,1(5 字节)对比 mov rax, strict dword 1(7 字节)对比 mov rax, strict qword 1(10 字节 imm64编码)