Sei sulla pagina 1di 10

6.

Le chiamate a sotto programma e lo stack

6.1 Introduzione

Nei precedenti capitoli abbiamo visto come il software abbia una struttura gerarchica che permette il riuti-

lizzo di soluzioni e strutture semplici per arrivare alla definizione di strutture e soluzioni complesse.

Una delle basi di questo modo gerarchico di costruire soluzioni complesse è quella di poter riutilizzare mo-

duli software che implementano le soluzioni complete di sotto problemi, per costruire una soluzione di un proble-

ma avente un livello di complessità maggiore. Operativamente, si tratta di poter riutilizzare moduli software, e cioè

algoritmi descritti in un particolare linguaggio di programmazione, all’interno di altri moduli softwaresenza do-

verli riprogettare o semplicemente riscrivere: questo concetto è alla base della costruzione di librerie di programmi,

più o meno semplici, più o meno di uso generale, che possono essere eseguiti anche da più punti di un programma

di livello maggiore semplicemente richiamandone in quest’ultimo il nome (l’indirizzo al quale risiedono in memo-

ria), per eseguire il loro codice.

In questo capitolo ci occuperemo dei meccanismi e delle strutture informative a livello CPU che permetto-

no all’elaboratore di eseguire dei sotto programmi, all’interno di un programma di livello superiore, e della messe

di metodologie di programmazione che ha portato nell’informatica l’introduzione di una certa struttura di memoria.

6.2 Richiami di programmazione in linguaggio macchina

In questo e nei suoi sotto paragrafi, la discussione sottintenderà la programmazione in linguaggio Assem-

bler.

L’esecuzione sequenziale di un programma da parte della CPU si basa sull’utilizzo di un registro (spesso

chiamato “program counter”) dedicato a contenere l’indirizzo della prossima istruzione da eseguire e da particolari

meccanismi insiti nella circuiteria della macchina che ne alterano automaticamente il contenuto. Tuttavia, è possi-

bile alterarne volontariamente il contenuto per modificare l’andamento sequenziale dell’esecuzione del program-

ma, ad esempio per costruire dei cicli di elaborazione all’interno del programma.

La semplice alterazione del contenuto del program counter, effettuata tramite le istruzioni di salto, purtrop-

po non permette di soddisfare le esigenze d’utilizzo di sotto programmi: difatti, le istruzioni di salto modificano il

Liceo Scientifico “F. Cecioni” – Livorno - Appunti d’Informatica per le classi IV ST – Ed. 0

Cap. 6 pagina 1 di 1
contenuto del program counter distruggendone il vecchio contenuto, ovvero l’indirizzo dell’istruzione che sarebbe

stata eseguita se l’istruzione di salto non avesse portato a modificare tale indirizzo. Invece, nell’esecuzione di un

sotto programma, come del servizio di una richiesta d’interruzione, è essenziale che al termine del sotto program-

ma l’esecuzione riprenda dall’istruzione seguente la chiamata del sotto programma o da quella che sarebbe stata

eseguita se non ci fosse stato il servizio della richiesta d’interruzione.

6.2.1 Una prima soluzione

Disponendo delle sole istruzioni di salto, si potrebbe ipotizzare di risolvere il problema posto nel paragrafo

precedente facendo in modo che ogni sotto programma terminasse con una istruzione di salto all’istruzione es-

guente a quella che lo ha chiamato (l’atto di mandare in esecuzione di un sotto programma prende il nome di

“chiamata a sotto programma”, dal momento che si specifica il sotto programma da eseguire tramite il suo nome):

un tale modo di procedere impone però che ogni sotto programma sia chiamato da uno e un solo punto nel pro-

gramma chiamante, poiché il sotto programma non sarebbe in grado di distinguere da quale istruzione del pro-

gramma chiamante (detto anche “principale”, rispetto al chiamato) è stato chiamato, in quanto ritornerebbe sempre

e comunque al medesimo punto.

Ancora, un tale modo di procedere legherebbe indissolubilmente il sotto programma a quello principale, di-

sattendendo la richiesta che un sotto programma possa essere utilizzato quante volte è necessario daqualunque

