Introduction: The Tale of Two Modes
If you’ve ever wondered why x86 processors boot in real mode, or what exactly protected mode protects you from, you’re in the right place. This is the story of how Intel tried to build a better processor, got stuck with backward compatibility, and ended up creating one of the most confusing architectures in computing history.
I remember the first time I tried to understand real mode versus protected mode. I was reading the Intel Software Developer’s Manual (all 4,000+ pages of it), and I kept thinking: “Why is this so complicated? Why can’t we just use 32-bit addressing from the start?”
The answer, as with so many things in computing, is backward compatibility. The x86 architecture carries the weight of 40+ years of design decisions, and real mode is the most visible manifestation of that history.
In this article, we’re going to dissect real mode and protected mode from a conceptual level. We’ll understand WHY they exist, HOW they work, and WHAT the implications are for assembly programmers. We’ll explore the addressing mechanisms, the privilege levels, the transition between modes, and the architectural evolution that led to long mode (x86-64).
By the end of this article, you won’t just know the mechanics of LGDT and CR0.PE—you’ll understand the philosophical and engineering trade-offs that shaped modern x86 processors.
The 8086 Legacy – Why Real Mode Still Exists
To understand real mode, we have to go back to 1978. The Intel 8086 processor was being designed, and the Intel engineers had a problem: how do you address more than 64KB of memory when your CPU registers are only 16 bits wide?
The 8086 Addressing Problem
The 8086 had 16-bit general-purpose registers (AX, BX, CX, DX, etc.), but it needed to address up to 1MB of memory (2^20 bytes). With only 16 bits, you can only address 64KB directly. How do you get to 1MB?
The solution that Intel came up with was segmented memory. The idea is simple: use two 16-bit values to compute a 20-bit physical address.
The formula is:
Physical Address = (Segment × 16) + Offset
Or, in hexadecimal:
Physical Address = (Segment << 4) + Offset
For example, if CS (Code Segment) = 0x1000 and IP (Instruction Pointer) = 0x0200, the physical address of the next instruction is:
(0x1000 × 16) + 0x0200 = 0x10000 + 0x0200 = 0x10200
This gives you a 20-bit address (up to 0xFFFF0 + 0xFFFF = 0x10FFEF, which is slightly more than 1MB—but we’ll get to that).
Why “Real Mode”?
The term “real mode” was coined much later (when the 80286 introduced protected mode). In the 8086 era, there was only one mode—what we now call “real mode.” It’s called “real” because addresses correspond directly to physical memory locations. There’s no memory protection, no virtual memory, no privilege levels. What you see is what you get.
Real mode characteristics:
- 20-bit addressing (1MB maximum, though see the A20 line discussion later)
- Segmented memory: All memory accesses use a segment register (CS, DS, ES, SS) combined with an offset
- No memory protection: Any code can read or write any memory location
- No privilege levels: All code runs with full privilege
- 1MB address space (0x00000-0xFFFFF)
The Backward Compatibility Trap
Fast-forward to 1982. Intel is designing the 80286, which has a 24-bit address bus (16MB of addressable memory). They want to add memory protection, virtual memory, and privilege levels. But they have a problem: the 8086 has a massive installed base. Software written for the 8086 MUST run on the 80286.
Intel’s solution was to create two modes:
- Real mode: Acts like an 8086 (for backward compatibility)
- Protected mode: The “new and improved” mode with memory protection
When the 80286 first powers on, it starts in real mode. To use protected mode, you have to explicitly switch. And here’s the kicker: once you switch to protected mode on an 80286, you can’t switch back to real mode without resetting the processor.
This was a massive design flaw. It meant that operating systems couldn’t easily use protected mode while still supporting real-mode applications (like DOS programs). The 80286 could run DOS programs OR protected-mode OS, but not both.
The 80386 Fix (And More Complexity)
The 80386 (1985) fixed this problem by adding the ability to switch back to real mode from protected mode. But by then, the architecture had become incredibly complex. The 80386 added:
- 32-bit addressing (4GB address space)
- Paging (virtual memory)
- The Virtual 8086 mode (a mode within protected mode that simulates real mode)
And thus, the x86 architecture became a layered cake of backward compatibility. Every new processor had to boot in real mode, emulate an 8086, and provide a tortuous path to get to protected mode (and later, long mode).
Why This Matters to Assembly Programmers
As an assembly programmer, you’ll encounter real mode in several contexts:
- Bootloaders: The BIOS loads your bootloader in real mode. If you want to access more than 1MB of memory, you must switch to protected mode (or long mode).
- BIOS interrupts: In real mode, you can use
INT 0x10(video),INT 0x16(keyboard),INT 0x13(disk), and other BIOS services. In protected mode, these don’t work (because they’re 16-bit real-mode code). - Memory limitations: Real mode can only address 1MB (or 1MB + 64KB – 16 bytes, due to the wrap-around issue). For any serious programming, you need protected mode.
- Legacy code: If you’re maintaining or reverse-engineering old DOS programs, you need to understand real-mode segmented memory.
Let me show you a simple real-mode program:
; A real-mode COM program (file. COM)
; Assemble with: nasm -f bin program.asm -o program.com
org 0x100 ; DOS COM programs start at offset 0x100
section .text
start:
; Display a message using DOS INT 0x21
mov ah, 0x09 ; DOS print string function
mov dx, msg ; DS:DX points to the string
int 0x21 ; Call DOS
; Exit to DOS
mov ah, 0x4C
mov al, 0
int 0x21
section .data
msg db 'Hello from real mode!', '$' ; '$' terminates DOS string
This program only works in real mode (or Virtual 8086 mode) because it uses DOS interrupts (INT 0x21). In protected mode, you can’t call DOS interrupts directly.



