【问题标题】:Setting CF while cmp在 cmp 时设置 CF
【发布时间】:2017-08-11 09:04:38
【问题描述】:

CF 标志在我们比较两个数字并且一个数字小于另一个数字时设置:

mov eax,1
cmp eax,2
jb truWay

二进制形式:

1=00000001 
2=00000010=11111101+1(add. code)=11111110и 
00000001+11111110=11111111(no carry)

为什么指令cmp eax,2 设置CF 标志?没有进位,否则我错了。

【问题讨论】:

  • cmp相减,1-2需要进位
  • 你能用二进制形式给我看吗?
  • 因为 2 大于 1,所以你不能不借用减去...不需要转换成二进制来看到这个 ;-)
  • 你应该真正阅读 CMP 的指令集参考,以便理解它的语义。

标签: assembly x86


【解决方案1】:

您可以参考these slides 了解如何在 ALU 中执行减法。

虽然 A - B = A + (-B) 并且在二进制补码中是 A + ¬B + 1 是正确的,但这种考虑仅考虑了结果。

用半加器实现的减法器采用以下形式

             

请注意,CarryOut 位是反转的。

您可以通过举个例子来检查这是必要的和正确的(将大小限制为 4 位):

1 - 2 = 1 + (-2) = 0001b + 1110b = 0|1111b 因为 ¬0 = 1 我们有借位

而对于 2 - 1 个有

2 - 1 = 2 + (-1) = 0010b + 1111b = 1|0001b 因为 ¬1 = 0 我们没有借位

因此,在您的示例中,存在借位,因此设置了 CF,这正是因为 0001b + 1110b 不产生进位。

为了更正式地证明倒置进位标志的正确性,一次可以对位数使用归纳法。

基本情况
n = 1

这可以用真值表证明

a  b   a-b (a+¬b+1)  ¬carryOut  Expected borrow
0  0   0+1+1 = 1|0       0           0
0  1   0+0+1 = 0|1       1           1
1  0   1+1+1 = 1|1       0           0
1  1   1+0+1 = 1|0       0           0

感应案例

当两个n位数字相减时 A = an an-1 ... a0 and B = bn bn-1 ... b0 我们可以有 A > B、A 在第一种情况下,有一个 k 使得 akk 和 aj = bj 表示所有 j > k 直到 n
条件 akk 意味着 ak = 0 和 bk = 1。
因此,A 和 ¬B 等于第 k-1 位,因此只有这么多位会影响进位。
但是根据归纳假设,执行是正确的,所以在这种情况下也是正确的。

同样的过程也适用于案例 A > B。

情况 A = B 更容易,因为整个操作简化为 A + ¬A + 1 减少到 111...1 + 1 总是产生进位,因此没有借位。

【讨论】:

    【解决方案2】:

    第一:

    a-b 的结果与a+(-b) 的结果相同。

    但是,a-b 操作设置的标志a+(-b) 操作设置的标志(至少不总是)相同!

    这可以通过比较不同的 CPU 类型(例如现代 x86 CPU 和历史悠久的 6502)来看出:

    a+b 操作后的标志值在 x86 和 6502 上是相同的,而“进位标志”在两个 CPU 上在a-b 操作后具有完全相反的含义。

    这意味着“进位标志”在两个 CPU 上运行 a+(-b) 后具有相同的值,而 a-b 后的值在两个 CPU 上始终不同。

    第二:

    在 x86 上,“进位标志”被定义为减法的“借出”。你可以模仿这个

    • 将这两个数字扩展为具有更多位的数字 - 例如 9 而不是 8 位
    • 然后将“扩展”数字设为负数
    • 然后做加法
    • 忽略加法中的进位
    • 而不是使用结果的最高位作为进位

    例子:

    1 = 00000001 (8 bit) = 0 00000001 (9 bit)
    2 = 00000010 (8 bit) = 0 00000010 (9 bit)
    3 = 00000011 (8 bit) = 0 00000011 (9 bit)
    => -2 = 1 11111110 (9 bit!)
    
    Do the addition:
    3 + (-2) = 1000000001 (9 bit plus carry)
    1 + (-2) =  111111111 (9 bit)
    
    Ignore carry:
    3 + (-2) = 000000001 (9 bit)
    1 + (-2) = 111111111 (9 bit)
    
    Use the highest bit as carry:
    3 + (-2) =  000000001 = 0 00000001 = (no carry) 00000001
    1 + (-2) =  111111111 = 1 11111111 = (carry)    11111111
    

    【讨论】:

      【解决方案3】:

      确实有借出。如果有借出CFcmp 指令设置。

      您的指令cmp 执行以下减法:

        1 = 0001
      - 2 = 0010
      --------------
            1111
      

      最右边的第一列没有什么特别之处:1 - 0 = 1

      最右边的第二列有一个借用(即:1 是从下一列之一“借用”的)。借用是因为0 < 1。此列的结果为10 - 1 = 1

      但是请注意,对于第一个操作数,左侧没有一个可以借用 1 的列,因此会发生借出:借出最多有效位,它实际上设置了CF

      您的减法操作实际上就像设置CF(即:“借用”或“获取”第一个操作数的MSB 的1)并执行以下减法:

        10001
      -  0010
      -------
         1111
      

      请注意,第一个操作数在其真正 MSB 的左侧有一个 1。这个1 以前不存在,它代表借用

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-02-29
        • 1970-01-01
        • 2011-03-09
        • 2011-12-23
        • 1970-01-01
        相关资源
        最近更新 更多