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-3 and cpu8bit1-6 both 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-3 drew 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 orderdestination, sourcesource, destination — reversed
Register prefixnone% (e.g. %rax)
Immediate prefixnone$ (e.g. $5)
Size suffixnone (inferred from register name)b/w/l/q appended to the mnemonic (byte/word/long/quad)
Used byNASM, MASM — this course's own examplesGAS, 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
The operand order genuinely reverses
This is the single most common source of confusion when reading code in the "other" syntax: 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.
This course uses Intel syntax throughout
Every example from here forward uses Intel syntax, matching NASM — the toolchain 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

Exercise 1

Translate this Intel-syntax sequence into AT&T syntax, using this chapter's own table: MOV RAX, RCX followed by SUB RAX, 10.

📄 View solution
Exercise 2

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 solution
Exercise 3

Explain 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 solution

Chapter 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