x86中的进位/溢出和减法

14

我试图理解x86中的溢出和进位标志。

据我所知,对于有符号2进制数的加法,这些标志只能通过以下四种方式之一产生(我的示例是4位数):

  1. pos+pos = neg(溢出)
    • 0111 + 0001 = 1000(7 + 1 = -8)
  2. pos+neg = pos(进位)
    • 0011 + 1110 = 0001(3 + -2 = 1)
  3. neg+neg = neg(进位)
    • 1111 + 1111 = 1110(-1 + -1 = -2)
  4. neg+neg = pos(溢出和进位)
    • 1000 + 1001 = 0001(-8 + -7 = 1)

因此,在x86汇编中,将B从A中减去是否会生成与添加A和-B相同的标志?


1
请参阅理解有符号和无符号的进位和溢出条件/标志,以及x86标签维基中的其他链接。 - Peter Cordes
2个回答

23

这里有一个参考表可能会有所帮助。它展示了x86 ADD和SUB指令可能导致的4个算术标志的每种组合的示例。 'h','ud'和'd'表示每个值的十六进制、无符号十进制和有符号十进制表示。例如,SUB的第一行表示0xFF - 0xFE = 0x1,没有设置任何标志。

但是,我认为Alex的答案是正确的。

 ADD
       A                   B                   A + B              Flags  
 ---------------     ----------------    ---------------      -----------------
 h  |  ud  |   d   | h  |  ud  |   d   | h  |  ud  |   d   | OF | SF | ZF | CF
 ---+------+-------+----+------+-------+----+------+-------+----+----+----+---
 7F | 127  |  127  | 0  |  0   |   0   | 7F | 127  |  127  | 0  | 0  | 0  | 0
 FF | 255  |  -1   | 7F | 127  |  127  | 7E | 126  |  126  | 0  | 0  | 0  | 1
 0  |  0   |   0   | 0  |  0   |   0   | 0  |  0   |   0   | 0  | 0  | 1  | 0
 FF | 255  |  -1   | 1  |  1   |   1   | 0  |  0   |   0   | 0  | 0  | 1  | 1
 FF | 255  |  -1   | 0  |  0   |   0   | FF | 255  |  -1   | 0  | 1  | 0  | 0
 FF | 255  |  -1   | FF | 255  |  -1   | FE | 254  |  -2   | 0  | 1  | 0  | 1
 FF | 255  |  -1   | 80 | 128  | -128  | 7F | 127  |  127  | 1  | 0  | 0  | 1
 80 | 128  | -128  | 80 | 128  | -128  | 0  |  0   |   0   | 1  | 0  | 1  | 1
 7F | 127  |  127  | 7F | 127  |  127  | FE | 254  |  -2   | 1  | 1  | 0  | 0


 SUB
       A                   B                   A - B              Flags  
 ---------------     ----------------    ---------------      -----------------
 h  |  ud  |   d   | h  |  ud  |   d   | h  |  ud  |   d   || OF | SF | ZF | CF
----+------+-------+----+------+-------+----+------+-------++----+----+----+----
 FF | 255  |  -1   | FE | 254  |  -2   | 1  |  1   |   1   || 0  | 0  | 0  | 0
 7E | 126  |  126  | FF | 255  |  -1   | 7F | 127  |  127  || 0  | 0  | 0  | 1
 FF | 255  |  -1   | FF | 255  |  -1   | 0  |  0   |   0   || 0  | 0  | 1  | 0
 FF | 255  |  -1   | 7F | 127  |  127  | 80 | 128  | -128  || 0  | 1  | 0  | 0
 FE | 254  |  -2   | FF | 255  |  -1   | FF | 255  |  -1   || 0  | 1  | 0  | 1
 FE | 254  |  -2   | 7F | 127  |  127  | 7F | 127  |  127  || 1  | 0  | 0  | 0
 7F | 127  |  127  | FF | 255  |  -1   | 80 | 128  | -128  || 1  | 1  | 0  | 1

你的表格很有帮助,但是127 - -1 应该是 128 而不是 -128。 - James Black
3
@James - 不,引用x86程序员参考手册,“整数值在字节整数范围内为-128到+127”。 - srking
这是一个关于如何系统地确定加法和减法中进位和溢出的好解释。 - Cubi73
8位二进制补码中,128(0x80)等于-128(0x80)。如果以有符号数的形式显示,则正确的形式应该是-128,因为表格显示的是有符号数而不是无符号数。这是一个溢出,如下所示:127 - -1 = -128,如果没有溢出,结果将是+128。(需要9位才能表示)。 - old_timer

10

在加减法运算中,进位和溢出值的4种组合均有可能出现。您可以在这个答案中查看更多示例。

这个答案证明了从A-B得到的进位值是从A+(-B)得到的进位值的相反数。第一个链接中的代码利用了这个属性将ADC转换为SBB

然而,有符号溢出标志的值必须对于A-BA+(-B)都相同,因为它取决于结果是否具有正确的符号位,在两种情况下符号位都是相同的。


1
如果有人想要用ADC实现x86语义的SBB,这里有一个有用的提示:SBB{inputs(a, b, cf), outputs(out, of, sf, zf, af, pf, cf)} = ADC{inputs(a, NOT(b), NOT(cf)), outputs(out, of, sf, zf, NOT(af), pf, NOT(cf))} - mrexodia

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接