Ud6: Linguaggio Assembly Lezione Uno: Il linguaggio Assembly e i

Ud6: Linguaggio Assembly
Lezione Uno: Il linguaggio Assembly e i metodi di indirizzamento (libro di testo pag.
119 - 127)
Caratteristiche di un linguaggio Assembly
• Basso livello
• Diverso per ogni architettura (perché corrispondente al linguaggio macchina...e
ogni architettura ha il suo set di istruzioni macchina)
• Corrispondenza di 1 a 1 tra istruzioni in linguaggio macchina e istruzioni in
linguaggio assembly..... un'istruzione macchina corrisponde esattamente ad un
istruzione in assembly e viceversa
• Stesso formato istruzioni:
ETCHETTA: OPERAZIONE OPERANDI
Facilitazioni che l'asssembly mette a disposizione rispetto al linguaggio macchina
• L'operazione viene indicata con un codice mnemonico e non binario ( ADD non
1001)
• Si possono dare nomi alle variabili e quindi riferirsi a locazioni in memoria
attraverso un nome e non solo attraverso un indirizzo
• Si possono utilizzare etichette (nomi simbolici) per indicare i punti di arrivo delle
istruzioni di salto.
Formato istruzione:
ETCHETTA: OPERAZIONE OPERANDI
Etichetta:
Utilizzata come punto di arrivo nelle istruzioni di salto al posto dell'indirizzo binario
Operazione:
Parola chiave che identifica l'istruzione (ADD → somma, JMP → Salto incodizionato,
….)
Operando/i:
Il valore o i valori su cui si effettua l'operazione. Al seconda del metodo di
indirizzamento utilizzato un operando può indicare:
1. Un valore costante
2. Il nome di una variabile
3. Il riferimento ad un registro
4. Il nome di una variabile che contiene l'indirizzo in memoria
METODI DI INDIRIZZAMENTO
Indirizzamento immediato
L'istruzione contiene già l'operando (fornito come costante). Ovviamente l'eventuale
operando destinazione non può mai essere fornito con questo tipo di indirizzamento.
I valori costanti possono venir specificati in binario (b), ottale (o), decimale (d) o
esadecimale (h). Quando si specifica un valore, quindi, è necessario indicare in che base
bisogna considerarlo aggiungendo la lettera corrispondente.
Esempi
34d significa 34 in decimale
101b significa 101 i binario
ecc.
Indirizzamento tramite registro
L'istruzione contiene il nome del registro che funge da operando. I registri utilizzabili
sono a 8 bit o a 16 bit.
Registri a 8 bit: AL, AH, BL, BH, CL, CH, DL, DH
Prendendo a coppie i registri a 8 bit si possono formare dei registri a 16 bit AX (AHAL),
BX (BHBL), CX (CHCL), DX (DH,DL)
Esempio
MOV AL,15d
Salva nel registro AL al il valore 15. In questa istruzione ci sono due operandi; il primo è
passato con indirizzamento tramite registro il secondo con indirizzamento immediato
Indirizzamento diretto
L'istruzione indica il nome della variabile che funge da operando. In un'istruzione non si
possono mai fornire entrambi gli operandi con l'indirizzamento diretto
Esempio.
Supponiamo che la variabile var1 sia di 8 bit, sia stata dichiarata e che contenga il valore
17d; l'operazione
MOV AL, VAR1
ha il primo operando AL specificato per indirizzamento tramite registro
ha il secondo operando VAR1 specificato per indirizzamento diretto
ha l'effetto di copiare il valore contenuto in var1 (17d) anche nel registro AL
Indirizzamento indiretto
L'istruzione contiene il nome della variabile che contiene l'indirizzo di memoria in cui si
può trovare l'operando.
Indirizzamento implicito
Alcune operazioni (per esempio la divisione) assumono che un operando si trovi sempre
nello stesso registro e quindi non viene specificato
Lezione Due: Le Istruzioni Base e la dichiarazione delle variabili (libro di testo pag.
131- 134 e 153-162)
Dichiarazione di variabili
Nome_variabile DB (valore)
Nome_variabile DW )valore)
La differenza tra le 2 dichiarazioni è che per la prima, tipo byte, vengono riservati in
memoria 1 byte; mentre per la seconda, tipo word, vengono riservati in memoria 2 byte.
Il valore, sia nel tipo byte sia word, può essere:
costante binaria:
Es: 00001011b
costante decimale:
Es: 123d
costante ottale:
Es: 47o
costante esadecimale: Es: A4Fh
senza inizializzarla:
Es: ?
Istruzione di trasferimento
Sintassi:
MOV destinazione, sorgente
Effetto:
Copia i dati o gli indirizzi di 8 o 16 bit dalla sorgente alla destinazione (destinazione =
sorgente in un linguaggio ad alto livello)
Limitazioni:
• destinazione non può essere fornito con indirizzamento immediato
• destinazione e sorgente devono avere la stessa dimensione
• sorgente e destinazione non devono essere entrambe fornite per indirizzamento
diretto
ISTRUZIONI ARITMETICHE
Addizione
Sintassi:
ADD destinazione, sorgente
Effetto:
destinazione=destinazione+sorgente
Limitazioni:
• Le stesse dell'istruzione MOV
Addizione con riporto
Sintassi:
ADC destinazione, sorgente
Effetto:
destinazione=destinazione+sorgente+bit di carry
Limitazioni:
• Le stesse dell'istruzione MOV
Sottrazione
Sintassi:
SUB destinazione, sorgente
Effetto:
destinazione=destinazione-sorgente
Limitazioni:
• Le stesse dell'istruzione MOV
Sottrazione con riporto
Sintassi:
SBB destinazione, sorgente
Effetto:
destinazione=destinazione-sorgente-bit di carry
Limitazioni:
• Le stesse dell'istruzione MOV
Moltiplicazione
Sintassi:
MUL fattore
Effetto:
Se fattore ha 8 bit
AX = AL * fattore
Se fattore ha 16 bit
DXAX = AX * fattore
Limitazioni:
• Fattore non può essere fornito con indirizzamento immediato
Divisione
Sintassi:
DIV dividendo
Effetto:
Se dividendo ha 8 bit
AH = resto di AX/dividendo
AL = quoziente di AX/dividendo
Se dividendo ha 16 bit
DX = resto di DXAX/dividendo
AX = quoziente di DXAX/dividendo
Limitazioni
• Le stesse di Mul
Lezione Tre: L'input/output
Il linguaggio Assembly non prevede istruzioni per la visualizzazione e l’acquisizione dei
caratteri e quindi sarebbero necessari dei programmi in Assembly stesso molto
complicati. Per ovviare a tale inconveniente ( e aggiungerei per fortuna!) possiamo
utilizzare le funzioni libreria di DOS che sono richiamabili attraverso l’istruzione:
INT 21h
L’istruzione int 21h permette di richiamare diversi servizi del dos tra cui:
 l’input e l’output di CARATTERI (servizi 01 e 02)
 invio di un carattere sulla stampante (servizio 05)
 Visualizzazione di una stringa (servizio 09)
 Acquisizione di una stringa (servizio 10)
Prima di invocare l’istruzione INT 21h è necessario mettere nel registro AH il numero del
servizio che si intende utilizzare
Input di un carattere (servizio 01)
Il servizio 01 attende un carattere dallo standard input, lo visualizza sul video e copia il
codice ASCII del carattere inserito nel registro AL.
Per invocare questo servizio è necessario salvare il valore 01d nel registro AH prima di
chiamare INT21H.
L’acquisizione di un carattere è dunque eseguita dalle seguenti istruzioni assembly
Mov ah,01h
Int 21h
Dopo queste due istruzioni in AL si trova il codice ASCII del carattere inserito che,
ovviamente, andrà copiato (con MOV) in qualche altro registro o in qualche variabile
prima di eseguire la prossima acquisizione.
Output di un carattere (servizio 02)
Il servizio 02 stampa su video il carattere il cui codice ASCII è contenuto in AL.
Per invocare questo servizio è necessario salvare il valore 02d nel registro AH ed il
codice ASCII del carattere che si vuole stampare nel registro AL prima di chiamare
INT21H.
L’acquisizione di un carattere è dunque eseguita dalle seguenti istruzioni assembly
Mov ah,02h
Mov AL,codice carattere da stampare
Int 21h
Dopo queste tre istruzioni viene visualizzato il carattere con codice ASCII contenuto in AL.
Esempi:
 Visualizzazione sullo schermo di un punto di domanda e uno spazio bianco:


