因为-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吗?如果没有,该如何强制?
不,它们不相等。例如,如果rax = 1
和rcx = 3
,则sub rax, rcx
将设置进位标志,因为您是从较小的数中减去较大的数。但是在您的第二个指令序列中,在add rax, temp
之后,rax
将包含-3
(即0xfffffffffffffffd
),并且将1
添加到-3
不会引起进位。因此,在第二条指令序列之后,进位标记将被清除。
我不知道有什么简单的方法可以精确地模拟sub
的行为,包括其对标志的影响(除了使用cmp
之外,但这是作弊的,因为它实际上只是sub
在幕后)。原则上,您可以编写一长串指令,这些指令手动进行与sub
内部进行的所有相同测试(请参阅指令集手册中的精确描述),并在最后使用sahf
或[ C0]之类的。
这会做很多工作,特别是如果您不打算使用popf
,并且我也不会通过这个答案。尤其是因为我也想不出为什么需要这样做的任何理由,除非是一项毫无意义的练习。
是,在RAX中得到相同的整数结果。
换句话说,后者会以完全相同的方式影响EFLAGS吗?
当然不是。 x86的进位标志是减法的借位输出。 (与某些ISA(例如ARM)不同,如果没有借位,减法将设置进位标志。)
传统反例:cmp
与0 - 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-affected和sub 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
的借用输出并不容易,并且可能不太有趣。