在x86-64英特尔手册之旅中,我阅读了
也许最令人惊讶的事实是诸如
MOV EAX, EBX
自动将RAX
寄存器的高32位清零的指令。
同一来源引用的英特尔文档(手动基本体系结构中的3.4.1.1通用寄存器在64位模式下)告诉我们:
- 64位操作数在目标通用寄存器中生成64位结果。
- 32位操作数生成32位结果,并将其零扩展到目标通用寄存器中的64位结果。
- 8位和16位操作数生成8位或16位结果。目的通用寄存器的高56位或高48位(分别)不会被该操作修改。如果8位或16位运算的结果打算用于64位地址计算,则将寄存器显式符号扩展为完整的64位。
在x86-32和x86-64汇编中,16位指令例如
mov ax, bx
不要显示eax的高位字为零的这种“奇怪”行为。
因此:引入此行为的原因是什么?乍一看似乎是不合逻辑的(但是原因可能是我已经习惯了x86-32程序的怪癖)。
r32
目标操作数的指令都将高32归零,而不是合并。例如,某些汇编程序将替换pmovmskb r64, xmm
为pmovmskb r32, xmm
,保存REX,因为64位目标版本的行为相同。即使手册的“ 操作”部分分别列出了32个/ 64位dest和64/128 / 256b源的所有6种组合,r32形式的隐式零扩展也复制了r64形式的显式零扩展。我对HW的实施方式感到好奇...
xor eax,eax
或是xor r8d,r8d
将RAX或R8归零的最佳方法(为RAX保存REX前缀,并且甚至在Silvermont上也不专门处理64位XOR)。相关:Haswell / Skylake上的部分寄存器的性能如何?编写AL似乎对RAX有错误的依赖性,而AH则不一致