assembly 汇编:为什么有些x86操作码在x64中无效?

9rnv2umw  于 4个月前  发布在  其他
关注(0)|答案(2)|浏览(58)

为什么在x64中有些操作码是无效的(例如0607),而在x86中用于相当基本的指令(0607pushpop)?我认为这些最简单的指令在两种架构中都能很好地完成。
为什么他们在x64中禁用了一些简单的指令?为什么它们不能工作?为什么他们禁用了一些操作码,在操作码列表中创建了漏洞,而他们可以将它们分配给x64版本的指令?
参考文件:
http://ref.x86asm.net/coder32.html
http://ref.x86asm.net/coder64.html

jm2pwxwz

jm2pwxwz1#

对于所有的CPU来说,都有一个类似于“操作码空间”的东西。例如,如果CPU使用8位操作码,那么它最多可以有256条指令。操作码越大,你可以拥有的操作码就越多,但是快速获取和解码它们就越困难。
80 x86是一个相对较老的架构。它开始时的操作码空间不大,主要由1字节和2字节操作码组成。每次CPU制造商添加新功能时,都会从操作码空间中占用更多的操作码。他们用完了操作码。他们很快就用完了。
为了解决这个问题,他们开始做一些事情,比如添加转义码和前缀来人为地扩展操作码空间。举个例子,对于最近的AVX指令,你会看到一个VEX前缀,后面跟着一个旧的/回收的转义码(例如0xF 0),后面跟着一个旧的/回收的地址/操作数大小前缀(例如0x 66),再后面跟着另外4个字节。
同时,还有一些现在很少使用的旧指令(AAD,AAM等)和具有多个/冗余操作码的指令(INC/DEC),这些指令消耗了宝贵的“1字节”操作码。由于向后兼容性,这些指令无法完全删除。
然而,当64位被设计出来的时候,根本就没有任何64位代码可以兼容-向后兼容性并不重要。被“不太重要”的指令消耗的1字节操作码可以被回收;使这些指令在64位代码中无效(但释放了一些有价值的1字节操作码)。
大多数1字节的操作码(如果我没记错的话,是整个1字节的INC/DEC组)立即被回收用于支持64位操作数所需的雷克斯前缀。有些没有,并成为“未来扩展的自由”(限制是扩展只能在64位代码中工作,因为这些指令在16位和32位代码中仍然有效)。

siotufzp

siotufzp2#

32位模式下的0607操作码是指令PUSH ESPOP ES。在64位模式下,段寄存器CS、DS、ES和SS不再用于确定内存地址:处理器假定基址为0,并且没有大小限制。由于现在通常没有理由使用(而不是操作系统本身)访问这些寄存器时,删除了用于更改和访问它们的push/pop操作码,只留下mov到/来自Sreg(这仅仅是2个总操作码;寄存器号在ModRM字节中,而不是1字节操作码的一部分)。这对于几乎不需要的东西来说完全足够了。
FS和GS段寄存器仍然可以在64位模式下设置基址,因此与它们相关的push和pop操作码没有被删除。(这些2字节0F xx操作码是在386中添加的,与8086段寄存器的旧1字节操作码相比,操作码空间的价值较小)。
段寄存器的Push/pop或mov不是操作系统通常设置FS或GS段基数的方式,但是:这需要GDT或LDT条目,并且只能在低32位内设置基址。64位OS将使用相关的MSR直接读取和写入基址,而不是架构寄存器。(现代的32位操作系统也是这样做的,除非运行在不支持基于段的MSR的旧硬件上。

相关问题