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