Comprensione dello stack frame della chiamata di funzione in C / C ++?


19

Sto cercando di capire come vengono costruiti i frame di stack e quali variabili (parametri) vengono spinti per impilare in quale ordine? Alcuni risultati della ricerca hanno mostrato che il compilatore C / C ++ decide in base alle operazioni eseguite all'interno di una funzione. Ad esempio, se la funzione dovesse solo incrementare un valore int passato di 1 (simile all'operatore ++) e restituirlo, metterebbe tutti i parametri della funzione e le variabili locali nei registri.

Mi chiedo quali registri vengano utilizzati per i parametri restituiti o passati. Come vengono restituiti i riferimenti? Come fa il compilatore a scegliere tra eax, ebx, ecx ed edx?

Cosa devo sapere per capire come registri, riferimenti stack e heap vengono utilizzati, creati e distrutti durante le chiamate di funzione?


questo è piuttosto difficile da leggere (muro di testo). Ti dispiacerebbe modificare il tuo post in una forma migliore?
moscerino del

1
Questa domanda mi sembra piuttosto ampia. Inoltre, questo non sarà molto specifico per la piattaforma?
Kazark,

La domanda è stata posta anche su SO: stackoverflow.com/questions/16088040/…
Wayne Conrad,

Risposte:


11

Oltre a ciò che ha detto Dirk, un uso importante dei frame dello stack è quello di salvare i valori precedenti dei registri in modo che possano essere ripristinati dopo una chiamata di funzione. Pertanto, anche sui processori in cui i registri vengono utilizzati per passare parametri, restituire un valore e salvare l'indirizzo di ritorno, i valori di tali registri vengono salvati nello stack prima di una chiamata di funzione in modo che possano essere ripristinati dopo la chiamata. Ciò consente a una funzione di chiamarne un'altra senza sovrascrivere i propri parametri o dimenticare il proprio indirizzo di ritorno.

Pertanto, la chiamata di una funzione B dalla funzione A su un tipico sistema "generico" potrebbe comportare i seguenti passaggi:

  • funzione A:
    • spingere lo spazio per il valore restituito
    • parametri push
    • spingere l'indirizzo di ritorno
  • passa alla funzione B
  • funzione B:
    • spingere l'indirizzo del frame dello stack precedente
    • invia i valori dei registri utilizzati da questa funzione (in modo che possano essere ripristinati)
    • spingere spazio per le variabili locali
    • fare il calcolo necessario
    • ripristinare i registri
    • ripristinare il frame dello stack precedente
    • memorizzare il risultato della funzione
    • passa all'indirizzo di ritorno
  • funzione A:
    • pop i parametri
    • pop il valore di ritorno

Questo non è affatto l'unico modo in cui le chiamate di funzione possono funzionare (e potrei avere un passo o due fuori servizio), ma dovrebbe darti un'idea di come lo stack viene utilizzato per consentire al processore di gestire le chiamate di funzione nidificate.


Cosa significa esattamente "push" qui? Non ho idea di cosa farne.
Tomáš Zato - Ripristina Monica il

2
@ TomášZato pushe popsono le due operazioni fondamentali in pila. Una pila è una struttura last-in-first-out, come una pila di libri. Quando stai push, stai mettendo un nuovo oggetto in cima alla pila; quando popprendi un oggetto dalla cima della pila. Non è consentito inserire o rimuovere oggetti nel mezzo, è possibile operare solo nella parte superiore della pila. Puoi leggere di più sugli stack in generale e sullo stack del programma in particolare su Wikipedia.
Caleb,

11

Questo dipende dalla convenzione di chiamata in uso. Chiunque definisce la convenzione di chiamata può prendere questa decisione come desidera.

Nella convenzione di chiamata più comune su x86, i registri non vengono utilizzati per passare parametri; i parametri vengono inseriti nello stack a partire dal parametro più a destra. Il valore restituito viene inserito in eax e può utilizzare edx se necessita di spazio aggiuntivo. Riferimenti e puntatori vengono entrambi restituiti sotto forma di indirizzo in eax.


5

Se capisci molto bene lo stack, allora capirai come funziona la memoria nel programma e se capisci come funziona la memoria nel programma, capirai come l'archivio funzioni nel programma e se capisci come l'archivio funzioni nel programma capirai come funziona la funzione ricorsiva e se capisci come funziona la funzione ricorsiva capirai come funziona il compilatore e se capisci come funziona il compilatore la tua mente funzionerà come compilatore e eseguirai il debug di qualsiasi programma molto facilmente

Lasciami spiegare come funziona lo stack:

Per prima cosa devi sapere come store di funzioni nello stack:

Valori di allocazione della memoria dinamica dell'heap store. Stack store valori di allocazione e cancellazione automatici.

inserisci qui la descrizione dell'immagine

Comprendiamo con esempio:

def hello(x):
    if x==1:
        return "op"
    else:
        u=1
        e=12
        s=hello(x-1)
        e+=1
        print(s)
        print(x)
        u+=1
    return e

hello(4)

Ora capisci parti di questo programma:

inserisci qui la descrizione dell'immagine

Ora vediamo cos'è lo stack e quali sono le parti dello stack:

inserisci qui la descrizione dell'immagine

Allocazione dello stack:

Ricorda una cosa se una qualsiasi funzione ottiene "return", indipendentemente dal fatto che abbia caricato tutte le sue variabili locali o qualsiasi cosa restituisca immediatamente dallo stack, sarà il suo frame dello stack. Significa che quando una qualsiasi funzione ricorsiva ottiene la condizione di base e mettiamo il ritorno dopo la condizione di base, quindi la condizione di base non aspetterà di caricare le variabili locali che si trovano nella parte "else" del programma, restituirà immediatamente il frame corrente dallo stack e ora se un frame ritorna il prossimo fotogramma è nel record di attivazione. Vedi questo in pratica:

inserisci qui la descrizione dell'immagine

Deallocation del blocco:

Quindi ora ogni volta che una funzione trova un'istruzione return, cancella il frame corrente dallo stack.

mentre ritornano dal valore dello stack torneranno in ordine inverso rispetto all'ordine in cui sono stati allocati nello stack.

inserisci qui la descrizione dell'immagine

Queste sono una descrizione molto breve e se vuoi saperne di più sullo stack e sulla doppia ricorsione leggi due post di questo blog:

Maggiori informazioni sullo stack passo dopo passo

Maggiori informazioni sulla doppia ricorsione passo dopo passo con lo stack


Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.