14

I'm trying to wrap my head around overflow & carry flags in x86.

As I understand it, for addition of signed 2's complement numbers, the flags can only be generated in one of four ways (my examples are 4-bit numbers):

  1. pos+pos = neg (overflow)
    • 0111 + 0001 = 1000 (7 + 1 = -8)
  2. pos+neg = pos (carry)
    • 0011 + 1110 = 0001 (3 + -2 = 1)
  3. neg+neg = neg (carry)
    • 1111 + 1111 = 1110 (-1 + -1 = -2)
  4. neg+neg = pos (overflow & carry)
    • 1000 + 1001 = 0001 (-8 + -7 = 1)

So, in x86 assembly, does subracting B from A generate the same flags as adding A and -B?

Robz
  • 1,747
  • 5
  • 21
  • 35
  • 1
    See also [Understanding Carry vs. Overflow conditions/flags for signed vs. unsigned.](http://teaching.idallen.com/dat2343/10f/notes/040_overflow.txt), and other links in the [x86 tag wiki](https://stackoverflow.com/tags/x86/info). – Peter Cordes Sep 01 '17 at 18:04

2 Answers2

23

Here's a reference table that might help. This shows an example of every possible combination of the 4 arithmetic flags that can result from the ADD and SUB instructions on x86. 'h' 'ud' and 'd' stand for hex, unsigned decimal and signed decimal representations of each value. For example, the first row for SUB says 0xFF - 0xFE = 0x1 with no flags set.

But, I think the short story is that Alex's answer is correct.

 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
srking
  • 4,512
  • 1
  • 30
  • 46
  • Your table is helpful, but 127 - -1 is 128 not -128. – James Black Feb 27 '13 at 17:43
  • 3
    @James - No, quoting the x86 programmer's reference "Integer values range from –128 to +127 for a byte integer" – srking Feb 27 '13 at 22:39
  • http://www.doc.ic.ac.uk/~eedwards/compsys/arithmetic/ Nice explaination on how to determine carry and overflow systematically. For both, addition and subtraction. – Cubi73 Apr 03 '15 at 23:15
  • 8 bit twos complement 128 (0x80) = -128 (0x80) the proper form would be -128 if shown as a signed number as the table shows signed numbers not unsigned. Its an overflow as demonstrated: 127 - - 1 = -128 if it had not overflowed then the result would be +128. (need 9 bits for that) – old_timer Nov 15 '19 at 14:54
10

All 4 combinations of the carry and overflow values are possible when adding or subtracting. You can see more examples in this answer.

This answer contains a proof of the fact that the carry that you get from A-B is the inverse of the carry you get from A+(-B). The code by the first link exploits this property to turn ADC into SBB.

The signed overflow flag value, however, must be the same for both A-B and A+(-B) because it depends on whether or not the result has the correct sign bit and in both cases the sign bit will be the same.

Community
  • 1
  • 1
Alexey Frunze
  • 61,140
  • 12
  • 83
  • 180
  • 1
    A useful note in case someone is implementing x86 semantics for SBB in terms of ADC: 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 Jun 20 '18 at 11:22