altro programma che necessiti delle sue funzioni (bisogna ottemperare a questa richiesta almeno nell’ambito di tutti

i programmi sviluppati con il medesimo linguaggio di programmazione1).

Talvolta, ma solamente nell’ambito di piccoli programmi scritti in linguaggio Assembler, e in casi molto

particolari, questa soluzione può essere adottata efficacemente, ma mai per gestire il servizio di una richiesta

d’interruzione in quanto, non potendo conoscere a priori in quale punto del programma giungerà l’interrupt, non è

possibile definire l’indirizzo dell’istruzione alla quale ritornare una volta terminato il servizio dell’interruzione.

6.2.2 Una soluzione migliore

1
Le modalità operative di una chiamata a sotto programma possono differire notevolmente da un linguaggio
all’altro e, addirittura, per uno stesso linguaggio implementato da Ditte diverse. Perciò, se non espressamente
dichiarato, un programma scritto in un certo linguaggio e compilato con un compilatore fornito da una certa
Ditta normalmente può chiamare ed essere chiamato solamente da altri programmi compilato con il medesimo
compilatore.

Liceo Scientifico “F. Cecioni” – Livorno - Appunti d’Informatica per le classi IV ST – Ed. 0

Cap. 6 pagina 2 di 2
Ciò che manca alla “soluzione” del paragrafo precedente è la memorizzazione (in gergo informatico

s’indica col termine “salvataggio”) dell’indirizzo contenuto nel program counter prima che questo venga modifi-

cato dall’istruzione di salto: dal momento che è possibile conoscere da programma l’indirizzo di qualunque istru-

zione del programma medesimo (basta anteporre all’istruzione un’etichetta, detta anche “label”, perché

l’assemblatore le assegni come valore l’indirizzo dell’istruzione alla quale è apposta, e poi usare l’etichetta stessa

come costante numerica intera senza segno), è possibile memorizzare tale l’indirizzo di ritorno in una opportuna

struttura di memoria alla quale i sotto programmi possono fare riferimento.

La struttura di memoria più semplice che si può ipotizzare è una locazione che contiene il codice operativo

dell’istruzione di salto seguito dall’indirizzo di salto stesso: il programma principale, prima di effettuare il salto al

sotto programma, memorizza nella parte della struttura riservata all’indirizzo di salto quello dell’istruzione succes-

siva a quella di salto al sotto programma. Unico presupposto perché questo metodo possa funzionare è che tutti i

sotto programmi conoscano l’indirizzo di struttura, cosa possibile senza eccessivi problemi. Il meccanismo di

ritorno dal sotto programma prevede di saltare all’indirizzo della struttura, e dunque di eseguirne il contenuto che è

costituito da un’altra istruzione di salto al punto di ritorno nel programma chiamante.

Un metodo simile, anche se con intenti diversi, è stato usato nel sistema operativo CP/M per le chiamate da

programma utente alle routine di servizio del sistema operativo. Il metodo è stato anche usato, per compatibilità,

nel sistema operativo MS-DOS.

Il metodo così come sopra esposto, pur superando le maggiori difficoltà incontrate con quello precedente,

presenta ancora il grave problema di poter richiamare un solo programma per volta. Difatti, se il sotto programma

chiamato, sia esso “A”, richiamasse a sua volta un sotto programma “B” la chiamata a quest’ultimo distruggerebbe

l’indirizzo di ritorno di “A” al programma principale: con una sola locazione per l’indirizzo di ritorno non è dun-

que possibile che un sotto programma ne richiami a sua volta un altro, ovvero non è possibile “annidare” le chia-

mate a sotto programmi una dentro l’altra, ma è possibile un solo livello di sotto programmi.

Il fatto di non poter annidare le chiamate a sotto programmi, se pur estremamente limitativo per la pro-

grammazione, è facilmente superabile ampliando e modificando la struttura di memoria che contiene l’indirizzo di

ritorno. Per esempio, è ipotizzabile l’utilizzo di una struttura di memoria formata da un certo numero di locazioni

per gli indirizzi di ritorno (un vettore) affiancate da un indice (una variabile intera) che memorizzi quale è