MOV AL, 63d
MOV AH, 02h
INT 21h
MOV AL, 32d
MOV AH, 02h
INT 21h
Passaggio alla riga successiva con inizio a capo della riga:
MOV AL, 10d
MOV AH, 02h
INT 21h
MOV AL, 13d
MOV AH, 02h
INT 21h
Acquisizione di un dato
MOV AH, 01h
INT 21h
MOV Var, AL
Input di numeri
Purtroppo non esiste un servizio del DOS che consenta di acquisire in input numeri
decimali; per realizzare tale scopo è indispensabile convertire i codici ASCII inseriti, che
corrispondono alle cifre che compongono il numero, nel numero decimale
corrispondente.
Il problema è semplice nel caso di numeri ad una cifra in quanto le cifre decimali
occupano posizioni adiacenti nella tabella dei codi ASCII ed in particolare:
Carattere
Codice
ASCII
0
1
2
3
4
5
6
7
8
9
48 (0+48)
49 (1+48)
50 (2+48)
51 (3+48)
52 (4+48)
53 (5+48)
54 (6+48)
55 (7+48)
56 (8+48)
57 (9+48)
Se, dunque, si vuole convertire il codice ASCII della cifra inserita (contenuta in AL) nel
corrispondente numero decimale ad una cifra è sufficiente sottrarre 48
;Selezionare il servizio di acquisizione carattere mettendo 02 nel registro
AH
MOV AH,01d
;Invocare l’int 21h
Int 21h
;Sottrarre al contenuto di AL 48 per trasformare la codifica ASCII nel
numero ad una ;cifra corrispondente
SUB AL,48d
;Salvo in Var il numero
mov var,AL
Risulta ovviamente più complessa l’acquisizione di un numero a due cifre. Il
procedimento di acquisizione di un numero a due cifre può essere diviso nelle seguenti
fasi







