LAB-03Medium
Control Flow Tracing
Trace a short assembly routine step-by-step and determine the final register state and taken branch.
15 min5 prerequisites4 tools
Disassembly
start:
00: mov rax, 0
01: mov rcx, 5
02: mov rdx, 0
loop:
03: add rax, rcx
04: sub rcx, 1
05: cmp rcx, 0
06: jne loop
done:
07: mov rdx, rax
08: ret Hints
Hint 1
RAX accumulates a running sum.
Hint 2
RCX starts at 5 and is decremented each iteration.
Hint 3
JNE jumps while the result is not equal to zero (ZF = 0).
Submit Findings
Solution
Control Flow Tracing — Solution
The routine computes the sum 5 + 4 + 3 + 2 + 1:
| Iteration | RAX before | RCX before | add rax, rcx |
RCX after sub |
cmp rcx, 0 |
jne loop |
|---|---|---|---|---|---|---|
| 1 | 0 | 5 | 5 | 4 | ZF=0 | taken |
| 2 | 5 | 4 | 9 | 3 | ZF=0 | taken |
| 3 | 9 | 3 | 12 | 2 | ZF=0 | taken |
| 4 | 12 | 2 | 14 | 1 | ZF=0 | taken |
| 5 | 14 | 1 | 15 | 0 | ZF=1 | not taken |
On the fifth iteration, sub rcx, 1 brings RCX to 0. cmp rcx, 0 then sets ZF=1, so jne (jump if ZF=0) falls through instead of looping again.
- RAX = 15 (sum of 5+4+3+2+1)
- Loop body runs 5 times — once per value from 5 down to 1
- JNE depends on ZF — it jumps while
ZF=0(result not zero) and falls through the momentZF=1.
Prerequisites
- a1-registers-movement
- a2-arithmetic-logic
- a3-control-flow
- x64 register conventions (RAX, RCX, RDX)
- Flags register (ZF, CF, SF, OF)
Methodology
Investigation Methodology
1. Understand the Routine Structure
- Identify entry point (
startlabel) - Find loop structure: label, body, condition, jump
- Identify exit point (
ret)
2. Register Initialization
mov rax, 0— accumulator initialized to 0mov rcx, 5— loop counter initialized to 5mov rdx, 0— cleared (unused in loop, used at end)
3. Loop Analysis
Loop label at address 3:
add rax, rcx— add counter to accumulatorsub rcx, 1— decrement countercmp rcx, 0— compare counter to zero, sets flagsjne loop— jump if not equal (ZF=0)
4. Flag Behavior
cmpperforms subtraction (RCX - 0) and sets flags, does not store resultZF = 1when result is zero (RCX == 0)ZF = 0when result non-zero (RCX != 0)jne= Jump if Not Equal = Jump if ZF = 0
5. Iteration Trace
| Iteration | RAX (before) | RCX (before) | ADD result | RCX (after SUB) | CMP result | JNE taken? |
|---|---|---|---|---|---|---|
| 1 | 0 | 5 | 5 | 4 | ≠0 (ZF=0) | Yes |
| 2 | 5 | 4 | 9 | 3 | ≠0 (ZF=0) | Yes |
| 3 | 9 | 3 | 12 | 2 | ≠0 (ZF=0) | Yes |
| 4 | 12 | 2 | 14 | 1 | ≠0 (ZF=0) | Yes |
| 5 | 14 | 1 | 15 | 0 | =0 (ZF=1) | No |
6. Post-Loop
- Loop exits when RCX = 0, ZF = 1
mov rdx, rax— copy final sum (15) to RDXret— return with RAX = 15, RDX = 15
Common Pitfalls
- Thinking the loop runs 6 times (0 through 5) — it runs 5 times (5 down to 1)
- Confusing `jne` (jump if ZF=0) with `je` (jump if ZF=1)
- Forgetting `cmp` doesn't modify registers, only flags
- Missing that the final iteration adds 1 (when RCX=1), not 0
Tools
- Assembly Visualizer (built-in)
- Ghidra decompiler (to verify logic)
- x64dbg / GDB (step through manually)
- Pen and paper (register trace table)
References
- Lesson A2: Arithmetic & Logic — ADD, SUB, CMP
- Lesson A3: Control Flow — JNE, JE, JG, JL
- Intel SDM Vol 2: CMP, Jcc instructions
- x64 Calling Convention — RAX return value
Extensions & Challenges
- Modify the loop to sum 1..10 (change RCX initial value)
- Convert to a `while` loop structure (check at top)
- Add a second nested loop
- Research: How does the compiler optimize this loop? (e.g., `lea` + `loop` instruction)