2012-01-21 28 views
7

Estoy intentando hacer algo de programación básica en ARM con GCC y probando en QEMU. Cada vez que llamo a una etiqueta ARM desde C, mi programa se cuelga. Tengo un ejemplo simple de código que muestra el problema en https://gist.github.com/1654392 - cuando llamo activate() en ese código, se cuelga.Llamando al conjunto ARM desde C, GCC (metal desnudo)

He observado con objdump que cuando hago un bl desde el ensamblado hasta el código C (desde _start) está generando una pequeña envoltura que cambia a instrucciones de pulgar. Parece que el código C se está generando en las instrucciones, pero todo mi ensamblaje se genera en instrucciones ARM (32 bits). No puedo entender por qué es esto o cómo solucionarlo.

+0

dónde está el compilador? –

+0

kernel.o :(. ARM.exidx + 0x0): referencia indefinida a '__aeabi_unwind_cpp_pr1 ' make: *** [kernel.elf] Error 1 –

+0

¿Estás intentando construir una aplicación de brazo linux? o una aplicación incrustada (sin sistema operativo)? si es una aplicación de Linux, entonces no necesita el código de inicio, la cadena de herramientas debe hacer todo eso por usted, le preocupa que main() sea su punto de entrada. –

Respuesta

5

Para llamar a una función de modo ARM definida en ensamblaje desde una función de modo PULGADA definida en C, necesita definir un símbolo en ensamblaje como una función, y las herramientas (Linaro gcc) producirán una instrucción blx en lugar de bl.

Ejemplo:

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

.type fn, %function 

fn: 
    mov pc, lr 
+0

¡Gracias!Esto parece funcionar perfectamente y me permite vincularlo en el código de la biblioteca. – singpolyma

3

ver http://github.com/dwelch67/yagbat qemu directorio.

Aquí hay un par de ejemplos de llamar brazo o el pulgar del brazo

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 

Si nos fijamos en la referencia del conjunto de instrucciones se verá que es necesario utilizar BX o BLX para cambiar entre el brazo y el pulgar estados . BLX no es tan ampliamente compatible como BX.

Desde el punto de vista de la definición, el contador del programa, la PC tiene dos instrucciones por delante durante la ejecución de una instrucción. para el pulgar que es de 4 bytes, para armar 8 bytes. En cualquier caso, dos instrucciones. Para simular un bl que no se puede usar para cambiar el estado, debe cargar el registro de enlace con la dirección de retorno, y usar un bx para bifurcar al estado de cambio de función dependiendo del lsbit de la dirección. por lo que el

mov lr,pc 
bx r1 
here: 

lr mov, PC por encima de carga la dirección de aquí: que es nuestra dirección de retorno, r1 bx de una manera independiente del estado llama a la función. el bit menos significativo de la dirección de izquierda a derecha indica el modo de volver a y hay que utilizar siempre BX para volver

pre_thumb: 
ldr pc,lr 

thumb_capable: 
bx lr 

El compilador asigna una instrucción de BL para llamar funciones, el enlazador rellena el resto más tarde, si es demasiado lejos de un alcance, entonces necesita una función de trampolín que el enlazador se está agregando. Del mismo modo, si necesita cambiar los modos, el bl llama a una función de trampolín que hace eso. He modelado eso en uno de los anteriores para imitar eso, se puede ver que es un poco derrochador, con suerte mi explicación del compilador solo asignando espacio para un bl lo hace más claro, desperdiciador sería siempre planear un cambio de modo y tiene que insertar nops para la mayoría de las llamadas a funciones en el código.

El código también incluye una llamada para armar desde el pulgar en ensamblador:

.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 

sobre todo igual, excepto que no se puede hacer estallar a LR en el modo de pulgar, que puede hacer estallar a la PC, pero yo no creo que cambia de modo , por lo que no puede usarlo, nuevamente necesita un registro extra. Usted, por supuesto, necesita saber las convenciones de llamada para saber qué registros se puede utilizar o se puede envolver otra serie de empujones y pops para preservar todos menos 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 

pulgar a pulgar o un brazo a otro sólo tiene que utilizar un bl si puedes alcanzar ldr pc, dirección si no puedes.

0

Si ensambla el código asm como Pulgar, debe marcar la función como una función Pulgar, de modo que el enlazador utilice las instrucciones correctas cuando se bifurca (por ejemplo, BLX o BX a una dirección con el bit bajo configurado). Esto se hace con el.Directiva thumb_func:

.global activate 
.thumb_func 
activate: 
    b test 

Otra opción es pedir explícitamente el ensamblador para generar código ARM:

.code 32 
.global activate 
activate: 
    b test 

Comprobar this article también, aunque recuerde que los procesadores actuales no necesitan muchas soluciones que eran necesarios en ARMv4 , entonces probablemente no deberías seguirlo a ciegas.

0

para eliminar la confusión:

El problema era que GCC compilador cruzado de Ubuntu para ARM genera instrucciones de pulgar (16 bits) de forma predeterminada. Como muestran otras respuestas aquí, es posible llamar entre los dos, pero mientras el ensamblador GNU detectó que el código C estaba generando instrucciones y por lo tanto generó cuñas usando bx para configurar correctamente el modo para llamar a en C, no tengo control sobre lo que GCC genera para las funciones de llamada, y las llamaba con solo bl, que se rompió porque mi código ensamblador debe ser instrucciones ARM (32 bits).

La solución (que está poco documentada) es enviar gcc -marm, que al menos hará que todos los códigos sean del mismo tipo.

Si hay un interruptor para que gcc genere llamadas bx para funciones, probablemente también funcione.

+0

gcc -marm no funciona para mí. Necesito el código de ensamblaje para arm-v4t-linux-gnueabi –