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 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.
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.
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.
; 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
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.