Machine Code and the CPU
This level has walked a program down through its representations: text, tokens, tree, bytecode. One floor remains, and it is the real one. A physical CPU does not know about your language, your VM, or your intentions. It knows how to do exactly one thing, extremely fast: read a number from memory, treat it as an instruction, carry it out, and move to the next. This lesson is about that floor, because every program you will ever protect or attack ultimately runs there.
Instructions are just numbers
A machine instruction is a pattern of bits sitting in ordinary memory. Some of those bits name the operation, add, load, compare, jump, and the rest name the operands. There is no separate magic storage for code: instructions and data live in the same memory, and the only thing that makes a number an instruction is that the CPU happens to fetch and execute it.
; three machine instructions, shown three ways
; (a simplified teaching encoding, not any specific real chip)
bits in memory as hex human spelling (assembly)
00000001 01000101 -> 01 45 -> LOAD r1, [address 69]
00000011 01001010 -> 03 4A -> ADD r1, r2
00000010 01000101 -> 02 45 -> STORE r1, [address 69]The three columns are the same three instructions. The left column is what actually exists in the machine, the middle is the same bits written compactly for humans, and the right is a readable spelling. Nothing is translated between the columns except notation, the way 12, twelve, and XII are one number in three costumes.
That readable spelling on the right is assembly. It matters to understand what assembly is not: it is not a higher-level language that compiles down. It is a one-to-one human notation for machine instructions, one line per instruction. A disassembler converts the numbers to the spelling; an assembler converts the spelling to the numbers. Both directions are mechanical and lose nothing, which is why disassembly is always available to an attacker, on any program, forever.
Registers: the CPU's hands
Memory is huge but comparatively far away. So the CPU keeps a small set of working slots on the chip itself, called registers, each holding one value. Nearly all real work happens between registers: load a value from memory into a register, combine registers, store a register back to memory. If Level 0's stack and heap are the desk and the warehouse, registers are the CPU's hands, and there are only a couple dozen of them.
Two registers matter most for this course. The program counter holds the memory address of the next instruction, and it is the machine's entire notion of where it is in your program. And a jump instruction is nothing more than an assignment to the program counter. Every if, while, and function call in every language you have seen compiles down, in the end, to arithmetic on this one register.
The fetch-decode-execute cycle
Now the whole machine fits in one loop. Forever, the CPU: fetches the instruction at the address in the program counter, decodes those bits into an operation and its operands, executes the operation, and advances the program counter, unless the instruction was a jump, in which case the jump already set it. That cycle is the entire secret. Silicon runs it billions of times per second, and everything your computer does is that loop wearing different instructions.
You have already operated this loop yourself. Stepping the visualizer below is fetch-decode-execute at human speed: each press picks the next statement (fetch), works out what it means (decode), does it and updates state (execute), and moves the highlight (advance the counter). The CPU differs from you in exactly two ways, its statements are numbers, and it does not get bored.
This should feel familiar for another reason: the stack machine you stepped through two lessons ago runs the same cycle in software, fetch an opcode from the bytecode array, decode it in a dispatch switch, execute the handler, advance. A virtual machine is the fetch-decode-execute loop reimplemented as an ordinary program. The physical CPU runs the VM's loop, and the VM's loop runs your bytecode: one machine hosting another.
Reality check for the curious: modern CPUs do not literally execute one instruction at a time. They pipeline the cycle so several instructions are in flight at once, predict which way jumps will go before knowing, and execute instructions out of order when results permit, all while preserving the illusion of the simple sequential loop. The illusion is the contract: any mental model built on fetch-decode-execute stays correct, which is why the simple loop is still the right thing to learn, decades into these optimizations.
And a consequence for this academy's core subject: because instructions are readable numbers in ordinary memory, no program can hide its own code from the machine that must run it. Whatever encryption or encoding wrapped the instructions, they must exist in executable form at the moment of execution, at an address the program counter can reach, where a debugger or memory dump can also reach them. This is the hardware-level root of the run-and-dump ceiling you will meet formally in Level 5: protection can raise the cost of that capture, sometimes enormously, but the floor guarantees it can never make the capture impossible.
The full tower, assembled
- Source text: written for humans, full of names, formatting, and intent.
- Tokens: the text chopped into typed pieces; formatting and comments already gone.
- AST: the tokens arranged into a tree; structure and precedence made physical.
- Bytecode: the tree flattened into instructions for a software machine; structure dissolved into jumps.
- Machine code: instructions for the silicon itself, numbers in memory driven through fetch-decode-execute.
Every tool you will study from here on lives somewhere on this tower. Compilers move programs down it. Decompilers and disassemblers climb back up it, recovering what they can. Obfuscators rewrite a floor to make the climb expensive. You now know every floor by name, which is the entire prerequisite for the rest of the academy.
A CPU is a loop that fetches numbers, decodes them as instructions, and executes them, with the program counter as its only sense of place. Assembly is a spelling of those numbers, not a separate language, and code must always be present in memory to run. Level 3 is complete: you can follow a program from keystroke to silicon.
Frequently asked questions
Do I need to learn assembly to continue the academy?
No. You need the concepts from this page: instructions are numbers, the program counter is position, and the fetch-decode-execute loop runs everything. Level 5 shows disassembler and debugger output, and this mental model is enough to read along.
Is bytecode ever turned into machine code?
Constantly. Just-in-time compilers inside modern runtimes watch which bytecode runs hottest and compile those paths to real machine instructions on the fly, combining the portability of a VM with much of the speed of native code.
Different CPUs use different instruction sets. Does that change anything here?
The encodings and register names differ between processor families, but every mainstream CPU is a fetch-decode-execute machine with registers and a program counter. The model on this page transfers across all of them, which is exactly why it is worth learning once.