web-dev-qa-db-fra.com

Que signifient les réinstallations R_X86_64_32S et R_X86_64_64?

Vous avez l'erreur suivante lorsque j'ai essayé de compiler une application C dans FreeBSD 64 bits:

la relocalisation R_X86_64_32S ne peut pas être utilisée lors de la création d'un objet partagé; recompiler avec -fPIC

Quel est R_X86_64_32S relocalisation et qu'est-ce que R_X86_64_64?

J'ai cherché sur Google l'erreur, et ses causes possibles - Ce serait génial si quelqu'un pouvait dire ce que R_X86_64_32S signifie vraiment.

46
Raj

Le R_X86_64_32S et R_X86_64_64 sont des noms de types de relocalisation, pour le code compilé pour l'architecture AMD64. Vous pouvez tous les rechercher dans le AMD64 ABI . Selon elle, R_X86_64_64 se décompose en:

  • R_X86_64 - tous les noms sont précédés de ce
  • 64 - Relocalisation directe 64 bits

et R_X86_64_32S à:

  • R_X86_64 - préfixe
  • 32S - tronquer la valeur à 32 bits et étendre le signe

ce qui signifie essentiellement "la valeur du symbole pointé par cette relocalisation, plus tout ajout", dans les deux cas. Pour R_X86_64_32S l'éditeur de liens vérifie ensuite que la valeur générée signe-s'étend à la valeur 64 bits d'origine.

Maintenant, dans un fichier exécutable, le code et les segments de données reçoivent une adresse de base virtuelle spécifiée. Le code exécutable n'est pas partagé et chaque exécutable obtient son propre espace d'adressage frais. Cela signifie que le compilateur sait exactement où se trouvera la section de données et peut la référencer directement. Les bibliothèques, en revanche, ne peuvent savoir que leur section de données sera à un décalage spécifié par rapport à l'adresse de base; la valeur de cette adresse de base ne peut être connue qu'au moment de l'exécution. Par conséquent, toutes les bibliothèques doivent être produites avec du code qui peut s'exécuter peu importe où il est mis en mémoire, connu sous le nom de code indépendant de la position (ou PIC pour faire court).

Maintenant, lorsqu'il s'agit de résoudre votre problème, le message d'erreur parle de lui-même.

34

Pour que tout cela ait un sens, vous devez d'abord:

Normes

R_X86_64_64, R_X86_64_32 et R_X86_64_32S sont tous définis par le System V AMD ABI , qui contient les spécificités AMD64 du format de fichier ELF.

Ce sont toutes des valeurs possibles pour le ELF32_R_TYPE champ d'une entrée de relocalisation, spécifié dans le System V ABI 4.1 (1997) qui spécifie les parties neutres de l'architecture du format ELF. Cette norme spécifie uniquement le champ, mais pas ses valeurs dépendantes de Arch.

Sous 4.4.1 "Types de réinstallation", nous voyons le tableau récapitulatif:

Name          Field   Calculation
------------  ------  -----------
R_X86_64_64   Word64  A + S
R_X86_64_32   Word32  A + S
R_X86_64_32S  Word32  A + S

Nous expliquerons ce tableau plus tard.

Et la note:

Le R_X86_64_32 et R_X86_64_32S les relocalisations tronquent la valeur calculée à 32 bits. L'éditeur de liens doit vérifier que la valeur générée pour la relocalisation R_X86_64_32 (R_X86_64_32S) se déploie à zéro (extension de signe) à la valeur 64 bits d'origine.

Exemple de R_X86_64_64 et R_X86_64_32

Examinons d'abord R_X86_64_64 et R_X86_64_32:

.section .text
    /* Both a and b contain the address of s. */
    a: .long s
    b: .quad s
    s:

Alors:

as --64 -o main.o main.S
objdump -dzr main.o

Contient:

0000000000000000 <a>:
   0:   00 00                   add    %al,(%rax)
                        0: R_X86_64_32  .text+0xc
   2:   00 00                   add    %al,(%rax)

0000000000000004 <b>:
   4:   00 00                   add    %al,(%rax)
                        4: R_X86_64_64  .text+0xc
   6:   00 00                   add    %al,(%rax)
   8:   00 00                   add    %al,(%rax)
   a:   00 00                   add    %al,(%rax)

Testé sur Ubuntu 14.04, Binutils 2.24.

Ignorez le démontage pour l'instant (ce qui n'a pas de sens car il s'agit de données) et ne regardez que les étiquettes, octets et relocalisations.

La première relocalisation:

0: R_X86_64_32  .text+0xc

Ce qui signifie:

  • 0: agit sur l'octet 0 (étiquette a)
  • R_X86_64_: préfixe utilisé par tous les types de relocalisation du système AMD64 V ABI
  • 32: l'adresse 64 bits de l'étiquette s est tronquée à une adresse 32 bits car nous n'avons spécifié que .long (4 octets)
  • .text: nous sommes sur le .text section
  • 0xc: c'est le addend, qui est un champ de l'entrée de relocalisation

