XCHG RAX,RAX:0x09,这段代码是做什么的,它是如何工作的?

逆向工程 拆卸 部件 x86 反编译 x86-64
2021-07-07 07:17:46

鉴于以下简短的程序集片段:

shr   rax, 3
adc   rax, 0

我解决了这个问题:

  • 我们知道SHR用最后一位移位来设置 CF。
  • 我们知道ADC dest, 0只是添加 CF。

所以看着点点滴滴,

        128  64  32  16  8   4   2   1 
        8    7   6   5   4   3   2   1
        ------------------------------
        1    1   1   1   1   CF  X   X
CF=1 |  0    0   0   1   1   1   1   1  ; shr 3

所以如果我们 div 8 并添加 CF 最正确的功能是这样的,

def f(x):
  return x//8  + int( (x//4) % 2 )

什么时候有用。快速测试一下,我可以看到我是对的。

rax = 0  -> 0
rax = 1  -> 0
rax = 2  -> 0
rax = 3  -> 0

rax = 4  -> 1
rax = 7  -> 1
rax = 8  -> 1
rax = 11 -> 1

rax = 12 -> 2
rax = 13 -> 2
rax = 14 -> 2
rax = 15 -> 2
rax = 16 -> 2
rax = 17 -> 2
rax = 18 -> 2
rax = 19 -> 2

...

rax = 20 -> 3
rax = 28 -> 4

用 Radare 反编译在这里也没有用,

int64_t entry0 (void) {
    rax >>= 3;
    __asm ("adc rax, 0");
}

因此,我的问题是,尽管我确实理解这些指令对操作数寄存器的直接影响,但该指令序列的更高级别含义是什么?


这是来自XCHG RAX、RAX书中的谜语0x09

1个回答

shr rax, 3是一个无符号的除以 8 并朝零截断包含adc rax, 0使除法四舍五入到最近(虽然 0.5 总是会四舍五入)

所以这个操作设置RAX

  • 1 如果RAX[4-11]( 8*1 ±4)的范围内
  • 2 如果RAX[12-20]( 8*2 ±4)的范围内
  • 3 如果RAX[20-27]( 8*3 ±4)的范围内

您可以通过将移位减少到 1 来进一步简化此操作。

mov rax, 47  ; (remember 47/2 is 23.5)
shr rax, 1   ; rax = 23
adc rax, 0   ; rax = 24

如果我们再做一次

mov rax, 46  ; (remember 46/2 is 23)
shr rax, 1   ; rax = 23
adc rax, 0   ; rax = 23