2010-06-30 14 views
22

je bâtiment récemment une certaine bibliothèque partagée (ELF) ciblant l'architecture x86-64, comme ceci:différence dans le code indépendant de la position: x86 vs x86-64

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

Ce a échoué avec l'erreur suivante:

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

Bien sûr, cela signifie que j'ai besoin de le reconstruire en tant que code indépendant de la position, donc il convient à la liaison dans une bibliothèque partagée.

Mais cela fonctionne parfaitement sur x86 avec exactement les mêmes arguments de construction. Donc, la question est, comment le déplacement sur x86 est-il différent de x86-64 et pourquoi n'ai-je pas besoin de compiler avec -fPIC sur le premier?

+1

Je n'ai jamais compris cela. Si le compilateur peut vous dire exactement quelle option utiliser automatiquement, pourquoi faut-il que vous disiez des mots magiques pour le faire fonctionner correctement? Grrr .. –

+0

@Billy ONeal, Maintenant, je crois que c'est le cas de l'abstraction qui fuit. Ils diffèrent dans la façon dont ils chargent les données globales, ce qui affecte si PIC est nécessaire ou non. –

+0

Je comprends le besoin de la différence. Ce que je ne comprends pas, c'est pourquoi vous devez donner un interrupteur au compilateur pour qu'il le fasse. –

Répondre

16

J'ai trouvé a nice and detailed explanation, qui se résume à:

  1. x86-64 utilise-IP par rapport décalage pour charger les données globales, x86-32 ne peut pas, il déréférence un décalage global.
  2. Le décalage relatif IP ne fonctionne pas pour les bibliothèques partagées, car les symboles globaux peuvent être remplacés, donc x86-64 se décompose lorsqu'il n'est pas construit avec PIC.
  3. Si x86-64 construit avec PIC, le déréférencement de décalage relatif IP donne maintenant un pointeur vers l'entrée GOT, qui est ensuite déréférencé.
  4. x86-32, cependant, déjà utilise une déréférence d'un décalage global, de sorte qu'il est transformé en entrée GOT directement.
4

Il s'agit d'un problème de modèle de code. Par défaut, le code statique est construit en supposant que le programme entier restera dans la partie inférieure 2G de l'espace d'adresses de la mémoire. Le code pour les bibliothèques partagées doit être compilé pour un autre modèle de mémoire, soit PIC, soit avec -mcmodel = large qui compilera sans faire cette supposition. Notez que -mcmodel = large n'est pas implémenté dans une version plus ancienne de gcc (il est dans 4.4, il n'est pas dans 4.2, je ne sais pas pour 4.3). .

+0

Cela a du sens - l'adresse absolue de 32 bits ne peut pas être transformée en une relocalisation relative, car l'adresse de chargement de la bibliothèque peut être> 2 Go. – caf

+0

Oui, je comprends que le code indépendant de la position doit être différent dans le calcul des décalages de sauts, mais j'ai du mal à comprendre pourquoi il * fonctionne * sur x86 * sans * '-fpic'. –

+0

@Alex, le chargeur dynamique est capable de gérer certains enregistrements de relocalisation, mais pas tous, et la raison pour laquelle certains enregistrements de relocalisation ne sont pas gérés est qu'ils supposent une situation qui n'est pas vraie. Il existe un seul modèle de mémoire non 32 bits PIC et ce modèle utilise uniquement des enregistrements de relocalisation gérés. Il existe plusieurs modèles de mémoire non 64 bits, certains compatibles avec le déplacement dynamique, d'autres non. Si vous utilisez -mcmodel = large avec gcc 4.4, vous n'avez pas besoin de -fpic. – AProgrammer

0

C'est une exigence purement arbitraire que les personnes ABI nous ont imposées. Il n'y a aucune raison logique pour laquelle l'éditeur de liens dynamiques sur x86_64 ne peut pas prendre en charge les bibliothèques non-PIC. Cependant, puisque x86_64 n'est pas sous une pression de registre aussi horrible que x86 (et a de meilleures caractéristiques pour PIC), je ne connais pas de raison significative de ne pas utiliser PIC.

+0

Excepté qu'il supporte les bibliothèques non-PIC. Il ne prend pas en charge certains enregistrements de relocalisation, car les .so sont généralement chargés de telle sorte que les suppositions faites par ces enregistrements de relocalisation ne sont pas valides, mais si vous ne les utilisez pas, il n'y a pas de problème. – AProgrammer