【问题标题】:Arithmetic identities and EFLAGS算术恒等式和 EFLAGS
【发布时间】:2020-06-05 15:29:22
【问题描述】:

既然 −x = not(x)+1 意味着 a-b = a+not(b)+1,那么会

sub rax, rcx

相当于

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

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

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

【问题讨论】:

  • 虽然您似乎认识到它,但鉴于这是您问题的一部分,我确实想指出,没有理由假设对EFLAGS 的影响是相同的。它在数学上是等价的并不意味着对处理器状态的影响是相同的(忽略temp)。
  • sub 是否在您的 CPU 中损坏? - 除了:也许你可以用not rcx; add rax, rcx; add rax, 1; not rcx;避免temp
  • @500 不,我想你的意思是交换后两个建议的指令
  • @ThomasJager 但从理论上讲,可能是这样,这是问题所在。
  • @500-InternalServerError: not 不会影响标志,这与大多数其他 ALU 指令不同。 (felixcloutier.com/x86/not#flags-affected)

标签: assembly x86 x86-64 eflags


【解决方案1】:

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

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

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

【讨论】:

    【解决方案2】:

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

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

    当然不是。 ZF、SF 和 PF 仅取决于整数结果,但 CF 和 OF1 取决于您如何到达那里。 x86 的 CF 进位标志是减法的借位输出。 (与 ARM 等一些 ISA 不同,如果没有借位,减法会设置进位标志。)

    您可以在脑海中检查的琐碎反例:
    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 指令(包括 neg)不同。neg 设置的标志与来自 0sub 相同。x86 历史的一个奇怪怪癖。@ 987654321@)

    脚注 1:AF 也是如此,它是低字节中从低半字节到高半字节的半进位标志(辅助)。您不能直接对其进行分支,x86-64 删除了读取它的 BCD 指令,例如 aaa,但它仍然存在于 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。您最后的add rax, 1 会在较早的 CF 结果上进行操作,从而使 CF 成为您想要的结果的可能性/可能性更低。

    有符号溢出 (OF) 有一个极端情况。大多数输入都是相同的,其中x -= yx += -y 的带符号算术运算相同。但是如果-y 溢出仍然是负数(the most-negative 2's complement number 没有反转),它是加一个负数而不是减去一个负数。

    例如-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的借用输出并不容易,而且可能不是很有趣。

    请注意,硬件 ALU 经常使用类似于二进制 Adder–subtractor 的东西,它将 A~A 复用为全加器的输入以进位/借位感知方式来实现 @987654369 @ 或 A - B 带有正确的借位输出以进行减法。

    应该可以在 asm 中使用 stc / adc dst, inverted_src 来复制类似硬件的实际作用:添加逆进位为 1。不单独加1。

    (TODO:重写此答案的更多内容以显示使用 not / stc / adc 而不是可能需要将进位一直传播到数字的多个操作)。

    相关:

    【讨论】:

    • 嗨,彼得,当您在二进制文件中执行 0-1 时,您从哪里借来的? 0 的左侧没有位/数字,那么“借来的”1 来自哪里?这是设置标志以指示不存在借用的地方吗?我发现这篇文章解释了我的问题,但答案还不够:stackoverflow.com/questions/46570941/…
    • @Dan:从下一个高位开始。就像在二进制中添加1+1 时一样,没有足够的空间来存储10 结果,因此该位的结果为0,进位为1。(en.wikipedia.org/wiki/Adder_(electronics)#Full_adder)。 0-1 = 1,借用输出为 1en.wikipedia.org/wiki/Subtractor#Full_subtractor
    • 但在这种情况下,下一个更高的位是0。假设我们有一个 8 位 cpu,然后运行 ​​0b00000000 - 0b00000001。第一个输入位都是 0,没有什么可以借用的?
    • @Dan:对,0b10 - 0b01 = 0b01,包括从低位0-1 借入第二位。但是该位没有进一步的借位,因此整个 2 位减法(从​​最重要的全减法器中)的借位输出为 0。在0 - 1 中,有 借用整个事物的输出。即左手操作数在右手操作数下方是无符号的。即0 - 1 = -1 没有任何东西可以借用,所以结果是否定的。即0b11(无符号溢出,只有无符号进位)。
    • @Dan:思考一下 1 位全减法器 (en.wikipedia.org/wiki/Subtractor#Full_subtractor) 的逻辑以及它是如何独立工作的。请记住,借位(如进位)从 LSB 传播到 MSB;有什么可以借的并不重要。一旦您了解了实际发生的细节,您就可以开始考虑如何为这些位分配数学意义,以便对这些位进行无符号或有符号 2 的补码解释。 (二进制符号/大小的工作方式不同)。
    猜你喜欢
    • 1970-01-01
    • 2014-10-10
    • 1970-01-01
    • 2019-05-22
    • 1970-01-01
    • 1970-01-01
    • 2022-01-23
    • 2014-02-07
    • 2011-01-25
    相关资源
    最近更新 更多