Why does CMP (compare) sometimes sets a Carry Flag in 8086 assembly?
Asked Answered
A

4

9

I've been reading around and with the 8086 Instruction Set, it says that a CMP (compare) can set the Carry Flag. I understand that a compare subtracts two operands but I was wondering if anyone can provide an example when that is the case.

I just can't grasp the idea of adding a number and a negative number will set the carry flag. I've read into the borrow flag but I just needed an example to clarify my understanding of a compare instruction.

Also, I understand that if 3 - 5 = -2 would set the negative flag... when is carry set?

Airtight answered 7/11, 2011 at 0:43 Comment(9)
The statement "I need to make an example" makes this sound like homework. If you just debug through some existing code, and watch the CY flag, I'm sure you will see it set after some ADD instructions.Sthilaire
Well I'm creating my own Instruction Set Architecture and I'm just reading up on 8086 instructions and wondering how a compare (which subtracts 2 operands and sets the respective flags) can set the carry flag. I know when the ADD sets the carry, but I'm a little skeptical on subtract/carry (not to be confused with borrow).Airtight
on the 8086 (and many others), the carry flag does double duty and represents the borrow in subtraction or compare operations. If you do a compare where the value being compared is larger than what's in the register, there is a borrow, e.g., the CY flag is set. If the value is the same or smaller than the register, there's no borrow, and CY is cleared.Eurythermal
@Eurythermal So what you're saying is that.. if a subtract uses a borrow, that should set the carry flag?Airtight
yes. that's what i'm saying. double checked with cmd.exe and the strangely still available 'debug' utility.Eurythermal
And what has this to do with MIPS anyway? :SBelostok
I'm confused, you talk about CMP and subtraction, but then you ask "how can adding a number and a negative number set the carry flag?" (Easy: Add +1 and -1. Boom, carry set.) The Intel manual explains how the status flags work. (Section 3.2: Binary arithmetic instructions.)Sthilaire
@faul: the CPU treats the two numbers as unsigned to set the carry flag after ADD/ADC and SUB/SBB. After ADD/ADC the carry tells if the unsigned sum overflowed. After SUB/SBB the carry tells if the unsigned difference underflowed. The CPU treats these same two numbers as signed to set the overflow flag. This flag has the same function for signed numbers as the carry for unsigned numbers. The CPU doesn't care how you treat the numbers. It just sets 2 different overflow/underflow indicators, carry for unsigned numbers, overflow for signed. It's up to you which one of them to use.Geis
Thank you everyone, every little bit helps.Airtight
L
7
  • The carry flag is set after an operation that resulted in an underflow or overflow. For example, subtracting 10 from 6 will result in an underflow and set the carry flag. Similarly, adding 1 to the maximum value of the register will result in an overflow and set the carry flag.
  • The carry flag is also modified during a shift operation, it is set to the value of the last bit shifted out of the destination register.
  • Bit testing will place the value of the tested bit into the carry flag. Opcodes that do this: BT, BTC, BTR, and BTS.
  • Instructions that affect the Carry Flag directly: CLC, CMC, and STC.
  • During a comparison, the carry flag is set just as if the two operands had been subtracted.
  • During a negation (NEG), the carry flag is set unless the operand is zero, in which case it is cleared.
Legionary answered 7/11, 2011 at 16:55 Comment(0)
B
2

Carry flag is normally set when using unsigned arithmetic. For example, adding two unsigned (whose result does not fit in register) numbers would not raise the overflow flag but only carry flag. However, when using signed arithmetic, overflow flag is set in such event.

Babism answered 8/11, 2011 at 21:23 Comment(0)
G
1

You can find examples of when the carry and overflow flags are set to 0 and 1 following addition or subtraction of integer numbers in this answer to a related question.
You can also find there sample C code emulating the add with carry and subtract with borrow instructions for 8-bit numbers and you can play with that, maybe get more examples.

