Exercises — x86 architecture overview
Two tiny reminders we will lean on constantly, stated in plain words before any symbol appears:

Level 1 — Recognition
Recall Solution
x86 is CISC (Complex Instruction Set Computer). The opposite family is RISC (Reduced Instruction Set Computer), which uses fixed-length instructions — see RISC vs CISC. Why: CISC's whole selling point in 1978 was fitting more work per byte, which meant variable length; RISC later traded that density for a regular fixed length that is easier to decode and pipeline.
Recall Solution
Smallest → largest (using = "is nested inside", defined above): AL AX EAX RAX, exposing 8, 16, 32, 64 bits respectively. Why: each name is a window onto the low bits of the same physical register. Nothing is copied; you just read fewer bytes off the low end. Look at figure s01 — every layer is nested inside the next like drawers in a chest.
Recall Solution
Between 1 and 15 bytes (variable); a typical RISC instruction is exactly 4 bytes (fixed). Why the 15-byte cap matters: the decoder must know where instruction ends before it can even find instruction . A hard ceiling of 15 bounds how far the fetch/decode stage must scan.
Level 2 — Application
Before the address problems, look at figure s02. It draws the 1 MB physical address line and shows two segment "bars" reaching the same byte. Keep it beside you for L2·1, L3·1 and L3·2.

