Le procedure sono delle porzioni di codice associate ad un nome, che possono essere invocate più volte e che eseguono un compito specifico. Hanno una lista di parametri come input e come output un valore di ritorno.
Vantaggi:
Un esempio sono le funzioni di C:
...
f = f + 1;
risultato = somma(f, g);
La procedura chiamante sopra, invoca un'altra procedura (chiamata):
int somma(f, g){
return f + g + 2;
}
Chiamante
Chiamato
jal IndirizzoProcedura
jal = jump and link
Salta all'indirizzo (offset) con etichetta IndirizzoProcedura
.
Una volta che è stata eseguita la procedura invocata, il PC esegue il codice a partire dall'istruzione successiva al punto in cui è stata chiamata la procedura. L'indirizzo dell'istruzione successiva (del PC) viene memorizzata nel registro x1
(return address ra
) per potervi ritornare alla fine della procedura. L'istruzione successiva sarà PC + 4.
Viene introdotto un nuovo formato di istruzione: J
jalr rd, offset(rs1)
jalr = jump and link register
Questa istruzione consente al PC di saltare ad un indirizzo qualsiasi.
Quando la procedura che è stata chiamata ha finito di eseguire il suo corpo, come ultima cosa deve ritornare al punto in cui la procedura è stata chiamata (nel chiamante). Questo viene fatto grazie a questa istruzione, in particolare:jalr x0, 0(x1)
(jalr
è codificata con il formato di istruzione del tipo I), x1
come abbiamo già detto è l'indirizzo dell'istruzione successiva.
Questa istruzione, per come è implementate si porta dietro una serie di problemi:
Queste tre soluzioni hanno una cosa in comune, l'utilizzo della memoria come strumento di appoggio per salvare il valore di eventuali valori di ritorno, o di contenuti di registri che potrebbero essere utilizzati nella funzione chiamata o del numero eccessivo di parametri e/o variabili utilizzate da un procedura. L'area di memoria in cui è possibile salvare i registri per evitarne la perdita è lo stack.
Oltre allo stack, in memoria trovano posto:
malloc()
del C)Esempi di codice assembly RISC-V: