dwww Home | Manual pages | Find package

dlopen(3)                  Library Functions Manual                  dlopen(3)

NOM
       dlclose, dlopen, dlmopen - Ouvrir et fermer un objet partagé

BIBLIOTHÈQUE
       Bibliothèque de liens dynamiques (libdl, -ldl)

SYNOPSIS
       #include <dlfcn.h>

       void *dlopen(const char *filename, int flags);
       int dlclose(void *handle);

       #define _GNU_SOURCE
       #include <dlfcn.h>

       void *dlmopen(Lmid_t lmid, const char *filename, int flags);

DESCRIPTION
   dlopen()
       La  fonction  dlopen() charge la bibliothèque dynamique dont le nom est
       fourni dans la chaîne filename (terminée par l'octet NULL)  et  renvoie
       un  descripteur  opaque (« handle ») représentant la bibliothèque dyna-
       mique. Ce descripteur est utilisé avec d'autres  fonctions  dans  l'API
       dlopen, telles que dlsym(3), dladdr(3), dlinfo(3) et dlclose().

       Si  l'argument  filename  est  un pointeur NULL, le descripteur renvoyé
       correspond au programme  principal.  Si  filename  contient  une  barre
       oblique (« / »), il est interprété comme un chemin (relatif ou absolu).
       Autrement, l'éditeur dynamique de liens cherche la bibliothèque  de  la
       façon suivante (consultez ld.so(8) pour plus de détails) :

       •  (ELF  seulement)  Si  l'objet appelant (c'est-à-dire la bibliothèque
          partagée  ou  l'exécutable  depuis  lequel  dlopen()  est   appelée)
          contient  la  balise DT_RPATH mais pas la balise DT_RUNPATH, les ré-
          pertoires listés dans la balise DT_RPATH seront parcourus.

       •  Si à l'instant où le programme est démarré, la variable d'environne-
          ment  LD_LIBRARY_PATH  est  définie  et contient une liste de réper-
          toires séparés par des deux-points  « : »,  ces  répertoires  seront
          parcourus.  Par  mesure de sécurité, cette variable est ignorée dans
          le cas de programmes set-user-ID et set-group-ID.

       •  (ELF seulement) Si l'objet appelant contient la  balise  DT_RUNPATH,
          les répertoires listés dans cette balise seront parcourus.

       •  Le fichier de cache /etc/ld.so.cache (entretenu par ldconfig(8)) est
          vérifié pour voir s'il contient une entrée correspondant à filename.

       •  Les répertoires /lib et /usr/lib sont parcourus (dans cet ordre).

       Si l'objet indiqué dans filename a des dépendances sur d'autres  objets
       partagés,  ceux-ci  seront  automatiquement chargés par l'éditeur dyna-
       mique de liens, en utilisant les mêmes règles. Le processus  peut  être
       récursif  si  ces objets ont, à leur tour, des dépendances, et ainsi de
       suite.

       L'une des deux valeurs suivantes doit être incluse dans flag :

       RTLD_LAZY
              Effectuer des liaisons paresseuses. Ne résoudre les symboles que
              lorsque  le  code  qui  les référence est exécuté. Si le symbole
              n'est jamais référencé, alors il n'est jamais résolu. Les  liai-
              sons  paresseuses  ne sont effectuées que pour les références de
              fonctions ; les références de variables sont toujours immédiate-
              ment  liées  quand  l'objet  partagé  est chargé. Depuis la ver-
              sion 2.1.1 de la glibc, ce drapeau est supplanté par l'effet  de
              la variable d'environnment LD_BIND_NOW.

       RTLD_NOW
              Si  cette valeur est spécifiée ou si la variable d'environnement
              LD_BIND_NOW est définie avec une chaîne non vide, tous les  sym-
              boles  non  définis de l'objet partagé sont résolus avant le re-
              tour de dlopen(). Si cela ne peut pas être fait, une erreur  est
              renvoyée.

       Zéro ou plusieurs des valeurs suivantes peuvent être spécifiées avec un
       OU binaire dans flag :

       RTLD_GLOBAL
              Les symboles définis par cet objet partagé seront rendus  dispo-
              nibles pour la résolution des symboles des objets partagés char-
              gés ultérieurement.

       RTLD_LOCAL
              C'est la réciproque de RTLD_GLOBAL et le comportement par défaut
              si  aucun des drapeaux n'est spécifié. Les symboles définis dans
              cet objet partagé ne sont pas rendus disponibles  pour  résoudre
              les références des objets partagés chargés ultérieurement.

       RTLD_NODELETE (depuis la glibc 2.2)
              Ne  pas  décharger  l'objet partagé lors de dlclose(). En consé-
              quence, les variables statiques de l'objet ne sont pas réinitia-
              lisées si l'objet est chargé ultérieurement avec dlopen().

       RTLD_NOLOAD (depuis la glibc 2.2)
              Ne pas charger l'objet partagé. Cela peut être utilisé pour tes-
              ter si l'objet partagé n'est pas déjà chargé  (dlopen()  renvoie
              NULL s'il n'est pas chargé, ou le descripteur de l'objet partagé
              s'il est déjà chargé). Ce drapeau peut aussi être  utilisé  pour
              promouvoir  les  drapeaux  d'un  objet  partagé déjà chargé. Par
              exemple, un objet partagé qui a été chargé avec RTLD_LOCAL  peut
              être de nouveau ouvert avec RTLD_NOLOAD | RTLD_GLOBAL.

       RTLD_DEEPBIND (depuis la glibc 2.3.4)
              Placer  l'espace  de recherche des symboles de cet objet partagé
              avant l'espace global. Cela signifie qu'un objet autonome utili-
              sera  de préférence ses propres symboles aux symboles globaux de
              même noms contenus dans les objets déjà chargés.

       Si l'argument filename est un pointeur  NULL,  le  descripteur  renvoyé
       correspond  au  programme  principal. Lorsqu'il est passé à dlsym(), ce
       descripteur provoque la recherche d'un symbole dans le programme  prin-
       cipal,  puis dans tous les objets partagés chargés au démarrage du pro-
       gramme, puis dans toutes les objets partagés chargés par dlopen()  avec
       l'attribut RTLD_GLOBAL.

       Les  références aux symboles de l'objet partagé sont résolues en utili-
       sant (dans l'ordre) : les symboles dans la table de  liens  des  objets
       chargés  pour  le  programme principal et ses dépendances, les symboles
       dans les objets partagés (et leurs dépendances) qui ont été ouverts par
       un  appel antérieur à dlopen() avec le drapeau RTLD_GLOBAL et les défi-
       nitions dans l'objet partagé lui-même (ainsi que toute dépendance ayant
       été chargée pour cet objet).

       Tout  symbole global dans l'exécutable qui a été placé dans sa table de
       symboles dynamiques par ld(1) peut aussi être utilisé pour résoudre les
       références  dans  un  objet  partagé dynamiquement chargé. Les symboles
       peuvent être placés dans la table de symbole soit parce que  les  liens
       de l'exécutable ont été édités avec le drapeau « -rdynamic » (ou de fa-
       çon synonyme « --export-dynamic »), qui fait que tous les symboles glo-
       baux  de l'exécutable sont placés dans la table de symboles dynamiques,
       soit parce que ld(1) a identifié une dépendance sur un symbole dans  un
       autre objet durant l'édition de liens statiques.

       Si le même objet partagé est chargé une nouvelle fois avec dlopen(), le
       même descripteur sera renvoyé. Un décompte du nombre de chargements est
       toutefois conservé par l'éditeur dynamique de liens afin d'éviter de le
       décharger avant que la fonction dlclose() n'ait été appelée  autant  de
       fois  que  dlopen()  a réussi. Les constructeurs (voir ci-dessous) sont
       seulement appelés lorsque l'objet  est  réellement  chargé  en  mémoire
       (c'est-à-dire  lorsque  le compteur de références est augmenté et passe
       à 1).

       Un appel ultérieur à dlopen() qui charge le  même  objet  partagé  avec
       RTLD_NOW  peut  forcer  la résolution de symboles pour un objet partagé
       chargé antérieurement avec RTLD_LAZY.  De  façon  similaire,  un  objet
       préalablement ouvert avec RTLD_LOCAL peut être promu à RTLD_GLOBAL lors
       d'un appel ultérieur à dlopen().

       Si dlopen() échoue pour une raison quelconque, elle renvoie NULL.

   dlmopen()
       Cette fonction effectue la même tâche que dlopen() ; les arguments  fi-
       lename  et  flags,  de  même  que la valeur de renvoi, sont les mêmes à
       l'exception des différences décrites plus bas.

       La fonction dlmopen() diffère de la  fonction  dlopen()  principalement
       parce  qu'elle accepte un argument supplémentaire, lmid, qui indique la
       liste de tables de liens (aussi appelée espace de noms)  dans  laquelle
       l'objet partagé doit être chargé. En comparaison, dlopen() ajoute l'ob-
       jet partagé dynamiquement chargé au même espace  de  noms  que  l'objet
       partagé  pour  lequel  l'appel dlopen() est fait. Le type Lmid_t est un
       gestionnaire opaque qui fait référence à un espace de noms.

       L'argument lmid est soit l'ID d'un espace  de  noms  existant  (pouvant
       être  obtenu  en  utilisant la requête dlinfo(3) RTLD_DI_LMID) ou l'une
       des valeurs spéciales suivantes :

       LM_ID_BASE
              Charger  l'objet  partagé  dans   l'espace   de   noms   initial
              (c'est-à-dire l'espace de noms de l'application).

       LM_ID_NEWLM
              Créer un nouvel espace de noms et y charger l'objet partagé. Les
              liens de l'objet doivent avoir été liés pour référencer tous les
              autres objets partagés dont il a besoin puisque l'espace de noms
              est initialement vide.

       Si filename est vide, alors l'unique valeur  autorisée  pour  lmid  est
       LM_ID_BASE.

   dlclose()
       La  fonction  dlclose() décrémente le compteur de références de l'objet
       partagé chargé dynamiquement et indiqué par handle.

       Si le compteur de références de cet objet tombe en dessous de  zéro  et
       qu'aucun  symbole dans cet objet n'est requis par un autre objet, alors
       l'objet est déchargé après avoir appelé tous les  destructeurs  définis
       pour  l'objet.  Des  symboles dans cet objet peuvent être requis par un
       autre objet parce qu'il a été ouvert avec le drapeau RTLD_GLOBAL et que
       l'un de ses symboles a permis une relocalisation dans un autre objet.

       Tous  les  objets  partagés qui ont été chargés automatiquement lorsque
       dlopen() a été invoquée sur l'objet référencé par  handle  sont  fermés
       récursivement de la même façon.

       Un  renvoi  réussi  de  dlclose() ne garantit que les symboles associés
       avec handle sont supprimés de l'espace d'adressage  de  l'appelant.  En
       plus  de  références résultant d'appels explicites à dlopen(), un objet
       partagé a peut-être été chargé de façon implicite  (et  les  références
       prises  en compte) à cause de références dans d'autres objets partagés.
       Ce n'est que lorsque toutes les références sont relachées  que  l'objet
       partagé peut être supprimé de l'espace d'adressage.

VALEUR RENVOYÉE
       En  cas  de succès, dlopen() et dlmopen() renvoient un gestionnaire non
       nul pour l'objet chargé. En cas d'erreur (le fichier ne peut  pas  être
       trouvé,  il  n'est  pas lisible, a le mauvais format ou bien a provoqué
       des erreurs lors de son chargement), ces fonctions renvoient NULL.

       En cas de succès, dlclose() renvoie 0, en cas d'erreur une  valeur  non
       nulle est renvoyée.

       Les  erreurs  de ces fonctions peuvent être diagnostiquées en utilisant
       dlerror(3).

VERSIONS
       dlopen() et dlclose() sont présentes dans la version 2.0  et  suivantes
       de  la  glibc. dlmopen() est apparue pour la première fois dans la ver-
       sion 2.3.4 de la glibc.

ATTRIBUTS
       Pour une explication des termes utilisés dans cette section,  consulter
       attributes(7).

       ┌─────────────────────────────────────┬──────────────────────┬─────────┐
       │InterfaceAttributValeur  │
       ├─────────────────────────────────────┼──────────────────────┼─────────┤
       │dlopen(), dlmopen(), dlclose()       │ Sécurité des threads │ MT-Safe │
       └─────────────────────────────────────┴──────────────────────┴─────────┘

STANDARDS
       POSIX.1-2001  décrit  dlclose()  et dlopen(). La fonction dlmopen() est
       une extension GNU.

       Les drapeaux RTLD_NOLOAD, RTLD_NODELETE et RTLD_DEEPBIND sont  des  ex-
       tensions GNU ; les deux premiers sont également présents sur Solaris.

NOTES
   dlmopen() et espace de noms
       Une liste de table de liens définit un espace de noms isolé pour la ré-
       solution de symboles par l'éditeur dynamique de  liens.  À  l'intérieur
       d'un  espace de noms, les objets partagés dépendants sont implicitement
       chargés selon les règles usuelles, et les références aux symboles  sont
       résolues  selon les règles usuelles, mais un telle résolution est limi-
       tée aux définitions fournies aux objets qui ont été chargés (explicite-
       ment et implicitement) dans l'espace de noms.

       La  fonction  dlmopen()  permet  une  isolation  de chargement d'objet,
       c'est-à-dire la capacité à charger un objet partagé dans un nouvel  es-
       pace de noms sans exposer le reste de l'application aux symboles rendus
       disponibles par le nouvel objet. Notez  que  l'utilisation  du  drapeau
       RTLD_LOCAL  n'est  pas  suffisante pour réaliser cela puisque qu'il em-
       pêche les symboles des objets partagés d'être disponibles à tout  autre
       objet  partagé.  Dans  certains cas, il peut être souhaitable de rendre
       les symboles fournis par un objet partagé chargé  dynamiquement  dispo-
       nibles  à d'autres objets (ou à un sous-ensemble) partagés sans exposer
       ces symboles à l'application entière. Cela peut être réalisé par l'uti-
       lisation d'un espace de noms séparé et du drapeau RTLD_GLOBAL.

       La  fonction  dlmopen()  peut  également être utilisée pour fournir une
       meilleure isolation que le drapeau RTLD_LOCAL. En particulier, les  ob-
       jets partagés chargés avec RTLD_LOCAL peuvent être promus à RTLD_GLOBAL
       s'ils sont  des  dépendances  d'un  autre  objet  partagé  chargé  avec
       RTLD_GLOBAL  mis  à part dans le cas (peu commun) où l'on a un contrôle
       explicite sur les dépendances de tous les objets partagés.

       Les cas possibles d'utilisation de dlmopen() sont des greffons où l'au-
       teur  du cadriciel de chargement de greffon ne peut pas faire confiance
       aux auteurs du greffon et ne souhaite pas que des symboles non  définis
       du  cadriciel  greffon soient résolus en symboles du greffon. Une autre
       utilisation est de charger le même objet plus d'une fois. Sans l'utili-
       sation de dlmopen(), cela exigerait la création de copies distinctes du
       fichier de l'objet partagé. Grâce à l'utilisation  de  dlmopen(),  cela
       peut  être  réalisé  par  le chargement du même fichier d'objet partagé
       dans différents espaces de noms.

       L'implémentation de la glibc prend  en  charge  un  nombre  maximal  de
       16 espaces de noms.

   Fonctions d'initialisation et de finalisation
       Les objets partagés peuvent exporter des fonctions en utilisant les at-
       tributs de fonction __attribute__((constructor)) et __attribute__((des-
       tructor)).  Les fonctions de construction sont exécutées avant que dlo-
       pen() ne renvoie, et les fonctions de destruction sont exécutées  avant
       que  dlclose()  ne  renvoie.  Un  objet partagé peut exporter plusieurs
       constructeurs et destructeurs et des priorités peuvent être associées à
       chaque  fonction pour déterminer l'ordre dans lequel elles s'exécutent.
       Consultez les pages d'information de gcc  (sous  « Attributs  de  fonc-
       tion ») pour plus d'informations.

       Une  méthode  plus  ancienne d'obtenir (partiellement) le même résultat
       passe par l'utilisation de deux symboles spéciaux reconnus  par  l'édi-
       teur  de  liens : _init et _fini. Si un objet partagé chargé dynamique-
       ment exporte une routine nommée _init(), alors  son  code  est  exécuté
       après le chargement d'un objet partagé, avant le retour de dlopen(). Si
       l'objet partagé exporte une routine  nommée  _fini,  elle  est  appelée
       juste  avant le déchargement de l'objet. Dans ce cas, vous voudrez évi-
       ter de lier l'exécutable avec les fichiers de démarrage du système, qui
       contiennent  des  versions par défaut de ces fichiers ; pour cela, vous
       pouvez spécifier l'option -nostartfiles  à  la  ligne  de  commande  de
       gcc(1).

       L'utilisation  de  _init  et  _fini  est  rendue obsolète en faveur des
       constructeurs et destructeurs susmentionnés, ce qui entre autres  avan-
       tages,  permet la définition de plusieurs fonctions d'initialisation et
       de finalisation.

       Depuis la glibc 2.2.3, atexit(3) peut être utilisée pour enregistrer un
       gestionnaire  de  sortie qui sera automatiquement appelé quand un objet
       partagé est déchargé.

   Historique
       Ces fonctions font partie de l'API dlopen, dérivée de SunOS.

