繁体   English   中英

算术恒等式和 EFLAGS

[英]Arithmetic identities and EFLAGS

因为 −x = not(x)+1 意味着 ab = a+not(b)+1,所以

sub rax, rcx

相当于

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

某些寄存器在哪里 temp 被认为是易失性的?

换句话说,后者是否以完全相同的方式影响 EFLAGS? 如果不是,怎么能被迫?

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

我不知道有任何简单的方法可以精确地模拟sub的行为,包括它对标志的影响(除了使用cmp ,但那是作弊,因为它实际上只是sub在引擎盖下)。 原则上,您可以编写一长串指令,手动执行sub内部执行的所有相同测试(参考指令集手册中的精确描述),并在末尾使用sahfpopf之类的设置标志。

这将是很多工作,特别是如果您不打算使用cmp ,并且我不会通过它 go 来回答这个问题。 尤其是因为我也想不出任何理由需要这样做,除了作为一项相当无意义的练习。

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

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

当然不是。 ZF、SF 和 PF 仅取决于 integer 结果,但CF 和 OF 1取决于您如何到达那里 x86 的 CF 进位标志是从减法中借用 output。 (与某些 ISA 不同,例如 ARM,如果没有借位,减法会设置进位标志。)

您可以在脑海中检查一个简单的反例:
0 - 1sub集 CF=1。 但是您的方式清除了CF。

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 + anything  clears CF
add rax, 1                 # 0xFE + 1 = 0xFF..FF = -1.  clears CF

(有趣的事实: not不会影响 FLAGS,不像大多数其他 ALU 指令,包括negneg设置标志与sub0相同。x86 历史的一个奇怪怪癖。https://www.felix#cloutier.com/x86/not标志影响

脚注 1:AF 也是如此,它是低字节中从低半字节到高半字节的半进位标志(辅助)。 您不能直接对其进行分支,并且 x86-64 删除了读取它的像aaa这样的 BCD 指令,但它仍然存在于 RFLAGS 中,您可以使用pushf / pop rax读取它。

如果不是,怎么能被迫?

使用不同的指令。 在 EFLAGS 上获得所需效果的最简单和最有效的方法是将其优化回sub rax, rcx 这就是为什么 x86 有subsbb指令的原因。 如果那是您想要的,请使用它。


如果你想要一个替代方案,你肯定需要避免像add rax,1作为最后一步。 仅当最终结果为零时才会设置 CF,从 ULONG_MAX = -1 开始。

在大多数情况下,将x -= y作为x += -y适用于 OF。 (但不是最负数y=LONG_MIN ( 1UL<<63 ),其中neg rcx会溢出)。

但是 CF 告诉你 64 + 64 位加法或减法的 65 位完整结果。 64 位否定是不够的: x += -y并不总是将 CF 设置为与x -= y的相反。

可能涉及neg / sbb的东西可能有用吗? 但是不,这将否定的执行视为 -0 / -1,而不是-(1<<64)

# Broken attempt that fails for CF when rcx=0 at least, probably many more cases.
# Also fails for OF for rcx=0x8000000000000000 = LONG_MIN
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

请注意,我们在一个步骤中组合了 x 和 y。 您在较早的 CF 结果的末尾add rax, 1 ,使 CF 成为您想要的结果的可能性甚至更低。

有符号溢出 (OF) 有一个极端情况。 大多数输入都是相同的,其中带符号的算术运算对于x -= yx += -y是相同的。 但是如果-y溢出仍然是负数([最负的 2 的补数][1] 没有倒数),它是加一个负数而不是减去一个负数。

例如-LONG_MIN == LONG_MIN因为有符号溢出。 (C 表示法;有符号溢出是 ISO C 中的 UB,但在 asm 中它会换行)。

CF 尝试的反例:

-1 - 0不借,所以 CF=0。 -1 + -0 = -1 + 0也不进位,然后 CMC 会将 CF 翻转为 1

但是-1 ( 0xff...ff ) 加上任何其他数字会执行,而-1减去任何数字不会。


所以要准确模拟sub的借用output并不容易,而且可能不是很有趣。

请注意,硬件 ALU 经常使用二进制 [加法器-减法器][2] 之类的东西,它以进位/借位感知方式A~A多路复用作为全加器的输入,以正确实现A + BA - B借用 output 做减法。

[1]: https://en.wikipedia.org/wiki/Two%27s_complement#:~:text=The%20two's%20complement%20of%20the%20most%20negative%20number%20representable%20(例如,%C2% A7%20Most%20negative%20number%20below. [2]: https://en.wikipedia.org/wiki/Adder%E2%80%93subtractor

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM