carry/overflow & subtraction in x86
Solution 1
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
Solution 2
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.
Related videos on Youtube
Comments
-
Robz about 2 years
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):
- pos+pos = neg (overflow)
- 0111 + 0001 = 1000 (7 + 1 = -8)
- pos+neg = pos (carry)
- 0011 + 1110 = 0001 (3 + -2 = 1)
- neg+neg = neg (carry)
- 1111 + 1111 = 1110 (-1 + -1 = -2)
- 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?
- pos+pos = neg (overflow)
-
James Black over 11 yearsYour table is helpful, but 127 - -1 is 128 not -128.
-
srking over 11 years@James - No, quoting the x86 programmer's reference "Integer values range from –128 to +127 for a byte integer"
-
Cubi73 about 9 yearsdoc.ic.ac.uk/~eedwards/compsys/arithmetic Nice explaination on how to determine carry and overflow systematically. For both, addition and subtraction.
-
mrexodia about 6 yearsA 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))}
-
old_timer over 4 years8 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)