2011-06-18 11 views
9

Estoy trabajando en un proyecto ARM7TDMI usando GCC 4.3 y tengo dificultades para decirle al compilador que use llamadas largas en ciertos casos pero no en otros.long_calls entre secciones RAM y ROM en bare metal ARM con gcc

El proceso de construcción se ejecuta arm-eabi-gcc para generar ficheros objeto ELF reubicable para cada archivo de origen .c (CFLAGS más relevantes incluyen -Os -ffunction-sections -fdata-sections -mthumb -mthumb-interwork), luego todos los enlaces en un archivo ejecutable ELF (la mayoría de LDFLAGS relevantes incluyen -Wl,--gc-sections -Wl,-static -Wl,-n -nostdlib, y una secuencia de comandos personalizada enlazador) . A continuación, ese archivo ELF se convierte en un ejecutable sin procesar con arm-eabi-objcopy -O binary, y un gestor de arranque personalizado lo copia de ROM a RAM (una sola SRAM con código y datos) al inicio. Entonces, todo se ejecuta desde RAM, .rodata está presente en la RAM, y todo avanza rápidamente, ignorando completamente la ROM después del arranque.

Estoy tratando de cambiar eso, de modo que ciertas piezas seleccionadas de datos de RO y el texto de las funciones de selección solo puedan vivir en ROM y se pueda acceder durante el tiempo de ejecución según sea necesario. Modifiqué la secuencia de comandos del enlazador para conocer dos secciones nuevas, ".flashdata" y ".flashtext", y ambas deben colocarse en una dirección fija de la ROM. También rocié __attribute__((__section__(".flashdata"))) y __attribute__((__section__(".flashtext"),__long_call__)) en todo el código C, según corresponda, y rejigué el proceso de compilación para que el viejo objcopy ahora agregue -R .flashdata -R .flashtext, y hago un segundo objcopy con -j para cada una de esas secciones, luego combino el dos archivos de salida para que el gestor de arranque pueda hacer lo correcto y las secciones ROM aparecen en la ubicación asignada de memoria esperada.

Todo esto funciona bien - puedo printf cadenas etiquetados en la sección .flashdata, y puedo llamar a una función .flashtext de código que se ejecuta sin memoria RAM (que sabe utilizar una llamada de larga duración debido al atributo __long_call__ junto al atributo __section__(".flashtext")) Esa función basada en ROM puede, afortunadamente, llamar brevemente a otras funciones basadas en ROM, y puede regresar a su llamador basado en RAM.

El problema consiste en intentar llamar desde una función basada en ROM a una basada en RAM, que también debe ser una llamada larga. No quiero utilizar llamadas largas en todas partes, así que no quiero -mlong_calls en mi CFLAGS. Si agrupo todas las funciones para vivir en ROM en un solo rom.c, puedo construir ese archivo con -mlong-calls y todo funciona. Sin embargo, prefiero evitar eso, y mantener las funciones agrupadas generalmente por propósito, simplemente etiquetando algunas aquí y allá según sea apropiado para ejecutar desde ROM.

Por cierto, esto no era suficiente en gcc 3.4. El uso de -mlong-calls hizo que el compilador pensara lo correcto, pero no pudo seguir porque solo estaba dispuesto a realizar saltos largos con sus ayudantes _call_via_rX ... todos vivían en la RAM y solo se podía acceder mediante una llamada larga. This was fixed in the linker in gcc 4.0, but not backported to anything in the 3.x tree.

Así que es maravilloso que ahora pueda volver a llamar a RAM, ya que estoy usando gcc 4.3. Sería aún mejor si pudiera etiquetar el código de alguna manera en las funciones basadas en ROM para forzarlo a usar llamadas largas. Hay un #pragma long_calls, pero solo afecta a las declaraciones, por lo que podría usarlo en lugar de __attribute__((__long_call__)). Por desgracia, no obliga mágicamente al compilador a utilizar llamadas largas para todas las llamadas a funciones que se producen mientras está en vigor.

Organizacionalmente, simplemente no es lo correcto hacer agrupar todo el código de ejecución lenta en un solo archivo, fuera de contexto y separado de otro código en su categoría general. Por favor dime que hay una opción que aún no he considerado. ¿Por qué las secciones de no-función o simplemente el hecho de que el código está en diferentes secciones (.text versus .flashtext) solucionando automáticamente mi problema?

Por cierto, el error de salida del engarce cuando se da cuenta de que el compilador usó una llamada corta que no dejó suficiente espacio para gestionar la reubicación es: relocation truncated to fit: R_ARM_THM_CALL against symbol foo 'definido en la sección .text.foo en objs/foo.o (and the section .text.foo is used instead of .text because of -ffunction-sections` en CFLAGS).

Respuesta

3

Parece que el problema probablemente se corrigió en gcc 4.3.3 y posterior, pero he estado usando 4.3.2. Creé un ejemplo de mascota que no se ejecutará, pero demuestra el uso de diferentes secciones y el error de enlace resultante. No se puede compilar con el arm-2008q3 de Codesourcery, pero se compila con arm-2009q1 y posterior. Me llevará más tiempo actualizar todo el proyecto para usar una versión más nueva de gcc, por lo que todavía no puedo decir de manera definitiva que esto solucione mi problema, pero sospecho que sí lo hace.

Como un aparte, tengo otra solución alternativa a la agrupación de todas las funciones basadas en ROM en un -mthumb-calls -cimbra construida.c: llamar a todo a través del puntero de función. En el caso de esta solución, la cura es peor que la enfermedad:

((void(*)(void*, void*, int))&memcpy+1)(&dest, &src, len); 

Se necesita el +1 para que el optimizador no le burlar, pero no es un problema en mi caso porque bx -ing a una la dirección impar indica el modo pulgar, y todo mi código es pulgar. Sin embargo, no creo que exista una forma de hacer que una macro genérica abarque todas las llamadas a funciones, ya que cada puntero deberá emitirse explícitamente para que coincida con el tipo de retorno y la lista de argumentos; de hecho, se volverá a declarar explícitamente cada función desea llamar, incluso las funciones de la biblioteca que no proporciona.

3

Sospecho que no hay forma de hacer lo que desea automáticamente. Tengo una sugerencia, aunque no es exactamente lo que quieres.

declarar las funciones de memoria RAM (en ram_funcs.h, dicen) así:

int foo() RAM_CALL; 

a continuación, poner todas sus funciones ROM en sus propios archivos, y empezar cada uno de esos archivos como esto:

#define RAM_CALL __attribute__((__long_call__)) 
#include "ram_funcs.h" 

Otros archivos se utilizan:

#define RAM_CALL 
#include "ram_funcs.h" 

Esto no es mucho mejor que usar -mlong-calls, pero al menos pone la lógica cerca de las funciones en vez de en alguna opción de compilación. Por lo tanto, es más fácil poner algunas funciones en cada archivo .c.

Cuestiones relacionadas