2012-05-07 23 views
39

Sto programmando il lato host di un sistema host-accelerator. L'host viene eseguito sul PC sotto Ubuntu Linux e comunica con l'hardware incorporato tramite una connessione USB. La comunicazione viene eseguita copiando blocchi di memoria da e verso la memoria dell'hardware incorporato.Che cosa significa questo errore GCC "... relocation truncated to fit ..."?

Sulla memoria della scheda è presente un'area di memoria che utilizzo come mailbox in cui scrivo e leggo i dati. La cassetta postale è definita come una struttura e io uso la stessa definizione per allocare una casella postale mirror nel mio spazio host.

Ho usato questa tecnica con successo in passato, quindi ora ho copiato il progetto host Eclipse nello spazio di lavoro del mio progetto corrente e ho apportato le modifiche al nome appropriato. La cosa strana è che quando si costruisce il progetto di accoglienza ora ottengo il seguente messaggio: obiettivo

costruzione: fft2d_host
Invocare: GCC C Linker
gcc -L/opt/Adapteva/esdk/strumenti/host/x86_64/-o lib "fft2d_host" ./src/fft2d_host.o -le_host -lrt

./src/fft2d_host.o: In funzione `main':.

fft2d_host.c :(testo + 0x280): trasferimento troncato per adattarsi: R_X86_64_PC32 contro il simbolo `Mailbox 'definito nella sezione COMMON in ./src/fft2d_host.o

Che cosa significa questo errore e perché non si baserà sul progetto corrente, mentre è corretto con il progetto precedente?

risposta

39

Si sta tentando di collegare il progetto in modo tale che l'obiettivo di uno schema di indirizzamento relativo sia più lontano di quello che può essere supportato con lo spostamento a 32 bit della modalità di indirizzamento relativo scelto. Ciò potrebbe essere dovuto al fatto che il progetto corrente è più grande, perché collega i file oggetto in un ordine diverso o perché è in gioco uno schema di mappatura inutilmente espansivo.

questa domanda è un perfetto esempio del perché è spesso produttiva di fare una ricerca sul web sulla parte generica di un messaggio di errore - a trovare cose come questa:

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

che offre alcuni suggerimenti curative.

+2

Ecco un suggerimento: potresti essere costruire accidentalmente oggetti a 64 bit senza '-fPIC'. Questo mi ha fatto inciampare per un po '. –

6

Ricordarsi di gestire i messaggi di errore in ordine. Nel mio caso, l'errore sopra questo era "riferimento non definito" e l'ho visivamente ignorato per l'errore "dislocazione" più interessante. In effetti, il mio problema era una vecchia libreria che stava causando il messaggio "riferimento non definito". Una volta sistemato, anche il "trasferimento troncato" andò via.

+0

anche io: il problema era scaduto .o file. Le intestazioni si riferivano a funzioni che non c'erano. Ricompilato e andava bene, immagino che il linker in queste situazioni decida che la posizione è "molto grande" piuttosto che "inesistente" :) – robert

13

Esempio minimo che genera l'errore

main.S: muove un indirizzo in %eax (32 bit):

_start: 
    mov $_start, %eax 

linker.ld:

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

Compile x86 -64:

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

Esito ld:

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

Tenete a mente che:

  • as mette tutto sul .text se nessun altra sezione è specificato
  • ld utilizza il .text come il punto di ingresso predefinito se ENTRY. Pertanto, _start è il primo byte di .text.

come risolvere il problema: utilizzare questo linker.ld invece, e sottrarre 1 fin dall'inizio:

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

Note:

  • non possiamo fare _start globale in questo esempio con .global _start, altrimenti fallisce ancora. Penso che questo accada perché i simboli globali hanno vincoli di allineamento (0xFFFFFFF0 funziona). TODO dove è documentato nello standard ELF?

  • il segmento .text ha anche un vincolo di allineamento di p_align == 2M. Ma il nostro linker è abbastanza intelligente da posizionare il segmento a 0xFFE00000, riempire di zeri fino a 0xFFFFFFFF e impostare e_entry == 0xFFFFFFFF. Funziona, ma genera un eseguibile sovradimensionato.

Testato su Ubuntu 14.04 AMD64, Binutils 2.24.

Spiegazione

In primo luogo è necessario capire che cosa delocalizzazione è un esempio minimo: https://stackoverflow.com/a/30507725/895245

Avanti, date un'occhiata a objdump -Sr main.o:

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

Se guardiamo come le istruzioni sono codificato nel manuale Intel, vediamo che:

  • b8 dice che questo è un mov per %eax
  • 0 è un valore immediato di essere spostati in %eax. Il riposizionamento lo modificherà per contenere l'indirizzo di _start.

Quando si passa a registri a 32 bit, l'immediato deve essere anche 32 bit.

Ma qui, il riposizionamento deve modificare quei 32 bit per inserire l'indirizzo di _start in loro dopo il collegamento avviene.

0x100000000 non si adatta a 32 bit, ma lo fa 0xFFFFFFFF. Quindi l'errore.

Questo errore può verificarsi solo su rilocazioni che generano il troncamento, ad es. R_X86_64_32 (8 byte a 4 byte), ma mai su R_X86_64_64.

