Assembly Language - Loop Structures

Loops are one of the most common control structures in programs. In assembly language, you can use the LOOP instruction or conditional jumps to implement various loop logic.


LOOP Instruction

LOOPIt is an x86 instruction specially designed for loops, using ECX as a counter:

Each time LOOP is executed, ECX is automatically decremented by 1; if ECX is not 0, it jumps to the target label.

Example

; File path: loop_basic.asm
; Basic usage of LOOP instruction: repeat output 5 times

section .data
    msg db 'example', 0xA
    len equ $ - msg

section .text
    global _start

_start:
    mov ecx, 5                  ; Loop counter = 5 (loop 5 times)

repeat:
    ; Save ecx (system calls may modify it)
    push ecx

    ; Output msg
    mov eax, 4
    mov ebx, 1
    mov ecx, msg
    mov edx, len
    int 0x80

    ; Restore ecx
    pop ecx
    loop repeat                 ; ecx--; if ecx != 0 jump to repeat

    mov eax, 1
    mov ebx, 0
    int 0x80

Output:

$ nasm -f elf32 loop_basic.asm -o loop_basic.o
$ ld -m elf_i386 loop_basic.o -o loop_basic
$ ./loop_basic
example
example
example
example
example

loopBy default, ECX (32-bit) is used as the counter. In 16-bit mode, CX is used; in 64-bit mode, RCX is used. Be sure to set ECX correctly before the loop.


Variants of LOOP

InstructionJump ConditionDescription
LOOPECX != 0Standard loop: decrement ECX first, then test
LOOPE / LOOPZECX != 0 and ZF = 1Continue loop if equal
LOOPNE / LOOPNZECX != 0 and ZF = 0Continue loop if not equal

Example

; LOOPE example: find the first non-zero value in an array

section .data
    array db 0, 0, 0, 5, 0, 0  ; The first three are 0, the fourth is 5

section .text
    global _start

_start:
    mov ecx, 6                  ; Array length
    mov esi, array - 1          ; Point to one position before the array

find_nonzero:
    inc esi                     ; Move to the next element
    cmp byte [esi], 0           ; Is the current element == 0?
    loope find_nonzero          ; If it is 0 and ecx > 0, continue the loop
    ; Loop ends: found the first non-zero element, or finished traversal

    ; esi now points to the address of the first non-zero element
    ; ecx holds the number of elements not yet compared

    mov eax, 1
    mov ebx, 0
    int 0x80

Conditional Loop (WHILE Loop)

Use conditional jumps to implement a while loop: test the condition first, then execute the loop body.

Example

; File path: while_loop.asm
; Implements: while (x < 100) x = x * 2;

section .data
    x dd 1
    limit dd 100

section .text
    global _start

_start:
    ; while loop
while_start:
    mov eax, [x]                ; Load x
    cmp eax, [limit]            ; x < 100 ?
    jge while_end               ; If x >= 100, exit the loop

    shl eax, 1                  ; x = x * 2
    mov [x], eax                ; Store x back

    jmp while_start             ; Go back to loop start and re-test

while_end:
    ; x is now 128 (1->2->4->8->16->32->64->128, stops when 128 >= 100)

    mov eax, 1
    mov ebx, [x]                ; Return x as the exit code
    int 0x80

DO-WHILE Loop

Execute the loop body first, then test the condition:

Example

; DO-WHILE loop: executes at least once

section .data
    counter dd 0

section .text
    global _start

_start:
    mov dword [counter], 0

do_loop:
    ; Loop body: counter++ (executes at least once)
    inc dword [counter]

    ; Test condition
    cmp dword [counter], 5
    jl  do_loop                 ; Continue while counter < 5
    ; counter finally = 5

    mov eax, 1
    mov ebx, 0
    int 0x80

Nested Loops

Nested loops require attention to saving the outer loop counter:

Example

; File path: nested_loop.asm
; Nested loop example: print a multiplication table (3×3)

section .data
    space db ' '
    newline db 0xA
    ; Used to store the converted numeric characters (2 digits + space + null)
    num_str db '  ', 0

