2

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

第一的:

xorq %rcx, %rcx

第二:

movq $0, %rcx

它还告诉第一个只占用 3 个字节,但第二个占用 7 个字节。

这两种方式是如何工作的?为什么第一个比第二个占用更少的字节?

4

2 回答 2

8

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

两者都不需要 REX 前缀,因此您应该将 2-bytexor %ecx,%ecx与 5-bytemov $0, %ecx进行比较。 为什么 32 位寄存器上的 x86-64 指令会将完整 64 位寄存器的上部归零?
GAS 不会为您进行此优化,而是为您movq提供编码而不是省略 ModRM 字节mov $sign_extended_imm32, %r/m64的特殊情况 5 字节编码。 (除非您在这种情况下使用它将优化操作数大小,如 NASM。请注意,不会优化选项传递给.)mov $imm32, %r32
as -O2gcc -O2 -c foo.sas

(如CS:APP example uses idivq with two operands?中所述,CS:APP 似乎充满了 asm 错误。这不是无效语法错误,只是错过了优化。)


不幸的是,没有mov带符号扩展的 8 位立即数的编码,否则我们可以有 3-byte mov reg, imm8。(https://www.felixcloutier.com/x86/mov)。(我很惊讶 x86-64 的迭代没有重新利用它释放的一个操作码字节用于mov像这样的良好编码,可能与 BMI1 或其他东西混为一谈。)

有关 x86 指令编码的更多详细信息,请阅读 Intel 的 vol.2 手册并查看反汇编,并且https://wiki.osdev.org/X86-64_Instruction_Encoding是一个很好的概述,它比 Intel 的手册更简洁。

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

于 2019-09-25T02:39:30.013 回答
4

为什么第一个比第二个占用更少的字节?

虽然 Peter Cordes 的回答已经涉及技术细节,但我想重点关注数学背景:

x86s CPU 显然不区分大数(如 12345789)和零值:存储这样的值需要 4 个字节。

但是,零值是一个非常特殊的值:

它可以写成 (aa) 或 (a XOR a) 而“a”可以是任何整数值!

这意味着您可以执行一个技巧:

您执行subq %rcx, %rcx计算值的操作(rcx - rcx)。它不关心哪个值rcx具有:如果从自身中减去该值,结果将为零(因为 (aa)=0)。

这意味着该rcx操作后将为 0。

该操作xorq %rcx, %rcx具有相同的效果,因为 (a XOR a) 也始终为 0。

于 2019-09-25T11:46:53.987 回答