Alessio Luffarelli - Sito Web
Sei qui: Guide e Tutorial / Basso Livello / Operazioni di I/O in assembly
Le operazioni di I/O in Assembly.

prev Tutorial
Precedente
next

Sommario:

 

INTRODUZIONE

Una delle prime cose di cui ci si rende conto programmando in Assembler (per essere rigorosi andrebbe detto Assembly, ma da qui in poi non farò attenzione al termine utilizzato), è la mancanza di istruzioni per l'input da tastiera e per l'output sul video. Ciò non è da considerarsi una carenza del linguaggio ma, se ci si pensa su un attimo, si capisce che non può essere altrimenti. Questa impossibilità di I/O diretto con le periferiche è ancora più evidente per chi è solito programmare con linguaggi di medio/alto livello; in C++, ad esempio, siamo soliti scrivere cin>>pippo, o cout<<"Ciao Mondo". Ma vi siete mai chiesti cosa c'è dietro a "cin" e "cout"? Beh, dietro vi sono moltissime istruzioni Assembler.

LE INTERRUZIONI

Un interrupt (o interruzione) è un segnale di attenzione che può essere passato al microprocessore da qualunque periferica (harware) o da un programma (software). Nel caso di interruzione hardware, questo consiste in un segnale elettrico che, quando viene inviato al processore, causa il trasferimento del controllo ad una data locazione di memoria, da dove inizia l'esecuzione del cosiddetto programma di interrupt; quando quest'ultimo viene completato il processore riprende l'esecuzione del lavoro interrotto dal punto in cui l'aveva lasciato. Un interrupt software, invece, consiste in un tipo particolare di istruzione della CPU, che consente l'interruzione di un processo, qualora lo stesso debba effettuare una richiesta al sistema operativo o al BIOS del sistema.

Ma vediamo come sia possibile realizzare delle procedure di I/O. Il discorso è abbastanza semplice. Si sfruttano gli interrupt messi a disposizione dal DOS.
Queste interruzioni, in linguaggio x86, si richiamano con l'istruzione assembler INT, seguita dal numero esadecimale corrispondente all'interruzione desiderata. Prima di richiamare la INT è necessario però settare dei particolari registri, come, ad esempio AH (la parte alta di AX) e DL (la parte bassa di DX), con dei valori che fungeranno da parametri per l'operazione di interruzione. Vediamo subito un esempio, per chiarire meglio il concetto.

MOV DL,41h ;41h = 65 in decimale
MOV AH,02h
INT 21h

Questo frammento di codice pone il valore 65 (che in esadecimale è 41h) nel registro DL; pone poi in AH il valore 02h che corrisponde alla funzione di visualizzazione di un carattere a video; infine l'istruzione INT 21h richiama all'interruzione numero 21h del DOS (in cui è presente la funzione 02h di visualizzazione di un carattere). Ma questo frammento di codice quale carattere stampa a video? Proprio il carattere che nel codice ASCII corrisponde al valore caricato, prima di richiamare l'interruzione, nel registro DL; in questo caso il valore caricato in DL è 65 che corrisponde al carattere 'A'. È semplice il giochetto, no? Ma vediamo ora un altro esempio in cui i registri non hanno la funzione di parametri di ingresso dell'interruzione, bensì di parametri di uscita (dove, cioè, verrà restituito il "risultato" dell'interruzione).

MOV AH,07h
INT 21h

La funzione 07h interrompe l'esecuzione del programma e attende che venga premuto un tasto sulla tastiera, senza però farne l'eco sul video. La chiamata all'interruzione 21h permette poi di eseguire tale interruzione. Ma una volta eseguito questo frammento di codice, come facciamo a sapere quale carattere della tastiera è stato premuto? Grazie al registro AL (che qui funge da parametro di uscita dell'interruzione) in cui verrà posto il valore del codice ASCII corrispondente al carattere acquisito.

E' chiara la differenza fra i due esempi? Penso di sì.

OLTRE I CARATTERI

Spesso in un programma, si deve andare oltre l'acquisizione o la stampa di singoli caratteri. Si può avere, ad esempio, la necessità di acquisire o stampare una intera stringa oppure un numero, sia intero che in virgola mobile. Per fare questo, bisogna tenere a mente un concetto fondamentale: tutto ciò che si batte alla tastiera, sia esso un numero o una stringa, viene acquisito dal computer sotto forma di singoli caratteri. Sta quindi al programmatore assembler, scrivere codice per interpretare una sequenza di caratteri come un numero o come una stringa. Se non avete idea di come si possa fare, alla fine di questa guida troverete una libreria di input output di base ma completa (acquisizione e stampa di: caratteri, numeri interi e stringhe).

UNA PANORAMICA

Le interruzioni messe a disposizione dal BIOS e dal DOS sono moltissime e ognuna di queste comprende moltissime funzioni. Il risultato è che si può fare veramente di tutto. Si possono leggere e stampare caratteri, si può accedere ai file sull'hard disk, si può gestire la stampante, lo scanner, la penna ottica, il mouse, si può leggere e modificare l'orologio di sistema, emettere suoni, realizzare grafici e disegni sul monitor.

Per avere l'elenco completo delle interruzioni fate riferimento a qualche manuale di Assembler. Qui di seguito ne elenco solo alcune del DOS:

20h - Program terminate
21h - Function request
22h - Terminate address
23h - Ctrl-break exit address
24h - Critical error handler vector
25h - Absolute disk read
26h - Absolute disk write
27h - Terminate but stay resident
2Fh - Printer

Il più importante tra questi, come abbiamo avuto modo di vedere, è il 21h. Se siete interessati, potete scaricare da qui, l'elenco delle funzioni dell'interrupt 21h. In questo file trovate solo un elenco di tali funzioni. Se desiderate informazioni più approfondite, come quali siano i parametri di ingresso e di uscita, cercate il nome della funzione di vostro interesse su Google: troverete sicuramente più informazioni di quante possa darvene io in poche righe.

N.B.: con l'introduzione di Windows XP, alcune funzioni del BIOS e del DOS non sono state più rese disponibili. Questo perchè tale sistema operativo, introduce cambiamenti radicali rispetto ai sistemi precedenti, soprattutto sul piano della stabilità.

LA LIBRERIA DI I/O

Vi propongo ora una libreria di I/O realizzata da me (assembler_io.zip - 2k). Purtroppo al suo interno non vi sono molti commenti (i preziosi commenti..!), poichè quando l'ho scritta non avevo acquisito ancora questa esperienza. La libreria è stata scritta per l'assemblatore ZMASM (quindi se ne utilizzate un altro, potrebbe essere necessario ritoccare qualcosa) ed è perfettamente funzionante. Per utilizzarla dovete inserirla nella stessa cartella del file sorgente del vostro programma e richiamarla con la direttiva INCLUDE.


Questo articolo ti è piaciuto o ti è stato utile? Scrivimi e dimmi cosa ne pensi. Mi incoraggerai a scriverne altri..

(C) Alessio Luffarelli