'instruction prefixes' 在现代 x86 中是什么意思

What do 'instruction prefixes' mean in modern x86

为了了解 Bulldozer 为何低于标准,我一直在阅读 Agner Fog 的优秀微体系结构书籍,在第 178 页的 bulldozer 下有这一段。

Instructions with up to three prefixes can be decoded in one clock cycle. There is a very large penalty for instructions with more than three prefixes. Instructions with 4-7 prefixes take 14-15 clock cycles extra to decode. Instructions with 8-11 prefixes take 20-22 clock cycles extra, and instructions with 12-14 prefixes take 27 - 28 clock cycles extra. It is therefore not recommended to make NOP instructions longer with more than three prefixes. The prefix count for this rule includes operand size, address size, segment, repeat, lock, REX and XOP prefixes. A three-bytes VEX prefix counts as one, while a two-bytes VEX prefix does not count. Escape codes (0F, 0F38, 0F3A) do not count.

当我搜索前缀时,我遇到了远远超出我能力范围的非常技术性的定义。或者,建议将它们限制为每条指令 4 个,这与上述摘录冲突。

所以简单来说,有人可以解释一下他们 are/do 的内容,以及为什么您可能想要将最多 14+ 附加到一条指令上而不是将其分解?

通常情况下,您可以根据需要使用多少,具体取决于预期的指令和操作数。汇编程序会自动发出一些前缀,而另一些则需要您手动使用。

他们提到的案例是针对多字节 NOP 的,它传统上用于对齐填充,其想法是使用单个但适当长的指令来节省资源。显然,事实证明,使用更多前缀只是为了保持一条指令可能比使用两条前缀更少的指令性能更差。

The prefix count for this rule includes operand size, address size, segment, repeat, lock, REX and XOP prefixes. A three-bytes VEX prefix counts as one, while a two-bytes VEX prefix does not count.

示例:

  • 操作数大小:可以在32位和16位寄存器之间切换,例如mov ax, [foo] 的编码与 mov eax, [foo] 相同,但前缀为 66h
  • 地址大小:可以在 32/16 或 64/32 位地址大小之间切换,例如mov [eax], foo 的编码与 mov [rax], foo 相同,但前缀为 67h(在 64 位模式下)
  • 段:可以覆盖使用的段,例如mov [fs:eax], foo 的编码与 mov [eax], foo 相同,但前缀为 64h.
  • repeat:与字符串指令一起使用,用于重复,例如rep cmpsb 的编码与 cmpsb 相同,但前缀为 f3h
  • lock:与某些指令一起使用,使它们成为原子,例如lock add [foo], 1 的编码与 add [foo], 1 相同,但前缀为 f0h
  • REX.W:用于切换到 64 位操作数大小,例如add rax, 1 的编码与 add eax, 1 相同,但前缀为 48h
  • REX.R,B,X:用作 modr/m 字节的扩展以访问额外的寄存器,例如add r8d, 1add eax, 1 相同,但前缀为 41h
  • XOP、VEX:与向量指令子集一起使用

"four prefixes" 交易来自 "prefix groups":

  1. lock/rep/repne
  2. 段覆盖
  3. 操作数大小覆盖
  4. 地址大小覆盖

您可以重复前缀,但不能(可以,但行为未定义)使用来自同一组的多个不同 前缀。虽然这只适用于第 1 组和第 2 组,但其他组每组只有 1 个东西。

类似 66 66 66 66 66 66 66 66 90 的内容有效(但解码速度可能较慢)。 2E 3E 00 00(混合段覆盖)不是。

当必须执行字节时,堆栈前缀对于代码对齐很有用,与使用 nop 填充不同,它不会花费执行时间。一次使用太多可能会花费解码时间。