Vediamo più nel dettaglio il costrutto if/else in assembly e approfondiamo il concetto di “salto”
Già nell’esempio 13 abbiamo visto il funzionamento dell’if, costrutto che in assembly si traduce con una costruzione inversa della condizione con l’uscita dalla if attraverso un salto di codice verso una label, una etichetta che contraddistingue una riga di codice fuori dalla condizione. L’else per certi versi rafforza questa necessita. Riprendiamo l’esempio precedente modificandolo un po’ trasformandolo in un “trova massimo tra due numeri letti in input”.
cin >>x;
cin >>y;
if (x <= y)
{
cout<<"x più piccolo";
//devi saltare fuori per non fare l'else
}
else
{
cout<<"x è più grande";
}
In SASM scriviamo questo frammento:
%include “io.inc”
section .data
max dd 0
section .text
global CMAIN
CMAIN:
mov ebp, esp ;for correct debugging
GET_DEC 4, eax ;la nostra x
GET_DEC 4, edx ;la nostra y
cmp eax, edx
jg else
PRINT_STRING “x è più piccolo di y”
mov [max], edx
jmp fuoridallif ;forzo l’uscita per non eseguire il blocco else:
else: ;else è un’etichetta non una parola chiave!
PRINT_STRING “x è più grande di y”
mov [max], eax
fuoridallif:
NEWLINE
PRINT_DEC 4, max
xor eax, eax
ret
Proviamo ad analizzare frammento per frammento.
Dichiariamoci una variabile da 32 (o 64 bit) bit che chiamiamo max, dove inseriremo il risultato finale. Le prime due righe GET_DEC si occupano di leggere due numeri dalla finestra laterale di input. Scriviamoci sullo stesso rigo due numeri di esempio con uno spazio tra i due. A questo punto dobbiamo inserire un blocco condizionale, il classico if.
L’operatore if in assembly si indica con cmp, contrazione della parola “compare”, che prende due valori, ovvero per noi i registri eax, edx che contengono le nostre x ed y, rispettivamente. Ora bisogna cercare di imporre una condizione come il <= dell’esempio in c. Come notato nella lezione/post precedente, il trucco dell’assembly è quello di imporre una condizione “inversa” ovvero se voglio controllare x<=y devo verificare x > y per imporre il salto al codice opportuno. Ed infatti con l’operatore jg, jumper greater, salta se più grande all’etichetta che abbiamo chiamato else:. Se non viene eseguito il salto, l’assembler scende al codice immediatamente sotto che corrisponde al caso “x più piccolo”, che stampa una stringa a video e mette nella variabile max il valore del registro opportuno. A questo punto dobbiamo risaltare per non eseguire il codice sotto corrispondente all’else ed andiamo col comando jmp, jump all’etichetta fuoridallif. Se dal jg siamo saltati all’etichetta else, andiamo a stampare il messaggio sotto ed aggiornare il valore della variabile max. Il codice fuori quindi dal costrutto if/else, che sia eseguito dal salto o dall’uscita dell’else, semplicemente stampa una linea vuota con NEWLINE e il contenuto della variabile max.
Lo stesso esercizio visto con EMU8086 con i registri a 16bit è del tutto analogo. Ricordiamo che la funzione per semplificare la lettura da tastiera inserisce il numero letto direttamente nel registro CX, quindi bisogna aver premura di spostare il valore in un altro registro per leggere il successivo, che altrimenti andrebbe a sovrascrivere il primo. Le funzioni per if/else sono uguali a quelle commentate precedentemente. Tenete presente che il valore max che ci mettiamo da parte nella variabile, per essere stampato, deve essere riportato nel registro AX che è il parametro di default che viene preso dalla istruzione PRINT_NUM.
include ‘emu8086.inc‘
.MODEL SMALL
.STACK
.DATA
max dw 0
.CODE
.STARTUP
call SCAN_NUM
mov ax, cx ; AX sarà la nostra x
call SCAN_NUM
mov dx, cx ; AX sarà la nostra y
cmp ax, dx
jg else
PRINTN ‘x è più piccolo di y’
mov [max], dx
jmp fuoridallif ;forzo l’uscita per non eseguire il blocco else:
else:
PRINTN “x è più grande di y”
mov [max], ax
fuoridallif:
PRINTN ”
mov ax, max
call PRINT_NUM
;mi dichiaro delle funzioni
DEFINE_SCAN_NUM
DEFINE_PRINT_NUM
DEFINE_PRINT_NUM_UNS
.EXIT
END
Ultima modifica 24 Marzo 2023