l’indirizzo di ritorno attuale. L’indice verrà incrementato ogniqualvolta si effettua una chiamata a un sotto pro-

gramma e verrà decrementato quando un sotto programma, terminando, tornerà all’indirizzo di ritorno del pro-

gramma che l’ha chiamato.

Liceo Scientifico “F. Cecioni” – Livorno - Appunti d’Informatica per le classi IV ST – Ed. 0

Cap. 6 pagina 3 di 3
Pur nonostante i miglioramenti apportati, anche quest’ultima soluzione presenta due problemi: il primo, e

meno grave, è costituito dal fatto che, per quanto ben dimensionata la struttura di memorizzazione degli indirizzi di

ritorno o spreca spazio (vengono annidate meno chiamate di quante la struttura non ne sopporti), o è limitativa del

numero di chiamate annidabili e, comunque, una struttura di lunghezza fissa dal punto di vista informatico è quanto

di meno elegante si possa pensare.

Il secondo fatto è comunque il più grave, in quanto anche questa soluzione non permette di gestire il ritorno

dei programmi di servizio delle interruzioni, sempre perché non è possibile conoscere a priori il punto in cui

l’interrupt interrompe il programma in esecuzione (si ricordi che il servizio di una richiesta d’interruzione può

essere considerato come una chiamata a sottoprogramma che può avvenire tra il termine dell’esecuzione di

un’istruzione e l’inizio della fase di fetch dell’istruzione successiva, senza che ciò sia sotto il controllo del pro-

gramma stesso).

6.2.3 La soluzione definitiva

Il problema della gestione dell’indirizzo di ritorno dei sotto programmi di servizio delle richieste

d’interruzione spingono verso una soluzione hardware intrinseca della circuiteria della CPU. Poiché non è prevedi-

bile il momento in cui giungerà una richiesta d’interrupt, e dunque non è prevedibile il punto in cui il programma

sarà interrotto per gestire la richiesta, e così susseguentemente non può essere noto a priori il punto di ritorno dal

sotto programma di gestione, non è possibile eseguire delle istruzioni che memorizzino il punto di ritorno prima

della chiamata del sotto programma di gestione dell’interrupt.

Visto che non possibile gestire via software (cioè sotto il pieno controllo del programma) l’attivazione dei

sotto programmi di gestione delle interruzioni, ma che il loro punto di ritorno deve comunque essere memorizzato

da qualche parte e in qualche modo, l’unica soluzione attuabile è stata quella di fornire la CPU di un meccanismo

automatico (poi vedremo che è disponibile anche al controllo del programmatore) per salvare l’indirizzo di ritorno

durante una chiamata a sotto programma.

Tale meccanismo rimane il medesimo sia che la chiamata al sotto programma sia effettuata volontaria-

mente dal programma, sia che tale chiamata venga generata a seguito della richiesta di gestione di un’interruzione.

Nel caso della chiamata volontaria a un sotto programma, tra i codici operativi della CPU è stata inserita

un’istruzione di chiamata a sotto programma (il cui codice mnemonico è per l’appunto “CALL <nome del sotto

programma>”) che altro non è se non un’istruzione di salto all’indirizzo <nome del sotto programma> “allungata”

del salvataggio del contenuto del program counter dopo che la CPU ha letto l’indirizzo <nome del sotto program-

ma> contenuto nell’istruzione stessa.

Liceo Scientifico “F. Cecioni” – Livorno - Appunti d’Informatica per le classi IV ST – Ed. 0

Cap. 6 pagina 4 di 4
Il sotto programma, come sua ultima istruzione, dovrà contenere un’istruzione di “ritorno” (il cui codice

mnemonico è generalmente “RET”, abbreviativo dell’inglese “return”) che semplicemente ricopierà nel program

counter il vecchio valore memorizzato dalla CALL2.

Per rendere più semplice ed automatico il meccanismo di CALL/RETurn, sempre in hardware nelle CPU è

implementato un particolare registro, lo stack pointer, che indirizza un’area di memoria (detta “stack”, cioè “pila”,

“catasta”) dove vengono automaticamente memorizzati e recuperati gl’indirizzi di ritorno dei programmi chiaman-

