在intel software developers manual volumen 2A chapter 2.1.2中说
用于通用和SIMD指令的两字节操作码格式 由以下之一组成:
- 一个转义操作码字节0FH作为主要操作码,另一个操作码字节。
- 强制性前缀(66H,F2H或F3H),转义操作码字节和第二个操作码字节(与上一个项目符号相同)。
什么是“转义操作码”,其目的是什么?
答案 0 :(得分:6)
通常,“转义”代码是一种修改下一个字节/符号的含义的代码,而不是自己的含义。
例如,在ASCII键盘输入中(例如在Linux终端上),alt +字母通常作为转义+字母发送。 (在ASCII ESC character is 0x1b
的位置,因此如果我运行hd
(十六进制转储)并在其中键入 alt + x ,我将得到1b 78
从那一次修改的击键中。
或者在双引号C字符串中,n
只是一个普通字母。但是\n
的含义有所不同:它是换行符,仍然是单个字符(在编译器处理转义序列之后)。反斜杠转义了n
,因此意味着其他含义。
x86机器码具有许多单字节操作码(例如00
ADD r/m8, r8
),但是某些字节值(例如0F
)是多字节操作码的第一个字节,而不是完整的操作码
通过使用一个单字节操作码(0f
)提供另外256个2字节操作码,扩展了256种可能的操作码(加上ModRM字节的/ r字段中的重载)的编码空间。 / p>
例如0F AF
is IMUL r32, r/m32
和0F B6
is movzx r32, r/m8
。这些通用指令是在最初的8086之后引入的,没有足够的编码空间来提供单字节操作码。 (或者英特尔正在将其保存以用于将来的转义序列。)
强制性前缀,例如66
,是一个扩展编码空间以允许对更多不同操作码进行编码的类似想法,使用在其他上下文中具有不同含义的字节,而不仅仅是转义字节(出现在操作码的开头)。
当这些字节与有意义的操作码一起使用时,这些字节是操作数大小的REP/REPE, and REPNE前缀。但是对于某些指令,这些前缀没有是有意义的:操作码已经隐含了单个操作数大小,并且它不是字符串指令。 (请注意,address-size前缀和segment-override前缀可以应用于具有显式内存操作数的任何指令,因此不能用作强制性前缀。lock
都不是。)
诸如MMX 0F FC paddb mm0, mm1/m64
之类的指令已经具有固定的SIMD操作数大小。这些前缀都没有意义。英特尔选择(针对SSE2)制作XMM版本66 0F FC PADDB xmm1, xmm2/m128
,并在MMX编码中添加操作数大小的前缀。
类似地,F3 0F 59 MULSS xmm1,xmm2/m32
是mulps
+ REP前缀。
英特尔已将rep
用作某些非SIMD指令的必需前缀。例如pause
是rep nop
,tzcnt
是rep bsf
(这很有趣,因为它们在具有或不具有BMI1的CPU上执行相同的操作,除非输入为零)。这允许向后兼容,因为通常CPU会忽略他们不理解为应用的REP前缀。
(尽管有意将不适用的REP前缀用作填充,但这并不是将来的证明,因为编码可能会在将来的CPU中获得某些含义。但是,当既知道旧含义又知道新含义时,英特尔通常会确保所有旧CPU解码{ {1}}就像rep nop
一样,可以安全地在自旋循环中使用nop
,而无需检查CPUID功能位。)