x86-64 Architecture

NASM Syntax

Program structure
; NASM program template
; Assemble: nasm -f elf64 program.asm -o program.o
; Link:     ld program.o -o program

section .data           ; Initialized data
    msg:    db "Hello", 10    ; String with newline
    len:    equ $ - msg       ; Length = current pos - start
    number: dd 42             ; 32-bit integer
    array:  dq 1, 2, 3, 4    ; Array of 64-bit integers

section .bss            ; Uninitialized data (zeroed)
    buffer: resb 256    ; Reserve 256 bytes
    count:  resd 1      ; Reserve 1 dword (4 bytes)
    ptr:    resq 1      ; Reserve 1 qword (8 bytes)

section .text           ; Code
    global _start       ; Entry point for linker

_start:
    ; ... code here ...
    mov rax, 60         ; sys_exit
    xor rdi, rdi        ; status 0
    syscall
Data definition directives
db    Define Byte       1 byte     "abc", 0x41, 10
dw    Define Word       2 bytes    0x1234
dd    Define Doubleword 4 bytes    42, 3.14 (float)
dq    Define Quadword   8 bytes    0x123456789ABCDEF0
dt    Define Ten bytes  10 bytes   (extended precision float)

resb  Reserve Bytes     1 byte each
resw  Reserve Words     2 bytes each
resd  Reserve Dwords    4 bytes each
resq  Reserve Qwords    8 bytes each

equ   Constant (no storage allocated)
  SIZE equ 100         ; Like #define SIZE 100 in C

times Repeat
  buffer: times 256 db 0    ; 256 zero bytes

Addressing Modes Summary

Intel syntax (NASM)
; Immediate:    mov rax, 42
; Register:     mov rax, rbx
; Direct:       mov rax, [label]         ; absolute address
; RIP-relative: mov rax, [rel label]     ; position-independent (PIE)
; Indirect:     mov rax, [rbx]           ; register as pointer
; Displaced:    mov rax, [rbx + 8]       ; base + offset
; Indexed:      mov rax, [rbx + rcx*4]   ; base + index × scale
; Full:         mov rax, [rbx + rcx*4 + 8]  ; base + index × scale + disp

; Scale must be 1, 2, 4, or 8
; This matches common data sizes:
;   1 = byte (char)
;   2 = word (short)
;   4 = dword (int, float)
;   8 = qword (long, double, pointer)

; LEA: calculate address without memory access
lea rax, [rbx + rcx*4 + 8]   ; rax = rbx + rcx*4 + 8 (math only!)

Build Workflow

Assembly, linking, debugging
# Pure assembly (no libc)
nasm -f elf64 -g -F dwarf program.asm -o program.o
ld program.o -o program

# With libc (for printf, malloc, etc.)
nasm -f elf64 -g -F dwarf program.asm -o program.o
gcc program.o -o program -no-pie

# With debug symbols (-g -F dwarf)
nasm -f elf64 -g -F dwarf program.asm -o program.o
ld program.o -o program
gdb ./program

# C to assembly (see what compiler does)
gcc -S -O0 -masm=intel program.c       # Unoptimized
gcc -S -O2 -masm=intel program.c       # Optimized

# Disassemble a binary
objdump -d -M intel program
objdump -d -S -M intel program          # With source if debug info

# Check binary properties
file program
readelf -h program                       # ELF header
readelf -S program                       # Section headers
nm program                               # Symbol table
Makefile for assembly projects
ASM = nasm
ASMFLAGS = -f elf64 -g -F dwarf
LD = ld

.PHONY: all clean

all: program

program: program.o
	$(LD) $< -o $@

%.o: %.asm
	$(ASM) $(ASMFLAGS) $< -o $@

clean:
	rm -f *.o program

Debugging Assembly with GDB

Essential GDB commands for assembly
# Start with Intel syntax
gdb -q ./program
(gdb) set disassembly-flavor intel

# Breakpoints
(gdb) break _start              # At label
(gdb) break *0x401000           # At address
(gdb) info break                # List breakpoints

# Execution
(gdb) run                       # Start program
(gdb) stepi                     # Step ONE instruction
(gdb) nexti                     # Next instruction (skip calls)
(gdb) continue                  # Run until next breakpoint
(gdb) finish                    # Run until function returns

# Examine registers
(gdb) info reg                  # All registers
(gdb) info reg rax rbx rsp      # Specific registers
(gdb) print/x $rax              # Print RAX in hex
(gdb) print/d $rax              # Print RAX in decimal
(gdb) print/t $rax              # Print RAX in binary

# Examine memory
(gdb) x/10i $rip                # Next 10 instructions
(gdb) x/20xg $rsp               # 20 qwords at stack pointer
(gdb) x/s 0x402000              # String at address
(gdb) x/10xb $rax               # 10 bytes at RAX address

# Examine flags
(gdb) print $eflags              # Show flags
(gdb) info reg eflags            # Detailed flag view

# Modify registers
(gdb) set $rax = 0x42
(gdb) set *(int*)0x601050 = 100

# Watch memory changes
(gdb) watch *0x601050            # Break when value changes
(gdb) display/x $rax             # Show RAX after each step

Common Instruction Patterns

Idioms
; Zero a register (fastest/smallest encoding)
xor eax, eax                    ; 2 bytes, zeros RAX too

; Test if register is zero
test rax, rax                   ; Sets ZF=1 if zero
jz is_zero

; Test if odd
test rax, 1                     ; ZF=0 if odd (bit 0 set)
jnz is_odd

; Multiply by constant without MUL
lea rax, [rax + rax*2]          ; × 3
shl rax, 2                      ; × 4
lea rax, [rax + rax*4]          ; × 5
lea rax, [rax + rax*2]          ; × 3
shl rax, 1                      ; then × 2 = × 6

; Swap without temp
xchg rax, rbx                   ; Atomic on x86 (has implicit LOCK for mem)

; Conditional move (branchless)
cmp rax, rbx
cmovl rax, rbx                  ; rax = min(rax, rbx)

; Function prologue/epilogue
push rbp
mov rbp, rsp
sub rsp, 32                     ; Allocate locals
; ... body ...
leave                           ; mov rsp, rbp; pop rbp
ret