ti. Lo stack pointer viene automaticamente variato durante l’esecuzione delle istruzioni CALL e RET per indirizza-

re sempre l’attuale indirizzo valido presente nello stack, che è l’ultimo indirizzo di ritorno memorizzato e che sarà

il primo ad essere prelevato a seguito di una RET.

Lo stack pointer viene in genere inizializzato al reset della CPU, ma comunque può esserlo sotto il diretto

controllo del programma, per mezzo di una particolare istruzione di movimentazione di dati.

6.3 Lo stack e lo stack pointer

Lo stack è un’area di memoria di dimensione variabile che implementa una lista “last in – first out”, cioè

una lista nella quale gli elementi possono essere aggiunti e rimossi sempre e solamente a partire dall’ultimo immes-

so: si pensi a dei libri poggiati su di un tavolo per una delle superfici maggiori, oppure a una pila di barattoli in un

negozio.

Il fatto che ogni elemento viene aggiunto di seguito al precedente e viene tolto nella sequenza inversa, fa sì

che basti un solo puntatore che indirizzi indifferentemente (ma una volta scelto rimane sempre quello!) l’ultimo

elemento occupato della lista o il primo libero. Questo puntatore viene solitamente chiamato “stack pointer” e

viene automaticamente modificato, decrementato o incrementato, rispettivamente quando si aggiunge o si toglie un

elemento dalla pila.

È opportuno notare che nel periodo precedente si è accoppiato il decremento dello stack pointer con

l’aggiunta di un elemento alla lista e l’incremento con l’estrazione di un elemento dalla lista; ciò è dovuto al fatto

che lo stack è una struttura che cresce espandendosi verso gli indirizzi “bassi” (numericamente minori) di memoria,

partendo dall’elemento di memoria d’indirizzo più elevato. Quella che a prima vista può sembrare un’inutile com-

2
La richiesta d’interruzione genera automaticamente un’istruzione CALL che ha per indirizzo un valore prefissato,
a seconda del tipo della CPU, dal progettista della CPU stessa o dal programmatore in una delle prime fasi
dell’esecuzione del programma, prima di attivare il meccanismo di risposta alle interruzioni. Al termine, il sotto
programma di servizio dell’interruzione esegue un’istruzione “RETI” (“return from interrupt”) che ai fini della
presente discussione è del tutto equivalente a una “RET”.

Liceo Scientifico “F. Cecioni” – Livorno - Appunti d’Informatica per le classi IV ST – Ed. 0

Cap. 6 pagina 5 di 5
plicazione, fatta apposta per rendere difficile la vita agli studenti, altro non è che un ulteriore esempio di come in

informatica si cerchi d’evitare ogni spreco sia di memoria , sia di tempo.

Per capire il perché del fatto che lo stack cresce espandendosi verso gli indirizzi “bassi”, si pensi al mecca-

nismo d’auto incremento del program counter: tale meccanismo fa sì che l’esecuzione di un programma proceda

naturalmente dagli indirizzi bassi verso gli indirizzi alti, rendendo logica la memorizzazione di un programma a

partire dall’indirizzo libero più basso possibile. Nella memoria ad indirizzo appena superiore a quello dell’ultima

cella occupata dal programma vengono memorizzate le eventuali costanti contenute nel programma (è bene mante-

nere separati i dati dal codice eseguibile, se non altro perché se i dati fossero frammisti al codice prima di ogni dato

dovrebbe esserci una istruzione di salto che eviti d’interpretare il dato successivo come un’istruzione) e di seguito,

dunque ad indirizzi ancora maggiori, le variabili di programma che sono state dichiarate (in nome, tipo e lunghez-

za) durante la compilazione. Infine, ancora a indirizzi più elevati, normalmente esiste una zona di memoria di

dimensione variabile, ma comunque espandibile sempre verso indirizzi più elevati, detta “heap”, che può essere

utilizzata per allocare, sotto il controllo del programma e a seconda delle necessità istantanee dovute ai dati da

elaborare, variabili il cui tipo è stato previsto dal programmatore al momento della scrittura del programma, ma il

