All courses

Binary formats, linkers, instruction sets and compilers, taught from the bytes up. Read the routes below if you do not know where to start; the catalogue under them is every course, with its concepts one click away.

The collection is 34 courses, 398 concepts, 8157 minutes of material, every concept reachable from this page.

Three ways through the collection

These are not difficulty tiers. Each one is an order, and each step says why it sits where it does. The three are meant to be walked in sequence: the second assumes the first, the third assumes both.

Formats: what a binary is

One question, asked seven times.

Start with one container you can read end to end with nothing but xxd. Then read the others as answers to the same questions, because the differences are the evidence that these fields are answers and not laws. Finish with the two formats that are verified rather than loaded, and with the one that makes a loaded executable debuggable.

  1. The only course here with no prerequisites, and the one the other six are written against. Nothing else in the collection declares it a dependency as often as it does.

    8 modules24 concepts408 minintermediatedependency graph
    declared prerequisitesnone — nothing in the collection declares this one as a dependency
  2. Mach-O answers the header, segment, symbol and relocation questions ELF just answered. Its load commands, __LINKEDIT and chained fixups are the clearest proof that these fields are one platform's answers rather than the answers.

    8 modules24 concepts400 minintermediatedependency graph
    declared prerequisiteself
  3. PE answers them a third time, with a DOS stub, sixteen data directories and an RVA model. Having read ELF and Mach-O, the DOS stub reads as an accident rather than a mystery.

    8 modules24 concepts360 minintermediatedependency graph
    declared prerequisiteself
  4. The object-file layer all three share: PE is built out of COFF, and so is the classic Mach-O object file. It sits after the two of them and before the formats that are only a container.

    5 modules18 concepts334 minintermediatedependency graph
    declared prerequisitespe
  5. A format with no operating system in it. The class file is verified, not loaded, and after ELF, PE and Mach-O that trade is legible as a container giving up the loader's job to a verifier.

    5 modules18 concepts369 minintermediatedependency graph
    declared prerequisiteselfcoff
  6. Almost every number in the file is one variable-width encoding, and the core specification deliberately does not define an object file. It is the format where the compiler/runtime boundary is being renegotiated in public.

    5 modules13 concepts274 minintermediatedependency graph
    declared prerequisiteselfcoff
  7. The format that travels beside an executable instead of being one, and the only reason a stack trace can name a line. Last because it is what you read once everything else is already in place.

    5 modules23 concepts450 minintermediatedependency graph
    declared prerequisiteself

Every architecture, then the backend

x86-64, then AArch64, then RISC-V, then IR to all three.

