DLOPEN
Section : Manuel du programmeur Linux (
3)
Mise à jour de la version anglaise : 14 juin 2008
Index
Menu principal
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);
Lier avec
-ldl.
DESCRIPTION
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 intelligible,
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 depuis le fichier
dont le nom est fourni dans la chaîne
filename
(terminée par un octet 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 (voir
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 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 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.)
Une des deux valeurs suivantes doit être incluse dans
flag :
- RTLD_LAZY
-
Effectuer un liage fainéant.
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é, il n'est jamais résolu.
(le liage fainéant n'est effectué que pour les références aux fonctions ;
les références aux variables sont toujours immédiatement liées lorsque
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 dans cette bibliothèque seront disponibles
pour les bibliothèques chargées ultérieurement.
- RTLD_LOCAL
-
C'est la réciproque de
RTLD_GLOBAL,
et la valeur par défaut si aucun attribut n'est spécifié.
Les symboles définis dans cette bibliothèque ne seront pas
disponibles pour la résolution de référence dans les bibliothèques
chargées ultérieurement.
- RTLD_NODELETE (depuis la glibc 2.2)
-
Ne pas décharger la bibliothèque lors d'un
dlclose().
En conséquence, les variables statiques de la bibliothèque ne sont pas
réinitialisées si la bibliothèque est rechargée avec
dlopen()
plus tard.
Cet attribut n'est pas spécifié dans POSIX.1-2001.
- RTLD_NOLOAD (depuis la glibc 2.2)
-
Ne pas charger la bibliothèque.
Cela peut être utilisé pour tester si la bibliothèque est déjà résidente
(dlopen()
renvoie NULL si ce n'est pas le cas,
ou le descripteur de la bibliothèque si elle est résidente).
Cet attribut peut être utilisé pour promouvoir les attributs
sur une bibliothèque qui est déjà chargée.
Par exemple, une bibliothèque qui a été précédemment chargée avec
RTLD_LOCAL
peut être réouverte avec
RTLD_NOLOAD | RTLD_GLOBAL.
Cet attribut n'est pas spécifié dans POSIX.1-2001.
- RTLD_DEEPBIND (depuis glibc 2.3.4)
-
Placer la portée de consultation des symboles dans cette bibliothèque
devant la portée globale.
Cela signifie qu'une bibliothèque autonome utilisera ses propres symboles
de préférence aux symboles globaux de même nom contenus
dans des bibliothèques qui ont déjà été chargées.
Cet attribut 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 l'attribut
RTLD_GLOBAL.
Si l'édition des liens de l'exécutable a été faite avec l'option
« -rdynamic » (ou, de manière synonyme, « --export-dynamic »),
alors ses symboles globaux seront également employés pour résoudre
les références de la 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 de 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 un descripteur de bibliothèque dynamique renvoyée par
dlopen()
et un nom de symbole terminé par un octet nul,
et renvoie l'adresse où ce symbole a été chargé.
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 sur la bibliothèque dynamique
dont le descripteur est
handle.
Si ce nombre descend à 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 si une erreur est survenue.
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(),
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 le lien avec les fichiers de démarrage
du système, vous pouvez préciser le paramètre
-nostartfiles
sur 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 attributs
__attribute__((constructor))
et
__attribute__((destructor)).
Voir les pages info de
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 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ù elle 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 à
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 si elle réussit.
La fonction
dlvsym(),
fournie par la glibc depuis la version 2.1,
effectue la même chose que
dlsym()
mais prend une chaîne de version 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é lorsque la bibliothèque sera déchargée.
Historique
L'interface standard dlopen provient de SunOS.
Ce système possède également
dladdr()
mais pas
dlvsym().
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
Les bibliothèques qui exportent
_init()
et
_fini()
seront compilées comme suit, en prenant
bar.c
comme exemple :
gcc -shared -nostartfiles -o bar bar.c
VOIR AUSSI
ld(1),
ldd(1),
dl_iterate_phdr(3),
feature_test_macros(7),
ldconfig(8),
ld.so(8),
pages info de ld.so, gcc et ld
TRADUCTION
Ce document est une traduction réalisée par Christophe Blaess
<http://www.blaess.fr/christophe/> le 30 août 2000
et révisée le 17 juillet 2008.
L'équipe de traduction a fait le maximum pour réaliser une adaptation
française de qualité. La version anglaise la plus à jour de ce document est
toujours consultable via la commande : « LANG=C man 3 dlopen ».
N'hésitez pas à signaler à l'auteur ou au traducteur, selon le cas, toute
erreur dans cette page de manuel.
Index
- NOM
-
- SYNOPSIS
-
- DESCRIPTION
-
- dlerror()
-
- dlopen()
-
- dlsym()
-
- dlclose()
-
- Les symboles obsolètes _init() et _fini()
-
- Extensions glibc : dladdr() et dlvsym()
-
- CONFORMITÉ
-
- NOTES
-
- Historique
-
- EXEMPLE
-
- VOIR AUSSI
-
- TRADUCTION
-
Dernière mise à jour : 17 juillet 2008