2010-06-30 4 views
22

Recentemente stavo costruendo una certa libreria condivisa (ELF) mira architettura x86-64, in questo modo:Differenza di codice indipendente dalla posizione: 86 vs x86-64

g++ -o binary.so -shared --no-undefined ... -lfoo -lbar 

Questo non è riuscita con il seguente errore:

relocation R_X86_64_32 against `a local symbol' can not be used when making a shared object; recompile with -fPIC

Ovviamente, significa che ho bisogno di ricostruirlo come codice indipendente dalla posizione, quindi è adatto per il collegamento in una libreria condivisa.

Ma questo funziona perfettamente su x86 con gli stessi argomenti di build. Quindi la domanda è: in che modo il riposizionamento su x86 è diverso da x86-64 e perché non devo compilare con -fPIC sul primo?

+1

Non l'ho mai capito. Se il compilatore può dirti esattamente quale opzione usare automaticamente, perché richiede che tu pronunci parole magiche per farlo funzionare correttamente? Grrr .. –

+0

@Billy ONeal, ora credo che sia il caso di un'astrazione che perde. Differiscono nel modo in cui caricano i dati globali, il che influisce sul fatto che il PIC sia necessario o meno. –

+0

Capisco la necessità della differenza. Quello che non capisco è il motivo per cui è necessario dare al compilatore un passaggio per farlo fare. –

risposta

16

ho trovato a nice and detailed explanation, che si riduce a:

  1. x86-64 utilizza offset per caricare i dati globali IP-relativa, x86-32 non può, quindi dereference un offset globale.
  2. compensati non funziona per le librerie condivise, in quanto simboli globali possono essere sovrascritte IP-relativa, in modo x86-64 si rompe quando non è costruita con PIC.
  3. Se x86-64 è stato creato con PIC, la deviazione dell'offset relativo all'IP ora restituisce un puntatore alla voce GOT, che viene quindi dereferenziata.
  4. x86-32, tuttavia, già utilizza un dereferenziamento di un offset globale, quindi viene convertito direttamente in Voce di destinazione.
4

Si tratta di problemi relativi al modello di codice. Per impostazione predefinita, il codice statico viene generato assumendo che l'intero programma rimanga nella parte inferiore 2G dello spazio di indirizzamento della memoria. Il codice per le librerie condivise deve essere compilato per un altro modello di memoria, o PIC, o con -mcmodel = grande che verrà compilato senza fare questa ipotesi.

Si noti che -mcmodel = large non è implementato nella versione precedente di gcc (è in 4.4, non è in 4.2, non so per 4.3). .

+0

questo ha un senso - l'indirizzo assoluto a 32 bit non può essere trasformato in una delocalizzazione relativa, perché l'indirizzo di carico della biblioteca potrebbe essere> 2 GB. – caf

+0

Sì, ho capito che il codice indipendente dalla posizione deve essere diverso nel calcolo offset di salto, ma faccio fatica a capire perché * non * lavoro su x86 * senza * '-fpic'. –

+0

@Alex, il caricatore dinamico è in grado di gestire alcuni ma non tutti i record di delocalizzazione e il motivo per cui alcuni record di rilocazione non vengono gestiti è che assumono una situazione che non è vera. Esiste un solo modello di memoria PIC a 32 bit e tale modello utilizza solo i record di rilocazione gestiti. Esistono diversi modelli di memoria non a 64 bit PIC, alcuni compatibili con il riposizionamento dinamico, altri no. Se si utilizza -mcmodel = large con gcc 4.4, non è necessario -fpic. – AProgrammer

0

È puramente un requisito arbitrario che le persone ABI ci hanno imposto. Non c'è alcuna ragione logica per cui il linker dinamico su x86_64 non possa supportare librerie non-PIC. Tuttavia, dal momento che x86_64 non è sotto una pressione di registro così orribile come x86 (e ha caratteristiche migliori per PIC), non conosco alcun motivo significativo per non utilizzare PIC.

+0

Tranne che supporta librerie non PIC. Non supporta alcuni record di rilocazione perché solitamente vengono caricati in modo tale che le ipotesi fatte da questi record di rilocazione non siano valide, ma se non le usi, non c'è alcun problema. – AProgrammer