Lesson 20 of 48 intermediate

Effective Address Calculation Practice

Master the EA formulas by tracing through real examples with every addressing mode

Open interactive version (quiz + challenge)

Real-world analogy

Calculating an effective address is like following a treasure map with multiple clues. The segment register tells you which island (memory segment). The base register is the town. The index register is the street number. The displacement is the house number. Combine them all: Island + Town + Street + House = exact treasure location.

What is it?

Effective Address calculation is the process of computing the offset within a segment where data resides. Each addressing mode has a formula combining base registers (BX/BP), index registers (SI/DI), and displacements. The physical address is always Segment × 10h + EA. Default segment rules determine which segment register is used unless explicitly overridden.

Real-world relevance

Compilers spend significant effort choosing the optimal addressing mode for each memory access. A good compiler minimizes the complexity of addressing modes to reduce instruction size and execution time. When you read disassembled code in tools like IDA Pro, objdump, or x64dbg, understanding EA calculation is essential for tracing how the program accesses memory — especially when analyzing malware or debugging crashes.

Key points

Code example

; Complete EA practice worksheet
; Given: DS=1000h, SS=2000h, ES=3000h
;        BX=0100h, BP=0200h, SI=0010h, DI=0020h

; Problem 1: MOV AX, [BX]
;   EA = 0100h
;   Seg = DS (BX -> DS)
;   PA = 10000h + 0100h = 10100h

; Problem 2: MOV AX, [BP+06h]
;   EA = 0200h + 06h = 0206h
;   Seg = SS (BP -> SS)
;   PA = 20000h + 0206h = 20206h

; Problem 3: MOV AX, [BX+SI]
;   EA = 0100h + 0010h = 0110h
;   Seg = DS (BX present -> DS)
;   PA = 10000h + 0110h = 10110h

; Problem 4: MOV AX, [BP+DI+100h]
;   EA = 0200h + 0020h + 0100h = 0320h
;   Seg = SS (BP present -> SS)
;   PA = 20000h + 0320h = 20320h

; Problem 5: MOV AX, ES:[SI+50h]
;   EA = 0010h + 0050h = 0060h
;   Seg = ES (override!)
;   PA = 30000h + 0060h = 30060h

; Problem 6: MOV AX, [1234h]
;   EA = 1234h
;   Seg = DS (direct -> DS)
;   PA = 10000h + 1234h = 11234h

Line-by-line walkthrough

  1. 1. Problem 1: MOV AX,[BX] — register indirect. EA = BX = 0100h. BX defaults to DS. PA = 1000h×10h + 0100h = 10100h.
  2. 2. Problem 2: MOV AX,[BP+06h] — based addressing with BP. EA = 0200h + 06h = 0206h. BP defaults to SS. PA = 2000h×10h + 0206h = 20206h.
  3. 3. Problem 3: MOV AX,[BX+SI] — based-indexed. EA = 0100h + 0010h = 0110h. BX is present, so DS is default. PA = 10110h.
  4. 4. Problem 4: MOV AX,[BP+DI+100h] — based-indexed with displacement. EA = 0200h + 0020h + 0100h = 0320h. BP is present, so SS is default. PA = 20320h.
  5. 5. Problem 5: MOV AX,ES:[SI+50h] — indexed with segment override. EA = 0010h + 0050h = 0060h. Override forces ES instead of default DS. PA = 30060h.
  6. 6. Problem 6: MOV AX,[1234h] — direct addressing. EA = 1234h. No register, so DS is default. PA = 10000h + 1234h = 11234h.
  7. 7. Key insight: the EA formula depends only on registers and displacement. The segment adds a separate 'base' that shifts the entire access to a different 64 KB window in the 1 MB space.
  8. 8. Segment overrides cost 1 extra byte in the instruction encoding but can access any segment — essential when data spans multiple segments.

Spot the bug

; Given: DS = 1000h, SS = 2000h, BP = 0050h
; Goal: Read a local variable at stack offset [BP+04h]
; Then store it in a global variable at DS:3000h
;
MOV AX, [BP+04h]    ; Read stack variable
MOV [BP+04h], AX    ; Store to global at 3000h ???
;
; Programmer thinks both access the same location.
; But something is wrong with the second instruction.
Need a hint?
Look at the segment defaults. Does [BP+04h] use DS or SS? And is the second instruction accessing address 3000h?
Show answer
Bug: Both instructions use [BP+04h] which defaults to SS (because BP is used). The first instruction correctly reads from SS:0054h (PA = 20054h). But the second instruction ALSO writes to SS:0054h — the programmer wanted to write to DS:3000h but used [BP+04h] again! This just reads and writes the same stack location. Fix: To write to the global at DS:3000h, use MOV [3000h], AX (direct addressing, defaults to DS). The programmer confused the effective address [BP+04h]=0054h with the target address 3000h.

Explain like I'm 5

Finding an address is like finding a house. The segment is like the city name — it tells you the big area. The base register is like the neighborhood. The index register is like the street number. The displacement is like the house number. You add them all up to get the exact location. If someone says 'use the ES city instead of the DS city,' that is a segment override — same street and house number, but in a completely different city!

Fun fact

The 8086 has an interesting limitation: you cannot use AX, CX, DX, or SP as base or index registers in addressing modes. Only BX, BP, SI, and DI are valid. This restriction exists because Intel only had 4 bits in the ModR/M byte encoding to specify the addressing mode — and only 8 combinations were enough to cover all useful patterns. Modern x86-64 removed this limitation with the REX prefix and SIB byte.

Hands-on challenge

Given DS=5000h, SS=6000h, ES=7000h, CS=8000h, BX=1000h, BP=2000h, SI=0300h, DI=0400h, calculate EA, default segment, and 20-bit PA for each: (a) MOV AX,[3000h], (b) MOV AX,[BX+SI+100h], (c) MOV AX,[BP+DI], (d) MOV AX,CS:[SI], (e) MOV AX,[BP+1000h], (f) MOV AX,[BX+DI+200h]. Then identify which two instructions access overlapping memory ranges if we change ES to 5130h.

More resources

Open interactive version (quiz + challenge) ← Back to course: Microprocessor A–Z