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

CPU Architecture & Registers

Assembly is the lowest level of programming humans write directly. Every instruction maps 1-to-1 to a CPU operation. Today you learn x86-64 registers, memory organization, and write your first program.

x86-64 Registers

x86-64 has 16 general-purpose 64-bit registers: RAX, RBX, RCX, RDX, RSI, RDI, RSP, RBP, and R8-R15. Each 64-bit register contains a 32-bit (EAX), 16-bit (AX), and 8-bit (AL/AH) sub-register. RAX is the accumulator (return values). RSP is the stack pointer. RBP is the base pointer for stack frames. RIP is the instruction pointer — it always points to the next instruction to execute.

Memory Segments

A running program's memory is divided into segments: .text (executable code, read-only), .data (initialized global variables), .bss (uninitialized globals, zeroed at startup), the heap (dynamic allocation, grows up), and the stack (function calls and locals, grows down). Understanding these segments is critical for security work — buffer overflows target the stack; heap exploits target heap metadata.

System Calls

Assembly communicates with the OS via system calls. On Linux x86-64: put the syscall number in RAX, arguments in RDI, RSI, RDX, R10, R8, R9, then execute the syscall instruction. The kernel handles it and returns the result in RAX. Syscall 1 = write, syscall 60 = exit. On Windows, syscall numbers change between OS versions — Windows assembly typically uses the Win32 API instead.

nasm
; hello.asm - x86-64 Linux (NASM syntax)
section .data
    msg db 'Hello from Assembly!', 0x0a  ; string + newline
    msglen equ $ - msg                    ; length

section .text
    global _start

_start:
    ; sys_write(1, msg, msglen)
    mov rax, 1          ; syscall: write
    mov rdi, 1          ; fd: stdout
    mov rsi, msg        ; buffer address
    mov rdx, msglen     ; byte count
    syscall

    ; sys_exit(0)
    mov rax, 60         ; syscall: exit
    xor rdi, rdi        ; exit code 0
    syscall

; Assemble and run:
; nasm -f elf64 hello.asm -o hello.o
; ld hello.o -o hello
; ./hello
💡
Use 'xor rdi, rdi' instead of 'mov rdi, 0' to zero a register. It generates a 2-byte instruction instead of 7 bytes, and the CPU executes it faster by breaking the false dependency on the previous register value.
📝 Day 1 Exercise
Write and Run Your First Assembly Program
  1. Install NASM on Linux: sudo apt install nasm
  2. Type the hello.asm source above into a file
  3. Assemble: nasm -f elf64 hello.asm -o hello.o
  4. Link: ld hello.o -o hello
  5. Run: ./hello — you should see 'Hello from Assembly!'

Day 1 Summary

  • x86-64 has 16 general-purpose 64-bit registers with 32/16/8-bit sub-registers
  • RAX holds return values; RSP is the stack pointer; RIP is the instruction pointer
  • Memory segments: .text (code), .data (globals), stack (locals), heap (dynamic)
  • Linux system calls: number in RAX, args in RDI/RSI/RDX, then syscall instruction
  • xor reg, reg is faster and smaller than mov reg, 0 for zeroing
Challenge

Write an assembly program that prints the numbers 1 through 10, one per line, using a loop (dec/jnz or cmp/jle). No C library — pure syscalls only.

Finished this lesson?