'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, 1
与 add eax, 1
相同,但前缀为 41h
- XOP、VEX:与向量指令子集一起使用
"four prefixes" 交易来自 "prefix groups":
- lock/rep/repne
- 段覆盖
- 操作数大小覆盖
- 地址大小覆盖
您可以重复前缀,但不能(可以,但行为未定义)使用来自同一组的多个不同 前缀。虽然这只适用于第 1 组和第 2 组,但其他组每组只有 1 个东西。
类似 66 66 66 66 66 66 66 66 90
的内容有效(但解码速度可能较慢)。 2E 3E 00 00
(混合段覆盖)不是。
当必须执行字节时,堆栈前缀对于代码对齐很有用,与使用 nop
填充不同,它不会花费执行时间。一次使用太多可能会花费解码时间。
为了了解 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, 1
与add eax, 1
相同,但前缀为41h
- XOP、VEX:与向量指令子集一起使用
"four prefixes" 交易来自 "prefix groups":
- lock/rep/repne
- 段覆盖
- 操作数大小覆盖
- 地址大小覆盖
您可以重复前缀,但不能(可以,但行为未定义)使用来自同一组的多个不同 前缀。虽然这只适用于第 1 组和第 2 组,但其他组每组只有 1 个东西。
类似 66 66 66 66 66 66 66 66 90
的内容有效(但解码速度可能较慢)。 2E 3E 00 00
(混合段覆盖)不是。
当必须执行字节时,堆栈前缀对于代码对齐很有用,与使用 nop
填充不同,它不会花费执行时间。一次使用太多可能会花费解码时间。