Que signifie la relocalisation R_X86_64_32S et R_X86_64_64?

J’ai eu l’erreur suivante lorsque j’ai essayé de comstackr 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 object partagé; recomstackr avec -fPIC

Qu’est- R_X86_64_32S déplacement de R_X86_64_32S et qu’est-ce que R_X86_64_64 ?

J’ai googlé sur l’erreur et ses causes possibles – Ce serait génial si quelqu’un pouvait dire ce que R_X86_64_32S signifie vraiment.

Les 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 regarder dans l’ AMI amd64 . Selon lui, R_X86_64_64 est divisé en:

  • R_X86_64 – Tous les noms sont préfixés par ceci
  • 64 – Relocalisation directe 64 bits

et R_X86_64_32S pour:

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

ce qui signifie fondamentalement “la valeur du symbole indiqué par cette relocalisation, plus un addend”, dans les deux cas. Pour R_X86_64_32S l’éditeur de liens vérifie ensuite que le signe de valeur généré s’étend jusqu’à 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. Cela signifie que le compilateur sait exactement où la section de données sera et peut la référencer directement. Les bibliothèques, d’autre part, ne peuvent que savoir que leur section de données se trouvera à un décalage spécifié par rapport à l’adresse de base; la valeur de cette adresse de base ne peut être connue qu’à l’exécution. Par conséquent, toutes les bibliothèques doivent être produites avec un code qui peut être exécuté quel que soit l’endroit où il est mis en mémoire, appelé code indépendant de la position (ou PIC).

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

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 l’ ABI System V AMD , qui contient les spécificités AMD64 du format de fichier ELF.

Ce sont toutes les valeurs possibles pour le champ ELF32_R_TYPE d’une entrée de relocalisation, spécifiées 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 les valeurs dépendantes de l’archive.

Sous 4.4.1 “Types de relocalisation”, 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 allons expliquer ce tableau plus tard.

Et la note:

Les R_X86_64_32 et R_X86_64_32S 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) est nulle (extension de signe) pour 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 : 0: 00 00 add %al,(%rax) 0: R_X86_64_32 .text+0xc 2: 00 00 add %al,(%rax) 0000000000000004 : 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ésassemblage pour le moment (ce qui n’a pas de sens car il s’agit de données), et ne regardez que les étiquettes, les octets et les déplacements.

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 avons uniquement spécifié un .long (4 octets)
  • .text : nous sums sur la section .text
  • 0xc : ceci est l’ addend , qui est un champ de l’entrée de relocalisation

L’adresse de la relocalisation est calculée comme suit:

 A + S 

Où:

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

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

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

R_X86_64_64 est analogue, mais plus simple, puisqu’il n’est pas nécessaire de tronquer l’adresse de s . Ceci est indiqué par la norme via 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 et R_X86_64_32 se produit lorsque l’éditeur de liens se plaint “avec un déplacement tronqué pour s’adapter”:

  • 32 : se plaint si la valeur tronquée après la relocalisation n’est pas nulle, étendre l’ancienne valeur, c.-à-d.

    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 nulle.

  • 32S : se plaint si la valeur tronquée après la relocalisation ne signe pas l’ extension de l’ancienne valeur.

    Par exemple: FF FF FF FF 80 00 00 00 à 80 00 00 00 est correct, car le dernier bit de 80 00 00 00 et les bits tronqués sont tous 1.

Voir aussi: que signifie cette erreur GCC “… la 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 

Maintenant, nous pouvons observer la “relocalisation” tronquée pour tenir sur 32S avec un script de liaison:

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

À présent:

 ld -Tlink.ld ao 

Est 0xFFFFFFFF80000000 , car: 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, car ce 0 fait que ce n’est plus une extension de signe.

Justification de l’utilisation de 32S pour l’access à la mémoire, mais 32 pour l’immédiat: Quand est-il préférable pour un assembleur d’utiliser la relocalisation étendue des signes comme R_X86_64_32S au lieu de l’extension zéro comme R_X86_64_32?

Cela signifie que compilé un object partagé sans utiliser l’ -fPIC comme vous le devriez:

  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 objects partagés sont compilés avec un code indépendant de la position – code pouvant être exécuté à 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. object.

J’ai rencontré ce problème et trouvé que cette réponse ne m’aidait pas. J’essayais de lier une bibliothèque statique avec 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, était de changer la bibliothèque statique en partage. Je soupçonne que le message d’erreur concernant -fPIC peut être dû à un certain nombre de causes, mais fondamentalement, ce que vous voulez voir, c’est la façon dont vos bibliothèques sont construites et se méfier des bibliothèques construites de différentes manières.

Dans mon cas, le problème était dû au fait que le programme à comstackr devait trouver des bibliothèques partagées dans un répertoire distant, alors que seules les bibliothèques statiques correspondantes étaient en erreur.

En fait, cette erreur de relocalisation était une erreur de fichier non trouvée dans le déguisement.

J’ai détaillé comment je m’en suis occupé dans cet autre sujet https://stackoverflow.com/a/42388145/5459638