cui numero è funzione dei dati da elaborare.

Dal momento che la memoria è dunque suddivisa in un’area di lunghezza determinata (quella che contiene

il codice, le costanti e le variabili allocate staticamente) e da un’area di lunghezza variabile che cresce verso gli

indirizzi alti, se anche lo stack, che è anch’esso un’area di lunghezza variabile, crescesse allo stesso modo verso

indirizzi alti dovrebbe iniziare in una locazione di memoria ad un indirizzo compreso tra quellodell’heap e quello

dell’ultima cella di memoria. Questa situazione porterebbe a definire implicitamente e a priori le lunghezze massi-

me dell’heap e dello stack (la lunghezza dell’heap sarebbe uguale alla differenza tra l’indirizzo di partenza dello

stack e quella dell’heap stesso, e quella dello stack sarebbe uguale a quella tra l’ultimo indirizzo di memoria e

quello di partenza dello stack): perciò si avrebbe una doppia limitazione data dalla doppia determinazione delle due

lunghezze.

Se invece le due strutture variabili, heap e stack, crescono una contro l’altra, allora esiste una sola limita-

zione alla loro crescita data dall’obbligo che la somma dello spazio occupato da entrambe sia minore o uguale allo

spazio disponibile. Ovviamente, per massimizzare in questo caso lo spazio disponibileheap e stack devono partire

da locazioni tra loro le più distanti possibile: l’heap partirà dunque dalla prima locazione lasciata libera dal pro-

gramma e dai dati allocati staticamente e lo stack dall’ultima locazione di memoria disponibile.

6.4 Altri utilizzi dello stack

Liceo Scientifico “F. Cecioni” – Livorno - Appunti d’Informatica per le classi IV ST – Ed. 0

Cap. 6 pagina 6 di 6
Aggiungendo alle istruzioni macchina poche istruzioni, è possibile sfruttare al massimo l’esistenza dello

stack, in parallelo alle sue funzioni peculiari di memorizzazione degli indirizzi di ritorno.

Le istruzioni che permettono l’utilizzo dello stack in maniera diretta da parte del programma sono solo due,

“push” e “pop”, rispettivamente per memorizzare il contenuto di un registro nello stack e per estrarre un dato dallo

stack copiandolo in un registro, e la possibilità scambiarne il contenuto con un altro registro. Le istruzionipush e

pop, oltre a scambiare dati con lo stack, modificano opportunamente il contenuto dello stack pointer.

Il primo utilizzo delle istruzioni di push e pop è quello di salvare il contenuto dei registri utilizzati dai sotto

programmi di servizio delle interruzioni. Dal momento che il programma sospeso dal servizio di un’interruzione

deve poter riprendere la sua elaborazione come se l’interruzione non fosse stata servita, e che il servizio

dell’interruzione comporta comunque l’alterazione del contenuto di alcuni registri, ogni sotto programma di servi-

zio, una volta attivato e prima di utilizzare i registri deve salvare il contenuto di quelli che intende utilizzare, ripri-

stinandolo appena prima dell’esecuzione dell’istruzione reti.

Il salvataggio e il ripristino dei registri utilizzati dai sotto programmi di servizio delle interruzioni viene ef-

fettuato tramite l’utilizzo delle istruzioni push e pop. A tale proposito si noti che i registri salvati nello stack devo-

no essere ripristinati in ordine inverso, per non scambiarne tra loro il contenuto3.

6.4.1 Passaggio dei parametri ad un sotto programma

I sotto programmi, per poter essere utilizzati proficuamente, devono poter elaborare la più vasta classe pos-

sibile dei sotto problemi per la quale sono stati costruiti. Per fare ciò, i sotto programmi devono poter ricevere dal

programma chiamante la parametrizzazione della soluzione da computare.

Per chiarire le idee, si prenda in considerazione un sotto programma che, dati i coefficienti di un’equazione

di secondo grado, ne calcola le radici. Il programma chiamante dovrà perciò richiamare il sotto programma infor-

mando (“passando a”) quest’ultimo quali valori hanno i coefficienti dell’equazione che si vuole risolvere, e che,

