assembly x86-64非法两字节操作码的说明

gywdnpxw  于 2023-01-05  发布在  其他
关注(0)|答案(1)|浏览(159)

最近编写了一个C程序到Find Two-byte Illegal Opcodes for x86-64并将输出粘贴到https://pastebin.com/5xjjFea6
例如,下面是一些非法的两字节操作码

0x0f,0x04  0x0f,0x0a  0x0f,0x0b  0x0f,0x0c  0x0f,0x0e  0x0f,0x0f  0x0f,0x24  0x0f,0x25 0x0f,0x26  0x0f,0x27  0x0f,0x36  0x0f,0x37 0x0f,0xaa

我在谷歌上只找到了几个描述

0x0f,0x0b - ud2 - Generates an invalid opcode. 
 
0x0f,0x37 - getsec - Exit authenticated code execution mode.
 
0x0f,0xaa - rsm - Resume operation of interrupted program.
    • 问题**
  • 是否有文档解释大多数非法操作码?
  • 为什么会存在非法操作码?
  • 为什么它们在x86 - 64上不被当作NOP处理,或者分配给一些有用的东西?
unftdfkk

unftdfkk1#

#UD非法指令错误的存在是为了让您知道您试图运行此CPU不支持的指令。
对于大多数新指令,最好是旧CPU #UD在它们上出错,而不是默默地做错误的事情(或者什么也不做)。例如,getsecrsm不是您可以使用的指令,因为它们可能作为NOP运行,而不是执行您想要的操作。(有趣的事实:8086没有#UD错误;任何字节序列都将作为 * something * 执行。)
只有对于像prefetchw这样的推测性提示,或者其他回退有效的情况,你才希望旧CPU把它作为NOP运行,这样代码就可以不用检查就可以使用它。你通常可以在现有指令前面使用REP来实现这一点(比如pauserep nop)。
有足够的NOP等价操作码供将来使用;最好让其余未使用的编码空间实际上出错。
从CPU供应商的Angular 来看,有一些字节序列#UD错误意味着他们可以确保现有代码不会(意外地或故意地)依赖于它们作为长NOP工作,而不是使用推荐的编码。
是否有文档解释大多数非法操作码?
没有,除了英特尔说执行任何当前手册 * 没有 * 明确定义的东西的结果是不可预测的。我没有检查英特尔或AMD手册的措辞,但我认为他们说这是可能性之一。
请记住,他们 * 不是 * 记录特定的CPU,他们记录x86 - 64 ISA的方式鼓励人们创建向前兼容的程序,这些程序仍然可以在未来的CPU上正常工作,这些字节序列可能是目前尚未提出的新指令的一部分。

UD错误是许多字节序列在实践中的常见行为。但其他序列,比如指令上的rep前缀,如果它没有任何意义,通常会忽略rep前缀。这让CPU供应商引入了一个新的扩展,其中rep xyz表示其他含义(如rep bsf变为tzcnt,这对于非零输入产生相同的结果),在 * 那 * 点上,他们可以记录以前的CPU运行它的行为,只是普通的bsf。(或者对于pause,将rep nop作为nop运行)。

还有其他多个示例,但问题是,这种行为一直存在,只是在设置了一些CPUID功能位时,当rep xyz编码被记录为执行其他操作时,才追溯记录旧CPU的行为。
相关:

为什么不给他们分配一些有用的工作?
32位模式基本上没有剩余的编码空间,也没有空闲的单字节操作码,迄今为止所有的扩展都对32位和64位使用相同的编码;如果你关心32位模式,你希望解码器只需要寻找相同的模式,这是有道理的。这就是为什么VEX(AVX)和EVEX(AVX-512)前缀使用一些反转位,以便它们与32位模式下的无效编码重叠,也是为什么它们在32位模式下仍限于8个矢量寄存器。
不幸的是,还没有任何扩展引入新的仅64位指令来使用一些释放的1字节操作码(BCD指令,如aaa或段寄存器的push/pop)。它们可以添加多个,如mov r/m32, sign_extended_imm8,以提高64位模式下的代码密度,使得像mov ecx, -21这样的指令变成3字节而不是5字节,并且对于mov rcx, -2变成4字节而不是7字节。
但是微软的软件分发模式是,一个二进制文件在任何地方运行,并检测CPU特性以用于一些特殊功能,这样的特性并不能带来足够的好处。它是一种在整个二进制文件中只会有一点帮助的东西,所以只有像gcc -march=native这样的情况。BMI1/2就是这样,大多数情况下,只需一条指令就可以完成2条指令就可以完成的事情。所以在一个程序的所有函数中使用时,它通常是有帮助的。但是可以想象,一些bithack函数可以获得足够的加速,这是值得的。

Intel和AMD对引入不会立即有用的扩展没有兴趣,所以在十年左右的时间里当扩展无处不在时,它们会变得最有用,但却被大多数人忽略了(广泛到一些程序可以把它当作他们“基线”的一部分)。尽管他们用BMI 1/2涉足这些沃茨,英特尔多年来继续销售 * 没有 * 那些扩展的CPU,包括Skylake Pentium/Celeron,我认为还有Silvermont系列CPU(上网本和低功耗服务器)。
一些BMI 1/2指令使用VEX编码,禁用VEX解码是英特尔在Ice Lake之前的低端CPU中禁用AVX的方式,BMI 1/2是一个牺牲品。(Silvermont系列直到Gracemont(桤木Lake E核心)根本不支持AVX,他们也根本不需要能够解码VEX前缀。)
AMD最初对AMD 64的设计相当保守,除了删除一些操作码以释放它们以备将来可能的扩展之外,尽可能少地改变机器码的含义。显然,他们不想陷入需要更多解码器晶体管的困境,以防AMD 64在商业上无法流行。为了促进编译器和汇编器的采用,他们保留了32位模式的大部分缺点。包括X1 M28 N1 X而不是X1 M29 N1 X,所以X86在从比较条件有效地具体化整数0/1方面仍然很糟糕。

相关问题