Twelve courses that pay the exhaustive per-architecture reference the mission asks for, then the backend that has to emit any of them. The order inside each architecture is fixed by its own prerequisites; the order between the three is a choice, and it is made here so that each one can be read as a contrast against the one before it.

  1. The instruction surface and the encoding behind it. Declares isa, exe, priv, simd and smp -- all of Route 2 -- and is the reference the other two architectures are measured against.

    2 modules5 concepts127 minadvanceddependency graph
    declared prerequisitesisaexeprivsimdsmp
  2. The calling convention: why the fourth argument of a call is in rcx and the fourth argument of a syscall is in r10, which is a difference of one instruction.

    2 modules6 concepts150 minadvanceddependency graph
    declared prerequisitesx86asmisaexesecdynsimd
  3. The privileged side as an inventory: every instruction a ring-3 process can try, and the signal it dies from. The set is not the one in the manual.

    3 modules9 concepts231 minadvanceddependency graph
    declared prerequisitesx86asmx86abiisaexememprivsmpsimd
  4. SSE, AVX and AVX-512, then the instructions that imply LOCK without saying so. Declares x86asm, x86abi, smp, simd and mem -- the last data-path course for this architecture.

    2 modules6 concepts154 minadvanceddependency graph
    declared prerequisitesx86asmx86abiisasmpsimdmem
  5. AArch64 encoding from the ground up: fixed 32-bit, a four-bit class field, and a logical-immediate encoding that reaches 1,302 of 4,294,967,296 constants.

    2 modules5 concepts127 minadvanceddependency graph
    declared prerequisiteself
  6. AAPCS64. The no-flags-register contrast with x86-64 is the reason this is worth reading after x86abi rather than instead of it: one machine needs csel, another does not have a condition to select.

    2 modules5 concepts125 minadvanceddependency graph
    declared prerequisitesa64asm
  7. Modes, exceptions, interrupts, virtual memory and page tables -- six concepts in two modules, the AArch64 half of what x86sys did for x86-64.

    2 modules6 concepts150 minadvanceddependency graph
    declared prerequisitesa64abi
  8. NEON, atomics and memory ordering, where one bit carries two meanings depending on which register it is in. Completes the AArch64 half.

    2 modules5 concepts127 minadvanceddependency graph
    declared prerequisitesa64sys
  9. The encoding spectrum: 16 or 32 bits, decided by two bits that are also the two bits saying 'this is a 32-bit instruction', and a second three-bit register encoding in the compressed extension.

    2 modules5 concepts127 minadvanceddependency graph
    declared prerequisiteself
  10. The calling convention, and the register that isn't there: no flags register and no condition codes anywhere in the base ISA.

    2 modules4 concepts101 minadvanceddependency graph
    declared prerequisiteselfrvasm
  11. The privileged architecture as a document. Declares rvasm, rvabi and obj, and reads the privileged specification the way a compiler author has to read it: encodings, field widths, and the records a page-table walk emits.

    2 modules4 concepts101 minadvanceddependency graph
    declared prerequisiteselfrvasmrvabiobj
  12. Atomics, fences and the vector extension. Declares all three data-path courses and both privileged predecessors, which is why it closes the RISC-V half rather than coming earlier in it.

    2 modules4 concepts101 minadvanceddependency graph
  13. IR to machine code: instruction selection, register allocation, scheduling, and the ABI contract, across all three targets. Declares elf, obj, reloc, link and six of the twelve courses above.

    3 modules6 concepts150 minadvanceddependency graph

107 of 107 declared prerequisites are satisfied by this order.

All 33 courses named by the three routes exist on disk.

Outside the three routes

1 of the 34 courses sits outside all three routes: it has no prerequisites, nothing declares it a dependency, and it is not part of the linking chain or either architecture half. It is listed here rather than left out, because an index that silently drops 69 concepts reads as a bug — and this one is. Its full card is in the catalogue below.

HAT — Higher Education Aptitude Test6 modules69 concepts1141 minbeginner

Every course

Every count on a card — modules, concepts, minutes, difficulty, importance — is read from that course's own manifest, not written down here. Expand a card for a direct link to each lesson in it.

2 modules

The AArch64 Procedure Call Standard

Pass arguments and return values the way AArch64 code expects, and know the rules clang obeys that the C source never mentions, from the stack alignment to the unwind table.

5 concepts125 minadvancedcritical

Every architecture, then the backend · step 6

AAPCS64. The no-flags-register contrast with x86-64 is the reason this is worth reading after x86abi rather than instead of it: one machine needs csel, another does not have a condition to select.

5 concepts
2 modules

AArch64: Encoding From The Ground Up

Decode any AArch64 instruction from its 32 bits: the register classes, the logical-immediate encoding, the conditionals and the bit patterns that do not mean what they first look like.

5 concepts127 minadvancedcritical

Every architecture, then the backend · step 5

AArch64 encoding from the ground up: fixed 32-bit, a four-bit class field, and a logical-immediate encoding that reaches 1,302 of 4,294,967,296 constants.

5 concepts
2 modules

The AArch64 Data Path: NEON, Atomics and Ordering

Read and write AArch64 SIMD registers, express an atomic in the form the architecture defines, and put a barrier where one is actually needed rather than where habit puts it.

5 concepts127 minadvancedcritical

Every architecture, then the backend · step 8

NEON, atomics and memory ordering, where one bit carries two meanings depending on which register it is in. Completes the AArch64 half.

5 concepts
2 modules

The AArch64 Machine: Modes, Memory and Faults

Handle an exception, take a page-table walk and place the registers an interrupt saves, on the machine an embedded target actually runs on.

