Programmazione Assembly Note su Microsoft Assembler Giacomo Fiumara [email protected] Anno Accademico 2012-2013 1 / 254 Microsoft Assembler Masm32.com installare configurare path perchè contenga la directory bin di Masm32 2 / 254 Microsoft Assembler Strumenti Editor di testo (anche Notepad) emulatore DOS Assemblatore (ml) Link a 16 bit (link16) 3 / 254 Microsoft Assembler Documentazione Documentazione Intel Debugger K. R. Irvine, Assembly language for Intel-based computers, 4th or 5th edition J. T. Streib, Guide to Assembly Language, Springer L. B. Das, The x86 Microprocessors, Pearson 4 / 254 Codice Assembly embedded in programmi C Uno degli elementi di maggiore difficoltà della programmazione Assembly è rappresentata dalla gestione dell’I/O Per evitare queste difficoltà, nei primi tempi, è possibile effettuare l’embedding di porzioni di codice Assembly in programmi C La compilazione deve essere effettuata tenendo conto della presenza di codice Assembly Per esempio, nel caso di un compilatore gcc (consigliato), il comando di compilazione è: gcc -fasm-blocks nome_programma.c -o nome_programma.x 5 / 254 Codice Assembly embedded in programmi C /2 Si consideri il seguente codice C: #include stdio.h int main() { int num1, num2; num1 = 5; num2 = num1; printf("%s%d\n", "Valore di num2: ", num2); return 0; } 6 / 254 Codice Assembly embedded in programmi C /3 Si modifica come segue: #include stdio.h int main() { int num1, num2; num1 = 5; __asm{ mov eax, num1 mov num2, eax } printf("%s%d\n", "Valore di num2: ", num2); return 0; } 7 / 254 Registri Introduzione Una delle cose più importanti di un processore è l’insieme dei registri Quelli accessibili al programmatore sono detti general purpose Nel caso delle architetture x86 sono presenti, per motivi di compatibilità, registri a 8, 16, 32 bit 8 / 254 Registri È la situazione dei registri eax, ebx, ecx, edx Ognuna della porzioni può essere considerata un registro vero e proprio Ognuna delle porzioni può essere utilizzata indipendentemente (e contemporaneamente) dalle altre 9 / 254 Registri Registri a 32 bit eax ebx ecx edx esi edi esp ebp eip eflags Nome Accumulator Base Counter Data Source Index Destination Index Stack Pointer Base Pointer Instruction Pointer Flag 16/8 bit ax, ah, al bx, bh, bl cx, ch, cl dx, dh, dl si di sp bp ip flag Descrizione Arithmetic and Logic Arrays Loops Arithmetics Strings and arrays Strings and arrays Top of stack Base of stack Points to next instruction Status and control flag 10 / 254 Registro eflags Si tratta di un registro particolare, nel senso che ogni singolo bit che lo compone può essere riferito indipendentemente dagli altri Ogni bit controlla un’operazione della CPU o fornisce informazioni sul risultato dell’operazione Si tratta comunque di un registro che può essere acceduto in lettura e scrittura: In lettura per verificare, come detto, il risultato di un’operazione In scrittura per impostare lo stato di un flag del processore 11 / 254 Registro eflags /2 Il registro eflags è un registro a 16 bit 7 bit non sono utilizzati 6 flag condizionali (contengono informazioni sullo stato delle operazioni della CPU): Carry Flag (CF) Zero Flag (ZF) Parity Flag (PF) Sign Flag (SF) Auxiliary Carry Flag (AF) Overflow Flag (OF) 3 flag di controllo: Direction Flag (DF) Interrupt Flag (IF) Trap Flag (TF) 12 / 254 Registro eflags /3 Flag condizionali Carry Flag (CF) Viene settato se si verifica un riporto sul bit più significativo durante un calcolo. Il riporto può verificarsi sul bit 7 (operazioni a 8 bit) oppure sul bit 15 (operazioni a 16 bit) Zero Flag (ZF) Viene settato quando il risultato di un’operazione logico-aritmetica è zero. Per esempio: quando si decrementa il contenuto di un registro (di solito il registro CX, che viene usato come contatore), il contenuto del registro sarà zero. In quel momento ZF viene settato. Un altro caso è rappresentato dal confronto tra due numeri. Parity Flag (PF) Quando questo flag viene settato, si ha un numero pari di bit nel byte meno significativo del registro destinazione. Non viene molto usato. 13 / 254 Registro eflags /4 Flag condizionali /2 Sign Flag (SF) Viene settato se il risultato di un’operazione logico-aritmetica è negativo. Di fatto contiene il MSB (most significant bit) del risultato, ovvero il bit di segno nelle operazioni aritmetiche con segno. Auxiliary Carry Flag (AF) Identico a CF, salvo il fatto che viene settato quando si produce riporto sul bit 3, cioè quando si produce riporto sui 4 bit meno significativi. Overflow Flag (OF) Viene settato se: si produce overflow nel MSB con riporto si produce overflow senza riporto 14 / 254 Registro eflags /5 Flag di controllo Direction Flag (DF) Controlla la direzione (sx-dx o viceversa) nella manipolazione delle stringhe. Quando è settato, le operazioni che auto-incrementano i registri sorgente e destinazione (SI e DI) incrementano entrambi i registri e il flusso dei caratteri che compongono le stringhe avviene da sinistra verso destra. Quando è posto uguale a zero, il flusso avviene da destra verso sinistra. Interrupt Flag (IF) Quando viene settato da programmi con sufficienti privilegi, gli interrupt hardware mascherabili possono essere gestiti. Trap Flag (TF) Viene settato per scopi di debug: i programmi vengono eseguiti un’istruzione per volta e si arrestano. Ovviamente, questo consente di esaminare lo stato dei registri. 15 / 254 Registri di segmento Architettura della memoria Il processore 8086 ha un bus degli indirizzi a 20 bit Questo significa che la memoria indirizzabile ammonta a 220 = 1.048.576 byte Cioè dall’indirizzo 00000H all’indirizzo fffffH La memoria è vista come suddivisa in quattro segmenti: Segmento Segmento Segmento Segmento dati codice stack extra 16 / 254 Registri di segmento /2 Ognuno dei segmenti è accessibile mediante l’indirizzo contenuto nel corrispondente registro di segmento Ogni registro memorizza l’indirizzo base (di partenza) del segmento corrispondente Considerata la differenza di dimensione (indirizzo a 20 bit, registro a 16), nei registri vengono memorizzati i 16 bit più significativi dell’indirizzo L’indirizzo fisico (a 20 bit) di un dato viene calcolato a partire dall’indirizzo base (contenuto nel registro) Per esempio, l’indirizzo logico 2222H : 0016H diventa 22220H + 0016H = 22236H Si noti che il registro DS (Data Segment) contiene il valore 2222H, e che la quantità 0016H viene detta scostamento (offset) 17 / 254 Registri di segmento /3 Segmento di Codice Il segmento di codice (Code Segment, CS) è l’area di memoria che contiene soltanto il codice di un programma. L’offset rispetto al segmento di codice è fornito dall’Instruction Pointer (IP), che punta sempre all’istruzione successiva. L’indirizzo logico di una istruzione è pertanto CS:IP Segmento di Stack Il segmento di stack (Stack Segment, SS) è l’area di memoria che contiene lo stack. È gestita seconda la logica last-in-first-out. Il registro Stack Pointer punta alla cima dello stack. Un indirizzo logico 4466H : 0122H significa che il registro SS contiene il valore 4466H e che il registro IP 0122H: l’indirizzo fisico si ottiene come 44660H + 01220H = 44782H. 18 / 254 Registri di segmento /4 Segmento Dati e Segmento Extra Contengono entrambi dati, ma in alcuni casi particolari (quando si gestiscono stringhe) può essere necessario gestirli in segmenti separati. I registri corrispondenti sono DS (Data Segment) e ES (Extra Segment). 19 / 254 Struttura della memoria 20 / 254 Struttura della memoria /2 21 / 254 Mappa della memoria Disposizione del codice eseguibile e dei dati in memoria: Stack Dati non inizializzati Dati del programma Codice eseguibile Prefisso del segmento del programma (PSP, Program Segment Prefix 22 / 254 Modelli di memoria I programmi eseguibili presentano di norma segmenti separati per i dati, il codice, lo stack ogni segmento non può occupare più di 64kB di memoria il modello di memoria è il modo in cui un programma indirizza le differenti aree della mappa di memoria Modello small compact medium large Num. segmenti codice 1 1 più di 1 più di 1 Num. segmenti dati 1 più di 1 1 più di 1 23 / 254 Interrupt Introduzione Sono il mezzo con cui i circuiti esterni al microprocessore comunicano il verificarsi di un evento i microprocessori possono rispondere ad interrupt hardware e/o software un dispositivo hardware può produrre un segnale di interrupt che viene elaborato dal PIC (Programmable Interrupt Controller) e da questi trasmesso al processore gli interrupt software vengono generati mediante la funzione INT l’effetto di un interrupt è che il processore arresta la sua normale attività ed esegue una routine residente in memoria (gestione di interrupt) al termine, il microprocessore riprende la sua attività dal punto in cui l’interrupt l’aveva fermato 24 / 254 Interrupt Gestione degli interrupt 8086 La famiglia di processori 80x86 gestisce fino a 256 interrupt differenti (da 00H fino a FFH), dove H sta per esadecimale ad ogni interrupt è associata una routine l’indirizzo di ognuna delle 256 routine è memorizzato in una tabella, detta tabella dei vettori di interrupt ogni vettore di interrupt occupa 4 byte, quindi l’indirizzo di ogni vettore di interrupt può essere ottenuto moltiplicando per 4 il numero dell’interrupt 25 / 254 Interrupt Interrupt software Quando il processore esegue l’istruzione: INT 12H vengono caricati sullo stack i contenuti correnti: del registro dei flag del registro del codice (CS) del registro IP (Instruction Pointer) il controllo viene trasferito alla routine di gestione dell’interrupt, mediante l’indirizzo 48H il processore esegue la routine di gestione dell’interrupt la routine termina con l’istruzione IRET, che scarica dallo stack i contenuti dei registri della routine interrotta il controllo viene restituito al programma interrotto 26 / 254 Interrupt Interrupt del DOS Interrupt 20H (32D) 21H (33D) 22H (34D) 23H (35D) 24H (36D) 25H (37D) 26H (38D) 27H (39D) 28H (20D) 2FH (47D) Descrizione Arresto del programma Servizi generali del DOS Indirizzo di terminazione Indirizzo del gestore del Ctrl-C Indirizzo gestore errori critici Lettura disco assoluta Scrittura disco assoluta TSR (Terminate and Stay Resident) Interrupt stato d’attesa DOS Interrupt Multiplex 27 / 254 Interrupt L’interrupt int21h Uno degli interrupt più utilizzati è INT 21H Nell’elenco alcune funzioni: Funzione 00H (00D) 01H (01D) 02H (02D) 05H (05D) 08H (08D) 09H (09D) 0FH (15D) 10H (16D) Descrizione Termina Input di un carattere con eco Output di un carattere Output della stampante Input dalla console senza eco Output di una stringa Apertura file Chiusura file 28 / 254 Interrupt L’interrupt int21h Esempio di utilizzo di una delle funzioni dell’interrupt int 21h: mov ah, 1h int 21h Nell’esempio: il valore 1h viene caricato nel registro ah (viene selezionata la funzione di input carattere con eco) viene invocato l’interrupt il carattere digitato da tastiera viene memorizzato nel registro al 29 / 254 Struttura di un programma assembly .model small .stack 100h .data .code start: ... mov ax, 4c00h int 21h end start 30 / 254 Esempi di programmazione assembly ; prog1.asm ; stampa il carattere ’a’ a schermo ; .model small .stack 100h .code start: mov dl, ’a’ mov ah, 2h int 21h mov ax, 4c00h int 21h end start 31 / 254 Esempi di programmazione assembly / 2 ; legge un carattere da tastiera e lo stampa a video .model small .stack 100h .code start: mov int mov mov int ah, 1h 21h dl, al ah, 2h 21h mov ax, 4c00h int 21h end start 32 / 254 Esempi di programmazione assembly / 3 ; legge un carattere da tastiera ; lo stampa a video ; viene visualizzato un prompt mov ah, 1h int 21h mov bl, al .model small .stack 100h mov dl, ’ ’ mov ah, 2h int 21h .code mov dl, bl start: mov ah, 2h int 21h mov dl, ’>’ mov ah, 2h int 21h mov ax, 4c00h int 21h end start 33 / 254 Esempi di programmazione assembly / 4 ; prog4.asm ; legge un carattere da tastiera ; mostra CR, LF e il carattere inserito ; mov bl, al mov dl, 13d mov ah, 2h int 21h .model small .stack 100h mov dl, 10d mov ah, 2h int 21h .code start: mov dl, ’>’ mov ah, 2h int 21h mov ah, 1h int 21h mov dl, bl mov ah, 2h int 21h mov ax, 4c00h int 21h end start 34 / 254 Esempi di programmazione assembly / 5 ; prog5.asm ; visualizza una stringa a video ; mov dx, offset stringa mov ah, 9h int 21h .model small .stack 100h .data stringa db ’Ciao a tutti’, 13, 10, ’\$’ mov ax, 4c00h int 21h end start .code start: mov ax, @data mov ds, ax 35 / 254 Operazioni e Metodi di Indirizzamento L’architettura 8086 richiede l’esistenza di uno o due operandi Per esempio uno shift richiede un operando, un’addizione due Come esempio si consideri l’istruzione mov destination, source Gli operandi (destination e source) possono essere specificati nei seguenti modi: Indirizzamento Indirizzamento Indirizzamento Indirizzamento Indirizzamento Indirizzamento Indirizzamento mediante registri immediato diretto indiretto mediante registri relativo mediante registri indicizzato indicizzato relativo 36 / 254 Operazioni e Metodi di Indirizzamento Indirizzamento mediante registri In questo caso, destination e source sono entrambi registri Per esempio: mov al, ah mov si, ax mov ax, bl ; errore (un dato a 8 bit viene copiato in un registro a 16 bit) mov bl, ax ; errore (un dato a 16 bit viene copiato in un registro a 8 bit) 37 / 254 Operazioni e Metodi di Indirizzamento Indirizzamento immediato In questo caso, source è un dato costante Per esempio: mov mov mov mov al, 33h cx, 1234h al, ’c’ var1, 44 38 / 254 Operazioni e Metodi di Indirizzamento Indirizzamento diretto In questo caso, destination o source sono indirizzi (offset rispetto al valore di DS) di memoria Per esempio: mov mov mov mov ax, [1234h] [5678h], al var1, al bx, var2 39 / 254 Operazioni e Metodi di Indirizzamento Indirizzamento indiretto mediante registri In questa modalità di indirizzamento, l’indirizzo di un dato è memorizzato in un registro, che si comporta come se fosse un puntatore al dato. I registri permessi in questa modalità sono BX, SI, DI mov al, [bx] ; il contenuto della locazione il cui indirizzo è puntato da bx viene copiato in al mov [si], cl ; il contenuto di cl viene copiato nella locazione il cui indirizzo è puntato da si 40 / 254 Operazioni e Metodi di Indirizzamento Indirizzamento relativo mediante registri In questa modalità il registro (quelli permessi sono BX, SI, DI, BP) contiene l’indirizzo di un dato; a questo viene aggiunto uno scostamento mov cl, 10[bx] mov cl, [bx+10] mov cl, [bx]10 41 / 254 Operazioni e Metodi di Indirizzamento Indirizzamento indicizzato In questa modalità l’indirizzo del dato viene ottenuto sommando il contenuto di due registri: un registro base e un registro indice mov al, [bx][si] mov [bx][di], cx 42 / 254 Operazioni e Metodi di Indirizzamento Indirizzamento indicizzato relativo In questa modalità l’indirizzo del dato viene ottenuto sommando il contenuto di due registri ed uno scostamento mov dl, 5[bx][di] mov 5[bp][si], ax 43 / 254 Operazioni e Metodi di Indirizzamento Esempio - Indirizzamento relativo mediante registri .model small .data array db 10h, 20h, 30h, 40h, 50h .code start: mov mov add add mov di, 0 al, array[di] al, 07h di, 05h array[di], al mov ax, 4c00h int 21h end start 44 / 254 Operazioni e Metodi di Indirizzamento Esempio - Indirizzamento indicizzato .model small .data array db 34h, 87h, 56h, 05h, 07h .code start: mov mov mov add mov bx, di, al, al, di, offset array 0 [bx + di] 35h 05 mov [bx + di], al mov ax, 4c00h int 21h end start 45 / 254 Tipi di dati Gli operandi numerici possono essere espressi in notazione decimale, binaria, esadecimale e ottale la convenzione utilizzata dall’assemblatore è che un operando viene espresso in base 10 a meno che non sia presente un suffisso che indichi il contrario i suffissi utilizzabili sono: H (hexadecimal) D (decimal) B (binary) O o Q (octal) nessuno (decimale) 46 / 254 Tipi di dati /2 Tipo BYTE SBYTE WORD SWORD DWORD SDWORD FWORD QWORD TBYTE REAL4 REAL8 REAL10 Descrizione Intero senza segno a 8 bit Intero con segno a 8 bit Intero senza segno a 16 bit Intero con segno a 16 bit Intero senza segno a 32 bit Intero con segno a 32 bit Intero a 48 bit Intero a 64 bit Intero a 80 bit Reale a 32 bit Reale a 64 bit (long) Reale a 80 bit (extended) 47 / 254 Tipi di dati /3 La direttiva BYTE riserva uno o più byte per la memorizzazione di dati. La direttiva: numero BYTE 01100101b riserva un byte di memoria e lo inizializza al valore 65H a tutti gli effetti pratici, sono assolutamente equivalenti le seguenti direttive: numero numero numero numero BYTE BYTE BYTE BYTE 01100101b 65h 101 145q 48 / 254 Tipi di dati /4 Analogamente, le direttive WORD e DWORD permettono di riservare una o due parole di memoria tenendo conto del segno del numero che si vuole memorizzare; si può avere: WORD da -32.768 a 32.767 oppure WORD da 0 a 65.535 DWORD da -2.147.483.648 a 2.147.483.647 oppure DWORD da 0 a 4.294.967.295 49 / 254 Tipi di dati /5 Esempio Ad esempio: var1 var2 var3 var4 var5 dvar1 dvar2 dvar3 dvar4 dvar3 WORD WORD WORD WORD WORD DWORD DWORD DWORD DWORD DWORD -1 0 32767 65535 -32768 0 -1 4294967295 -2147483648 4294967266 50 / 254 Tipi di dati /6 BYTE La direttiva BYTE permette di definire operandi sotto forma di caratteri o di stringhe di caratteri caratteri e stringhe devono essere racchiusi tra apici (semplici o doppi) char1 char2 str1 str2 BYTE BYTE BYTE BYTE ’g’ "g" ’ciccio’ "ciccio’s" 51 / 254 Tipi di dati /7 Assegnazioni multiple Le costanti permettono le assegnazioni multiple L’etichetta si riferisce soltanto all’offset del primo byte Per esempio: lista BYTE 10, 20, 30, 40 Offset 0000 0001 0002 0003 Valore 10 20 30 40 52 / 254 Tipi di dati /8 Operatore DUP L’operatore DUP produce un’allocazione ripetuta, mediante l’utilizzo di un’espressione costante come contatore È particolarmente utile quando si alloca spazio per array o stringhe, e può essere impiegato per la definizione di dati inizializzati o meno Per esempio: BYTE 20 DUP(0) ; 20 byte, tutti inizializzati a zero BYTE 20 DUP(?) ; 20 byte, non inizializzati mioarray DWORD 100 DUP(101) ; 100 elementi DWORD, inizializzati a 101 53 / 254 Tipi di dati /9 Esempio di utilizzo di DUP ; prog9.asm ; utilizzo di DUP mov ax, 4c00h int 21h .model small .stack 100h .data ostr db 50 dup(’*’) ;;;;;;;;;;;;;;;;;; ; subroutine puts puts: .code start: mov ax, @data mov ds, ax mov dx, offset ostr call puts mov ah, 9h int 21h ret end start 54 / 254 Istruzione mov Copia dati da un operando sorgente ad un operando destinazione bisogna rispettare le seguenti regole: gli operandi devono avere la stessa dimensione gli operandi non possono essere entrambi locazioni di memoria i registri CS, EIP e IP non possono essere operandi destinazione un valore immediato non può essere spostato in un registro di segmento Le possibilità sono: MOV MOV MOV MOV MOV reg, reg mem, reg reg, mem mem, imm reg, imm 55 / 254 Istruzione xchg Scambia il contenuto di due operandi Le possibilità sono: xchg reg, reg xchg reg, mem xchg mem, reg Per esempio: xchg ax, bx xchg ah, al xchg var1, bx 56 / 254 Operandi con offset diretto E’ possibile aggiungere un offset ad una variabile questo permette di raggiungere locazioni di memoria prive di etichette esplicite Per esempio: vettore ... mov al, mov al, mov al, byte 10h, 20h, 30h, 40h, 50h vettore [vettore+1] [vettore+2] ; al = 10 ; al = 20 ; al = 30 57 / 254 Operandi con offset diretto /2 Lo scostamento dipende dalla dimensione della locazione di memoria Per esempio: .data vettore word 100h, 200h, 300h .code mov ax, vettore ; ax = 100 mov ax, [vettore+2] ; ax = 200 ogni elemento dell’array occupa 16 bit, e quindi l’offset deve essere di 2 per raggiungere il secondo elemento dell’array 58 / 254 Incremento e decremento Permettono (rispettivamente) di incrementare e decrementare di 1 un singolo operando La sintassi: inc reg/mem dec reg/mem Per esempio: .data var word 1000h .code inc var ; var = 1001h mov bx, var dec bx ; bx = 1000h 59 / 254 Addizione e sottrazione Permettono di addizionare (sottrarre) l’operando sorgente all’ (dall’)operando destinazione La sintassi: add dest/source sub dest/source Per esempio: .data var1 word 2000h var2 word 1000h .code mov ax, var1 add ax, var2 ... mov ax, var1 sub ax, var2 60 / 254 Istruzione NEG Inverte il segno di un numero mediante complemento a due Sono permessi gli operandi: NEG reg NEG mem 61 / 254 Implementazione di istruzioni matematiche Si supponga di dover implementare l’espressione: Res = −X + (Y − Z ) res sword ? x sword 25 y sword 30 z sword 40 ; primo termine (-x) mov ax, x neg ax ; secondo termine (y - z) mov bx, y sub bx, z ; addizione e memorizzazione add ax, bx mov res, ax 62 / 254 Operatori MASM presenta una serie di operatori utili per descrivere e indirizzare variabili: offset, restituisce la distanza di una variabile dall’inizio del segmento di appartenenza ptr, permette di modificare la dimensione di default di una variabile type, restituisce la dimensione in byte di ogni elemento di un array lengthof, restituisce il numero di elementi di un array sizeof, restituisce il numero di byte usati per inizializzare un array 63 / 254 Operatore offset L’operatore offset restituisce l’offset di una variabile, cioè la distanza in byte della variabile dall’inizio del segmento dati in modalità protetta un offset è sempre di 32 bit in modalità reale un offset è sempre di 16 bit Per esempio: .data bvar byte ? wvar word ? dvar1 dword ? dvar2 dword ? .code mov si, offset mov si, offset mov si, offset mov si, offset bvar wvar dvar1 dvar2 ; ; ; ; si si si si = = = = 4000 4001 4003 4007 64 / 254 Operatore ptr Permette di modificare la dimensione di default di un operando È necessario quando si tenta di accedere alla variabile utilizzando un attributo di dimensione differente da quello utilizzato per la dichiarazione della variabile esempio: spostare i 16 bit meno significativi di una variabile DWORD in un registro (a 16 bit) Per esempio: .data var dword 12345678h .code mov ax, var mov ax, word ptr var mov ax, byte ptr var mov ax, word ptr [var + 2] ; ; ; ; SBAGLIATO ax = 5678h ax = 78h ax = 1234h 65 / 254 Operatore type Restituisce la dimensione in byte di un singolo elemento di una variabile Per esempio: .data var1 byte ? var2 word ? var3 dword ? ; type = 1 ; type = 2 ; type = 4 66 / 254 Operatore lengthof Conta il numero di elementi di un array definiti in base ai valori che appaiono nella linea della label Per esempio: .data byte1 vec1 vec2 vec3 str1 byte 10, 20, 30 word 30 dup(?),0,0 word 5 dup(3 dup(?)) dword 1, 2, 3, 4 byte "12345678",’\$’ ; ; ; ; ; lengthof lengthof lengthof lengthof lengthof = = = = = 3 32 5*3 4 9 67 / 254 Operatore sizeof Restituisce un valore uguale al prodotto di lengthof per type Per esempio: vec word 32 dup(0) ; sizeof = 64 68 / 254 Procedure ; prog7.asm ; conversione M/m .model small .stack 100h .data istr db ’Carattere M: $’ ostr db ’Carattere m: $’ .code ; subroutine getc getc proc mov ah, 1h int 21h ret getc endp ; subroutint putc putc proc mov ah, 2h int 21h ret putc endp ; subroutine puts puts proc mov ah, 9h int 21h ret puts endp 69 / 254 Procedure /2 ; subroutine put1310 put1310 proc mov dl, 13d mov ah, 2h int 21h mov dl, 10d mov ah, 2h int 21h ret put1310 endp main proc mov ax, @data mov ds, ax mov dx, offset istr invoke puts call getc mov bl, al add bl, 32d call put1310 mov dx, offset ostr call puts mov dl, bl call putc mov ax, 4c00h int 21h main endp end main 70 / 254 Procedure /3 Programmazione modulare ; modules2.asm ; conversione M/m ; programmazione modulare, ; le procedure si trovano ; nel file procs.asm .model small main proc mov ax, @data mov ds, ax mov dx, offset istr invoke puts invoke getc .stack 100h mov bl, al add bl, 32d invoke put1310 mov dx, offset ostr invoke puts mov dl, bl invoke putc mov ax, 4c00h int 21h main endp end main .data istr db ’Carattere M: $’ ostr db ’Carattere m: $’ .code getc proto putc proto puts proto put1310 proto 71 / 254 Procedure /4 Programmazione modulare - file procedure .model small .code ; subroutine getc getc proc mov ah, 1h int 21h ret getc endp ; subroutint putc putc proc mov ah, 2h int 21h ret putc endp ; subroutine puts puts proc mov ah, 9h int 21h ret puts endp ; subroutine put1310 put1310 proc mov dl, 13d mov ah, 2h int 21h mov dl, 10d mov ah, 2h int 21h ret put1310 endp end 72 / 254 Procedure /5 Programmazione modulare - compilazione C:\masm32\progs>ml /c modules2.asm procs.asm C:\masm32\progs>link16 modules2.obj procsobj ,,,,, C:\masm32\progs>modules2 Carattere M: F Carattere m: f 73 / 254 Debug debug.exe e un programma per il debug, la verifica e il test di programmi Sintassi: debug nome-programma.exe al prompt (-) digitare ? per ottenere un elenco dei comandi disponibili 74 / 254 Debug /2 75 / 254 Debug /3 Comando g (go) digitando g viene effettuata l’esecuzione del programma nell’ambiente di debug 76 / 254 Debug /4 Comando r (registers) serve a visualizzare lo stato dei registri 77 / 254 Debug /5 Comando t (trace) permette di eseguire l’istruzione corrente molto utile, perche mostra lo stato dei registri ad ogni istruzione 78 / 254 Debug /6 Comando u (unassemble) traduce in assembly i byte contenuti dopo la conclusione del codice sorgente, il comando u continua ... ... disassemblando tutto quello che incontra (quasi sempre senza senso) 79 / 254 Debug /7 Comando p (proceed) esegue una procedura (call o int) per intero senza entrare nei dettagli delle istruzioni della procedura si usa in alternanza al comando t 80 / 254 Debug /8 Comando d (dump) mostra il contenuto della memoria quando un eseguibile e caricato dal debug mostra la mappa di memoria 81 / 254 Debug /9 Esempio di utilizzo Visualizzare lo stato dei registri mediante il comando trace di debug .model small .stack 100h .data .code start: mov ax, 11h add ax, 22h sub ax, 30h mov ax, 4c00h int 21h end start 82 / 254 Indirizzamento indiretto L’indirizzamento diretto non pratico per operazioni sugli array richiede infatti di fornire un nome (label) per ogni elemento dell’array la soluzione consiste nell’utilizzare un registro come puntatore e modificare il valore del registro questa tecnica si chiama indirizzamento indiretto il registro che memorizza un indirizzo viene detto operando indiretto 83 / 254 Operandi indiretti Un operando indiretto pu essere qualsiasi registro general-purpose (bx, si, di, bp) viene utilizzato racchiudendolo tra parentesi quadre (per esempio, [ax]) .data var1 byte 10h .code start: mov si, offset var1 mov al, [si] end start 84 / 254 Operandi indiretti (modalit protetta, a 32 bit) In modalit protetta si possono utilizzare pcome operandi indiretti i registri a 32 bit: eax, ebx, ecx, edx, esi, edi, ebp, esp se l’indirizzo punta ad un’area esterna al segmento dati del programma si genera un general protection (GP) fault un GP fault si pu verificare anche senza che si intenda modificare la memoria indirizzata il modo migliore per evitare questo tipo di errori consiste nell’inizializzare i registri da impiegare per l’indirizzamento indiretto i GP fault non si verificano in modalit reale (16 bit) 85 / 254 Utilizzo di ptr con gli operandi indiretti La dimensione di un operando non sempre chiara dal contesto Per esempio: inc [si] ; errore: l’operando deve essere dimensionato inc ptr byte [si] ; corretto: si chiarisce il puntamento ad un byte 86 / 254 Array Gli operandi indiretti sono particolarmente utili quando si gestiscono array, perch il valore di un operando indiretto pu essere modificato facilmente in modo analogo all’indice di un array, un operando indiretto pu puntare ai diversi elementi di un array Per esempio: .data vettore .code mov ax, mov ds, mov si, mov al, inc si mov al, inc si mov al, byte 10h, 20h, 30h @data ax offset vettore [si] ; al = 10h [si] ; al = 20h [si] ; al = 30h 87 / 254 Array /2 Quando si gestisce un array di interi a 16 bit (word), bisogna incrementare il registro si di 2 per indirizzare i successivi elementi Per esempio: .data vettore .code mov si, mov ax, add si, mov ax, add si, mov ax, word 1000h, 2000h, 3000h offset vettore [si] ; ax = 1000h 2 [si] ; ax = 2000h 2 [si] ; ax = 3000h 88 / 254 Array /3 Quando si gestisce un array di interi a 32 bit (dword), bisogna incrementare il registro si di 4 Per esempio: .data vettore .code mov si, mov ax, add si, mov ax, add si, add ax, dword 10000h, 20000h, 30000h offset vettore [si] ; ax = 10000h 4 [si] ; ax = 20000h 4 [si] ; ax = 30000h 89 / 254 Operandi indicizzati Un operando indicizzato aggiunge una costante ad un registro per produrre un indirizzo in modalit protetta qualsiasi registro a 32 bit pu essere utilizzato come registro indice in modalit reale soltanto i registri si, di, bx o bp possono essere utilizzati come registri indice MASM permette due notazioni: cost[reg ] [cost + reg ] 90 / 254 Operandi indicizzati /2 E’ buona consuetudine inizializzare a zero il registro indice .data bvec byte 10h, 20h, 30h .code mov si, 0 mov al, [bvec + si] ; al = 10h 91 / 254 Operandi indicizzati /3 .data wvec word 1000h, 2000h, 3000h .code mov si, offset wvec mov ax, [si] ; ax = 1000h mov ax, [si + 2] ; ax = 2000h mov ax, [si + 4] ; ax = 3000h 92 / 254 Puntatori Una variabile che contiene l’indirizzo di un’altra variabile detta variabile puntatore i puntatori sono essenziali quando si elaborano array e strutture dati MASM prevede l’utilizzo di due tipi di puntatori near (16 bit in modalit reale, 32 bit in modalit protetta) far (32 bit in modalit reale, 48 bit in modalit protetta) 93 / 254 Puntatori /2 bvec wvec ptrb ptrw byte 10h, 20h, 30h, 40h word 1000h, 2000h, 3000h dword bvec dword wvec In alternativa: ptrb dword offset bvec ptrw dword offset wvec 94 / 254 Puntatori Definizione mediante typedef L’operatore typedef permette di creare un tipo di variabile pu essere utilizzato per creare puntatori Per esempio: pbyte typedef ptr byte Per esempio: pbyte typedef ptr byte .data bvec byte 10h, 20h, 30h, 40h ptr1 pbyte ? ; non inizializzato ptr2 pbyte bvec ; punta all’array bvec 95 / 254 JMP e LOOP Un trasferimento di controllo, o branch un modo di alterare l’ordine in cui le istruzioni vengono eseguite tutti i linguaggi di programmazione presentano istruzioni di branching possibile suddividere queste istruzioni in: trasferimenti incondizionati, per esempio mediante l’istruzione JMP trasferimenti condizionati, in cui la ramificazione si verifica soltanto se una certa condizione vera. Per esempio, l’istruzione LOOP 96 / 254 Istruzione jmp Provoca un trasferimento incondizionato ad una locazione interna al segmento di codice la locazione destinazione deve essere identificata mediante un’etichetta la sintassi : jmp etichetta L’istruzione jmp pu essere impiegata per realizzare un loop top: ... ... jmp top ; attenzione si genera un loop infinito 97 / 254 Istruzione loop Fornisce un modo semplice per ripetere l’esecuzione di un blocco di istruzioni per un numero specificato di volte il registro cx viene automaticamente utilizzato come contatore e viene decrementato ogni volta che il ciclo si ripete la sintassi : loop destinazione Per esempio: mov ax, 0 mov cx, 5 L1: inc ax loop L1 98 / 254 Istruzione loop Avvertenze bisogna evitare di inizializzare il registro cx a zero prima di avviare il loop. Se questo avvenisse, l’istruzione loop incrementerebbe cx a ffff e itererebbe 65536 volte la destinazione del ciclo deve trovarsi nell’intervallo da -128 a +127 rispetto al contatore locale; le istruzioni macchina hanno una dimensione media di 3 byte, quindi un loop pu contenere circa 40 istruzioni una modifica del valore di cx all’interno del loop può avere effetti indesiderati 99 / 254 .model small .stack 100h .data str1 byte "Stringa da copiare","0" str2 byte sizeof str1 dup(0) .code start: mov si, 0 mov cx, sizeof str1 L1: mov al, str1[si] mov str2[si], al inc si loop L1 mov ax, 4c00h int 21h end start 100 / 254 Gestione della memoria Introduzione I processori IA-32 (Intel Architecture 32 bit, dal 386 in poi) presentano tre modalità fondamentali: protetta 8086 virtuale (un caso particolare di modalità protetta) real-address system management 101 / 254 Gestione della memoria /2 Modalità protetta Si tratta della modalità di esecuzione nativa del processore, nel quale tutte le istruzioni e le possibilità sono consentite Ai programmi vengono assegnate aree di memoria (segmenti) Il processore individua ogni tentativo di accedere ad aree di memoria esterne al segmento assegnato Il processore può accedere a 4 GB di memoria (i registri vengono considerati tutti a 32 bit) 102 / 254 Gestione della memoria /3 Modalità 8086 virtuale Si tratta di un caso particolare della modalità protetta Il processore si comporta come un 8086, ma in un ambiente multitasking Per esempio, un crash non influenza negativamente altri programmi e/o il sistema 103 / 254 Gestione della memoria /4 Modalità real-address Nota anche come modalità reale Questa modalità implementa l’ambiente di programmazione del processore Intel 8086 con alcuni elementi ulteriori Tra questi la possibilità di commutare alle altre due modalità Questa modalità è stata introdotta in Windows 98 Si tratta della modalità di avvio di tutti i processori Intel In questa modalità soltanto 1 MB di memoria è accessibile ai programmi (20 bit, da 00000 a FFFFF) 104 / 254 Gestione della memoria /5 Modalità system management Fornisce al sistema operativo un meccanismo per implementare alcune funzionalità come il power management e la sicurezza di sistema 105 / 254 Operazioni sullo stack Introduzione Come si ricorderà, lo stack è una struttura LIFO (Last In First Out) cioè, l’ultimo valore inserito è sempre il primo ad essere estratto il runtime stack è un array di memoria gestita direttamente dalla CPU mediante due registri: SS e SP il registro SS indica l’indirizzo iniziale del segmento di memoria dedicato allo stack il registro SP contiene un offset a 16 bit relativo a qualche locazione dello stack il registro SP viene manipolato raramente, viene invece esplicitamente modificato da istruzioni come CALL, RET, PUSH e POP il registro StackPointer SP punta all’ultimo intero inserito nello stack 106 / 254 Operazioni sullo stack Push Un’operazione di push decrementa lo stack pointer di 4 (2 in modalità reale) e copia un valore nella locazione dello stack puntata dallo stack pointer 107 / 254 Operazioni sullo stack Pop Un’operazione di pop incrementa lo stack pointer di 4 (2 in modalità reale) e rimuove un valore nella locazione dello stack puntata dallo stack pointer 108 / 254 Operazioni sullo stack Utilità Lo stack viene utilizzato nei programmi per: creare un’area temporanea per i registri quando questi vengono utilizzati per qualche scopo salvare l’indirizzo di ritorno della procedura corrente al momento dell’invocazione dell’istruzione call contenere gli argomenti (eventualmente) passati come parametri ad una procedura al momento della sua esecuzione memorizzare le variabili locali di una procedura 109 / 254 Operazioni sullo stack Istruzione push L’istruzione push decrementa SP e copia un operando sorgente da 16 o 32 bit nello stack un operando a 16 bit implica un decremento di SP di 2, un operando a 32 bit un decremento di 4 Attenzione: il push di un operando immediato è stato introdotto a partire dalle architetture 80286 push r/m16 push r/m32 push imm32 (imm16 in real mode) 110 / 254 Operazioni sullo stack Istruzione pop L’istruzione pop prima copia il contenuto dell’elemento dello stack puntato da SP in un operando destinazione a 32 o 16 bit e successivamente incrementa SP se l’operando è a 16 bit, SP viene incrementato di 2, se l’operando è a 32 bit l’incremento di 4 pop r/m16 pop r/m32 111 / 254 Operazioni sullo stack Istruzioni pushfd e popfd (pushf e popf) L’istruzione pushfd scrive il registro a 32 bit EFLAGS sullo stack popfd scrive su EFLAGS il contenuto prelevato dallo stack modalità reale: pushf per il push del registro (a 16 bit) FLAGS sullo stack modalità reale: popf per il pop nel registro (a 16 bit) FLAGS dallo stack pushf ; pushfd in modalit\‘a protetta ; ; codice ... ; popf ; popfd in modalit\‘a protetta 112 / 254 Operazioni sullo stack Istruzioni pushad e popad (pusha e popa) L’istruzione pushad effettua il push sullo stack di tutti i registri a 32 bit general-purpose l’ordine nel quale viene effettuato: EAX, ECX, EDX, EBX, ESP, EBP, ESI e EDI Analogamente, l’istruzione popad ripristina lo stato dei registri modalità reale: l’istruzione pusha effettua il push di AX, CX, DX, BX, SP, BP, SI e DI modalità reale: l’istruzione popa ripristina i predetti registri Attenzione: il push di un operando immediato è stato introdotto a partire dalle architetture 80286 113 / 254 Operazioni sullo stack Esempio: inversione di una stringa (stringa.asm) .model small .stack 100h .data str1 byte "ciao","$" str2 byte sizeof str1 dup(0) .code start: mov ax, @data mov ds, ax mov si, 0 mov cx, sizeof str1 dec cx L1: mov al, str1[si] push ax inc si loop L1 114 / 254 Operazioni sullo stack Esempio: inversione di una stringa (stringa.asm) / 2 mov cx, sizeof str1 dec cx mov si, 0 L2: pop ax mov str2[si], al inc si loop L2 mov al, "$" inc si mov str2[si], al mov dx, offset str2 mov ah, 9h int 21h mov ax, 4c00h int 21h end start 115 / 254 Elaborazione condizionata Introduzione Le condizioni che permettono di modificare il flusso delle istruzioni Assembly operano in base al valore di alcuni bit del registro FLAGS In particolare vengono settati i flag (bit): Zero: quando il risultato di un’operazione è uguale a zero Carry: quando un’istruzione genera un riporto Segno: copia del bit più significativo dell’operando destinazione Overflow: quando un’istruzione genera un risultato con overflow Parità: quando un’istruzione produce un numero pari di bit 1 nel byte meno significativo dell’operando destinazione 116 / 254 Elaborazione condizionata Istruzione AND Effettua un AND booleano (bitwise, bit a bit) tra i bit di uguale posto di due operandi il risultato viene memorizzato nell’operando destinazione AND destinazione, sorgente Le combinazioni permesse di operandi sono: AND AND AND AND AND reg, reg, reg, mem, mem, reg mem imm reg imm 117 / 254 Elaborazione condizionata Istruzione AND / 2 I due operandi possono essere a 8, 16 o 32 bit, ma devono essere della stessa dimensione AND viene spesso utilizzato per eliminare determinati bit e salvarne altri Per esempio: 00111011 AND 00001111 ---------------00001011 mov al, 00111011b and al, 00001111b Flags: vengono resettati i bit di Overflow e Carry, modificati i bit di Segno, Zero e Parità 118 / 254 Elaborazione condizionata Istruzione AND / 3 Mediante l’istruzione AND è possibile convertire facilmente una lettera minuscola in maiuscola si osservino i codici ASCII di A e a soltanto il bit 5 è differente: 0 1 1 0 0 0 0 1 = 61h (’a’) 0 1 0 0 0 0 0 1 = 41h (’A’) La regola vale per le altre lettere dell’alfabeto ponendo in AND una lettera minuscola con 11011111, tutti i bit saranno preservati ad eccezione del bit 5 119 / 254 Elaborazione condizionata Istruzione AND - Esempio ; prog09.asm .model small .stack 100h .code start: mov al, 01100001b and al, 11011111b mov dl, al mov ah, 2h int 21h mov ax, 4c00h int 21h end start 120 / 254 Elaborazione condizionata Istruzione OR L’istruzione OR effettua un OR booleano tra ogni coppia di bit (di posto uguale) di due operandi il risultato viene posto nell’operando destinazione OR destinazione, sorgente L’istruzione OR utilizza le stesse combinazioni di operandi dell’AND: OR OR OR OR OR reg, reg, reg, mem, mem, reg mem imm reg imm 121 / 254 Elaborazione condizionata Istruzione OR / 2 I due operandi possono essere a 8, 16 o 32 bit, ma devono essere della stessa dimensione OR viene spesso utilizzato per settare alcuni bit e preservarne altri Per esempio: 00111011 OR 00001111 ------------00111111 Flags: vengono resettati i bit di Overflow e Carry, modificati i bit di Segno, Zero e Parità 122 / 254 Elaborazione condizionata Istruzione OR / 3 L’istruzione OR viene utilizzata per convertire un byte contenente un intero compreso tra 0 e 9 nel carattere ASCII corrispondente a tale scopo necessario settare i bit 4 e 5 per esempio, 05h in OR con 30h diventa il carattere ASCII 35h 0 0 0 0 0 1 0 1 05h OR 0 0 1 1 0 0 0 0 30h -------------------0 0 1 1 0 1 0 1 35h mov dl, 5 or dl, 30h 123 / 254 Elaborazione condizionata Istruzione OR - Esempio ; prog10.asm .model small .stack 100h .code start: mov al, 00000101b or al, 00110000b mov dl, al mov ah, 2h int 21h mov ax, 4c00h int 21h end start 124 / 254 Elaborazione condizionata Istruzione XOR L’istruzione XOR effettua un OR booleano esclusivo tra ogni coppia di bit (di posto uguale) di due operandi il risultato viene posto nell’operando destinazione XOR destinazione, sorgente L’istruzione XOR utilizza le stesse combinazioni di operandi dell’AND: XOR XOR XOR XOR XOR reg, reg, reg, mem, mem, reg mem imm reg imm 125 / 254 Elaborazione condizionata Istruzione XOR / 2 Ricordando la tabella di verità di XOR si può vedere che qualsiasi bit in XOR con 0 mantiene il suo valore, mentre in XOR con 1 viene complementato Una caratteristica di XOR è che si annulla quando viene applicato due volte allo stesso operando Infatti x 0 0 1 1 y 0 1 0 1 (x XOR y) 0 1 1 0 (x XOR y) XOR y 0 0 1 1 Questo lo rende uno strumento ideale per le operazioni di cifratura/decifratura di dati. 126 / 254 Elaborazione condizionata Istruzione XOR / 3 XOR viene utilizzato per controllare la parità (pari o dispari) di un numero Infatti: mov xor mov xor al, al, al, al, 10110101b 0 11001100b 0 ; ; ; ; 5 bit = flag di 4 bit = flag di parita’ parita’ parita’ parita’ dispari azzerato (PO) pari settato (PE) Flags: l’istruzione XOR resetta sempre i bit di Overflow e Carry. Modifica i bit di Segno, Zero e Parità in base al valore dell’operando destinazione. 127 / 254 Elaborazione condizionata Istruzione XOR - Esempio ; prog11.asm .model small .stack 100h .code start: mov al, 10110101b xor al, 0 mov al, 11001100b xor al, 0 mov ax, 4c00h int 21h end start 128 / 254 Elaborazione condizionata Istruzione NOT L’istruzione NOT complementa tutti i bit di un operando Il risultato è chiamato complemento a 1. Sono permessi i seguenti tipi di operandi: NOT reg NOT mem mov al, 11110000b not al ; al = 00001111b 129 / 254 Elaborazione condizionata Istruzione TEST L’istruzione TEST effettua un AND implicito tra ogni coppia di bit (di uguale posto) di due operandi e setta i flag di conseguenza A differenza di AND, l’operando destinazione non viene modificato Le combinazioni permesse sono uguali a quelle di AND TEST è utile quando si vuole verificare se determinati bit sono settati. test al, 00001001b ; test dello stato dei bit 0 e 3 di AL 130 / 254 Elaborazione condizionata Istruzione TEST / 2 Per comprendere il comportamento del flag Zero si consideri il seguente esempio: 0 0 1 0 0 1 0 1 0 0 0 0 1 0 0 1 0 0 0 0 0 0 0 1 valore da verificare valore di test ZF = 0 0 0 1 0 0 1 0 0 0 0 0 0 1 0 0 1 0 0 0 0 0 0 0 0 valore da verificare valore di test ZF = 1 131 / 254 Elaborazione condizionata Istruzione cmp L’istruzione cmp (compare) effettua una sottrazione implicita di un operando sorgente da un operando destinazione Nessuno dei due operandi viene modificato. L’istruzione cmp è fondamentale perchè fornisce le basi per la maggior parte delle strutture logiche. L’istruzione cmp seguita da un’istruzione di salto condizionato è equivalente ad un IF. La sintassi è: cmp destinazione, sorgente 132 / 254 Elaborazione condizionata Istruzione cmp / 2 L’istruzione cmp modifica i flag di Overflow, Segno, Zero, Carry, Auxiliary Carry e Parità in base al valore che l’operando destinazione avrebbe se venisse utilizzata l’istruzione sub: Risultato di cmp dest < sorgente dest > sorgente dest = sorgente ZF 0 0 1 CF 1 0 0 Se i due operandi sono considerati con segno, i flag Segno, Zero e Overflow indicano le seguenti relazioni tra gli operandi: Risultato di cmp dest < sorgente dest > sorgente dest = sorgente Flag SF != OF SF = OF ZF = 1 133 / 254 Elaborazione condizionata Istruzione cmp / 3 mov ax, 5 cmp ax, 10 ; CF = 1 (10 - 5 richiede il "prestito") mov ax, 1000 mov cx, 1000 cmp ax, cx ; ZF = 1 mov si, 105 cmp si, 0 ; ZF = 0 e CF = 0 134 / 254 Elaborazione condizionata Istruzione cmp - Esempio ; prog12.asm .model small .stack 100h .code start: mov ax, 5 cmp ax, 10 mov ax, 1000 mov cx, 1000 cmp ax, cx mov si, 105 cmp si, 0 mov ax, 4c00h int 21h end start 135 / 254 Elaborazione condizionata Operazioni sui singoli flag Le operazioni sui singoli flag sono di set e reset. Per esempio: and al, 0 or al, 1 ; ZF = 1 ; ZF = 0 or al, 80h and al, 7fh ; SF = 1 ; SF = 0 stc clc ; set carry flag ; clear carry flag mov al, 7fh inc al or ax, 0 ; al = +127 ; al = -128 ; OF = 0 OF = 1 136 / 254 Elaborazione condizionata Operazioni sui singoli flag - Tabella di debug Set OV DN EI NG ZR AC PO CY Descrizione Overflow Direction Down Interrupts Enabled Sign Flag Negative Zero Auxiliary Carry Odd Parity Carry Clear NV UP DI PL NZ NA PE NC Descrizione No Overflow Direction Up Interrupts Disabled Sign Flag Positive Not Zero Not Auxiliary Carry Even Parity No Carry 137 / 254 Elaborazione condizionata Operazioni sui singoli flag - Esempio ; prog13.asm .model small .stack 100h .code start: and al, 0 or al, 1 or al, 80h and al, 7fh stc clc mov al, 7fh inc al or ax, 0 mov ax, 4c00h int 21h end start 138 / 254 Elaborazione condizionata Istruzione jcond Un’istruzione di salto condizionato effettua una ramificazione verso un’etichetta destinazione quando la condizione di un flag vera se la condizione sul flag falsa, viene eseguita l’istruzione immediatamente successiva La sintassi : Jcond destinazione cond si riferisce alla condizione di un flag. Si pu avere per esempio: jc (jump if carry) jnc (jump if not carry) jz (jump if zero) jnz (jump if not zero) 139 / 254 Elaborazione condizionata Istruzione jcond / 2 MASM richiede che la destinazione del salto sia una label all’interno della procedura corrente Ad ogni modo, questa limitazione viene superata utilizzando una label globale indicata dal simbolo :: Per esempio: Jc L1 ... L1:: In modalità reale, i salti possono avvenire entro un offset di 1 byte (positivo o negativo) in modalità protetta, questa limitazione stata rimossa 140 / 254 Elaborazione condizionata Istruzione jcond / 3 mov ax, 5 cmp ax, 5 je L1 ; jump if equal mov ax, 5 cmp ax, 6 jl L1 ; jump if less mov ax, 5 cmp ax, 4 jg L1 ; jump if greater 141 / 254 Elaborazione condizionata Istruzione jcond / 4 I salti condizionati possono essere raggruppati come segue: in base a specifici valori dei flag in base all’uguaglianza tra operandi, oppure al valore del registro cx in base al confronto tra operandi senza segno in base al confronto tra operandi con segno 142 / 254 Elaborazione condizionata Istruzione jcond / 5 Salti condizionati dipendenti dai valori dei flag Simbolo jz jnz jc jnc jo jno js jns jp jnp Descrizione jump if zero jump if not zero jump if carry jump if not carry jump if overflow jump if not overflow jump if sign jump if not sign jump if parity Flags ZF = 1 ZF = 0 CF = 1 CF = 0 OF = 1 OF = 0 SF = 1 SF = 0 PF = 1 jump if not parity PF = 0 143 / 254 Elaborazione condizionata Istruzione jcond / 6 Salti condizionati dipendenti da uguaglianze Simbolo je jne jcxz Descrizione jump if equal jump if not equal jump if cx = 0 jecxz jump if ecx = 0 144 / 254 Elaborazione condizionata Istruzione jcond / 7 Salti condizionati da confronti senza segno Simbolo ja jnbe jae jnb jb jnae jbe Descrizione jump if above jump if not below or equal (uguale a ja) jump if above or equal jump if not below (uguale a jae) jump if below jump if not above or equal (uguale a jb) jump if below or equal jna jump if not above (uguale a jbe) 145 / 254 Elaborazione condizionata Istruzione jcond / 8 Salti condizionati da confronti con segno jg jnle jge jnl jl jnge jle jng jump jump jump jump jump jump jump jump if if if if if if if if greater not less or equal (uguale a jg) greater or equal not less (uguale a jge) less not greater or equal (uguale a jl) less or equal not greater (uguale a jle) 146 / 254 Elaborazione condizionata Istruzione jcond / 9 I salti basati sui confronti con segno vengono utilizzati quando i numeri che si confrontano possono essere interpretati come valori con segno Per esempio, quando si confronta 80h con 7Fh, l’interpretazione è differente se si utilizza ja o jg mov al, 7Fh cmp al, 80h ja Lab jg Lgr ; ; ; ; 7Fh = +127 80h = -128 non funziona funziona 147 / 254 Elaborazione condizionata Istruzione jcond / 10 Istruzioni come AND, OR, NOT, CMP e TEST sono utili quando seguite da istruzioni di salti condizionati che utilizzano i valori del flag di stato per modificare il flusso del programma Per esempio: mov al, status test al, 00100000b jnz Label ; verifica del bit 5 Si supponga di voler verificare lo stato dei bit 0, 1 o 4: mov al, status test al, 00010011b jnz Label ; verifica dei bit 0, 1, 4 148 / 254 Elaborazione condizionata Istruzione jcond / 11 Si supponga di voler effettuare un salto se i bit 2, 3 e 7 sono tutti contemporaneamente settati: mov and cmp je al, status al, 10001100b al, 10001100b Label ; preserva i bit 2, 3 e 7 ; verifica che siano settati Si supponga di voler confrontare gli interi senza segno in AX e BX e spostare il maggiore in DX mov cmp jae mov L1: dx, ax ax, bx L1 dx, bx ; se ax >= bx salta a L1 ; else bx maggiore ; dx contiene il maggiore 149 / 254 Elaborazione condizionata Istruzione jcond / 12 Si supponga di voler confrontare i valori senza segno memorizzati nelle variabili V1, V2 e V3 il minore dei tre viene poi spostato in ax: .data v1 word v2 word v3 word .code start: mov cmp jbe mov L1: cmp jbe mov L2: ... ? ? ? ax, ax, L1 ax, ax, L2 ax, v1 v2 v2 v3 v3 150 / 254 Elaborazione condizionata Istruzione jcond / 13 Ricerca del primo elemento non nullo in un array .data intvec sword 0, 0, 0, 0, 1, 20, 35, -12, 66, 4, 0 niente byte "Non sono stati trovati valori non nulli",0 .code start: mov ax, @data mov ds, ax mov bx, offset intvec mov cx, lengthof intvec L1: cmp word ptr [bx], 0 jnz trovato add bx, 2 loop L1 jmp nontrovato trovato: mov dx, word ptr[bx] add dx, 30h mov ah, 2h int 21h jmp quit nontrovato: mov dx, offset niente mov ah, 9h int 21h quit: mov ax, 4c00h int 21h end start 151 / 254 Elaborazione condizionata Istruzioni di bit testing Le istruzioni BT, BTC, BTR e BTS sono chiamate istruzioni di bit testing. Sono importanti perchè effettuano più operazioni all’interno di una singola operazione atomica L’istruzione BT (bit test) seleziona l’n-esimo bit del primo operando e lo copia nel Carry flag: BT bitbase, n Il primo operando (bitbase) non viene modificato. Gli operandi consentiti sono: BT BT BT BT r/m16, r/m32, r/m16, r/m32, r16 r32 imm8 imm8 152 / 254 Elaborazione condizionata Istruzioni di bit testing / 2 Per esempio: .data semaforo word 10001000b .code ... BT semaforo, 7 ; CF = 1 In alternativa (ma molto più rischioso): mov ax, semaforo ; semaforo word 10001000b shr ax, 8 ; CF = 1 ; in modalit reale shift di 1 153 / 254 Elaborazione condizionata Istruzioni di bit testing / 2 - Esempio .model small .stack 100h .data semaforo byte 10001000b .code start: mov dl, semaforo mov cx, 7 L1: shr dl, 1 loop L1 mov ah, 02h int 21h mov ax, 4c00h int 21h end start 154 / 254 Elaborazione condizionata Istruzioni di bit testing / 3 L’istruzione BTC (bit test and complement) seleziona il bit n nel primo operando, lo copia nel Carry flag e lo complementa BTC bitbase, n Gli operandi consentiti sono gli stessi dell’istruzione BT. .data semaforo word 10001000b .code ... BTC semaforo, 6 ; CF = 0, semaforo = 11001000b 155 / 254 Elaborazione condizionata Istruzioni di bit testing / 4 L’istruzione BTR (bit test and reset) seleziona il bit n nel primo operando, lo copia nel Carry flag e lo azzera BTR bitbase, n Gli operandi consentiti sono gli stessi dell’istruzione BT. .data semaforo word 10001000b .code ... BTR semaforo, 7 ; CF = 1, semaforo = 00001000b 156 / 254 Elaborazione condizionata Istruzioni di bit testing / 5 L’istruzione BTS (bit test and set) seleziona il bit n nel primo operando, lo copia nel Carry flag e lo setta BTS bitbase, n Gli operandi consentiti sono gli stessi dell’istruzione BT. .data semaforo word 10001000b .code ... BTS semaforo, 6 ; CF = 1, semaforo = 11001000b 157 / 254 Aritmetica dei numeri interi Operatori di traslazione e rotazione SHL (shift left) SHR (shift right) SAL (shift arithmetic left) SAR (shift arithmetic right) ROL (rotate left) ROR (rotate right) RCL (rotate carry left) RCR (rotate carry right) Lo shift logico riempie di zeri le posizioni che si liberano, mentre lo shift aritmetico riempie le posizioni che si liberano con il bit di segno del numero soggetto a traslazione 158 / 254 Operatori di traslazione e rotazione Istruzione SHL Effettua uno shift logico a sinistra ponendo a zero il bit meno significativo Il bit più significativo viene spostato nel Carry flag, sovrascrivendone il contenuto SHL destination, count Gli operandi consentiti sono: SHL SHL SHL SHL reg, mem, reg, mem, imm8 imm8 CL CL 159 / 254 Operatori di traslazione e rotazione Istruzione SHL / 2 I processori 8086 e 8088 richiedono che imm8 sia uguale a 1 nei modelli più recenti imm8 pu assumere qualsiasi valore CL può contenere un intero utilizzato come contatore (su qualsiasi processore) Le stesse regole si applicano anche agli altri operatori di traslazione e rotazione mov bl, 8Fh shl bl, 1 ; bl = 1001111b ; bl = 0011110b , CF = 1 160 / 254 Operatori di traslazione e rotazione Istruzione SHL / 3 SHL viene utilizzato per la moltiplicazione veloce per potenze di 2 Infatti, shiftare di n bit a sinistra significa moltiplicare l’operando per 2n Per esempio: mov shl ... mov shl dl, 5 dl, 1 ; dl = 00000101 ; dl = 00001010 5 10 dl, 10 ; dl = 00001010 dl, 2 ; dl = 00101000 10 40 161 / 254 Operatori di traslazione e rotazione Istruzione SHR Effettua uno shift logico a destra ponendo a zero il bit pi significativo Il bit meno significativo viene spostato nel Carry flag, sovrascrivendone il contenuto SHR destination, count mov al, 0d0h shr al, 1 ; al = 11010000b ; al = 01101000b, CF = 0 162 / 254 Operatori di traslazione e rotazione Istruzione SHR / 2 SHR viene utilizzato per la divisione veloce per potenze di 2 Infatti, shiftare di n bit a destra significa dividere l’operando per 2n Per esempio: mov shr ... mov shr dl, 32 dl, 1 ; dl = 00100000 ; dl = 00010000 al, 01000000b al, 3 32 16 ; al = 64 ; al = 00001000b 8 163 / 254 Operatori di traslazione e rotazione Istruzioni SAL e SAR L’istruzione SAL effettua uno shift aritmetico a sinistra identica a SHL L’istruzione SAR effettua uno shift aritmetico a destra La sintassi è identica a quella delle istruzioni SHL e SHR mov sar ... mov sar al, 0f0h al, 1 ; al = 11110000b ; al = 11111000b (-16) (-8) CF = 0 dl, -128 dl, 3 ; dl = 10000000b ; dl = 11110000b (-128) (-16) 164 / 254 Operatori di traslazione e rotazione Istruzione ROL L’istruzione ROL effettua una rotazione di tutti i bit verso sinistra Il bit più significativo viene copiato nel Carry flag Si noti che nella rotazione, a differenza dello shift, non si ha perdita di bit La sintassi è identica a quella delle istruzioni SHL e SHR mov rol rol rol ... mov rol al, al, al, al, 40h 1 1 1 al, 26h al, 4 ; ; ; ; al al al al = = = = 01000000b 10000000b 00000001b 00000010b CF = 0 CF = 1 CF = 0 ; al = 62h 165 / 254 Operatori di traslazione e rotazione Istruzione ROR L’istruzione ROR effettua una rotazione di tutti i bit verso destra Il bit meno significativo viene copiato nel Carry flag La sintassi è identica a quella delle istruzioni SHL e SHR mov al, 01h ror al, 1 ror al, 1 ; al = 00000001b ; al = 10000000b ; al = 01000000b CF = 1 CF = 0 166 / 254 Operatori di traslazione e rotazione Istruzione RCL L’istruzione RCL effettua una rotazione di tutti i bit verso sinistra, copia il Carry flag nel bit meno significativo e copia il bit più significativo nel Carry flag L’istruzione CLC resetta il Carry flag clc mov bl, 88h rcl bl, 1 rcl bl, 1 ; ; ; ; CF bl bl bl = = = = 0 10001000b 00010000b 00100001b CF = 0 CF = 1 CF = 0 167 / 254 Operatori di traslazione e rotazione Istruzione RCR L’istruzione RCR effettua una rotazione di tutti i bit verso destra, copia il Carry flag nel bit più significativo e copia il bit meno significativo nel Carry flag L’istruzione STC setta il Carry flag stc mov ah, 10h rcr ah, 1 ; CF = 1 ; ah = 00010000b ; ah = 10001000b CF = 1 168 / 254 Operatori di traslazione e rotazione Moltiplicazione binaria L’istruzione SHL consente di effettuare efficientemente moltiplicazioni per potenze di 2 Qualsiasi numero binario può essere espresso come la somma di potenze di 2 Per esempio, la moltiplicazione di AX per 36 può essere vista come la moltiplicazione per 32 + 4, quindi: AX * 36 = AX * ( 32 + 4) = AX * 32 + AX * 4 mov mov shl shl add ax, bx, ax, bx, ax, 123 ax 5 2 bx 169 / 254 Operatori di traslazione e rotazione Isolamento di stringhe di bit La funzione MS-DOS 57h restituisce la data di un file nel registro DX I bit 0-4 indicano il giorno (1-31), i bit 5-8 indicano il mese, i bit 9-15 l’anno La data 20-05-2010 viene quindi indicata come (l’anno viene riferito al 1980, cioè 30): 0011110 0101 01010 30 05 20 Per estrarre il giorno: mov al, dl and al, 00011111b mov giorno, al 170 / 254 Moltiplicazione e divisione Istruzione MUL L’istruzione MUL moltiplica un operando a 8, 16 o 32 bit per il contenuto dei registri AL, AX o EAX (rispettivamente) MUL accetta quindi un solo operando, con formati: MUL r/m8 MUL r/m16 MUL r/m32 Il prodotto è contenuto in un registro doppio rispetto alle dimensioni del moltiplicando e del moltiplicatore, per garanzia dagli overflow Moltiplicando AL AX EAX Moltiplicatore r/m8 r/m16 r/m32 Prodotto AX DX:AX EDX:EAX 171 / 254 Moltiplicazione e divisione Istruzione MUL / 2 L’istruzione MUL setta i flag Carry (CF) e Overflow (OF) soltanto se la metà superiore del prodotto non è zero Per esempio, quando AX viene moltiplicato per un operando a 16 bit, il prodotto viene memorizzato in DX:AX Se DX non è uguale a zero, il Carry flag viene settato mov al, 5h mov bl, 10h mul bl mov ax, var1 mul var2 ; CF = 0 ; var1 word 2000h ; var2 word 0100h; CF = 1 172 / 254 Moltiplicazione e divisione Istruzione IMUL L’istruzione IMUL effettua la moltiplicazione tra interi con segno L’unica differenza con MUL consiste nel preservare il segno del prodotto Vengono settati i flag Carry e Overflow quando il registro che contiene la parte più significativa del prodotto non è un’estensione di segno della parte meno significativa 173 / 254 Moltiplicazione e divisione Istruzione IMUL / 2 ; 1. moltiplicazione con segno 48 * 4 mov al, 48 mov bl, 4 imul bl ; ax = 00c0h, OF = 1 ; (ah non e’ un’estensione di segno di al) ; 2. moltiplicazione con segno -4 * 4 mov al, -4 mov bl, 4 imul bl ; ax = fff0h, OF = 0 ; (ah e’ un’estensione di segno di al) ; 3. moltiplicazione con segno 48 * 4 mov ax, 48 mov bx, 4 imul bx ; dx:ax = 000000c0h, OF = 0 ; (dx e’ un’estensione di segno di ax) 174 / 254 Moltiplicazione e divisione Istruzione DIV L’istruzione DIV effettua la divisione di interi a 8, 16 o 32 bit Viene fornito un solo operando, il divisore I formati accettati sono: DIV r/m8 DIV r/m16 DIV r/m32 Il risultato è memorizzato secondo il seguente schema: Dividendo AX DX:AX EDX:EAX Divisore r/m8 r/m16 r/m32 Quoziente AL AX EAX Resto AH DX EDX 175 / 254 Moltiplicazione e divisione Istruzione DIV / 2 mov ax, 0083h mov bl, 2 div bl ; al = 41h, ah = 01h mov mov mov div dx, 0 ax, 8003h cx, 100h cx ; ax = 0080h, dx = 0003h 176 / 254 Moltiplicazione e divisione Istruzioni di conversione L’istruzione CBW (Convert Byte to Word) estende il bit di segno di AL nel registro AH L’istruzione CWD (Convert Word to Double) estende il bit di segno di AX nel registro DX L’istruzione CDQ (Convert Double to Quad) estende il bit di segno di EAX nel registro EDX Questo preserva il segno del numero .data bvar sbyte -101 .code mov al, bvar cbw ; 9bh ; al = 9bh ; ax = ff9bh 177 / 254 Moltiplicazione e divisione Istruzioni di conversione / 2 .data wvar sword -101 .code mov ax, wvar cwd .data dvar sdword -101 .code mov eax, dvar cdq ; ff9bh ; ax = ff9bh ; dx:ax = ffffff9bh ; ffffff9bh ; edx:eax = ffffffffffffff9bh 178 / 254 Moltiplicazione e divisione Istruzione IDIV L’istruzione IDIV effettua la divisione di interi con segno Gli operandi sono gli stessi dell’istruzione DIV Quando si effettua la divisione, bisogna prima estendere il segno del dividendo nel secondo registro (ah per la divisione a 8 bit, dx a 16bit) mov al, bvar cbw mov bl, 5 idiv bl ; ; ; ; dividendo (bvar sbyte -48) estensione del segno in ah divisore al = -9, ah = -3 mov ax, wvar cwd mov bx, 256 idiv bx ; ; ; ; dividendo (wvar sword -5000) estensione del segno in dx divisore quoziente ax = -19, resto dx = -136 179 / 254 Moltiplicazione e divisione Overflow di divisione Se una divisione produce un quoziente troppo grande per essere contenuto nell’operando destinazione, viene generato un divide overflow Questo provoca un interrupt di CPU e la terminazione del programma Per esempio: mov ax, 1000h mov bl, 10h div bl ; al = 100h IMPOSSIBILE mov ax, dividendo mov bl, 0 div bl 180 / 254 Moltiplicazione e divisione Overflow di divisione / 2 Una soluzione potrebbe essere l’utilizzo di registri più grandi Ma non si tratta di una soluzione che garantisce in tutti i casi Molto meglio verificare sempre prima che, almeno, il divisore non sia nullo mov ax, dividendo mov bl, divisore cmp bl, 0 je DivZero div bl ... divZero: ; messaggio di errore per tentata divisione per zero 181 / 254 Moltiplicazione e divisione Espressioni aritmetiche var4 = (var1 + var2) * var3 mov ax var1 add ax, var2 mul var3 jc overflow mov var4, ax jmp prossimo overflow: ; messaggio di errore per overflow 182 / 254 Moltiplicazione e divisione Espressioni aritmetiche / 2 var4 = (var1 * 5) / (var2 - 3) mov mov mul mov sub div mov ax var1 bx, 5 bx bx, var2 bx, 3 bx var4, bx 183 / 254 Moltiplicazione e divisione Espressioni aritmetiche / 3 var4 = (var1 * -5) / (-var2 % var3) mov ax, var2 neg ax cbw idiv var3 mov bx, dx mov ax -5 imul var1 idiv bx mov var4, dx 184 / 254 Moltiplicazione e divisione Addizione e sottrazione in precisione estesa Permettono di sommare e sottrarre numeri con dimensione (quasi) illimitata a tale scopo si utilizzano le istruzioni ADC (Add with Carry) e SBB (Sub with Borrow) L’istruzione ADC somma l’operando sorgente e il contenuto del Carry flag ad un operando destinazione I formati consentiti sono identici a quelli dell’istruzione MOV ADC ADC ADC ADC ADC reg, mem, reg, mem, reg, reg reg mem imm imm 185 / 254 Moltiplicazione e divisione Addizione e sottrazione in precisione estesa / 2 Per esempio: mov mov add adc dl, al, al, dl, 0 0ffh 0ffh 0 ; al = fe ; dl = 01 186 / 254 Moltiplicazione e divisione Addizione e sottrazione in precisione estesa / 3 L’istruzione SBB sottrae un operando sorgente e il valore del Carry flag da un operando destinazione I possibili operandi sono identici a quelli dell’istruzione ADC Per esempio: mov mov sub sbb dx, ax, ax, dx, 1 0 1 0 187 / 254 Moltiplicazione e divisione Aritmetica decimale in formato ASCII La CPU effettua i calcoli in binario, ma è possibile effettuare operazioni aritmetiche su stringhe decimali in formato ASCII A tale scopo sono necessarie istruzioni specifiche che permettano di operare su ogni coppia di cifre ASCII Si consideri per esempio il numero 3402, che può essere rappresentato come: Formato unpacked: 03 04 00 02 Formato ASCII : 33 34 30 32 L’aritmetica in formato ASCII è lenta perchè viene effettuata cifra a cifra, ma consente di operare su grandi numeri Infatti i numeri vengono in effetti visti come stringhe di caratteri 188 / 254 Moltiplicazione e divisione Aritmetica decimale in formato ASCII / 2 L’istruzione AAA (ASCII adjust after addition) sistema il risultato binario di un’istruzione ADD o ADC Il risultato presente nel registro AL viene reso consistente con la rappresentazione ASCII Per esempio: mov ah, 0 mov al, ’8’ add al, ’2’ aaa or ax, 3030h ; ; ; ; ax ax ax ax = = = = 0038h 006ah 0100h 3130h = ’10’ 189 / 254 Moltiplicazione e divisione Aritmetica decimale in formato ASCII / 3 L’istruzione AAS (ASCII adjust after subtraction) sistema il risultato binario di un’istruzione SUB o SBB Il risultato presente nel registro AL viene reso consistente con la rappresentazione ASCII La correzione è necessaria soltanto quando la sottrazione produce un risultato negativo Per esempio: mov ah, 0 mov al, var1 sub al, var2 aas pushf or al, 30h popf ; var1 byte ’8’; ax = 0038h ; var2 byte ’9’; ax = 00ffh ; ax = ff09h ; ax = ff39h 190 / 254 Moltiplicazione e divisione Aritmetica decimale in formato ASCII / 4 L’istruzione AAM (ASCII adjust after multiplication) sistema il risultato binario di un’istruzione MUL La moltiplicazione deve essere effettuata su numeri decimali unpacked, cioè non su cifre ASCII Per esempio: .data val byte 05h, 06h .code mov bl, val mov al, [val+1] mul bl aam ; ; ; ; primo operando secondo operando ax = 001eh ax = 0300h 191 / 254 Moltiplicazione e divisione Aritmetica decimale in formato ASCII / 5 L’istruzione AAD (ASCII adjust before division) sistema il dividendo decimale unpacked in AX prima di una divisione Per esempio: .data quoziente byte resto byte .code mov ax, 0307h aad mov bl, 5 div bl mov quoziente, al mov resto, ah ; dividendo ; ax = 0025h ; divisore 192 / 254 Procedure avanzate Variabili locali Una variabile locale una variabile che viene creata, utilizzata e distrutta all’interno di una procedura Tutte le variabili viste in precedenza sono state definite nel segmento data; vengono definite variabili globali statiche: statiche: ciclo di vita di una variabile uguale alla durata del programma globali: visibili da tutte le procedure del programma Le variabili locali presentano una serie di vantaggi: accesso limitatato, perch soltanto un numero ridotto di istruzioni possono accedervi uso efficiente della memoria, perch al termine della procedura vengono distrutte con conseguente risparmio della memoria la stessa variabile pu apparire in due o pi procedure senza creare conflitti di nome 193 / 254 Procedure avanzate Variabili locali / Direttiva LOCAL La direttiva LOCAL dichiara una o pi variabili locali all’interno di una procedura deve essere posta immediatamente dopo la direttiva PROC (vedi pi avanti) La sua sintassi : LOCAL lista_var La definizione di ogni variabile assume la forma: label: type 194 / 254 Procedure avanzate Variabili locali / Direttiva LOCAL / 2 Per esempio: MySub PROC LOCAL var1: byte ... ENDP BubbleSort PROC LOCAL temp: word, swapflag: byte ... ENDP Merge PROC LOCAL pvec: ptr word ... ENDP 195 / 254 Procedure avanzate Variabili locali / Direttiva LOCAL / 3 Quando si creano variabili locali bisogna fare attenzione all’allocazione dello spazio nello stack In particolare, se le procedure sono annidate, lo spazio necessario sar la somma di tutte le variabili locali Si supponga, per esempio, che Sub1 chiami Sub2, che a sua volta chiama Sub3 Sub1 PROC LOCAL array1[50]: word ... Sub2 PROC LOCAL array2[80]: word ... Sub3 PROC LOCAL array3[300]: byte ; 200 byte ; 160 byte ; 300 byte Quando inizia l’esecuzione di Sub3, le variabili locali occuperanno un totale di 660 byte, pi gli indirizzi di ritorno delle procedure e i registri eventualmente salvati sullo stack 196 / 254 Procedure avanzate Parametri di stack e parametri di registro Definizione: i valori passati ad una procedura da un programma chiamante si dicono argomenti; gli stessi valori, dal punto di vista della procedura invocata, si dicono parametri Esistono due tipi fondamentali di parametri di procedura: i parametri di registro e i parametri di stack I parametri di registro velocizzano l’esecuzione dei programmi, ma bisogna salvare lo stato dei registri prima che vengano caricati con i valori degli argomenti I parametri di stack sono i parametri di una procedura che vengono caricati sullo stack dal programma chiamante 197 / 254 Procedure avanzate Parametri di stack e parametri di registro / 2 Esempio di parametri di registro pusha mov si, offset array mov cx, lengthof array mov bx, type array call Sub popa Esempio di parametri di stack push push push call type array lengthof array offset array Sub 198 / 254 Procedure avanzate Parametri di stack e parametri di registro / 3 La direttiva INVOKE automaticamente effettua il push degli argomenti sullo stack e invoca la procedura INVOKE Sub, offset array, lengthof array, type array I tipi di argomenti che si possono utilizzare con INVOKE sono: Tipo valore immediato espressione intera nome di variabile espressione di indirizzo nome di registro ADDR nome Esempio 10, 300h, offset lista, type array (10 * 20), count lista, array, bvar, wvar [bx + si], [lista + 2] ax, bl, ebx ADDR lista 199 / 254 Procedure avanzate Parametri di stack e parametri di registro / 4 L’operatore ADDR pu essere utilizzato per passare un puntatore quando si invoca una procedura con la direttiva INVOKE Il passaggio di un indirizzo come argomento di una procedura viene detto passaggio per riferimento Per esempio: INVOKE Subarray, ADDR vec In modalit reale, ADDR restituisce un offset a 16 bit .data vec byte 50 dup(?) .code INVOKE Subarray, ADDR vec 200 / 254 Procedure avanzate Direttiva PROC La direttiva PROC permette di dichiarare una procedura seguita da una lista di parametri La sintassi : label PROC, parametro_1, parametro_2, ... parametro_n Oppure: label PROC, parametro_1, parametro_2, ..., parametro_n 201 / 254 Procedure avanzate Direttiva PROC / 2 Un singolo parametro ha la seguente sintassi: parametro: type parametro un nome arbitrario che si assegna al parametro la sua visibilit limitata alla procedura corrente lo stesso nome di parametro pu essere utilizzato in pi procedure, ma non pu essere il nome di una variabile globale o di una label di codice il tipo di dato pu essere: byte, sbyte, word, sword, dword, sdword, oppure ptr byte, ptr sbyte, ..., ptr sdword 202 / 254 Procedure avanzate Direttiva PROC / 3 Somma PROC, val1: dword, val2: dword ... Somma ENDP Subvec PROC, pvec: ptr byte ... Subvec ENDP ReadFile PROC, pbuffer: ptr byte local fileHandle: dword ... ReadFile ENDP 203 / 254 Procedure avanzate Direttiva PROTO La direttiva PROTO crea un prototipo per una procedura esistente Un prototipo dichiara il nome di una procedura e la lista dei parametri Permette di invocare una procedura senza bisogno di definirla MASM richiede un prototipo per ogni procedura invocata mediante istruzione INVOKE PROTO deve precedere sempre l’istruzione INVOKE relativa 204 / 254 Procedure avanzate Direttiva PROTO Le due possibili implementazioni sono: Sub1 PROTO INVOKE Sub1 ; prototipo ; invocazione Sub PROC ... Sub ENDP ; codifica Sub PROC ... Sub ENDP INVOKE Sub1 ; codifica ; invocazione 205 / 254 Procedure avanzate Operatore USES L’operatore USES, utilizzato insieme alla direttiva PROC permette di elencare i nomi di tutti i registri modificati nel corso dell’esecuzione di una procedura Le conseguenze dell’utilizzo di USES sono: generare istruzioni push all’inizio della procedura generare istruzioni pop alla fine della procedura Per esempio: VecSum PROC mov ax, L1: add ax, add si, loop L1 ret VecSUM ENDP USES si, cx 0 [si] 4 206 / 254 Procedure avanzate Operatore USES / 2 Esempio (somma di due vettori) VecSum proc uses si, cx, ptrvec: ptr word, sizevec: word mov si, mov cx, cmp cx, je L2 mov ax, L1: add ax, add si, loop L1 L2: ret SumVec endp ptrvec sizevec 0 0 [si] 2 207 / 254 Procedure avanzate Passaggio di argomenti per valore Un argomento viene passato ad una procedura per valore quando viene passata una copia della variabile Questa tecnica preserva il valore originale della variabile Funzionamento: la variabile viene copiata sullo stack dalla procedura chiamante la procedura invocata recupera il valore dallo stack e lo utilizza 208 / 254 Procedure avanzate Passaggio di argomenti per valore / 2 Esempio: .data var word 1000h .code main PROC INVOKE Sub1, var exit main ENDP Sub1 PROC dato: word mov dato, 0 ret Sub1 ENDP 209 / 254 Procedure avanzate Passaggio di argomenti per riferimento Alla procedura viene passato l’indirizzo di una variabile La procedura invocata ha la possibilit di modificare il valore originale della variabile Come regola generale bisognerebbe utilizzare questa tecnica soltanto quando si vuole che la procedura modifichi il dato trasmesso Eccezione: la trasmissione di strutture dati (array) dovrebbe essere effettuata per riferimento, ma solo per motivi di prestazioni e di occupazione delle risorse 210 / 254 Procedure avanzate Passaggio di argomenti per riferimento / 2 Esempio: .data var word 1000h .code main PROC INVOKE Sub2, addr var exit main ENDP Sub1 PROC datoptr: ptr word mov si, datoptr mov word ptr[si], 0 ret ret Sub2 ENDP 211 / 254 Organizzazione della memoria 212 / 254 Organizzazione della memoria / 2 In modalità reale, i 640K di memoria sono utilizzati sia dal sistema operativo che dai programmi applicativi le locazioni da C0000 a FFFFF sono riservate per la ROM di sistema all’interno dell’area riservata al sistema operativo, i 1024 byte più bassi (da 00000 a 003FF) contengono una tabella di indirizzi a 32 bit denominata tabella dei vettori di interrupt immediatamente dopo, è presente l’area BIOS & DOS area nell’area Software BIOS sono presenti le procedure per la gestione dei dispositivi di I/O (tastiera, disk drive, video, porte di I/O) nell’area DOS Kernel, Device Drivers sono contenuti i buffer e i driver dei dispositivi nell’area Resident command processor è contenuto l’interprete dei comandi, caricato dall’eseguibile command.com 213 / 254 Organizzazione della memoria / 3 I programmi applicativi possono essere caricati in memoria nel primo indirizzo superiore alla parte residene del processore dei comandi e utilizzare tutta la memoria fino all’indirizzo 9FFFF L’area di memoria video (VRAM) inizia alla locazione A0000 quando invece viene utilizzata in modalità color text mode la locazione B8000 contiene tutto il testo correntemente mostrato a schermo Lo schermo si dice memory-mapped, nel senso che ogni riga e colonna dello schermo corrisponde ad un word in memoria Un carattere copiato nella memoria video appare immediatamente sullo schermo 214 / 254 Ridirezione I/O I dispositivi noti come standard input e standard output rappresentano la tastiera per l’input e il video per l’output È possibile ridirigere lo standard input cosı̀ che venga letto da un file o da una porta hardware piuttosto che dalla tastiera lo standard output può essere ridiretto verso un file, una stampante, un dispositivo di I/O Si consideri per esempio un programma prog.exe Può leggere i dati di input da tastiera oppure da un file Nel secondo caso si può scrivere (da linea di comando): prog.exe < prog-in.txt 215 / 254 Ridirezione I/O / 2 Analogamente, è possibile ridirigere lo standard output prog.exe > prog-out.txt Oppure entrambi prog.exe < prog-in.txt > prog-out.txt Si noti che la scelta dei nomi dei file sui quali effettuare la ridirezione del tutto libera! 216 / 254 Ridirezione I/O / 3 E’ possibile utilizzare il simbolo di pipe | perchè l’output di un comando diventi l’input del comando posto a destra della pipe Per esempio: dir | sort L’output del programma sort può essere a sua volta ridiretto (come si potrebbe fare anche per l’input del comando dir): dir | sort > prn 217 / 254 Funzioni di int 21h L’interrupt DOS int 21h presenta numerose funzioni oltre a quelle già viste Una di questa è la funzione 6, che stampa un carattere su standard output mov ah, 6 mov dl, "A" int 21h Si ricordi che: AH = 6, DL = carattere 218 / 254 Funzioni di int 21h / 2 La funzione 40h scrive un array di byte su un file o un dispositivo Si ricordi che: AH = 40h, BX = file o dispositivo (console = 1), CX = numero di byte da scrivere, DX = indirizzo dell’array .data msg "Ciao a tutti" .code mov ah, 40h mov bx, 1 mov cx, lengthof msg mov dx, offset msg int 21h 219 / 254 Funzioni di int 21h / 3 Esempio .model small .stack 100h .data msg byte "Ciao a tutti", 13, 10 .code main PROC mov ax, @data mov ds, ax mov mov mov mov int ah, bx, cx, dx, 21h 40h 1 sizeof msg offset msg mov ax, 4c00h int 21h end main 220 / 254 Funzioni di int 21h / 3a Creazione file con 3ch La funzione 3ch permette di creare/troncare un file Registri DX Descrizione offset filename (ASCIIZ) CX 0 1 2 3 AX 3 4 5 Attributi file Normal Read only Hidden System Codici di errore Path not found No handle available (too many files) Access denied 221 / 254 Funzioni di int 21h / 3b Creazione file con 3ch ;f40-creat.asm .model small .stack 100h .data fh byte "provatxt.txt",0 .code start: mov ax, @data mov ds, ax mov mov mov int dx, offset fh cx, 0 ah, 3ch 21h . . . 222 / 254 Funzioni di int 21h / 3c Apertura file con 3dh La funzione 3dh permette di aprire un file già esistente Registri DX Descrizione offset filename (ASCIIZ) AL 0 1 2 AX 2 3 4 5 0ch Codice di accesso Read Write Read/Write Codici di errore File not found Path does not exist No handle available (too many files) Access denied Access code invalid 223 / 254 Funzioni di int 21h / 3d Apertura file con 3dh ; f40-open.asm .model small .stack 100h .data fh byte "provatxt.txt",0 .code start: mov ax, @data mov ds, ax mov mov mov int . . . dx, offset fh al, 1 ah, 3dh 21h 224 / 254 Funzioni di int 21h / 3e Lettura file con 3fh La funzione 3fh permette di leggere da un file (già esistente) Registri BX Descrizione file handle DX CX AX AX AX offset buffer numero di byte da leggere numero di byte letti Raggiunto EOF Codici di errore Access denied Invalid handle or not open 0 5 6 225 / 254 Funzioni di int 21h / 3f Lettura file con 3fh . . . .data buf byte 50 . . . mov bx, mov ah, mov cx, mov dx, int 21h . . . dup(’+’),"$",’13’,’10’ ax 3fh 9 offset buf 226 / 254 Funzioni di int 21h / 3g Scrittura su file con 40h La funzione 40h permette di scrivere su un file (già esistente) Registri BX Descrizione file handle DX CX AX AX AX offset buffer numero di byte da scrivere numero di byte scritti Disk full Codici di errore Access denied Invalid handle or not open 0 5 6 227 / 254 Funzioni di int 21h / 3h Scrittura su file con 40h . . . .data msg byte "Ciao a tutti" . . . mov bx, ax mov ah, 40h mov cx, lengthof msg mov dx, offset msg int 21h . . . 228 / 254 Funzioni di int 21h / 4 La funzione 6 legge un carattere dallo standard input senza attendere A differenza della funzione 1 non si ha attesa in caso di buffer vuoto e non si ha echo del carattere digitato mov ah, 6 mov dl, 0ffh int 21h jz salta mov char, al salta: 229 / 254 Funzioni di int 21h / 5 La funzione 0ah legge una stringa bufferizzata dallo standard input terminata da Enter L’invocazione di questa funzione richiede che si passi un puntatore ad una struttura di input avente il seguente formato: count = 80 KEYBOARD struct maxInput byte count inputCount byte ? buffer byte count dup(?) KEYBOARD ends ; numero max di caratteri in input ; conta effettiva caratteri ; contenitore caratteri di input 230 / 254 Funzioni di int 21h / 6 Il campo maxInput specifica il numero massimo di caratteri da inserire, compreso Enter E’ possibile utilizzare Backspace per cancellare caratteri I caratteri non ASCII (per esempio, i tasti funzione e le frecce) vengono ignorati .data kbd KEYBOARD <> .code mov ah, 0ah mov dx, offset kbd int 21h 231 / 254 Funzioni di int 21h / 7 La funzione 0ah viene spesso utilizzata in congiunzione con la funzione 0bh, che restituisce lo stato del buffer di input Se presente un carattere AL = 0ffh, altrimenti AL = 0 mov ah, 0bh int 21h cmp al, 0 je salta ; procedura di acquisizione del carattere salta: 232 / 254 Funzioni di int 21h / 8 La funzione 3fh legge un array di byte da un file o da una dispositivo Può essere utilizzata per l’input da tastiera quando il dispositivo in BX viene posto a zero .data inputbuffer byte 127 dup(0) bytesread word ? .code mov ah, 3fh mov bx, 0 mov cx, lengthof inputbuffer mov dx, offset inputbuffer int 21h mov byteread, ax 233 / 254 Funzioni di int 21h / 9 Eventuali caratteri in eccesso rimangono nel buffer Invocazioni successive provocano la lettura dei dati dal buffer e non dalla tastiera, quindi è bene vuotare il buffer cleanbuff proc .data unbyte byte ? .code pusha L1: mov ah, 3fh mov bx, 0 mov cx, 1 mov dx, offset unbyte int 21h cmp unbyte, 0ah jne L1 popa ret cleanbuff endp 234 / 254 Funzioni di int 21h / 10 Funzioni date/time La funzione 2ah permette di ottenere la data di sistema, mentre la funzione 2bh ne permette la regolazione mov int mov mov mov mov ... mov mov mov mov int cmp jne ah, 2ah 21h anno, cx mese, dh giorno, dl giornosett, al ah, 2bh cx, nuovoanno dh, nuovomese dl, nuovogiorno 21h al, 0 fallita 235 / 254 Funzioni di int 21h / 11 Funzioni date/time Analogamente, la funzione 2ch permette di ottenere l’ora di sistema, e la funzione 2dh ne permette la regolazione mov int mov mov mov ... mov mov mov mov int cmp jne ah, 2ch 21h ora, ch min, cl sec, dh ah, 2bh ch, new_ora cl, new_min dh, new_sex 21h al, 0 fallita 236 / 254 Funzioni di int 21h / 12 Funzioni di I/O da file e directory L’interrupt int 21h fornisce una (lunga) serie di servizi per la gestione dell’I/O di file e directory Le funzioni utilizzate più di frequente sono: Funzione 716Ch 3Eh 42h 5706h Descrizione Crea o apre un file Chiude l’handle di un file Sposta il puntatore al file Ottiene data e ora di creazione del file 237 / 254 Funzioni di int 21h / 13 Funzioni di I/O da file e directory File e directory sono identificati mediante interi a 16 bit denominati handle Esistono 5 handle predefiniti Ad eccezione dell’handle 2 (errore) permettono tutti la ridirezione al prompt dei comandi Gli handle disponibili in qualunque momento sono: Numero 0 1 2 3 4 Descrizione Tastiera (standard input) Console (standard output) Errore Dispositivo ausiliario Stampante 238 / 254 Funzioni di int 21h / 14 Funzioni di I/O da file e directory Tutte le funzioni di I/O generano, in caso di errore, un codice restituito nel registro AX: Codice 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F Descrizione Invalid function number File not found Path not found Too many open files Access denied Invalid handle Memory control blocks destroyed Insufficient memory Invalid memory block address Invalid environment Invalid format Invalid access code Invalid data Reserved Invalid drive was specified 239 / 254 Funzioni di int 21h / 15 Funzioni di I/O da file e directory Continua: Codice 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F Descrizione Attempt to remove current directory Not same device No more files Diskette write-protected Unknown unit Drive not ready Unknown command Data error (CRC) Bad request structure length Seek error Unknown media type Sector not found Printer out of paper Write fault Read fault General failure 240 / 254 Funzioni di int 21h / 16 Funzioni di I/O da file e directory La funzione 716Ch permette di creare un nuovo file o di aprirne uno esistente Lo stato dei registri è: Registro AX BX CX DX SI Stato 716Ch 0 = read, 1 = write, 2 = read/write 0 = normal, 1 = read-only, 2 = hidden 3 = system, 8 = volume ID, 20h = archive 1 = open, 2 = truncate, 10h = create offset filename 241 / 254 Funzioni di int 21h / 16bis Funzioni di I/O da file e directory Esempio: mov ax, 716ch mov bx, 0 mov cx, 0 mov dx, 1 mov si, offset filename int 21h jc fallita mov handle, ax mov azione, cx ; read-only ; attributo normale ; file esistente ; handle del file 242 / 254 Funzioni di int 21h / 18 Funzioni di I/O da file e directory Esempio n. 2 (creazione nuovo file o troncamento file esistente): mov ax, 716ch mov bx, 2 mov cx, 0 mov dx, 10h+02h mov si, offset filename int 21h jc fallita mov handle, ax mov azione, cx ; read-write ; attributo normale ; creazione + troncamento ; handle del file 243 / 254 Funzioni di int 21h / 19 Funzioni di I/O da file e directory Esempio n. 3 (creazione nuovo file o fallimento se esistente): mov ax, 716ch mov bx, 2 mov cx, 0 mov dx, 10h mov si, offset filename int 21h jc fallita mov handle, ax mov azione, cx ; read-write ; attributo normale ; creazione ; handle del file 244 / 254 Funzioni di int 21h / 20 Funzioni di I/O da file e directory La funzione 3eh chiude un handle di file Il contenuto del buffer di scrittura viene scritto su disco Il registro BX deve contenere il file handle mov ah, 3eh mov bx, filehandle int 21h jc fallita 245 / 254 Funzioni di int 21h / 21 Funzioni di I/O da file e directory La funzione 42h sposta il puntatore alla posizione di un file aperto Il registro BX deve contenere il file handle Il registro CX:DX deve contenere il valore dell’offset (32 bit) Il contenuto del registro AL pu essere: 0: offset dall’inizio del file 1: offset dalla posizione corrente 2: offset dalla fine del file mov mov mov mov mov int ah, al, bx, cx, dx, 21h 42h 0 filehandle offsethi offsetlo 246 / 254 Funzioni di int 21h / 22 Funzioni di I/O da file e directory La funzione 5706h fornisce la data e l’ora di creazione di un file Ovviamente, il file deve essere aperto Il registro BX deve contenere il file handle mov ah, 5706h mov bx, filehandle int 21h jc errore mov data, dx mov ora, cx mov msec, si 247 / 254 Funzioni di int 21h / 23 Funzioni di I/O da file e directory - Lettura e copia di un file di testo .data buffersize = 5000 ifile byte "ifile.txt",0 ofile byte "ofile.txt",0 ihandle word ? ohandle word ? buffer byte buffersize dup(?) bytesread word ? .code main PROC mov ax, @data mov ds, ax mov ax, 716ch ; apertura file di input mov bx, 0 ; read-only mov cx, 0 ; normal mov dx, 1 ; open mov si, offset ifile int 21h jc esci mov ihandle, ax 248 / 254 Funzioni di int 21h / 24 Funzioni di I/O da file e directory - Lettura e copia di un file di testo / 2 mov ah, 3fh mov bx, ihandle mov cx, buffersize mov dx, offset buffer int 21h jc esci mov bytesread, ax ; ; ; ; mov ah, mov bx, mov cx, mov dx, int 21h jc esci ; scrittura su file o device ; console 40h 1 bytesread offset buffer mov ah, 3eh mov bx, ihandle int 21h jc esci lettura file di input handle file di input max byte da leggere puntatore al buffer ; chiusura file 249 / 254 Funzioni di int 21h / 24 Funzioni di I/O da file e directory - Lettura e copia di un file di testo / 3 mov ax, 716ch mov bx, 1 mov cx, 0 mov dx, 12h mov si, offset ofile int 21h jc esci mov ohandle, ax mov ah, mov bx, mov cx, mvo dx, int 21h jc esci 40h ohandle bytesread offset buffer ; ; ; ; creazione/apertura file write-only normal creazione/troncamento ; scrittura su file o device ; file handle mov ah, 3eh mov bx, ohandle int 21h 250 / 254 Funzioni di int 21h / 24 Funzioni di I/O da file e directory - Lettura e copia di un file di testo / 4 esci: mov mov int mov mov int dl, ah, 21h dl, ah, 21h 13 2h 10 2h mov ax, 4c00h int 21h main endp 251 / 254 Esempio Conversione di un numero da base decimale a base binaria .model small .stack 100h .data ni byte 10 dup(?) nf byte 10 dup(?) .code start: mov ax, @data mov ds, ax mov mov mov mov si, bl, ax, al, 0 2 0 29 . . . Li: div bl mov ni[si], ah or ni[si], 30h inc si cmp al, 2 jc Lf mov ah, 0 jmp Li Lf: mov ni[si], al or ni[si], 30h . . . 252 / 254 Esempio Conversione di un numero da base decimale a base binaria (cont.) . . . mov di, 0 Lv: mov bl, ni[si] mov nf[di], bl mov bh, nf[di] inc di dec si cmp si, 0 jge Lv . . . . . . mov mov int mov int ah, 09h dx, offset ni 21h dx, offset nf 21h mov ax, 4c00h int 21h end start 253 / 254 Bibliografia K. Irvine, Assembly Language for Intel-Based Computers, 5th edition - Pearson/Prentice Hall - ISBN: 0-13-238310 - 1 Lyla B. Das, The x86 Microprocessor - Architecture, Programming and Interfacing, Pearson - ISBN: 978-81-317-3246-5 254 / 254