Sei sulla pagina 1di 29

DISPENSA

LINGUAGGIO

ASSEMBLY

ANNO SCOLASTICO 2013 – 2014

PROF. RANALLI LORIS

DISPENSA LINGUAGGIO ASSEMBLY ANNO SCOLASTICO 2013 – 2014 PROF. RANALLI LORIS

LINGUAGGIO ASSEMBLY

PROF. RANALLI LORIS

CAPITOLO 1: STRUTTURA DI UN PROGRAMMA ASSEMBLY

Un programma assembly deve essere strutturato in un certo modo, si può dire che il linguaggio assembly è un linguaggio ordinato, se si seguono tutte le regole di struttura di un programma si ottiene qualcosa di ordinato, leggibile e abbastanza privo di errori. Il programma è strutturato nel seguente modo:

Definizione del segmento Dati

Definizione del segmento Stack

Definizione del segmento di Codice

In questo capitolo vedremo quali sono le direttive che vengono usate per definire i vari segmenti.

1.1 Definizione dei Segmenti Dati, Stack e Codice.

Per definire un segmento si usa la direttiva segment preceduto dal nome che vogliamo dare al segmento:

Dati segment ;definisco il segmento per l’area Dati

...

;

parte relativa

all’area Dati, contiene

la ...

;dichiarazione delle variabili con

...

;visibilità globale.

ends

; chiusura della definizione del segmento

In Assembly i commenti vanno inseriti preceduti dal ;

Il segmento Dati viene utilizzato per la definizione e l’eventuale inizializzazione delle variabili con visibilità globale ( tali variabili sono accessibile in ogni parte del programma). La dichiarazione del segmento dati è quella che abbiamo appena illustrato.

La definizione del segmento Stack è opzionale. Nella definizione dello stack bisogna indicare la dimensione che si vuole dare allo Stack (alla pila), poiché per lo stack viene utilizzato un segmento possiamo dire che la dimensione massima dello stack può essere di 64 KB. La definizione dello stack è la seguente:

2

LINGUAGGIO ASSEMBLY

PROF. RANALLI LORIS

stack segment … ; eventuale inizializzazione della pila ends

Il segmento Codice è sempre presente all’interno di un programma scritto in assembly, esso contiene l’inizializzazione dei registri di segmento, il codice del programma e il ritorno del controllo al sistema operativo (terminazione del programma). La struttura del segmento di Codice è la seguente:

Codice segment assume cs:Codice ;Con la direttiva assume assume ds:Dati assume ss:Stack assume es:Dati

start:

;Area di codice: contiene il codice del ;nostro programma

MOV AX,Dati MOV DS,AX

;Inizializzazione a runtime ;dei registri di segmento

MOV AX,Stack MOV SS,AX MOV AX,Extra MOV ES,AX … MOV AX,4c00h

;Terminazione del programma

INT 21h

;invio della richiesta di terminazione ;del programma

ends

;chiusura del segmento Codice

end start

;Chiusura dell’Area di codice

1.2 Identificatori, Espressioni e costanti.

Un programma può contenere:

Identificatori: Sono nomi che vengono assegnati alle varie entità del programma (ad esempio i nomi delle variabili, le etichette, i nomi che vengono dati ai segmenti ecc.). Sono composti da caratteri alfanumerici (non possono però iniziare con un numero). Possono avere al massimo 31 caratteri.

3

LINGUAGGIO ASSEMBLY

PROF. RANALLI LORIS

Costanti:

le

costanti

sono

dei

valori

numerici

nei

formati:

decimale, binario, ottale, esadecimale, ASCII. Alcuni esempi di costanti:

Binario: 0100110B Ottale: 15O

Esadecimale: 0ffh, 26Ah, 0ffffh (devono iniziare sempre con un numero).

ASCII: ‘A’

, ‘Hello World’

1.3 Variabili di memoria definiti nel segmento dati

Le variabili che vengono definite nel segmento dati sono dette variabili globali e sono visibili in ogni parte del programma. La definizione di una variabile (chiamata anche allocazione in memoria di una variabile), va fatta all'interno del segmento dati:

Dati segment ;allocazione delle variabili ends

Per allocare una variabile si utilizza la seguente sintassi:

nome_var D* dato * può essere:

  • - B se viene allocato un byte in memoria per contenere il dato

  • - W se vengono allocati due byte in memoria per contenere il dato

Dato può essere:

  • - Un numero (56, 0F3h )

  • - un carattere indicato tra apici ('A')

  • - ? --> quando non si vuole inizializzare la variabile

Esempi:

Dati segment zero DB DW

esa non_ini DB ends

0

1234ABCD h ?

Per definire una costante numerica si utilizza la direttiva EQU. es.

minuto

EQU

60

ora

EQU

3600

4

LINGUAGGIO ASSEMBLY

PROF. RANALLI LORIS

In questo modo si associa ad una costante numerica un nome simbolico che può essere utilizzato nel nostro programma. Una costante non può essere modificata all'interno del nostro programma.

5

LINGUAGGIO ASSEMBLY

