左移操作期间使用的寄存器

Registers used during left shift operation

我有一个关于寄存器在一些基本操作中的使用的小问题。实际上,我已经看过在 XOR 或 AND 等操作期间生成的汇编代码,这些代码很容易理解。实际上,如果我们考虑 a = b & c,这将分 3 个步骤进行翻译:

  1. b 移至 %rax
  2. %rax = %rax + c
  3. %rax 被移动到

注意a、b、c是unsigned long变量。如果将加法替换为 XOR 或 OR,则此翻译也可用。无论如何,我已经检查过轮班是否也是这种情况,我发现了一件奇怪的事情:事实上, a = b << c 被翻译为 follow

  1. b 移至 %rax
  2. c 移至 %rcx
  3. %rax = %rax <<(shlq) %cl
  4. %rax 被移动到

我不太确定我是否真的理解第二步和第三步。我想这是因为 %rax (b) 不能移动超过 63,否则,结果显然是 0。看起来 %cl 是一个 8 位寄存器,所以我认为这是一个快速的方法到 select 只有有用的位,而不是 %rcx 中的 64 位。对吗?

谢谢

这就是 shl 的工作原理。
来自英特尔手册 2B:

Shifts the bits in the first operand (destination operand) to the left or right by the number of bits specified in the second operand (count operand). Bits shifted beyond the destination operand boundary are first shifted into the CF flag, then discarded. At the end of the shift operation, the CF flag contains the last bit shifted out of the destination operand.

The destination operand can be a register or a memory location. The count operand can be an immediate value or the CL register. The count is masked to 5 bits (or 6 bits if in 64-bit mode and REX.W is used). The count range is limited to 0 to 31 (or 63 if 64-bit mode and REX.W is used). A special opcode encoding is provided for a count of 1.

可变长度移位必须使用cl.

嗯,CL 是一个 8 位寄存器,可能的值为 0..255。所以将一些值移动到 %RCX 只是部分相关,因为只有最低的 8 位(CL)才算数。像 %RAX 这样的 64 位目标寄存器只能左移 63 位而不会溢出。将它向左移动 64 位或更多(最多 255 = CL 的最大值)总是会导致 0(零)。所以你的假设是正确的。

relevant SHL OpCode 的解释可以在那里找到。

REX.W + D3 /4     SHL r/m64, CL     Multiply r/m64 by 2, CL times.

I suppose this is due to the fact that %rax (b) cannot be shifted more than 63, otherwise, the result is obviously 0.

如果它像那样工作,它可能会使用 rcx 作为操作数(或者在任何上下文中最有意义的宽度,即指令的操作数大小),以检查是否有任何上限位已设置(如果已设置,则将结果设置为零)。

但事实并非如此,移位量以操作数大小为模,因此任何高位都完全不相关。所以它 可以 只读取低 8 位,它也可以,尽管这个决定在 16 位时代可能更有意义(ch 实际上会被使用)比它现在。较新的 shrx 系列读取 "full" 寄存器(与操作数大小一样宽),然后忽略更多位。