SUB subtracts the source from the destination and stores the difference in the destination: SUB AX, BX sets AX = AX − BX. The operand rules are the same as for ADD: bytes with bytes, words with words, register, memory or immediate as the source, never two memory operands and never a segment register. With a memory destination and an immediate source, give the size: SUB WORD PTR [BX], 2.
MOV AL, 50SUB AL, 8 ; AL = 42AAM ; AH = tens, AL = onesOR AX, 3030h ; both digits -> charactersMOV BX, AXMOV DL, BHMOV AH, 02h ; DOS: print DLINT 21hMOV DL, BLMOV AH, 02hINT 21h
Flags
Again the flags describe both the signed and the unsigned reading of the operands.
| Flag | Set when |
|---|---|
| CF | a borrow was needed: unsigned, the source was larger than the destination |
| OF | the signed difference did not fit (for example 100 − (−100) in a byte) |
| ZF | the result is 0, which means the two values were equal |
| SF | the top bit of the result is 1 |
| AF | a borrow out of bit 3 (used by AAS and DAS) |
| PF | the low byte of the result has an even number of 1 bits |
So MOV AL, 3 then SUB AL, 5 leaves AL = FEh, which is −2 as a signed byte or 254 unsigned, with CF = 1 (a borrow) and SF = 1.
Idioms
SUB AX, AX clears AX and sets ZF, just like XOR AX, AX. SUB SP, n reserves n bytes of local variables on the stack. If you only want to know how two values compare and do not need the difference, use CMP, which does the same subtraction but throws the result away. For numbers wider than 16 bits, subtract the low words with SUB and the higher ones with SBB.
Later CPUs
The 386 adds 32-bit forms (SUB EAX, EBX); nothing else changed.