6. dlopen() et ses amies

Pour charger une bibliothèque partagée au vol, il vous suffit d'effectuer un appel à dlopen(), de chercher les fonctions et de faire pointer vos pointeurs dessus grâce à dlsym, et lorsque vous avez fini d'utiliser la bibliothèque partagée, un appel à dlclose() ferme tout.

dlopen() prend deux arguments. Le premier est le nom de la bibliothèque partagée. Si cette bibliothèque n'est pas trouvée, elle est cherchée dans les chemins par défaut, ceux spécifiés dans /etc/ld.so.conf pour GNU/Linux, et dans les chemins contenus dans la variable d'environnement $LD_LIBRARY_PATH pour tous les unices, GNU/Linux inclus. Le second argument est soit RTLD_LAZY qui dit que la résolution des symboles (inclus les noms des fonctions) se fera lorsqu'on en aura besoin, ou RTLD_NOW qui force cette résolution de manière à ce qu'elle soit faite lorsque dlopen() vous rend la main. Avec un ou binaire, vous pouvez ajouter l'option RTLD_GLOBAL qui rend les symboles externes accessibles aussi aux autres bibliothèques partagées que vous seriez susceptibles de charger ensuite. dlopen() exécute aussi le code se trouvant dans une fonction appelée _init() si elle en trouve une.

dlopen(), de la mème manière que les appels servant à ouvrir des fichiers, renvoie un identificateur. Cet identificateur nous sert de premier argument à la fonction dlsym(), alors que le second argument est le nom d'une fonction (ou tout autre symbole externe) qui nous intéresse. La valeur renvoyée par dlsym() est un pointeur sur cette fonction (ou sur le symbole externe voulu), si tout s'est bien passé.

Si quelque chose s'est mal passé, la fonction dlerror(), qui ne prend pas d'argument, renvoie une chaîne de caractères contenant le message d'erreur.

Pour décharger la bibliothèque dynamique, c'est-à-dire quand vous avez fini d'utiliser les fonctions qu'elles contient et non pas quand vous avez récupéré les pointeurs sur les fonctions, vous pouvez utiliser dlclose() en fournissant l'identificateur de dlopen() en premier et unique argument. Ici comme pour dlopen(), une fonction peut être exécutée avant le déchargement de la bibliothèque dynamique. Cette fonction doit s'appeler _fini().

Exemple avec libfstest.so:

 1 void *libfstest_handle;
 2 fs_test_f fs_test;
 3 fs_test_t result;
 4 
 5 if (!(libfstest_handle = dlopen ("libfstest.so", RTLD_LAZY)))
 6   {
 7     printf ("Erreur dlopen: %s\n", dlerror ());
 8     exit (EXIT_FAILURE);
 9   }
10 if (!(fs_test = dlsym (libfstest_handle, "fs_test")))
11   {
12     printf ("Erreur dlsym: %s\n", dlerror ());
13     dlclose (libfstest_handle);
14     exit (EXIT_FAILURE);
15   }
16 fs_test ("/", &result);
17 dlclose (libfstest_handle);
18 exit (EXIT_SUCCESS);

Je pense que les commentaires sont inutiles ici: nous avons une simple illustration de ce qu'il faut avant et après l'appel à fs_test() ligne 16.

création est mise à disposition sous un contrat Creative Commons