BRACCIO: link registrazione e frame pointer

Sto cercando di capire come il link registrazione e il frame pointer lavoro in BRACCIO. Ho un paio di siti, e volevo confermare la mia comprensione.

Supponiamo che ho avuto il seguente codice:

int foo(void)
{
    //..
    bar();
    //(A)
    //..
}

int bar(void)
{
    //(B)
    int b1;
    //..
    //(C)
    baz();
    //(D)
}

int baz(void)
{
    //(E)
    int a;
    int b;
    //(F)
}

e ho chiamata foo(). Sarebbe il link registrati contenere l’indirizzo del codice di cui al punto (A) e il telaio puntatore contiene l’indirizzo al codice di cui al punto (B)? E il puntatore dello stack avrebbe potuto essere in qualsiasi luogo all’interno di un bar(), dopo che tutti i locali sono stati dichiarati?

[edit] Aggiunto un’altra funzione chiamata baz()

  • Io non sono sicuro di quello che si potrebbe dire “il puntatore dello stack avrebbe potuto essere in qualsiasi luogo all’interno di un bar()”. Inoltre, ti sembra di chiedere che cosa è lo stato di queste cose potrebbe essere quando foo() chiamate bar(), non quando qualcosa di chiamate foo() (ma forse sto fraintendimento la domanda).
  • Sì, volevo dire lo stato delle cose quando foo() chiama bar(). Quello che volevo dire per quanto riguarda il SP è stato che dopo i locali sono stati dichiarati e mettere in pila, la SP punta alla cima dello stack, in cui l’ultima variabile locale è stato dichiarato.
  • possibile duplicato di Quali sono le SP (stack) e LR in BRACCIO?
InformationsquelleAutor user2233706 | 2013-04-01



