2012-05-07 22 views
39

Estoy programando el lado 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.¿Qué significa este error de GCC "... relocation truncated to fit ..."?

En la memoria de la placa hay una región de memoria que utilizo como buzón de correo 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 de Eclipse del host al espacio de trabajo de mi proyecto actual y realicé los cambios de nombre apropiados. Lo extraño es que cuando la construcción del proyecto de acogida que ahora aparece el siguiente mensaje:

Edificio objetivo: fft2d_host
Invocación: GCC C Enlazador
gcc -L/opt/adapteva/esdk/herramientas/host/x86_64/-o lib "fft2d_host" ./src/fft2d_host.o -le_host -lrt

./src/fft2d_host.o: En función `principal:.

fft2d_host.c :(texto + 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?

Respuesta

39

Está intentando vincular su proyecto de tal forma que el objetivo de un esquema de direccionamiento relativo está más alejado 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é es a menudo productivo que hacer una búsqueda en Internet sobre la parte genérica de un mensaje de error - a encontrar cosas como esta:

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

que ofrece algunas sugerencias curativas.

+2

Aquí hay una sugerencia: Puede ser crear accidentalmente objeto (s) de 64 bits sin '-fPIC'. Eso me hizo tropezar por un tiempo. –

6

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.

+0

yo también: el problema estaba desactualizado .o archivos. Los encabezados se referían a funciones que no estaban allí. Recompilado y estuvo bien, supongo que el enlazador en estas situaciones decide que la ubicación es "muy grande" en lugar de "inexistente" :) – robert

13

ejemplo Minimal que genera el error

main.S: mueve una direcciónen %eax (32-bit):

_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' 

Tenga en cuenta que:

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

cómo solucionarlo: Utilice esta linker.ld lugar, y restar 1 desde el principio:

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

Notas:

  • no podemos hacer _start global en este ejemplo con .global _start, de lo contrario, todavía falla. 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, llenarlo 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

En primer lugar hay que entender lo que la reubicación es con un ejemplo mínimo: https://stackoverflow.com/a/30507725/895245

A continuación, echar 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 nos fijamos en cómo instrucciones son codificado en el manual de Intel, vemos que:

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

Al mover a los 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 ocurra la vinculación.

0x100000000 no cabe en 32 bits, pero 0xFFFFFFFF hace. Por lo tanto, el error.

Este error solo puede ocurrir en reubicaciones que generan truncamiento, p. 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 la extensión de signo en lugar de cero como se muestra aquí, p. Ej. R_X86_64_32S. Ver también: https://stackoverflow.com/a/33289761/895245

7

Me encontré con este problema al crear 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.

+2

Confirmo esto. Tampoco tiene que compilarlo como una biblioteca usando '-fPIC': https://software.intel.com/en-us/forums/intel-fortran-compiler-for-linux-and-mac-os-x/ tema/268374 # comment-1590873 –

+1

En caso de que esto no fuera obvio, ** no use '-mcmodel = medium' si no tiene que **, porque hace que el asm sea menos eficiente cuando se trata de grande ('-mlarge-data-threshold' se establece por defecto en 64kiB) arrays estáticos/globales. Busque primero otras razones, p. prueba '-fPIC'. No es obvio por qué más de 2GB de * stack * serían incompatibles con '-mcmodel = small' por defecto, ya que los símbolos globales no se refieren a la memoria de la pila, y la pila ya está fuera de la baja 2GiB para el normal (' -mcmodel = pequeños') ejecutables. Ver https://gcc.gnu.org/onlinedocs/gcc/x86-Options.html. –

5

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.

+0

Eso funciona para mí. ¿Cómo te diste cuenta de eso? – garyp

3

A menudo, lo que significa este error es su programa es demasiado grande, y con frecuencia 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á una "reubicación truncado para caber" error en x86-64/Linux si se compila en el modo por defecto y sin optimización. (Si activa la optimización, podría, al menos en teoría, darse cuenta de que large_array no se utiliza y/o que other_global no está escrito, y así generar código que no provoca el problema.)

Lo que está pasando 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 permanentemente no se pueden usar.Si está compilando una biblioteca compartida o un ejecutable independiente de la posición, todo el código y los datos todavía deben caber en dos gigabytes, pero ya no están clavados en la parte inferior del espacio de direcciones). large_array consume todo ese espacio por sí mismo , por lo que other_global tiene asignada una dirección superior al límite, y el código generado para main no puede alcanzarlo. Se obtiene un error críptico del vinculador, 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 gigantescas matrices estáticas y/o gigabytes de código máquina. Sin embargo, si realmente los necesita por alguna razón, puede usar el "medium" or "large" code models para levantar 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 bytes)

+0

Gracias. Como se señaló en la pregunta, este no es un código x86. Esto fue hace mucho tiempo, pero de todos modos, no estoy seguro de cómo el tamaño del modelo de código está relacionado con un procesador integrado. ¿No era esta limitación/propiedad específica de x86? – ysap

+0

@ysap Cada arquitectura de CPU tiene limitaciones _like_ this - generalmente se establece por la cantidad de bits que entran en el operando inmediato de alguna instrucción de máquina. Escribí esta respuesta porque se cerró una pregunta mucho más reciente como duplicado de esta pregunta y no creo que las respuestas existentes aborden muy bien el problema de esa persona, y utilicé x86-64 solo como un ejemplo conveniente. (El mensaje de error en la pregunta contiene el término 'R_X86_64_PC32', que seguro suena como si estuvieras compilando código para x86-64. Tal vez tu problema real era que tu archivo MAKE no invocaba el compilador cruzado que debería tener) – zwol

+0

Estaba compilando de forma cruzada con seguridad, pero bueno, incluso esa compañía ya no existe ... Gracias por la contribución. – ysap

Cuestiones relacionadas