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

时间:2016-02-13 12:28:48

标签: assembly x86 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+用于指令而不是分解?

2 个答案:

答案 0 :(得分: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位模式下)
  • 细分:可以覆盖使用的细分,例如mov [fs:eax], foo的编码方式与mov [eax], foo相同,但前缀为64h
  • 重复:与字符串指令一起使用以重复,例如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:与向量指令子集一起使用

答案 1 :(得分:5)

“四个前缀”交易来自“前缀组”:

  1. 锁/ REP / REPNE
  2. 段覆盖
  3. 操作数大小覆盖
  4. 地址大小覆盖
  5. 您可以重复前缀,但您不能(您可以,但行为未定义)使用同一组中的多个不同前缀。虽然这仅适用于第1组和第2组,但其他组中每组只有1件事。

    66 66 66 66 66 66 66 66 90之类的东西是有效的(但解码速度可能很慢)。 2E 3E 00 00(混合段覆盖)不是。

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

相关问题