Loading

NOM

       dladdr,   dlclose,  dlerror,  dlopen,  dlsym,  dlvsym  -  Interface  de
       programmation pour le chargeur de bibliothèques dynamiques

SYNOPSIS

       #include <dlfcn.h>

       void *dlopen(const char *filename, int flag);

       char *dlerror(void);

       void *dlsym(void *handle, const char *symbol);

       int dlclose(void *handle);

       Effectuez l’édition des liens avec l’option -ldl.

       Les  quatre   fonctions   dlopen(),   dlsym(),   dlclose(),   dlerror()
       implémentent  l’interface pour le chargeur de bibliothèques dynamiques.

   dlerror()
       La fonction dlerror() renvoie une chaîne de caractères,  compréhensible
       par  l’homme,  décrivant  la  dernière  erreur  survenue dans dlopen(),
       dlsym() ou dlclose() depuis le dernier appel à dlerror(). Elle  renvoie
       NULL  si aucune erreur n’est survenue depuis l’initialisation ou depuis
       son dernier appel.

   dlopen()
       La fonction dlopen() charge la bibliothèque dynamique dont le  nom  est
       fourni  dans  la  chaîne  filename  (terminée  par un caractère nul) et
       renvoie un descripteur opaque (« handle ») représentant la bibliothèque
       dynamique.  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, le chargeur dynamique cherche la bibliothèque de la
       façon suivante (voyez ld.so(8) pour plus de détails) :

       o   (ELF seulement) si le fichier exécutable pour le programme appelant
           contient la balise DT_RPATH mais  pas  la  balise  DT_RUNPATH,  les
           répertoires listés dans la balise DT_RPATH seront parcourus.

       o   Si   à   l’instant   où  le  programme  est  démarré,  la  variable
           d’environnement LD_LIBRARY_PATH est définie et contient  une  liste
           de répertoires (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-UID et set-GID).

       o   (ELF seulement) si le fichier exécutable pour le programme appelant
           contient la balise DT_RUNPATH, les répertoires  listés  dans  cette
           balise seront parcourus.

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

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

       Si  la  bibliothèque  a  des  dépendances  sur  d’autres  bibliothèques
       partagées, celles-ci seront automatiquement chargées  par  le  chargeur
       dynamique,  en  utilisant  les  mêmes  règles.  (Le processus peut être
       récursif si ces bibliothèques 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.  Résoudre  seulement  les
              symboles dont 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 bindings paresseux ne sont seulement effectués que pour les
              références  de  fonctions ;  les  références  de  variables sont
              toujours immédiatement liées quand la bibliothèque est chargée).

       RTLD_NOW
              Si   cette   valeur   est   spécifiée,   ou   que   la  variable
              d’environnement LD_BIND_NOW est  définie  avec  une  chaîne  non
              vide,  tous  les  symboles  non  définis de la bibliothèque sont
              résolus avant le retour 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 cette bibliothèque  seront  disponibles
              pour  la  résolution  des  symboles  des  futurs  chargements de
              bibliothèques.

       RTLD_LOCAL
              C’est la réciproque  de  RTLD_GLOBAL,  et  le  comportement  par
              défaut  si  aucun  drapeau  n’est spécifié. Les symboles définis
              dans cette bibliothèque ne sont pas  disponibles  pour  résoudre
              les références des chargement de bibliothèques futurs.

       RTLD_NODELETE (depuis la glibc 2.2)
              Ne   pas   décharger  la  bibliothèque  lors  de  dlclose().  En
              conséquence, les variables statiques de la bibliothèque ne  sont
              pas    ré-initialisées    si   la   bibliothèque   est   chargée
              ultérieurement avec dlopen() . Ce  drapeau  n’est  pas  spécifié
              dans POSIX.1-2001.

       RTLD_NOLOAD (depuis la glibc 2.2)
              Ne  pas  charger  la  bibliothèque.  Ceci peut être utilisé pour
              tester si la  bibliothèque  n’est  pas  déjà  chargée  (dlopen()
              renvoie  NULL si elle n’est pas chargée, ou le descripteur de la
              bibliothèque si elle déjà chargée). Ce drapeau peut  aussi  être
              utilisé  pour  promouvoir  les  drapeaux d’une bibliothèque déjà
              chargée. Par exemple, une bibliothèque qui a  été  chargée  avec
              RTLD_LOCAL     peut     être    de    nouveau    ouverte    avec
              RTLD_NOLOAD |RTLD_GLOBAL. Ce drapeau  n’est  pas  spécifié  dans
              POSIX.1-2001.

       RTLD_DEEPBIND (depuis la glibc 2.3.4)
              Placer  l’espace de recherche des symboles de cette bibliothèque
              avant  l’espace  global.  Cela  signifie   qu’une   bibliothèque
              autonome  utilisera  ses  propres  symboles  de  préférence  aux
              symboles globaux de même noms contenus  dans  les  bibliothèques
              déjà  chargées. Ce drapeau n’est pas spécifié dans POSIX.1-2001.

       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
       principal,  puis  dans  toutes  les bibliothèques partagées chargées au
       démarrage du programme, puis dans toutes  les  bibliothèques  partagées
       chargées par dlopen() avec l’attribut RTLD_GLOBAL.

       Les  références  externes de la bibliothèque sont résolues en utilisant
       les bibliothèques mentionnées dans sa liste de dépendances,  et  toutes
       les  autres  bibliothèques  éventuellement  ouvertes auparavant avec le
       drapeau RTLD_GLOBAL. Si l’édition des liens de l’exécutable a été faite
       avec   l’option   « -rdynamic »   (ou,   de   manière   synonyme,  avec
       « --export-dynamic»), alors les symboles globaux  du  programme  seront
       également  utilisés  pour  résoudre  les  références d’une bibliothèque
       chargée dynamiquement.

       Si la même bibliothèque est chargée une nouvelle fois avec dlopen(), le
       même  descripteur  sera renvoyé. Un compte du nombre de chargements est
       toutefois conservé afin d’éviter de la décharger avant que la  fonction
       dlclose()  n’ait  été  appelée autant de fois que dlopen() a réussi. La
       routine _init, si elle existe, est appelée  une  seule  fois.  Mais  un
       appel  postérieur  avec RTLD_NOW peut forcer la résolution des symboles
       pour une bibliothèque précédemment chargée avec RTLD_LAZY.

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

   dlsym()
       La fonction  dlsym()  prend  comme  arguments,  un  « descripteur »  de
       bibliothèque  dynamique  renvoyé  par  dlopen()  et  un  nom de symbole
       terminé par un caractère nul, et renvoie l’adresse où ce symbole a  été
       chargé  en  mémoire.  Si  le  symbole  n’est  pas  trouvé, soit dans la
       bibliothèque spécifiée, soit dans n’importe quelle bibliothèque chargée
       automatiquement  par dlopen() lorsque cette bibliothèque a été chargée,
       dlsym() renvoie NULL. (La recherche effectuée par dlsym()  est  d’abord
       en  largeur à travers l’arbre des dépendances de ces bibliothèques). Le
       symbole pouvant légitimement avoir  la  valeur  NULL  (la  valeur  NULL
       renvoyée par dlsym() n’indique pas nécessairement une erreur), la bonne
       manière  de  vérifier  si  une  erreur  s’est  produite  est  d’appeler
       dlerror()   pour   effacer  toute  ancienne  condition  d’erreur,  puis
       d’appeler  dlsym()  et  appeler  une   nouvelle   fois   dlerror()   en
       sauvegardant  sa  valeur  de retour dans une variable et vérifier si la
       valeur sauvegardée n’est pas NULL.

       Il y a deux pseudo-descripteurs spéciaux : RTLD_DEFAULT  et  RTLD_NEXT.
       Le  premier  recherche  la  première  occurrence  du  symbole désiré en
       utilisant l’ordre de recherche des bibliothèques par défaut. Le  second
       recherche   l’occurrence   suivante  d’une  fonction  à  partir  de  la
       bibliothèque en cours. Ceci permet de fournir une  enveloppe  pour  une
       fonction se trouvant dans une autre bibliothèque partagée.

   dlclose()
       La   fonction  dlclose()  décrémente  le  nombre  de  références  d’une
       bibliothèque dynamique dont le descripteur est  handle.  Si  ce  nombre
       atteint  zéro  et  si  aucune autre bibliothèque n’emploie des symboles
       exportés par celle-ci, elle est déchargée.

       La fonction dlclose() renvoie 0 si elle  réussit,  et  une  valeur  non
       nulle en cas d’erreur.

   Les symboles obsolètes _init() et _fini()
       L’éditeur  de  liens reconnaît les symboles spéciaux _init et _fini. Si
       une bibliothèque dynamique exporte une routine  nommée  _init(),  alors
       son  code est exécuté après le chargement, avant le retour de dlopen().
       Si la bibliothèque exporte une routine nommée _fini, elle  est  appelée
       juste  avant  le  déchargement.  Au cas où vous voudriez éviter de lier
       l’exécutable avec les fichiers de démarrage  du  système,  vous  pouvez
       spécifier  le paramètre -nostartfiles à la ligne de commande de gcc(1).

       L’utilisation de ces routines  ou  des  options  gcc  -nostartfiles  ou
       -nostdlib  n’est  pas  recommandée. Il peut en résulter un comportement
       non désiré tant que les routines constructeur/destructeur ne  sont  pas
       exécutées (à moins que des mesures spéciales ne soient prises).

       À  la  place,  les  bibliothèques  devraient  exporter  les routines en
       utilisant  les  fonctions  attribut   __attribute__((constructor))   et
       __attribute__((destructor)).  Voyez  la  documentation de gcc au format
       Info pour plus d’information sur celles-ci. Les  routines  constructeur
       sont  exécutées  avant  que dlopen revienne et les routines destructeur
       sont exécutées avant que dlclose revienne.

   Extensions de la glibc :dladdr() et dlvsym()
       La glibc a ajouté deux fonctions, qui ne sont pas décrites  par  POSIX,
       dont les prototypes sont :

       #define _GNU_SOURCE
       #include <dlfcn.h>

       int dladdr(void *addr, Dl_info *info);

       void *dlvsym(void *handle, char *symbol, char *version);

       La  fonction  dladdr() prend un pointeur vers une fonction et essaie de
       résoudre le nom et le  fichier  où  il  se  trouve.  L’information  est
       stockée dans une structure Dl_info :

           typedef struct {
               const char *dli_fname; /* Chemin du fichier de l’objet partagé
                                         contenant l’adresse */
               void       *dli_fbase; /* Adresse à laquelle l’objet partagé
                                         est chargé */
               const char *dli_sname; /* Nom du symbole le plus proche avec
                                         une adresse inférieure à addr */
               void       *dli_saddr; /* Adresse exacte du symbole dont
                                         le nom est dli_sname */
           } Dl_info;

       Si  aucun  symbole  correspondant à l’adresse addr ne peut être trouvé,
       dli_sname et dli_saddr sont définis à NULL.

       dladdr() renvoie 0 en cas d’erreur et une valeur non nulle  en  cas  de
       succès.

       La  fonction  dlvsym(),  fournie  par  la  glibc depuis la version 2.1,
       effectue la même chose que dlsym() mais prend une version sous forme de
       chaîne comme argument supplémentaire.

