现代x86中'指令前缀'的含义是什么

Lor*_*ndy 14 x86 assembly prefix

为了理解Bulldozer为什么不合格,我一直在关注Agner Fog的优秀微架构书,在第178页的推土机下它有这一段.

最多三个前缀的指令可以在一个时钟周期内解码.对于具有三个以上前缀的指令,会有非常大的惩罚.具有4-7前缀的指令需要额外14-15个时钟周期才能进行解码.带有8-11前缀的指令需要额外增加20-22个时钟周期,带有12-14前缀的指令需要额外增加27-28个时钟周期.因此,不建议使用超过三个前缀来延长NOP指令.此规则的前缀计数包括操作数大小,地址大小,段,重复,锁定,REX和XOP前缀.三字节VEX前缀计为一,而两字节VEX前缀不计.转义码(0F,0F38,0F3A)不计算在内.

当我搜索前缀时,我的技术定义远远超出了我的能力.或者,建议每条指令限制为4条,这与上述摘录相冲突.

因此,简单来说,有人可以解释他们是什么/做什么以及为什么你可能想要将多达14+用于指令而不是分解?

Jes*_*ter 11

通常情况下,您可以根据需要使用尽可能多的指令和操作数来确定.汇编程序会自动发出一些前缀,而其他人则可以手动使用.

他们提到的情况是多字节NOP,传统上用于对齐填充,其中的想法是使用单个但适当长的指令来节省资源.显然,事实证明,使用更多的前缀只是为了保持单个指令可能比使用两个前缀更少的指令更糟糕.

此规则的前缀计数包括操作数大小,地址大小,段,重复,锁定,REX和XOP前缀.三字节VEX前缀计为一,而两字节VEX前缀不计.

例子:

  • 操作数大小:可以在32位和16位寄存器之间切换,例如mov ax, [foo]编码mov eax, [foo]与前缀相同但编码方式相同66h
  • 地址大小:可以在32/16或64/32位地址大小之间切换,例如mov [eax], foo编码mov [rax], foo与前缀相同67h(在64位模式下)
  • segment:可以覆盖使用的段,例如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:与向量指令子集一起使用


har*_*old 5

“四个前缀”协议来自“前缀组”:

  1. 锁定/重复/重复
  2. 段覆盖
  3. 操作数大小覆盖
  4. 地址大小覆盖

您可以重复前缀,但不能(可以,但是行为未定义)可以使用同一组中的多个不同前缀。尽管这仅适用于第1组和第2组,但其他各组中只有1件东西。

类似的东西66 66 66 66 66 66 66 66 90是有效的(但可能会很慢地解码)。2E 3E 00 00(混合细分替代)不是。

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

  • @ zx485,你不能。“ 4个前缀”规则意味着最多只能有4个前缀是非冗余的,除了必须包含冗余前缀之外的任何前缀都可以。在任何情况下,只有11个不同的旧前缀,因此即使使用无效的组合,您也不能拥有12个非冗余前缀(除非您添加新的REX或VEX,但它们具有不同的规则)。 (3认同)