设置rax
为 1 的最短 Intel x86-64 操作码是多少?
我试过xor rax,rax
and inc al
(在 NASM 语法中);它给出了 5 字节的操作码48 31 c0
fe c0
。是否有可能在 4 个字节中实现相同的结果?
您可以修改或读取任何其他寄存器,但不能假定先前指令中的任何一个都具有特定值。
设置rax
为 1 的最短 Intel x86-64 操作码是多少?
我试过xor rax,rax
and inc al
(在 NASM 语法中);它给出了 5 字节的操作码48 31 c0
fe c0
。是否有可能在 4 个字节中实现相同的结果?
您可以修改或读取任何其他寄存器,但不能假定先前指令中的任何一个都具有特定值。
由于 push 有一个字节立即编码,而寄存器有一个字节 pop,这可以在三个字节中完成:6a 01 58
或push $1 / pop %rax
.
在任何已知的前提条件下,有一些技巧比 push imm8/pop rax 3 字节解决方案更有效(在速度方面)。
因为速度mov eax, 1
有很多优势,因为它没有任何输入依赖,而且只有一条指令。乱序执行可以在它(以及任何依赖它的东西)上开始,而无需等待其他东西。(参见Agner Fog 的指南和x86标签 wiki)。
显然,其中许多利用了编写 32 位寄存器将上半部分归零的事实,以避免 OP 代码的不必要的 REX 前缀。(另请注意,在 Silvermont 上,这xor rax,rax
不是特殊情况下的归零习惯用法。它仅识别 32 位寄存器的异或归零,例如 eax 或 r10d,而不是 rax 或 r10。)
如果您在任何寄存器中有一个小的已知常数开始,您可以使用
lea eax, [rcx+1] ; 3 bytes: opcode + ModRM + disp8
disp8 可以编码从 -128 到 +127 的位移。
如果eax中有奇数,and eax, 1
也是3个字节。
在 32 位代码中,inc eax
只占用一个字节,但这些 inc/dec 操作码被重新用作 AMD64 的 REX 前缀。所以xor eax,eax
/inc eax
在 x86-64 代码中是 4 个字节,但在 32 位代码中只有 3 个字节。尽管如此,如果在 a 上保存 1 个字节mov eax,1
就足够了,并且 LEA 或 AND 不起作用,那么这比 push/pop 更有效。