2013-04-20 4 views
12

Capisco che ho bisogno di spingere il registro di collegamento all'inizio di una chiamata di funzione, e inserire quel valore nel Program Couter prima di tornare, in modo che l'esecuzione possa portarne uno da dove era prima della chiamata di funzione.ARM: Perché devo premere/inserire due registri nelle chiamate di funzione?

Quello che non capisco è perché la maggior parte delle persone lo fa aggiungendo un registro extra al push/pop. Per esempio:

push {ip, lr} 
... 
pop {ip, pc} 

Per esempio, ecco un mondo Ciao a ARM, forniti dal official ARM blog:

.syntax unified 

    @ -------------------------------- 
    .global main 
main: 
    @ Stack the return address (lr) in addition to a dummy register (ip) to 
    @ keep the stack 8-byte aligned. 
    push {ip, lr} 

    @ Load the argument and perform the call. This is like 'printf("...")' in C. 
    ldr  r0, =message 
    bl  printf 

    @ Exit from 'main'. This is like 'return 0' in C. 
    mov  r0, #0  @ Return 0. 
    @ Pop the dummy ip to reverse our alignment fix, and pop the original lr 
    @ value directly into pc — the Program Counter — to return. 
    pop  {ip, pc} 

    @ -------------------------------- 
    @ Data for the printf calls. The GNU assembler's ".asciz" directive 
    @ automatically adds a NULL character termination. 
message: 
    .asciz "Hello, world.\n" 

Domanda 1: qual è la ragione per "registro fittizio" il come lo chiamano ? Perché non spingere semplicemente {lr} e pop {pc}? Dicono che è per mantenere allineato lo stack di 8 byte, ma non è allineato lo stack di 4 byte?

Domanda 2: ciò che registro è "ip" (vale a dire, R7 o cosa?)

+0

Ho collegato a un post del blog ARM in cui raccomandano questo modello a due registri. Si prega di controllare, c'è del codice lì. –

+0

utilizzando i collegamenti è sconsigliato su SO, perché il collegamento potrebbe non durare fino a quando la domanda (e/o semplicemente rimuovere la domanda perché utilizza collegamenti piuttosto che avere la discussione qui). –

+0

ahh, quindi il link risponde alla tua domanda. Puoi pubblicare la risposta da solo. e chiudi questa domanda. –

risposta

5

qual è il motivo di "registro fittizio" il come lo chiamano? Perché non spingere semplicemente {lr} e pop {pc}? Dicono che è per mantenere allineato lo stack di 8 byte, ma non è allineato lo stack di 4 byte?

Lo stack richiede solo l'allineamento a 4 byte; ma se il bus dati ha una larghezza di 64 bit (come in molti ARM moderni), è più efficiente mantenerlo su un allineamento di 8 byte. Quindi, ad esempio, se si chiama una funzione per cui lo ha bisogno di per impilare due registri, è possibile farlo in una singola scrittura a 64 bit anziché in due scritture a 32 bit.

AGGIORNAMENTO: Apparentemente non è solo per l'efficienza; è un requisito dello standard di chiamata della procedura ufficiale, come indicato nei commenti.

Se si stanno cercando vecchi ARM a 32 bit, il registro sovrapposto in più potrebbe ridurre leggermente le prestazioni.

ciò che registro è "ip" (vale a dire, R7 o cosa?)

r12. Vedere, ad esempio, here per l'insieme completo di alias di registro utilizzati dallo standard di chiamata della procedura.

+0

Grazie mille, questo lo spiega. –

+1

Questa risposta è fuorviante e pericolosa. Allineamento a 8 byte È un requisito per tutto il codice conforme EABI e il fatto di non mantenerlo su tutti i limiti esterni può causare errori di runtime. Ancor peggio, può comportare errori di runtime quando viene creato su determinate versioni di compilatori in esecuzione su determinati processori. – unixsmurf

+2

Solo echo la risposta di @ unixsmurf. 5.2.1.2 degli stati AAPCS "SP mod 8 = 0. Lo stack deve essere allineato a due parole." per interfacce pubbliche. Vuoi davvero seguirlo sempre, a meno che tu non sappia cosa stai facendo. ARM ha un articolo di conoscenza su [Allineamento dello stack di 8 byte pure] (http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.faqs/ka4127.html). – jszakmeister

3

Dal momento che si desidera memorizzare e recuperare dopo aver eseguito la funzione. Sulla funzione entrence salva i registri ip e lr (denominato prolog). Dopo aver terminato la funzione che assegna entrambi (epilog):

pc <- lr 

ip <- old_ip 

EDIT

Register r12 è indicato anche come IP, ed è usato come un intra-procedura registro graffio chiamata vedi also.

La convenzione è che la funzione callee può cambiare ip,r0-r3 quindi è necessario ripristinarli dependes sul calling convention

EDIT2: Why we might want the stack to be 8 aligned on ARM

Se la pila non è di otto byte allineato l'uso di LDRD e STRD (load and store doubleword) potrebbe causare un errore di allineamento, a seconda della destinazione e della configurazione utilizzato.

Nota that we have the same issue on X86, e Mac OS we have 16 bytes alignment

+0

So che lo fa.La mia domanda è perché la maggior parte delle persone usa due registri su push/pop. Perché non spingere {lr} e pop {pc} semplicemente? –

+0

poiché la lingua abilita la selezione di {liste di registri}, ed è un'istruzione di assemblaggio, supponendo che si desideri memorizzare 'r0-r15' è possibile farlo in lunghezza di codice a 32 bit o 15 * lunghezza di codice a 32 bit, cosa è meglio? http://en.wikipedia.org/wiki/KISS_principle – 0x90

+0

Non hai capito la mia domanda. L'ho ri-montato, check it out. –

6

L'allineamento a 8 byte è un requisito per l'interoperabilità tra oggetti conformi a AAPCS.

braccio ha una nota di consulenza su questo argomento:

ABI for the ARM® Architecture Advisory Note – SP must be 8-byte aligned on entry to AAPCS-conforming functions

articolo cita due ragioni per usare 8 byte allineamento

  • errore di allineamento o di un comportamento imprevedibile. (Motivi correlati all'hardware/all'architettura - LDRD/STRD potrebbero causare un errore di allineamento o mostrare un comportamento INDIPENDIBILE su architetture diverse da ARMv7)

  • Errore dell'applicazione. (Compiler - differenze Runtime assunzione, danno va_start e va_arg come esempio)

Naturalmente questo è tutto interfacce pubbliche, se si stanno facendo un eseguibile statico, senza ulteriore collegamento è possibile allineare pila a 4 byte .

+0

Vale la pena menzionare: il caso di uso dei registri del negozio 2 è così comune che in armv8, che ha abbandonato 'push' e' pop', ci sono istruzioni push pair e pop pair 'stp' e' ldp': http: // stackoverflow. com/domande/27941220/push-LR-and-pop-LR-in-braccio-Arch64 –