๐Ÿ’พIntro to Computer Architecture

Addressing Modes in Assembly Language

Study smarter with Fiveable

Get study guides, practice questions, and cheatsheets for all your subjects. Join 500,000+ students with a 96% pass rate.

Get Started

Why This Matters

Understanding addressing modes is fundamental to mastering computer architecture because they reveal how the CPU actually locates and retrieves data during instruction execution. You're being tested on the trade-offs between speed, flexibility, and memory efficiency, concepts that appear throughout processor design, from instruction encoding to cache optimization. When an exam asks about performance implications or why certain code patterns exist, addressing modes are often the underlying answer.

Don't just memorize the syntax of each mode. Focus on when and why each mode is optimal: What problem does it solve? What's the cost in clock cycles or instruction size? The best exam answers connect addressing modes to broader concepts like instruction cycle efficiency, data structure implementation, and position-independent code.


Speed-Optimized Modes: No Memory Access Required

These modes prioritize execution speed by keeping operands in the fastest storage locations, either embedded in the instruction itself or stored in registers. The key principle: fewer memory accesses mean faster execution.

Immediate Addressing

The operand is embedded directly in the instruction, so no memory fetch is required. This makes it the fastest addressing mode.

  • Best for constants and known values like loop counters, bit masks, or initialization values (e.g., MOV R1, #5)
  • Limited by instruction format size: the immediate field is typically 8 or 16 bits wide, which constrains the range of values you can encode

Register Addressing

The operand lives in a CPU register, the fastest accessible storage in the memory hierarchy.

  • Eliminates memory bottlenecks since register-to-register operations complete in a single cycle on most architectures
  • Constrained by register count: RISC architectures commonly have 32 general-purpose registers, while x86 historically offered far fewer

Compare: Immediate vs. Register Addressing: both avoid memory access for speed, but immediate embeds a fixed value in the instruction while register addressing references a variable value that can change at runtime. If you're loading a constant, use immediate. If you're doing arithmetic on a value that changes, use register.


Memory-Direct Modes: Explicit Address Specification

These modes access main memory by specifying addresses directly or through a single level of indirection. The trade-off: simpler addressing logic but slower execution due to memory access latency.

Direct Addressing

The memory address is hardcoded in the instruction itself. The CPU reads that address and fetches the operand in one memory access.

  • Useful for global variables and fixed memory-mapped I/O locations where the address never changes
  • Address field size limits reach: a 16-bit address field can only reference 216=65,5362^{16} = 65{,}536 memory locations

Indirect Addressing

The instruction doesn't contain the data's address directly. Instead, it points to a register or memory location that holds the address of the data.

  • Enables dynamic memory access, which is essential for pointers, linked lists, and any location determined at runtime
  • Requires an extra memory fetch: first retrieve the address, then retrieve the data. This doubles the memory access overhead compared to direct addressing.

Compare: Direct vs. Indirect Addressing: direct is faster (one memory access) but inflexible since the address is fixed at compile time. Indirect adds a memory fetch but supports dynamic data structures. When you need to implement pointers or traverse a linked list, indirect addressing is the right tool.


Computed Address Modes: Base + Offset Calculations

These modes calculate the effective address by combining a base value with an offset or index. The general formula is:

Effectiveย Address=Base+Offset\text{Effective Address} = \text{Base} + \text{Offset}

This enables efficient access to structured data like arrays, structs, and records.

Base Register Addressing

A base register holds a starting address, and a constant offset is added to reach a specific location. For example, LOAD R1, 100(R2) means "go to the address in R2, move forward 100 bytes, and load what's there into R1."

  • Ideal for accessing fields within structs or records: the base register points to the start of the struct, and each field has a known, fixed offset
  • Supports relocatable data structures: if you change the base register's value, all field accesses automatically adjust to the new location

Indexed Addressing

A base address is combined with a variable index stored in a register. For example, LOAD R1, (R2 + R3) adds the contents of R2 and R3 to compute the target address.

  • Perfect for array traversal: R2 holds the array's starting address while R3 increments through elements on each loop iteration
  • Scales with element size: some architectures automatically multiply the index by 2, 4, or 8 to handle different data types (e.g., multiplying by 4 for 32-bit integers)

Compare: Base Register vs. Indexed Addressing: both compute addresses, but base register uses a constant offset (good for struct fields that don't move) while indexed uses a variable index (good for iterating through array elements). If an exam asks which mode suits arrays vs. records, this is the distinction.


Control Flow and Stack Modes: Program Structure Support

These modes support branching, function calls, and local variable management. They're how high-level constructs like loops, conditionals, and recursion get implemented at the hardware level.

Relative Addressing

An offset is added to the program counter (PC) to compute the target address:

Effectiveย Address=PC+Offset\text{Effective Address} = \text{PC} + \text{Offset}

  • Used for branches and loops: an instruction like BEQ +8 means "if equal, jump 8 bytes forward from the current PC"
  • Enables position-independent code: because the offset is relative, the program can be loaded at any memory address without modifying branch targets. The jumps still land in the right place.

Stack Addressing

Operands are accessed implicitly through the stack pointer (SP). Push and pop operations automatically update the address.

  • LIFO (last-in, first-out) structure naturally supports function calls: return addresses, parameters, and local variables are pushed on entry and popped on exit
  • Critical for recursion: each function call creates its own stack frame, isolating local state so recursive calls don't overwrite each other's variables

Compare: Relative vs. Stack Addressing: relative addressing handles horizontal control flow (jumps and branches within a sequence) while stack addressing handles vertical control flow (diving into and returning from function calls). Both enable modular, position-independent code but serve different structural purposes.


Quick Reference Table

ConceptBest Examples
Fastest execution (no memory access)Immediate, Register
Fixed memory locationsDirect Addressing
Dynamic/pointer-based accessIndirect Addressing
Struct/record field accessBase Register Addressing
Array traversal and iterationIndexed Addressing
Position-independent branchingRelative Addressing
Function calls and recursionStack Addressing
Computed effective addressBase Register, Indexed, Relative

Self-Check Questions

  1. Which two addressing modes avoid memory access entirely, and why does this matter for execution speed?

  2. You're implementing a linked list traversal. Which addressing mode is essential, and what's the performance cost compared to direct addressing?

  3. Compare base register addressing and indexed addressing: if you're accessing the third field of a struct vs. the third element of an array, which mode fits each scenario?

  4. Why does relative addressing enable position-independent code, and what instruction type most commonly uses it?

  5. Explain how a function call stores its return address and local variables. Which addressing mode and data structure are involved, and what memory access pattern do they use?