1

If the CPU treats the subtraction as add like this question.
Then (-1) - (-2) should be FF...FF + 00...02, and the CARRY FLAG should be set.
I wrote c code to test (-1) - (-2) on linux, but found the CARRY FLAG was not set.
How CPU deal with this situation.

Disassembly Code

00000000004004ed <main>:
  4004ed:   55                      push   %rbp
  4004ee:   48 89 e5                mov    %rsp,%rbp
  4004f1:   c7 45 fc ff ff ff ff    movl   $0xffffffff,-0x4(%rbp)
  4004f8:   c7 45 f8 fe ff ff ff    movl   $0xfffffffe,-0x8(%rbp)
  4004ff:   8b 45 f8                mov    -0x8(%rbp),%eax
  400502:   8b 55 fc                mov    -0x4(%rbp),%edx
  400505:   29 c2                   sub    %eax,%edx
  400507:   89 d0                   mov    %edx,%eax
  400509:   89 45 f4                mov    %eax,-0xc(%rbp)
  40050c:   5d                      pop    %rbp
  40050d:   c3                      retq   
  40050e:   66 90                   xchg   %ax,%ax

GDB test

(gdb) ni
0x0000000000400505 in main ()
(gdb)
0x0000000000400507 in main ()
(gdb) p $eflags
$1 = [ IF ]
phuclv
  • 37,963
  • 15
  • 156
  • 475
mingw xu
  • 11
  • 2
  • 1
    Carry is for unsigned. If you convert your numbers to unsigned you will see that `(-1) > (-2)` so the subtraction does not produce a carry. – Jester Dec 01 '19 at 17:27
  • Exactly as Jester wrote: There are no negative numbers when we talk about carry flag. 255 - 254 = 1, CF=0. Also, who said subtraction is the same as addition? It's just *almost* the same, I would say. – Al Kepp Dec 01 '19 at 17:28
  • 2
    In fact now that you have posted the assembly code, you can directly see that it's doing `0xffffffff - 0xfffffffe` so that clearly does not produce a carry. – Jester Dec 01 '19 at 17:33
  • Carry??? Maybe overflow, but not carry - as it is literally what is done - it overflows the register to subtract values. – Antoniossss Dec 01 '19 at 17:33
  • @Antoniossss `(-1) - (-2)` does not produce overflow either as you can see in the gdb output. – Jester Dec 01 '19 at 17:35
  • I think it shold as it adds 2 to FFFFF....FFFF or something . – Antoniossss Dec 01 '19 at 17:35
  • @Jester Yes, I understand that. But how ALU do than subtraction? Just use A minus B, or negate B and add B to A, then use other condition to determine the flags? – mingw xu Dec 01 '19 at 17:45
  • 1
    There are architectures where carry is reversed for subtraction. x86 is not one of those. As to how it's implemented in hardware, it's hard to tell and as programmers we only care about the visible behavior. – Jester Dec 01 '19 at 17:48
  • Sub is done always as addition of second argument converted to U2. This will work for every sign combination. – Antoniossss Dec 01 '19 at 17:49
  • to get CARRY +1 you would have to have to add 2 positive numbers. It will be only an overflow otherwise - that is easy to implement on hardware level - IF V is set AND both arguments sign bits are 0, than C=1. – Antoniossss Dec 01 '19 at 17:50
  • @Antoniossss: on x86, CF after a subtract is a "borrow" output. It's only set by `a-b` if `a` is below `b` (smaller unsigned value). e.g. `2-3` or `0xFF...FE - 0xFF..FF`. This is why x86's `jb` Below condition is CF==1. https://www.felixcloutier.com/x86/jcc. Some other ISAs (like ARM) have opposite `C` output from subtraction. Maybe you're thinking of that because you use flag names like ARM V and C, not x86 OF and CF. – Peter Cordes Dec 01 '19 at 23:14
  • The answers to the linked duplicate fully answer this, even though the actual question is subtly different. There are probably other duplicates, too, but the one I used is the first I found. – Peter Cordes Dec 02 '19 at 00:38

0 Answers0