L'adresse du déménagement est calculée comme suit:

A + S

Où:

  • A: l'addend, ici 0xC
  • S: la valeur du symbole avant relocalisation, ici 00 00 00 00 == 0

Par conséquent, après la relocalisation, la nouvelle adresse sera 0xC == 12 octets dans le .text section.

C'est exactement ce que nous attendons, puisque s vient après un .long (4 octets) et un .quad (8 octets).

R_X86_64_64 est analogue, mais plus simple, car ici il n'est pas nécessaire de tronquer l'adresse de s. Ceci est indiqué par la norme par Word64 au lieu de Word32 dans la colonne Field.

R_X86_64_32S vs R_X86_64_32

La différence entre R_X86_64_32S contre R_X86_64_32 est lorsque l'éditeur de liens se plaindra "avec une relocalisation tronquée pour correspondre":

  • 32: se plaint si la valeur tronquée après la relocalisation ne prolonge pas zéro l'ancienne valeur, c'est-à-dire que les octets tronqués doivent être nuls:

    Par exemple.: FF FF FF FF 80 00 00 00 à 80 00 00 00 génère une réclamation car FF FF FF FF n'est pas nul.

  • 32S: se plaint si la valeur tronquée après la relocalisation ne signe étend l'ancienne valeur.

    Par exemple.: FF FF FF FF 80 00 00 00 à 80 00 00 00 est très bien, car le dernier morceau de 80 00 00 00 et les bits tronqués sont tous 1.

Voir aussi: Que signifie cette erreur GCC "... relocalisation tronquée pour s'adapter ..."?

R_X86_64_32S peut être généré avec:

.section .text
.global _start
_start:
    mov s, %eax
    s:

Alors:

as --64 -o main.o main.S
objdump -dzr main.o

Donne:

0000000000000000 <_start>:
   0:   8b 04 25 00 00 00 00    mov    0x0,%eax
                        3: R_X86_64_32S .text+0x7

Nous pouvons maintenant observer la "relocalisation" tronquée pour tenir sur 32S avec un script de l'éditeur de liens:

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

Maintenant:

ld -Tlink.ld a.o

Ça va, parce que: 0xFFFFFFFF80000000 est tronqué en 80000000, qui est une extension de signe.

Mais si nous changeons le script de l'éditeur de liens en:

. = 0xFFFF0FFF80000000;

Il génère maintenant l'erreur, parce que 0 a fait que ce ne soit plus une extension de signe.

Justification de l'utilisation de 32S pour l'accès à la mémoire mais 32 pour les intermédiaires: Quand est-il préférable pour un assembleur d'utiliser la relocalisation étendue de signe comme R_X86_64_32S au lieu d'une extension nulle comme R_X86_64_32?

R_X86_64_32S et PIE (positionner les exécutables indépendants

R_X86_64_32S ne peut pas être utilisé dans des exécutables indépendants de la position, par ex. fini avec gcc -pie, sinon le lien échoue avec:

relocation R_X86_64_32S against `.text' can not be used when making a PIE object; recompile with -fPIC

l

J'ai fourni un exemple minimal l'expliquant à: Qu'est-ce que l'option -fPIE pour les exécutables indépendants de la position dans gcc et ld?

Cela signifie que compilé un objet partagé sans utiliser -fPIC marquer comme il se doit:

 gcc -shared foo.c -o libfoo.so # Wrong

Vous devez appeler

 gcc -shared -fPIC foo.c -o libfoo.so # Right

Sous la plate-forme ELF (Linux), les objets partagés sont compilés avec du code indépendant de la position - code pouvant s'exécuter à partir de n'importe quel emplacement en mémoire, si cet indicateur n'est pas donné, le code généré dépend de la position, il n'est donc pas possible d'utiliser ce partage objet.

2
Artyom

J'ai rencontré ce problème et j'ai trouvé que cette réponse ne m'a pas aidé. J'essayais de lier une bibliothèque statique à une bibliothèque partagée. J'ai également étudié la possibilité de placer le commutateur -fPIC plus tôt sur la ligne de commande (comme indiqué dans les réponses ailleurs). La seule chose qui a résolu le problème, pour moi, a été de changer la bibliothèque statique en partagée. Je soupçonne que le message d'erreur à propos de -fPIC peut se produire pour un certain nombre de causes, mais fondamentalement ce que vous voulez regarder est la façon dont vos bibliothèques sont construites et méfiez-vous des bibliothèques qui sont construites de différentes manières.

2
jonawebb

Dans mon cas, le problème est survenu parce que le programme à compiler s'attendait à trouver des bibliothèques partagées dans un répertoire distant, alors que seules les bibliothèques statiques correspondantes étaient là dans une erreur.

En fait, cette erreur de relocalisation était une erreur déguisée de fichier introuvable.

J'ai détaillé comment je m'en suis sorti dans cet autre fil https://stackoverflow.com/a/42388145/5459638

1
XavierStuvw