dispensa i 6 - liceoischia.org · dispensa di informatica – i.6 ... pippo resw 1 ;riserva 1 word...
TRANSCRIPT
Dispensa di Informatica – I.6
Dispensa I.6 versione 1.0 mail: [email protected] Pagina 1 di 20
PROGRAMMAZIONE ASSEMBLER
La dispensa di seguito proposta si pone come tutorial per poter porre le basi per la
programmazione in ASSEMBLER.
Sarà di compendio il libro
PC Assembly Language, di Paul A. Carter” – disponibile per il download in italiano alla pagina
http://www.drpaulcarter.com/pcasm/pcasm-book-italian-pdf.zip oppure disponibile sul sito della
scuola.
Per poter sviluppare i programmi proposti sarà inoltre necessario scaricare l’ambiente di sviluppo
DJGPP scaricabile alla pagina http://www.delorie.com/djgpp/zip-picker.cgi oppure disponibile sul
sito della scuola in tre file .zip
- Ambiente_di_sviluppo_parte_1
- Ambiente_di_sviluppo_parte_2
- Ambiente_di_sviluppo_parte_3
Per installare l’ambiente di sviluppo è necessario avere i diritti di amministratore sulla macchina su
cui si installa e leggere ATTENTAMENTE il documento HOWTO_INSTALL_DJGPP.txt disponibile sul
sito della scuola.
Dispensa di Informatica – I.6
Dispensa I.6 versione 1.0 mail: [email protected] Pagina 2 di 20
AMBITO DI PROGRAMMAZIONE
Per facilitare lo studente l’ambiente di programmazione scelto è WINDOWS. Per poter utilizzare
l’ampia letteratura disponibile viene dunque utilizzato un ambiente di sviluppo DJGPP il quale
coniuga software OPESOURCE/FREEWARE con il S.O. Windows.
La architettura proposta è quella di un processore INTEL 386 o superiore (come vedremo non
cambia molto) e dunque – rispetto alla architettura studiata in precedenza e valida per qualsiasi
tipo di processore che sia stato realizzato seguendo il modello di VON NEUMANN – verranno
definiti alcuni specifici registri.
Dispensa di Informatica – I.6
Dispensa I.6 versione 1.0 mail: [email protected] Pagina 3 di 20
LA FAMIGLIA CPU 8086
Tutte le CPU della famiglia Intel presentano alcune caratteristiche comuni, tra le quali il linguaggio
macchina nativo
Le macchine 8088 (1979) ed 8086 (giugno 1978) risultano Identiche dal punto di vista della
programmazione, sono dotate di 16 registri generali a 16 bit e possono gestire programmi di al
massimo 1 megabyte di memoria.
Operano solo il REAL MODE, Non c’è alcuna limitazione sugli indirizzi di memoria cui un generico
programma può accedere.
Il processore può indirizzare fino a 1 MEGABYTE di memoria ( indirizzo a 20 bit ).
Le macchina 80286 (1982) aggiunge nuove istruzioni in linguaggio macchina, inoltre permette di
operare in PROTECTED MODE e compare il concetto di memoria virtuale, tuttavia i registri
continuano ad essere a 16 bit
Le macchina 80386 (1985) estende i registri a 32 bit permettendo l’indirizzamento tramite 32 bit e
dunque potendo allocare fino a 4 GB di dati ( 2 elevato alla 32).
Dalla macchina 80486 in poi non ci sono stati – a livello di architettura – grossi cambiamenti
mentre sono state migliorati gli aspetti prestazionali dei processori sia tramite la aggiunta di
istruzioni per la gestione delle immagini (MMX MultiMedia eXtensions) sia ottimizzando la
gestione delle risorse della CPU (CACHE, gestione della predizione dei CACHE HIT/MISS, gestione
del PIPELINING, etc etc)
Dispensa di Informatica – I.6
Dispensa I.6 versione 1.0 mail: [email protected] Pagina 4 di 20
MODALITA’ DI INDIRIZZAMENTO
La macchina 8086 permette di lavorare allocando fino ad 1 MB di memoria Centrale (e dunque è
necessario un indirizzo di 20 bit), la macchina 80286 indirizza fino a 16 MB.
Essendo tali CPU dotate di registri da 16 bit l’indirizzamento avveniva utilizzando 2 registri (e
dunque è possibile avere indirizzi fino a 32 bit).
L’indirizzo è dunque distinto in due componenti:
• Selettore, che indicava un insieme di locazioni di memoria chiamate SEGMENTO
• Offset, che indicava all’interno del segmento, la POSIZIONE (o spostamento dalla prima
posizione)
Per ottenere l’indirizzo fisico dalla coppia segmento e posizione l’indirizzo fisico si calcola
Indirizzo fisico = segmento * 161 + posizione
Ad esempio l’indirizzo fisico referenziato dalla coppia 0A12:0032 è
0A12*F + 0032 = A120+0032 = A152
1 Moltiplicare per 16 in esadecimale significa aggiungere uno 0 a destra del numero.
Dispensa di Informatica – I.6
Dispensa I.6 versione 1.0 mail: [email protected] Pagina 5 di 20
REAL MODE / PROTECTED MODE
• In modalità reale l’indirizzo (segmento:posizione) individua un indirizzo fisico della
memoria centrale. Non vi è modo per un programma di limitare gli indirizzi a cui accedere.
• In modalità protetta a 16 bit invece viene introdotta la tecnica della memoria virtuale. I
segmenti sono spostai tra memoria centrale e disco all’occorrenza, tutto ciò in maniera
trasparente rispetto al programma.
Dunque ad ogni segmento è associata una tabella in cui sono indicate una serie di
informazioni(dove si trova il segmento, se è sul disco o nella memoria, permessi di accesso,
etc etc). L’indice della riga associata al segmento è contenuta nel SELETTORE.
Nella modalità protetta a 16 bit il segmento è monolitico (o si trova nella memoria o nel
disco)
• In modalità protetta a 32 bit, la posizione diviene un numero da 32 bit (e dunque i
segmenti passano da 64 kB (2 elevato alla 16) a 4.000.000 kB (2 elevato alla 32)
Nella modalità protetta a 32 bit il segmento NON è monolitico essendo divisibile in pagine
da 4 kB (potendo trovarsi in parte sul disco in parte in memoria centrale).
Dispensa di Informatica – I.6
Dispensa I.6 versione 1.0 mail: [email protected] Pagina 6 di 20
LA MEMORIA
La memoria è divisa in una serie di locazioni indirizzabili.
Ogni locazione indirizzabile può essere più o meno “capiente” in dipendenza della tecnologia
utilizzata.
Le meno recenti permettevano di contenere 1 Byte per locazione mentre adesso è possibile
immagazzinare fino a 16 byte per locazione; tale ampliamento è stato seguito di pari passo
dall’aumento del parallelismo del BUS di accesso.
Di seguito un esempio di memoria con capienza 1 Byte (1 B è 8 cifre binarie oppure 2 cifre HEX)
Sono dunque definite delle unità superiori al Byte
Dispensa di Informatica – I.6
Dispensa I.6 versione 1.0 mail: [email protected] Pagina 7 di 20
I REGISTRI
Oltre ai registri interni necessari al funzionamento del processore (vedi Dispensa I.3) non sempre
visibili al programmatore sono presenti altri Registri Visibili ed Utilizzabili dal programmatore.
Tali registri si distinguono in REGISTRI GENERALI e REGISTRI SPECIALI e possono essere utilizzati dal
programma per contenere dati da elaborare.
Registri generali sezionabili in 2 registri da 8 bit
Dispensa di Informatica – I.6
Dispensa I.6 versione 1.0 mail: [email protected] Pagina 8 di 20
Dispensa di Informatica – I.6
Dispensa I.6 versione 1.0 mail: [email protected] Pagina 9 di 20
CICLO DI SVILUPPO
Viene di seguito propposto il ciclo di sviluppo per la realizzazione di un programma (insieme di
istruzioni) da far eseguire su un elaboratore.
L’insieme di istruzioni viene digitato in un file di testo tramite un editor (file sorgente).
Viene di seguito elaborato da un programma di assemblaggio che – previa verifica sintattica – lo
“traduce” in un file oggetto che viene di seguito connesso a librerie esistenti (linked) e dunque
confezionato in un unico file eseguibile.
Dispensa di Informatica – I.6
Dispensa I.6 versione 1.0 mail: [email protected] Pagina 10 di 20
FORMATO DEL CODICE SORGENTE
Ogni linea di codice sorgente è costituita da 4 parti (o campi)
LABEL / OPCODE / OPERANDS /COMMENTS
LABEL è una stringa alfanumerica che definisce un nome simbolico per il corrispondente indirizzo.
OPCODE è un codice mnemonico o pseudo-operatore e determina la generazione di un’istruzione
in linguaggio macchina oppure la variazione del valore corrente del Program Counter
OPERANDS sono gli oggetti dell’azione specificata dall’OPCODE, e variano a seconda dell’OPCODE
e del modo di indirizzamento.
COMMENTS è un testo arbitrario inserito dal programmatore.
Ad esempio
POSIZIONE: ADD AX,4 ; sommo 4 al valore presente nel registro AX
La label POSIZIONE permetterà al programmatore di individuare l’istruzione negli altri punti del
programma e tornarci (ad es.) con una istruzione di salto
Dispensa di Informatica – I.6
Dispensa I.6 versione 1.0 mail: [email protected] Pagina 11 di 20
OPERANDI
Dipendentemente dal OPCODE il numero di operandi varia. Il tipo di operando può essere:
• REGISTRO: fa riferimento al contenuto di un registro
• MEMORIA: fa riferimento a dati in memoria
• IMMEDIATO: un valore costante espresso nella istruzione
• IMPLICITO: un valore deducibile dal OPCODE
Dispensa di Informatica – I.6
Dispensa I.6 versione 1.0 mail: [email protected] Pagina 12 di 20
ISTRUZIONE MOV
La sintassi corretta è
MOV destinazione , sorgente
I dati specificati in sorgente vengono spostati (copiati) in destinazione.
mov ax, 3A34 ; sposta il valore 3A34 nel registro ax
mov bx, ax ; sposta il valore contenuto nel registro ax nel registro bx
mov ax, [3A34] ;sposta il valore contenuto nella locazione di memoria referenziata
dall’indirizzo 3A34 (offset) nel registro ax
mov [3A34] , ax ;sposta nella locazione di memoria referenziata dall’indirizzo
3A34 (offset) nel registro ax
Dispensa di Informatica – I.6
Dispensa I.6 versione 1.0 mail: [email protected] Pagina 13 di 20
ISTRUZIONE ADD
La sintassi corretta è
ADD operando1 , operando2
Lo scopo della istruzione ADD è permettere la somma di interi (il risultato viene salvato in
operando1)
add ax, 3A34 ; somma il valore 3A34 al registro ax e salva il risultato in ax
add bx, ax ; somma il valore contenuto nel registro ax nel registro bx e salva il risultato in bx
add ax, [3A34] ; somma il valore contenuto nella locazione di memoria referenziata
dall’indirizzo 3A34 (offset) al registro ax e salva il risultato in ax
Dispensa di Informatica – I.6
Dispensa I.6 versione 1.0 mail: [email protected] Pagina 14 di 20
ISTRUZIONI INC E DEC
La sintassi corretta è
INC operando1
DEC operando1
Lo scopo della istruzione INC è incrementare di una unità il valore contenuto nel registro indicato
tramite operando1l
Lo scopo della istruzione DEC è incrementare di una unità il valore contenuto nel registro indicato
tramite operando1l
Dispensa di Informatica
Dispensa I.6 versione 1.0
DIRETTIVE
Le direttive non sono istruzioni bensì comandi dati al compilatore ASSEMBLER.
Usi comuni delle direttive sono:
definire costanti
definire memoria per memorizzare dati
raggruppare memorie in segmenti
etc etc
La direttiva EQU e DEFINE
ALTEZZA EQU 34
La label ALTEZZA assume il valore 34.
%define SIZE 100
La label SIZE assume il valore 100.
DIRETTIVE DATI
Le direttive D e RES servono per inizializzare riservare memoria.
Dispensa di Informatica – I.6
mail: [email protected]
direttive non sono istruzioni bensì comandi dati al compilatore ASSEMBLER.
definire memoria per memorizzare dati
raggruppare memorie in segmenti
ALTEZZA assume il valore 34.
La label SIZE assume il valore 100.
direttive D e RES servono per inizializzare riservare memoria.
Pagina 15 di 20
direttive non sono istruzioni bensì comandi dati al compilatore ASSEMBLER.
Dispensa di Informatica – I.6
Dispensa I.6 versione 1.0 mail: [email protected] Pagina 16 di 20
DIRETTIVA RES
La direttiva DES viene utilizzata dal programmatore per individuare un “pezzo” di memoria entro il
quale ha intenzione di conservarci un dato durante l’esecuzione del programma. D’ora in avanti
parleremo di VARIABILE come di una o più locazioni di memoria destinate a contenere un dato.
Il programmatore avrà l’onere di stabilire quando grande (quanti byte) dovrà contenere la
VARIABILE e questa informazione sarà essenziale al compilatore per definirne la grandezza.
Ad esempio supponiamo che il programmatore voglia individuare una variabile che conterrà un
carattere. Come sappiamo la memoria può contenere solo numeri binari, e dunque ad ogni
carattere viene associato un codice che può essere:
• ASCII (American Standard Code for Information Interchange) che individua fino a 256
diversi caratteri ( 2 elevato alla 8 quindi 1 BYTE)
• Unicode che estende a caratteri di tutte le lingue del mondo utilizzando 1 WORD (2 BYTE)
Supponendo che il programmatore scelga il codice UNICODE, allora dovrà comunicare al programma che la
variabile dovrà essere di 1 WORD.
pippo RESW 1 ;riserva 1 WORD e la indica con il nome pippo
pluto RESB 10; riserva 10 BYTE e la indica con pluto
Dispensa di Informatica – I.6
Dispensa I.6 versione 1.0 mail: [email protected] Pagina 17 di 20
In generale la direttiva RES può riservare BYTE, WORD, DOUBLE WORD, QUAD WORD, TEN BYTE utilizzando
le lettere B , W , D , Q , T
DIRETTIVA D
La direttiva D ha la medesima funzione di RES permettendo inoltre di inizializzare la variabile con
un valore prestabilito (che potrà poi comunque cambiare durante la esecuzione del programma).
Ad esempio
pippo db ‘c’,’i’,’a’,’o’,0 ;definisce una variabile di 5 byte (4 byte contengono le lettere ciao + 1 byte
che contiene uno 0 che fa da fine riga)
pippo db “ciao”,0 ;identico a quanto sopra descritto
Dispensa di Informatica – I.6
Dispensa I.6 versione 1.0 mail: [email protected] Pagina 18 di 20
INPUT ED OUTPUT
Le attività di input (leggi i dati da tastiere) ed Output (scrivi i dati a video) sono estremamente
complesse e – per quanto ci riguarda – utilizzeremo delle funzioni già esistenti che collegheremo ai
nostri programmi.
In tale maniera non solo possiamo concentrarci su quella parte di codice che ci interessa ma
iniziamo a comprendere una delle regole fondamentali dell’informatica :
“non si ricrea quello che già esiste, ma lo si utilizza”
In particolare utilizzeremo delle funzioni che andranno a leggere e scrivere sul registro EAX.
print_int stamperà a video il numero intero memorizzato nel registro EAX
print_char stamperà a video il carattere corrispondente al codice ASCII contenuto nel registro AL
print_string stamperà a video la stringa contenuta in memoria all’indirizzo memorizzato in EAX (la
stringa deve terminare con un null cioè 0)
print_nl stampa a video una nuova riga (cioè va “daccapo”)
read_int legge un numero intero dalla tastiera e lo memorizza nel registro EAX
read_char legge un carattere dalla tastiera e lo memorizza nel registro EAX
Come vedremo le funzioni sopra descritte saranno eseguite utilizzando l’istruzione CALL
Dispensa di Informatica – I.6
Dispensa I.6 versione 1.0 mail: [email protected] Pagina 19 di 20
RAPPRESENTAZIONE DEGLI INTERI
Come abbiamo visto le CPU sono passate da registri a 8 bit a registri a 16, poi 32 ed infine,
ultimamente a 64 bit.
Ciò nonostante nel tempo non sono state variate le grandezze (numero di byte) associati ad un
determinato tipo di dato2.
Un numero intero è storicamente associato a 2 BYTE (16 bit) e quindi può contenere fino a 65535
valori diversi (2 elevato alla 16).
Se vogliamo associare ad una stringa di bit un numero positivo allora possiamo sicuramente
utilizzare la notazione BINARIA a noi nota per rappresentarlo.
Ad esempio 152 diviene 10011000
Se dunque destiniamo 2 BYTE ad un numero intero sappiamo che possiamo rappresentare i
numeri compresi tra 0 e 65535 (216
- 1).
Ma se vogliamo rappresentare un numero negativo – non avendo a disposizione nessun altro
simbolo che non siano 0 ed 1 – dobbiamo sacrificare almeno un bit per rappresentare il segno.
La rappresentazione ATTUALMENTE utilizzata e il complemento a 2
Dato un numero binario si esegue il complemento ad 1 del numero (ogni 0 diviene 1 ed ogni uno
diviene 0) ed a questo viene poi sommato 1
Ad esempio 23 in binario diviene 00010111. Per rappresentare -23 dobbiamo
• prima eseguire il complemento ad 1 di 23 che dunque diviene 11101000
• sommarci 1 e dunque diviene 11101001
dunque da 00010111 si passa a 11101001.
2 Con l’arrivo delle architetture a 64 bit effettivamente sono state raddoppiate le quantità di BYTE associate ad alcuni
tipi di dato.
Dispensa di Informatica – I.6
Dispensa I.6 versione 1.0 mail: [email protected] Pagina 20 di 20
DECREMENTARE LA DIMENSIONE DI INTERI
Supponiamo di avere un intero insigned – cioè un intero che non può assumere valori negativi
rappresentato con 16 bit. Possiamo sicuramente pensare di rappresentarlo con meno bit (ad
esempio 8) se tutti i bit che non rappresentiamo sono 0.
Ad esempio 000000001111111 (255 in decimale) può essere rappresentato con 11111111 – e cioè
tronchiamo 8 0 più a sinistra – senza avere alcuna perdita di informazione.
Nel caso in cui invece abbiamo un numero rappresentato con complemento a 2 (quindi un numero
che può essere anche negativo) dobbiamo rispettare la seguente regola.
E’ possibile ridurre il numero di bit purchè
• tutti i bit eliminati siano dello stesso valore.
• il primo bit non rimosso sia dello stesso valore di quelli rimossi.
Ad esempio 1111111111101001 (- 23 rappresentato a 16 bit) può essere ridotto a 11101001
essendo eliminati TUTTI 1 ed essendo il bit più significativo (il primo non rimosso) ancora 1.