Assemblers & Toolchains in Practice

x86-64 Assembly

Chapter 11 · Assemblers & Toolchains in Practice

assembly1-9 taught the two-pass assembler algorithm, symbol tables, object files, and linking using LC-3 as the example. This chapter is the confirmation that none of that was simplified for teaching purposes — real, modern tools do exactly the same thing, just at real-world scale.

NASM and GAS — Two Real Assemblers

NASM (Netwide Assembler) uses Intel syntax — matching this course's own committed choice from assembly2-3 — and is widely used for standalone, hand-written assembly projects with a simple, self-contained command-line workflow. GAS (GNU Assembler, part of binutils) uses AT&T syntax by default and is the assembler GCC itself uses internally to emit its own generated assembly — it's what shows up when reading compiler output or inline assembly inside C code, deeply embedded in the Linux/GNU toolchain.

For hand-writing assembly directly — what every example in this course has been doing — NASM's Intel syntax and simpler standalone workflow are typically the more approachable starting point; GAS becomes unavoidable the moment the goal shifts to reading or embedding assembly inside compiler-generated code.

assembly1-9's Own Two-Pass Assembler, For Real

Real assemblers use the exact same two-pass approach assembly1-9 taught, for the exact same reason: Pass 1 builds a symbol table by scanning the whole file first; Pass 2 generates real machine code, resolving forward references against that already-complete table. This isn't a simplified teaching model real tools have since moved past — it's genuinely how NASM and GAS work today.

The directives differ in spelling but not in job — assembly1-9's own "instructions to the assembler, not the CPU" idea still applies exactly:

JobLC-3 (assembly1-9)NASMGAS
Set the origin address.ORIGORG(handled by linker script / section placement)
Reserve a byte value.FILLDB.byte
Reserve a wider value.FILL (word-sized by default)DW / DQ.word / .quad
A null-terminated string.STRINGZDB "text", 0.asciz "text"

Object Files and Real Linking

Real x86-64 toolchains produce real object files (.o on Linux, .obj on Windows), and a real linker — ld on Linux, link.exe on Windows — does exactly the job assembly1-9 described: resolving cross-file references, combining multiple object files, and (for real programs) linking against system libraries, into one final executable.

What's genuinely new here: a real executable isn't just raw bits sitting at a fixed address the way LC-3's own simple model was. It's a structured, documented file format.

ELF vs. PE — Real Executable Formats

Linux (and most Unix-like systems) use ELF (Executable and Linkable Format); Windows uses PE (Portable Executable). Both exist to carry information a flat block of bits never could: where the program's entry point is, which external libraries need to be dynamically linked in — and, directly connecting back to assembly2-8's own paging material, which memory permissions each section of the program needs. A file format explicitly marks which parts are code (executable), which are data (writable), and which are read-only constants — and it's precisely this information the OS loader uses to set up the actual per-page protections assembly2-8 covered. The file format isn't just packaging; it's the literal source of the information ring-3 memory protection is built from.

A Minimal Real Build Pipeline

Conceptually — this chapter illustrates the shape of the real pipeline rather than serving as a full setup tutorial:

# Linux, via NASM + ld
nasm -f elf64 program.asm -o program.o
ld program.o -o program

# Windows, via NASM + a Windows linker
nasm -f win64 program.asm -o program.obj
; (linked with link.exe or an equivalent)
Illustrative, not a full setup tutorial
This chapter shows the shape of a real build pipeline, matching cpu8bit1-12's and assembly1-10's own scope notes about not walking through full hardware/emulator setup. Real toolchain installation and environment configuration genuinely varies by system and is deliberately left outside this course's own scope.
Conceptassembly1-9 (LC-3)This chapter (x86-64)
Two-pass assemblyYesYes — genuinely the same real mechanism
Object filesDescribed conceptuallyReal .o/.obj files, produced by real tools
LinkerDescribed conceptuallyReal: ld (Linux), link.exe (Windows)
Final outputA simple, flat LC-3 executable imageA structured format carrying real protection metadata: ELF or PE
Everything converges in the capstone
assembly2-12 puts this entire chapter's own toolchain to real use — a genuine NASM program, assembled and linked for real, making a real Linux syscall.

Hands-On Exercises

Exercise 1

Explain why real assemblers like NASM and GAS still use the exact two-pass approach assembly1-9 taught for LC-3, rather than some more advanced modern technique — what specific problem does the two-pass approach solve that hasn't changed between a teaching ISA and a real modern assembler?

📄 View solution
Exercise 2

Explain what genuinely new information a structured executable format (ELF or PE) needs to carry that assembly1-9's own simple LC-3 executable model never needed to represent, tying your answer directly to assembly2-8's own paging/protection material.

📄 View solution
Exercise 3

Using this chapter's own reasoning, explain which assembler — NASM or GAS — a beginner writing x86-64 assembly by hand would likely find more approachable, and why.

📄 View solution

Chapter 11 Quick Reference

  • NASM — Intel syntax, this course's own choice, approachable for hand-written assembly
  • GAS — AT&T syntax, GCC's own internal assembler, unavoidable when reading compiler output or inline asm
  • Real assemblers use assembly1-9's exact two-pass algorithm — not a simplified teaching model, genuinely how they work
  • Directives differ in spelling (ORG/DB/DW vs. .section/.byte/.word) but do the same job as LC-3's own .ORIG/.FILL
  • Real object files (.o/.obj) and real linkers (ld, link.exe) do exactly the job assembly1-9 described conceptually
  • ELF (Linux) and PE (Windows) — structured executable formats carrying the exact per-section permission data assembly2-8's own paging protection is built from
  • This chapter is illustrative of the real pipeline's shape, not a full environment-setup tutorial