2012-01-21 17 views
7

Sto provando a eseguire una programmazione bare-metal in ARM con GCC e test su QEMU. Ogni volta che chiamo in un'etichetta ARM da C, il mio programma si blocca. Ho un semplice esempio di codice che mostra il problema a https://gist.github.com/1654392 - quando chiamo activate() in quel codice, si blocca.Chiamare il gruppo ARM da C, GCC (bare metal)

Ho osservato con objdump che quando eseguo un bl da assembly a codice C (come da _start) genera un piccolo wrapper che passa alle istruzioni del pollice. Sembra che il codice C sia tutto generato nelle istruzioni del pollice, ma tutto il mio assembly viene generato in istruzioni ARM (32 bit). Non riesco a capire perché questo sia o come risolverlo.

+0

dove si trova questo compilatore da? –

+0

kernel.o :(. ARM.exidx + 0x0): riferimento non definito a '__aeabi_unwind_cpp_pr1 ' make: *** [kernel.elf] Errore 1 –

+0

stai provando a creare un'applicazione arm linux? o un'applicazione incorporata (senza sistema operativo)? se un'applicazione Linux non ha bisogno di codice di avvio, la toolchain dovrebbe fare tutto questo per te, ti preoccupi di main() come punto di ingresso. –

risposta

5

Per chiamare una funzione di modalità ARM definita in assembly da una funzione in modalità THUMB definita in C, è necessario definire un simbolo in assembly come una funzione e gli strumenti (Linaro gcc) generano un'istruzione blx anziché bl.

Esempio:

@ Here, we suppose that this part of code is inside of .code 32 

.type fn, %function 

fn: 
    mov pc, lr 
+0

Grazie!Questo sembra funzionare perfettamente e mi permette di collegare il codice della libreria! – singpolyma

3

vedere la directory http://github.com/dwelch67/yagbat qemu.

Ecco un paio di esempi di chiamare il braccio o il pollice dal braccio

start_vector: 
    mov sp,#0x20000 
    ;@ call an arm function from arm 
    bl notmain 

    ;@ call a thumb function frm arm 
    ldr r0,=0xAABBAABB 
    bl hexstring_trampoline 

    ;@ call a thumb function frm arm 
    ldr r0,=0x12341234 
    ldr r1,hexstring_addr 
    mov lr,pc 
    bx r1 

    ;@ call a thumb function frm arm 
    ldr r0,=0x12312344 
    bl hexstring_trampoline 

hang: 
    b hang 

hexstring_trampoline: 
    ldr r1,hexstring_addr 
    bx r1 

hexstring_addr: .word hexstring 

Se si guarda il riferimento set di istruzioni vedrete che è necessario utilizzare BX o BLX per passare tra braccio e pollice stati . BLX non è ampiamente supportato come BX.

Dal punto di vista della definizione, il contatore del programma, pc è due istruzioni successive durante l'esecuzione di un'istruzione. per pollice che è 4 byte, per braccio 8 byte. In entrambi i casi due istruzioni. Per simulare un bl che non può essere usato per cambiare stato, è necessario caricare il registro di collegamento con l'indirizzo di ritorno, e utilizzare un bx per diramarlo allo stato di modifica della funzione a seconda dell'lbit dell'indirizzo. così il

mov lr,pc 
bx r1 
here: 

lr converter, pc sopra carica l'indirizzo di qui: che è il nostro indirizzo di ritorno, bx r1 in modo indipendente stato chiama la funzione. la LSBit dell'indirizzo lr indica il modo per tornare a ed è necessario utilizzare sempre BX per tornare

pre_thumb: 
ldr pc,lr 

thumb_capable: 
bx lr 

Il compilatore alloca un'istruzione bl per le funzioni di chiamata, il linker riempie il resto più tardi, se è troppo di gran lunga quindi ha bisogno di una funzione trampolino che il linker si aggiunge. Allo stesso modo, se è necessario cambiare modalità, il bl chiama una funzione trampolino che lo fa. Ho modellato che in uno dei precedenti per simularlo, si può vedere che è un po 'dispendioso, si spera che la mia spiegazione del compilatore che alloca solo lo spazio per un bl rende più chiaro e dispendioso pianificare sempre un cambio di modalità e inserire nops per la maggior parte delle chiamate di funzione nel codice.

Il codice comprende anche una chiamata a braccio dal pollice in assembler:

.thumb 

.thumb_func 
.globl XPUT32 
XPUT32: 
    push {lr} 
    ;@ call an arm function from thumb asm 
    ldr r2,=PUT32 
    mov lr,pc 
    bx r2 
    pop {r2} 
    bx r2 

per lo più lo stesso, tranne non si può pop alla Lr in modalità pollice, è possibile pop al pc, ma non penso che gli interruttori modalità , quindi non puoi usarlo, hai ancora bisogno di un registro di riserva. È ovviamente necessario conoscere le convenzioni di chiamata per sapere cosa registri è possibile utilizzare o si può avvolgere un altro set di spinte e pop per conservare tutti, ma lr

push {r2,lr} 
    ;@ call an arm function from thumb asm 
    ldr r2,=PUT32 
    mov lr,pc 
    bx r2 
    pop {r2} 
    mov lr,r2 
    pop {r2} 
    bx lr 

pollice per pollice o un braccio all'altro è sufficiente utilizzare un bl se puoi raggiungere pc ldr, indirizzo se non puoi.

0

Se si assembla il codice asm come Thumb, è necessario contrassegnare la funzione come una funzione Thumb, in modo che il linker utilizzi l'istruzione corretta quando si dirama (ad esempio BLX o BX in un indirizzo con il bit basso impostato). Questo è fatto con il.direttiva thumb_func:

.global activate 
.thumb_func 
activate: 
    b test 

Un'altra opzione è quella di chiedere in modo esplicito l'assemblatore per generare il codice ARM:

.code 32 
.global activate 
activate: 
    b test 

Controllare this article troppo, anche se ricordiamo che i processori attuali non hanno bisogno di molte soluzioni alternative che erano necessarie in ARMv4 , quindi probabilmente non dovresti seguirlo alla cieca.

0

di eliminare la confusione:

Il problema era che di Ubuntu GCC cross-compilatore per ARM genera pollice istruzioni (a 16 bit) per impostazione predefinita. Come mostrano altre risposte, chiamare tra i due è possibile, ma mentre l'assemblatore GNU ha rilevato che il codice C stava generando istruzioni pollice e ha così felicemente generato shim usando bx per impostare correttamente la modalità per chiamare in C, non ho controllo su ciò che GCC stesso genera per chiamare le funzioni, e lo chiamava semplicemente con bl, che si è rotto perché il mio codice assembly doveva essere istruzioni ARM (32 bit).

La soluzione (che è scarsamente documentata) è quella di inviare gcc -marm, che renderà almeno tutto il codice dello stesso tipo.

Se c'è un passaggio per ottenere gcc per generare chiamate bx per le funzioni, probabilmente funzionerebbe anche.

+0

gcc -marm non funziona per me. Ho bisogno del codice assembly per arm-v4t-linux-gnueabi –