INT n is a far call through a table. The first 1024 bytes of memory, 0000:0000 to 0000:03FF, hold 256 vectors of four bytes each: an offset, then a segment. Vector n lives at address n × 4. The CPU does this:
| Step | What happens |
|---|---|
| 1 | push FLAGS |
| 2 | clear IF (no maskable interrupts) and TF (no single-stepping) |
| 3 | push CS |
| 4 | push IP: the address of the instruction after the INT |
| 5 | load IP from word n × 4 and CS from word n × 4 + 2 |
Six bytes go on the stack, and on entry to the handler [SP] is the return IP, [SP+2] the return CS and [SP+4] the saved flags. The handler ends with IRET, which undoes all three pushes. Because the address is looked up at run time, a program can ask DOS or the BIOS for a service without knowing where its code is.
Calling a service
Services take a function number in AH and further arguments in other registers, and return results in registers, often with CF = 1 for an error. Which registers a service changes is part of its documentation.
MOV AH, 0Eh ; BIOS INT 10h, 0Eh: teletype outputMOV AL, "B"MOV BH, 0 ; display page 0INT 10hMOV AH, 02h ; DOS INT 21h, 02h: print DLMOV DL, "D"INT 21hMOV AH, 09h ; DOS 09h: print a $-terminated stringMOV DX, OFFSET MSG1INT 21hMSG1 DB " <- B from the BIOS, D from DOS", 13, 10, "$"
Interrupts nobody wrote INT for
Hardware uses the same mechanism: the 8259 interrupt controller hands the CPU a vector number (08h for the timer, 09h for the keyboard in a PC), and the call happens between two instructions when IF = 1. The CPU raises some itself: 0 for a divide error, 1 after each instruction when TF = 1, 2 for the non-maskable interrupt, 4 from INTO. INT 3 has a one-byte encoding (CCh) so a debugger can patch it over any instruction as a breakpoint; every other INT n is two bytes, CDh n.
A handler starts with interrupts disabled. A long one should execute STI once it is safe, or the timer and keyboard wait.
Later CPUs
In real mode later processors use the same table and the same pushes. The 80186 adds exceptions of its own (BOUND raises INT 5), and in protected mode the table becomes the interrupt descriptor table of gates.