Calcolatori elettronici/Le procedure

Indice del libro

Una procedura è una porzione di codice richiamabile tramite il suo nome in qualsiasi punto del programma. Il salto alla procedura supporta il ritorno al chiamante. Migliora la leggibilità del codice e risparmia memoria.

Struttura

modifica

Una procedura si definisce in questo modo:

<etichetta> PROC <tipo>
...
<etichetta> ENDP

La procedura può essere richiamata con l'istruzione CALL <etichetta>. In realtà nell'istruzione CALL l'assemblatore converte il simbolo <etichetta> nell'indirizzo della prima istruzione della procedura. Alla chiamata, l'indirizzo del chiamante viene salvato dall'IP allo stack.

L'istruzione RET, priva di parametri, permette di ritornare alla procedura chiamante.

Località

modifica

Una procedura di tipo NEAR (predefinito) può essere richiamata solo all'interno dello stesso segmento di codice, e viene richiamata da una CALL su 3 byte tramite l'offset della sua prima istruzione. Una procedura di tipo FAR può essere chiamata da procedure appartenenti a segmenti di codice diversi; la CALL su 5 byte prima di caricare l'offset della procedura deve modificare il registro CS, effettuando il push nello stack del vecchio valore di CS.

Anche l'istruzione RET si distingue per i tipi NEAR e FAR, effettuando la pop dallo stack di uno o due word.

Memorizzazione di variabili locali

modifica

La procedura può memorizzare temporaneamente nello stack le variabili dichiarate in modo locale al suo interno.

Backup del contenuto dei registri

modifica

Le procedure vengono richiamate tramite l'istruzione CALL, che salta alla prima istruzione della procedura. Al termine della procedura, l'istruzione RET deve poter ritornare al chiamante → l'istruzione CALL, prima di sovrascrivere il PC con il nuovo indirizzo, deve quindi temporaneamente salvare (push) nello stack il PC del chiamante, che verrà letto (pop) dall'istruzione RET. La struttura LIFO garantisce che l'ordine dei PC letti da una serie di istruzioni RET appartenenti a procedure annidate sia corretto, cioè dall'ultima procedura chiamata fino al primo chiamante.

I valori dei registri possono essere salvati prima della prima istruzione e ripristinati dopo l'ultima istruzione, in modo che la procedura non "sporchi" i registri.

Passaggio di parametri

modifica

I linguaggi assembler non hanno alcun meccanismo apposito per il passaggio dei parametri.

Prima della chiamata della procedura il chiamante può salvare nello stack i parametri, che verranno letti durante l'esecuzione della procedura. Il problema è che l'istruzione CALL li coprirebbe con il valore dell'IP. Il registro BP serve per salvare temporaneamente il valore del­l'SP subito dopo la chiamata come prima istruzione della procedura (lo stack si riempie a partire dal fondo), in modo che il primo parametro sia accessibile all'indirizzo [BP+2]. Un semplice ripristino dell'SP al valore originario segue il ritorno al chiamante. I parametri di ritorno possono essere salvati dalla procedura e letti dal chiamante in una posizione destinata appositamente nello stack tramite una istruzione SUB dell'SP che precede le push dei parametri. Non c'è limite al numero di parametri, e i parametri rimangono in memoria solo per il tempo di esecuzione della procedura. Questa soluzione non può essere applicata a procedure annidate, perché il registro BP può contenere un solo valore di SP; per ovviare a questo problema, si può salvare il contenuto di BP a sua volta nello stack subito prima di sovrascriverlo con il valore di SP, e quindi ripristinarlo con una pop subito prima della istruzione RET, avendo l'accortezza di accedere al primo parametro all'indirizzo [BP+4].

Altri modi

modifica
Variabili globali
modifica

La procedura può usare direttamente delle variabili globali, che sono visibili a tutte le procedure compresa quella chiamante.

Svantaggio
non è una soluzione flessibile
Registri
modifica

Lo scambio di informazioni tra la procedura e il chiamante avviene tramite i registri.

I registri che non sono restituiti al programma chiamante possono essere usati internamente alla procedura, salvando temporaneamente nello stack i loro vecchi valori.

Svantaggio
il numero di registri è limitato