Una volta scritto il codice con un semplice editor di testo il programma deve essere compilato e poi linkato, per far questo scrivete dal prompt del DOS
TUT5.EXE TUT5.ASM ;TUT5.ASM (Hello Word) - by b0nuS 1997 .MODEL small ; indica al compilatore il modello di memoria da usare .STACK 100h ; dimensiona lo Stack .DATA ; inizio del segmento dati Messaggio DB "Salve Mondo",13,10,'$' ;dichiarazione del messaggio .CODE ; inizio del segmento di codice inizio: ;etichetta che segna l'inizio del programma (entry point) mov ax,SEG Messaggio ; ax = indirizzo del Segmento Dati mov ds,ax ; ds = ax mov dx,OFFSET Messaggio ; ds = offset del Segmento Dati mov ah,09h ; ah = 09h int 21h ; chiamata all'interrupt DOS mov ah,4Ch ; ah = 4Ch int 21h ; chiamata all'interrupt DOS END inizio ; fine del programma
( verranno visualizzate alcune informazioni sulla compilazione )
C:\tlink tut5.obj
(ora il file eseguibile è pronto : tut4.exe)
Per eseguire il programma scrivete semplicemente tut4.
Vediamolo ora nel dettaglio istruzione per istruzione :
.MODEL small
-------------
Definisce il tipo dei segmenti di memoria da utilizzare nel programma. Le
principali scelte possibili sono:
- TINY : tutto il codice e i dati sono in un unico segmento (stanno in 64Kb). Questo modello è il modello utilizzato per i file con estensione COM. - SMALL : è il modello più comune, un segmento per il codice e uno per i dati e lo stack tutti non oltre i 64Kb. - MEDIUM : il codice usa più segmenti, può quindi superare la barriera dei 64Kb. I dati e lo stack come nel modello small. - COMPACT : è come lo small ma per accedere ai dati uso puntatori di tipo FAR quest'ultimi possono infatti superare i 64Kb. - LARGE : è come il compact ma con il codice in più segmenti; sia codice che dati superano i 64Kb. - FLAT : supporta la modalità a 32bit dei processori 386+; in questa modalità viene abolito il metodo di indirizzamento SEGMENTO:OFFSET, l'indirizzo è dato da un unico numero a 32bit..STACK 100h
.DATA
-------
Inizializza il segmento dati. Dopo questa direttiva si dichiarano le variabili
da usare nel programma.
Messaggio DB "Salve Mondo",13,10,'$'
------------------------------------
Questa istruzione assegna alla variabile Messaggio il valore Salve Mondo,
cioè la stringa "Salve Mondo" più altri 3 caratteri.
DB definisce dei Byte in memoria e in questo caso il numero dei byte è 14 : 13
per la stringa Salve mondo uno per il carattere 13 (CR), uno per il 10 (LF) e
uno per il terminatore '$', che deve essere sempre presente alla fine di una
stringa.
In questo caso la variabile è quindi inizializzata se avessimo voluto solo
riservare dello spazio (ad esempio 10 Byte) per riempirlo durante l'esecuzione
del programma avremmo dovuto scrivere:
Nome_Variabile DB 10 DUP(?)
Quindi abbiamo visto che la direttiva DB definisce byte , ne esistono altre:
DW - Define Word
DD - Define Double word
DQ - Define Quadword
DF - Define 48-bit (puntatore FAR 6 byte)
DT - Define TenByte
.CODE
------
Indica l'inizio del segmento di codice del programma.
mov ax,SEG Messaggio
--------------------
Questa prima istruzione (vera e propria) sposta in AX il valore del puntatore al
Data Segment.
Mov è (penso) l'istruzione più usata nei programmi, è quella che permette di
spostare dati dalla memoria alla cpu e viceversa.
Vediamo quali sono i modi di indirizzamento (così si chiamano) possibili:
1.Indirizzamento immediato mov ax,1643 1643 è il dato numerico da mettere in AX. 2.Indirizzamento assoluto mov ax[7563] 7563 è l'indirizzo del dato da mettere in AX. 3.Indirizzamento con registro mov ax,[si] metto in ax il dato puntato da si (che si trova all'indirizzo si). Si può anche scrivere: mov ax,[si+45] ; avete capito cosa fa vero? 4.Indirizzamento indiretto mov ax,[[1450]] equivale alle seguenti istruzioni: mov si,[1540] mov ax,[si] in pratica in 1450 c'è l'indirizzo del dato da mettere in AX.Note :
mov ds,ax
----------
Questa istruzione dovrebbe essere ormai chiara il contenuto di ax viene
spostato nel data segment. Quest'ultimo quindi punta all'inizio del
segmento dati.
Qualcuno potrebbe pensare di condensare le due istruzioni fin'ora viste in una
sola in questo modo:
mov ds,SEG Messaggio ; ERRATO !!!!beh...è sbagliato!
mov dx,OFFSET Messaggio
------------------------
Ora copiamo l'offset della variabile Messaggio in dx. OFFSET come SEG è una
parola riservata del linguaggio.
mov ah,09h
-----------
Copia il valore 09h (esadecimale) in ah. Nota che 09h viene copiato nella parte
alta di ax senza modificare il valore di al.
int 21h
--------
Ora si dovrebbe aprire una lunga (lunghissima) parentesi sugli Interrupt.
Gli Interrupt sono delle funzioni messe a disposizione dal sistema operativo o
dal BIOS per permettere alcune operazioni. Si possono paragonare alle funzioni
di libreria che si usano nei linguaggi ad alto livello certo queste hanno
un'interfaccia meno comoda.
consideriamo questo interrupt in particolare : INT 21h :
Questa è una funzione del Sistema Operativo (DOS) (tutti gli int 21h sono del
DOS) , ma cosa fa ???
Per sapere cosa fa si deve guardare al valore di AH al momento della chiamata
che nel nostro caso è 09h; bene se si va a guardare sul Reference Manual si
vede che questa funzione (int 21h funz. 09h) stampa una stringa sullo standard
output (Monitor) e si vede che la stringa che stampa è quella puntata da DS:DX
che nel nostro caso è proprio il messaggio "Salve Mondo".
Riassumendo la chiamata ad interrupt prevede le seguenti operazioni:
1. Settaggio dei parametri per la chiamata nei GIUSTI registri
2. Settaggio del valore di AH che identifica la funzione da eseguire
3. Chiamata all'INT XXh (XX = 21 per le chiamate al DOS)
4. (Non sempre)Lettura dei parametri dai registri
Il quarto punto non sempre deve essere eseguito ad esempio nel caso di stampa di
una stringa non è necessario ma se consideriamo la funzione che legge una
stringa dalla Console una volta letta dovremo pur farci qualcosa !!!!
Per avere la lista degli interrupt potete scaricare da internet la famosa lista
di Ralph Brown dal sito ftp : x2ftp.oulu.fi (nota : questa lista è la vostra
Bibbia: directory /pub/msdos/programming/doc/interXX.zip!!)
Spero abbiate capito cosa sono gli interrupt e allora vediamo cosa succede
quando ne viene generato uno (consideriamo proprio il nostro int 21h,09h).
Al momento della chiamata il flusso lineare del programma si interrompe, viene
salvato lo stato della CPU (registri, flag, ecc...) e l'IP salta all'indirizzo
della routine di interrupt, vi chiederete: dove sono, le routine di
interrupt???
Gli indirizzi di tutte queste routine sono memorizzate nel primo K di RAM la parte
di memoria che va dall'indirizzo 000h all'indirizzo 3FFh; ogni funzione ha a
disposizione 4byte , quindi nel nostro es. 21h * 4 = 84h che è l'indirizzo della
funzione DOS.
Vedremo più avanti come è possibile modificare queste funzioni.
Una volta eseguito il codice dell'interrupt il controllo torna a programma,
viene ripristinato lo stato della CPU e si continua l'esecuzione.
Per ora fermo qui la discussione sugli interrupt; ne vedremo altri nei prossimi
esempi e imparerete ad usarli.
mov ah,4Ch
-----------
OK !! Lo so che sapete già cosa fa e se guardate anche alla prossima istruzione
capite anche perchè lo fa , OK ??
Beh forse non sapete che funzione è la 4Ch, ve lo dirò io !
Questa funzione ritorna il controllo del computer al DOS. E' importante per far
terminare il programma.
int 21h
--------
Fa terminare il programma è un'altra funzione del DOS. Se togliamo questa
istruzione il computer si "impalla" e non ci resta che fare un bel reset.
PROVATE !!!
Analizziamo ora un'altra versione dello stesso programma :
Qual'è la differenza con l'esempio precedente ?
TUT5-1.COM TUT5-1.ASM ;TUT5-1.ASM - by b0nuS 1997 SEG_A SEGMENT ASSUME CS:SEG_A, DS:SEG_A ORG 100H Salve PROC FAR INIZIO: JMP START ;salta a START Messaggio DB "Salve Mondo",13,10,'$' ;dichiarazione del messaggio START: mov dx,OFFSET Messaggio ; ds = offset del Segmento Dati mov ah,09h ; ah = 09h int 21h ; chiamata all'interrupt DOS RETN Salve ENDP SEG_A ENDS END INIZIO
ASSUME CS:SEG_A DS:SEG_A
Indica al programma di riferire sia il CS che il DS al SEG_A (unico segmento
per i dati e per il codice)
ORG 100h
Indica l'indirizzo di partenza del programma. NOTA: tutti i programmi con
estensione COM DEVONO cominciare all'indirizzo 100h !!!
In questo esempio il programma non è altro che una procedura che viene chiamata
subito all'inizio del programma con l'istruzione JUMP START che non fa altro che
saltare all'etichetta START.
Alla fine della procedura c'è l'istruzione RETN che ritorna al chiamante.
C'è inoltre da notare che manca l'interrupt per la terminazione del programma
che nel caso di programmi .COM non serve !
IL resto del programma è uguale alla versione precedente.
Nei nostri futuri esempi useremo spesso questo tipo di programmi (anche se sono limitati a 64Kb ) in quanto per le nostre applicazioni sono sufficienti.
Vorrei aprire infine una parentesi sui programmi assembly.
Una volta scritto il codice sorgente (.ASM) questo viene compilato in codice
oggetto(.OBJ) ed infine linkato per creare il file eseguibile (.EXE o .COM).
Se provate a vedere il contenuto di quest'ultimo file binario vedrete solo una
serie di caratteri ASCII indecifrabile, ebbene ogni carattere ha un preciso
significato esiste infatti una corrispondeza biunivoca tra il codice sorgente
e il codice eseguibile al punto che il programma finale può essere deassemblato
per tornare al file sorgente; a dire il vero questa operazione non è poi così
facile è però possibile.
Se infatti provate ad usare un debugger come il Turbo Debugger accanto ad ogni
istruzione assembly c'è il suo relativo OPCODE.
Quindi ogni istruzione in linguaggio assembly viene tradotta in modo univoco
in un OPCODE esadecimale, ad esempio l'istruzione int 21h diventa CD 21 (in
esadecimale) e occupa due byte uno per l'istruzione uno per l'operando.
Come dicevamo nel tutorial 4 la CPU legge questi OPCODE nella fase di prefetch
e poi li decodifica in codice macchina.
Spero sappiate che un carattere ASCII occupa un byte (0-255, 0h-FFh).
Ora che abbiamo analizzato a fondo il programma forse preferite ritornare a
programmare in PASCAL che per scrivere una stringa sul monitor usa una semplice
istruzione. Come vedete anche nelle operazioni più semplici le cose da fare
sono molte ma è proprio questo il bello : il controllo assoluto sulla
macchina!!!
Beh non vi scoraggiate con un po' di pratica potrete diventare dei veri GURU
della programmazione!
Assembly Page di Antonio |
|