2012-02-12 13 views
8

Da http://en.wikipedia.org/wiki/Stack_pointer#StructurePerché i parametri della funzione spinto in precedenza su stack di chiamate che l'indirizzo di ritorno?

enter image description here

Mi chiedo il motivo per cui l'indirizzo di ritorno di una funzione è posto al di sopra dei parametri per quella funzione?

ha più senso avere Return Address inserito nello stack prima che i Parametri per DrawLine perché i parametri non sono più necessari quando l'indirizzo di ritorno è spuntato per il ritorno di nuovo alla funzione chiamante.

Quali sono le ragioni per preferire l'attuazione illustrata nel diagramma sopra?

+3

Si prega di sapere che questa disposizione è ** non ** parte dello standard C++. È specifico per una singola CPU, un compilatore e/o un ambiente operativo. La situazione descritta in quell'articolo è tipica ed è accurata per GCC/X86, ma non è affatto universale. –

+0

Il numero di entrambi i parametri e i locals potrebbe non essere corretto. Come hai potuto determinare l'indirizzo di tutti e 3 se l'indirizzo di ritorno non era nel mezzo? – Pubby

+0

@Pubby: Non ho la risposta, ma questa situazione si verifica anche con ** Locals di DrawSquare ** e ** Parametri di DrawLine ** qui. – Lazer

risposta

5

L'indirizzo di ritorno viene solitamente inviato tramite il comando di macchina call, [che nella lingua nativa è instruction set] mentre i parametri e le variabili vengono inviati con diversi comandi macchina, che viene creato dal compilatore.

Quindi, l'indirizzo di ritorno è l'ultima cosa spinta dal chiamante e prima di qualsiasi cosa [variabili locali] inviate dal destinatario.

I parametri vengono tutti inviati prima dell'indirizzo di ritorno, poiché il comando passa alla funzione effettiva e l'inserimento dell'indirizzo di ritorno nello stack avviene nello stesso comando di macchina.

Inoltre, un altro motivo è - il chiamante è quello allocare spazio sullo stack per i parametri - E '[il chiamante] dovrebbe anche essere quello che pulisce in su.

+0

"Anche [il chiamante] dovrebbe essere quello che lo pulisce." - in realtà, in quasi tutte le convenzioni di chiamata che non supportano i parametri variadici (es. 'stdcall') la responsabilità di pulizia spetta al chiamante per ridurre la dimensione dell'eseguibile (il codice per la pulizia viene scritto una sola volta alla fine della funzione invece di una volta per ogni chiamata di funzione). –

1

La ragione è semplice: gli argomenti della funzione vengono spinti nello stack dalla funzione chiamante (che è l'unica che può farlo perché solo ha le informazioni necessarie, dopo tutto il punto è farlo per passare quella informazione alla funzione chiamata). L'indirizzo di ritorno viene inviato allo stack dal meccanismo di chiamata della funzione. La funzione viene chiamata dopo la funzione chiamante è impostare i parametri, perché dopo la chiamata è chiamato funzione che viene eseguita, non chiamando uno.

OK, ora si potrebbe sostenere che la funzione chiamante potrebbe mettere i parametri al di là lo stack attualmente utilizzato, e la funzione chiamata potrebbe quindi basta regolare lo stack pointer di conseguenza. Ma non funzionerebbe bene perché in qualsiasi momento potrebbe esserci un interrupt o un segnale, che spingerebbe lo stato corrente sullo stack per ripristinarlo in un secondo momento (non sarei sorpreso se anche un interruttore di attività lo facesse) . Ma se si impostano i parametri oltre lo stack corrente, quegli eventi asincroni lo sovrascriveranno e, poiché non è possibile prevedere quando accadrà, non è possibile evitarlo (oltre la disabilitazione, che potrebbe avere altri svantaggi o addirittura essere impossibile, nel caso del commutatore di attività). In sostanza, tutto ciò che va oltre lo stack corrente deve essere considerato volatile.

noti inoltre che questo è indipendente dalla questione di chi pulisce i parametri. In linea di principio, la funzione chiamata potrebbe chiamare distruttori chiamate degli argomenti anche se fisicamente si trovano in stack frame del chiamante.Inoltre, molti processori (incluso x86) hanno istruzioni che fanno automaticamente spazio extra sopra l'indirizzo di ritorno al momento del ritorno (ad esempio, i compilatori Pascal lo facevano di solito perché in Pascal non si ha alcuna ripulitura oltre a restituire memoria, e almeno fr processori del tempo, era più efficiente pulire con quella istruzione del processore (non ho idea se ciò sia ancora vero per i processori moderni). C tuttavia non ha usato quel meccanismo a causa degli elenchi di argomenti di lunghezza variabile: per quelli, il meccanismo non era applicabile perché avresti bisogno di sapere in fase di compilazione quanto spazio extra da rilasciare, e K & RC non ha richiesto di inoltrare funzioni variadiche (C89 lo fa, ma pochi se qualsiasi compilatore ne approfitta, a causa della compatibilità con il vecchio codice), quindi non c'era modo per la funzione chiamante di sapere se pulire gli argomenti a meno che non lo facesse sempre.

Problemi correlati