CONFORMITÉ

       POSIX.1-2001 décrit dlclose(), dlerror(), dlopen() et dlsym().

NOTES

       Les  symboles  RTLD_DEFAULT  et  RTLD_NEXT  sont définis dans <dlfcn.h>
       seulement si _GNU_SOURCE a été définie avant l’inclusion.

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

   Historique
       L’interface standard dlopen  provient  de  SunOS.  Ce  système  possède
       également dladdr() mais pas dlvsym().

BOGUES

       Quelquefois,  les pointeurs de fonctions passés à dladdr() peuvent vous
       surprendre. Sur certaines architectures (notablement i386  et  x86_64),
       dli_fname  et  dli_fbase peuvent pointés sur l’objet depuis lequel vous
       appelez dladdr(), même si la  fonction  utilisée  en  paramètre  semble
       provenir d’une bibliothèque liée dynamiquement.

       Le  problème est que le pointeur de fonction ne sera résolu que lors de
       la compilation, mais pointe  simplement  vers  la  section  de  l’objet
       original  plt  (table  de  procédure d’édition des liens), qui redirige
       l’appel après avoir demandé à l’éditeur de liens dynamique de  résoudre
       le  symbole).  Un  contournement consiste à compiler le code pour qu’il
       soit indépendant de son adressage : dans ce cas le compilateur ne  peut
       pas  préparer  le  pointeur  à  la compilation, et de nos jours, gcc(1)
       générera du code qui chargera juste l’adresse finale du symbole  depuis
       la  table GOT (table d’offset globale) lors de l’exécution, avant de la
       passer à dladdr().

