Skip to content

Assembly String Operations — rep movs, stos, scas, and lods

DodaTech Updated 2026-06-28 6 min read

In this tutorial, you will learn about Assembly String Operations. We cover key concepts, practical examples, and best practices to help you master this topic.

Assembly string instructions enable efficient block operations using rep prefixes with movs, stos, lods, and scas for copying, filling, and scanning memory regions.

What You'll Learn

  • rep prefix for repeated operations
  • movs for block copy
  • stos for memory fill
  • scas for memory scan
  • lods for load string
  • Direction flag (DF) control

Why It Matters

String instructions are the fastest way to copy, fill, or search memory. DodaZIP uses rep movs for high-throughput buffer copies in its compression engine. Durga Antivirus Pro uses scas for signature scanning.

Real-World Use

Memory copying (memcpy), buffer filling (memset), string scanning (strlen), and pattern matching in performance-critical library routines.

flowchart LR
    A["String Ops"] --> B["rep prefix"]
    A --> C["movs"]
    A --> D["stos"]
    A --> E["scas"]
    A --> F["lods"]
    B --> G["Repeat RCX times"]
    C --> H["Copy"]
    D --> I["Fill"]
    E --> J["Search"]
    style A fill:#2563eb,stroke:#2563eb,color:#fff
    style B fill:#dbeafe,stroke:#2563eb,color:#1e40af
    style C fill:#dbeafe,stroke:#2563eb,color:#1e40af
    style D fill:#dbeafe,stroke:#2563eb,color:#1e40af
    style E fill:#dbeafe,stroke:#2563eb,color:#1e40af

Direction Flag

cld                     ; clear DF — forward direction (addresses increase)
std                     ; set DF — backward direction (addresses decrease)

; Default: cld (forward)
; RSI and RDI are adjusted by the size of the operation

rep movs — Block Copy

; Copy [RSI] to [RDI], RCX bytes/words/dwords/qwords

section .data
    src db "Hello, World!", 0
    len equ $ - src

section .bss
    dst resb 64

section .text
    global _start

_start:
    cld                     ; forward direction
    mov rsi, src            ; source address
    mov rdi, dst            ; destination address
    mov rcx, len            ; number of bytes
    rep movsb               ; copy RCX bytes

    ; Now dst contains "Hello, World!"

Available sizes: movsb (byte), movsw (word), movsd (dword), movsq (qword).

rep stos — Memory Fill

; Fill [RDI] with value in RAX/EAX/AX/AL, RCX times

section .bss
    buffer resb 256

section .text
    global _start

_start:
    cld
    mov rdi, buffer         ; destination
    mov al, 0               ; fill value
    mov rcx, 256            ; count
    rep stosb               ; fill 256 bytes with 0

    ; Alternative: fill with pattern
    mov rax, 0xDEADBEEF     ; qword pattern
    mov rdi, buffer
    mov rcx, 32             ; 32 qwords = 256 bytes
    rep stosq
; Scan [RDI] for value in RAX/EAX/AX/AL
; Stops when found or RCX reaches 0
; Sets ZF if found

section .data
    msg db "Hello, World!", 0

section .text
    global _start

_start:
    cld
    mov rdi, msg
    mov al, ','             ; search for comma
    mov rcx, 13
    repne scasb             ; scan until found or exhausted

    ; If found: ZF=1, RDI points after match
    ; If not found: ZF=0, RCX=0
    jz found

found:
    dec rdi                 ; RDI was incremented after match
    ; RDI points to the comma

lods — Load String

; Load value from [RSI] into RAX/EAX/AX/AL, adjust RSI

section .data
    msg db "Hello", 0

section .text
    global _start

_start:
    cld
    mov rsi, msg
    lodsb                   ; al = 'H', rsi++
    lodsb                   ; al = 'e', rsi++
    lodsb                   ; al = 'l', rsi++
    ; AL has each byte sequentially

Implementing strlen

; Returns length of null-terminated string in RAX
strlen:
    push rdi
    mov rdi, rsi            ; string pointer
    xor al, al              ; search for null
    mov rcx, -1             ; maximum count
    cld
    repne scasb             ; scan for null
    sub rdi, rsi            ; RDI - RSI = bytes scanned
    dec rdi                 ; exclude null terminator
    mov rax, rdi
    pop rdi
    ret

