Instructions
x86-64ADC / SBB
Add-with-carry and subtract-with-borrow. The carry flag is folded into the operation, which is exactly how the CPU chains arithmetic across multiple words.
ADC dst, src computes dst = dst + src + CF. SBB dst, src computes
dst = dst - src - CF. They behave just like ADD/SUB
but additionally fold in the carry flag left over from a previous operation.
Multi-word arithmetic
This is what they exist for. To add two 128-bit values held in register pairs,
add the low halves with ADD (which produces a carry), then add the high
halves with ADC (which consumes it):
; (rdx:rax) += (rcx:rbx)
add rax, rbx ; low half; CF = carry-out
adc rdx, rcx ; high half + carrySubtraction mirrors this with SUB then SBB:
; (rdx:rax) -= (rcx:rbx)
sub rax, rbx ; low half; CF = borrow-out
sbb rdx, rcx ; high half - borrowBecause the chain depends on CF, you must not disturb the flag between the two
instructions — note that INC/DEC preserve CF
precisely so they can be used inside such loops.
Reverse-engineering notes
add … / adc …andsub … / sbb …pairs are the unmistakable signature of 64-bit math on a 32-bit target, or 128-bit (__int128) math on x86-64. Spotting them tells you the source operated on a wider integer type than the register width.sbb reg, regis a famous idiom that has nothing to do with subtraction: it materialisesCFas a full-width mask —0ifCFwas clear, all-ones (-1) if set. Combined withNEGorand, it builds branchless conditionals.setb/setc(SETcc) is the modern, clearer replacement compilers now prefer.- Long carry-propagating loops (
adc/sbbinside a loop over an array of words) are typical of big-integer / cryptographic code: bignum addition, modular arithmetic, montgomery multiplication.