BOGUES
       Pour la version 2.24 de la glibc, spécifier le drapeau RTLD_GLOBAL lors
       de  l'appel à dlmopen() génère une erreur. De plus, spécifier RTLD_GLO-
       BAL lors d'un appel à dlopen() résulte  en  un  plantage  du  programme
       (SIGSEGV)  si  l'appel  est effectué depuis n'importe quel objet chargé
       dans un autre espace de noms que celui initial.

EXEMPLES
       Le programme suivant charge la bibliothèque de maths (de la glibc), re-
       cherche  l'adresse  de la fonction cos(3) et affiche le cosinus de 2.0.
       Ci-dessous, un exemple de construction et d'exécution du programme :

           $ cc dlopen_demo.c -ldl
           $ ./a.out
           -0.416147

   Source du programme

       #include <dlfcn.h>
       #include <stdio.h>
       #include <stdlib.h>

       #include <gnu/lib-names.h>  /* Defines LIBM_SO (which will be a
                                      string such as "libm.so.6") */
       int
       main(void)
       {
           void *handle;
           double (*cosine)(double);
           char *error;

           handle = dlopen(LIBM_SO, RTLD_LAZY);
           if (!handle) {
               fprintf(stderr, "%s\n", dlerror());
               exit(EXIT_FAILURE);
           }

           dlerror();    /* Supprime une erreur existante */

           cosine = (double (*)(double)) dlsym(handle, "cos");

           /* D'après le standard ISO C, la conversion de type entre un pointeur
              de fonction et « void * », comme effectuée ci-dessus, produit des
              résultats indéfinis.
              POSIX.1-2003 et POSIX.1-2008 ont admis cet état de fait et proposé
              le contournement ci-dessous :

                  *(void **) (&cosine) = dlsym(handle, "cos");

              Cette conversion (lourde) de type est conforme au standard
              ISO C and évitera tout avertissement du compilateur.

              La révision technique 2013 de POSIX.1-2008 a amélioré la
              situation en exigeant que les implémentations prennent en charge
              la conversion du type « void * » vers un pointeur de fonction.
              Cependant, certains compilateurs (par exemple gcc avec
              l'option « -pedantic ») peuvent se plaindre de la conversion
              effectuée dans ce programme. */

           error = dlerror();
           if (error != NULL) {
               fprintf(stderr, "%s\n", error);
               exit(EXIT_FAILURE);
           }

           printf("%f\n", (*cosine)(2.0));
           dlclose(handle);
           exit(EXIT_SUCCESS);
       }

