1

I've encountered two possibilities for how the carry flag can be set with:

0x00_00_00_00_00_00_00_00 - 0x80_00_00_00_00_00_00_00

(underscores to show bytes)

If I did this by subtraction, we would have to borrow from a bit we don't have, which should set the CF to 1.

However, I was under the impression that ALUs do not subtract, but rather just add the two's complement. The two's complement of 0x80_00_00_00_00_00_00_00 is 0x80_00_00_00_00_00_00_00. So, 0x00_00_00_00_00_00_00_00 - 0x80_00_00_00_00_00_00_00 does not carry any bits out of the 63 bit, which would set the CF to 0.

Which of these situations is valid for 64 bit values in x86?

Does the ALU actually carry out a subtraction or does it convert to 2's complement and the converted values to do a subtraction?

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
Enigma22134
  • 532
  • 5
  • 12
  • 2
    Why haven't you tried it? x86 will subtract so it will set CF to 1. Some architectures do indeed use CF reversed for subtraction. – Jester Nov 12 '16 at 19:51
  • I'm not sure how to test this? How would I go about seeing the result? I'm in an introduction to systems class; everything is in C. I can view the disassembly, but I have no idea how to see the status registers? I could probably program something to try and infer what is happening, but I would love to know how to actually view the flags. – Enigma22134 Nov 12 '16 at 20:20
  • Use a debugger. `(gdb) p $eflags` gives `$1 = [ CF PF SF IF OF ]` Also, if you are coding in C, why do you care about flags? The compiler will take care of them... – Jester Nov 12 '16 at 20:26
  • I need to know how the flags work for my exams. Our lab is just C programs, but we're learning about x86 in class. Thanks, I check out the behavior. :) – Enigma22134 Nov 12 '16 at 21:28
  • You can also make an ALU that subtracts, and then implement addition on top of that. Which one of these the various x86's (there isn't just one implementation, while its a family with similar semantics the implementations can be (and are) very different) actually use in their ALU is impossible to find out by experimentation. – harold Nov 12 '16 at 21:38

1 Answers1

1

See Understanding Carry vs. Overflow conditions/flags to learn more about carry.

Yes of course any implementation of SUB still has to preserve the same architecturally-visible behaviour, including the flag results.

It doesn't matter how the ALU works internally, only what the results are, and zero minus non-zero produces a carry, so any x86 CPU will set CF in this situation. Any CPU that doesn't is not an x86.

See the tag wiki for links to Intel's x86 manuals (and lots of other good links); I'm sure there's a section on flag-setting behaviour somewhere in the official manuals.


In practice, yes, presumably x86 CPUs use a normal binary adder-subtractor, where sub / cmp is done by NOTing one input and feeding in a carry-in of 1 to the low bit. (So there's only a single addition, so an input of 0 becomes FFFFFFFF with a carry-in of 1, guaranteeing a carry-out from the ALU adder).

Since x86 wanted the semantics of CF to be a borrow on subtraction, it has to invert the ALU adder's carry-out signal when doing subtraction, and x86 sbb has to invert it back.

Some other ISAs, like ARM, have their carry flag indicate not-borrow, so ARM's sbc can feed the C flag directly into the ALU just like its adc.

See also Arithmetic identities and EFLAGS re: emulating sub with not / stc / adc. And I guess a cmc to complement CF afterwards. I haven't checked if that would give correct output for OF signed-overflow.

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847