The output format there is something like this:
127( 127) - 255( -1) - 1 = 127( 127) CY=1 OV=0
Where each number is represented as both unsigned and parenthesized signed (2's complement) next to it. The number before = is the carry flag before ADC/SBB. CY= and OV= show the carry and overflow flags after ADC/SBB.

Compare does pretty much the same thing as subtract without borrow, except it only affects the carry, overflow, sign and zero flags (and parity and auxiliary carry, but they're unimportant here) without modifying any number in a register/memory.

Geis answered 8/11, 2011 at 22:42 Comment(0)
W
1

https://www.hellboundhackers.org/articles/read-article.php?article_id=729

Just as a quick summary, I wrote this article for two purposes. First, It is interesting, and more knowledge of how your computer works is always helpful. Secondly, there are always programs where flags will be manipulated directly, and it is helpful to know the effects they will have on jumps. For example, something as simple as CMP eax,ebx JC somewhere might confuse most beginning reversers, but hopefully not after this article. Enjoy :)

[Important Note: I will use 8 bit integers for my examples when I write out binary numbers. Just remember that, although 8 bit integers are not commonly used in programming, the same rules that I discuss apply to integers with more bits]

The CMP Instruction:

The CMP instruction operates by performing an implied subtraction of the two operands. This means that the result is not stored in memory. After subtracting them, it does a few quick tests, updating the Z,O,C,S, and P flags. The P, or parity, flag is rarely used, so we'll ignore it in this article for the purpose of brevity.

Binary subtraction is performed by adding the negated version of the second operand from the first. This is just like what you learned in middle school, about how 4+3 = 4 - (-3), and visa versa. At the end of the article I will explain how this is done, but I'll move onto the more important matters for now since that knowledge is not really needed for cracking or coding.

Sign and Zero Flag:

The four flags that the CMP instruction can set - Z,O,C, and S, are known as the zero, overflow, carry, and sign flags respectively. The zero flag is set whenever the result of the subtraction is equal to zero. This, of course, only occurs when the operands are equal. The sign flag is set when the result of the subtraction is negative. Although we are inclined to think that this means the sign flag in combination with the zero flag are enough to test all > >= < and <=, this is not true, because the result can be negative even if the first number is greater than the second. This is because of overflow.

Overflow Flag:

Signed integers are represented in binary with the same amount of bits as unsigned integers. This means, of course, that the sign must be set in one of the bits of the integer. Signed integers store the sign in the MSB (most significant bit). This means that, while 00000001 converts to 1 in decimal, 10000001 converts to -127. I will discuss why it is -127 and not -1 or -2 later in the article. When the processor performs subtraction, It wraps around if the subtraction goes below 00000000 or above 11111111. Therefore, if you subtract a negative number from a positive one, or subtract a positive number from a negative one, there is the possibility that the answer will overflow over the boundary. For example, 100 - (-100) is equal to 200, but the highest value an 8 bit signed integer can be is 127, so 200 will wrap through the upper boundary and end up as a negative number, even though it should be positive. The same problem occurs with -100 - 100; It wraps through the low end and ends up positive when it should be negative, causing an underflow. Note that an underflow also sets the overflow flag, and overflow will refer to both overflows and underflows further in the article. The CPU checks for this, and sets the overflow flag if it occurs.

Carry Flag:

The carry flag is set when, if both operands are interpreted as unsigned integers, the first one is greater. This is easy to determine because it occurs whenever the subtraction passes through 00000000 into the higher range (11111111). For example, 00000001 - 00000010 = 11111111, so carry is set. However, 00000010 - 00000001 = 00000001, so carry is not set.

Westerman answered 9/4, 2018 at 16:52 Comment(2)
teaching.idallen.com/dat2343/10f/notes/040_overflow.txt is a nice article on unsigned carry vs. signed overflow and how flags are set / what they mean.Gifted
In your last paragraph, I think you have CF backwards. It's set when the 1st operand is below the 2nd. e.g. cmp eax, ecx sets CF if eax < ecx (unsigned), because that's what makes eax - ecx produce a carry-out.Gifted

© 2022 - 2024 — McMap. All rights reserved.