Day 3 of 5
⏱ ~60 minutes
Assembly Language in 5 Days — Day 3

Memory & Pointers

Direct memory manipulation is assembly's superpower. Today covers addressing modes, the stack vs. heap, and how to call C library functions from assembly for more complex I/O.

Addressing Modes

x86-64 supports rich memory addressing: [addr] (direct), [reg] (register indirect), [reg + disp] (base + displacement for struct fields), [base + index*scale + disp] (full form for array indexing). Example: 'mov rax, [rbp-8]' loads a local variable from the stack frame. 'mov rax, [rsi + rcx*8]' loads the RCX-th element of a 64-bit array at RSI.

Stack Frames in Detail

At function entry, RSP points to the return address. After 'push rbp / mov rbp, rsp', the frame is set up. Local variables live at [rbp-8], [rbp-16], etc. Function arguments passed on the stack (7th arg and beyond) live at [rbp+16], [rbp+24], etc. The red zone: Linux x86-64 guarantees 128 bytes below RSP won't be clobbered by signal handlers, so leaf functions can use [rsp-8] through [rsp-128] without adjusting RSP.

Calling C Library Functions

Linking with libc lets you call printf, malloc, fopen, etc. from assembly. Declare them extern, use CALL, follow the ABI (args in registers), and ensure RSP is 16-byte aligned before the call (the ABI requires this). Link with 'ld hello.o -lc -dynamic-linker /lib64/ld-linux-x86-64.so.2' or compile with gcc to handle linking automatically.

nasm
; array_sum.asm: sum an integer array
extern printf
section .data
    arr    dq 10, 20, 30, 40, 50  ; 5 x 64-bit integers
    arrlen equ 5
    fmt    db 'Sum: %ld', 0x0a, 0

section .text
    global main

main:
    push rbp
    mov  rbp, rsp

    lea  rsi, [rel arr]   ; pointer to array
    xor  rax, rax         ; sum = 0
    xor  rcx, rcx         ; index = 0
.loop:
    add  rax, [rsi + rcx*8]  ; sum += arr[i]
    inc  rcx
    cmp  rcx, arrlen
    jl   .loop

    ; printf(fmt, sum)
    lea  rdi, [rel fmt]
    mov  rsi, rax
    xor  eax, eax         ; 0 FP args in XMM regs
    call printf

    xor  eax, eax
    pop  rbp
    ret

; gcc -no-pie array_sum.asm -o array_sum
💡
Before calling any C function, ensure RSP is 16-byte aligned. If you've done an odd number of pushes since entering your function, do 'sub rsp, 8' to realign. Misaligned SSE instructions cause segfaults.
📝 Day 3 Exercise
String Manipulation in Assembly
  1. Write a strlen function in assembly (loop until null byte, return count in RAX)
  2. Write a strcpy function (loop copying bytes until null terminator)
  3. Write a reverse_string function (two-pointer swap from ends to middle)
  4. Call printf from assembly to print the reversed string
  5. Compile with: nasm -f elf64 str.asm -o str.o && gcc str.o -no-pie -o str

Day 3 Summary

  • x86-64 addressing modes: direct, register indirect, base+disp, base+index*scale+disp
  • [rbp-8], [rbp-16] access local variables; [rbp+16] accesses stack arguments
  • The red zone: 128 bytes below RSP are safe for leaf function scratch space
  • RSP must be 16-byte aligned before any CALL instruction
  • Link with gcc for automatic libc/dynamic linker setup
Challenge

Implement a complete string library in assembly: strlen, strcpy, strcmp, and strrev. Write a test harness that exercises all four functions and prints pass/fail for each test case.

Finished this lesson?