section .text
    global _start

_start:
    mov ecx, 3                  ; Outer loop counter (row count)

outer_loop:
    push ecx                    ; ★ Save the outer loop counter! (Important)
    mov ecx, 3                  ; Inner loop counter (column count)

inner_loop:
    push ecx                    ; Save the inner loop counter

    ; Calculate product = outer row number (4 - current ecx) × inner column number
    ; Specific number conversion output omitted here, only demonstrating the structure
    ; Actual output: row number × column number

    pop ecx                     ; Restore the inner loop counter
    loop inner_loop             ; Inner loop

    ; Output newline
    mov eax, 4
    mov ebx, 1
    mov ecx, newline
    mov edx, 1
    int 0x80

    pop ecx                     ; ★ Restore the outer loop counter
    loop outer_loop             ; Outer loop

    mov eax, 1
    mov ebx, 0
    int 0x80

The most common mistake in nested loops is forgetting to use the stack to save the outer loop counter's value. LOOP modifies ECX; when you reset ECX in the inner loop, the outer loop count is lost. The solution is to save it before each entry into the inner loop,push ecxand restore it after leaving.pop ecx。


Loop Optimization Techniques

Some ways to improve loop efficiency:

Example

; Loop optimization comparison

; Method A: Using LOOP instruction (slower, but not obvious)
    mov ecx, 1000
loop_a:
    add eax, [ebx]
    add ebx, 4
    loop loop_a

; Method B: Using conditional jump (manual counting) (usually faster)
    mov ecx, 1000
loop_b:
    add eax, [ebx]
    add ebx, 4
    dec ecx
    jnz loop_b

; Method C: Loop unrolling (fastest, but large code size)
    ; Unroll a 1000-iteration loop to process 4 elements per iteration
    mov ecx, 250                ; 1000 / 4 = 250
loop_unrolled:
    add eax, [ebx]
    add eax, [ebx + 4]
    add eax, [ebx + 8]
    add eax, [ebx + 12]
    add ebx, 16
    dec ecx
    jnz loop_unrolled

; Method D: Counting down (reduces compare instructions)
    mov ecx, 1000
    lea ebx, [array + 1000*4 - 4]  ; Start from the end of the array
loop_reverse:
    add eax, [ebx]
    sub ebx, 4
    dec ecx
    jnz loop_reverse

Complete Example: Calculate the Sum from 1 to 100

Example

; File path: sum_1_to_100.asm
; Calculate 1+2+...+100 = 5050

section .data
    msg db 'Sum of 1 to 100 is: '
    msg_len equ $ - msg
    newline db 0xA

section .bss
    result_str resb 12           ; Store the converted numeric string

section .text
    global _start

_start:
    ; Calculate the cumulative sum
    mov ecx, 100                 ; Loop 100 times
    mov eax, 0                   ; Initial cumulative sum is 0
    mov ebx, 1                   ; The current number to add

sum_loop:
    add eax, ebx                 ; eax += ebx
    inc ebx                      ; Next number
    loop sum_loop                ; Continue loop
    ; eax = 5050

    ; Output prompt text
    push eax                     ; Save result
    mov eax, 4
    mov ebx, 1
    mov ecx, msg
    mov edx, msg_len
    int 0x80
    pop eax                      ; Restore result

    ; Convert number to string (simple version: directly output the integer value)
    ; Simplified here: convert the low byte of eax to a character
    add al, '0'                  ; Not accurate, only for demonstration
    mov [result_str], al

    ; Output result
    mov eax, 4
    mov ebx, 1
    mov ecx, result_str
    mov edx, 12
    int 0x80

    mov eax, 4
    mov ebx, 1
    mov ecx, newline
    mov edx, 1
    int 0x80

    mov eax, 1
    mov ebx, 0
    int 0x80

Converting numbers to strings is a common problem in assembly. The simple method above only works when the number is 0-9. The complete number-to-string algorithm will be explained in detail in the "Number Processing" chapter.

Other extensions