100% Free Forever
AI-Powered Learning
Industry Expert Content
Certificates & Badges
Learn At Your Own Pace
Programming

Loops in Assembly

Discover how high-level for and while loops are built from conditional jumps, counters, and the dedicated LOOP instruction in x86 assembly.

Control FlowBeginner9 min readJul 10, 2026
Analogies

Loops as Backward Jumps

At the machine level, there is no dedicated 'for' or 'while' construct — a loop is simply a label, a body of instructions, a condition check, and a conditional jump back to the label. A while loop typically checks its condition at the top (test-then-execute), which compiles to a comparison and a forward conditional jump past the body, followed by an unconditional jump back to the check. A do-while loop checks at the bottom (execute-then-test), which needs only a single backward conditional jump after the body, making it marginally more efficient since it avoids one extra jump on every iteration except possibly the last.

🏏

Cricket analogy: A bowler running through their over checks after each ball whether six have been bowled before walking back to their mark — that bottom-of-loop check mirrors a do-while loop's single backward jump, more efficient than checking before every ball.

The Dedicated LOOP Instruction

x86 provides a specialized LOOP instruction that implicitly uses ECX as a counter: each execution decrements ECX and jumps to the target label if ECX is not zero, combining decrement and conditional-branch into a single instruction. While convenient for simple fixed-count loops, LOOP is rarely used in modern optimized code because it is often slower than an equivalent DEC/JNZ pair on contemporary CPUs, and it hard-codes ECX, which conflicts with register allocation in more complex functions. Compilers today almost always emit explicit DEC/CMP/Jcc sequences instead.

🏏

Cricket analogy: LOOP is like a fixed-over bowling machine that always counts down from a preset number of deliveries and stops automatically — convenient, but a real coach adjusting overs based on match situation (DEC/JNZ with flexible registers) gives finer control.

x86asm
section .data
    sum dd 0

section .text
    global _start

_start:
    mov ecx, 10          ; loop counter: sum 1..10
    mov eax, 0            ; running total
    mov ebx, 1             ; current value

sum_loop:
    add eax, ebx
    inc ebx
    dec ecx
    jnz sum_loop           ; jump back while ecx != 0

    mov [sum], eax          ; sum now holds 55

    mov eax, 1               ; sys_exit
    mov ebx, 0
    int 0x80

Off-by-One Errors and Loop Bounds

Because assembly loop bounds are entirely explicit, off-by-one errors are extremely common: using JLE instead of JL (or vice versa) when comparing an index against an array length shifts the loop by exactly one iteration, either skipping the last valid element or reading one element past the end of the array. This is especially dangerous when iterating over a zero-indexed array of length N, where valid indices run from 0 to N-1; comparing the index against N with JL is correct, but comparing with JLE will access index N, which is out of bounds.

🏏

Cricket analogy: Counting overs from over 0 to over 49 in a 50-over match, a scorer who stops the innings after over 50 instead of over 49 has made an off-by-one error, just like using JLE instead of JL against a zero-indexed array bound.

Always double-check whether your loop-bound comparison should be inclusive or exclusive relative to the array or buffer size. Reading or writing one element past the end of a statically allocated array can silently corrupt adjacent memory rather than crashing immediately, making the bug extremely hard to trace back to its source.

Most modern compilers, when targeting performance, transform countdown loops (ECX toward zero) into forms that let a single JNZ handle both the decrement-check and the branch, because comparing against zero is cheaper on many architectures than comparing against an arbitrary bound — this is one reason hand-optimized assembly sometimes counts down even when the source loop counts up.

  • A loop in assembly is fundamentally a label, a body, a condition test, and a jump back to the label.
  • While loops (test at top) need a forward skip-jump plus a backward loop-jump; do-while loops (test at bottom) need only one backward jump.
  • The dedicated LOOP instruction decrements ECX and branches automatically but is rarely used in optimized modern code.
  • Compilers favor explicit DEC/CMP/Jcc sequences over LOOP for flexibility and speed.
  • Off-by-one errors from using JLE instead of JL (or vice versa) are among the most common assembly bugs.
  • Zero-indexed arrays of length N have valid indices 0 to N-1; comparing against N should use JL, not JLE.
  • Reading or writing past an array's bound can silently corrupt memory instead of crashing immediately.

Practice what you learned

Was this page helpful?

Topics covered

#Programming#AssemblyLanguageStudyNotes#LoopsInAssembly#Loops#Assembly#Backward#Jumps#StudyNotes#SkillVeris#ExamPrep