Assembly 8086 metodi di indirizzamento

// obiettivi di apprendimento
Comprendere la struttura di un’istruzione Assembly x86: label, opcode, operandi
Distinguere i tre tipi fondamentali di indirizzamento: immediato, diretto e indiretto
Analizzare le varianti dell’indirizzamento indiretto: tramite registro, con displacement, con base e indice
Calcolare l’indirizzo effettivo con la formula: base address + index + displacement
Scegliere il metodo di indirizzamento appropriato in base al contesto di programmazione
📄
Slides
Indirizzamento in Assembly

Assembly — il linguaggio mnemonico del processore

Il codice macchina — le sequenze di bit che la CPU esegue direttamente — è incomprensibile all’uomo. L’Assembly è la sua rappresentazione simbolica: ogni istruzione binaria corrisponde esattamente a un mnemonico leggibile. Non c’è astrazione: Assembly e codice macchina sono equivalenti uno a uno.

// codice macchina — solo per la CPU
1011 0000 0100 1101
1000 1001 1100 0011
1010 0001 0110 1010
// assembly — leggibile dall’uomo
MOV AL, 4Dh
MOV BX, AX
MOV AX, [6Ah]

Ogni riga Assembly viene tradotta dall’assemblatore (assembler) nel corrispondente opcode binario. Il vantaggio è fondamentale: si scrive in simboli mnemonici e si ottiene il controllo assoluto sull’hardware — senza rinunciare alla leggibilità.

Struttura di un’istruzione Assembly x86

Un’istruzione Assembly x86 segue una sintassi precisa e può contenere fino a quattro elementi:

// anatomia di un’istruzione
loop_start: MOV AX, BX
LABEL (opzionale)
Nome simbolico dell’indirizzo di questa istruzione in memoria. Usata per salti (JMP loop_start) e chiamate.
OPCODE (obbligatorio)
Il mnemonico dell’operazione da eseguire — MOV, ADD, SUB, JMP, CALL… Corrisponde direttamente al byte opcode binario.
DESTINAZIONE
Primo operando — dove va il risultato. Può essere un registro o una locazione di memoria.
SORGENTE
Secondo operando — da dove proviene il dato. Può essere immediato, registro o memoria.
// regola fondamentale in x86
In Intel x86, il primo operando è sempre la destinazione e il secondo è la sorgente: MOV destinazione, sorgente. Non è possibile avere entrambi gli operandi in memoria nello stesso ciclo — almeno uno deve essere un registro.

I registri principali dell’8086

Prima di analizzare i metodi di indirizzamento è essenziale conoscere i registri disponibili — sono loro i protagonisti di quasi ogni istruzione.

RegistroNome estesoDimensioneUso tipico
AX / AH / ALAccumulator16 / 8 / 8 bitOperazioni aritmetiche, risultati I/O
BX / BH / BLBase16 / 8 / 8 bitIndirizzamento base per accesso a memoria
CX / CH / CLCounter16 / 8 / 8 bitContatore per cicli (LOOP), shift
DX / DH / DLData16 / 8 / 8 bitDati, coppia con AX per MUL/DIV a 32 bit
SISource Index16 bitPuntatore sorgente — indirizzamento indiretto
DIDestination Index16 bitPuntatore destinazione — indirizzamento indiretto
BPBase Pointer16 bitAccesso ai dati nello stack frame (parametri funzione)
SPStack Pointer16 bitPunta alla cima dello stack — gestito automaticamente da PUSH/POP
// registro AX — struttura a 16 bit
AH (bit 15–8) AL (bit 7–0)
AX = registro a 16 bit completo · AH = byte alto · AL = byte basso. Scrivere in AL non modifica AH e viceversa.

I tre tipi fondamentali di indirizzamento

Il metodo di indirizzamento specifica dove si trova il dato che l’istruzione deve elaborare. Ogni modalità offre un diverso compromesso tra velocità, flessibilità e complessità.

IMMEDIATO
Il dato è nell’istruzione
Nessun accesso a memoria o registro aggiuntivo — il valore è codificato direttamente nell’opcode
1 passo
DIRETTO
Indirizzo del dato è nell’istruzione
L’istruzione contiene l’indirizzo (registro o locazione di memoria) dove si trova il dato
1–2 passi
INDIRETTO
Indirizzo dell’indirizzo del dato
L’istruzione contiene dove trovare l’indirizzo — il dato finale è sempre in memoria
2–3 passi

Indirizzamento Immediato

Il dato è incorporato direttamente nell’istruzione. Non serve alcun accesso aggiuntivo a memoria o registri — il valore è lì, pronto in un solo passo.

