1

The operation of ADC is DEST ← DEST + SRC + CF, and the operation of SBB is DEST ← (DEST – (SRC + CF)). What puzzles me is the effect on FLAGS that these instructions have. In the case of SBB, the associativity is clear, and I would therefore assume that SBB is equivalent to (in terms of register states in the end)

    jnc label
    lea src, [src+1]
    sub dest, src
    lea src, [src-1]
    jmp label2
label:
    sub dest, src
label2:

However in the case of ADC, would SRC be added to DEST first and then on top of that CF would be added? It matters because, if so, it would have a different effect on FLAGS.

Erik Eidt
  • 23,049
  • 2
  • 29
  • 53

1 Answers1

5

Carry-out from both ADC and SBB is based on the whole operation.
If you write sbb as dst -= CF, dst -= src, if either of those produces a borrow then CF should be set.

The parens in the pseudo-code are not trying to tell you which part of the operation actually sets FLAGS. You're reading too much into it, and it's not that easy to emulate a full-adder (adc or sbb with carry in and carry out. That's why it's super helpful to have hardware supported instructions for them.)

Your emulation for sbb is buggy for the case where src+CF wraps to 0. You don't distinguish the src=-1 CF=1 case (always carry) from src=0, CF=0. (dst-=0 always produces CF=0). Try it on a real CPU with a debugger.


You can think of ADC as dst += src + CF (or -= for SBB) where the src+CF temporary is computed without truncation; e.g. a 33-bit sum for 32-bit operand-size. The dst and CF outputs of ADD / SUB / ADC / SBB can also be regarded as a 33-bit value.

Simple example:

mov al, 0xFF         ; AL=0xFF
stc                  ; CF=1
adc al, 0xFF         ; CF:AL = AL + (0xFF+CF) = AL + 0x100
; AL = 0xFF,  CF=1

It's complicated enough to emulate adc it's more helpful IMO to just understand it in terms of carry-in and carry-out from addition. Or if it helps, like a full adder, or actually a chain of 8, 16, 32, or 64 full adders. (Of course the physical implementation is lower latency than ripple carry).

For me, working out the annoyingly complicated sequence of branching or whatever that would be needed to emulate adc or sbb in terms of 32-bit fixed-width operations would be zero help in understanding what they do. They're simple enough to think of as primitive operations, and hard enough to emulate.

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
  • 1
    So emulating ADC would require at least two ADDs? –  Jun 09 '20 at 19:07
  • 1
    @super: That or equivalent INC or LEA to preserve CF after branching based on the incoming CF, yes. Same for SBB; if `src+1` overflows to zero, your emulation can give the wrong answer. – Peter Cordes Jun 09 '20 at 19:11