Recall Solution
The formula (from the parent note) is WHAT we do: shift the segment left by 4 bits, then add the offset. WHY: the 8086 has only 16-bit registers but wants a 20-bit (1 MB) address. Shifting the segment up by 4 bits places it in the high part of a 20-bit number; the 16-bit offset fills the low part. In figure s02 the coloured bar starts at the shifted segment base and the offset is the arrow that walks along it. In decimal: .
One caveat we'll fully exploit in L5·2: real-mode addresses live in a 20-bit world, so the sum is always taken modulo (1 MB). Here is well under , so no wrap happens — but keep that modulo in the back of your mind.
Recall Solution
Read the low bits off the right-hand end:
EAX= low 32 bits =0xCAFEB0BAAX= low 16 bits =0xB0BAAL= low 8 bits =0xBA
Why: two hex digits = one byte, so AL is the last 2 hex digits, AX the last 4, EAX the last 8. No arithmetic, no data movement — just a narrower window.
Recall Solution
First, the two encodings this hardware actually offers for "put a constant in a 64-bit register" (we re-state them here rather than assume them; the /0 slash notation is defined in the box up top):
REX.W + C7 /0 + imm32— the immediate field is always 4 bytes (imm32); the CPU then sign-extends it to 64 bits. There is no imm8 form formovinto a full register. Recall/0costs exactly one ModR/M byte.REX.W + B8+rd + imm64— the immediate field is a full 8 bytes (imm64), used when the constant doesn't fit in 32 bits. (B8+rdmeans the register number is baked into the opcode byte itself, so there is no separate ModR/M byte here.)
Now count (REX = 1 prefix byte, opcode = 1 byte):
mov rcx, 0x11223344=REX.W(1) + opcodeC7(1) + ModR/M(1) + imm32(4) = 7 bytes.mov rcx, 0x1122334455667788=REX.W(1) + opcodeB8+rd(1) + imm64(8) = 10 bytes.
The second is longer. Why: the immediate constant lives inside the instruction bytes. The 4-byte-immediate form is 7 bytes; needing all 8 bytes of a 64-bit constant forces the imm64 form and pushes the instruction to 10 bytes. Bigger baked-in constant ⇒ longer instruction — the direct, physical cause of variable length.
Level 3 — Analysis
Recall Solution
Compute both:
Both land on 0x10000 — the same byte, exactly the orange dashed line in figure s02.
WHY this happens: the segment is scaled by 16, so incrementing the segment by 1 moves the base by 16 bytes. The offset can range across 0…65535 bytes — far more than 16. So many segment values' ranges overlap, and the same physical address has multiple (segment, offset) names. This is called aliasing, and it is a direct consequence of : only 4 bits of "new" range per segment step, but a full 16-bit offset. In figure s02 the teal and plum bars overlap and both arrows meet at 0x10000.
A second, sneakier source of aliasing: because the real address is taken modulo , any (segment, offset) whose raw sum climbs above 0xFFFFF wraps back down and collides with a low address too. We meet that case head-on in L5·2.
Recall Solution
Step 1 (WHAT): x86 length is variable (1–15). Step 2 (WHY it blocks parallelism): to know where instruction #2 begins, you must know where instruction #1 ends. To know where #1 ends, you must parse its opcode, its ModR/M byte (which may demand a SIB byte), and any displacement/immediate — i.e. you must nearly fully decode #1. Step 3 (consequence): decoding is a chain of dependencies: end of #1 → start of #2 → end of #2 → start of #3. You cannot leap ahead. Contrast: RISC's fixed length means instruction always starts at byte — no parsing needed to find boundaries, so all decoders fire at once. This is the deep reason x86 spends transistors on complex parallel length-predecoders, and it feeds the translation to micro-ops.
Recall Solution
The original 8086 opcode space had no room to name registers R8–R15 (they did not exist) or to say "operate on 64 bits." The REX prefix is an extra leading byte added by AMD64 whose bits extend the register-number fields (the very fields the ModR/M byte and the /r slot use) and set 64-bit operand size.
mov r8, r9— needs REX because R8/R9 are the new registers; the extra high bit of each register number lives in REX (the ModR/M byte alone can only count 0–7).mov rax, rbx— needs REX to select 64-bit operand size (without it you'd get the 32-biteax, ebx).mov ax, bx— needs no REX: 16-bit ops and registers AX/BX existed since 8086, so the old encoding suffices.
Why it's a fossil: REX is the "there was no space left, so we bolted on a prefix" solution — pure backward-compatibility engineering.
Level 4 — Synthesis
Recall Solution
We do not want magic constants, so let us derive each field's maximum before summing:
- Legacy prefixes ≤ 4 bytes. Legacy prefixes come in groups (operand-size, address-size, segment-override, lock/repeat). A sane instruction uses at most one from each group, and there are 4 groups — hence at most 4 legacy prefix bytes.
- REX prefix = 1 byte (a separate category).
REXis not one of the four legacy groups; it is a fifth prefix kind and, when present, sits as one extra byte right before the opcode. It must be counted on its own, so the true prefix allowance the decoder faces is 4 (legacy) + 1 (REX) = 5 bytes. - Opcode ≤ 3 bytes. The oldest opcodes are 1 byte. When Intel ran out of room they added a
0F"escape" byte (2-byte opcodes), then0F 38/0F 3Aescapes (3-byte opcodes). Three is the deepest escape chain that exists — hence 3. - ModR/M = 1 byte. A single byte that names the operand register(s) and addressing form. There is exactly one, so 1.
- SIB = 1 byte. The "Scale-Index-Base" byte, present only when ModR/M asks for scaled-index addressing. At most one — 1.
- Displacement ≤ 4 bytes. A constant address offset; its widest form is a 32-bit (4-byte) displacement — 4.
- Immediate ≤ 4 bytes in this budget. The widest ordinary immediate is 32 bits = 4 bytes (the imm64
movfrom L2·3 is a special one-off that trades the displacement slot away, so it doesn't stack on top here).
Now sum the derived maxima (note REX is counted separately from the 4 legacy prefixes): The naive sum is 18, but no single legal instruction actually uses every field at its maximum simultaneously (e.g. an instruction carrying a 4-byte immediate rarely also carries a 4-byte displacement and the full prefix stack). Intel therefore imposes a hard cap of 15 bytes; any encoding exceeding 15 raises a fault. Enforcing 15 (rather than the naive 18) is exactly how Intel keeps the decoder's scan window bounded even though the fields could sum higher. Synthesis point: the cap is a pragmatic decode-cost limit, not a natural sum. It says "the predecoder never has to scan more than 15 bytes to find a boundary," bounding the worst case of the problem you analysed in L3·2.
Recall Solution
Base physical address of the struct:
Field is 0x0C further in:
(Sanity check on the modulo world: is far below , so no wrap — this is a plain in-range address.)
The mode that expresses [base + displacement] is base-plus-displacement (register-indirect with displacement), e.g. mov eax, [rbx + 0x0C]. Why it fits: the struct's start goes in a base register, and the constant field offset is the displacement baked into the instruction — exactly the ModR/M + Displacement fields from the length budget. The 0x0C here is small enough to ride in a single-byte (disp8) displacement, so the resulting instruction stays short.
Recall Solution
Internally the CPU cracks the one CISC instruction into a small sequence of µops (micro-ops), each RISC-like and simple, roughly:
load tmp ← [rbx](read memory)add tmp ← tmp + rax(arithmetic)store [rbx] ← tmp(write memory)
These µops then flow through the pipeline out-of-order and in parallel with other work (see Micro-operations (µops)). Reconciliation: the ISA stays CISC for backward compatibility (programmers/binaries still see one dense instruction), while the microarchitecture is RISC-like for speed. "x86 is CISC" and "x86 is fast" describe two different layers — the front-end contract vs. the back-end execution engine. Compare with ARM Architecture, which is RISC at both layers.
Level 5 — Mastery
Recall Solution
The argument for extending: x86's single most valuable asset is the enormous installed base of software that runs unchanged. A clean, incompatible ISA would have to win developers, compilers, and users from scratch — historically a graveyard (Intel's own clean 64-bit Itanium struggled for exactly this reason). By keeping the old encodings valid and adding REX + 64-bit + R8–R15 on top, AMD let existing 32-bit code run instantly while offering a 64-bit upgrade path. Compatibility → adoption → market win.
The locked-in cost: the fossils stay forever. Variable-length decoding (the L3·2 serial-boundary tax), the legacy segment registers (CS/DS/SS/ES/FS/GS) even in flat long mode, and an irregular register set are permanent liabilities the decoder pays for on every chip. Mastery insight: this is a classic path-dependence trade — you buy adoption with today's compatibility and pay interest in decode complexity for decades. Given x86's position in 2003, it was the right call.
Recall Solution
Raw sum first:
That value exceeds the 20-bit maximum 0xFFFFF (1 MB − 1). On the real 8086, physical addresses had only 20 wires, so the top bit was simply dropped — i.e. the address is taken modulo and wraps around to a low address:
So segment 0xFFFF, offset 0xFFFF does not point near the top of memory — it lands at 0x0FFEF, right down near the bottom. Why it's a fossil: some 8086 programs depended on this wrap-around (they addressed low memory via a high segment on purpose). When the 80286 added a 21st address wire and stopped wrapping, that broke those programs, so hardware makers added the infamous A20 gate to force the old wrap back on for compatibility. It is a perfect illustration of the mastery theme: even a hardware overflow quirk became a permanent feature because software relied on it — and it is the extreme case of the modulo- aliasing flagged back in L2·1 and L3·1.