MOV AL, 4Dh   ; scrivi il valore 0x4D (77 decimale) nel registro AL
MOV BX, 1234h ; scrivi il valore 0x1234 nel registro BX a 16 bit
MOV CX, 10    ; scrivi il valore decimale 10 nel registro CX
// esecuzione di MOV AL, 4Dh — passo per passo
1
La CPU legge l’istruzione dal bus — l’opcode B0 identifica “MOV AL, imm8” e il byte successivo 4D è il dato immediato
2
Il valore 4Dh viene scritto direttamente in AL — nessun accesso aggiuntivo a memoria
Prima: AL = ??  →  Dopo: AL = 4Dh
// quando usarlo
Ideale per inizializzare registri con valori costanti noti a tempo di compilazione: contatori, maschere di bit, valori di configurazione. È la modalità più veloce — la CPU non deve accedere alla RAM.

Indirizzamento Diretto

Da registro a registro

Entrambi gli operandi sono registri — la CPU opera interamente al suo interno, senza accedere alla RAM. La velocità è massima.

MOV AX, BX   ; copia il contenuto di BX in AX (AX ← BX)
MOV CX, DX   ; copia DX in CX
MOV AL, BH   ; copia il byte alto di BX nel byte basso di AX
// esecuzione di MOV AX, BX
1
La CPU legge il contenuto del registro BX — operazione interna, nessun bus da attraversare
2
Il valore letto da BX viene copiato in AX. Il contenuto di BX rimane invariato — MOV è una copia, non uno spostamento
BX = 1234h  →  AX = 1234h  ·  BX = 1234h (invariato)

Da registro a memoria e viceversa

Un operando è un registro, l’altro è una locazione di memoria specificata direttamente dall’offset nell’istruzione, indicato tra parentesi quadre. La CPU deve calcolare l’indirizzo effettivo e poi accedere alla RAM.

MOV AX, [6Ah]   ; legge dalla memoria all'offset 6Ah → AX
MOV [6Ah], AX   ; scrive AX in memoria all'offset 6Ah
MOV [0200h], BX ; scrive BX in memoria all'offset 0200h
// esecuzione di MOV AX, [6Ah] — 2 passi
1
Calcolo dell’indirizzo effettivo: base address (DS) + offset (6Ah) = indirizzo fisico
2
Accesso alla RAM: il dato all’indirizzo calcolato viene letto e copiato in AX
DS = 1000h · offset = 6Ah
Indirizzo effettivo = 1000h × 10h + 6Ah = 1006Ah
AX ← Mem[1006Ah]
// segmentazione 8086
Nell’8086 l’indirizzo fisico a 20 bit si calcola sempre come segmento × 16 + offset. Per gli accessi ai dati il registro di segmento è DS (Data Segment). La formula esatta è: EA = DS × 10h + offset.

Indirizzamento Indiretto

Nell’indirizzamento indiretto, l’istruzione non contiene il dato né il suo indirizzo diretto — contiene dove trovare l’indirizzo. Il dato finale è sempre in memoria e mai in un registro o nell’istruzione stessa.

Tramite registro (register indirect)

L’offset non è scritto nell’istruzione — è contenuto in un registro indice o puntatore (SI, DI, BX, BP). Le parentesi quadre intorno al registro indicano “usa il contenuto come indirizzo”.

MOV AX, [SI]  ; legge dalla memoria all'indirizzo contenuto in SI → AX
MOV AX, [DI]  ; legge dalla memoria all'indirizzo contenuto in DI → AX
MOV [BX], CX  ; scrive CX in memoria all'indirizzo contenuto in BX
// esecuzione di MOV AX, [SI] — 2 passi
1
Calcolo dell’indirizzo effettivo: base address (DS) + contenuto di SI = indirizzo fisico
2
Il dato all’indirizzo calcolato viene letto dalla RAM e copiato in AX
SI = 0050h · DS = 1000h
Indirizzo effettivo = 10000h + 0050h = 10050h
AX ← Mem[10050h]
// potenza dell’indirizzamento indiretto
Modificando SI a runtime (es. INC SI), si può scorrere un array in memoria senza modificare l’istruzione stessa — è la base di cicli e strutture dati dinamiche in Assembly.

Tramite registro e displacement

Al contenuto del registro indice si aggiunge un ulteriore displacement (spiazzamento fisso scritto nell’istruzione) per raggiungere una locazione specifica rispetto all’indirizzo base puntato dal registro.

