Page suivante - Page précédente - Table des matières

7. Chargement dynamique

Ce paragraphe est en fait un peu court : il sera étendu dans une version ultérieure dès que j'aurai récupéré le HowTo ELF

7.1 Concepts

Linux possède des bibliothèques dynamiques, comme on vous le répète depuis le début de ce document ! Or, il existe un système pour reporter le travail d'association des noms des symboles et de leur adresse dans la bibliothèque, qui est normalement effectué lors de l'édition de liens en l'effectuant lors du chargement du programme.

7.2 Messages d'erreur

Envoyez moi vos erreurs ! Je n'en fait pas grand chose sauf les insérer dans ce paragraphe...

can't load library: /lib/libxxx.so, Incompatible version

(seulement a.out) Cela signifie que vous n'avez pas la version correcte de la bibliothèque (numéro dit majeur). Non, il n'est pas possible d'effectuer un lien symbolique sur la bibliothèque que vous possédez : si vous avez de la chance, vous obtiendrez un segmentation fault. Récupérez la nouvelle version. Un message un peu équivalent existe également sur les systèmes ELF :

ftp: can't load library 'libreadline.so.2'

warning using incompatible library version xxx

(seulement a.out) Vous avez un numéro de version de bibliothèque (mineur) inférieur à la version avec laquelle a été compilé le programme. Le programme fonctionnera sûrement. Une mise à jour est toutefois conseillée.

7.3 Contrôler l'opération de chargement dynamique

Il existe certaines variables d'environnements que le chargeur dynamique utilise. Beaucoup sont exploitées par le programme ldd lorsqu'il s'agit de particularités de l'environnement de l'utilisateur, ce qui peuvent être positionnées pour lancer ldd avec des options particulières. Voici une description des différentes variables d'environnement que vous pouvez rencontrer :

  • LD_BIND_NOW --- normalement, les fonctions ne sont pas cherchées dans les bibliothèques avant leur appel. En positionnant cette option, vous vérifiez que toutes les fonctions employées dans votre programmes se trouvent bien dans la bibliothèque lors de son chargement, ce qui ralentit le lancement du programme. C'est utile lorsque vous voulez tester que l'édition de liens s'est parfaitement déroulée et que tous les symboles sont bien associés.
  • LD_PRELOAD peut être défini avec un nom de fichier qui contient des fonctions surchargeant des fonctions déjà existantes. Par exemple, si vous testez une stratégie d'allocation mémoire, et que vous voulez remplacer le malloc de la bibliothèque C par le vôtre situé dans un module ayant pour nom malloc.o, il vous suffit de faire :
    $ export LD_PRELOAD=malloc.o
    $ test_mon_malloc
    
    LD_ELF_PRELOAD et LD_AOUT_PRELOAD sont similaires, mais leur utilisation est spécifique au type de binaire utilisé. Si LD_TypeBinaire_PRELOAD et LD_PRELOAD sont positionnés, celui correspondant le mieux à la machine est utilisé.
  • LD_LIBRARY_PATH contient une liste de répertoires contenant les bibliothèques dynamiques. Cela n'affecte pas l'édition de liens : cela n'a qu'un effet lors de l'exécution. Il faut noter qu'elle est désactivée pour des programmes qui s'exécutent avec un setuid ou un setgid. Enfin, LD_ELF_LIBRARY_PATH et LD_AOUT_LIBRARY_PATH peuvent être utilisés pour orienter le mode de compilation du binaire. LD_LIBRARY_PATH ne devrait pas être nécessaire en principe : ajoutez les répertoires dans le fichier /etc/ld.so.conf/ et relancez ldconfig.
  • LD_NOWARN s'applique au format a.out uniquement. Lorsqu'elle est positionnée (c.a.d si elle existe par exemple avec LD_NOWARN=true; export LD_NOWARN) cela arrête le chargeur du programme même sur des avertissements insignifiants (tels que des messages d'incompatibilités de numéros mineurs de version).
  • LD_WARN s'applique à ELF uniquement. Lorsqu'elle est positionnée, on transforme le message habituellement fatal Can't find library en un avertissement. Ce n'est pas positionné par défaut mais c'est important pour un programme comme ldd.
  • LD_TRACE_LOADED_OBJECTS s'applique à ELF uniquement, et permet de simuler l'exécution des programmes comme s'ils l'étaient par ldd :
    $ LD_TRACE_LOADED_OBJECTS=true /usr/bin/lynx
     libncurses.so.1 => /usr/lib/libncurses.so.1.9.6
     libc.so.5 => /lib/libc.so.5.2.18
    

7.4 Ecrire des programmes en utilisant le chargement dynamique

Cela ressemble énormément au système de chargement dynamique utilisé sous Solaris 2.x. Ce système est décrit d'une manière précise dans le document expliquant la programmation avec ELF écrit par H J Lu et dans la page de manuel dlopen(3), qui se trouve dans le paquetage ld.so. Voici un exemple simple : pensez à faire l'édition de liens avec -ldl

#include <dlfcn.h>
#include <stdio.h>
main()
{
 void *libc;
 void (*printf_call)();
 if(libc=dlopen("/lib/libc.so.5",RTLD_LAZY))
 {
 printf_call = dlsym(libc,"printf");
 (*printf_call)("Bonjour ! Ha ben ca marche pil poil sous Linux !\n");
 }
}


Page suivante - Page précédente - Table des matières