Memory Addressing Modes
An addressing mode is the specific way an instruction's operand tells the CPU where to find the actual value it should operate on. The same mnemonic, mov, behaves completely differently depending on the addressing mode of its operands: mov eax, 5 places a literal constant into a register, while mov eax, [rbx] tells the CPU to treat the value in RBX as a memory address, go fetch the 4 bytes stored there, and load that into EAX. Choosing the right addressing mode is central to writing correct and efficient assembly, because array traversal, struct field access, and pointer dereferencing are all implemented purely through the addressing modes an ISA provides — there is no separate 'array' or 'struct' concept at the machine level, only combinations of base registers, index registers, scale factors, and displacement constants.
Cricket analogy: Addressing modes are like the different ways a captain can instruct a fielder: 'stand at exactly deep square leg' (a fixed direct address) versus 'stand wherever the previous fielder is plus five meters' (register-relative addressing) — same instruction format, completely different meaning based on how the location is specified.
Immediate, Register, and Direct Addressing
Immediate addressing embeds the actual constant value right inside the instruction itself, as in mov eax, 42, where 42 is encoded directly into the machine code bytes and requires no memory access at all beyond fetching the instruction. Register addressing uses a register's contents directly as the operand, such as add eax, ebx, which is fast because both operands already live in on-chip storage with no RAM access required. Direct (absolute) addressing specifies a fixed, literal memory address to read from or write to, as in mov eax, [0x404000], which is useful for accessing a global variable at a known, fixed location but becomes fragile the moment code is relocated in memory, which is why position-independent code typically avoids pure direct addressing in favor of RIP-relative addressing instead.
Cricket analogy: Immediate addressing is like a pre-decided fixed target score written on the scoreboard before the innings even starts — the value 42 doesn't need to be looked up anywhere, it's baked into the plan itself.
Indirect and Indexed (Base + Index + Scale + Displacement) Addressing
Register-indirect addressing treats a register's value as a pointer: mov eax, [rbx] reads the 4-byte value found at the memory address currently stored in RBX, which is how dereferencing a pointer variable is implemented in every compiled C program. x86-64's most powerful mode combines four components in a single instruction — base register, index register, scale factor, and constant displacement — written as mov eax, [rbx + rcx*4 + 8], which computes the effective address as RBX + (RCX × 4) + 8 in one step; this single instruction form is precisely how compilers implement array indexing like array[i] for a 4-byte-element array, where RBX is the array's base address, RCX is the index i, the scale factor 4 matches the element size, and the displacement offsets past any leading struct fields. Understanding this addressing form explains why choosing data types with power-of-two sizes (1, 2, 4, or 8 bytes) lets a compiler use the hardware's built-in scale factor instead of emitting extra multiply instructions.
Cricket analogy: Indirect addressing is like a captain saying 'throw the ball to whoever RBX is currently pointing at' rather than naming a fixed fielder — the actual target is looked up through a reference that can change between overs.
; x86-64 NASM: addressing modes side by side
section .data
numbers dd 10, 20, 30, 40 ; an array of 4-byte (dword) integers
section .text
global _start
_start:
mov eax, 42 ; immediate addressing: literal constant
mov ebx, eax ; register addressing: EBX = EAX
mov rcx, numbers ; RCX now holds the array's base address
mov edx, [rcx] ; register-indirect: reads numbers[0] -> 10
mov esi, 2 ; index i = 2
mov edi, [rcx + rsi*4] ; base+index+scale: reads numbers[2] -> 30
mov eax, 60
xor rdi, rdi
syscallDirect (absolute) addressing embeds a fixed memory address into the instruction, which breaks under Address Space Layout Randomization (ASLR) and position-independent executables, since the program's actual load address changes each run. Modern compilers default to RIP-relative addressing (e.g. mov eax, [rip + var]) for this exact reason — always prefer it over hardcoded absolute addresses in real-world assembly.
- An addressing mode determines how an instruction's operand locates its actual value: immediate, register, direct, or indirect/indexed.
- Immediate addressing embeds a literal constant directly in the instruction's encoded bytes, needing no memory access.
- Register addressing uses a register's contents directly as the operand, the fastest option since no RAM access occurs.
- Direct addressing reads or writes a fixed literal memory address, but is fragile under ASLR/relocation.
- Register-indirect addressing ([reg]) dereferences a pointer stored in a register, the basis of pointer dereferencing.
- Base + index*scale + displacement addressing computes array[i]-style access in a single instruction.
- Modern position-independent code favors RIP-relative addressing over hardcoded absolute addresses.
Practice what you learned
1. What does the instruction mov eax, [rbx] do?
2. In the instruction mov eax, [rbx + rcx*4 + 8], what does the scale factor 4 typically represent?
3. Why is pure direct (absolute) addressing considered fragile in modern programs?
4. Which addressing mode requires no access to memory at all beyond fetching the instruction itself?
Was this page helpful?
You May Also Like
CPU Registers Explained
A practical guide to what CPU registers are, the main categories on x86-64, and how assembly instructions use them to do work.
What Is Assembly Language?
An introduction to assembly language as the human-readable face of machine code, and why understanding it still matters for serious programmers.
Your First Assembly Program
A hands-on walkthrough of writing, assembling, linking, and running a minimal x86-64 Linux assembly program from scratch.
Related Reading
Related Study Notes in Programming
Browse all study notesApache Spark Study Notes
Programming · 30 topics
ProgrammingApache Flink Study Notes
Programming · 30 topics
ProgrammingHadoop Study Notes
Programming · 30 topics
ProgrammingSnowflake Study Notes
Programming · 30 topics
ProgrammingApache Airflow Study Notes
Programming · 30 topics
Programmingdbt (Data Build Tool) Study Notes
Programming · 30 topics