Implementing memcpy

; memcpy(dest in RDI, src in RSI, count in RDX)
memcpy:
    push rdi
    push rsi
    mov rcx, rdx
    cld
    rep movsb
    pop rsi
    pop rdi
    mov rax, rdi             ; return dest
    ret

rep Prefix Variants

Prefix Condition
rep Repeat while RCX > 0 (for movs/stos)
repe/repz Repeat while RCX > 0 and ZF=1 (for cmps/scas)
repne/repnz Repeat while RCX > 0 and ZF=0 (for scas)

Common Mistakes

1. Direction flag state

Always set DF with cld or std before string operations. Never assume the state of DF.

2. Wrong operand size

Use movsb for bytes, movsd for dwords, movsq for qwords. Mismatched sizes read/write wrong amounts.

3. Forgetting to initialize RCX

rep uses RCX. If RCX is 0, the operation does nothing. If RCX is huge, it runs forever.

4. Overlapping source and destination

rep movs with overlapping regions and forward direction produces wrong results. Use backward copy (std) for overlapping.

5. Not preserving RSI/RDI

String operations modify RSI and RDI. Save them before calling string routines that use them.

Practice Questions

1. What does rep movsb do?

Copies RCX bytes from address in RSI to address in RDI, incrementing both pointers.

2. How do you fill a buffer with zeros?

cld; mov rdi, buffer; xor eax, eax; mov rcx, size; rep stosb

3. What is the difference between scasb and lodsb?

scasb scans memory comparing with AL (search). lodsb loads a byte from memory into AL (read).

4. What registers do string operations use?

RSI (source), RDI (destination), RCX (count), AL/EAX/RAX (value), DF (direction).

Challenge: Implement memmove that handles overlapping regions correctly.

Solution
memmove:
    cmp rsi, rdi
    jae .forward
    ; backward copy for overlapping
    mov rcx, rdx
    add rsi, rcx
    dec rsi
    add rdi, rcx
    dec rdi
    std
    rep movsb
    cld
    ret

.forward:
    cld
    rep movsb
    ret

FAQ

{{< faq question="Are string instructions faster than loops?" >}} Yes, rep movs can use ERMSB (Enhanced REP MOVSB/STOSB) on modern CPUs, which copies in cache-line-sized chunks for near bandwidth-limit performance. {{< /faq >}}

{{< faq question="What is ERMSB?" >}} Enhanced REP MOVSB/STOSB is a CPU feature that accelerates rep movsb/stosb for large blocks by using internal microcode optimizations. {{< /faq >}}

{{< faq question="Can string operations be interrupted?" >}} Yes, an interrupt during a rep instruction saves the state of RCX, RSI, RDI. After the interrupt, the instruction resumes where it left off. {{< /faq >}}

{{< faq question="Are string instructions available in 32-bit mode?" >}} Yes, they work in 16-bit, 32-bit, and 64-bit modes. The address size adjusts based on the mode. {{< /faq >}}

{{< faq question="What is the performance of scasb for long strings?" >}} Scasb is slower than a SIMD-based strlen for long strings. Modern implementations use SSE/AVX for scanning. {{< /faq >}}

Mini Project

Write a program that uses string instructions to convert a string to uppercase.

section .data
    msg db "hello world", 0
    len equ $ - msg

section .text
    global _start

_start:
    mov rsi, msg
    mov rdi, msg
    mov rcx, len
    cld

.loop:
    lodsb
    cmp al, 'a'
    jb .next
    cmp al, 'z'
    ja .next
    sub al, 32          ; convert to uppercase
.next:
    stosb
    loop .loop

    ; Write result
    mov rax, 1
    mov rdi, 1
    mov rsi, msg
    mov rdx, len
    syscall

    mov rax, 60
    xor rdi, rdi
    syscall

What's Next

Now that you understand string operations, proceed to floating-point arithmetic.

Topic Description Link
Floating-point FPU and math {{< ref "15-floating-point" >}}
SSE SIMD floating-point {{< ref "16-sse" >}}
Instructions CPU instruction set {{< ref "06-instructions" >}}

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro