Chapter 3 Summary and Quiz
Review the flags register, the conditional jump family, and the compiled shapes of if/else, loops, and switch statements.
Control flow in assembly recap
You can now read every branch, loop, and switch a compiler emits. This chapter took the straight-line instruction reading from earlier chapters and added the machinery of decisions: flags, jumps, and the recognisable shapes they form. Let's review the key ideas from each lesson.
Compare and the Flags Register
cmp a, b computes a - b, sets the flags register, and throws the result away; test a, b does the same with a bitwise AND, and test reg, reg is the compiler's idiom for "is this value zero?". Four flags carry the answer: ZF (result was zero), SF (result was negative), OF (signed overflow), and CF (unsigned overflow, or borrow). A comparison only prepares the flags, so always read a cmp or test together with the jump that follows it, that pair tells you what question was really asked.
Unconditional and Conditional Jumps
jmp always transfers control; a conditional jump branches only when the flags match, and otherwise falls through. je/jz and jne/jnz read ZF, while js/jns read SF. The orderings come in two families, and the mnemonic reveals the signedness of the data: less/greater (jl, jle, jg, jge) means the compiler is treating values as signed, while below/above (jb, jbe, ja, jae) means unsigned. Compilers also routinely branch on the inverted condition, sometimes against an adjusted constant (score >= 50 becoming cmp ..., 49 / jle), so the jump you see is often the negation of the comparison you wrote.
How if/else Compiles
An if with no else is a cmp/test, a jump on the inverted condition that skips the body, and an after-label. An if/else adds an else-label and a trailing jmp at the end of the then block so both paths reconverge at an end-label:
cmp eax, 0
jne .Lelse ; inverted condition skips the then block
... ; then block
jmp .Lend
.Lelse:
... ; else block
.Lend:
Block order in the listing need not match source order, so follow the labels, not physical position. At higher optimization levels a small if/else can become branchless: a conditional move like cmovge always executes and simply chooses whether to keep its result, leaving nothing for the CPU to mispredict.
How Loops Compile
A loop is a jump that points backwards: the back-edge, a conditional jump whose target label sits above it. The standard layout is bottom-test: init runs once, an initial jmp drops straight to the condition (so the loop can run zero times), the body sits at a label, and the condition at the bottom ends with the back-edge, costing just one branch per iteration. for and while compile to the same skeleton, a for merely adds the one-time init and the increment inside the body, and the exit test is an ordinary cmp plus conditional jump obeying all the signed/unsigned rules above.
Switch Statements and Jump Tables
A switch compiles to one of two strategies chosen by how dense the case values are. Dense cases become a jump table: a bounds check (often an unsigned ja, which catches both too-high and negative values in a single compare), a table lookup, and an indirect jump like jmp rax that lands directly on the matching case in constant time. Sparse cases become a chain of compares, a run of cmp/je pairs identical to an if/else if ladder. A jump whose target is a register is the giveaway that a table is in play.
Key Terminology
- Flags register: The register where
cmpandtestrecord single-bit facts about a result - ZF (Zero Flag): Set when a result is exactly zero, i.e. when
cmp's operands are equal - SF (Sign Flag): Set when a result is negative
- OF (Overflow Flag): Set on signed overflow
- CF (Carry Flag): Set on unsigned overflow (a borrow)
cmp: Subtracts its operands, sets the flags, and discards the resulttest: ANDs its operands, sets the flags, and discards the result- Unconditional jump (
jmp): Always transfers control to its label - Conditional jump: Branches only when the flags match; otherwise falls through
- Signed jump family:
jl,jle,jg,jge, ordering jumps for signed values - Unsigned jump family:
jb,jbe,ja,jae, ordering jumps for unsigned values - Inverted condition: The compiler's habit of branching on the opposite of the source test to skip a block
- Conditional move (
cmov): A branchless instruction that keeps or discards a copy based on the flags - Back-edge: A conditional jump to a label above it; the defining feature of a loop
- Bottom-test layout: Loop shape with the condition at the bottom and an initial
jmpdown to it - Jump table: A table of code addresses indexed by the switch value, reached via an indirect jump
- Indirect jump: A jump whose target is held in a register (
jmp rax) rather than a fixed label - Compare chain: A sequence of
cmp/jepairs implementing a sparse switch
Looking Forward
You can now follow execution wherever it goes within a function. The next chapter follows it between functions: how the call stack grows and shrinks, what the prologue and epilogue boilerplate you have been skimming actually does, and the System V calling convention that dictates which registers carry arguments in and results out. The mysterious push rbp and edi you have been stepping past are about to make complete sense.
Create an account to track your progress and access interactive exercises. Already have one? Sign in.
Chapter 3 Summary and Quiz - Quiz
Test your understanding of the lesson.
Lesson Discussion
Share your thoughts and questions
No comments yet. Be the first to share your thoughts!