1.4 Istruzioni

PROF. RANALLI LORIS

Quando si scrivono le istruzioni occorre rispettare le seguenti regole:

  • - nelle istruzioni con due operandi (dest, sorg), i due operandi non possono essere contemporaneamente locazioni di memoria: (reg- mem, mem-reg, reg-reg, reg-costante, mem-costante)

  • - una costante non può essere mai l'operando di destinazione

  • - Per indicare una locazione di memoria si pone l'indirizzo tra parentesi quadre ( [ind]).

  • - Gli operandi sorg e dest devono avere la stessa dimensione.

  • - Istruzione MOV

MOV dest, sorg

Equivale all’operazione = (assegnamento):

dest = sorg

dest e sorg possono essere:

-

registri :

ax,

, dx – di, si, ...

-

memoria: indirizzo di memoria

sorg può essere anche una costante dest e sorg non possono essere entrambi indirizzi di memoria dest non può mai essere il registro CS alcuni esempi:

-

registro – registro

MOV AX,BX

 

MOV CX,DX

-

registro – costante

MOV AX,123 MOV CX,0ff3h

 

-

registro - memoria

MOV AX, var1

 
 

MOV

BX, [CX] Il registro CX contiene un indirizzo di memoria

-

memoria – registro

MOV

var1, AX

MOV [CX],BX Il registro CX contiene un indirizzo di memoria

6

LINGUAGGIO ASSEMBLY

  • - Metodi di indirizzamento

PROF. RANALLI LORIS

I metodi di indirizzamento sono sistemi di accesso agli operandi di un'istruzione. Esistono quattro tipi di indirizzamento (gli esempi verranno fatti tramite l'utilizzo dell'unica istruzione vista):

  • - Indirizzamento immediato: si ha quando l'operando è una costante

numerica

(l'operando può essere una costante solo se è l'operando

sorgente).

MOV AX,123

--> Qui si ha un indirizzamento immediato, 123 è l'operando immediato.

  • - Indirizzamento a registro: si ha quando l'operando è contenuto in un registro.

MOV AX,123

--> Qui si ha un indirizzamento

a registro, l'operando di destinazione è contenuto in un registro.

  • - Indirizzamento diretto: si ha quando l'operando è una variabile contenuta in una locazione del segmento Dati.

MOV AX,var1 --> Qui si ha un indirizzamento diretto, l'operando sorgente è contenuto in una variabile del segmento dati (var1).

  • - Indirizzamento indiretto: si ha quando l'operando è contenuto in una locazione di memoria il cui indirizzo è contenuto in un registro (si utilizzano i registri BX, SI, DI se la locazione di memoria si trova nel segmento Dati, BP se la locazione si trova nel segmento Stack. Se la locazione di memoria si trova nel segmento Extra l'indirizzo di tale locazione deve essere espresso nella forma segmento:offset ). Il registro che contiene l'indirizzo è racchiuso tra le parentesi [ ] (le parentesi stanno ad indicare il contenuto della locazione di memoria il cui indirizzo è memorizzato nel registro).

MOV [BX],AL --> Qui si ha un indirizzamento indiretto, l'operando di destinazione è contenuto nella locazione di memoria il cui indirizzo è memorizzato nel registro racchiuso tra parentesi [ ] (BX).

7

LINGUAGGIO ASSEMBLY

PROF. RANALLI LORIS

MOV ES:[BX],AL

--> In questo caso la locazione è contenuta nel segmento Extra

  • - Istruzione XCHG (Exchange)

XCHG dest,sorg

il contenuto dei due operandi viene scambiato dest assume il valore di sorg e viceversa.

es. prima di XCHG dest,sorg

dest=5

sorg=123

dopo XCHG dest,sorg

dest=123

sorg=5

Per questa istruzione gli operandi non possono essere immediati.

  • - Istruzioni INC e DEC

INC op

Incrementa di un'unità l'operando dell'istruzione, che può essere un registro o una locazione di memoria.

DEC op

Decrementa di un'unità l'operando dell'istruzione, che può essere un registro o una locazione di memoria.

Se si tratta di una locazione di memoria (il cui indirizzo è racchiuso tra [ ]) bisogna indicare la dimensione di tale locazione attraverso l'uso delle parole chiave byte ptr e word ptr che specificano rispettivamente una locazione di un byte e una locazione di due byte.

esempi

INC AX

INC var

INC byte ptr [BX]

8

LINGUAGGIO ASSEMBLY

  • - Istruzioni AND, OR, NOT, XOR

AND dest,sorg

PROF. RANALLI LORIS

Calcola l'AND logico bit a bit tra dest e sorg ponendo il risultato in dest.

esempio:

prima di AND dest,sorg

dest=0110B

sorg=0101B

dopo AND dest,sorg dest=0100B

OR dest,sorg

Calcola l'OR logico bit a bit tra dest e sorg ponendo il risultato in dest.

esempio:

prima di OR dest,sorg

dest=0110B

sorg=0101B

dopo OR dest,sorg dest=0111B

NOT dest

 

