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, 50
SUB AL, 8 ; AL = 42
AAM ; AH = tens, AL = ones
OR AX, 3030h ; both digits -> characters
MOV BX, AX
MOV DL, BH
MOV AH, 02h ; DOS: print DL
INT 21h
MOV DL, BL
MOV AH, 02h
INT 21h

Flags

Again the flags describe both the signed and the unsigned reading of the operands.

FlagSet when
CFa borrow was needed: unsigned, the source was larger than the destination
OFthe signed difference did not fit (for example 100 − (−100) in a byte)
ZFthe result is 0, which means the two values were equal
SFthe top bit of the result is 1
AFa borrow out of bit 3 (used by AAS and DAS)
PFthe 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.