Acceder a los símbolos definidos en el script del enlazador por aplicación

6 minutos de lectura

avatar de usuario
ka05

En mi archivo de script del enlazador, he definido dos símbolos

define symbol _region_RAM_start__     = 0xC0000000;
define symbol _region_RAM_end__       = 0xC00fffff; 

y luego los he exportado como se muestra a continuación

export symbol _region_RAM_start__;
export symbol _region_RAM_end__;

Desde el código de la aplicación intento acceder a estos símbolos

extern const unsigned int _region_RAM_start__;
extern const unsigned int _region_RAM_end__;
....
int GetRAMSize()
{
    int size = 0;
    unsigned int address_1 = _region_RAM_start__;
    unsigned int address_2 = _region_RAM_end__;
    size = address_2 - address_1 + 1U;
    return size;
}

Ahora, esperaba que el valor devuelto fuera 0x00100000, sin embargo, todo lo que obtengo es 0. Entonces, cuando recurrí al depurador, noté que _region_RAM_start__ y _region_RAM_end__ tienen los valores 0xC0000000 y 0xC00fffff respectivamente, pero address_1 y address_2 tener el valor 0.

La optimización del compilador se establece en “Ninguno”. Esto me ha estado molestando desde hace un tiempo. ¿Hay algo muy obvio que me estoy perdiendo aquí? (aparte de “No debería estar haciendo esto en primer lugar”)?

Solución
Gracias a nm por la respuesta

  unsigned int address_1 = (unsigned int) (&_region_RAM_start__);

De lo contrario address_1 y address_2 ambos contienen valores basura (es decir, valores disponibles en la dirección 0xC0000000 y 0xC00fffff respectivamente, pero basura desde el punto de vista de este código)

  • Este es un comportamiento correcto y esperado. Un símbolo es un nombre para una dirección. extern xyz significa “Sr. Linker, no sé la dirección de xyzpor favor resuélvelo por mí”.

    – norte 1.8e9-dónde-está-mi-participación m.

    6 de diciembre de 2011 a las 11:12


  • ¡Perfecto! Gracias por el puntero @nm Así que la solución fue usar address_1 = (int sin firmar) (&_region_RAM_start__);

    – ka05

    6 de diciembre de 2011 a las 11:51

  • Iba a preguntar: ¿dónde está el define sintaxis documentada, pero finalmente vi la etiqueta iar. ¡Hay otros enlazadores por ahí en el mundo! 🙂

    – Ciro Santilli Путлер Капут 六四事

    06/10/2015 a las 21:38

avatar de usuario
Keith mono

Eso es un poco viejo, pero lo responderé de todos modos…

Desde el ld manual:

Acceder a una variable definida por el script del enlazador desde el código fuente no es intuitivo. En particular, un símbolo de script de enlace no es equivalente a una declaración de variable en un lenguaje de alto nivel, sino que es un símbolo que no tiene un valor.

Antes de continuar, es importante tener en cuenta que los compiladores a menudo transforman los nombres del código fuente en nombres diferentes cuando se almacenan en la tabla de símbolos. Por ejemplo, los compiladores de Fortran suelen anteponer o agregar un guión bajo, y C++ realiza una amplia manipulación de nombres. Por lo tanto, puede haber una discrepancia entre el nombre de una variable como se usa en el código fuente y el nombre de la misma variable como se define en un script de enlace. Por ejemplo, en C, una variable de secuencia de comandos del enlazador podría denominarse como:

extern int foo;

Pero en el script del enlazador podría definirse como:

_foo = 1000;

Sin embargo, en los ejemplos restantes se supone que no ha tenido lugar ninguna transformación de nombre.

Cuando se declara un símbolo en un lenguaje de alto nivel como C, suceden dos cosas. La primera es que el compilador reserva suficiente espacio en la memoria del programa para contener el valor del símbolo. La segunda es que el compilador crea una entrada en la tabla de símbolos del programa que contiene el símbolo Dirección. es decir, la tabla de símbolos contiene la dirección del bloque de memoria que contiene el valor del símbolo. Entonces, por ejemplo, la siguiente declaración C, en el alcance del archivo:

int foo = 1000;

crea una entrada llamada “foo” en la tabla de símbolos. Esta entrada contiene la dirección de un bloque de memoria de tamaño int donde se almacena inicialmente el número 1000.

Cuando un programa hace referencia a un símbolo, el compilador genera código que primero accede a la tabla de símbolos para encontrar la dirección del bloque de memoria del símbolo y luego codifica para leer el valor de ese bloque de memoria. Asi que:

foo = 1;

busca el símbolo foo en la tabla de símbolos, obtiene la dirección asociada con este símbolo y luego escribe el valor 1 en esa dirección. Mientras:

int * a = & foo;

busca el símbolo foo en la tabla de símbolos, obtiene su dirección y luego copia esta dirección en el bloque de memoria asociado con la variable “a”.

Las declaraciones de símbolos de los scripts de enlazador, por el contrario, crean una entrada en la tabla de símbolos pero no les asignan ninguna memoria. Por lo tanto, son una dirección sin valor. Entonces, por ejemplo, la definición del script del enlazador:

foo = 1000;

crea una entrada en la tabla de símbolos llamada @samp{foo} que contiene la dirección de la ubicación de memoria 1000, pero no se almacena nada especial en la dirección 1000. Esto significa que no puede acceder a la valor de un símbolo definido por el script del enlazador – no tiene ningún valor – todo lo que puede hacer es usar el Dirección de un símbolo definido por la secuencia de comandos del enlazador.

Por lo tanto, cuando utilice un símbolo definido por un script de vinculación en el código fuente, siempre debe tomar la dirección del símbolo y nunca intentar utilizar su valor. Por ejemplo, suponga que desea copiar el contenido de una sección de memoria llamada .ROM en una sección llamada .FLASH y el script del enlazador contiene estas declaraciones:

start_of_ROM   = .ROM;
end_of_ROM     = .ROM + sizeof (.ROM);
start_of_FLASH = .FLASH;

Entonces el código fuente en C para realizar la copia sería:

extern char start_of_ROM, end_of_ROM, start_of_FLASH;

memcpy (& start_of_FLASH, & start_of_ROM, & end_of_ROM - & start_of_ROM);

Tenga en cuenta el uso de los operadores “&”. son correctos

  • si copia y pega de otra fuente, debe citarlo. sourceware.org/binutils/docs/ld/Source-Code-Reference.html

    – Felipe

    11/06/2017 a las 21:25

  • He estado escribiendo secuencias de comandos de enlazador y código mixto C/ASM durante años y este me hizo abofetearme la cabeza. Por supuesto, tiene sentido que los símbolos de enlace sean siempre ubicaciones de almacenamiento y no valores una vez explicados. Gracias.

    – gran josh

    22 de abril de 2019 a las 2:04

Dado que son símbolos de dirección genéricos a los que intenta acceder y no necesariamente punteros a un tipo específico, no desea declararlos sin firmar, sino declararlos como

vacío externo _region_RAM_START;

entonces &_region_RAM_START tendrá el tipo apropiado ‘void *’.

avatar de usuario
Juan Sures Kumar

El siguiente código debería funcionar como se esperaba:

extern const volatile unsigned int _region_RAM_start__;

extern const volatile unsigned int _region_RAM_end__;

....
int GetRAMSize()

{

int size = 0;

unsigned int address_1 = &_region_RAM_start__;

unsigned int address_2 = &_region_RAM_end__;

size = address_2 - address_1 + 1U;

return size;

}

  • si _region_RAM_end__ es un unsigned intla expresion &_region_RAM_end__ es un unsigned int* y no se puede asignar a un unsigned int address_2. Verifique la salida del mensaje de su compilador.

    – arpista

    6 de marzo de 2018 a las 15:01


¿Ha sido útil esta solución?