算术身份和EFLAGS

问题描述 投票:1回答:2

因为-x = not(x)+1,则意味着a-b = a + not(b)+1,然后

sub rax, rcx

相当于

mov temp, rcx
not temp
add rax, temp
add rax, 1

某些寄存器的温度被认为是易失的?

换句话说,后者会以完全相同的方式影响EFLAGS吗?如果没有,该如何强制?

assembly x86 x86-64 eflags
2个回答
1
投票

不,它们不相等。例如,如果rax = 1rcx = 3,则sub rax, rcx将设置进位标志,因为您是从较小的数中减去较大的数。但是在您的第二个指令序列中,在add rax, temp之后,rax将包含-3(即0xfffffffffffffffd),并且将1添加到-3不会引起进位。因此,在第二条指令序列之后,进位标记将被清除。

我不知道有什么简单的方法可以精确地模拟sub的行为,包括其对标志的影响(除了使用cmp之外,但这是作弊的,因为它实际上只是sub在幕后)。原则上,您可以编写一长串指令,这些指令手动进行与sub内部进行的所有相同测试(请参阅指令集手册中的精确描述),并在最后使用sahf或[ C0]之类的。

这会做很多工作,特别是如果您不打算使用popf,并且我也不会通过这个答案。尤其是因为我也想不出为什么需要这样做的任何理由,除非是一项毫无意义的练习。


1
投票

是,在RAX中得到相同的整数结果。

换句话说,后者会以完全相同的方式影响EFLAGS吗?

当然不是。 x86的进位标志是减法的借位输出。 (与某些ISA(例如ARM)不同,如果没有借位,减法将设置进位标志。)

传统反例:cmp0 - 1一起设置CF = 1。但是您的方法清除了CF。

sub

(有趣的是:mov temp, rcx # no effect on FLAGS not temp # no effect on FLAGS, unlike most other x86 ALU instructions add rax, ~1 = 0xFF..FE # 0 + whatever clears CF add rax, 1 # 0xFE + 1 = 0xFF..FF = -1. CF still clear 不会影响FLAGS,与大多数其他ALU指令(包括not不同)不同。neg设置与neg中的sub相同的标志。x86历史记录的一个奇怪现象。[C0 ])

如果没有,如何强制执行?

使用不同的说明。在EFLAGS上获得理想效果的最简单,最有效的方法是将其优化回0。这就是x86具有https://www.felixcloutier.com/x86/not#flags-affectedsub rax, rcx指令的原因。如果这是您想要的,请使用它。


[如果需要替代方法,我认为在某些情况下sub会将CF设置为与sbb相反。它适用于OF,但我认为y = LONG_MIN(x += -y)。

x -= y

注意,我们将x和y结合在一个步骤中。最后的1UL<<63会显示较早的CF结果。

SF,ZF和PF仅取决于结果,因此显然会得到相同的结果

Signed-overflow(OF)有一个极端的情况。大多数输入都是相同的,其中# Works sometimes, not always for CF. mov temp, rcx # no effect on FLAGS neg temp # or NOT + INC if you insist on avoiding sub-like operations add rax, temp # x += -y cmc # complement carry. CF = !CF add rax, 1的带符号算术运算是相同的。但是,如果x -= y溢出仍为负数(x += -y没有逆数),则它是添加负数而不是减去负数。

例如-y由于有符号溢出。 (C表示法;有符号的溢出在ISO C中为UB,但在asm中包装)。

针对CF的尝试的反例:

the most-negative 2's complement number不借用,因此CF = 0。-LONG_MIN == LONG_MIN= -1 - 0也没有携带,然后CMC会将CF翻转为1

但是-1 + -0-1 + 0)加上任何其他数字不会带出,而-1减去任何数字则不会带出。


因此,要精确模拟0xff...ff的借用输出并不容易,并且可能不太有趣。

© www.soinside.com 2019 - 2024. All rights reserved.