RFLAGS and Instruction Basics
x86-64 Assembly
Chapter 3 · RFLAGS and Instruction Basics
Before writing real programs, this chapter covers the two things every one of them will lean on: the flags register, and the handful of instructions that set it. It also resolves a real cliffhanger from cpu8bit1-12 — and introduces a genuinely new kind of gotcha neither LC-3 nor the 6502/Z80 ever had: two competing, incompatible-looking ways to write the exact same instruction.
RFLAGS — x86-64's Status Register
cpu8bit1-3's 6502 packed its flags into an 8-bit P register; cpu8bit1-6's Z80 did the same with its 8-bit F register. x86-64's RFLAGS is nominally 64 bits wide — but only a small handful of those bits are actually meaningful flags; the rest are reserved, unused, or hold rarely-touched system-level state. Even the flags register itself carries its own quiet layer of accretion.
The flags this course actually uses:
- CF (Carry Flag) — the same underlying concept
cpu8bit1-3andcpu8bit1-6both covered. - ZF (Zero Flag) — set when a result is exactly zero, the same idea as every prior chip's own Z flag.
- SF (Sign Flag) — the same idea as the 6502's N and the Z80's S: set when a result is negative.
- OF (Overflow Flag) — signed overflow, distinct from Carry's unsigned signal, the same distinction
cpu8bit1-3drew for the 6502's own V flag.
Resolving cpu8bit1-12's Cliffhanger
cpu8bit1-12 found that the 6502's CMP and the Z80's CP set Carry in opposite directions for the identical comparison. x86-64 now supplies a third data point — and it sides with the Z80: after a CMP or SUB, CF is set if a borrow was needed (the destination was smaller than the source, unsigned), exactly matching the Z80's own convention, not the 6502's inverted one.
Basic Instructions — MOV, ADD, SUB, CMP
MOV RAX, RBX ; RAX = RBX (a copy — "MOV" doesn't clear RBX, a slight historical misnomer) ADD RCX, 5 ; RCX += 5 SUB RDX, RAX ; RDX -= RAX — sets CF/ZF/SF/OF CMP RAX, RBX ; computes RAX - RBX, sets flags, discards the result — like SUB without storing
CMP here is the direct x86-64 counterpart to cpu8bit1-12's own 6502 CMP and Z80 CP — same underlying idea, and, per the resolution above, the same flag convention as the Z80's.
The AT&T vs. Intel Syntax Divide
Here's the genuinely new kind of gotcha: real-world x86-64 code exists in two different syntaxes that look, at a glance, like different instruction sets entirely — even though they describe exactly the same underlying operations.
| Intel syntax (this course) | AT&T syntax | |
|---|---|---|
| Operand order | destination, source | source, destination — reversed |
| Register prefix | none | % (e.g. %rax) |
| Immediate prefix | none | $ (e.g. $5) |
| Size suffix | none (inferred from register name) | b/w/l/q appended to the mnemonic (byte/word/long/quad) |
| Used by | NASM, MASM — this course's own examples | GAS, GCC inline assembly, GDB's default disassembly |
The same instruction, in both syntaxes:
; Intel syntax (this course) MOV RAX, RBX ADD RCX, 5 ; AT&T syntax — same two instructions movq %rbx, %rax addq $5, %rcx
MOV RAX, RBX (Intel: destination first) and movq %rbx, %rax (AT&T: source first) describe the exact same operation — copy RBX into RAX — despite RAX and RBX appearing in opposite positions on the line. Misreading one syntax using the other's operand-order rule silently swaps source and destination.
assembly2-11 covers directly. Real code encountered elsewhere, especially anything touching Linux/GCC inline assembly or a default GDB disassembly listing, will very likely be in AT&T syntax instead (GDB can be told to switch to Intel syntax, but doesn't by default). Recognizing both, even while primarily writing in one, is a genuinely necessary real-world skill this course's own examples won't otherwise force you to practice.
Hands-On Exercises
Translate this Intel-syntax sequence into AT&T syntax, using this chapter's own table: MOV RAX, RCX followed by SUB RAX, 10.
Using this chapter's own resolution of cpu8bit1-12's cliffhanger, state whether x86-64's CF convention after CMP matches the 6502's or the Z80's, and explain what CF being SET actually means in x86-64 terms.
📄 View solutionExplain why RFLAGS being nominally 64 bits wide, while only using a small handful of those bits for the flags this course actually cares about, counts as a small instance of assembly2-1's own "four decades of accretion" theme.
📄 View solutionChapter 3 Quick Reference
- RFLAGS — nominally 64 bits, only a handful of bits actually used as flags (CF, ZF, SF, OF, among others)
- CF after CMP/SUB matches the Z80's convention — set if a borrow was needed, the opposite of the 6502's own convention (cpu8bit1-12)
- MOV/ADD/SUB/CMP — the basic instruction set this course builds on; CMP computes but discards, only affecting flags
- Intel syntax (this course, NASM, MASM) — destination first, no register/immediate prefixes
- AT&T syntax (GAS, GCC inline asm, GDB default) — source first, %-prefixed registers, $-prefixed immediates, b/w/l/q size suffixes
- The operand order genuinely reverses between the two syntaxes — the single most common real-world reading mistake
- This course commits to Intel syntax throughout, but recognizing AT&T syntax is a real, necessary skill outside it