2011-06-22 16 views
11

Empezaré con la última pregunta: en C con gcc, es posible obtener los valores de __func__ (o equivalentemente, __FUNCTION__) almacenados en una sección que no sea .rodata (o donde sea -mrodata= puntos) o subsección de la misma?Forzar ciertas variables generadas por el compilador en secciones específicas de ELF (con gcc)

La explicación completa:

Decir que tengo una macro de registro:

operador
#define LOG(fmt, ...) log_internal(__FILE__, __LINE__, __func__, fmt, ##__VA_ARGS__) 

(La concatenación de cadenas ## utilizado en ese contexto unario consume la coma anterior si y sólo si la lista __VA_ARGS__ está vacía , lo que permite el uso de una cadena de formato con o sin argumentos.)

Puedo utilizar la macro normalmente:

void my_function(void) { 
    LOG("foo!"); 
    LOG("bar: %p", &bar); 
} 

podría imprimir (obviamente dependiendo de la implementación de log_internal):

foo.c:201(my_function) foo! 
foo.c:202(my_function) bar: 0x12345678 

En este caso, las cadenas de formato ("foo" y "bar: %p") y las cadenas de preprocesador ("foo.c" y "my_function") son anónimas sólo lectura de datos , y se colocan automáticamente en la sección .rodata.

Pero digo que quiero que vayan a un lugar diferente (estoy en una plataforma incrustada que ejecuta casi todo desde RAM para velocidad, pero las restricciones de memoria están presionando para mover algunas cosas a la ROM). Es "fácil" para mover __FILE__ y la cadena de formato:

#define ROM_STR(str) (__extension__({static const __attribute__((__section__(".rom_data"))) char __c[] = (str); (const char *)&__c;})) 
#define LOG(fmt, ...) log_internal(ROM_STR(__FILE__), __LINE__, __func__, ROM_STR(fmt), ##__VA_ARGS__) 

No se puede poner un __attribute__ en una cadena anónima, por lo que el ROM_STR macro le da un nombre transitoria, afijos a una sección específica, después evalúa a la dirección de inicio, por lo que puede sustituir limpiamente. Esto no funciona si intenta pasar una variable char * a LOG como su cadena de formato, pero estoy dispuesto a excluir ese caso de uso.

Normalmente, las cadenas anónimas que son idénticas se combinan por el compilador en una única ubicación de almacenamiento, por lo que cada instancia de __FILE__ en un archivo compartiría la misma dirección de tiempo de ejecución. Con la nomenclatura explícita en ROM_STR, cada instancia obtendrá su propia ubicación de almacenamiento, por lo que probablemente no tenga sentido usarla en __FILE__.

Sin embargo, me gustaría usarlo en __func__. El problema es que __func__ no es el mismo tipo de magia que __FILE__. Desde el manual de gcc, "Los nombres de función como cadenas":

El identificador __func__ se declara implícitamente por el traductor como si, inmediatamente después de la llave de apertura de cada definición de función, la declaración

static const char __func__[] = "function-name"; 

aparece, donde nombre-función es el nombre de la función que encierra léxicamente. Este nombre es el nombre sin adornos de la función. ... Estos identificadores no son macros de preprocesador. En GCC 3.3 y anteriores, y solo en C, __FUNCTION__ y __PRETTY_FUNCTION__ se trataron como literales de cadena; podrían usarse para inicializar matrices de caracteres, y podrían concatenarse con otras literas de cadenas. GCC 3.4 y posterior los tratan como variables, como __func__.

Por lo tanto, si usted envuelve __func__ con ROM_STR, se obtiene

error: invalid initializer 

y si se intenta poner un atributo de la sección antes o después del uso de __func__, se obtiene

error: expected expression before ‘__attribute__’ 

o

error: expected ‘)’ before ‘__attribute__’ 

Y así volvemos a la pregunta de apertura: ¿es posible obtener __func__ almacenado en la sección que elija? Tal vez puedo usar -fdata-sections y hacer algo de magia del script enlazador para obtener .rodata.__func__.* excluidos del resto de .rodata? Si es así, ¿cuál es la sintaxis para globbing con exclusión en un script enlazador? En otras palabras, en algún lugar tiene un *(.rodata*) - podría poner un en otro lugar, pero tendría que modificar el glob original para excluirlo, así que no recibo dos copias.

Respuesta

2

Parece que respondí mi propia pregunta al final con el negocio -fdata-sections, simplemente no entendí el Enlazador de GNU lo suficiente para verlo. En realidad, no necesito el globbing con exclusión siempre que especifique el bit primero. Todas las secciones que coinciden con las combinaciones globales se marcarán como utilizadas, por lo que una imagen global posterior para *(.rodata*) no contará dos veces y las copiará en otro lugar. No necesito etiquetarlos con ROM_STR en absoluto. ¡Guay!

Es importante tener en cuenta que -fdata-sections realmente pone cada cadena de función en su propia sección .rodata.__func__.1234 (no estoy seguro de qué patrón siguen los números). No sé si las cadenas anónimas también tienen sus propias secciones; de ser así, podría usar los mismos trucos de enlazador para capturar todas las cadenas anónimas en lugar de la macro de atributo de sección ROM_STR, pero probablemente sería una mala idea. ROM_STR se usa en la macro LOG, por lo que se garantiza que solo se aplicará a las cadenas de formato de registro. Si forzaba todas las cadenas anónimas en ROM con un truco de enlazador, eso incluiría datos de mensajes normales, y pagaría una penalización de rendimiento en tiempo de ejecución para acceder desde Flash. Así que no sé si es posible, pero su conveniencia dependerá de los requisitos específicos de su sistema.

+0

Aquí hay una referencia útil [referencia a la sintaxis del script del enlazador] (http://www.xgc.com/manuals/gcc-1750-ug/p5node10.html) –

+1

A partir de 2015, gcc ya no hace esto. Ver: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=192 –

3

Un enfoque, que puede ser más complicado de lo que le gustaría, sería interponer una secuencia de comandos para cambiar los nombres de las secciones entre la compilación y el ensamblaje. Por ejemplo:

gcc -fdata-sections -S -o test.s test.c 
sed 's/^\t.section\t\.rodata\.__func__\.[0-9]*/\t.section .rom_data/' -i test.s 
gcc -c test.s 

También podría intentar escribir un pase transformación sonido metálico para colocar los __func__ declaraciones en una sección de su elección, o escribiendo un programa de manipulación de archivos objeto utilizando libbfd.

+0

Creo que el proceso de dos pasos para cambiar el nombre de las secciones en los archivos de ensamblado intermedio definitivamente podría funcionar. Con una inteligencia extra (no trivial), una secuencia de comandos podría incluso seleccionar los datos adecuados si compiló sin '-fdata-sections'. Pero mis experimentos y lecturas adicionales en los scripts del enlazador muestran que es mucho más fácil de lo que pensé colocar esas secciones explícitamente, así que lo detallé en una respuesta diferente. –

+0

Además, +1 para el enlace a BFD. Eso podría ser útil para muchas cosas. –

Cuestiones relacionadas