tools plugin mcu c eclipse memory-management gcc embedded

plugin - mcu eclipse



¿Qué significa este error de GCC "... relocation truncated to fit..."? (6)

A menudo, lo que significa este error es que su programa es demasiado grande y, a menudo, es demasiado grande porque contiene uno o más objetos de datos muy grandes. Por ejemplo,

char large_array[1ul << 31]; int other_global; int main(void) { return other_global; }

producirá un error de "reubicación truncada para ajustarse" en x86-64 / Linux, si se compila en el modo predeterminado y sin optimización. (Si large_array optimización, podría, al menos en teoría, descubrir que large_array no se utiliza y / o que other_global nunca se escribe, y así generar código que no desencadene el problema).

Lo que sucede es que, de forma predeterminada, GCC usa su "modelo de código pequeño" en esta arquitectura, en la que todo el código del programa y los datos asignados estáticamente deben caber en los 2 GB más bajos del espacio de direcciones. (El límite superior exacto es algo así como 2GB - 2MB, porque los 2MB más bajos del espacio de direcciones de cualquier programa permanecen inutilizables. Si está compilando una biblioteca compartida o un ejecutable independiente de la posición, todo el código y los datos aún deben caber en dos gigabytes, pero ya no están clavados en el fondo del espacio de direcciones). large_array consume todo ese espacio por sí mismo, por lo que a other_global se le asigna una dirección por encima del límite, y el código generado para main no puede alcanzarlo. Se obtiene un error críptico del enlazador, en lugar de un error útil " large_array es demasiado grande" del compilador, porque en casos más complejos el compilador no puede saber que other_global estará fuera de su alcance, por lo que ni siquiera intenta para los casos simples.

La mayoría de las veces, la respuesta correcta para obtener este error es refactorizar su programa para que no necesite arreglos estáticos gigantescos y / o gigabytes de código máquina. Sin embargo, si realmente los necesita por alguna razón, puede usar los modelos de código "mediano" o "grande" para elevar los límites, al precio de una generación de código algo menos eficiente. Estos modelos de código son específicos de x86-64; algo similar existe para la mayoría de las otras arquitecturas, pero el conjunto exacto de "modelos" y los límites asociados variarán. (En una arquitectura de 32 bits, por ejemplo, es posible que tenga un modelo "pequeño" en el que la cantidad total de código y datos se limitó a algo así como 2 24 bytes).

Estoy programando el lado del host de un sistema acelerador de host. El host se ejecuta en la PC bajo Ubuntu Linux y se comunica con el hardware integrado a través de una conexión USB. La comunicación se realiza copiando fragmentos de memoria hacia y desde la memoria del hardware incrustado.

En la memoria de la placa hay una región de memoria que utilizo como un buzón donde escribo y leo los datos. El buzón se define como una estructura y yo uso la misma definición para asignar un buzón espejo en mi espacio de host.

Utilicé esta técnica con éxito en el pasado, así que ahora copié el proyecto Eclipse del host en el espacio de trabajo de mi proyecto actual e hice los cambios de nombre apropiados. Lo extraño es que al construir el proyecto de host ahora recibo el siguiente mensaje:

Objetivo de compilación: fft2d_host
Invocando: GCC C Linker
gcc -L / opt / adapteva / esdk / tools / host / x86_64 / lib -o "fft2d_host" ./src/fft2d_host.o -le_host -lrt

./src/fft2d_host.o: en la función `main '':

fft2d_host.c :(. text + 0x280): reubicación truncada para ajustarse: R_X86_64_PC32 contra el símbolo `Buzón ''definido en la sección COMÚN en ./src/fft2d_host.o

¿Qué significa este error y por qué no se basará en el proyecto actual, mientras que está bien con el proyecto anterior?


En Cygwin -mcmodel=medium ya está predeterminado y no ayuda. Para mí, agregar -Wl,--image-base -Wl,0x10000000 al engarce de GCC solucionó el error.


