(Incompleto) MINI CORSO DI ASSEMBLER 8086

(tratto dal sito:http://www.giobe2000.it/Tutorial/Cap01/Pag/cap01-01.asp)
http://ece425web.groups.et.byu.net/stable/labs/8086InstructionSet.html#in

SET DI ISTRUZIONI

Elenchiamo di seguito le istruzioni + utilizzate:

CLD
DIV
JMP
MOV
NEG
REP
STD
IN
OUT
 

Funzioni Statistiche

 

MOV <sorgente>, <destinatario>


Questa istruzione copia l'operando <sorgente> nell'operando <destinatario>. Gli operandi possono avere dimensione di un byte, di una word o di una doubleword. L'istruzione non modifica il registro dei flag.
Le tipologie dei suoi operandi sono:
- tra registro e registro di segmento (
MOV AX, ES)
- tra registro di segmento e memoria (
MOV ES,
[80h])
- tra memoria e registro di segmento (
MOV [80h], ES)
- tra registro e registro (
MOV AX,
BX)
- tra registro e memoria
 (MOV AX, [80h])
- tra memoria e registro.
 (MOV [80h], AL)
- tra registro e costante
 (MOV AL, 02)
- tra memoria e costante.
 (MOV [80h], 1234h)
- tra accumulatore e costante
(MOV AL, 02)
- tra accumulatore e memoria
(MOV AL, DS:[80h])
Questa istruzione ha un rapporto privilegiato con i registri di segmento. Infatti l'unico modo per inizializzarli è tramite registro o memoria, non è possibile, infatti, caricarli direttamente (cioè in modo immediato, con un numero).

mov ax,SEG Messaggio
Questa prima istruzione (vera e propria) sposta in AX il valore del puntatore al Data Segment. Mov è (penso) l'istruzione più usata nei programmi, è quella che permette di spostare dati dalla memoria alla cpu e viceversa. Vediamo quali sono i modi di indirizzamento (cosi si chiamano) possibili:

1. Indirizzamento Immediato

mov ax, 1643
1643 è il dato numerico da mettere in AX.

2. Indirizzamento Assoluto

mov ax, [7563]
7563 è l'indirizzo del dato da mettere in AX.

3. Indirizzamento con Indiretto

mov ax, [si]
Metto in AX il dato puntato da SI (che si trova all'indirizzo SI). Si può anche scrivere:

mov ax, [si+45] ; avete capito cosa fa vero?

 

 

 

J.. - Istruzione di salto


JMP <etichetta>


L' istruzione
JMP salta in modo incondizionato all'istruzione contrassegnata con l'<etichetta>. Contrariamente all'istruzione CALL JMP non salva il contenuto dell'IP. Nessun flag viene alterato.

 

JNS <etichetta>


L' istruzione
JNS salta se non c'è segno nel registro AX. Attenzione: i salti condizionati sono sempre di tipo corto (Short), cioè rispetto alla posizione in cui vengono richiesti, possono puntare le istruzioni poste 127 locazioni in avanti o 128 indietro. Un errore frequente, nelle prime esperienze di programmazione è proprio quello di inserire troppe istruzioni tra il punto di partenza e il punto di arrivo del salto: in queste occasioni l'assemblatore segnala l'errore "error A2053: Jump out of range by nnn byte(s)".

 

JNE <etichetta>


Questa istruzione esegue un salto condizionato dal risultato di una operazione aritmetico-logica tra numeri senza segno. Si evidenzia anche che JNE (salta se non uguale) viene eseguita se [flag di Zero]=0; nessuna flag è invece influenzata da questa istruzione. Il servizio di questa istruzione è identico a quello offerto dalla JNZ (salta se non è zero)
 

LOOP <etichetta>


Salta incondizionatamente CX volte - In pratica prima decrementa il valore di CX e in funzione del risultato:
- se CX=0000 prosegue con l'istruzione successiva.
- se CX è diverso da 0000 salta all'indirizzo corrispondente all'etichetta.
In entrambi i casi modifica il puntatore di codice CS:IP.

Naturalmente perchè sia significativa bisogna predisporre in CX un numero compreso tra 0 e 65535 (=216); con 80386/486 il registro di riferimento diventa ECX, per cui il range diventa a 32 bit.

Attenzione: il numero caricato in CX è quello dei giri (loop, cicli) che si desidera fare; non dimenticare che l'istruzione prima decrementa CX e poi, eventualmente, salta: per questa ragione se, per errore (o coscientemente..) carichi CX con 0000 il programma sembra bloccarsi. Per forza! l'hai obbligato a fare 65535 giri!

 

CLD


L' istruzione
CLD imposta a 0 il flag di direzione DF. Quando il flag DF è a 0 le funzioni di manipolazione delle stringhe agiscono in avanti. L'istruzione corrispondente è STD.

 

DIV <divisore>


Questa istruzione esegue la divisione tra operandi ritenuti interi senza segno; il dividendo (destinazione) è per default:
- AX (numero a 16 bit), se il <divisore> ha la dimensione di un byte; il risultato (quoziente) è lasciato in AL e il resto in AH.
- DX:AX (numero a 32 bit), se il <divisore> ha la dimensione di una word; il risultato (quoziente) è lasciato in AX e il resto in DX.
- EAX:EDX (con 80386/486, numero a 64 bit), se il <divisore> ha la dimensione di una doubleword; il risultato (quoziente) è lasciato in EAX e il resto in EDX.

Il <divisore> non può essere una costante, cioè un dato immediato come, per esempio, in DIV 05H. 
Se gli operandi sono incoerenti il processore si ribella ed esegue un INT 00, una speciale procedura di sistema messa in esecuzione quando viene tentata una divisione per 0; : il programma in esecuzione viene terminato e sul monitor appare la segnalazione d'errore "overflow di divisione".
Questa situazione si può verificare in 2 occasioni:
- il divisore è effettivamente nullo (per esempio DL=00H=0);
- il divisore è troppo piccolo, o meglio il quoziente ottenuto è troppo grande per essere contenuto nel registro destinazione

 

 

STD


L' istruzione
STD imposta a 1 il flag di direzione DF. Quando il flag DF è a 1 le funzioni di manipolazione delle stringhe agiscono indietro. L'istruzione corrispondente è CLD.

 

 

CMP <operando1>, <operando2>

 

L' istruzione CMP si comporta come una sottrazione: sottrae il secondo operando dal primo senza modificare alcun valore. L'unico effetto è quello di impostare i flag di stato in base al risultato calcolato. Ad ogni flag di stato sono associate due istruzione di salto condizionato: una che salta se il flag è a 1 e altra se il flag è a 0. Vediamo un esempio:

 

ESEMPIO FUNZIONAMENTO CMP CREA CON: DEBUG<CMP.TXT
C:\trans>debug cmp.com
-
u 100 ld
168C:0100 B81000 MOV AX,0010
168C:0103 3D0900 CMP AX,0009
168C:0106 3D1000 CMP AX,0010
168C:0109 3D1100 CMP AX,0011
168C:010C C3     RET
-
t

AX=
0010 BX=0000 CX=000D DX=0000 SP=FFFE BP=0000 SI=0000 DI=0000
DS=17B1 ES=17B1 SS=17B1 CS=17B1 IP=0103 NV UP EI PL NZ NA PO NC
17B1:0103 3D0900
CMP AX,0009
-
t

AX=0010 BX=0000 CX=000D DX=0000 SP=FFFE BP=0000 SI=0000 DI=0000
DS=17B1 ES=17B1 SS=17B1 CS=17B1 IP=0106 NV UP EI
PL NZ AC PO NC
17B1:0106 3D1000
CMP AX,0010
-t

AX=0010 BX=0000 CX=000D DX=0000 SP=FFFE BP=0000 SI=0000 DI=0000
DS=17B1 ES=17B1 SS=17B1 CS=17B1 IP=0109 NV UP EI
PL ZR NA PE NC
17B1:0109 3D1100
CMP AX,0011
-t

AX=0010 BX=0000 CX=000D DX=0000 SP=FFFE BP=0000 SI=0000 DI=0000
DS=17B1 ES=17B1 SS=17B1 CS=17B1 IP=010C NV UP EI
NG NZ AC PE CY
17B1:010C C3     RET
 
a
mov AX,10
cmp AX,9
cmp AX,10
cmp AX,11
RET

n cmp.com
r cx
c
w
q
Legenda;
Flag segno: PL positivo - NG negativo
Flag Zero: ZR zero - NZ non zero
Flag Parità: PE pari - PO dispari
Flag Riporto: NC no riporto - CY si riporto
Flag Riporto Ausiliario: NA no riporto - AC si riporto

 

il registro flag è così fatto:

 

FLAG  SET    RESET
Overflow Overflow OV si NV no
Direction Direzione DN decremento UP incremento
Interrupt Interruzione EI abilitato DI disabilitato
Sign Segno NG negativo PL positivo
Zero Zero ZR si NZ no
Auxiliary Carry Riporto ausiliario AC si NA no
Parity Parità PE pari PO dispari
Carry Riporto CY si NC no

NEG <operando>


L' istruzione
NEG esegue il complemento a 2 dell'operando. In altre parole cambia di segno. Se l'operando è nullo (00H) l'istruzione non ha effetto e la flag C (Prestito/Carry) è lasciata a 0; in tutti gli altri casi la flag C è lasciata a 1. Se l'operando è il massimo valore negativo (per esempio - 128=80H o - 32768=8000H) l'istruzione non ha effetto e lascia la flag O (Overflow) a 1. Il risultato è lasciato nell'operando di destinazione, al posto di quello di partenza. L'operando può essere un registro o una locazione di memoria, con dimensione di un byte, di una word o di una doubleword

 


PUSH <origine>


L' istruzione
PUSH decrementa il registro SP (stack pointer) di 2 e copia in cima allo  stack il valore contenuto nell'<origine>. L'operando non può essere un registro a 8 bit (esempio AL o AH). L' istruzione PUSHF (priva di argomenti) decrementa il registro SP di 2 e carica una copia del registro dei flag in cima allo stack. Queste tipologie di istruzioni risultano molto usate all'inizio delle macro e delle procedure per salvare i valori originali dei registri prima che quella routine li modifichi durante la sua esecuzione. Il comando PUSHA (aggiunto negli 80186) copia in cima allo stack il contenuto di tutti i registri d'uso generale (ax, cx, dx, bx, sp, bp, si, di) e decrementa di 16 il valore nel registro SP. Il motivo per cui venga salvato anche il registro sp con tale comando (operazione inutile) è dovuto a semplificazioni hw


POP <destinazione>


L' istruzione
POP copia nel registro di <destinazione> il valore in cima allo stack e incrementa il registro SP (stack pointer) di 2. L'operando non può essere il registro CS. L' istruzione POPF (priva di argomenti) incrementa il registro SP di 2 e ripristina il registro dei flag ai valori contenuti prima dell'ultimo PUSHF. Queste tipologie di istruzioni risultano molto usate alla fine dell'esecuzione delle macro e delle procedure per ripristinare i valori originali nei registri modificati dalla routine durante la sua esecuzione.

 

ESEMPIO FUNZIONAMENTO CMP CREA CON: DEBUG<POPPUSH.TXT
C:\trans>debug poppush.com
-
u 100 l9
168E:0100 B81000 MOV AX,0010
168E:0103 50     PUSH AX
168E:0104 B80000 MOV AX,0000
168E:0107 58     POP AX
168E:0108 C3     RET
-
t

AX=
0010 BX=0000 CX=0009 DX=0000 SP=FFFE BP=0000 SI=0000 DI=0000
DS=168E ES=168E SS=168E CS=168E IP=0103 NV UP EI PL NZ NA PO NC
168E:0103 50 PUSH AX
-
t

AX=
0010 BX=0000 CX=0009 DX=0000 SP=FFFC BP=0000 SI=0000 DI=0000
DS=168E ES=168E SS=168E CS=168E IP=0104 NV UP EI PL NZ NA PO NC
168E:0104 B80000 MOV AX,0000
-
t

AX=
0000 BX=0000 CX=0009 DX=0000 SP=FFFC BP=0000 SI=0000 DI=0000
DS=168E ES=168E SS=168E CS=168E IP=0107 NV UP EI PL NZ NA PO NC
168E:0107 58 POP AX
-
t

AX=
0010 BX=0000 CX=0009 DX=0000 SP=FFFE BP=0000 SI=0000 DI=0000
DS=168E ES=168E SS=168E CS=168E IP=0108 NV UP EI PL NZ NA PO NC
168E:0108 C3 RET
 
a
mov AX,10
push AX
mov AX,0
pop AX
RET

n poppush.com
r cx
8
w
q
 
Legenda;
Il registro IP contiene l'indirizzo dell'istruzione corrente


Il comando POPA (aggiunto negli 80186) ripristina i valori nei registri ax, cx, dx, bx, sp, bp, si, di prelevandoli dalla cima dello stack  ed incrementa di 16 il valore nel registro SP

 

LEA <registrodestinazione>, <operando>


L' istruzione
LEA copia nel registro di <destinazione> l'indirizzo effettivo relativo all'etichetta nel secondo argomento. In alternativa si può utilizzare l'operatore OFFSET
 

MOV <registrodestinazione>, OFFSET <operando>.


Questa ha il vantaggio di pesare di meno in termini di codifica in byte rispetto a LEA ma non consente scritture del tipo (poichè OFFSET effettua i suoi calcoli durante l'assemblaggio e SI non è noto se non durante l'esecuzione [runtime] ):

 

MOV BX, OFFSET FRASE[SI]   - NON VALIDA

 

mentre è corretto

 

LEA BX, FRASE[SI] - VALIDA

 

In altre parole LEA è più potente poichè permette di acquisire l'indirizzo anche di variabili inidicizzate. Nessun flag viene influenzato dall'esecuzione di questa istruzione
 

MOVSB


Questa istruzione copia un byte dall'indirizzo puntato da  DS:SI all'indirizzo puntato da ES:DI. Dopo la copia i registri SI e DI vengono incrementati di 1 se il flag di direzione DF vale 0 (DF è settabile a zero mediante l'istruzione CLD) altrimenti vengono decrementati.

L'istruzione non ha operandi (la dimensione del dato da copiare è prefissata per default: un byte) e i dati sono comunque letti dalla locazione puntata da DS:SI e copiati in ES:DI. L'uso di questa istruzione ha quindi senso solo se, in precedenza, entrambi i registri puntatori, SI e DI, sono stati inizializzati con le rispettive etichette.
Questa istruzione può fruire dell'operatore di autoripetizione
REP: anteponendolo al suo mnemonico il processo di spostamento dati viene ripetuto automaticamente CX volte, con conseguente copia automatica di tutta l'area sorgente di memoria; naturalmente il numero bytes da copiare va caricato preventivamente in CX.  I segmenti dati usati sono impliciti ovvero ES e DS

 

.DATA                       ; segmento dati
    STR_SORGENTE DB 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
    STR_DESTINAZ DB 26 DUP (?)
.CODE                
      ; segmento codice
    CLD                    
; Imposto l'incremento di DI e SI
    LEA SI, STR_SORGENTE   
; Indirizzo sorgente
    LEA DI, STR_DESTINAZ   
; Indirizzo di destinazione
    MOV CX,100             
; Carico in CX il numero di byte da copiare
    REP MOVSB              
; ripeto CX volte la copia ...
 

Questa potente istruzione esegue con un solo codice operativo il compito di 4 istruzioni, cioè equivale all'esecuzione del seguente codice:


MOV AL,DS:[SI]  ; carico in AL il byte puntato da DS:SI
MOV ES:[DI],AL  ; copio nell'area puntata da ES:DI il contenuto di AL
INC SI
INC DI

 

La lettera finale B dopo MOVS indica che deve trattare i dati come byte.

 

NOP


Questa istruzione non fa nulla! Il suo scopo è quello di consumare tempo (occupa 3 cicli di clock) o di riservare spazio in memoria (per eventuali aggiunte future di istruzioni).

 

IN


Questa istruzione trasferisce nel primo operando (destinazione, per default l'accumulatore) il dato assunto dalla porta specificata dal secondo operando (sorgente).
Il registro destinazione avrà ovviamente la dimensione del dato letto dal dispositivo, cioè sarà ad esempio AL se il dato letto è un byte, AX se word e EAX se doubleword (con processori 80386/486).

Il secondo operando esprime il nome della periferica coinvolta in lettura e può essere:
- una costante immediata a 8 bit, cioè un numero intero da 0 a 255 (da 00H a FFH): in questo caso si tratta di un dispositivo presente sulla scheda madre, come il timer di sistema 8253 o le porte di I/O interne 8255.
- il contenuto del registro DX, cioè un numero intero da 0 a 65535 (da 0000H a FFFFH): in questo caso il registro DX va caricato prima di effettuare l'input e, esclusi i primi 256 indirizzi, si riferisce a dispositivi esterni alla scheda madre, come la porta parallela o la porta seriale.

 

MOV DX,0379H
IN AL,DX

 

La sua esecuzione non determina cambiamenti nel registro flag.

 

OUT


Questa istruzione trasferisce verso la porta specificata dal primo operando (destinazione) il dato assunto dal secondo operando (sorgente, per default l'accumulatore AX). Il registro sorgente avrà ovviamente la dimensione del dato scritto sul dispositivo, cioè sarà AL se il dato letto è un byte, AX se word e EAX se doubleword (con processori 80386/486).

Il primo operando esprime il nome della periferica coinvolta in scrittura e può essere:
- una costante immediata a 8 bit, cioè un numero intero da 0 a 255 (da 00H a FFH): in questo caso si tratta di un dispositivo presente sulla scheda madre, come il timer di sistema 8253 o le porte di I/O interne 8255.
 

OUT DX,AL    ; spedisco il dato in AL alla porta puntata da DX


- il contenuto del registro DX, cioè un numero intero da 0 a 65535 (da 0000H a FFFFH): in questo caso il registro DX va caricato prima di effettuare l'input e, esclusi i primi 256 indirizzi, si riferisce a dispositivi esterni alla scheda madre, come la porta parallela o la porta seriale.

 

MOV DX,0378H ; specifico l'indirizzo della porta da utilizzare
MOV AL,0FFH  ; specifico il dato da inviare alla porta
OUT DX,AL    ; spedisco il dato in AL alla porta puntata da DX

La sua esecuzione non determina cambiamenti nel registro flag.

 

REP


Non si tratta di un'istruzione ma di un prefisso e va messa davanti ad un'istruzione che gestisce stringhe o, in genere, aree di dati. Il suo compito è quello di obbligare la ripetizione di questi tipi d'istruzione il numero di volte indicato dal registro CX. Il processore: controlla se CX ha valore 0000H: in questo caso non ripete l'istruzione abbinata a REP e prosegue con il resto del programma. Se CX è diverso da zero lo decrementa ed esegue l'istruzione di gestione stringhe e ripete il controllo su CX.

Quindi se il valore iniziale di CX è nullo il prefisso non produce alcun effetto, cioè nessuna delle istruzioni supportate viene eseguita. Va sottolineato che, dopo aver verificato il valore di CX, viene anche verificato se c'è qualche richiesta d'interruzione pendente; non c'è pericolo che la ripetizione delle istruzioni di gestione stringhe mettano in crisi questa importante esigenza.
Il prefisso si applica alle istruzioni: MOVS, STOS, LODS, INS, OUTS, CMP e SCAS (e alle loro varianti con postfisso B, W e D).

L'istruzione:

REP <Istruz.Gestione Stringhe>

equivale a questa sequenza:

DiNuovo: CMP CX,0000H
         JZ Finito
         <Istruz.Gestione Stringhe>
         DEC CX
         JMP DiNuovo
Finito:  ...

 

CALL <Destinazione>


Questa istruzione organizza la chiamata e l'esecuzione di una procedura, cioè un sottoprogramma terminato con RET. La procedura chiamata può essere di tipo NEAR, cioè posta dentro lo stesso segmento di codice in cui abbiamo la chiamata CALL, o
FAR, in caso contrario. Questa caratteristica impone all'istruzione un diverso modo di gestire le operazioni.

L'istruzione
CALL non altera alcuna flag (almeno se non si effettua un cambio di processo). 
Le possibili tipologie dell'unico operando sono:
- etichetta, lasciando all'assemblatore il compito di sostituirla con i 16 o i 32 bit dell'effettivo indirizzo, vicino o lontano. Esempio: 
CALL PULISCIVIDEO (near) oppure CALL FAR PRT PULISCIVIDEO (far).
- un registro (a 16 o 32 bit), chiamata indiretta di procedura. Esempio:
CALL AX
- il valore contenuto in una locazione di memoria (a 16 o a 32 bit), puntata nei possibili modi (ancora chiamata indiretta).  Esempio:
CALL [00ADh]

La procedura può essere già presente nell'apposita zona del programma, oppure prelevata da una libreria (in questo caso occorre dichiararla come esterna,
EXTRN).

Operativamente l'istruzione
CALL lavora in questo modo:

A) Se la chiamata di procedura è
NEAR l'istruzione provvede ai seguenti compiti:
- calcola l'indirizzo Offset dell'istruzione successiva a quella che sta eseguendo il
CALL, semplicemente sommando 0003 (numero di bytes del codice macchina corrispondente a CALL ProcNear) all'indirizzo corrente contenuto in IP.
- decrementa il valore corrente di SP e lo utilizza per puntare la locazione in cui scrivere la parte alta dell'indirizzo appena calcolato. Decrementa ancora il valore di SP e lo utilizza per puntare la locazione in cui scrivere la parte bassa dell'indirizzo appena calcolato. In altre parole effettua un
PUSH IP
- carica IP con l'indirizzo di offset
ProcNear, operando dell'istruzione, obbligando di fatto a saltare a quell'indirizzo.

B) Se la chiamata di procedura è
FAR l'istruzione provvede ai seguenti compiti:
- calcola l'indirizzo Offset dell'istruzione successiva a quella che sta eseguendo il
CALL, sommando 0005 (numero di bytes del codice macchina corrispondente a CALL ProcFar) all'indirizzo corrente contenuto nell'IP.
- decrementa il valore corrente di SP e lo utilizza per puntare la locazione in cui scrivere la parte alta del registro CS.
Decrementa ancora il valore di SP e lo utilizza per puntare la locazione in cui scrivere la parte bassa di CS.  In altre parole effettua un
PUSH
CS.
-
effettua un PUSH IP
- carica IP con l'indirizzo di offset ProcFar.
- carica CS con l'indirizzo di segment
ProcFar, obbligando di fatto se stesso a saltare al nuovo indirizzo CS:IP.

Dopo l'esecuzione di
CALL il processore si viene a trovare in tutt'altro ambiente, lontano dal programma principale da cui è partito, nel medesimo segmento se NEAR o addirittura in un altro se FAR. Si mette ad eseguire diligentemente tutte le istruzioni della procedura, in attesa del RET, che gli consentirà di tornare nel suo percorso nativo, naturalmente a partire dall'indirizzo successivo a quello contenente l'istruzione CALL

 

 

RET [nr byte di stack]


L' istruzione  RET
è usata per terminare una procedura e restituire il controllo all'istruzione successiva a quella che ha effettuato la chiamata mediante una CALL. Equivale a un POP IP  (RETN) nel caso la procedura sia di tipo NEAR mentre se si tratta di una del tipo FAR (intersegmentale) effettua anche un POP CS (RETF) .


Quindi se la procedura da cui si torna è
NEAR l'istruzione RET (o specificatamente RETN) provvede ai seguenti compiti:
1) preleva il byte contenuto nella locazione attualmente puntata da SP, lo trasferisce nella parte bassa di IP;
2) incrementa il valore di SP e lo utilizza per puntare la locazione da cui prelevare il byte da utilizzare come parte alta di IP.
3) incrementa ancora SP.
4) salta alla locazione di programma indicata dal nuovo valore di IP, praticamente l'indirizzo di offset dell'istruzione successiva a quella con la
CALL che aveva richiamato la procedura che si è appena terminata.

Quando la procedura da cui si torna è
FAR l'istruzione RET (o specificatamente RETF) provvede ai seguenti compiti:
a) esegue i punti 1, 2 e 3 di
RETN.
b) usa SP per puntare la locazione nello stack da cui prelevare la parte bassa di CS.
c) incrementa ancora SP e lo utilizza per puntare la locazione da cui prelevare la parte alta di CS.
d) incrementa ancora il valore di SP.
e) salta alla locazione di programma indicata dal nuovo valore di CS:IP, praticamente l'indirizzo logico completo della locazione del programma principale successiva a quella con la
CALL che aveva richiamato la procedura che si è appena terminata.

Se insieme all'istruzione
RET viene fornito un operando numerico, dopo le consuete operazioni illustrate qui sopra, il numero viene semplicemente sommato a SP; questo significa effettivamente "scaricare" i bytes dallo stack, anche se ovviamente di essi rimarrà traccia in memoria, almeno fino al prossimo riutilizzo di questa preziosa area. Questa opportunità è frequentemente utilizzata dai linguaggi di programmazione ad alto livello per liberare l'area stack dai parametri passati in ingresso alla procedura da cui si torna.