per poter riutilizzare il sotto programma anche con altre equazioni, non possono essere stati codificati direttamente

nel codice di quest’ultimo. Inoltre, il sotto programma dovrà poter inviare le soluzioni trovate al programma chia-

mante.

Studiamo nel seguito quali sono le possibili soluzioni al problema del passaggio dei parametri da pro-

gramma chiamante a un sotto programma e vice versa.

Liceo Scientifico “F. Cecioni” – Livorno - Appunti d’Informatica per le classi IV ST – Ed. 0

Cap. 6 pagina 7 di 7
6.4.1.1 Passaggio dei parametri attraverso i registri

Una possibile soluzione al problema del passaggio dei parametri è quella di usare direttamente i registri

della CPU. Essa è senz’altro il modo più veloce, ma presenta almeno tre contro indicazioni: la prima consiste ne

fatto che parametri costituiti nella forma di variabili strutturate, per esempio una stringa di caratteri, non possono

essere direttamente contenuto né un alcun registro, né spesso in tutti i registri presenti nella CPU. L’ostacolo può

tuttavia essere aggirato passando in un registro non l’intera stringa, ma il suo indirizzo in memoria.

Il secondo problema consiste nel numero limitato di registri che, solitamente, una CPU ospita. Nel caso che

si debbano passare più parametri di quanti non siano i registri con questa sola metodologia l’ostacolo è insormon-

tabile.

Il terzo, ma più grave problema, è che il metodo si adatta bene solo ai programmi scritti in Assembler in

quanto esso implica una profonda conoscenza dell’architettura interna della CPU che si sta utilizzando: questo fatto

è in netto contrasto con l’utilizzo di compilatori di linguaggi di più alto livello che sono nati apposta per permettere

la scrittura di programmi indipendenti il più possibile dall’architettura della macchina.

6.4.1.2 Passaggio di parametri tramite aree comuni

Il secondo metodo proposto è quello di memorizzare i parametri in un’area di memoria e di fare in modo

che la struttura, la lunghezza e l’indirizzo della medesima siano conosciute sia dal programma chiamante, sia dal

sotto programma.

Sebbene questo metodo risolva completamente i problemi discussi nel paragrafo precedente, anch’esso

comporta due problemi: il primo, e meno grave problema, è costituito dal fatto che i due programmi, chiamante e

chiamato, devono conoscere tutto dell’area comune. Per fare ciò, dal momento che si presuppone che il sotto pro-

gramma nasca prima del programma chiamante, e che anzi i due siano separati anche da un notevole intervallo di

tempo di progettazione e siano stati progettati da persone diverse, il progettista del programma chiamante deve

disporre di una buona documentazione sul sotto programma e vi si deve attenere perfettamente, in una maniera che

talvolta è noiosamente limitatrice della sua libertà di progettazione.

Il secondo problema è tuttavia quello di gran lunga più grave: tanto grave da sconsigliare l’uso di questa

metodologia che di fatto resta relegata al solo sviluppo di certe parti critiche dei sistemi operativi. Il problema di

3
La facile dimostrazione è lasciata al lettore….. che dovrà essere in grado di esporla correttamente al noto mo-
mento opportuno…..

Liceo Scientifico “F. Cecioni” – Livorno - Appunti d’Informatica per le classi IV ST – Ed. 0

Cap. 6 pagina 8 di 8
cui stiamo parlando deriva dal pericolo che l’interpretazione del contenuto dell’area comune sia diversa, poco

diversa, solo in qualche punto diversa, nel programma chiamante e nel sotto programma. In tale sciagurato caso,

ogni tanto, i maniera del tutto imprevedibile e per niente ripetibile il programma fornirà dei risultati errati o cesserà

di funzionare. Tipicamente, la ricerca e la soluzione di tali malfunzionamenti è così lunga e incerta da sconsigliare

vivamente ai comuni programmatori l’utilizzo di tale metodologia.

6.4.1.3 Passaggio di parametri tramite lo stack

Il più comune e sicuro modo di passare parametri tra un programma chiamante e un sottoprogramma è

quello di utilizzare l’area di stack.

Il programma chiamante, prima di effettuare la call al sotto programma, copia i parametri da passare