6 concepts150 minadvancedcritical

Every architecture, then the backend · step 7

Modes, exceptions, interrupts, virtual memory and page tables -- six concepts in two modules, the AArch64 half of what x86sys did for x86-64.

6 concepts
5 modules

COFF — Common Object File Format

Read a COFF object file: its file header, its section table, and the symbol and relocation records a linker uses to place code whose final address nobody knows yet.

18 concepts334 minintermediatecore

Formats: what a binary is · step 4

The object-file layer all three share: PE is built out of COFF, and so is the classic Mach-O object file. It sits after the two of them and before the formats that are only a container.

18 concepts
3 modules

Compiler Backend: From IR to Machine Code

Read a compiler backend from front to back: instruction selection, register allocation, scheduling and encoding, and see every one of those decisions in the emitted bytes.

6 concepts150 minadvancedcritical

Every architecture, then the backend · step 13

IR to machine code: instruction selection, register allocation, scheduling, and the ABI contract, across all three targets. Declares elf, obj, reloc, link and six of the twelve courses above.

6 concepts
5 modules

DWARF — The Debugging Data Format

Take an address in a running program back to the file, line and local variable it came from, by reading the DWARF sections a compiler emits.

23 concepts450 minintermediatecore

Formats: what a binary is · step 7

The format that travels beside an executable instead of being one, and the only reason a stack trace can name a line. Last because it is what you read once everything else is already in place.

23 concepts
4 modules

Dynamic Linking and Shared Libraries

Trace an undefined symbol from the first reference to the shared library that answers it: the lookup scope, .dynsym, versioning, TLS blocks and loading at run time.

10 concepts224 minadvancedcritical

The link: IR to a running process · step 5

PLT, GOT, lazy binding, symbol versioning and TLS: the same symbol table and the same relocations, resolved at run time instead of link time.

10 concepts
8 modules

Executable and Linkable Format

Read any ELF binary end to end: headers, sections, segments, symbols, relocations, and the dynamic structures that connect it to a shared library.

24 concepts408 minintermediatecore

Formats: what a binary is · step 1

The only course here with no prerequisites, and the one the other six are written against. Nothing else in the collection declares it a dependency as often as it does.

24 concepts
3 modules

How a CPU Executes Instructions

Explain why one instruction sequence runs faster than another: dependencies, execution width, the front end, branch prediction and speculation.

6 concepts150 minadvancedcritical

The link: IR to a running process · step 9

How the CPU actually executes them: the pipeline, speculation, branch prediction, store buffers. Declares isa, sec and img, and all three are now behind you.

6 concepts
6 modules

HAT — Higher Education Aptitude Test

Prepare for the HEC Higher Education Aptitude Test: the paper and how it is weighted, quantitative and verbal practice, analytical reasoning, timed drills and full mocks.

69 concepts1141 minbeginnercore

Outside the three routes — see the note below the routes.

69 concepts
4 modules

Executable Images and OS Loading

Follow a program from an executable image to its first instruction: the kernel's mapping, the auxiliary vector, the initial stack and the addresses you are handed.

6 concepts150 minadvancedcritical

The link: IR to a running process · step 6

The loader. auxv, the initial stack, address-space layout, relocation at load, initialisers. The link has produced a file; this is what turns it into a process.

6 concepts
4 modules

The Instruction Set Architecture

Decode x86-64 from bytes yourself: the mode, the opcode map, the prefix layers, ModRM and SIB, and the length arithmetic a tool has to do with no help.

7 concepts167 minadvancedcritical

The link: IR to a running process · step 8

What the bytes inside .text are: registers, flags, addressing modes and decoding, with all three instruction sets contrasted in one place. It declares obj and sec, which is exactly why it sits here and not earlier.

7 concepts
5 modules

JVM Class File Format

Read a .class file: the magic number, the versions, the constant pool everything points into, the code a verifier checks, and the attribute that has carried every new language feature for years.

18 concepts369 minintermediatecore

Formats: what a binary is · step 5

A format with no operating system in it. The class file is verified, not loaded, and after ELF, PE and Mach-O that trade is legible as a container giving up the loader's job to a verifier.