Inverte tutti i bit contenuti in destinazione.

esempio:

prima di NOT dest

dest=0110B

dopo NOT dest dest=1001B

XOR dest,sorg

Calcola lo XOR logico bit a bit tra dest e sorg ponendo il risultato in dest. Questa istruzione viene utilizzata di solito per azzerare il contenuto di un registro.

esempio:

prima di XOR dest,sorg dest=0110B

sorg=0101B

dopo XOR dest,sorg dest=0011B

9

LINGUAGGIO ASSEMBLY

PROF. RANALLI LORIS

esempio dell'uso dell'istruzione XOR per azzerare il contenuto di un registro:

prima di XOR ax,ax

ax=0110B

ax=0110B

dopo XOR ax,ax

ax=0000B

Esercizio 1

Dato il valore 38, impostare a 0 il bit di peso 2

(38) 10 =(100110) 2

il bit di peso 2 è il seguente

100110

quindi tale bit lo si può indicare come 000100 = (4) 10 ovvero 2 2 (bit di peso 2). Il numero che individua la posizione di un bit è chiamato maschera.

Quindi per azzerare tale bit si può ragionare in questa maniera:

prendo la maschera 000100 la inverto con una operazione not --> 111011. Effettua un operazione AND tra il numero 38 e la maschera invertita:

100110

AND

111011

------

100010

(il bit di peso due è azzerato)

Come si scrive tutto ciò in assembler? ;segmenti start:

MOV AL,38 MOV AH,4 NOT AH AND AH,AL MOV AX,4C00h INT 21h ENDS END start

10

LINGUAGGIO ASSEMBLY

  • - Istruzione ADD e ADC

PROF. RANALLI LORIS

ADD dest,sorg --> dest=dest+sorg