VOIR AUSSI
       ld(1),  ldd(1),  pldd(1),  dl_iterate_phdr(3),  dladdr(3),  dlerror(3),
       dlinfo(3), dlsym(3), rtld-audit(7), ld.so(8), ldconfig(8)

       pages Info de ld, pages Info de gcc

TRADUCTION
       La  traduction française de cette page de manuel a été créée par Chris-
       tophe Blaess <https://www.blaess.fr/christophe/>, Stéphan  Rafin  <ste-
       phan.rafin@laposte.net>, Thierry Vignaud <tvignaud@mandriva.com>, Fran-
       çois Micaux, Alain Portal <aportal@univ-montp2.fr>, Jean-Philippe  Gué-
       rard  <fevrier@tigreraye.org>,  Jean-Luc  Coulon (f5ibh) <jean-luc.cou-
       lon@wanadoo.fr>, Julien Cristau <jcristau@debian.org>,  Thomas  Huriaux
       <thomas.huriaux@gmail.com>,  Nicolas François <nicolas.francois@centra-
       liens.net>, Florentin Duneau <fduneau@gmail.com>, Simon  Paillard  <si-
       mon.paillard@resel.enst-bretagne.fr>,    Denis   Barbier   <barbier@de-
       bian.org>, David Prévot <david@tilapin.org>  et  Grégoire  Scano  <gre-
       goire.scano@malloc.fr>

       Cette traduction est une documentation libre ; veuillez vous reporter à
       la       GNU       General       Public        License        version 3
       ⟨https://www.gnu.org/licenses/gpl-3.0.html⟩  concernant  les conditions
       de copie et de distribution. Il n'y a aucune RESPONSABILITÉ LÉGALE.

       Si vous découvrez un bogue dans la traduction de cette page de  manuel,
       veuillez envoyer un message à ⟨debian-l10n-french@lists.debian.org⟩.

Pages du manuel de Linux 6.03   5 février 2023                       dlopen(3)

Generated by dwww version 1.15 on Sat Jun 29 01:45:25 CEST 2024.