What is actually running down here
All the way back in the toolchain rung you watched your source become machine code: the assembler turned human-readable assembly into bytes, the linker stitched those bytes into an executable, and the loader dropped them into memory to run. We treated the result as a black box and moved on. This rung opens that box. The processor never sees your `int x`, your `for` loop, or the word `main` — by the time anything runs, all of that has dissolved into a flat stream of numbered bytes that the CPU reads one tiny step at a time.
It helps to know what kind of machine you are looking at. Almost every computer you will ever program is a stored-program computer: the instructions that tell the CPU what to do live in the same memory, as the same kind of bytes, as the data they operate on. That single design choice — instructions and data sharing one address space — is the von Neumann architecture, and it is why the picture you built earlier still holds. Memory is still one long numbered array of bytes; we are now just pointing the CPU at some of those bytes and saying "these ones are commands."
So a running program, at this level, is nothing grander than this: a region of memory holding a sequence of instruction-bytes, and a processor that keeps reading the next instruction and obeying it. No loops, no functions, no variables as such — just a long, fast walk through bytes. Everything richer than that is something the compiler built out of this, and the whole point of this rung is to learn to read the walk. The first thing to understand is where the CPU keeps the values it is working on right now, because it is not, mostly, in memory.
Registers: the CPU's tiny, instant scratchpad
Reading and writing memory is fast by human standards but slow by CPU standards. So the processor keeps a very small set of slots built right into the chip, and these are where it does its actual work. They are called registers, and there are only a few dozen of them. On a 64-bit machine each one holds exactly one machine word — 64 bits, 8 bytes — which is just enough room for one integer or one address. The CPU can read or write a register in effectively zero time, far faster than touching memory, which is precisely why values get pulled into registers to be operated on and written back out to memory only when needed.
On x86-64, the general-purpose registers have names like rax, rbx, rcx, rdx, rsi, rdi, and r8 through r15 — sixteen of them, each a 64-bit box. Most are interchangeable workhorses: a value to be added, a loop counter, an address being computed. A handful, though, have special jobs the hardware and the conventions assign them, and three of those are worth meeting now because the rest of the rung leans on them constantly. They are not magic; they are ordinary registers that everyone has agreed to use for one specific purpose.
Three registers that keep the CPU's place
The first special register answers the question "which instruction is next?" Because instructions are just bytes in memory, the CPU needs to remember where in that byte-stream it currently is — and it stores that address in a register all its own, the program counter. On x86-64 it is called rip (the instruction pointer); on ARM it is the pc. The program counter always holds the address of the next instruction to run. Step through code in a debugger and the value you see in rip is your place in the program, in hex, like 0x401136.
The other two keep track of the stack. From the memory rung you already know there is a region called the call stack where each function call's local data lives, growing and shrinking as calls nest. At the instruction level that region is tracked by the stack pointer — rsp on x86-64, sp on ARM — which always holds the address of the current top of the stack. A companion register, the base pointer rbp, often marks a fixed reference point within the current function's frame. Together rsp and rbp are the stack pointer and base pointer, and guide 3 of this rung is devoted entirely to watching them move.
There is one more small but essential register: the flags register (rflags on x86-64). It is not a value you compute with; it is a strip of single-bit switches that the CPU sets as a side effect of arithmetic — a zero flag that turns on when a result was 0, a sign flag for negative results, a carry flag when an addition overflowed past the top bit, and a few more. These flags are how the CPU remembers the outcome of the last comparison, and they are what a conditional jump consults to decide whether to branch. That is the whole mechanism behind an `if`: compare, which sets flags; then jump-if-zero or jump-if-greater, which reads them.
An instruction is a verb plus its operands
Now the verbs. An instruction is the smallest unit of work the CPU can do, and each one is, in essence, a tiny command: move this here, add these two, compare those, jump there. The exact menu of instructions a given processor understands — every command, every encoding — is its instruction set architecture, or ISA. The ISA is a contract: it defines what the chip can be asked to do, independent of how the silicon is built inside. Code written for one ISA does not run on another, which is why a program compiled for your laptop will not run unchanged on a phone unless it is recompiled.
We do not read raw instruction-bytes; we read assembly language, a thin human-readable spelling of them, one line per instruction. Each line is a mnemonic — a short verb like mov, add, cmp, jmp — followed by its operands, the things it acts on. An operand can be a register (rax), a constant baked into the instruction (called an immediate, like 5), or a memory location named by an address. So assembly reads almost like terse, brutal English: `mov rax, 5` means "put 5 into rax," `add rax, rbx` means "add rbx into rax." That is genuinely the level of complexity per line.
; compute (7 + 3) and leave it in rax mov rax, 7 ; rax <- 7 mov rbx, 3 ; rbx <- 3 add rax, rbx ; rax <- rax + rbx (now rax == 10) ; the shape of every instruction: ; MNEMONIC destination, source ; ^verb ^operands
The hundreds of instructions in a real ISA sort into a few families, and once you see the families the whole thing stops looking intimidating. There is data movement (mov, push, pop — shuffle values between registers and memory), arithmetic and logic (add, sub, mul, and, or, shl — the ALU's work), comparison (cmp, test — do arithmetic but keep only the flags), control flow (jmp, je, jl, call, ret — change which instruction runs next), and a handful for talking to the operating system. Nearly everything your C does is built from these few kinds of move, compute, and jump.
Two families of ISA: x86-64 and ARM at a glance
You will meet two ISAs constantly. x86-64 (also called amd64) is what most desktops, laptops, and cloud servers run; ARM (in its 64-bit form, AArch64) runs nearly every phone, the Apple-silicon Macs, and a growing share of servers. They embody two old philosophies. x86-64 is broadly CISC — a Complex Instruction Set, with many instructions, variable-length encodings (an instruction can be anywhere from 1 to 15 bytes), and operations that can touch memory directly. ARM is broadly RISC — a Reduced Instruction Set, with fewer, simpler, fixed-length instructions (every ARM instruction is 4 bytes) that, with rare exceptions, only compute on registers and use separate load/store instructions to reach memory.
The good news for a learner is that the concepts are the same on both, and that is what this rung teaches. Both have a program counter, a stack pointer, general-purpose registers, a flags register, and the same families of move-compute-jump instructions. Only the spelling differs: x86-64 writes `mov rax, 5` where ARM writes `mov x0, #5`; x86-64 calls a function with `call`, ARM with `bl` (branch-with-link). If you can read one, the other is a translation, not a new language. We will use x86-64 syntax as our default because it is what you are most likely to disassemble first, and note ARM differences where they matter.
How the CPU runs, and where this leaves you
We can now sketch the engine that ties registers and instructions together. Inside the CPU sit two cooperating parts: the control unit, which reads instructions and orchestrates what happens, and the arithmetic logic unit (ALU), the calculator that actually adds, subtracts, compares, and shifts. The control unit and ALU do their work in a relentless rhythm: the control unit fetches the instruction at the address in the program counter, figures out (decodes) what it means, then executes it — pushing numbers through the ALU, moving them between registers, setting flags — and finally advances the program counter to the next instruction. Then it does it all again, billions of times a second.
That loop — fetch, decode, execute, advance — is the instruction cycle, and it is the heartbeat of every running program. It is so central that the next guide in this rung is devoted to it in full: how a jump instruction works by simply changing the program counter instead of advancing it, how a comparison plus a conditional jump becomes an `if`, and how this brutally simple loop, repeated, accounts for everything your code does. For now hold the one-sentence version: the CPU forever fetches the instruction at the program counter and obeys it, and nothing else.
Step back and take stock. You now know the cast: a small set of registers that hold the values being worked on right now, three of them with standing jobs (the program counter tracks where you are, the stack pointer tracks the stack's top, the flags register remembers comparisons), and a stream of tiny instructions sorted into a few families of move, compute, and jump. You know that x86-64 and ARM differ in spelling but not in concept. That is the vocabulary the rest of this rung speaks. Guide 2 sets the cycle in motion; guide 3 watches the stack pointer dance through a call; guides 4 and 5 reveal the conventions that let separately-compiled functions cooperate, and finally turn a real compiler loose so you can read the disassembly of your own C.