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:
| Job | LC-3 (assembly1-9) | NASM | GAS |
|---|---|---|---|
| Set the origin address | .ORIG | ORG | (handled by linker script / section placement) |
| Reserve a byte value | .FILL | DB | .byte |
| Reserve a wider value | .FILL (word-sized by default) | DW / DQ | .word / .quad |
| A null-terminated string | .STRINGZ | DB "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)
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.
| Concept | assembly1-9 (LC-3) | This chapter (x86-64) |
|---|---|---|
| Two-pass assembly | Yes | Yes — genuinely the same real mechanism |
| Object files | Described conceptually | Real .o/.obj files, produced by real tools |
| Linker | Described conceptually | Real: ld (Linux), link.exe (Windows) |
| Final output | A simple, flat LC-3 executable image | A structured format carrying real protection metadata: ELF or PE |
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
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 solutionExplain 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 solutionUsing 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 solutionChapter 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