Chapter 1 · Lesson 2

Set Up Your Toolkit

You can read about the machine, or you can watch it work. This course leans on the second option. Here we install and smoke-test the four small tools that will turn every later abstraction — assembly, gates, registers, memory — into something you can click, compile, and inspect with your own eyes.

None of these tools require prior tooling experience, and every one of them has a browser-only fallback in case you can't install software on your machine. The goal of this lesson is simple: by the end you'll have each tool open, you'll have produced your first piece of assembly, and you'll know what a raw byte dump looks like. That's the entire kit for the rest of the course.

The four tools, and what each is for

Different layers of the machine need different microscopes. You don't need them all at once — each tool shows up exactly when the topic does — but it's worth knowing the whole kit up front so nothing feels like it appears from nowhere.

The four tools of the course toolkit Four cards: Compiler Explorer for C to assembly, a logic simulator for gates and circuits, gcc and a debugger for local execution, and a hex viewer for raw bytes. 🔭Compiler ExplorerC → assembly,live in the browser 🔌Logic simulatorwire up gatesand circuits 🐛gcc + debuggercompile and stepreal programs 🔢Hex viewersee the rawbytes in memory
The whole kit. You'll meet each tool the moment the course needs it — none are required before then.
ToolUsed forBrowser-only fallback
Compiler Explorer (Godbolt)Seeing the assembly your C compiles to (Sections 6, 10)It is the browser tool — nothing to install
Logic simulatorBuilding gates, adders, a tiny CPU (Sections 4–5)CircuitVerse (runs in-browser)
gcc/clang + gdb/lldbCompiling and stepping real programs (most sections)Compiler Explorer's execute pane, or an online gdb
Hex viewerReading raw bytes & endianness (Sections 3, 8)An online hex editor, or print("%02x") in any language

Compiler Explorer: C in, assembly out

Compiler Explorer — everyone calls it "Godbolt" after its creator, Matt Godbolt — lives at godbolt.org and needs nothing installed. You type C (or C++, Rust, Go…) into the left pane, pick a compiler, and the right pane shows the exact assembly that compiler produces. It's the single most useful tool in this course because it makes the invisible translation from your code to machine instructions completely visible.

Compiler Explorer's two panes: source on the left, assembly on the right A C function in the left pane flows through a compiler arrow into x86-64 assembly in the right pane. source — add.c int add(int a, int b) { return a + b; } compile x86-64 assembly add: lea eax, [rdi+rsi] ret ; rdi = a, rsi = b, eax = return
Type a function on the left; the assembly the CPU will actually run appears on the right. Two arguments, one add, done.

Here's the function from this lesson's plan. Paste it into the source pane and choose a recent x86-64 gcc or clang compiler:

C — paste into the left pane
int add(int a, int b) {
    return a + b;
}

With optimizations on (try the flag -O2 in the compiler-options box), the assembly is strikingly short:

x86-64 assembly — appears on the right
add:
    lea     eax, [rdi + rsi]   ; eax = a + b
    ret                        ; return value is in eax

Don't worry about decoding this yet — that's Section 6's whole job. For now, notice three things. First, your two parameters arrived in registers named rdi and rsi, not on a stack. Second, the compiler was clever: it used lea ("load effective address"), an address-arithmetic instruction, to do a plain addition in one step. Third, the result leaves in eax. Every one of those choices is something you'll fully understand later — and you just watched the compiler make them.

💡 Two settings worth knowing now

In Compiler Explorer, the compiler-options box (top right) takes the same flags as the command line — -O0 for no optimization, -O2 for aggressive optimization. And the "Intel" vs. "AT&T" toggle changes the assembly syntax. This course uses Intel syntax, so flip it to Intel to match the examples.

Compiling and debugging locally

Godbolt is perfect for looking, but eventually you'll want to run code and poke at it while it runs. For that you need two command-line tools that almost certainly already ship with your system, or are one install away: a compiler (gcc or clang) and a debugger (gdb on Linux/Windows-WSL, lldb on macOS).

Let's prove they work. Save the same function plus a tiny main as add.c, then run two commands. The first compiles it; the second produces the assembly text file so you can compare it to what Godbolt showed you.

terminal — smoke-test your local compiler
# 1. Compile to a runnable program and run it
gcc add.c -o add
./add                 # prints: 2 + 3 = 5

# 2. Emit assembly to add.s (the -S flag = "stop after compiling")
gcc -O2 -S -masm=intel add.c -o add.s

Open add.s in any editor and you should find the same add: label with a lea and a ret inside it. That match — your local toolchain producing what the web tool produced — confirms the setup is sound. (If gcc isn't found: on Debian/Ubuntu run sudo apt install gcc gdb; on macOS run xcode-select --install; on Windows install WSL or MSYS2. No install access? Compiler Explorer's Execute pane runs the program right in the browser.)

The debugger lets you freeze a program mid-flight and read its registers and memory — exactly the state this course spends sixteen sections explaining. A first taste:

terminal — step a program in gdb
gcc -g add.c -o add          # -g keeps debug symbols
gdb ./add
(gdb) break add              # pause when add() is called
(gdb) run
(gdb) info registers rdi rsi # peek at the two argument registers
(gdb) stepi                  # execute exactly one machine instruction
(gdb) continue               # let it finish
💡 You don't need to memorize gdb

We'll introduce debugger commands one at a time, right where they're useful — break, run, stepi, info registers, and x (examine memory) cover almost everything this course does. The point of running it today is just to confirm it launches and stops where you ask.

Reading a hex dump

The last skill in your kit isn't a program to install but a way of seeing: reading raw bytes printed in hexadecimal. Memory holds nothing but bytes, and a hex viewer shows those bytes two hex digits at a time. You'll lean on this constantly once we discuss integers, endianness, and memory layout — so let's decode one dump now.

Suppose a program stores the 32-bit integer 1 in memory and we dump the four bytes at its address. On a typical x86-64 machine you'd see this:

hex dump — four bytes holding the int value 1
address   bytes          meaning
00400a10  01 00 00 00    the 32-bit integer 1

Wait — why is the 01 first, not last? Because x86-64 is little-endian: it stores the least-significant byte at the lowest address. The value is one, so the low byte is 0x01 and the three high bytes are zero. This will feel strange the first time and obvious by Section 3.8. The diagram below makes the byte order concrete.

A hex dump of the 32-bit integer one, little-endian Four memory cells at rising addresses hold the bytes 01, 00, 00, 00; the lowest address holds the least significant byte. value 0x00000001 stored at address 0x00400a10 low address high address → 010a10 000a11 000a12 000a13 least-significant byte
Little-endian: the smallest byte lives at the smallest address. Reading a dump means reading bytes right-to-left to reassemble the number.

You can produce a dump like this yourself without any special tool. In a terminal, xxd or hexdump -C will dump any file; or in code, printing each byte with a %02x format string does the same job in any language. Reading these takes thirty seconds of practice and then becomes second nature.

🛠️ Hands-on Exercise

Reproduce Compiler Explorer's output on your own machine. Compile the lesson's add function locally with gcc -O2 -S -masm=intel add.c -o add.s, open add.s, and confirm the body of add: matches the lea/ret you saw in the browser. (No local compiler? Use Compiler Explorer's Execute pane instead and just confirm it returns 5.)

Show the answer

Save this as add.c:

int add(int a, int b) { return a + b; }
#include <stdio.h>
int main(void) { printf("%d\n", add(2, 3)); return 0; }

Running gcc -O2 -S -masm=intel add.c -o add.s produces an add.s whose function body is essentially:

add:
    lea     eax, [rdi + rsi]
    ret

That's the same instruction Godbolt showed — proof your local toolchain matches the web tool. Minor differences (extra directives like .cfi_*, or a leading underscore on macOS) are normal: those are bookkeeping the assembler and linker need, not part of the actual computation.

🤔 Quick check
In Compiler Explorer, which setting makes the assembly match this course's examples?
Switch the syntax toggle to Intel (not AT&T). It's also worth setting the optimization flag — -O2 for optimized output, -O0 for the literal, unoptimized translation.
A dump shows 01 00 00 00 for a 4-byte int. What value is it, and why is the 01 first?
It's the integer 1. x86-64 is little-endian, so the least-significant byte (0x01) is stored at the lowest address and the zero high bytes follow.
Lesson Summary
  • Compiler Explorer shows your C as assembly, live in the browser — use Intel syntax and the -O2 flag to match this course.
  • A logic simulator (or CircuitVerse online) is for building gates and a tiny CPU later.
  • gcc/clang + gdb/lldb let you compile, run, and freeze real programs to inspect registers and memory.
  • A hex dump is just bytes in base-16; on little-endian x86-64 the least-significant byte sits at the lowest address.
  • Every tool has a browser-only fallback, so nothing here blocks you.