Upload
ferdinando-longhi
View
214
Download
0
Embed Size (px)
Citation preview
1 M. Rebaudengo, M. Sonza Reorda
Politecnico di TorinoDip. di Automatica e Informatica
M. Rebaudengo - M. Sonza Reorda
L’Assembler 8086Programmazione Avanzata
2 M. Rebaudengo, M. Sonza Reorda
Sommario
• Procedure Assembler richiamabili da un programma C
• Recursione
3 M. Rebaudengo, M. Sonza Reorda
Procedure Assemblerrichiamabili da un
programma C
Sorgente C
SorgenteAssembler
Compilatore
Assemblatore
Oggetto
Oggetto
Linker Eseguibile
4 M. Rebaudengo, M. Sonza Reorda
Dichiarazionedella procedura
chiamataAl fine di poter linkare una procedura Assembler con un programma chiamante C occorre che ci sia compatibilità tra i segmenti usati.
È necessario utilizzare lo stesso modello di memoria sia per il modulo C che per il modulo Assembler: la procedura Assembler va dichiarata NEAR per modelli tiny, small e compact, mentre va dichiarata FAR per modelli medium, large o huge.
5 M. Rebaudengo, M. Sonza Reorda
Dichiarazionedella procedura
chiamata(segue)Il nome della procedura Assembler deve essere reso
pubblico tramite una dichiarazione PUBLIC, così come il nome di ogni altra variabile che si vuole rendere accessibile dall’esterno.
I nomi di tutte le variabili e procedure definite esternamente al modulo Assembler e da esso utilizzate vanno dichiarate esterne attraverso la direttiva EXTRN.
6 M. Rebaudengo, M. Sonza Reorda
Convenzione per i nomiIl compilatore altera il nome degli identificatori prima di
memorizzarli nel file oggetto.
Tutti i nomi delle entità comuni ai moduli C ed a quello Assembler devono tener conto del fatto che il compilatore C premette sempre, nella costruzione della symbol table, un carattere ‘_’.
Il nome della procedura Assembler deve iniziare con tale carattere, così come quello di tutte le variabili pubbliche utilizzabili dal modulo C.
7 M. Rebaudengo, M. Sonza Reorda
Convenzioni per i nomi(segue)Utilizzando l’opzione di linguaggio nella direttiva .MODEL,
l’assemblatore aggiunge il carattere _ davanti a tutti gli identificatori del modulo Assembler.
8 M. Rebaudengo, M. Sonza Reorda
Convenzioni per i nomi(segue)Il linguaggio C è case sensitive; per fare in modo di
preservare il case degli identificatori è necessario compilare i moduli Assembler con l’opzione /Cp e linkare i vari moduli con l’opzione /NOI.
9 M. Rebaudengo, M. Sonza Reorda
Compatibilità del tipo di dato
Il linguaggio C presenta una molteplicità di tipi di dato, mentre il linguaggio Assembler presenta un numero ristretto di possibili tipi di dato:
C MASM
char BYTE
short, int WORD
long, float DWORD
double QWORD
long double TBYTE
10 M. Rebaudengo, M. Sonza Reorda
Compatibilità del tipo di dato(segue)I puntatori in C specificano indirizzi di variabili o di funzioni. In
base al modello di memoria utilizzato un puntatore occupa una word (puntatore di tipo NEAR) oppure una doubleword (puntatore di tipo FAR).
modello punt. a funzione punt. a dato
tiny WORD WORD
small WORD WORD
medium DWORD WORD
compact WORD DWORD
large DWORDDWORD
huge DWORD DWORD
11 M. Rebaudengo, M. Sonza Reorda
Convenzionesu parametri in
ingressoIl codice generato dal compilatore C passa i parametri alle procedure mettendoli nello stack in ordine inverso rispetto a quello in cui appaiono nella chiamata.
Ai parametri si può fare accesso attraverso il registro BP. Le prime istruzioni da eseguire all’interno della procedura Assembler sono le seguenti:
PUSH BP
MOV BP, SP
12 M. Rebaudengo, M. Sonza Reorda
Variabili locali
All’interno della procedura può essere allocato spazio per eventuali variabili locali, così come accade nei linguaggi di alto livello.
Per fare questo è necessario riservare un’area dello stack utilizzabile per la memorizzazione di variabili locali. Tale operazione può essere fatta o con un numero opportuno di istruzioni PUSH, oppure decrementando il contenuto di SP attraverso un’istruzione SUB.
13 M. Rebaudengo, M. Sonza Reorda
Salvataggio dei registri
Il compilatore C della Microsoft richiede che eventuali procedure chiamate da un programma C non modifichino i valori contenuti nei registri SI, DI, SS, DS e BP.
Nel caso in cui tali registri debbano essere utilizzati, devono essere opportunamente salvati nello stack e poi ripristinati al termine.
14 M. Rebaudengo, M. Sonza Reorda
Frame
Indirizzo di ritorno
Parametro n
. . .
Parametro 1
Registro BP
Area locale di dati
Registri salvati
. . .
BP
SS
SP
15 M. Rebaudengo, M. Sonza Reorda
Convenzionisui parametri di
uscitaIl parametro eventualmente ritornato dalla procedura Assembler è atteso dal chiamante nel registro accumulatore.
Se il tipo del dato di ritorno è un char il parametro è passato attraverso il registro AL; se il tipo è un int od un indirizzo di tipo NEAR il registro utilizzato è AX; se il tipo è un long od un indirizzo di tipo FAR il parametro di ritorno è copiato nella coppia di registri DX, AX.
16 M. Rebaudengo, M. Sonza Reorda
Uscita dalla procedura
Le operazioni da effettuare a conclusione della procedura sono:
• ripristinare i valori dei registri eventualmente salvati all’inizio;
• liberare l’area locale di dati incrementando opportunamente il contenuto del registro SP;
• eseguire l’istruzione RET.
17 M. Rebaudengo, M. Sonza Reorda
Procedura C chiamante
Il nome della procedura chiamata e tutte le variabili globali definite nel modulo Assembler devono essere dichiarate come extern all’interno della procedura C.
È compito del programma chiamante C svuotare lo stack dello spazio destinato ai parametri di ingresso. Tale operazione è effettuata dal compilatore C in maniera automatica.
18 M. Rebaudengo, M. Sonza Reorda
EsercizioCalcolo di un’espressione aritmetica.
Si vuole scrivere una procedura Assembler di nome power2 richiamabile da un programma scritto in linguaggio C per il calcolo dell’espressione X*2Y.
Alla procedura power2 vengono passati i due parametri interi X e Y; la funzione restituisce nel registro AX il risultato dell’espressione. Si supponga che il programma chiamante sia compilato usando il modello di memoria small.
19 M. Rebaudengo, M. Sonza Reorda
Programma C chiamante
#include <stdio.h>
extern int power2 (int factor, int power);
void main()
{
printf(”3 volte 2 elevato 5=%d\n”, power2(3,5));
}
20 M. Rebaudengo, M. Sonza Reorda
Procedura AssemblerPUBLIC _power2
.MODEL small
.CODE
_power2 PROC
PUSH BP
MOV BP, SP
MOV AX, [BP+4] ; primo parametro
MOV CX, [BP+6] ; secondo parametro
SHL AX, CL
POP BP
RET
_power2 ENDP
END
21 M. Rebaudengo, M. Sonza Reorda
Esercizio
Si vuole eseguire una procedura Assembler di nome invert richiamabile da un programma scritto in linguaggio C per l’inversione del contenuto di una stringa: al termine dell’esecuzione, gli elementi del vettore devono essere memorizzati nell’ordine inverso rispetto a quello iniziale.
22 M. Rebaudengo, M. Sonza Reorda
Programma C chiamante
#include <stdio.h>
extern char *invert (char * str);
void main()
{
char *s;
s = strdup(”Salve Mondo !”);
printf(”%s\n”, invert(s));
}
23 M. Rebaudengo, M. Sonza Reorda
Procedura AssemblerPUBLIC _invert
.MODEL small
.CODE
_invert PROC
PUSH BP
MOV BP, SP
PUSH SI
PUSH DI
MOV AX, DS
MOV ES, AX
MOV DI, WORD PTR [BP+4]
MOV SI, DI
XOR AX, AX
24 M. Rebaudengo, M. Sonza Reorda
MOV CX, 0FFFFH
REPNE SCASB
SUB DI, 2
NOT CX
DEC CX
SHR CX, 1
ciclo: MOV AH, [SI]
XCHG AH, [DI]
MOV [SI], AH
INC SI
DEC DI
LOOP ciclo
25 M. Rebaudengo, M. Sonza Reorda
MOV AX, WORD PTR [BP+4] POP DI
POP SI
POP BP
RET
_invert ENDP
END
26 M. Rebaudengo, M. Sonza Reorda
La recursione
L’Assembler permette la recursione, che deve però essere gestita dal programmatore stesso.
Nulla vieta che una procedura richiami se stessa: in tal caso l’indirizzo di ritorno messo nello stack è quello della procedura stessa e nello stack si accumuleranno tanti di questi indirizzi quante sono le chiamate recursive.
27 M. Rebaudengo, M. Sonza Reorda
Esempio I: Fact
Si realizzi una procedura di nome FACT che legge un numero nel registro BX e ne calcola il fattoriale, scrivendo il risultato nel registro AX.
La versione C della stessa procedura è:
int fact ( int x)
{ if( x == 1)
return( 1);
return( x * fact( x-1));
}
28 M. Rebaudengo, M. Sonza Reorda
Procedura recursivaFACT PROC NEAR
PUSH BXCMP BX, 1JE returnDEC BXCALL FACTINC BXMUL BXJMP fine
return: MOV AX, 1XOR DX, DX
fine: POP BXRET
FACT ENDPEND
29 M. Rebaudengo, M. Sonza Reorda
Esempio II: Split
Si vuole scrivere un programma in grado di espandere (splitting) stringhe di bit contenenti 0, 1 e X, producendo tutte le possibili stringhe ottenibili da quella data, tramite la sostituzione di ciascuna X con un 1 o uno 0.
Esempio
0x11x0 001100
001110
011100
011110
30 M. Rebaudengo, M. Sonza Reorda
Soluzione C
void split(void){ if (curr_index==len) { printf("%s\n", obuff); return;
} else switch (ibuff[curr_index]) { case '0': obuff[curr_index++] = '0'; split(); break; case '1': obuff[curr_index++] = '1'; split(); break;
31 M. Rebaudengo, M. Sonza Reorda
case 'X': obuff[curr_index++] = '0'; split(); obuff[curr_index-1] = '1'; split(); break; } return;}
32 M. Rebaudengo, M. Sonza Reorda
Soluzione Assembler
.MODEL smallLF EQU 10CR EQU 13DIM EQU 30 ; dimensione massima della
; stringa da espandere.DATA
OBUFF DB DIM DUP ('0')IBUFF DB DIM DUP ('0')LEN DW 0ERR_MESS DB 'Carattere non ammesso$'
33 M. Rebaudengo, M. Sonza Reorda
.CODE
.STARTUPMOV CX, DIM ; lettura stringa di input
MOV SI, 0 MOV AH, 1lab1: INT 21H MOV IBUFF[SI], AL INC SI CMP AL, CR LOOPNE lab1 DEC SI MOV LEN, SI
XOR BX, BX CALL SPLIT
.EXIT
34 M. Rebaudengo, M. Sonza Reorda
SPLIT PROCPUSH AX
PUSH DX PUSH SI
CMP BX, LEN ; stringa vuota ? JNE ancora
MOV CX, LEN ; Sì: visualizza MOV AH, 2 XOR SI, SIlab2: MOV DL, OBUFF[SI] INT 21H INC SI LOOP lab2 MOV DL, CR INT 21H MOV DL, LF INT 21H JMP fine
35 M. Rebaudengo, M. Sonza Reorda
ancora: MOV DL, IBUFF[BX] ; No,;considera il primo carattere
CMP DL, '0' JNE not_z
MOV OBUFF[BX], '0' ; '0' INC BX CALL SPLIT DEC BX JMP finenot_z: CMP DL, '1' ; '1' JNE not_one
MOV OBUFF[BX], '1' INC BX CALL SPLIT DEC BX JMP fine
36 M. Rebaudengo, M. Sonza Reorda
not_one: CMP DL, 'X' ; 'X' JNE error
MOV OBUFF[BX], '0' ; trasforma la X in 0
INC BX CALL SPLIT DEC BX MOV OBUFF[BX], '1'
; trasforma la X in 1 INC BX CALL SPLIT DEC BX JMP fine
37 M. Rebaudengo, M. Sonza Reorda
error: MOV AH, 9 ; carattere diverso da 0, 1 e X
LEA DX, ERR_MESS INT 21Hfine: POP SI POP DX POP AX
RETSPLIT ENDP END