PUSHF pushes the whole 16-bit flags register onto the stack, like a PUSH of a register (SP − 2). POPF pops a word into the flags register (SP + 2), so every flag, including TF, IF and DF, takes the value from that word. They are the only instructions that read or write all the flags at once, and POPF is the only ordinary way to set TF.
STC ; CF = 1PUSHF ; save the flagsCLC ; CF = 0POPF ; CF = 1 againMOV AL, 0ADC AL, 0 ; AL = 0 + 0 + CFADD AL, '0' ; digit -> characterMOV DL, ALMOV AH, 02h ; DOS: print DLINT 21h
Uses
Keeping the caller's flags across a routine that changes them, for instance one that must preserve DF or IF. Changing a single flag that has no instruction of its own: push the flags, pop them into a register, change the bit, push it and pop it into the flags. A debugger sets TF (bit 8) this way so that the CPU raises INT 1 after the next instruction.
PUSHFPOP AX ; AX = flagsOR AX, 0100h ; set TF (bit 8)PUSH AXPOPF ; single-step mode from here on
Telling the CPU apart
On the 8086 and 8088, bits 12 to 15 of the flags word always read as 1, whatever POPF tried to write. On the 80286 in real mode they always read as 0. Programs used this to detect the processor.
PUSHFPOP AXAND AX, 0FFFh ; try to clear bits 12-15PUSH AXPOPFPUSHFPOP AXAND AX, 0F000hCMP AX, 0F000h ; still all set: an 8086 or 8088JE CPU86
Pitfalls
POPF restores IF as well. A routine that does PUSHF / CLI / ... / POPF turns interrupts back on only if they were on before, which is usually what you want; a plain STI at the end would turn them on unconditionally. An interrupt pushes the flags itself, and IRET pops them, so an interrupt handler does not need PUSHF.
Later CPUs
The 80286 uses bits 12 to 14 for the I/O privilege level and nested task flag; in protected mode POPF may not change IF or IOPL without enough privilege. The 80386 adds PUSHFD / POPFD for the 32-bit EFLAGS.