为什么使用xor而不是mov需要更少的字节?

Jin*_*ark 1 assembly x86-64 machine-code code-size

当将x设置为零(x = 0)时,我的csapp书指出了两种方法。

第一:

xorq %rcx, %rcx
Run Code Online (Sandbox Code Playgroud)

第二:

movq $0, %rcx
Run Code Online (Sandbox Code Playgroud)

它还表明第一个仅占用3个字节,而第二个仅占用7个字节。

两种方式如何运作?为什么第一个字节比第二个字节少?

Pet*_*des 6

因为mov需要更多空间来对其32位立即数源操作数进行编码。
xor只需要ModRM字节来编码其操作数。

两者都不需要REX前缀,因此您应该将2字节xor %ecx,%ecx与5字节进行比较mov $0, %ecx为什么32位寄存器上的x86-64指令将整个64位寄存器的高位归零? GAS不会为您进行此优化,而是为您movq提供mov $sign_extended_imm32, %r/m64编码,而不是mov $imm32, %r32省略ModRM字节的特殊情况下的5字节编码。

(如CS:APP示例中所述,将idivq与两个操作数一起使用吗?,CS:APP似乎充满了asm错误。这不是一个无效的语法错误,只是一个错过的优化。)


不幸的是,没有mov使用符号扩展的8位立即数进行编码的,否则我们可以使用3个字节mov reg, imm8。(https://www.felixcloutier.com/x86/mov)。(令我惊讶的是,x86-64的任何迭代都没有重新利用它释放的操作码字节中的一个,以便进行mov类似这样的不错的编码,也许将其与BMI1结合使用。)

有关x86指令编码的更多详细信息,请阅读Intel的vol.2手册并查看反汇编。

另请参见在x86汇编中将寄存器设置为零的最佳方法是:xor,mov或and?有关为什么Xor调零最佳的更多详细信息:在某些CPU(尤其是P6系列和Sandybridge系列)上,mov除简单的代码大小外,它还具有微体系结构上的优势。