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.
Aquí hay una referencia útil [referencia a la sintaxis del script del enlazador] (http://www.xgc.com/manuals/gcc-1750-ug/p5node10.html) –
A partir de 2015, gcc ya no hace esto. Ver: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=192 –