AsAssembly · Lesson 3 of 10

Registers & Data Movement

`mov` is the most common instruction. It moves data between registers, and between registers and memory. 'Move' is a misnomer — it copies. The source is unchanged.

x86-64 ASM
section .text
global _start

_start:
    ; mov dst, src — copies src into dst (src unchanged)

    ; Register to register
    mov rax, 42         ; rax = 42
    mov rbx, rax        ; rbx = 42, rax still 42

    ; Immediate (literal) to register
    mov rcx, 0xFF       ; rcx = 255
    mov rdx, 0b1010     ; rdx = 10 (binary literal)
    mov rsi, 'A'        ; rsi = 65 (ASCII for 'A')

    ; Memory to register (load)
    ; Square brackets = "the value at this address"
    mov rax, [some_var]     ; rax = value stored at some_var

    ; Register to memory (store)
    mov [some_var], rbx     ; store rbx at address some_var

    ; Immediate to memory — must specify size
    mov qword [some_var], 99   ; store 64-bit value 99
    mov dword [some_var], 99   ; store 32-bit value 99
    mov  word [some_var], 99   ; store 16-bit value 99
    mov  byte [some_var], 99   ; store  8-bit value 99

    ; Address arithmetic in brackets
    mov rax, [rbp - 8]     ; load from rbp minus 8 bytes
    mov rax, [rdi + rcx*8] ; load from rdi + rcx*8 (array indexing!)

    ; lea — load effective address (compute address, don't dereference)
    lea rax, [rbp - 8]     ; rax = rbp - 8 (the address, not the value)
    lea rdi, [rel msg]     ; rdi = address of msg (position-independent)

    mov rax, 60
    xor rdi, rdi
    syscall

section .data
    some_var dq 0   ; dq = define quadword (8 bytes), initialized to 0
    msg      db "hi", 0
x86-64 ASM
; Size specifiers and their meanings:
; byte   —  8 bits (1 byte)   — db, al, bl, cl...
; word   — 16 bits (2 bytes)  — dw, ax, bx, cx...
; dword  — 32 bits (4 bytes)  — dd, eax, ebx...
; qword  — 64 bits (8 bytes)  — dq, rax, rbx...

; IMPORTANT: writing to a 32-bit register (eax) zero-extends to 64-bit (rax)
; but writing to 8-bit or 16-bit does NOT zero the upper bits!
mov rax, 0xFFFFFFFFFFFFFFFF
mov al,  0x00               ; rax = 0xFFFFFFFFFFFFFF00 (upper bytes unchanged!)
mov eax, 0x00               ; rax = 0x0000000000000000 (zero-extended!)

; xchg — swap two registers (no temp needed)
xchg rax, rbx

; movzx — move with zero extension
movzx rax, byte [some_byte]   ; load 1 byte into rax, zero-fill upper 56 bits

; movsx — move with sign extension (preserves sign bit)
movsx rax, byte [some_signed]  ; e.g., -1 (0xFF) becomes 0xFFFFFFFFFFFFFFFF
✦ Tip
`lea` (Load Effective Address) is useful for pointer arithmetic without touching memory. `lea rax, [rbx + rcx*4 + 8]` is a single instruction that computes rbx + rcx*4 + 8 and puts the result in rax — no load, no side effects. Compilers use it for fast multiplication by small constants.