Module 0 Exercises — Toolchain & First Program

Back to the Course 3 syllabus. Read first: Smith 1, 3.

Work in course3/m0/ of the labs repo. Record everything in course3/m0/notes.md.

NoteExercises in this set
ImportantmacOS adaptation notes (apply to the whole course)

Smith targets Linux/GNU tools; on Apple Silicon macOS the differences are small but non-negotiable:

  • Symbols: C-visible symbols carry a leading underscore — the entry point the linker wants is _main (linked against libc via the clang driver), declared .global _main.
  • Addressing: Linux adrp x0, label + add x0, x0, :lo12:label becomes adrp x0, label@PAGE + add x0, x0, label@PAGEOFF.
  • Sections: .data, .text, .balign/.p2align work as expected under the clang integrated assembler; ELF-specific directives (.type, .size) do not exist in Mach-O.
  • Debugger: lldb, not gdb. The Smith GDB workflows map almost 1:1 (b, si/ni, register read, memory read, disassemble).
  • System calls: macOS does not guarantee a stable syscall ABI — call libc (_write, _printf, _exit) instead of raw svc. This matters from Module 4 on.
  • ABI: x18 is reserved on Apple platforms — never touch it. The stack pointer must be 16-byte aligned at every external call.

Exercises

Exercise 0.1 — Toolchain inventory. Confirm the Xcode Command Line Tools are installed (xcode-select -p). Record in notes.md the output of clang --version, as -v < /dev/null, ld -v, lldb --version, and make --version, plus uname -m. Note which chip your Mac has and (from public sources) its performance/efficiency core counts — Module 2 measures them.

Tool Version
clang
ld
lldb
make

Exercise 0.2 — Hello world, driver route. Write hello.s: a _main that calls _puts with a string from your .data-equivalent section and returns 0. Build in one step with clang hello.s -o hello. Run it. This is the canonical shape every later exercise builds on: adrp/@PAGE addressing for the string, stp/ldp of x29/x30 around the call, ret at the end.

Exercise 0.3 — Hello world, explicit route. Rebuild the same program in explicit steps: assemble to an object (clang -c hello.s -o hello.o or as), inspect it (nm hello.o, file hello.o), then link with the clang driver acting as linker front end. Record in notes.md what each step produced and which symbols were undefined before linking. Deliverable: a notes.md section explaining, in your own words, what the assembler resolved and what the linker resolved.

Exercise 0.4 — First disassembly. Disassemble the binary with both objdump -d hello and otool -tv hello. In notes.md, annotate every instruction of _main: the adrp/add pair and the page arithmetic it performs, the prologue/epilogue pair, the call. Confirm the addresses adrp computes against the actual string address printed by lldb.

Exercise 0.5 — First lldb session. In lldb ./hello: set a breakpoint on _main, run, step instruction by instruction (si), and at each step watch register read x0 x29 x30 sp and the PC. Dump the string bytes with memory read. Record the value of sp at entry and verify 16-byte alignment. Deliverable: a short annotated transcript in notes.md.

Exercise 0.6 — Break it on purpose. Three deliberate failures, each recorded with the exact error message and a one-line explanation: (a) drop the leading underscore from _main; (b) replace the @PAGE/@PAGEOFF pair with a bare adr-style absolute reference to a far symbol; (c) misalign the stack by pushing a single 8-byte register before calling _puts. Knowing these failure signatures cold saves hours later.

Sabotage Error / symptom Why
No underscore
No @PAGE pair
Misaligned SP at call

Wrap-up: write a Makefile in course3/m0/ with a pattern rule for .s → binary and a clean target; every later module starts by copying it.