18 concepts
4 modules

Static Linking and Linker Scripts

Follow a link from object files to a finished executable, and write the linker script that decides where every section lands and why.

10 concepts221 minadvancedcritical

The link: IR to a running process · step 4

The static linker's stages, now that it is known what it resolves and how. Linker scripts, archive selection and LTO only make sense once the stages are named.

10 concepts
8 modules

Mach-O Format

Read any Mach-O binary: headers, load commands, segments, sections, symbols, dyld, code signing, and how macOS maps an image into memory.

24 concepts400 minintermediatecore

Formats: what a binary is · step 2

Mach-O answers the header, segment, symbol and relocation questions ELF just answered. Its load commands, __LINKEDIT and chained fixups are the clearest proof that these fields are one platform's answers rather than the answers.

24 concepts
4 modules

The Memory Hierarchy

Predict what a memory access will cost: cache sizes and associativity, the translation path, prefetching, and the point where a huge page stops paying for itself.

8 concepts192 minadvancedcritical

The link: IR to a running process · step 10

What happens between a load and its value: caches and associativity, TLBs, stores, and why a chase and a sweep measure different things. Declares isa and exe.

8 concepts
5 modules

Object Files

Read the object file your compiler emits: its sections, its symbol tables, its fixup records and the holes left for a linker to fill.

18 concepts362 minintermediatecore

The link: IR to a running process · step 1

The artefact every compiler emits and no programmer ever sees. It compares ELF, COFF and Mach-O object files side by side, which is why Route 1 comes first.

18 concepts
8 modules

Portable Executable Format

Read any Windows PE image: the DOS and COFF headers, data directories, sections, imports, exports, base relocations, TLS and resources.

24 concepts360 minintermediatecore

Formats: what a binary is · step 3

PE answers them a third time, with a DOS stub, sixteen data directories and an RVA model. Having read ELF and Mach-O, the DOS stub reads as an accident rather than a mystery.

24 concepts
4 modules

Exceptions, Privilege and Mode Changes

Explain what happens when a program asks for something it cannot do itself: the gate tables, the ways in, and what the privilege boundary really protects.

8 concepts204 minadvancedcritical

The link: IR to a running process · step 11

Exceptions, privilege levels and mode changes -- the boundary between asking for something and being refused, and the three ways in. Declares isa, exe, img and sec.

8 concepts
4 modules

Relocations, PIC and PIE

Choose the right relocation for a reference, explain what position independence actually costs, and recognise the two ways it goes wrong.

9 concepts195 minadvancedcritical

The link: IR to a running process · step 3

Why one relocation type is not enough -- absolute, PC-relative, GOT-relative, the addend and the pairing rules -- and what position independence actually costs. Needs both the file and the name, so it follows both.

9 concepts
2 modules

The RISC-V ABI, and the Register That Isn't There

Pass arguments and results the way RISC-V code requires, and understand why the architecture needs no condition-code register at all -- and what a compiler does instead.

4 concepts101 minadvancedcritical

Every architecture, then the backend · step 10

The calling convention, and the register that isn't there: no flags register and no condition codes anywhere in the base ISA.

4 concepts
2 modules

RISC-V: The Encoding Spectrum

Decode RISC-V instructions, compressed or not, and see why one format scatters its immediates while the compressed extension adds a second register field entirely.

5 concepts127 minadvancedcritical

Every architecture, then the backend · step 9

The encoding spectrum: 16 or 32 bits, decided by two bits that are also the two bits saying 'this is a 32-bit instruction', and a second three-bit register encoding in the compressed extension.

5 concepts
2 modules

RISC-V Atomics and the Vector Extension

Write correct RISC-V atomics and memory ordering, and set up a vector whose length and element width are programmed at run time rather than fixed in the encoding.

4 concepts101 minadvancedcritical

Every architecture, then the backend · step 12

Atomics, fences and the vector extension. Declares all three data-path courses and both privileged predecessors, which is why it closes the RISC-V half rather than coming earlier in it.

4 concepts
2 modules

The RISC-V Privileged Architecture