E ci sono alcuni tipi di riposizionamento che richiedono l'estensione segno invece di zero come mostrato qui, ad es. R_X86_64_32S. Vedere anche: https://stackoverflow.com/a/33289761/895245

7

Mi sono imbattuto in questo problema durante la creazione di un programma che richiede un'enorme quantità di spazio nello stack (oltre 2 GiB). La soluzione era aggiungere il flag -mcmodel=medium, che è supportato da entrambi i compilatori GCC e Intel.

+2

Lo confermo. Devi anche non compilarlo come una libreria usando '-fPIC': https://software.intel.com/en-us/forums/intel-fortran-compiler-for-linux-and-mac-os-x/ topic/268374 # comment-1590873 –

+1

Nel caso in cui ciò non fosse ovvio, ** non usare '-mcmodel = medium' se non si deve **, perché rende l'asm meno efficiente quando si ha a che fare con large ('-mlarge-data-threshold' imposta automaticamente a 64kiB) array statici/globali. Cerca prima altri motivi, ad es. prova '-fPIC'. Non è ovvio perché più di 2 GB di * stack * sarebbero incompatibili con il predefinito '-mcmodel = small', poiché i simboli globali non si riferiscono alla memoria dello stack, e lo stack è già al di fuori del basso 2GiB per normale (' -mcmodel = small') eseguibili. Vedi https://gcc.gnu.org/onlinedocs/gcc/x86-Options.html. –

5

Su Cygwin -mcmodel=medium è già predefinito e non aiuta. Per me l'aggiunta di -Wl,--image-base -Wl,0x10000000 al linker GCC ha corretto l'errore.

+0

Questo funziona per me. Come l'hai capito? – garyp

3

Spesso, ciò che questo errore indica è il tuo programma è troppo grande e spesso è troppo grande perché contiene uno o più oggetti di dati molto grandi. Ad esempio,

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

produrrà una "delocalizzazione troncato per adattarsi" errore x86-64/Linux, se compilato in modalità predefinita e senza ottimizzazione. (Se si attiva l'ottimizzazione, potrebbe, almeno teoricamente, capire che large_array è inutilizzato e/o che other_global non è mai scritto, e quindi generare il codice che non innescare il problema.)

Cosa sta succedendo è che, per impostazione predefinita, GCC utilizza il suo "modello di codice ridotto" su questa architettura, in cui tutto il codice del programma e i dati allocati staticamente devono essere contenuti nei 2 GB più bassi dello spazio degli indirizzi. (Il limite superiore preciso è qualcosa come 2GB - 2MB, perché i 2MB più bassi dello spazio di indirizzamento di qualsiasi programma sono permanentemente inutilizzabili.Se stai compilando una libreria condivisa o un eseguibile indipendente dalla posizione, tutto il codice e i dati devono ancora essere contenuti in due gigabyte, ma non sono più inchiodati nella parte inferiore dello spazio degli indirizzi.) large_array consuma tutto lo spazio da solo , quindi other_global viene assegnato un indirizzo sopra il limite e il codice generato per main non può raggiungerlo. Si ottiene un errore criptico dal linker, piuttosto che un utile errore "large_array è troppo grande" dal compilatore, perché nei casi più complessi il compilatore non può sapere che other_global sarà fuori dalla portata, quindi non prova nemmeno per i casi semplici.

La maggior parte delle volte, la risposta corretta per ottenere questo errore è quella di rifattorizzare il programma in modo che non occorra giganteschi array statici e/o gigabyte di codice macchina. Tuttavia, se davvero si hanno per qualche motivo, è possibile utilizzare "medium" or "large" code models per eliminare i limiti, al prezzo di una generazione di codice un po 'meno efficiente. Questi modelli di codice sono specifici per x86-64; qualcosa di simile esiste per la maggior parte delle altre architetture, ma l'esatto insieme di "modelli" e i limiti associati varieranno. (Su un'architettura a 32 bit, ad esempio, potresti avere un modello "piccolo" in cui la quantità totale di codice e dati era limitata a qualcosa come 2 byte.)

+0

Grazie. Come notato nella domanda, questo non è un codice x86. Questo è stato molto tempo fa, ma comunque, non sono sicuro di come la dimensione del modello di codice sia correlata a un processore embedded? Non era questa limitazione/proprietà specifica x86? – ysap

+0

@ysap Ogni architettura della CPU presenta delle limitazioni _like_ questo - di solito impostata dal numero di bit che si adattano all'operando immediato di alcune istruzioni della macchina. Ho scritto questa risposta perché una domanda molto più recente è stata chiusa come un duplicato di questa domanda e non pensavo che le risposte esistenti affrontassero molto bene il problema di quella persona, e ho usato x86-64 solo come esempio pratico. (Il messaggio di errore nella domanda contiene il termine 'R_X86_64_PC32', che suona sicuramente come se stessimo compilando il codice per x86-64. Forse il tuo vero problema era che il tuo makefile non stava invocando il cross-compilatore che avrebbe dovuto.) – zwol

+0

Sono stato un cross-compilation di sicuro, ma hey, anche quella compagnia non esiste più ... Grazie per l'input. – ysap

Problemi correlati