Esercizi sul linguaggio Assembly 8086 : indice argomenti
- Introduzione
- Architettura del processore x86
- Istruzione assembly
- Registri del processore
- Esempio di codice
- Somma di due numeri
- Calcolo del fattoriale
- Stampa dei numeri da 1 a 10
- Calcolo del MCD
- Stampa di una stringa inversa
- Calcolo della somma degli elementi di un array
- Link utili
Introduzione
L’Assembly 8086 è un linguaggio di basso livello utilizzato per la programmazione di computer che utilizzano l’architettura x86. Questo linguaggio è molto vicino alla lingua dell’hardware del computer e pertanto molto potente e flessibile. Tuttavia, il linguaggio Assembly è molto complesso e richiede una buona conoscenza dell’architettura hardware del computer.
Architettura del processore x86
Prima di iniziare a scrivere del codice Assembly 8086, è importante avere una buona conoscenza dell’architettura del processore x86. Il processore x86 è composto da un’unità di elaborazione centrale (CPU) e da una serie di registri, che sono piccole aree di memoria all’interno del processore utilizzate per l’archiviazione temporanea dei dati.
Il processore x86 utilizza anche una serie di bus di sistema per il trasferimento di dati tra la CPU, la memoria e i dispositivi di input/output (I/O). È importante avere una buona comprensione di questi bus di sistema prima di iniziare a scrivere del codice Assembly.
Istruzioni Assembly x86
Il codice Assembly 8086 è composto da una serie di istruzioni Assembly, che sono simili alle istruzioni in linguaggio macchina utilizzate dal processore x86. Ogni istruzione Assembly è costituita da un’operazione e uno o più operandi.
Ad esempio, l’istruzione Assembly MOV AX, BX
copia il contenuto del registro BX nel registro AX. L’operazione in questo caso è “MOV”, mentre gli operandi sono “AX” e “BX”.
È importante notare che le istruzioni Assembly sono molto specifiche per l’architettura hardware del processore. Quindi, mentre le istruzioni Assembly possono sembrare simili tra diverse architetture di processori, le differenze sottostanti possono essere significative.
Registri del processore 8086
Il processore x86 utilizza una serie di registri interni per l’archiviazione temporanea dei dati. Questi registri sono essenziali per l’esecuzione del codice Assembly e sono utilizzati frequentemente nelle istruzioni Assembly.
I registri del processore possono essere divisi in diverse categorie:
- Registri generali: questi registri sono utilizzati per l’archiviazione di dati temporanei durante l’esecuzione del codice Assembly. Ci sono 8 registri generali a 16 bit (AX, BX, CX, DX, BP, SP, SI e DI) e 8 registri generali a 8 bit (AL, AH, BL, BH, CL, CH, DL e DH).
- Registri di segmento: questi registri sono utilizzati per l’archiviazione di informazioni relative alla memoria. Ci sono 4 registri di segmento (CS, DS, SS e ES).
- Registri di controllo: questi registri sono utilizzati per il controllo del funzionamento del processore. Ci sono 4 registri di controllo (CR0, CR2, CR3 e CR4).
- Registri di stato: questi registri sono utilizzati per indicare lo stato del processore. Ci sono 6 registri di stato (FLAGS, CF, PF, AF, ZF, SF e OF).
Esempio di codice linguaggio Assembly 8086
Di seguito è riportato un esempio di codice Assembly 8086 per la stampa della stringa “Hello, World!” sulla console:
.model small
.stack 100h
.data
hello_msg db 'Hello, World!', 0ah, 0dh, '$'
.code
main proc
mov ah, 09h
lea dx, hello_msg
int 21h
mov ah, 4ch
int 21h
main endp
end main
.model small
: specifica il modello di memoria da utilizzare per il programma..stack 100h
: specifica la dimensione dello stack per il programma..data
: la sezione dei dati del programma, in cui vengono definiti i dati statici.hello_msg db 'Hello, World!', 0ah, 0dh, '$'
: definisce una stringa di caratteri con il testo “Hello, World!” seguito da un carattere di nuova riga (0ah
), un carattere di ritorno a capo (0dh
) e un carattere di terminazione ('$'
)..code
: la sezione del codice del programma, in cui viene definito il codice Assembly.main proc
: definisce la procedura principale del programma.mov ah, 09h
: carica il valore09h
nel registroah
, che corrisponde alla funzione di stampa del testo.lea dx, hello_msg
: carica l’indirizzo della stringahello_msg
nel registrodx
.int 21h
: esegue la funzione di stampa del testo utilizzando il valore nel registroah
e l’indirizzo della stringa nel registrodx
.mov ah, 4ch
: carica il valore4ch
nel registroah
, che corrisponde alla funzione di uscita dal programma.int 21h
: esegue la funzione di uscita dal programma utilizzando il valore nel registroah
.main endp
: indica la fine della procedura principale.end main
: indica la fine del programma.
Questo codice utilizza le istruzioni Assembly per caricare il messaggio “Hello, World!” nella memoria del computer e quindi utilizza le funzioni del sistema operativo per stamparlo sulla console.
Esercizi sul linguaggio Assembly 8086
Esempio 1: Somma di due numeri
.model small
.stack 100h
.data
num1 dw 1234h
num2 dw 5678h
result dw ?
.code
main proc
mov ax, num1
add ax, num2
mov result, ax
mov ah, 09h
lea dx, result
int 21h
mov ah, 4ch
int 21h
main endp
end main
Questo codice somma due numeri a 16 bit e stampa il risultato sulla console. Il primo numero è memorizzato nella variabile num1
e il secondo numero è memorizzato nella variabile num2
. Il risultato della somma viene memorizzato nella variabile result
.
.model small
: specifica il modello di memoria da utilizzare per il programma..stack 100h
: specifica la dimensione dello stack per il programma..data
: la sezione dei dati del programma, in cui vengono definiti i dati statici.num1 dw 1234h
: definisce una variabilenum1
di tipo word (16 bit) e la inizializza con il valore1234h
.num2 dw 5678h
: definisce una variabilenum2
di tipo word (16 bit) e la inizializza con il valore5678h
.result dw ?
: definisce una variabileresult
di tipo word (16 bit) senza inizializzarla..code
: la sezione del codice del programma, in cui viene definito il codice Assembly.main proc
: definisce la procedura principale del programma.mov ax, num1
: carica il valore della variabilenum1
nel registroax
.add ax, num2
: aggiunge il valore della variabilenum2
al registroax
.mov result, ax
: copia il valore del registroax
nella variabileresult
.mov ah, 09h
: carica il valore09h
nel registroah
, che corrisponde alla funzione di stampa del testo.lea dx, result
: carica l’indirizzo della variabileresult
nel registrodx
.int 21h
: esegue la funzione di stampa del testo utilizzando il valore nel registroah
e l’indirizzo della variabile nel registrodx
.mov ah, 4ch
: carica il valore4ch
nel registroah
, che corrisponde alla funzione di uscita dal programma.int 21h
: esegue la funzione di uscita dal programma utilizzando il valore nel registroah
.main endp
: indica la fine della procedura principale.end main
: indica la fine del programma.
Esempio 2: Calcolo del fattoriale
.model small
.stack 100h
.data
num dw 5
fact dw 1
.code
main proc
mov cx, num
loop_start:
mul cx
loop loop_start
mov fact, ax
mov ah, 09h
lea dx, fact
int 21h
mov ah, 4ch
int 21h
main endp
end main
Questo codice calcola il fattoriale di un numero utilizzando un loop. Il numero di cui calcolare il fattoriale è memorizzato nella variabile num
. Il risultato del fattoriale viene memorizzato nella variabile fact
.
Esempio 3: Stampa dei numeri da 1 a 10
.model small
.stack 100h
.code
main proc
mov cx, 10
mov ax, 1
loop_start:
mov ah, 09h
mov dx, ax
add dx, 30h
int 21h
inc ax
loop loop_start
mov ah, 4ch
int 21h
main endp
end main
Questo codice stampa i numeri da 1 a 10 sulla console. Il loop utilizza la variabile cx
per contare fino a 10 e la variabile ax
per tenere traccia del numero corrente da stampare.
Esempio 4: Calcolo del massimo comun divisore
.model small
.stack 100h
.data
num1 dw 45
num2 dw 30
gcd dw ?
.code
main proc
loop_start:
mov ax, num1
mov bx, num2
xor dx, dx
div bx
cmp dx, 0
jne loop_start
mov gcd, bx
mov ah, 09h
lea dx, gcd
int 21h
mov ah, 4ch
int 21h
main endp
end main
Questo codice calcola il massimo comun divisore di due numeri utilizzando l’algoritmo di Euclide. I due numeri sono memorizzati nelle variabili num1
e num2
. Il risultato del massimo comun divisore viene memorizzato nella variabile gcd
.
Esempio 5: Stampa di una stringa inversa
.model small
.stack 100h
.data
str db 'Hello, World!', 0ah, 0dh, '$'
.code
main proc
lea si, str
lea di, str
mov cx, 0
loop_start:
mov al, [si]
cmp al, '$'
je loop_end
inc si
inc cx
jmp loop_start
loop_end:
mov bx, cx
dec si
reverse_loop:
mov dl, [si]
mov [di], dl
inc di
dec si
dec bx
cmp bx, 0
jne reverse_loop
mov ah, 09h
lea dx, str
int 21h
mov ah, 4ch
int 21h
main endp
end main
Questo codice stampa una stringa al contrario sulla console. La stringa è memorizzata nella variabile str
. Il codice utilizza un loop per determinare la lunghezza della stringa e quindi un altro loop per stampare la stringa al contrario.
Esempio 6: Calcolo della somma degli elementi di un array
.model small
.stack 100h
.data
arr dw 1, 2, 3, 4, 5
arr_len dw 5
sum dw 0
.code
main proc
mov cx, arr_len
mov si, offset arr
loop_start:
mov ax, [si]
add sum, ax
add si, 2
loop loop_start
mov ah, 09h
lea dx, sum
int 21h
mov ah, 4ch
int 21h
main endp
end main
Questo codice calcola la somma degli elementi di un array di numeri. Gli elementi dell’array sono memorizzati nella variabile arr
e la lunghezza dell’array è memorizzata nella variabile arr_len
. Il risultato della somma viene memorizzato nella variabile sum
.
Link utili
Piattaforma per programmare su macchine virtuali
Conclusioni
In questa lezione abbiamo fornito una panoramica del linguaggio Assembly 8086 e fornito un esempio di codice. L’Assembly 8086 è un linguaggio molto potente e flessibile, ma richiede una buona conoscenza dell’architettura hardware del computer. Questo linguaggio è spesso utilizzato per la programmazione di driver di dispositivi e altri software a basso livello.