为什么使用 `xor` 比使用 `mov` 占用的字节少?
Why does it take less bytes to use `xor` than to use `mov`?
为了将 x 设置为零 (x = 0),我的 csapp 书指出了两种方法。
第一个:
xorq %rcx, %rcx
第二个:
movq [=11=], %rcx
还说第一个只占3个字节,第二个占7个字节
这两种方式如何工作?为什么第一个占用的字节数比第二个少?
因为mov
需要更多space来编码其32位立即源操作数。
xor
只需要 ModRM 字节对其操作数进行编码。
两者都不需要 REX 前缀,因此 您应该将 2 字节 xor %ecx,%ecx
与 5 字节 mov [=13=], %ecx
进行比较。 Why do x86-64 instructions on 32-bit registers zero the upper part of the full 64-bit register?
GAS 不会为您进行此优化,并且 movq
为您提供 mov $sign_extended_imm32, %r/m64
编码,而不是省略 ModRM 字节的特殊情况 5 字节 mov $imm32, %r32
编码。
(除非您使用 as -O2
,在这种情况下它将 optimize the operand-size like NASM。请注意 gcc -O2 -c foo.s
不会 而不是 将优化选项传递给 as
。 )
(如 中所述,CS:APP 似乎充满了 asm 错误。这不是无效语法错误,只是错过了优化。)
不幸的是,mov
没有带符号扩展的 8 位立即数的编码,否则我们可以有 3 字节 mov reg, imm8
。 (https://www.felixcloutier.com/x86/mov)。 (令我惊讶的是,x86-64 的迭代没有将它释放的操作码字节之一重新用于像这样的漂亮 mov
编码,可能与 BMI1 或其他东西混为一谈。)
有关 x86 指令编码的更多详细信息,请阅读 Intel 的第 2 卷手册并查看反汇编,https://wiki.osdev.org/X86-64_Instruction_Encoding 是一个很好的概述,比 Intel 的手册更简洁。
另请参阅 以了解有关异或归零为何最佳的更多详细信息:在某些 CPU 上,特别是 P6 系列和 Sandybridge 系列,它除了简单的代码外,还具有优于 mov
的微体系结构优势-尺寸。
Why does the first one take fewer bytes than second?
虽然 Peter Cordes 的回答已经是关于技术细节的,但我想专注于数学背景:
x86s CPU 显然不区分大数字(如 12345789)和零值:存储这样的值需要 4 个字节。
然而,零值是一个非常特殊的值:
可以写成(a-a)或(a XOR a)而"a"可以是任意整数值!
这意味着你可以表演一招:
您执行操作 subq %rcx, %rcx
来计算值 (rcx - rcx)
。它不关心 rcx
具有哪个值:如果您从自身中减去该值,结果将为零(因为 (a-a)=0)。
这意味着rcx
在该操作后将为0。
操作xorq %rcx, %rcx
具有相同的效果,因为(a XOR a)也总是0。
为了将 x 设置为零 (x = 0),我的 csapp 书指出了两种方法。
第一个:
xorq %rcx, %rcx
第二个:
movq [=11=], %rcx
还说第一个只占3个字节,第二个占7个字节
这两种方式如何工作?为什么第一个占用的字节数比第二个少?
因为mov
需要更多space来编码其32位立即源操作数。
xor
只需要 ModRM 字节对其操作数进行编码。
两者都不需要 REX 前缀,因此 您应该将 2 字节 xor %ecx,%ecx
与 5 字节 mov [=13=], %ecx
进行比较。 Why do x86-64 instructions on 32-bit registers zero the upper part of the full 64-bit register?
GAS 不会为您进行此优化,并且 movq
为您提供 mov $sign_extended_imm32, %r/m64
编码,而不是省略 ModRM 字节的特殊情况 5 字节 mov $imm32, %r32
编码。
(除非您使用 as -O2
,在这种情况下它将 optimize the operand-size like NASM。请注意 gcc -O2 -c foo.s
不会 而不是 将优化选项传递给 as
。 )
(如
不幸的是,mov
没有带符号扩展的 8 位立即数的编码,否则我们可以有 3 字节 mov reg, imm8
。 (https://www.felixcloutier.com/x86/mov)。 (令我惊讶的是,x86-64 的迭代没有将它释放的操作码字节之一重新用于像这样的漂亮 mov
编码,可能与 BMI1 或其他东西混为一谈。)
有关 x86 指令编码的更多详细信息,请阅读 Intel 的第 2 卷手册并查看反汇编,https://wiki.osdev.org/X86-64_Instruction_Encoding 是一个很好的概述,比 Intel 的手册更简洁。
另请参阅 mov
的微体系结构优势-尺寸。
Why does the first one take fewer bytes than second?
虽然 Peter Cordes 的回答已经是关于技术细节的,但我想专注于数学背景:
x86s CPU 显然不区分大数字(如 12345789)和零值:存储这样的值需要 4 个字节。
然而,零值是一个非常特殊的值:
可以写成(a-a)或(a XOR a)而"a"可以是任意整数值!
这意味着你可以表演一招:
您执行操作 subq %rcx, %rcx
来计算值 (rcx - rcx)
。它不关心 rcx
具有哪个值:如果您从自身中减去该值,结果将为零(因为 (a-a)=0)。
这意味着rcx
在该操作后将为0。
操作xorq %rcx, %rcx
具有相同的效果,因为(a XOR a)也总是0。