Sistemi - Classe Terza robertomana.it Cenni di Assembler pag 1 Assembly 8086 - Introduzione Rev. Digitale 1.0 del 01/09/2016 E‟ un linguaggio mnemonico in corrispondenza 1 : 1 con le istruzioni binarie riconosciute dalla CPU 8086. Cioè codifica con un nome mnemonico tutte le possibili istruzioni binarie riconosciute dalla CPU. Assemblatore Un particolare programma, detto assemblatore (assembler), traduce il file testuale assembly in linguaggio macchina, producendo un file binario che contiene il codice binario corrispondente al programma tradotto. L‟assemblatore, oltre al file OBJ, produce in genere anche un interessante file LST contenente l‟informazione binaria espressa in formato esadecimale con a fianco l‟istruzione testuale assembly. Linker Molto spesso una applicazione è costituita da più file sorgenti, ognuno dei quali contiene specifiche procedure, scritte spesso da persone diverse all‟interno di un team di lavoro. Uno di questi file può far riferimento a funzioni o simboli definiti all‟interno di un altro file. L‟assemblatore, che traduce ogni singolo file in binario, deve prevedere un meccanismo che consenta di gestire queste situazioni senza generare errori. A tal fine l‟assembly prevede l‟utilizzo di pseudoistruzioni che avvisano l‟assemblatore su simboli e procedure che si trovano in altri file. In corrispondenza di queste pseudoistruzioni, l‟assemblatore crea delle „note‟ all‟interno del file binario, che dunque non è più un file eseguibile, ma un file detto file oggetto, sempre binario, ma contenente delle note che verranno interpretato da un programma detto linker , che provvede ad integrare i vari file oggetto in un unico eseguibile risolvendo tutte le varie situazioni lasciate in sospeso dall‟assemblatore. Loader In realtà il codice macchina generato dal linker è un codice rilocabile , cioè che potrà essere caricato in memoria centrale a partire da un qualunque indirizzo. Ciò è possibile mediante l‟utilizzo dei Segment Register il cui contenuto viene assegnato dal loader durante il caricamento in memoria dell‟applicazione. Il loader è un componente del sistema operativo che viene automaticamente richiamato nel momento in cui l‟utente digita sulla riga di comando il nome di un file eseguibile (o fa doppio click sulla sua icona). Il loader provvede a trasferire il codice dell‟eseguibile all‟interno della memoria centrale, provvedendo ad assegnare un valore ai vari segmenti definiti dal linker. Caratteristiche di MASM 6.0 (Macro Assembler) Ogni riga deve essere terminata con un INVIO (ASCII 10). Uno statement può occupare più righe. La precedente deve terminare con \. La seguente deve iniziare con & E‟ case unsensitive: si può scrivere indifferentemente in minuscolo o maiuscolo Normalmente si usa il minuscolo, riservando il maiuscolo per PSEUDOISTRUZIONI e COSTANTI I commenti sono introdotti dal punto virgola Gli identificatori hanno lunghezza massima 31 chr (senza spazi) e devono iniziare con una lettera. Sono ammessi i seguenti 4 caratteri speciali _ ? @ $ Principali Direttive Assembly (Pseudoistruzioni) Non corrispondono ad una precisa istruzione binaria di codice, ma sono direttive che consentono di : Definire dimensioni e tipologia dei vari segmenti (l‟unico ad essere dimensionato automaticamente è il Code Segment). Queste informazioni vengono salvate dal linker all‟interno dell‟header del programma exe secondo un preciso formato che è quello utilizzato dal loader del SO per caricare il programmi. Assegnare un nome alle celle di memoria del Data Segment. In questo modo quando il programma dovrà accedere ad una cella di memoria potrà accedere molto più comodamente attraverso il nome piuttosto che attraverso l‟indirizzo. Assegnare un nome (etichetta) a particolari righe di codice, in modo che quando il programma dovrà eseguire un salto a quella riga potrà utilizzare l‟etichetta anziché l‟indirizzo.
19
Embed
Assembly 8086 - Introduzionerobertomana.altervista.org/wp-content/uploads/2016/08/Cenni-di-Assembler.pdfSistemi - Classe Terza robertomana.it Cenni di Assembler pag 1 Assembly 8086
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Sistemi - Classe Terza robertomana.it
Cenni di Assembler
pag 1
Assembly 8086 - Introduzione Rev. Digitale 1.0 del 01/09/2016
E‟ un linguaggio mnemonico in corrispondenza 1 : 1 con le istruzioni binarie riconosciute dalla CPU 8086. Cioè
codifica con un nome mnemonico tutte le possibili istruzioni binarie riconosciute dalla CPU.
Assemblatore
Un particolare programma, detto assemblatore (assembler), traduce il file testuale assembly in linguaggio macchina,
producendo un file binario che contiene il codice binario corrispondente al programma tradotto. L‟assemblatore, oltre
al file OBJ, produce in genere anche un interessante file LST contenente l‟informazione binaria espressa in formato
esadecimale con a fianco l‟istruzione testuale assembly.
Linker
Molto spesso una applicazione è costituita da più file sorgenti, ognuno dei quali contiene specifiche procedure, scritte
spesso da persone diverse all‟interno di un team di lavoro. Uno di questi file può far riferimento a funzioni o simboli
definiti all‟interno di un altro file. L‟assemblatore, che traduce ogni singolo file in binario, deve prevedere un
meccanismo che consenta di gestire queste situazioni senza generare errori. A tal fine l‟assembly prevede l‟utilizzo di
pseudoistruzioni che avvisano l‟assemblatore su simboli e procedure che si trovano in altri file. In corrispondenza di
queste pseudoistruzioni, l‟assemblatore crea delle „note‟ all‟interno del file binario, che dunque non è più un file
eseguibile, ma un file detto file oggetto, sempre binario, ma contenente delle note che verranno interpretato da un
programma detto linker, che provvede ad integrare i vari file oggetto in un unico eseguibile risolvendo tutte le varie
situazioni lasciate in sospeso dall‟assemblatore.
Loader
In realtà il codice macchina generato dal linker è un codice rilocabile, cioè che potrà essere caricato in memoria
centrale a partire da un qualunque indirizzo. Ciò è possibile mediante l‟utilizzo dei Segment Register il cui contenuto
viene assegnato dal loader durante il caricamento in memoria dell‟applicazione. Il loader è un componente del
sistema operativo che viene automaticamente richiamato nel momento in cui l‟utente digita sulla riga di comando il
nome di un file eseguibile (o fa doppio click sulla sua icona). Il loader provvede a trasferire il codice dell‟eseguibile
all‟interno della memoria centrale, provvedendo ad assegnare un valore ai vari segmenti definiti dal linker.
Caratteristiche di MASM 6.0 (Macro Assembler)
Ogni riga deve essere terminata con un INVIO (ASCII 10).
Uno statement può occupare più righe. La precedente deve terminare con \. La seguente deve iniziare con &
E‟ case unsensitive: si può scrivere indifferentemente in minuscolo o maiuscolo
Normalmente si usa il minuscolo, riservando il maiuscolo per PSEUDOISTRUZIONI e COSTANTI
I commenti sono introdotti dal punto virgola
Gli identificatori hanno lunghezza massima 31 chr (senza spazi) e devono iniziare con una lettera.
Sono ammessi i seguenti 4 caratteri speciali _ ? @ $
Principali Direttive Assembly (Pseudoistruzioni)
Non corrispondono ad una precisa istruzione binaria di codice, ma sono direttive che consentono di :
Definire dimensioni e tipologia dei vari segmenti (l‟unico ad essere dimensionato automaticamente è il Code
Segment). Queste informazioni vengono salvate dal linker all‟interno dell‟header del programma exe
secondo un preciso formato che è quello utilizzato dal loader del SO per caricare il programmi.
Assegnare un nome alle celle di memoria del Data Segment. In questo modo quando il programma dovrà
accedere ad una cella di memoria potrà accedere molto più comodamente attraverso il nome piuttosto che
attraverso l‟indirizzo.
Assegnare un nome (etichetta) a particolari righe di codice, in modo che quando il programma dovrà eseguire
un salto a quella riga potrà utilizzare l‟etichetta anziché l‟indirizzo.
Sistemi - Classe Terza robertomana.it
Cenni di Assembler
pag 2
Title
La direttiva TITLE consente di assegnare un titolo descrittivo al programma assembly. TITLE *** Calcolo di Area e Perimetro di un Rettangolo ***
Costanti
Subito dopo il titolo si possono definire, mediante la direttiva EQU delle costanti, cioè assegnare una etichetta
identificativa ad un valore, in modo da aumentare la leggibilità del programma.
Le costanti possono essere :
Decimali: 13, 13D
Binarie 00001111B
Esadecimali 72H, 0DH, 0A1H
devono iniziare con un numero. Se iniziano con una lettera occorre premettere uno zero 0A1H
Floating Point 2.345, 715E-3
Stringhe ASCII „CIAO‟, „2‟ ; lunghe uno o più caratteri. Apice Singolo e Apice Doppio sono indifferenti
Esempi: COLUMNS EQU 80
ROWS EQU 25
E‟ possibile anche creare degli alias, cioè simboli che rappresentano con altri nomi simboli già definiti in precedenza.
COLONNE EQU COLUMNS
RIGHE EQU ROWS
SCREEN EQU COLONNE * RIGHE
In alternativa ad EQU per definire delle costanti è anche possibile utilizzare l‟operatore di assegnazione = .
Direttive di Segmento
I programmi Assembly sono costituiti tipicamente da 3 segmenti: CODICE, DATI e STACK.
Per definire un segmento occorre utilizzare la seguente direttiva:
nomeSeg SEGMENT contenuto del segmento
nomeSeg ENDS
Definizione di variabili
All‟interno del Data Segmenti si possono “definire” delle celle di memoria, assegnando loro una etichetta
identificativa ed un valore. L‟etichetta potrà poi essere utilizzata dal programma per accedere alle celle medesime.
Dopo l‟etichetta i due punti di suddivisione dell‟etichetta dalla parte successiva non sono in questo caso accettati.
db definisce un byte
num1 db 60
num2 db ? ; definisce un byte senza assegnare nessun valore iniziale
num3 db 00001110b
Può essere anche utilizzata per memorizzare uno o più caratteri ASCII
var1 db „A‟, „B‟, „C‟ ; definisce tre byte contenenti i codici ASCII dei caratteri indicati
var2 db “ABC” ; equivalente alla precedente
Sistemi - Classe Terza robertomana.it
Cenni di Assembler
pag 3
dw definisce una word (2 bytes)
num1 dw 260
num2 dw ? ; definisce una word senza assegnare nessun valore iniziale
num3 dw AAFFH
Nota: dw non può essere utilizzata per memorizzare una sequenza di caratteri ASCII, ma solo per uno o due caratteri chr dw „A‟ ; viene memorizzato 0 nel byte alto e 65 nel byte basso
chr dw “AB” ; viene memorizzato 65 nel byte alto e 66 nel byte basso
Vettori
Per i nomi dei vettori è consigliato anteporre l‟underscore davanti.
_vect db 1,2,3,4,5,6,7,8,9,0 ;definisce un vettore di 10 bytes inizializzandolo con i valori indicati
_vect dw 1200, 2400, 3600 ;definisce un vettore di 3 word
_vect db 10 dup (0) ;definisce un vettore di 10 bytes tutti con valore 0
_vect dw 10 dup (?) ;definisce un vettore di 10 word non inizializzate
Nota: Per visualizzare il contenuto di una variabile NUM1 su code view utilizzare il comando W NUM1
Per visualizzare invece un vettore _vett lungo 10 su code view utilizzare il comando W _vett L A
Nota: dw può anche essere utilizzata per memorizzare un offset:
lista DB 100 DUP (?) ; 100 celle non inizializzate
listaOffset DW lista ; offset di lista
dd definisce una double word (4 bytes)
num1 dd 125000 ; maggiore di 65000
num2 dd 13.76 ; floating point
dq definisce una quad word (8 bytes). Numeri Double. Non prevista nelle versioni base di Assembly 8086
Nota: dd può anche essere utilizzata per memorizzare un indirizzo completo (segmento + offset) :
lista DB 100 DUP (?) ; 100 celle non inizializzate
listaOffset DD lista ; i due bytes alti contengono il segmento, i due byte bassi contengono l’offset
La direttiva END
Terminata la dichiarazione di tutti i segmenti, la direttiva END termina il modulo di compilazione. Il suo scopo è
quello di poter specificare una etichetta per indicare il punto di partenza del programma (entry point) .
In caso di unico segmento di codice, l‟entry point può essere omesso, nel qual caso il programma partirà dalla 1°
istruzione dell‟unico segmento di codice. Il loader provvede automaticamente a caricare CS e inizializzare PC a 0
In caso di più segmenti di codice, l‟entry point deve essere necessariamente specificato ed il loader caricherà
automaticamente all‟interno di CS l‟indirizzo di partenza del segmento contenente l‟entry point e dentro PC l‟offset
dell‟Entry Point rispetto all‟inizio del segmento. Esempio: END main
Etichette relative alle istruzioni
Davanti alle istruzioni si può aggiungere una etichetta alfanumerica (con primo carattere una lettera) che rappresenta
l‟indirizzo simbolico dell‟istruzione. I due punti devono separare l‟etichetta dall‟istruzione. Queste etichette sono
utilizzate principalmente per gestire le istruzioni di salto:
RIT: mov AX, 0
. . . . . . . . . . . . .
jmp RIT
Sistemi - Classe Terza robertomana.it
Cenni di Assembler
pag 4
Modello di un programma Assembly
.model small ; un solo segmento di codice ed un solo segmento di dati
.stack ; definisce uno stack segment di nome @stack grande 1024 bytes
; stack ends
.data ; definisce un data segment di nome @data
num1 dw 61
num2 dw 4
ris dw ?
; data ends
.code ; definisce un code segment di nome @code
; CS ed SS sono inizializzati automaticamente ai rispettivi segmenti
; DS non viene caricato in automatico in quanto possono esistere più dichiarazioni di DATA
SEGMENT all‟interno di file differenti. Queste dichiarazioni, nell‟ambito del MODEL
SMALL, verranno poi combinate in un unico segmento in un ordine che solo il linker conosce mov ax, @data
mov ds, ax
mov ax,num1 ; AX <- DS:NUM1
add ax,num2
mov ris, ax
mov ah, 4ch ; ritorno al DOS
int 21h
; code ends
end
Modelli di mappatura dei segmenti : La pseudoistruzione .MODEL
Consente di definire il modello di memoria che dovrà essere utilizzato nella compilazione del file. Modelli possibili:
Code Seg Data Seg Data e Code Combinati TINY Near Near Sì
SMALL Near Near No
MEDIUM Far Near No
COMPACT Near Far No
LARGE Far Far No
Dichiarare i segmenti di codice di tipo NEAR significa che tutti i segmenti di codice appartenenti ai vari moduli
verranno mappati su uno stesso segmento fisico di codice. Ciò implica che tutte le procedure e tutte le etichette
di salto saranno indirizzate come NEAR, cioè indirizzate utilizzando soltanto offset a 16 bit. Dichiarare invece i
segmenti di codice di tipo FAR significa che ogni segmento (eventualmente anche per segmenti appartenenti ad uno
stesso modulo) verrà mappato su un segmento di codice fisico diverso. Ciò implica che tutte le procedure e tutte le
etichette saranno indirizzate come FAR, cioè indirizzate utilizzando segmento + offset.
Dichiarare i data segment come NEAR significa che variabili sono indirizzate come NEAR, cioè soltanto mediante
un offset a 16 bit, mentre FAR significa che saranno tutte indirizzate mediante segmento + offset, cioè posso
indirizzare direttamente una variabile non contenuta nei segmenti attivi: MOV AX, FAR PTR _DATA2:NUM1
Nel modello TINY codice e dati vengono mappati in uno stesso segmento (vecchi file .COM più compatti degli
EXE). Il modello SMALL (utilizzato di default) prevede un unico segmento di codice con dim max 64 K e
l‟accesso soltanto ai dati memorizzati nei due data segment attivi . Per le applicazioni più grandi si utilizza il
modello LARGE che può gestire più segmenti di codice e più segmenti di dati paralleli.
Nei sistemi IA32 (che operano in modalità protetta), si utilizza un nuovo tipo di modello che è il modello FLAT.
Sistemi - Classe Terza robertomana.it
Cenni di Assembler
pag 5
Formato ed avvio di un programma eseguibile
Nel momento in cui il linker provvede a creare il file eseguibile, provvede anche a generare all‟inizio del file stesso
una testata lunga 512 bytes contenente le informazioni necessarie al caricamento del programma in memoria, cioè
sostanzialmente un elenco dei segmenti definiti all‟interno del programma stesso, ciascuno con il proprio indirizzo
virtuale di partenza (partendo da 0) e lunghezza espressa in byte.
Il linker, a richiesta, può generare un file .MAP contenente le informazioni che verranno salvate in testa all‟eseguibile
Start Stop Length Type (Name)
00000H 00003H 00004H DATA @DATA
00010H 0008FH 00080H STACK @STACK
00090H 000BCH 0002DH CODE @CODE
Program entry point at 0009:0000
Il Name è un identificativo mostrato all‟interno del file .MAP. In fase di avvio del programma, il loader provvede ad
allocare in memoria i segmenti necessari, assegnando ai vari segmenti un ben preciso indirizzo fisico.
Inoltre provvede automaticamente a:
inizializzare il registro CS al punto di partenza del segmento di codice contenente l‟Entry Point del programma
inizializzare il registro SS al registro unico di stack dichiarato con l‟opzione di classe „STACK‟
Riservare, al di sopra del segmento di codice, un‟area di 256 bytes (100H) detta PSP (Program Segment
Prefix, cioè Prefisso del Segmento di Programma) utilizzato dal DOS per memorizzare le informazioni
necessarie a ritrasferire il controllo al Sistema Operativo una volta terminata l‟esecuzione del programma.
L‟istruzione finale INT21H (4CH) esegue sostanzialmente un salto all‟indirizzo _CODE – 100H. DS ed ES
vengono entrambi utilizzati per scrivere quest‟area per cui, al termine del caricamento punteranno entrambi a
_CODE – 100H e dovranno essere inizializzati manualmente dal programma andando a scrivere al loro interno
l‟indirizzo effettivo di partenza del Data Segment.
L’istruzione MOVE e le modalità di Indirizzamento
MOV Dest, Source
E‟ l‟istruzione principale del linguaggio Assembly e consente di spostare dati tra una sorgente ed una destinazione,
dove sorgente e destinazione possono essere i registri della CPU o le celle di memoria. Il codice binario è il seguente:
100010dw (in esadecimale 88 o 89 o 8A o 8B) dove:
il bit w indica se deve essere trasferito un byte (w=0) oppure, più frequentemente, una word (w=1)
il bit d indica la direzione del trasferimento. d = 1 significa from MFIELD to REGister e viceversa
Modalità di Indirizzamento
Le modalità fondamentali sono 5 :
(1) Registro – Registro
(2) Indirizzamento diretto
(3) Indirizzamento indiretto
(4) Indirizzamento indiretto con displacement
(5) Indirizzamento immediato (in un registro o in memoria)
Insieme all‟istruzione MOV c‟è sempre un secondo byte che indica quale tipo di indirizzamento utilizzare e quali
sono i registri coinvolti. Il secondo byte è strutturato nel modo seguente:
MM RRR FFF dove i tre gruppi di bit sono indicati rispettivamente come MOD REG MFIELD
MOD(2 bit) indicano la modalità di trasferimento da adottare fra le prime 4 modalità precedenti
REG (Register su 3 bit ) indicano il registro coinvolto nel trasferimento (8 registri possibili)
MFIELD (Memory Field su 3 bit) indicano il registro o cella di memoria coinvolti nel trasferimento.
Sistemi - Classe Terza robertomana.it
Cenni di Assembler
pag 6
Il significato di MFIELD dipende dalla modalità di trasferimento adottata.
Il campo REG ha sempre il seguente significato :
REG W=0 W=1
000 AL AX
001 CL CX
010 DL DX
011 BL BX
100 AH SP
101 CH BP
110 DH SI
111 BH DI
(1) Modalità di trasferimento Registro – Registro (MOD = 11 )
In questo caso MFIELD utilizza la stesa codifica di REG, e contiene il codice del secondo registro coinvolto
nell‟operazione. Nella modalità REGISTER – REGISTER il bit d è sempre 1, cioè :
MFIELD rappresenta sempre il registro sorgente, mentre REG rappresenta sempre il registro destinatario.
mov CX, BX ; d = 1, w = 1, REG = 001, MFIELD = 011 8B CB
mov CL, BL ; d = 1, w = 0, REG = 001, MFIELD = 011 8A CB
mov CH, CL ; d = 1, w = 0, REG = 101, MFIELD = 001 8A E9
(2) Modalità di trasferimento diretto da memoria a registro e viceversa (MOD = 00 e MFIELD = 110)
Il campo MFILED assume il valore fisso 110.
Il campo REG indica il registro destinatario (d=1) oppure il registro sorgente (d=0).
num1 db 60
num2 dw 600
mov DH, num1 ; d = 1, w = 0, REG = 110, MFIELD = 110 + offset 2 bytes
mov num1, DH ; d = 0, w = 0, REG = 110, MFIELD = 110 + offset 2 bytes
mov DX, [num2] ; d = 1, w = 1, REG = 010, MFIELD = 110 + offset 2 bytes