Option GCC-fPIC
j'ai lu à propos de les Options de GCC pour les Conventions de génération de Code , mais je ne pouvais pas comprendre ce que" générer du code indépendant de la position (PIC) " fait. Donnez - moi un exemple pour m'expliquer ce que cela signifie.
6 réponses
Code Indépendant de la Position signifie que le code machine ne dépend pas être situé à une adresse spécifique pour fonctionner.
E. g. sauts généré relative plutôt qu'absolue.
Pseudo-assemblage:
PIC: cela fonctionnerait que le code soit à l'adresse 100 ou 1000
100: COMPARE REG1, REG2
101: JUMP_IF_EQUAL CURRENT+10
...
111: NOP
Non PIC: cela ne fonctionnera que si le code est à l'adresse 100
100: COMPARE REG1, REG2
101: JUMP_IF_EQUAL 111
...
111: NOP
EDIT: En réponse à un commentaire.
si votre code est compilé avec-fPIC, il est adapté pour être inclus dans une bibliothèque - la bibliothèque doit pouvoir être déplacée de son emplacement préféré en mémoire à une autre adresse, il pourrait y avoir une autre bibliothèque déjà chargée à l'adresse que votre bibliothèque préfère.
je vais essayer d'expliquer ce qui a déjà été dit de façon plus simple.
chaque fois qu'un lib partagé est chargé, le chargeur (le code sur L'OS qui charge n'importe quel programme que vous exécutez) change quelques adresses dans le code en fonction de l'endroit où l'objet a été chargé.
dans l'exemple ci-dessus, le" 111 " dans le code non PIC est écrit par le chargeur la première fois qu'il a été chargé.
pour les objets non partagés, vous pouvez vouloir qu'il soit comme cela parce que le compilateur peut faire quelques optimisations sur le code.
pour un objet partagé, si un autre processus veut "lier" ce code, il doit le lire aux mêmes adresses virtuelles ou le "111" n'aura aucun sens. mais cet espace virtuel pourrait déjà être utilisé dans le deuxième processus.
qui est intégré dans les bibliothèques partagées devrait normalement être du code indépendant de la position, de sorte que la bibliothèque partagée puisse facilement être chargée à (plus ou moins) n'importe quelle adresse dans la mémoire. L'option -fPIC
garantit que GCC produit un tel code.
ajout...
chaque processus a le même espace d'adresse virtuelle (si la randomisation de l'adresse virtuelle est stoppée en utilisant un drapeau dans linux OS) (Pour plus de détails désactiver et réactiver la randomisation de l'espace d'adresse uniquement pour moi )
donc si son exe unique sans lien partagé (scénario hypothétique), alors nous pouvons toujours donner la même adresse virtuelle à la même instruction asm sans aucun mal.
mais lorsque nous voulons lier l'objet partagé à l'exe, alors nous ne sommes pas sûrs de l'adresse de départ assignée à l'objet partagé car cela dépendra de l'ordre dans lequel les objets partagés ont été liés.Ceci étant dit, l'instruction asm à l'intérieur .ainsi, l'adresse virtuelle sera toujours différente selon le processus auquel elle renvoie.
Donc, un processus peut donner l'adresse de début .afin 0x45678910 dans son propre espace virtuel et d'autres processus en même temps peut donner l'adresse de début de 0x12131415 et si ils n'utilisent pas l'adressage relatif .il en sera de ne pas travailler du tout.
donc ils doivent toujours utiliser le mode d'adressage relatif et donc l'option fpic.
Le lien à une fonction dans une bibliothèque dynamique est résolu lorsque la bibliothèque est chargée ou au moment de l'exécution. Par conséquent, le fichier exécutable et la Bibliothèque dynamique sont chargés en mémoire lorsque le programme est lancé. L'adresse mémoire à laquelle une bibliothèque dynamique est chargé ne peut pas être déterminé avance, car une adresse fixe peut entrer en conflit avec une autre bibliothèque dynamique nécessitant la même adresse.
il existe deux méthodes couramment utilisées pour traitant de ce problème:
1.Réinstallation. Tous les pointeurs et adresses dans le code sont modifiés, si nécessaire, pour correspondre à l'adresse de charge réelle. La relocalisation est effectuée par le linker et le chargeur.
2.Code indépendant de la Position. Toutes les adresses dans le code sont relatives à la position actuelle. Les objets partagés dans les systèmes de type Unix utilisent par défaut du code indépendant de la position. Cela est moins efficace que la relocalisation si le programme fonctionne pendant une longue période, en particulier dans Mode 32 bits.
nom " indépendant de la position de code " implique réellement suivantes:
-
la section de code ne contient aucune adresse absolue qui nécessite un déménagement, mais seulement un parent adresse. Par conséquent, la section code peut être chargée à une adresse mémoire arbitraire et partagée entre plusieurs processus.
-
les données l'article n'est pas partagée entre plusieurs processus, car il contient souvent écriture de données. Par conséquent, la section de données peut contenir des pointeurs ou des adresses besoin de réinstallation.
-
toutes les fonctions publiques et les données publiques peuvent être dépassées sous Linux. Si une fonction dans le programme principal a le même nom qu'une fonction dans un objet partagé, puis le la version dans main aura priorité, non seulement quand elle est appelée depuis main, mais aussi quand appelé par le partage de l' objet. De même, lorsqu'une variable globale dans main a la même nom qu'une variable globale dans l'objet partagé, puis l'instance principale sera utilisé, même lorsqu'il est accédé à partir de l'objet partagé.
cette interposition de symboles est destinée à imiter le comportement des bibliothèques statiques.
un objet partagé a une table de pointeurs vers ses fonctions, appelée table de liaison de procédure (PLT) et un table de pointeurs vers ses variables appelées global offset table (GOT) afin d'implémenter cette fonctionnalité "override". Tous les accès aux fonctions et aux variables publiques passent par ces tables.
p. S. Lorsque la liaison dynamique ne peut être évitée, il existe plusieurs façons d'éviter les fonctionnalités fastidieuses du code indépendant de la position.
vous pouvez lire la suite de cet article: http://www.agner.org/optimize/optimizing_cpp.pdf
ajout mineur aux réponses déjà affichées: les fichiers objets qui ne sont pas compilés pour être indépendants de la position peuvent être déplacés; ils contiennent des entrées de table de réinstallation.
ces entrées permettent au chargeur (le bit de code qui charge un programme dans la mémoire) de réécrire les adresses absolues pour ajuster l'adresse de charge réelle dans l'espace d'adresse virtuel.
un système d'exploitation essaiera de partager une seule copie d'une" bibliothèque d'objets partagés " chargée en mémoire avec tous les programmes qui sont liés à cette même bibliothèque d'objets partagés.
puisque l'espace d'adresse du code (contrairement aux sections de l'espace de données) n'a pas besoin d'être contigu, et parce que la plupart des programmes qui se rapportent à une bibliothèque spécifique ont un arbre de dépendance de bibliothèque assez fixe, cela réussit la plupart du temps. Dans les rares cas où il y a divergence, oui, il peut être nécessaire d'avoir deux ou plusieurs copies d'une bibliothèque d'objets partagés en mémoire.
évidemment, toute tentative de randomiser l'adresse de chargement d'une bibliothèque entre les programmes et/ou les instances de programme (afin de réduire la possibilité de créer un motif exploitable) rendra de tels cas communs, non rares, donc quand un système a permis cette capacité, on devrait faire tous les efforts pour compiler toutes les bibliothèques d'objets partagés pour être indépendant de la position.
Depuis appels dans ces bibliothèques à partir du corps du programme principal sera également transférable, cela le rend beaucoup moins probable qu'une bibliothèque partagée devra être copié.