2013-03-27 14 views
5

Ho un codice di avvio per un ARM bare metal scritto in assembly e sto cercando di capire come funziona. Il file binario è scritto in alcuni Flash esterni e sta copiando parti di se stesso nella RAM all'avvio. Non ho ancora capito esattamente il concetto di delocalizzazione in questo contesto, anche se ho letto questo wikipedia entry. La RAM è mappata a una finestra di indirizzo basso e il flash in una finestra di indirizzo alto. Qualcuno può spiegarmi perché testiamo qui il valore del registro di collegamento?Trasferimento in assembly

/* Test if we are running from an address, we are not linked at */ 
     bl check_position 
check_position: 
     mov  r0, lr     
     ldr  r1, =check_position 
     cmp  r0, r1     /* ; don't relocate during debug */ 
     beq  relocated_entry 
+0

Grazie per le due eccellenti risposte! Accetterei entrambi se coud, dal momento che uno spiega l'obiettivo del codice (l'ipotesi del programma di caricamento del programma JTAG è corretta) e il secondo come funziona esattamente. –

risposta

5

La mia ipotesi è l'applicazione viene eseguita dalla RAM, e durante il debug dell'applicazione questo autore è forse utilizzando una sorta di bootloader ed o JTAG per caricare l'applicazione di test direttamente nella RAM, quindi nessuna ragione per copiare ed eseguire (che potrebbe causare un arresto anomalo).

Un'altra ragione per cui si dovrebbe fare qualcosa di simile è evitare un ciclo infinito. Se ad esempio si desidera eseguire l'avvio da Flash (in genere) ma eseguire da RAM, il modo più semplice per farlo è copiare semplicemente l'intero flash o tutto un po 'di flash in RAM e diramarlo all'inizio di RAM. Il che quando si fa questo significa che si preme di nuovo il ciclo "copia l'app su ram e ramificazioni", per evitarlo la seconda volta (che potrebbe bloccarti), si ha una sorta di sto eseguendo questo ciclo da flash o non test.

3

Qualcuno può spiegarmi perché testiamo qui il valore del registro di collegamento?

Il bl check_position posizionerà il valore di PC+4 nel registro link per trasferire il controllo al check_position relativa anche PC. bl at ARM Finora tutto è PC relativo.

ldr r1,=check_position riceve un valore dal pool letterario . Rif1 Il codice attuale sembra,

ldr r1,[pc, #offset] 
... 
    offset: 
    .long check_position # absolute address from assemble/link. 

Così il R0 contiene una versione relativa PC e il R1 contiene la versione in assoluto assemblato. Qui, sono confrontati. È anche possibile utilizzare l'aritmetica per calcolare la differenza e quindi ramo se non zero; o possibilmente copiare il codice nella sua destinazione assoluta. Ref2 Se il codice è in esecuzione allo indirizzo, quindi R0 e R1 sono gli stessi. Questo è un po 'pseudo code per bl.

mov lr,pc    ; pc is actually two instruction ahead. 
add pc,pc,#branch_offset-8 

La chiave è che BL fa tutto in base alla PC compreso l'aggiornamento di lr. Invece di usare questo trucco , potremmo usare mov R0,PC, eccetto lo PC con 8 byte di anticipo. Un'altra alternativa sarebbe quella di usare adr R0,check_position, che farebbe sì che l'assemblatore faccia tutti gli indirizzi matematici per noi.

/* Test if we are running from an address, we are not linked at */ 
check_position: 
    adr r0, check_position 
    ldr r1, =check_position 
    cmp r0, r1     /* ; don't relocate during debug */ 
    beq relocated_entry 

Rif1: Vedi Arm op-codes e .ltorg nel manuale di GNU-assemblatore
Rif2: Questo è esattamente ciò che il Linux head.S sta facendo per l'ARM.

Modifica: Ho controllato il BRACCIO ARM e il PC è apparentemente l'istruzione corrente +8, che va a mostrare perché il codice era come questo. Penso che la versione adr sia più diretta e leggibile, ma la pseudo-op adr non viene utilizzata più spesso così le persone potrebbero non averne familiarità.