nell’area di stack per mezzo di istruzioni push, nella sequenza definita dal sotto programma. Nel caso si debbano

prevedere parametri di ritorno, nello stack si memorizzerà l’indirizzo delle variabili del programma chiamante nelle

quali il sotto programma dovrà memorizzare i valori di ritorno. Prima di effettuare lacall, terminato di memorizza-

re i parametri nello stack, il programma chiamante copierà in un particolare registro il valore contenuto nello stack

pointer e poi effettuerà la call.

Il sotto programma potrà accedere ai parametri tramite il loro indirizzo, memorizzato nel registro particola-

re. Il registro utilizzato per memorizzare il vecchi valore dello stack pointer dipende dalla CPU e dal compilatore

del linguaggio utilizzato. L’ordine con il quale i parametri vengono memorizzati nello stack dipende da quello

definito nel sotto programma e dal compilatore utilizzato.

Al ritorno dalla call al sotto programma, sarà cura del programma chiamante eliminare dallo stack i para-

metri precedentemente memorizzati effettuando delle pop, o più semplicemente incrementando lo stack pointer di

tanto quanti erano i byte utilizzati dai parametri (i parametri di ritorno non vengono memorizzati nello stack, ma

nelle loro variabili nel programma chiamante: si ricordi che nello stack erano presenti solo le copie degli indirizzi

di tali variabili).

Questo è il metodo utilizzato ogniqualvolta si utilizza un linguaggio d’alto livello, anche se l’immissione e

l’estrazione dei parametri dallo stack, essendo questa un’area di memoria esterna alla CPU, è comunque

un’operazione più lenta della nessuna operazione effettuata con il passaggio di parametri tramite i registri e le

poche operazioni effettuate con l’utilizzo delle aree condivise.

Di fatto, la metodologia di passare i parametri tramite lo stack è quella standard perché più uniforme al va-

riare del tipo di CPU e la più sicura, perché automatica, dal punto di vista del programmatore.

Liceo Scientifico “F. Cecioni” – Livorno - Appunti d’Informatica per le classi IV ST – Ed. 0

Cap. 6 pagina 9 di 9
6.4.2 Allocazione delle variabili locali nello stack

Spesso, la memoria di un elaboratore è una risorsa limitante per l’esecuzione dei programmi. Perciò è sem-

pre opportuno provvedere a un uso oculato di tale risorsa, facendo in modo, tra l’altro, che le variabili dei sotto

programmi occupino la memoria solo quando i sotto programmi medesimi sono attivi e che una stessa porzione di

memoria possa essere riutilizzata da altre variabili quando le prime l’hanno rilasciata.

L’heap è stato pensato soprattutto per allocare variabili4 che devono essere condivise da tutti i sotto pro-

grammi di un programma, perciò alle variabili dinamiche come area d’allocazione rimane solo lo stack.

Un sotto programma, appena attivato, se ha bisogno di variabili locali (non conosciute e non utilizzate al di

fuori di esso) per le sue elaborazioni, ha a disposizione lo stack per allocarle, e lo fa decrementando il valore con-

tenuto nello stack pointer del numero di byte necessari. Così facendo rende disponibile nello stack una quantità di

memoria atta a contenere le variabili che gli abbisognano.

Prima di effettuare la ret, il sottoprogramma dovrà riportare il valore dello stack pointer a quello che aveva

prima di allocare le variabili locali. Le variabili locali sono indirizzate tramite il registro che contiene il vecchio

valore dello stack pointer, registro definito dal compilatore del linguaggio e inizializzato dal programma chiaman-

te.

4
Le variabili si differenziano in “classi” di memoria e prendono il nome di “statiche”, se occupano memoria per
tutta la durata del programma (sono statiche le variabili del programma principale); “automatiche” o
“dinamiche”, se occupano memoria solo il sotto programma che le utilizza è attivo; “controllate”, se vengono
allocate in memoria (nell’heap) sotto il diretto controllo del programma.

Liceo Scientifico “F. Cecioni” – Livorno - Appunti d’Informatica per le classi IV ST – Ed. 0

Cap. 6 pagina 10 di 10