2
votes

Jump's based on comparing signed integers use the Zero, Sign, and Overflow flag to determine the relationship between operands. After CMP with two signed operands, there are three possible scenario's:

  1. ZF = 1 - Destination = Source
  2. SF = OF - Destination > Source
  3. SF != OF - Destination < Source

I'm having trouble understanding scenario 2 and 3. I've worked through the possible combinations and see that they do work - but I still can't figure out why they work.

Can anyone explain why a comparison of the Sign and Overflow flags reflects signed integer relationships?

Edit:

There seems to be some understanding regarding what I'm asking. Jumps based on signed comparisons utilize the Zero, Sign, and Carry flag - these include JG, JL, and so on.

For example:

mov   al, 1
cmp   al, -1    
jg    isGreater

isGreater: 

The jump is taken because Overflow flag = Sign Flag (both are 0), indicating in terms of signed comparison, the destination operand is larger than the source.

If the Overflow flag was set to 1 and the Sign flag set to 0, that would indicate the destination is smaller.

My questions is - I just can't seem to wrap my head around WHY this actually works.

2
Think of a compare as a subtract where the result is discarded - the flags and their interpretation make more sense in that light (to me at least).Paul R
I understand CMP, Carry, and Overflow. I'm saying I don't understand how a combination of the Sign and Overflow flag reflects the relationship between two signed operands, used by Jumps based on signed comparisons.cafekaze
Try working through some actual examples with pen and paper - there aren't very many different cases to test. This will be much more educational than someone trying to explain it (especially given that there are already plenty of good written explanations available).Paul R

2 Answers

5
votes

Performing the signed subtraction R = Destination - Source yields a signed result.

Suppose there is no overflow - the usual arithmetic laws holds: if R = Destination - Source > 0 then Destination > Source.
Having no overflow means OF = 0 and R > 0 means SF = 0.

Now suppose there is an overflow - let's call O the most significant, non-sign, bit and S the sign bit.
An overflow condition means that either a) Computing the result's O needed a borrow and result's S didn't or b) result's O didn't need a borrow and S did.

In case a) since result's S didn't need a borrow, the two S bits of the operands were either (1, 0) (1, 1) or (0, 0).
Since result's O needed a borrow, and thus flipping the first source S bit, we must exclude the second and third option.
So the operands sign bits were 1 and 0 (thus Destination < Source), the result's sign bit SF = 0 and OF = 1 by hypothesis.

In case b) since result's S did need a borrow, the two S bits of the operands were (0, 1).
Since O didn't need a borrow, the first operand S bit has been not changed and we don't need to consider any further case.
So the operands sign bits were 0 and 1 (thus Destination > Source), the result's sign bit SF = 1 and OF = 1 by hypothesis.

To recap:

  • If OF = 0 then Destination > Source => SF = 0.
  • If OF = 1 then Destination > Source => SF = 1.

In short OF = SF.

3
votes

The OF flags tracks signed overflow, i.e. a change in the sign.
The sign flag obviously just tracks whether a number is negative or not.
Both flags monitor the sign or most significant bit (MSB) of the destination operand.

The compare CMP instructions perform a subtract.
If A != B and both operands have the same sign then obviously the following will happen (assume dword operands).

 100 -  200 = -100 (sign change OF=1 + SF=1, ergo A(100) < B(200)).
-100 - -200 =  300 (sign change OF=1 + SF=0, ergo A(-100) > B(-200)).

If A and B have different signs than the following will happen.

-100 - 100 = -200 (no sign change, SF=1, OF=0, A < B)
100 - -100 = 200  (no sign change, SF=0, OF=0, A > B)

That's all possible scenario's with OF+SF covered.
As you can see A > B only when SF <> OF and A < B only when SF = OF.

The only exception is when unsigned overflow occurs.
Let's assume we're comparing byte operands (-128..127).

126 - -126 = -4 (sign change OF=1 + SF=1, ergo A(126) < B(-126)) ***Oops.

However this will trigger the carry flag (CF) to be set, which the non-overflowing operations will not.
These incorrect results only occur when the result of the calculation does not fit inside the operand size, the solution is to keep a close eye on the carry flag and don't assume that OF and SF handle all possible cases.