Le istruzioni dichiarative servono a dichiarare le etichette dati e le etichette istruzioni nei programmi assembly.
Il ruolo e l'importanza di tali etichette è già stato illustrato nei vari esempi di queste dispense; ricordiamo solo che i nomi delle etichette sono «liberi» ma non devono coincidere con parole riservate del linguaggio, devono essere il più possibile significativi e devono essere seguiti dal simbolo «:».
Riguardo alle direttive all'assemblatore vediamo un piccolo elenco delle più usate, con una breve descrizione del loro ruolo:
.ascii o .asciz o .string: queste direttive permettono di dichiarare una o più stringhe separate da virgole; con .ascii le stringhe non sono terminate, con le altre le stringhe sono terminate con l'apposito carattere '\0'; esempio: messaggio: .string "Ciao\n";
.byte: permette di dichiarare un dato lungo un byte; esempio: carattere: .byte 'a';
.word: permette di dichiarare un dato lungo due byte; esempio: val: .word 1234;
.int o .long: permette di dichiarare un dato lungo quattro byte; esempio: val: .long 1000000;
.float e .double: permettono di dichiarare un dato reale macchina in singola precisione (lungo quattro byte) e in doppia precisione (lungo otto byte); a tale proposito occorre osservare che i dati reali vengono gestiti dal coprocessore matematico mediante otto registri interni lunghi 80 bit (viene usata la precisione estesa) denominati st0, st1, .. st7 (in queste dispense non vengono forniti ulteriori approfondimenti sul funzionamento del coprocessore matematico e sulla gestione di questi registri);
.data: definisce l'inizio del segmento dati; segnaliamo che, a differenza di quanto avviene con altri assembly, i registri di segmento vengono caricati automaticamente e il programmatore non deve preoccuparsi di tale aspetto;
.bss: (Block Starded by Symbol) è il segmento contenente i dati non inizializzati, o meglio che vengono allocati in memoria al momento dell'esecuzione e non al momento della traduzione del programma;
.text: definisce l'inizio del segmento istruzioni;
.extern: è una direttiva disponibile ma ignorata; tutti i simboli non definiti sono considerati automaticamente esterni, cioè definiti in un altro modulo sorgente (che dovrà essere uniti a quello corrente nella fase di linking);
.global o .globl: definiscono i simboli globali (esportati ad altri moduli); ognuna prende per argomento il simbolo da rendere globale; esempio: .globl _start;
.include: include un file nella posizione corrente; prende come argomento il nome del file tra virgolette; esempio: .include "stdio.inc";
.rept e .endr: permette di ripetere le dichiarazioni inserite fino alla direttiva .endr il numero di volte indicato come argomento di .rept; esempio:
|
dichiara una etichetta di nome v costituita da 100 elementi di tipo .long ognuno con valore zero.
Suddividiamo le istruzioni esecutive per tipologia:
istruzioni di uso generale:
int: attivazione di un interrupt software; si usa per richiamare delle routine del sistema operativo e ha come operando il valore numerico che identifica l'interrupt;
mov: effettua lo spostamento di valore tra due operandi;
nop: nessuna operazione, non ha operandi;
xchg: scambia il valore tra i due operandi;
istruzioni aritmetiche:
add: somma il primo operando al secondo, il risultato sostituisce il secondo operando;
adc: somma con carry, cioè tenendo conto del riporto dell'operazione precedente;
inc: incremento di una unità dell'operando;
sub: sottrae il primo operando al secondo, il risultato sostituisce il secondo operando;
sbb: sottrazione con borrow, cioè tenendo conto del prestito dell'operazione precedente;
dec: decremento di una unità dell'operando;
neg: negazione dell'operando (complemento a due);
cmp: confronto tra due operandi; è considerata istruzione aritmetica perché il confronto viene fatto con una sottrazione tra i due operandi e verificando se il risultato è zero;
mul: moltiplicazione tra valori naturali; prevede un solo operando;
imul: moltiplicazione tra interi; vale quanto detto per la mul;
div: divisione tra valori naturali; vale quanto detto per la mul;
idiv: divisione tra interi; vale quanto detto per la mul;
istruzioni logiche:
not: operazione di negazione; fa il complemento a uno dei bit dell'operando;
and: effettua l'operazione di «and» tra i bit corrispondenti dei due operandi;
or: effettua l'operazione di «or» tra i bit corrispondenti dei due operandi;
xor: effettua l'operazione di «or esclusivo» tra i bit corrispondenti dei due operandi;
istruzioni per gestire i bit del registro di stato:
cli: azzera il bit if per mascherare le interruzioni;
sti: setta il bit if per abilitare le interruzioni;
clc: azzera il flag cf;
stc: setta il flag cf;
istruzioni di I/O:
in: per leggere dati da una porta di I/O; ha due operandi, la porta e il registro;
out: per scrivere dati su una porta di I/O; ha due operandi, il registro e la porta;
istruzioni di salto; hanno tutte un operando che è l'etichetta istruzioni a cui saltare e devono seguire immediatamente (a parte quella di salto incondizionato) una istruzione il cui effetto sui flag del registro di stato condiziona l'avvenire o meno del salto:
jmp: salto incondizionato;
ja: salta se maggiore per confronti tra numeri naturali;
jae: salta se maggiore o uguale per confronti tra numeri naturali;
jb: salta se minore per confronti tra numeri naturali;
jbe: salta se minore o uguale per confronti tra numeri naturali;
jc: salta se il bit cf è settato;
je: salta se valori uguali;
jg: salta se maggiore per confronti tra numeri interi;
jge: salta se maggiore o uguale per confronti tra numeri interi;
jl: salta se minore per confronti tra numeri interi;
jle: salta se minore o uguale per confronti tra numeri interi;
jnc: salta se il flag cf non è settato;
jne: salta se valori diversi;
jno: salta se non è avvenuto overflow;
jns: salta se il risultato è positivo;
jnz: salta se il risultato non è zero;
jo: salta se è avvenuto overflow;
js: salta se il risultato è negativo;
jz: salta se il risultato è zero;
loop: esegue un ciclo (vedere paragrafo 3.13.3);
istruzioni per l'uso delle procedure:
call: chiamata a una procedura di cui va indicato il nome;
ret: ritorno da una procedura; non ha operandi;
istruzioni per la gestione dello stack:
pop: per prelevare un dato dallo stack e porlo nel registro usato come operando;
popa: per prelevare dallo stack i valori di tutti i registri (non ha operandi);
push: per inserire un dato nello stack prelevandolo dal registro usato come operando.
pusha: per inserire nello stack i valori di tutti i registri (non ha operandi).
Si ricordi che tutte le istruzioni che coinvolgono registri o operandi di memoria si differenziano grazio ad un opportuno suffisso (b, w, l), il cui uso non è obbligatorio ma «fortemente consigliato». |