Read the RISC-V privileged specification as a compiler author: CSR encodings and their accessibility fields, the satp page-table format, and the relocation records a walk emits.

4 concepts101 minadvancedcritical

Every architecture, then the backend · step 11

The privileged architecture as a document. Declares rvasm, rvabi and obj, and reads the privileged specification the way a compiler author has to read it: encodings, field widths, and the records a page-table walk emits.

4 concepts
4 modules

Executable Security and Hardening

Say what each hardening flag does to the bytes it produces, and which of the three layers -- compiler, linker or driver -- is where that decision gets made.

7 concepts167 minadvancedcritical

The link: IR to a running process · step 7

Hardening flags, once you know which bytes are code, which are relocatable and which the loader decides. RELRO, W^X and CET read as changes to specific fields rather than as switches.

7 concepts
4 modules

SIMD and Vector Processing

Decide when vectorisation pays, read a vector instruction, and use gathers, reductions and lane boundaries without a data-dependent stall.

7 concepts186 minadvancedcritical

The link: IR to a running process · step 13

Vectors last of the neutral courses because its costs are the memory hierarchy's costs: the same 4-wide loop wins on L1-resident data and stops winning at 24 MiB, with the lane count unchanged between the two numbers.

7 concepts
4 modules

Multiprocessor Architecture

Reason about a program running on more than one core: topologies, true and false sharing, memory ordering, and when an atomic instruction buys anything at all.

7 concepts179 minadvancedcritical

The link: IR to a running process · step 12

Multiprocessor: true and false sharing, the cost of a lock prefix with nothing to lock against, NUMA. Declares mem, exe, isa and priv, so it closes the neutral core.

7 concepts
4 modules

Symbol Resolution and Symbol Tables

Explain how a linker turns a name into an address: binding, visibility, archive extraction, versioning and the symbols the linker invents on your behalf.

12 concepts253 minadvancedcritical

The link: IR to a running process · step 2

The linker's central data structure, and the one both the static and the dynamic linker need. It is here rather than after relocations because a relocation's whole job is patching a reference to a symbol.

12 concepts
5 modules

WebAssembly — The Binary Format

Read a WebAssembly binary: its eight-byte header, its ordered sections, the variable-width LEB128 encoding almost every number uses, and the object file built on top.

13 concepts274 minintermediatecore

Formats: what a binary is · step 6

Almost every number in the file is one variable-width encoding, and the core specification deliberately does not define an object file. It is the format where the compiler/runtime boundary is being renegotiated in public.

13 concepts
2 modules

The x86-64 ABI

Place arguments, results and callee-saved registers the way x86-64 code requires, including why a system call moves the return address into r10 instead of rcx.

6 concepts150 minadvancedcritical

Every architecture, then the backend · step 2

The calling convention: why the fourth argument of a call is in rcx and the fourth argument of a syscall is in r10, which is a difference of one instruction.

6 concepts
2 modules

x86-64 Assembly and Encoding

Write and read x86-64 assembly: the legacy, VEX and EVEX encodings, the flags, the conditionals and the addressing modes a compiler emits.

5 concepts127 minadvancedcritical

Every architecture, then the backend · step 1

The instruction surface and the encoding behind it. Declares isa, exe, priv, simd and smp -- all of Route 2 -- and is the reference the other two architectures are measured against.

5 concepts
2 modules

The x86-64 Data Path: Atomics, Ordering and Vectors

Write correct x86-64 atomics and vector code, and know which LOCK-prefixed forms are exact, which only look it, and what alignment really costs.

6 concepts154 minadvancedcritical

Every architecture, then the backend · step 4

SSE, AVX and AVX-512, then the instructions that imply LOCK without saying so. Declares x86asm, x86abi, smp, simd and mem -- the last data-path course for this architecture.

6 concepts
3 modules

The x86-64 Machine: Privilege, Memory and Time

Find out what a ring-3 process can and cannot ask the CPU for, and tell a privilege check apart from a page table that will not map you.

9 concepts231 minadvancedcritical

Every architecture, then the backend · step 3

The privileged side as an inventory: every instruction a ring-3 process can try, and the signal it dies from. The set is not the one in the manual.

9 concepts