Acquisizione del codice ASCII della cifra che costituisce le decine
Trasformazione del codice ASCII in cifra sottraendo 48d
Moltiplicare per dieci il valore ottenuto. Per far questo devo
◦ Mettere in AL uno dei due fattori (il valorew ottenuto al passo precedente)
◦ Mettere 10 in un registro qualsiasi
◦ Eseguire MUL passando come operando il registro in cui ho messo 10. <il
risultato sarà in AX ma poiché sarà minore di 255 AH sarà composto di zeri
quindi la parte significativa del risultato è in AL
Salvare temporaneamente il valore del numero senza le unità (contenuto in AX
come da specifiche moltiplicazione) nella variabile o in un altro registro
Acquisizione del codice ASCII della cifra che costituisce le unità
Trasformazione del codice ASCII in cifra sottraendo 48d
Sommarlo al valore ottenuto precedentemente e salvare il risultato nella variabile
Il codice risulta dunque essere
;Leggo il codice ASCII delle decine (passo1)
mov ah,01h
int 21h
;in AL ho il codice ASCII del carattere delle decine
;sottraggo 48 per ottenere la cifra (passo 2)
sub al,48d
;moltiplico le decine per 10 (passo 3)
mov ah,00d
mov bl, 10d
mul bl
; salvo il valore ottenuto (passo 4)
mov var,al
;Leggo il codice ASCII delle unità (passo 5)
mov ah,01h
int 21h
;in AL ho il codice ASCII del carattere delle unità
;sottraggo 48 per ottenere la cifra e salvo il risultato nella variabile
unità (passo 6 e 7)
sub al,48d
add var, al
Nel caso di numeri a tre cifre il problema si risolve in modo analogo aggiungendo la
lettura delle centinaia (che andranno moltiplicate per cento) e facendo attenzione che
potrebbero servire 16 bit per contenere il numero inserito.
Output di numeri
Purtroppo non esiste un servizio del DOS che consenta di visualizzare numeri decimali;
per realizzare tale scopo è indispensabile convertire il numero decimale che si vuole
visualizzare nei codici ASCII delle cifre che lo compongono e viceversa.
Il problema è semplice nel caso di numeri ad una cifra in quanto le cifre decimali
occupano posizioni adiacenti nella tabella dei codi ASCII ed in particolare:
Carattere
0
1
2
3
4
5
6
7
8
9
Codice
ASCII
48 (0+48)
49 (1+48)
50 (2+48)
51 (3+48)
52 (4+48)
53 (5+48)
54 (6+48)
55 (7+48)
56 (8+48)
57 (9+48)
Se, dunque, si vuole stampare il contenuto del numero minore di dieci contenuto nella
variabile var bisogna:
;Spostarlo nel registro AL per prepararsi alla stampa
mov AL, var
;Aggiungere al contenuto di DL 48 per trasformare il numero nella
codifica ASCII ;della cifra corrispondente
ADD AL,48d
;Selezionare il servizio di stampa mettendo 02 nel registro AH
MOV AH,02d
;Invocare l’int 21h
Int 21h
Risulta ovviamente più complessa la stampa di un numero a due cifre. Il procedimento di
stampa di un numero a due cifra può essere diviso nelle seguenti fasi
1.
2.
3.
4.
5.
6.
7.
8.
9.
Divisione del numero da stampare per 10. Questo primo passo richiede
a) Spostamento del dividendo (numero da stampare) in AL
b) Azzeramento del registro AH in quanto il dividendo di una divisione è tutto
AX
c) Spostamento del divisore (10) in un registro
d) Divisione per il registro in cui si è messo il divisore
Salvataggio in qualche registro delle Unità costituite dal resto della divisione e
contenute (come da specifiche della divisione) in AH
Conversione della cifra delle decine (contenuta in AL) in carattere ASCII
sommando 48
Selezionare il servizio di stampa mettendo 02 in AH
Invocare int 21h per stampare le decine
Spostare le unità precedentemente salvare in AL
Conversione della cifra delle unità (contenuta ORA in AL) in carattere ASCII
sommando 48
Selezionare il servizio di stampa mettendo 02 in AH
Invocare int 21h per stampare le decine
Il codice risulta, dunque essere il seguente:
;Metto il numero a due cifre da stampare in al in quanto dovrò dividerlo
;per dieci ed il dividendo va in AX (passo 1a)
mov al,ris
;Azzero AH in quanto il dividendo è tutto AX (passo 1b)
mov ah,00d
;Metto in BL 10d (divisore) (passo 1c)
mov bl, 10d
;divido per 10 (passo 1d)
div bl
;adesso in ah ho il resto delle divisione (unità) ed in AL il quoziente
(centinaia)
; salvo in qualche registro (DL) le unità
mov dl, AH
;Adesso ho decine in AL e unità in DL non devo far altro che stamparli,
uno alla volta
;ricordandomi di convertirli nel rispettivo codice ascii sommando 48
;stampo le decine (passi 3, 4, 5)
add al,48d
mov ah,02h
int 21h
;stampo le unita (passi 6,7,8,9)
mov al,dl
add al,48d
mov ah,02h
int 21h
Lezione Quattro: Istruzioni di salto e simulazioni costrutti di selezione e iterativo
(libro di testo pagina 142-150)
Salto incodizionato
Sintassi:
JMP etchetta
Effetto:
La prossima istruzione che verrà eseguita non sarà quella che segue ma quella
posizionata dopo la scritta etichetta:
Confronto
Sintassi:
CMP op1, op2
Effetto:
Setta opportunamente i registri di stato in modo da memorizzare se:
• op1>op2
• op1>=op2
• op1=op2
• op1<>op2
• op1<=op2
• op1<op2
Limitazioni:
• op1 e op2 devono avere la stessa dimensione
• op1 e op2 non devono essere entrambe fornite per indirizzamento diretto
Salto codizionato
Sintassi:
Jxx etichetta
dove xx sono una o due lettere che verranno specificate di seguito che indicano in che
condizione saltare.
L'istruzione di salto condizionato deve essere preceduta da un CMP op1,op2
possibili condizioni:
JE → salta se op1 = op2
JNE → salta se op1<> op2
JA → salta se op1>op2
JAE → salta se op1>= op2
JB → salta se op1< op2
JBE → salta se op1<op2
Effetto
Se la condizione è rispettata si salta a etichetta altrimenti si esegue l'istruzione seguente
Simulazione del costrutto IF in assembly
Supponiamo di voler simulare il seguente programma C
if(var1>var2){
ist1
ist2
}
else{
ist3
ist4
}
ist5
;per prima cosa devo confrontare var1 con var2 ma poiché l'istruzione cmp non
ammette due operandi con indirizzamento indiretto devo spostare una delle due
(var1) in un registro (per esempio al)
MOV AL,var1
CMP AL,var2
;se la condizione è rispettata (cioè se al>var2) altrimenti devo eseguire ist3 e ist4
JA allora
;se var1 non è maggiore di var2 JA non esegue il salto e prosegue quindi qui
devo mettere le istruzioni da eseguire quando la condizione non è rispettata (ist3
e ist4) mentre, successivamente e dopo l'etichetta allora: scrivero le istruzioni
ist1 e ist2
IST3
IST4
;a questo punto devo andare alla fine dell'if altrimenti eseguirei tutte e due le
parti (then e else)
JMP fine
allora:
;qui è il punto in cui salterà la precedente istruzione JA quindi bisogna mettere
le istruzioni ist1 e ist2
IST1
IST2
;a questo punto si mette l'etichetta di fine della struttura
fine:
IST5
Simulazione del costruttoWHILE in assembly
Supponiamo di voler simulare il seguente programma C
while(var1>var2){
ist1
ist2
}
ist3
;come prima operazione devo mettere un'etichetta di inizio ciclo
ciclo:
;prima di eseguire il corpo devo confrontare var1 con var2 ma poiché
l'istruzione cmp non ammette due operandi con indirizzamento indiretto devo
spostare una delle due (var1) in un registro (per esempio al)
MOV AL,var1
CMP AL,var2
;se la condizione non è rispettata (cioè se al<=var2) devo uscire dal ciclo quindi
salto ad un etichetta che metterò alla fine
JBE fine
;se non sono uscito dal ciclo eseguo il suo corpo (ist1 e ist2) e poi salto in modo
incodizionato in testa (etichetta ciclo) al fine di ri testare la condizione
IST1
IST2
JMP ciclo
fine:
IST3