2 Replies
  1. 68

    Alcune registro convenzioni di chiamata dipende dalla ABI (Application Binary Interface). Il FP è richiesto il APC standard e non il più recente AAPCS (2003). Per il AAPCS (GCC 5.0+) il FP non hanno per essere utilizzati, ma certamente può essere; informazioni di debug è annotato con stack e frame pointer utilizzare per l’analisi dello stack e rilassarsi con il codice AAPCS. Se una funzione è static, un compilatore in realtà non aderire a eventuali convenzioni.

    In genere tutte BRACCIO registri sono general purpose. Il lr (link registrazione, anche R14) e pc (contatore di programma anche R15) sono speciali e affidare il set di istruzioni. È giusto che il lr a Un. Il pc e lr sono correlati. Uno è “dove sei” e l’altro è “dove sei”. Essi sono il codice aspetto di una funzione.

    In genere, abbiamo il sp (stack pointer, R13) e il fp (frame pointer, R11). Questi due sono anche correlati. Questo
    Microsoft layout fa un buon lavoro di descrivere le cose. Il stack è utilizzato per memorizzare i dati temporanei o locali in funzione. Tutte le variabili in foo() e bar(), sono memorizzati qui, sullo stack o in registri disponibili. Il fp tiene traccia delle variabili da funzione a funzione. Si tratta di un telaio o la finestra dell’immagine sullo stack per quella funzione. Il ABI definisce un layout di questo telaio. In genere il lr e altri registri sono salvati qui, dietro le quinte dal compilatore e il precedente valore di fp. Questo rende un lista collegata di stack frame e se si vuole si può ripercorrere tutta la strada indietro per main(). Il radice è fp, che punta a uno stack frame (come un struct) con una variabile in struct essere precedente fp. Si può andare lungo la lista fino all’ultimo fp che normalmente NULL.

    In modo che il sp è dove lo stack e il fp è dove la pila è stata, un po ‘ come il pc e lr. Ogni vecchio lr (link register) è memorizzato nel vecchio fp (frame pointer). Il sp e fp sono un dati aspetto di funzioni.

    Il tuo punto di B è attivo pc e sp. Punto Un è in realtà il fp e lr; a meno che non si chiama ancora un’altra funzione e quindi il compilatore potrebbe ottenere pronto per l’installazione della fp di scegliere i dati in B.

    Di seguito è riportato un BRACCIO assembler che potrebbe dimostrare come tutto questo funziona. Questo sarà diverso a seconda di come il compilatore ottimizza, ma dovrebbe dare un’idea,

    ; Prologo - installazione 
    mov ip, sp ; ottenere una copia di sp. 
    stmdb sp!, {fp, ip, lr, pc} ; Salvare il frame nello stack. Vedi Addendum 
    sub fp, ip, #4 ; Impostare il nuovo frame pointer. 
    ... 
    ; Forse altre funzioni chiamato qui.
    Anziani chiamante ritorno
    lr memorizzato nello stack frame. bl baz ... ; Epilogo - il ritorno ldm sp, {fp, sp, lr} ; ripristino stack frame pointer e il vecchio link. ... ; forse più roba qui. bx lr ; return.

    Questo è ciò che foo() sarebbe simile. Se non si bar(), quindi il compilatore foglia di ottimizzazione e non ha bisogno di salvare il telaio; solo il bx lr è necessario. Probabilmente questo forse perché non si sono confusi dal web esempi. Non è sempre la stessa.

    L’asporto, dovrebbe essere,

    1. pc e lr sono relative codice registri. Uno è “Dove sei”, l’altro è “Dove sei”.
    2. sp e fp sono relative dati locali registri.
      Uno è “Dove i dati sono”, l’altro è “Dove gli ultimi dati locali è”.
    3. Il lavoro insieme con il passaggio del parametro per creare funzione macchine.
    4. È difficile descrivere un caso generale, perché vogliamo che i compilatori di essere come veloce possibile, in modo che utilizzare ogni trucco possibile.

    Questi concetti sono generici per tutte le Cpu e i linguaggi compilati, anche se i dettagli possono variare. L’uso del link registrazione, frame pointer sono parte del funzione di prologo e un epilogo, e se hai capito tutto, tu sai come un di overflow dello stack funziona su un BRACCIO.

    Vedi anche: BRACCIO convenzione di chiamata.

                    MSDN BRACCIO stack articolo

                    Università di Cambridge APC panoramica

                    BRACCIO stack trace blog

                    Apple ABI link

    Base per il layout della struttura è,

    • fp[-0] salvato pc, dove abbiamo memorizzato questo telaio.
    • fp[-1] salvato lr, l’indirizzo di ritorno della funzione.
    • fp[-2] precedente sp, prima di questa funzione mangia stack.
    • fp[-3] precedente fp, l’ultimo stack frame.
    • tanti optional registri…

    Un ABI possono utilizzare altri valori, ma cui sopra sono tipici per la maggior parte delle configurazioni.

    Addendum: Questo non è un errore in assembler, ma è normale. Una spiegazione è il BRACCIO generato prologs domanda.

    • Ok, lr è dove il codice è stato, e fp è dove lo stack è stato. Questo significa che, se avessi avuto un’altra funzione baz(), sp sarebbe al punto (F) perché il puntatore dello stack è stato spostato per allocare le variabili a e b all’interno baz(); fp essere di cui al punto (E) perché sp era in cima baz(); e lr sarebbe a (D)?
    • Ho aggiornato la risposta. Invece di etichette, potrebbe essere meglio chiarire. Quando in baz(), sp a baz() dati. pc è baz() codice. Il fp punti di roba per ripristinare bar() contesto di codice e di dati O vecchio sp e vecchio lr==foo() ritorno. lr è il ritorno alla bar(), a meno che non baz() chiamate più funzioni, quindi il compilatore deve salvare lr in un altro stack frame perché la chiamata di distruggere lr.
    • Questo è il senso. L’attivo corrente lr contiene l’indirizzo di tornare al precedente stack frame (è “dove sei”). Attivo fp è un indirizzo interno al corrente dello stack frame. fp, lr, e ip vengono salvati nello stack prima che la succursale di una nuova funzione. Quando si esegue bx lr è tornare indietro di un frame dello stack. Ma poi, nel tuo codice, non dovrebbe essere il ripristino lr dallo stack dopo il bx lr dal lr già contiene in cui è necessario tornare? In caso contrario, si sarebbe ramo i precedenti-i precedenti stack frame.
    • Whoa, io avrei detto il lr contiene l’indirizzo del codice, dal precedente chiamata di funzione, per tornare a non l’indirizzo di tornare al precedente stack frame. lr punti da qualche parte nel testo segmento, mentre fp punti da qualche parte nella pila.
  2. 0

    Disclaimer: penso che questo è più o meno giusto; si prega di correggere come necessario.

    Come indicato altrove in questo Q&A, essere consapevoli del fatto che il compilatore non può essere richiesto per generare (ABI) il codice che utilizza frame puntatori. Frame nello stack di chiamate può spesso richiedere informazioni inutili a essere messo.

    Se le opzioni del compilatore chiamata per ‘frames’ (una pseudo flag di opzione), quindi il compilatore è in grado di generare più piccolo codice che mantiene stack di chiamate di dati più piccoli. La funzione di chiamata è compilato per memorizzare solo il necessario, chiamando info sullo stack, e la funzione chiamata è compilato solo pop le necessarie informazioni chiamare dalla pila.

    Ciò consente di risparmiare il tempo di esecuzione e spazio di stack – ma si rende analisi a ritroso nel codice chiamante estremamente difficile (ho rinunciato a…)

    Informazioni circa la dimensione e la forma della vocazione informazioni sullo stack è conosciuta solo dal compilatore e che l’info è stata gettata via dopo la fase di compilazione.

Lascia un commento