MOV AX, 03h[SI]  ; legge da Mem[DS + SI + 3] → AX
MOV BX, 10h[DI]  ; legge da Mem[DS + DI + 16] → BX
MOV [02h][BX], AL ; scrive AL in Mem[DS + BX + 2]
// esecuzione di MOV AX, 03h[SI] — 3 passi
1
Lettura dell’offset dal registro: SI = 0050h
2
Aggiunta del displacement: EA = DS×10h + SI + 03h = 10000h + 0050h + 03h = 10053h
3
Il dato all’indirizzo calcolato viene letto dalla RAM e copiato in AX
Formula: EA = base address + SI + displacement
EA = 10000h + 0050h + 03h = 10053h
// uso tipico — accesso a strutture (struct)
Con BX puntato all’inizio di una struttura in memoria, il displacement è l’offset del campo all’interno della struttura — es. se il campo “età” è 2 byte dopo l’inizio: MOV AL, 02h[BX]. Equivalente a struct->field in C.

Tramite registri base e indice

L’indirizzo effettivo si calcola sommando il contenuto di un registro base (BX o BP) e di un registro indice (SI o DI). Permette di navigare strutture dati bidimensionali — il base punta alla struttura, l’indice al singolo elemento.

MOV AX, [BX][SI]  ; legge da Mem[DS + BX + SI] → AX
MOV [BX][DI], AX  ; scrive AX in Mem[DS + BX + DI]
MOV CX, [BP][SI]  ; legge da Mem[SS + BP + SI] → CX (BP usa SS per default)
// esecuzione di MOV [BX][DI], AX — 2 passi
1
Calcolo dell’indirizzo effettivo: EA = DS×10h + BX + DI
2
Il valore di AX viene scritto nella RAM all’indirizzo calcolato
BX = 0100h · DI = 0004h · DS = 2000h
EA = 20000h + 0100h + 0004h = 20104h
Mem[20104h] ← AX

Tramite registri base, indice e displacement

La modalità più completa: si sommano registro base + registro indice + displacement fisso. È la forma più potente di indirizzamento indiretto — ideale per array di strutture dove base = inizio array, indice = elemento corrente, displacement = campo della struttura.

MOV AX, 02h[BX][SI]  ; legge da Mem[DS + BX + SI + 2] → AX
MOV 04h[BP][DI], CX  ; scrive CX in Mem[SS + BP + DI + 4]
// esecuzione di MOV AX, 02h[BX][SI] — 3 passi
1
Lettura dei registri: BX (base) e SI (indice)
2
Calcolo completo: EA = DS×10h + BX + SI + 02h
3
Il dato all’indirizzo calcolato viene letto dalla RAM e copiato in AX
BX = 0100h · SI = 0006h · DS = 3000h
EA = 30000h + 0100h + 0006h + 02h = 30108h
// uso tipico — array di strutture
Immaginate un array di record studente (nome, voto, età) di 10 byte ciascuno:
; BX = indirizzo base dell'array
; SI = indice × 10 (elemento corrente)
; displacement 06h = offset del campo "voto"
MOV AL, 06h[BX][SI]  ; legge il voto dello studente SI-esimo
INC SI               ; prossimo byte — scorrimento array

Quadro comparativo — tutti i metodi

MetodoSintassi esempioFormula EAPassiUso tipico
ImmediatoMOV AL, 4Dh— (dato nell’istruzione)1Costanti, inizializzazioni
Diretto reg→regMOV AX, BX— (solo registri)1Copia rapida tra registri
Diretto reg↔memMOV AX, [6Ah]DS×10h + offset2Variabili globali a indirizzo fisso
Indiretto via regMOV AX, [SI]DS×10h + SI2Puntatori, scorrimento array
Indiretto + dispMOV AX, 03h[SI]DS×10h + SI + disp3Accesso a campi di strutture
Base + indiceMOV AX, [BX][DI]DS×10h + BX + DI2Array bidimensionali, matrici
Base + indice + dispMOV AX, 02h[BX][SI]DS×10h + BX + SI + disp3Array di strutture — massima flessibilità

Riepilogo

  • L’Assembly è la rappresentazione simbolica del codice macchina — ogni mnemonico corrisponde esattamente a un opcode binario, senza livelli di astrazione intermedi
  • Ogni istruzione x86 è composta da: label opzionale, opcode obbligatorio, operando destinazione e operando sorgente — in questo ordine fisso
  • Nell’indirizzamento immediato il dato è nell’istruzione stessa — un solo passo, massima velocità
  • Nell’indirizzamento diretto l’istruzione specifica il registro o l’indirizzo di memoria dove si trova il dato — uno o due passi
  • Nell’indirizzamento indiretto l’istruzione indica dove trovare l’indirizzo — il dato finale è sempre in memoria
  • La formula dell’indirizzo effettivo è sempre: EA = DS×10h + base + index + displacement (con i componenti presenti nella modalità usata)
  • I registri indice (SI, DI) e base (BX, BP) sono i protagonisti dell’indirizzamento indiretto — cambiarli a runtime permette di navigare strutture dati dinamicamente
  • La modalità base + indice + displacement è la più potente: ideale per array di strutture dove base = inizio array, indice = elemento, displacement = campo della struttura

Lascia un commento