Está intentando vincular su proyecto de tal manera que el objetivo de un esquema de direccionamiento relativo está más lejos de lo que puede admitirse con el desplazamiento de 32 bits del modo de direccionamiento relativo elegido. Esto podría deberse a que el proyecto actual es más grande porque está vinculando archivos de objetos en un orden diferente, o porque hay un esquema de mapeo expansivo innecesario en juego.

Esta pregunta es un ejemplo perfecto de por qué a menudo es productivo hacer una búsqueda en la web en la parte genérica de un mensaje de error: encuentras cosas como esta:

http://www.technovelty.org/code/c/relocation-truncated.html

Que ofrece algunas sugerencias curativas.


Me encontré con este problema al construir un programa que requiere una gran cantidad de espacio de pila (más de 2 GiB). La solución fue agregar el indicador -mcmodel=medium , que es compatible con los compiladores de GCC e Intel.


Recuerde abordar los mensajes de error en orden. En mi caso, el error por encima de este fue "referencia indefinida", y visualmente omití el error "truncamiento de reubicación" más interesante. De hecho, mi problema era una biblioteca antigua que causaba el mensaje de "referencia no definida". Una vez que lo arreglé, la "reubicación truncada" se fue también.


Ejemplo mínimo que genera el error

main.S : mueve una dirección a %eax (32 bits):

_start: mov $_start, %eax

linker.ld :

SECTIONS { /* This says where `.text` will go in the executable. */ . = 0x100000000; .text : { *(*) } }

Compilar en x86-64:

as -o main.o main.S ld -o main.out -T linker.ld main.o

Resultado de ld :

(.text+0x1): relocation truncated to fit: R_X86_64_32 against `.text''

Manten eso en mente:

  • as pone todo en .text si no se especifica ninguna otra sección
  • ld usa .text como el punto de entrada predeterminado si ENTRY . Por lo tanto _start es el primer byte de .text .

Cómo solucionarlo: use este linker.ld en linker.ld lugar, y reste 1 desde el inicio:

SECTIONS { . = 0xFFFFFFFF; .text : { *(*) } }

Notas:

  • no podemos hacer _start global en este ejemplo con .global _start , de lo contrario, sigue fallando. Creo que esto sucede porque los símbolos globales tienen restricciones de alineación ( 0xFFFFFFF0 funciona). ¿TODO dónde está eso documentado en el estándar ELF?

  • el segmento .text también tiene una restricción de alineación de p_align == 2M . Pero nuestro enlazador es lo suficientemente inteligente como para colocar el segmento en 0xFFE00000 , rellenarlo con ceros hasta 0xFFFFFFFF y establecer e_entry == 0xFFFFFFFF . Esto funciona, pero genera un ejecutable de gran tamaño.

Probado en Ubuntu 14.04 AMD64, Binutils 2.24.

Explicación

Primero debe comprender qué es la reubicación con un ejemplo mínimo: https://.com/a/30507725/895245

A continuación, eche un vistazo a objdump -Sr main.o :

0000000000000000 <_start>: 0: b8 00 00 00 00 mov $0x0,%eax 1: R_X86_64_32 .text

Si miramos cómo están codificadas las instrucciones en el manual de Intel, vemos que:

  • b8 dice que esto es un mov a %eax
  • 0 es un valor inmediato que se moverá a %eax . La reubicación lo modificará para que contenga la dirección de _start .

Cuando se mueve a registros de 32 bits, el inmediato también debe ser de 32 bits.

Pero aquí, la reubicación tiene que modificar esos 32 bits para poner la dirección de _start en ellos después de que se _start vinculación.

0x100000000 no encaja en 32 bits, pero 0xFFFFFFFF sí. Por lo tanto, el error.

Este error solo puede ocurrir en reubicaciones que generan truncamiento, por ejemplo, R_X86_64_32 (8 bytes a 4 bytes), pero nunca en R_X86_64_64 .

Y hay algunos tipos de reubicación que requieren extensión de signo en lugar de extensión cero, como se muestra aquí, por ejemplo, R_X86_64_32S . Ver también: https://.com/a/33289761/895245