2010-06-30 10 views
22

ich vor kurzem eine bestimmte freigegebene Bibliothek (ELF) Targeting x86-64-Architektur, wie dieses Gebäude wurde:Differenz in positionsunabhängigen Code: x86 vs x86-64

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

Dies scheiterte mit dem folgenden Fehler:

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

Natürlich bedeutet es, dass ich es als positionsunabhängigen Code neu erstellen muss, damit es in eine gemeinsame Bibliothek verknüpft werden kann.

Aber das funktioniert perfekt auf x86 mit genau den gleichen Build-Argumente. Die Frage ist also, wie unterscheidet sich die Verschiebung auf x86 von x86-64 und warum muss ich nicht mit -fPIC auf der ehemaligen kompilieren?

+1

Ich habe das nie verstanden. Wenn der Compiler Ihnen genau sagen kann, welche Option automatisch verwendet werden soll, warum müssen Sie dann magische Wörter sagen, damit es korrekt funktioniert? Grrr .. –

+0

@Billy ONeal, jetzt glaube ich, dass der Fall der undichten Abstraktion ist. Sie unterscheiden sich darin, wie sie globale Daten laden, was sich darauf auswirkt, ob PIC benötigt wird oder nicht. –

+0

Ich verstehe die Notwendigkeit für den Unterschied. Was ich nicht verstehe, ist, warum Sie dem Compiler einen Schalter geben müssen, damit er das tut. –

Antwort

16

ich a nice and detailed explanation gefunden habe, was läuft darauf hinaus:

  1. x86-64 verwendet IP-versetzt globale Daten zu laden, x86-32 kann nicht, so dass es eine globale dereferenziert versetzt.
  2. IP-relativer Offset funktioniert nicht für gemeinsam genutzte Bibliotheken, da globale Symbole überschrieben werden können. Daher bricht x86-64 zusammen, wenn er nicht mit PIC erstellt wird.
  3. Wenn x86-64 mit PIC erstellt wurde, liefert die IP-relative Offset-Dereferenz nun einen Zeiger auf den GOT-Eintrag, der dann dereferenziert wird.
  4. x86-32 aber bereits verwendet eine Dereferenzierung eines globalen Offset, so dass es direkt in GOT-Eintrag umgewandelt wird.
4

Es ist ein Code-Modell Probleme. Standardmäßig wird statischer Code erstellt, wobei davon ausgegangen wird, dass das gesamte Programm im unteren 2G-Teil des Speicheradressraums bleibt. Code für gemeinsam genutzte Bibliotheken muss für ein anderes Speichermodell, entweder PIC, oder mit -mcmodel = large kompiliert werden, das kompiliert wird, ohne diese Annahme zu treffen.

Beachten Sie, dass -mcmodel = large ist nicht in älteren GCC-Version implementiert (es ist in 4.4, ist es nicht in 4.2, ich weiß nicht für 4.3). .

+0

Dies ist sinnvoll - die 32-Bit-Absolutadresse kann nicht in eine relative Verschiebung umgewandelt werden, da die Ladeadresse der Bibliothek> 2 GB sein kann. – caf

+0

Ja, ich verstehe, dass positionsunabhängiger Code bei der Berechnung von Sprungversätzen unterschiedlich sein muss, aber ich habe Mühe zu verstehen, warum * x * ohne * '-fpic * funktioniert. –

+0

@Alex, der dynamische Lader ist in der Lage, einige, aber nicht alle Verschiebungsdatensätze zu verarbeiten, und der Grund, warum einige Verschiebungsdatensätze nicht behandelt werden, besteht darin, dass sie eine Situation annehmen, die nicht wahr ist. Es gibt nur ein Nicht-PIC-32-Bit-Speichermodell und dieses Modell verwendet nur gehandhabte Verschiebungsdatensätze. Es gibt mehrere Nicht-PIC-64-Bit-Speichermodelle, von denen einige mit dynamischer Verschiebung kompatibel sind, andere nicht. Wenn Sie -mcmodel = large mit gcc 4.4 verwenden, brauchen Sie -fpic nicht. – AProgrammer

0

Es ist eine rein willkürliche Anforderung, die uns die ABI-Leute auferlegt haben. Es gibt keinen logischen Grund, warum der dynamische Linker auf x86_64 nicht-PIC-Bibliotheken nicht unterstützen konnte. Da x86_64 jedoch nicht unter solch einem schrecklichen Registerdruck wie x86 steht (und bessere Eigenschaften für PIC hat), weiß ich keinen wichtigen Grund, PIC nicht zu verwenden.

+0

Ausgenommen davon, dass es Nicht-PIC-Bibliotheken unterstützt. Einige Verlagerungsdatensätze werden nicht unterstützt, da sie in der Regel so geladen werden, dass die von diesen Verlagerungsdatensätzen angenommenen Annahmen nicht gültig sind. Wenn Sie sie jedoch nicht verwenden, besteht kein Problem. – AProgrammer