EXEMPLE

       Charger la bibliothèque mathématique et afficher le cosinus de 2,0 :

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

       int
       main(int argc, char **argv)
       {
           void *handle;
           double (*cosine)(double);
           char *error;

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

           dlerror();    /* Clear any existing error */

           /* Writing: cosine = (double (*)(double)) dlsym(handle, "cos");
              would seem more natural, but the C99 standard leaves
              casting from "void *" to a function pointer undefined.
              The assignment used below is the POSIX.1-2003 (Technical
              Corrigendum 1) workaround; see the Rationale for the
              POSIX specification of dlsym(). */

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

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

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

       Supposons que le programme s’appelle « foo.c »,  on  doit  le  compiler
       ainsi:

           gcc -rdynamic -o foo foo.c -ldl

       Une  bibliothèque (bar.c dans l’exemple suivant) qui exporte _init() et
       _fini() sera compilée comme suit :

           gcc -shared -nostartfiles -o bar bar.c

VOIR AUSSI

       ld(1),     ldd(1),     dl_iterate_phdr(3),      feature_test_macros(7),
       rtld-audit(7), ld.so(8), ldconfig(8), les pages Info de ld.so, gcc, ld

COLOPHON

       Cette  page  fait  partie  de  la  publication 3.23 du projet man-pages
       Linux. Une description du projet et des instructions pour signaler  des
       anomalies       peuvent       être       trouvées      à      l’adresse
       http://www.kernel.org/doc/man-pages/.

TRADUCTION

       Cette page de manuel a été traduite  et  mise  à  jour  par  Christophe
       Blaess  <http://www.blaess.fr/christophe/> entre 1996 et 2003, puis par
       Alain Portal <aportal AT univ-montp2 DOT fr> jusqu’en 2006, et  mise  à
       disposition sur http://manpagesfr.free.fr/.

       Les mises à jour et corrections de la version présente dans Debian sont
       directement gérées par Florentin Duneau <fduneau@gmail.com> et l’équipe
       francophone de traduction de Debian.

       Veuillez   signaler   toute   erreur   de   traduction  en  écrivant  à
       <debian-l10n-french@lists.debian.org> ou par un rapport de bogue sur le
       paquet manpages-fr.

       Vous  pouvez  toujours avoir accès à la version anglaise de ce document
       en utilisant la commande « man -L C <section> <page_de_man> ».