Dans les strace
sorties, les chemins d'accès aux bibliothèques que les exécutables appellent sont dans les appels open()
. S'agit-il de l'appel système utilisé par les exécutables liés dynamiquement? Et alors dlopen()
? open()
n'est pas un appel que j'aurais deviné jouerait un rôle dans l'exécution des programmes.
23
ld-linux
sont mappés par le noyau dans le cadre de l'execve
appel système.dlopen n'a rien à voir avec les bibliothèques partagées comme vous les pensez. Il existe deux méthodes de chargement d'un objet partagé:
main
fonction et configurera l'espace de processus de l'application de sorte que l'application trouve les fonctions de la bibliothèque. Cela implique d'open()
ingérer le lubrary, puis de l'intégrer,mmap()
suivi de la configuration de certaines tables de recherche.libdl
, à partir de laquelle vous ensuite ( en utilisant la première méthode) peut appelerdlopen()
etdlsym()
les fonctions. Avec dlopen, vous obtenez un handle vers la bibliothèque, que vous pouvez ensuite utiliser avec dlsym pour recevoir un pointeur de fonction vers une fonction particulière. Cette méthode est beaucoup plus compliquée pour le programmeur que la première méthode (puisque vous devez faire l'installation manuellement, plutôt que l'éditeur de liens le fait automatiquement pour vous), et elle est également plus fragile (puisque vous n'obtenez pas la compilation -time vérifie que vous appelez des fonctions avec les types d'arguments corrects lors de la première méthode), mais l'avantage est que vous pouvez décider quel objet partagé charger à l'exécution (ou même le charger), ce qui rend c'est une interface destinée à la fonctionnalité de type plugin. Enfin, l'interface dlopen est également moins portable que dans l'autre sens, car sa mécanique dépend de l'implémentation exacte de l'éditeur de liens dynamique (d'où libtool'slibltdl
, qui tente de résumer ces différences).la source
Aujourd'hui, la plupart des systèmes d'exploitation utilisent la méthode des bibliothèques partagées introduite fin 1987 par SunOS-4.0. Cette méthode est basée sur le mappage de la mémoire via mmap ().
Étant donné qu'au début des années 1990, Sun a même fait don de l'ancien code basé sur a.out (Solaris à l'époque était déjà basé sur ELF) aux gens de FreeBSD et que ce code a ensuite été transféré à de nombreux autres systèmes (y compris Linux) , vous comprendrez peut-être pourquoi il n'y a pas de grande différence entre les plates-formes.
la source
ltrace -S
l'analyse d'un exemple minimal montre qu'ilmmap
est utilisé dans la glibc 2.23Dans la glibc 2.23, Ubuntu 16.04, fonctionnant
latrace -S
sur un programme minimal qui utilisedlopen
avec:spectacles:
nous voyons donc immédiatement que
dlopen
appelleopen
+mmap
.L'
ltrace
outil génial trace à la fois les appels de bibliothèque et les appels système, et est donc parfait pour examiner ce qui se passe dans ce cas.Une analyse plus approfondie montre que
open
renvoie le descripteur de fichier3
(libre suivant après stdin, out et err).read
utilise ensuite ce descripteur de fichier, mais TODO pourquoimmap
les arguments sont limités à quatre, et nous ne pouvons pas voir quel fd a été utilisé car il s'agit du 5ème argument .strace
confirme comme prévu celui3
-là, et l'ordre de l'univers est rétabli.Les âmes courageuses peuvent également s'aventurer dans le code glibc, mais je n'ai pas pu trouver l'
mmap
after après une grep rapide et je suis paresseux.Testé avec cet exemple minimal avec build passe-partout sur GitHub .
la source
strace
rapports sur les appels système (c'est-à-dire les fonctions implémentées directement par le noyau). Les bibliothèques dynamiques ne sont pas une fonction du noyau;dlopen
fait partie de la bibliothèque C, pas du noyau. L'implémentation dedlopen
will callopen
(qui est un appel système) pour ouvrir le fichier de bibliothèque afin qu'il puisse être lu.la source
ltrace
.ltrace -S
est parfait pour analyser cela car il montre également les appels système: unix.stackexchange.com/a/462710/32558