Effettua la somma (intera o naturale) tra destinazione e sorgente. Il risultato viene memorizzato in dest. dest non può essere un operando immediato. Se il risultato della somma ha una dimensione (in numero di bit) maggiore di dest (c'è stato un riporto) allora viene settato a 1 il flag CF. Viene settato a 1 il flag OF se si ha un traboccamento.

ADC dest,sorg --> dest=dest+sorg+CF

Effettua la somma (intera o naturale) tra destinazione e sorgente somma inoltre anche il valore attuale del flag CF. questa istruzione viene utilizzata quando si voglio sommare due numeri a 32 bit.

esempio

H

L

AX=0100 1001 | 1001 0001

BX=1100 0110 | 1100 0000

voglio effettuare la seguente operazione:

AX|BX + 0000 0000 0000 0000 1100 0000 0000 0000

ADD BX,C000h

BX=1000 0110 1100 0000

CF=1

ADC AX,0000h

AX=0100 1001 1001 0010

La coppia di registri AX|BX

contiene il risultato dell’operazione svolta

N.B. se ADD contiene un operando con indirizzamento indiretto occorre specificare se l’operando è a 8 o 16 bit tramite le parole chiave byte ptr e word ptr. In realtà se il programmatore è attento nello scrivere correttamente l’istruzione, rispettando le dimensioni dei vari operandi, può anche omettere tali parole chiave. Il consiglio è quello di inserirle sempre in quanto se c’è qualche anomalia il compilatore ve la segnalerà. Il rischio che si corre quando non si inseriscono è quello di ottenere dei risultati errati.

11

LINGUAGGIO ASSEMBLY

PROF. RANALLI LORIS

esempio

ADD byte ptr [BX],12

ADD byte ptr [BX], 300

--> in questo caso il compilatore segnala l’errore, infatti i due operando non hanno la stessa dimensione (8 bit, 16 bit).

  • - Istruzione SUB e SBB

SUB dest,sorg --> dest=dest-sorg

Effettua la sottrazione (intera o naturale) tra destinazione e sorgente. Il risultato viene memorizzato in dest. Il flag CF viene settato a 1 se c’è una richiesta di prestito proveniente dal bit più significativo. Viene settato a 1 il flag OF se si ha un traboccamento.

SBB dest,sorg --> dest=dest-sorg-CF

Effettua la sottrazione (intera o naturale) tra destinazione e sorgente e sottrae, inoltre, anche il valore attuale del flag CF. questa istruzione viene utilizzata quando si vuole effettuare una sottrazione che produce un risultato su 32 bit (ad es. sottrazione tra due numeri a 32 bit).

esempio (AX=1B0Dh, DX=0000h)

H

L

AX=0001 1011 | 0000 1101

BX=0000 0000 | 0000 0000

voglio effettuare la seguente operazione:

AX|BX – 1= 0001 1011 0000 1101 0000 0000 0000 0000 - 0001

SUB BX,0001h

SBB AX,0000h

BX=1111 1111 1111 1111

AX=0001 1011 0000 1100

CF=1

La coppia di registri AX|BX contiene il risultato dell’operazione.

N.B. se SUB contiene un operando con indirizzamento indiretto occorre specificare se l’operando è a 8 o 16 bit tramite le parole chiave byte ptr e word ptr. In realtà se il programmatore è attento nello scrivere correttamente l’istruzione, rispettando le dimensioni dei vari operandi, può

12

LINGUAGGIO ASSEMBLY

PROF. RANALLI LORIS

anche omettere tali parole chiave. Il consiglio è quello di inserirle sempre in quanto se c’è qualche anomalia il compilatore ve la segnalerà. Il rischio che si corre quando non si inseriscono è quello di ottenere dei risultati errati.

  • - Istruzione MUL e IMUL

MUL operando

L’istruzione MUL viene utilizzata per effettuare una moltiplicazione tra numeri naturali. Se operando è un numero a 8 bit effettua la moltiplicazione tra operando e il registro implicito AL, il risultato viene salvato in AX.

AX = operando * AL

Se operando è un numero a 16 bit effettua la moltiplicazione tra operando e il registro implicito AX, il risultato viene salvato nella coppia di registri DX| AX (DX rappresentano i 16 bit più significativi, AX i 16 bit meno significativi).

DX|AX = operando * AX

L’istruzione IMUL effettua la moltiplicazione tra numeri interi, applicando la regola del segno (segni concordi risultato positivo, segni discordi risulato negativo).

Per precauzione si consiglia di AZZERARE il registro DX prima di effettuare l’operazione MUL/IMUL con operando a 16 bit.

ATTENZIONE!!! operando non può essere un operando immediato, può essere o un registro o un operando in memoria (indirizzamento diretto o indiretto).

  • - Istruzioni DIV e IDIV

DIV divisore

L’istruzione DIV viene utilizzata per effettuare una divisione tra numeri naturali. Se divisore è un numero a 8 bit effettua la divisione tra AX e l'operando divisore. Il quoziente della divisione viene collocato nel registro AL ed il resto nel registro AH

AX / divisore --> AL=Q AH=R

Se divisore è un numero a 16 bit effettua la divisione tra il contenuto a 32 bit della coppia di registri DX|AX e l'operando divisore. Il quoziente della divisione viene collocato nel registro AX ed il resto nel registro DX.

DX|AX / divisore --> AX=Q DX=R

13

LINGUAGGIO ASSEMBLY

PROF. RANALLI LORIS

L’istruzione IDIV effettua la divisione tra numeri interi, applicando la regola del segno (segni concordi risultato positivo, segni discordi risulato negativo).

Per precauzione si consiglia di AZZERARE il registro DX prima di effettuare l’operazione DIV/IDIV con operando a 16 bit.

ATTENZIONE!!! divisore non può essere un operando immediato, può essere o un registro o un operando in memoria (indirizzamento diretto o indiretto).

  • - Istruzione LEA

LEA reg,var

Inserisce

nel

registro

reg l’indirizzo della locazione di memoria della

variabile var.

 

Esempio

Data segment

 

Var1

DB

35

;supponiamo che var1 sia ;posizionata all’indirizzo 130h

end segment … LEA SI,variabile

;in SI viene inserito 130h (indirizzo ;della variabile var1)

1.5 Strutture di controllo e istruzioni di salto

Le strutture di controllo e le istruzioni di salto che verranno illustrate ci permettono di realizzare i costrutti IF-ELSE e i CICLI, i quali, sono utilizzati in tutti i linguaggi di programmazione.

14

LINGUAGGIO ASSEMBLY

PROF. RANALLI LORIS

-

Istruzione CMP (Compare)

CMP op1,op2

L’istruzione CMP viene utilizzata per effettuare un confronto tra op1 e op2, il risultato dell'istruzione è la modifica di alcuni flag del registro dei flag. In realtà, l'istruzione CMP non fa altro che una sottrazione tra op1 e op2:

op1 - op2 --> se il risultato è negativo allora op2>op1 quindi viene settato CF=1 (si ha una richiesta di prestito dal bit più significativo) altrimenti op1>=op2 Se op1=op2 allora il risultato della sottrazione sarà zero per cui sarà settato ZF=1 (l'ultima istruzione ha prodotto un risultato uguale a zero), se op1!=op2 --> ZF=0.

Riassumendo:

CMP op1,op2

op1>op2

-->

CF=0 ZF=0

op2<op2

-->

CF=1 ZF=0

op1=op2

-->

CF=? ZF=1

op1!=op2

-->

CF=? ZF=0

op1>=op2

-->

CF=0 ZF=?

op1<=op2

--> CF=1 ZF=?

op1 può essere: reg, imm, mem op2 può essere: reg, imm, mem L'istruzione CMP non modifica in nessun caso op1 e op2, op1 e op2 devono avere la stessa dimensione.

-

JMP: istruzione di salto incondizionato

JMP etichetta

JMP indirizzo_istruzione

L’istruzione JMP permette di saltare all'esecuzione dell'istruzione il cui indirizzo è indicato come operando dell'istruzione JMP. L'istruzione JMP modifica il registro IP (puntatore all'istruzione successiva), inserendo al suo interno l'indirizzo indicato nell'istruzione stessa.

Esempio 1

start:

...

JMP fine

;etichetta

fine

che

in

realtà

è

il

nome

simbolico di un indirizzo fine: MOV AX,4c00h

...

INT 21h

ends

end start

15

LINGUAGGIO ASSEMBLY

Esempio 2

start:

PROF. RANALLI LORIS

... JMP CS:120 ;Salta all'istruzione che si trova all'offset 120 (si suppone sial'offset dell'etichetta fine)

... fine: MOV AX,4c00h INT 21h

ends

end start

  • - J*: istruzione di salto condizionato J* etichetta

J* indirizzo_istruzione

Il

simbolo

*

va

sostituito

con

una

o

due lettere

opportune

 

L’istruzione J* permette di saltare all'esecuzione dell'istruzione il cui indirizzo è indicato come operando dell'istruzione se l'esecuzione dell'istruzione precedente ha provocato un certo evento (ha modificato uno o più flag). Questa istruzione viene utilizzata, di solito, dopo l'istruzione CMP L'istruzione J* modifica il registro IP (puntatore all'istruzione successiva), inserendo al suo interno l'indirizzo indicato nell'istruzione stessa.

CMP op1,op2 J*

J* può essere:

Istruzioni di salto

Operatore

Descrizione

cond.

equivalente

JE

   

(equal)

=

op1 = op2

JNE

   

(not equal)

!=

op1 != op2

JA

>

op1 > op2

(Above)

(solo numeri naturali)

JB

<

op1 < op2

(Below)

(solo numeri naturali)

JAE

 

op1>=op2

(Above or Equal)

>=

(solo numeri naturali)

JBE

 

op1<=op2

(Below or Equal)

<=

(solo numeri naturali)

JG

>

op1>op2

(Greater)

(per numeri interi)

16

LINGUAGGIO ASSEMBLY

PROF. RANALLI LORIS

JL

<

op1<op2

(Less)

(per numeri interi)

JGE

 

op1>=op2

(Greater or Equal)

>=

(per numeri interi)

JLE

 

op1<=op2

(Less or Equal)

<=

(per numeri interi)

istruzione ;istruzione che modifica i flag J*

J* può essere:

Istruzioni di

 

salto cond.

Descrizione

JC

salta se CF=1

JNC

salta se CF=0

JO

salta se OF=1

JNO

salta se OF=0

JP

salta se PF=1

JNP

salta se PF=0

JS

salta se SF=1

JNS

salta se SF=0

JZ

salta se ZF=1

JNZ

salta se ZF=0

Esempio: programma che trasforma un numero (contenuto in ax), se negativo, in positivo

start:

... CMP AX,0 JGE fine NOT AX ;per trasformare un numero negativo (in complemento a due) in numero positivo si invertono tutti i bit e si incrementa di uno

INC AX fine: MOV AX,4c00h INT 21h

ends

end start

17

LINGUAGGIO ASSEMBLY

PROF. RANALLI LORIS

- IF-ELSE Il costrutto IF-ELSE si realizza attraverso l’utilizzo della coppia di istruzioni CMP, J* e JMP:

18

LINGUAGGIO ASSEMBLY

start:

else:

... MOV AX,A MOV BX,B CMP AX,BX JA if … ;istruzioni else

if: …

JMP continua ;istruzioni if

continua:

 

… MOV AX,4C00H INT 21h

ENDS

END start

PROF. RANALLI LORIS

-

CICLO DO-WHILE

Il costrutto DO-WHILE si realizza attraverso l’utilizzo della coppia di

istruzioni CMP, J* :

 
 

start:

JA ciclo ;ripeti ciclo

...

;finchè op1>op2

ciclo:

;istruzioni

fine ciclo:

;ciclo CMP op1,op2

... MOV AX,4C00h INT 21h

 

ENDS

END

-

CICLO WHILE

Il costrutto WHILE si realizza attraverso l’utilizzo della coppia di istruzioni

CMP, J* :

start:

 

...

JMP inizio_ciclo

inizio_ciclo:

fine ciclo:

CMP op1,op2 JA fine ciclo ;se op1>op2 esci

... MOV AX,4C00h INT 21h

;dal ciclo

ENDS

... ;istruzioni ciclo

END

19

LINGUAGGIO ASSEMBLY

  • - CICLO FOR

PROF. RANALLI LORIS

Il costrutto FOR si realizza attraverso l’utilizzo della coppia di istruzioni CMP, J* :

MOV cx,0000h ; in Assembly inizio_ciclo:

CMP cx,n JE fine_ciclo … ; istruz. del ciclo INC cx JMP inizio_ciclo fine_ciclo: ;FINE CICLO

/* in C */ for (cx=0;cx!=n;cx++) { /* inizio ciclo */ … ; istruz. del ciclo } /* fine ciclo */

  • - Istruzione loop

indirizzo:

MOV CX,num_ripetizioni ... ... LOOP indirizzo

;decrementa CX e

;controlla CX!=0 L’istruzione loop permette di eseguire ciclicamente il codice racchiuso tra un punto del codice e l’istruzione loop, ad ogni esecuzione loop decrementa il contenuto di CX e controlla che CX sia diverso da zero. L’esecuzione ciclica termina quando CX è uguale a 0.

1.6 Interruzioni software e servizi

Il sistema operativo offre ai programmatori delle funzioni già pronte che permettono di accedere ai vari dispositivi di I/O del computer (video, mouse, tastiera, disco rigido ecc.). Tali funzioni, chiamate API (Application Programming Interface), facilitano il lavoro del programmatore che non deve conoscere nei dettagli come sono strutturare le periferiche di I/O. Per utilizzare le API il programmatore deve sfruttare il meccanismo dell’interruzione software, tramite l’utilizzo dell’istruzione INT:

INT num_int

num_int: rappresenta il numero identificativo (espresso in esadecimale) della funzione che si vuole utilizzare, è un numero che è compreso nell’intervallo

[0,255].

Il sistema operativo permette, quindi, di avere fino a 256 tipi di interruzioni (chiameremo così le nostre funzioni API). Ogni interruzione può offrire diverse sottofunzioni chiamate servizi di interruzione. Anche i servizi di interruzione sono identificati da un numero (num_serv) che viene inserito nel registro AH prima di invocare l’interruzione.

MOV AH,num_serv

20

LINGUAGGIO ASSEMBLY

INT num_int Le interruzione si distinguono in:

PROF. RANALLI LORIS

Interruzioni hardware (id: da 0h a Fh): sono interruzioni che non sono richieste dal programmatore ma dalla CPU quando c’è un eccezione oppure dal dispositivo di I/O associato a all’interruzione richiesta.

Interruzioni software del BIOS (id:

da 10h a 1Fh) e di

MSDOS (id: da 20h a 2Fh): sono le funzioni API descritte prima.

Le interruzioni da 30h a 3Fh non sono documentate, invece quelle da 40h a FFh sono disponibili al programmatore per creare delle interruzioni software proprie.

Cosa succede quando viene inviata una richiesta di interruzione? INT num_int

Il sistema interrompe l’esecuzione del programma attualmente in esecuzione (che ha invocato un istruzione INT) accede, in memoria, ad una tabella chiamata IDT (Interrupt Descriptor Table) contenente i descrittori delle 256 interruzioni. La tabella è in realtà un array di 256 elementi, ogni elemento ha dimensione 4 Byte è contiene al suo interno CS e IP della funzione richiesta (chiamata anche sottoprogramma o subroutine). Il sistema calcola l’indirizzo assoluto dell’elemento della tabella da selezionare: num_int*4, preleva i 4 Byte dell’elemento e li posiziona all’interno dei registri CS:IP e restituisce il controllo del processore alla funzione richiesta. Terminata l’esecuzione della funzione di interruzione il controllo del processore viene restituito al programma che era stato bloccato, viene reimpostato il vecchio valore di CS e in IP viene inserito l’identificativo dell’istruzione successiva all’istruzione INT appena eseguita.

  • 1.6.1 Interruzioni software per il video e la tastiera

Le principali funzioni per l’accesso alla tastiera e al video per le operazioni di Input/Output fanno parte delle interruzioni 10h, 16h e 21h:

  • - Interruzione 10h: Funzioni per la gestione del video (interruzione sw BIOS)

  • - Interruzione 16h: Funzioni per la gestione della tastiera (interruzione sw BIOS)

  • - Interruzzione 21h: Funzioni per la gestione del video e della tastiera (interruzione sw di MSDOS) La differenza tra l’interruzione BIOS e interruzione di MSDOS è che la prima può essere eseguita in ogni caso anche quando il sistema operativo non è avviato, invece la seconda può essere eseguita solo dopo aver avviato il sistema operativo.

21

LINGUAGGIO ASSEMBLY

PROF. RANALLI LORIS

Vediamo come utilizzare queste interruzioni per far diventare i nostri programmi più interattivi.

-

INT 10h: Servizio (o funzione) di stampa a video di un carattere sullo schermo.

Quali registri utilizziamo? AL In AL inseriremo il codice ASCII (in esadecimale) del carattere

o

 

o

da stampare AH In AH inseriremo il numero del servizio che permette stampa di un carattere a video: 0Eh

la

Come?

MOV AL,Cod_Ascii_car MOV AH,0Eh INT 10h

 

Esempio

Supponiamo di voler stampare a video il carattere ‘A’ (codice ASCII 41h) MOV AL,41h MOV AH,0Eh

 

INT 10h

Occorre conoscere a memoria la tabella ASCII? Ni, sarebbe utile sapere solo qual è il codice ASCII del carattere ‘0’ e del carattere ‘A’, attraverso questi codici è semplice trovare il codice ASCII dei numeri successivi o delle lettere successive in quanto anche nella tabella ASCII

sono successivi (Se ‘A’ è 41h allora ‘B’

è 42h, ‘C’

è 43h e così via). In ogni

caso l’assembly ci viene incontro e se non ricordiamo il codice ASCII di un carattere possiamo indicare il carattere da stampare racchiuso tra apici ( ‘A’) invece di indicare il relativo codice:

MOV AL,’A’ MOV AH,0Eh INT 10h

INT 16h: Servizio (o funzione) di acquisizione di un carattere da tastiera. Quali registri utilizziamo? o AL In AL verrà inserito il codice ASCII del carattere acquisito da tastiera

-

o

Come?

AH In AH inseriremo il numero del servizio che permette stampa di un carattere a video: 00h

MOV AH,00h

INT 16h

;Dopo questa operazione in AL verrà ;inserito il carattere acquisito

la

22

LINGUAGGIO ASSEMBLY

PROF. RANALLI LORIS

Quando il processore richiama l’interruzione il programma si blocca in attesa che venga premuto un tasto della tastiera.

Esempio

Supponiamo di voler acquisire il carattere ‘A’ (codice ASCII 41h) MOV AH,00h

INT 16h

;il programma si blocca in attesa di un ;carattere, premo ‘A’. Il programma torna ;in esecuzione e in AL è contenuto il ;codice ASCII di ‘A’

  • - INT 21h: Servizi (o funzioni) di stampa a video di un carattere e acquisizione di un carattere da tastiera.

Stampa di un Carattere Quali registri utilizziamo? DL In DL inseriremo il codice ASCII (in esadecimale) del carattere da stampare oppure il carattere stesso racchiuso tra apici (es. ‘A’) AH In AH inseriremo il numero del servizio che permette la stampa di un carattere a video: 02h

o

o

Come?

MOV DL,Cod_Ascii_car MOV AH,02h INT 21h

Esempio

Supponiamo di voler stampare a video il carattere ‘A’ (codice ASCII 41h) MOV DL,41h MOV AH,02h INT 21h

Acquisizione di un Carattere

Il funzionamento è identico a quello visto per l’interruzione INT 16h, le uniche differenze sono l’interruzione INT 21h e il numero di servizio che è lo 01h

MOV AH,01h INT 21h

;il programma si blocca in attesa di un ;carattere, premo ‘A’. Il programma torna ;in esecuzione e in AL è contenuto il ;codice ASCII di ‘A’

23

LINGUAGGIO ASSEMBLY

PROF. RANALLI LORIS

1.7 Definizioni di Array e Stringhe

ARRAY L’array è una struttura dati che è costituita da un insieme di valori, della stessa dimensione, che sono contigui in memoria. In assembly gli array si possono definire nel seguente modo nel segmento dati:

Data segment Array1 DB 10 DUP(0) ;1* Array2 DW 0,1,2,3,4,5,6,7,8,9 ;2* ends

1* Definisce un array di 10 elementi, di dimensione un byte, tutti di valore zero. 2* Definisce un array di 10 elementi, di dimensione una word (2 Byte), i cui valori sono elencati nella definizione dell’array

(1,2,3,4,5,

...

Esempi 1* e 2*:

 

0100h

0

0200h

0

0102h

0

0204h

1

0104h

0

0208h

2

0106h

0

020Ch

3

0108h

0

020Eh

4

010Ah

0

0202h

5

010Ch

0

0206h

6

010Eh

0

020Ah

7

0110h

0

021Eh

8

0112h

0

0212h

9

Come si accede ad un elemento dell’array?

Per accedere ad un elemento dell’array si utilizza una sintassi simile a

quella del C++. Guardiamo come fare con un esempio pratico:

Es.1

Accedere all’elemento 5 dell’array definito nel segmento Dati

Data Segment Array DB 0,1,2,3,4,5,6,7,8,9 ends Code Segment ... start:

... MOV BX,4 MOV AL,Array[BX]

24

LINGUAGGIO ASSEMBLY

ends

end start

PROF. RANALLI LORIS

Per accedere all’elemento specifico del nostro array abbiamo usato l’istruzione MOV AL,Array[BX], l’indice del nostro elemento va indicato esclusivamente con uno dei registri indice (BX,SI,DI) utilizzando tutti i 16 bit del registro (non si possono utilizzare BL e BH).

Es.2

Dato un array di 10 elementi, realizzare un programma in assembly che incrementi di uno il valore di ogni elemento dell’array

Data Segment A DB 10,5,3,11,6,77,9,6,0,12 ends Code Segment assume DS:Data assume CS:Code start:

MOV AX,Data ;Inizializzazione del registro MOV DS,AX ;Dati con l’indirizzo del Segmento

MOV CX,10 ;in CX indichiamo che il ciclo deve ;essere ripetuto per 10 volte

ciclo:

MOV BX,CX ;L’indice dell’elemento deve stare ;nel registro BX DEC BX ;Dobbiamo accedere all’elemento BX-1 INC A[BX] LOOP ciclo

ends

end start

STRINGHE In un calcolatore ogni carattere è codificato secondo un opportuna codifica, quella più utilizzata e la codifica ASCII. Le stringhe sono un insieme di caratteri contigui, in assembler le possiamo rappresentare come array di caratteri ASCII. Ogni carattere è codificato attraverso 8 bit, quindi l’array deve essere un array di byte. Come si definisce un array di byte? Lo si definisce attraverso il formato AsciiZ (ASCII Zero Terminated), ovvero ogni stringa termina con il valore 0 (l’ultimo elemento dell’array di caratteri della stringa deve essere 0). La definizione della stringa nel segmento dati può essere fatta nel seguente modo :

Str

DB

”Ciao”,0

;0 carattere di fine stringa

25

LINGUAGGIO ASSEMBLY

PROF. RANALLI LORIS

Il processore quando incontra tale definizione trasforma ogni carattere nel corrispondente codice ASCII e lo inserisce nella corrispondente locazione in memoria. Se volessi inserire il carattere ‘P’ nel registro AX eseguo la seguente istruzione:

MOV AX,’P’ ; Inserisce in AX il codice ASCII della lettera ‘P’.

26

LINGUAGGIO ASSEMBLY

Esempio 1

PROF. RANALLI LORIS

Data la stringa definita qui sopra settare ad 1 il registro CL se tale stringa è

inizia con la lettera ‘C’ altrimenti inserire in CL il primo carattere della stringa.

... Code segment assume CS:Code assume DS:Data assume ES:Data start:

MOV AX,Data ;INIZIALIZZO IL REGISTRO DS MOV DS,AX

MOV BX,0

;DEVO CONTROLLARE LA PRIMA LETTERA DELLA ;STRINGA, QUELLA IN POSIZIONE 0

CMP Str[BX],’C’

JE coincide MOV CL,Str[BX] JMP fine coincide:

;SE non coincide

MOV CL,1 fine:

MOV AX,4C00h INT 21h end segment end start

;SE COINCIDE SCRIVO 1 IN CL

1.8 Istruzione di manipolazione dei bit

Istruzioni SAR, SAL

Queste due istruzioni effettuano lo scorrimento dei bit dell’operando.

SAR op,n_pos

op può essere solo un registro a 8 o a 16 bit.

n_pos

può essere un operando immediato oppure il registro CL.

Scorre verso destra i bit di op tante volte quanto vale n_pos. Ogni bit che esce a destra viene inserito nel CF e ogni bit che entra a sinistra vale 0. Terminata l’esecuzione dell’istruzione CF contiene l’ultimo bit uscito a destra.

27

LINGUAGGIO ASSEMBLY

Esempio

op= 10001101 n_pos=3 SAR op,n_pos

Sequenza scorrimenti:

PROF. RANALLI LORIS

CF

  • 0 0

0 0 1 0 0

1

0

0

1

1

0

1

  • ?

  • 0 0

0

1

0

0

1

1

0

1

0 0 1 0 0 1 1 0 1 ? 0 0 0 1 0 0

  • 0 1

0

0

0

0

0

1

1

0 0 0 0 1
  • 0 0

0 0 0 0 1

0

0

1

0

0

0

1

0

1

L’operazione SAR equivale alla divisione per 2 n_pos , nel nostro esempio 141/2 3 =141/8=17 SAR op,n_pos

op può essere solo un registro a 8 o a 16 bit.

n_pos

può essere un operando immediato oppure il registro CL.

Scorre verso sinistra i bit di op tante volte quanto vale n_pos. Ogni bit che esce a sinistra viene inserito nel CF e ogni bit che entra a destra vale 0. Terminata l’esecuzione dell’istruzione CF contiene l’ultimo bit uscito a sinistra.

Esempio

op= 00001101 n_pos=3 SAL op,n_pos

Sequenza scorrimenti:

?

? 0 0 0 0 1 1 0 1 0

0

0

0

0

1

1

0

1

? 0 0 0 0 1 1 0 1 0

0

 

0

0 0 0 0 1 1 0 1 0 0

0

0

0

1

1

0

1

0

0 0 0 0 1 1 0 1 0 0

0

0

0 0 0 1 1 0 1 0 0 0

0

0

1

1

0

1

0

0

0 0 0 1 1 0 1 0 0 0

0

0

0

1

1

0

1

0

0

0

0

 
? 0 0 0 0 1 1 0 1 0 0 0 0 0 1 1
? 0 0 0 0 1 1 0 1 0 0 0 0 0 1 1

L’operazione SAL equivale alla divisione per 2 n_pos , nel nostro esempio 13*2 3 =13*8=104.

28

INDICE

CAPITOLO 1: STRUTTURA DI UN PROGRAMMA ASSEMBLY..................................................2

  • 1.1 Definizione dei Segmenti Dati, Stack e Codice .................................................................2

  • 1.2 Identificatori, Espressioni e costanti ..................................................................................3

  • 1.3 Variabili di memoria definiti nel segmento dati...............................................................4

  • 1.4 Istruzioni................................................................................................................................5

  • 1.5 Strutture di controllo e istruzioni di salto.......................................................................13

  • 1.6 Interruzioni software e servizi...........................................................................................19

    • 1.6.1 Interruzioni software per il video e la tastiera................................................................20

      • 1.7 Definizioni di Array e Stringhe..........................................................................................23

      • 1.8 Istruzione di manipolazione dei bit........................................................................................26