Skip to content

Instructions

x86-64

ADC / 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):

asm
; (rdx:rax) += (rcx:rbx)
add rax, rbx      ; low half; CF = carry-out
adc rdx, rcx      ; high half + carry

Subtraction mirrors this with SUB then SBB:

asm
; (rdx:rax) -= (rcx:rbx)
sub rax, rbx      ; low half; CF = borrow-out
sbb rdx, rcx      ; high half - borrow

Because 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 … and sub … / 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, reg is a famous idiom that has nothing to do with subtraction: it materialises CF as a full-width mask — 0 if CF was clear, all-ones (-1) if set. Combined with NEG or and, it builds branchless conditionals. setb/setc (SETcc) is the modern, clearer replacement compilers now prefer.
  • Long carry-propagating loops (adc/sbb inside a loop over an array of words) are typical of big-integer / cryptographic code: bignum addition, modular arithmetic, montgomery multiplication.

See also: ADD / SUB · INC / DEC · RFLAGS · SETcc.