The Intel 80386, part 3: Flags and condition codes

Raymond Chen

Raymond

The flags register contains a bunch of stuff, but here are the flags easily accessible in the debugger:

FlagClear/SetMeaningNotes
OFnv/ovOverflow
DFup/dnDirectionMust be up at function boundaries
SFpl/ngSign
IFei/diInterruptsSet if interrupts are enabled
ZFnz/zrZero
AFna/acAuxiliary carryNot used by C code
PFpe/poParityNot used by C code
CFnc/cyCarry

We’ll learn about the direction flag when we get to string operations. The important detail for now is that the direction flag must be clear (up) at function boundaries.

Instructions for manipulating the interrupt flag are privileged, so you won’t see user-mode code messing with it. I wouldn’t normally have mentioned it, but the Windows disassembler displays the state of the interrupt flags in the register output, so I included it here just so you can see what it means (and then promptly forget about it).

The auxiliary carry is used to indicate whether a carry occurred between bits 3 and 4. It is used by the binary coded decimal instructions.

The parity is used to indicate whether the number of set bits in the least significant 8 bits of the result is odd or even.

The Clear/Set column denotes how the Windows disassembler represents flags in the register output:

eax=00000000 ebx=00000000 ecx=9f490000 edx=00000000 esi=7f19e000 edi=00000000
eip=77a93dad esp=0048f844 ebp=0048f870 iopl=0         nv up ei pl zr na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000246

The efl represents the value of the 32-bit flags register, and selected bits are parsed out and rendered as mnemonics on the line above.

Various combinations of conditions can be expressed with condition codes. Note that many conditions have multiple mnemonics. The first one listed is the one the disassembler uses.

CodeMeaningConditionNotes
EEqualZF
ZZero
NENot equal!ZF
NZNot zero
AAbove!CF && !ZFUnsigned greater than
NBENot below or equal
AEAbove or equal!CFUnsigned greater than or equal
NBNot below
NCNo carryNo unsigned overflow
BBelowCFUnsigned less than
NAENot above or equal
CCarry setUnsigned overflow
BEBelow or equalCF || ZFUnsigned less than or equal
NANot above
GGreater!(SF ^ OF) && !ZFSigned greater than
NLENot less than or equal
GEGreater than or equal!(SF ^ OF)Signed greater than or equal
NLNot less than
LLess than(SF ^ OF)Signed less than
NGENot greater than or equal
LELess than or equal(SF ^ OF) || ZFSigned less than or equal
NGNot greater than
SSignSFNegative
NSNo sign!SFPositive or zero
OOverflowOFSigned overflow
NONo overflow!OFNo signed overflow
PParityPFEven number of bits set
PEParity even
NPNo parity!PFOdd number of bits set
POParity odd

The overflow and parity conditions are not normally used by C code. Note also that many flags are not testable via condition codes. (Poor auxiliary carry flag. Nobody loves you.)

There are a few instructions for directly manipulating selected flags:

    STC         ; set carry
    CLC         ; clear carry
    CMC         ; complement (toggle) carry

    STD         ; set direction (go down)
    CLD         ; clear direction (go up)

Controlling the interrupt flag is a privileged instruction, so you won’t see it in user-mode code. There are no instructions for directly manipulating the other flags, but you can manipulate them indirectly by performing an arithmetic operation with a known effect on flags. For example, you can force ZF to be set by performing a calculation whose result is known to be zero, such as XOR EAX, EAX.

Okay, that was extremely boring, but it had to be done. Next time, we’ll start doing arithmetic.

Raymond Chen
Raymond Chen

Follow Raymond