Démon BSD

Documentation NetBSD :

FAQ ELF de NetBSD

ELF en questions


ELF en questions


Qu'est-ce que ELF ? (haut)

ELF est un format binaire conçu pour supporter les objets dynamiques et les bibliothèques partagées. Sur les anciens systèmes COFF et ECOFF, cette gestion n'était pas naturelle et rendait les implémentations dynamiques à la fois complexes, capricieuses et lentes.

Un module chargé dynamiquement à l'exécution ne trouve pas les symboles de l'image de mon programme. (haut)

Vous avez certainement oublié l'option --export-dynamic lors de l'édition de liens. Cela n'est nécessaire que si un quelconque symbole du programme doit être utilisé par un module chargé dynamiquement, par exemple, si un programme décide à l'exécution s'il doit charger dynamiquement un module auquel il n'a jamais été lié. Notez que si vous utilisez cc(1) au lieu de ld(1), l'option est -Wl,--export-dynamic.

Pas besoin de ldconfig ou de ld.so.conf ! (haut)

Idéalement, il n'y a pas besoin de ldconfig ou de /etc/ld.so.conf car ELF met en place un bon mécanisme prédictible (lisez portable) pour localiser les bibliothèques partagées. Malheureusement, il existe encore certains cas rétifs (par exemple si vous lancez un binaire setuid dont vous n'avez pas les sources qui demande que les bibliothèques soit là où vous ne voulez pas). Un fichier /etc/ld.so.conf continuera donc à marcher. Lisez des avis sur les autres façons de faire et pourquoi ce n'est pas une bonne idée. La section suivante présente la façon qu'a ELF de localiser les bibliothèques partagées.

Mon programme ne trouve pas ses bibliothèques partagées (haut)

Un programme ELF a besoin de connaitre le répertoire et le fichier nécessaires pour que mmap(2) trouve les bibliothèques partagées. La version est incluse dans le nom de fichier. Il existe un mécanisme pour les répertoires et un autre pour les fichiers.

Répertoires

Bien que rarement utilisée, la variable d'environnement optionnelle LD_LIBRARY_PATH indique les chemins d'accès (séparés par deux points). Elle peut être utilisée par des scripts pour les applications mal configurées. Elle est ignorée par les binaires setuid.

Il en existe aussi avec le programme de chargement : ld.elf_so. Sur de nombreux système, ce chemin se résume à /usr/lib. Sur les version de NetBSD précédant la 1.4, la recherche s'effectue aussi dans /usr/local/lib.

Le premier mécanisme de localisation est la liste de recherche «rpath» incluse dans l'image de l'exécutable. Cette liste est établie à l'aide de la directive -R de ld(1). La syntaxe POSIX pour les options de ld est :

    -Wl,option,option,...

Par exemple : -Wl,-R/usr/quelquechose/lib. Plusieurs directives -R peuvent être données à un seul programme afin de créer une liste de chemins d'accès aux bibliothèques partagées.

Cette directive est aussi connue sous le nom de -rpath. L'avantage de -R est que ça marche aussi sur les anciennes versions de NetBSD.

Noms de fichiers et version

Lorsqu'une bibliothèque partagée est crée, la directive -soname est utilisée pour renseigner le champs interne DT_SONAME avec le numéro de version. La vraie bibliothèque est nommée, par exemple :

L'idée est que le Makefile ne cherchera à lier que le simple fichier .so (qui voudrait changer tous les Makefiles uniquement parce qu'une nouvelle version de bibliothèque est sortie ?). Cependant, une fois lié, le programme veut connaitre la version majeure mais ne veut pas utiliser de version mineure.

La bibliothèque elle-même sait qu'elle est libgizmo.so.4 car la directive -soname libgizmo.so.4 a été utilisée lors de sa création. Le programme sait qu'il utilisera la version majeure 4 car l'éditeur de liens a copié la chaine DT_SONAME, qui vaut libgizmo.so.4, de la bibliothèque dans l'exécutable.

N'utilisez pas -soname libgizmo.so car le programme utiliserait la dernière version majeure et pourrait se bloquer si elle a changé (le nombre majeur change lorsque la nouvelle bibliothèque devient incompatible). De même, n'utilisez pas -soname libgizmo.so.4.2 car une modification compatible qui augmente le nombre mineur casserait inutilement le lien.

Exemples de bibliothèques partagées ELF (haut)

Pour compiler f.c et en faire une bibliothèque partagée :

cc -O -Werror -c -fpic -DPIC f.c -o f.so
ar cq libf_pic.a `NM=nm lorder f.so | tsort -q`
ld -x -shared -R/my/directory/lib -soname libf.so.4 -o
   libf.so.4.9 /usr/lib/crtbeginS.o --whole-archive
   libf_pic.a /usr/lib/crtendS.o

Une autre façon :

% cat Makefile
LIB=f
SRCS=f.c
.include <bsd.lib.mk>
% cat shlib_version
major=4
minor=9
% make

Vous pouvez désactiver certaines cibles du Makefile avec NOPROFILE=1 et NOSTATICLIB=1.

Encore une autre façon :

libtool - Le paquetage libtool est un gros script shell destiné à gérer les bibliothèques statiques et dynamiques indépendamment de la machine. Il existe un paquetage NetBSD libtool et même une page d'accueil libtool.

Mais je veux ldconfig ! Je veux ld.so.conf ! Je le veux ! Je le veux ! (haut)

Au premier abord, il semble raisonnable de vouloir déplacer les choses où l'on veut puis de corriger les localisations correspondantes dans /etc.

En fait, quelques développeurs du système ELF ont apparamment ajouté un tel fichier mais avec des résultats mitigés. Le mécanisme ELF a été conçu pour corriger certains problèmes donc réintroduire l'ancien mécanisme peut les faire revenir.

Actuellement, nous supportons la fonctionnalité /etc/ld.so.conf dans notre éditeur de liens ELF mais rien ne prouve que la solution hybride soit la meilleure. Pour cette raison, son existance n'est pas dévoilée, son utilisation n'est pas encouragée et un modèle d'installation par défaut est proposé. Cela existe pour ceux qui pensent qu'ils en ont réellement besoin et ne peuvent vivre sans.

Voici quelques problèmes.

  1. Il s'agit d'une approche au fusil de chasse qui considère, à tort, que toutes les applications du système veulent utiliser les mêmes chemins d'accès. Un des avantages de l'option -R est que différentes applications peuvent utiliser différents chemins d'accès. Nous pourrions ajouter des exceptions mais il s'agit plus d'une question de configuration. Voir plus loin.
  2. Un fichier supplémentaire dans /etc est encore un bouton à tourner. Cela va à l'encontre d'un système facile à installer et utiliser.
  3. Le fichier d'/etc se désynchronise, sur le système installé, lorsque la configuration est changée ou un paquetage ajouté. Les erreurs résultantes peuvent dérouter les utilisateurs.
  4. Le système «doit marcher». Nous ne voulons pas obliger les utilisateurs à modifier le fichier de configuration pour les paquetages, X11, /usr/local.
  5. Pensez-vous qu'il soit raisonnable d'avoir une configuration de chemins d'accès locale pour des fichiers de configurations aléatoires ? Un seul chemin d'accès peut-il s'appliquer à toutes les applications ? Que se passe-t-il si deux applications on le même fichier de configuration ? Que se passe-t-il si deux paquetages veulent chacun leur «libutil.so.1» ?

Les outils ELF sont des paquetages standardisés entretenus par des tierces parties. Ils sont constamment utilisés sur les différents systèmes et plate-formes. A long terme, la standardisation d'ELF améliore la qualité à la fois des systèmes et des applications.

Passer un système de a.out à ELF (haut)

La méthode recommandée est d'installer un instantané ELF (snapshot).
Si vous effectuez une mise à jour par les sources et que quelque chose se passe mal, votre système peut très bien ne même plus redémarrer en mode mono-utilisateur.
Pour ceux qui veulent tout de même effectuer la mise à jour par les sources : (cette méthode peut s'appliquer sur i386, sparc et toute plate-forme utilisant ld.new et gas.new)
  1. Récupérez les sources de la -current

  2. Établissez l'arborescence /emul/aout contenant les bibliothèques partagées a.out :
    mkdir -p /emul/aout/usr/lib /emul/aout/usr/X11R6/lib
    cp -p /usr/lib/*.so* /emul/aout/usr/lib
    cp -p /usr/X11R6/lib/*.so* /emul/aout/usr/X11R6/lib

  3. Mettez config(8) à jour
    cd /usr/src/usr.sbin/config && make && make install

  4. Configurez, installez et démarrez un noyau dont EXEC_ELF, EXEC_AOUT et COMPAT_AOUT sont définis.

  5. Lancez le script suivant :
    #!/bin/sh -x -e
    
    SRC=/usr/src
    
    # Si src est une mise à jour, pe : vers -current, de même que config,
    # vous pouvez recompiler make :
    ### cp /usr/bin/make /usr/bin/make.old
    ### cd $SRC/usr.bin/make && make && make install
    # par la même occasion, /bin/sh, flex, etc
    
    # variables magiques de compilation
    export DESTDIR=/../.                    # bidouille d'enfer
    export OBJECT_FMT=a.out
    export BOOTSTRAP_ELF=YESSIREE
    
    # MàJ des fichiers .mk pour les nouvelles variables
    cd $SRC/share/mk && make install
    
    # Effacer les anciens objets
    cd $SRC && make cleandir
    
    # Éventuellement utile :
    ### cd $SRC/gnu && make depend
    
    # Outils de compilation
    cd $SRC/gnu/usr.bin/binutils && make
    cd ../gas.new && make
    cd ../ld.new && make
    cd ../egcs && make
    
    # (copier ici les anciens outils a.out, au cas où)
    cd $SRC/gnu/usr.bin/binutils && make install
    cd ../gas.new && make install
    cd ../ld.new && make install
    cd ../egcs && make install
    
    # Éventuellement utile :
    ### cd $SRC/gnu/lib/libbfd && make
    
    # compilation ELF native
    export OBJECT_FMT=ELF
    
    # MàJ des fichiers inclus et bibliothèques de base
    cd $SRC && make includes
    cd $SRC/lib/csu && make && make install
    cd $SRC/lib && make && make install
    
    # Éditeur de liens dynamiques (besoin de libc_pic.a)
    cd $SRC/libexec/ld.elf_so && make && make install
    
    # fin de compilation
    cd $SRC/gnu/lib && make && make install
    cd $SRC && make && make install
    

  6. Assurez-vous d'avoir compilé et installé les nouveaux blocs de démarrage avant de redémarrer avec le noyau ELF. Les anciens blocs ne savent pas comment lancer les fichiers ELF.

Si vous devez effectuer des modifications au script ci-dessus, faites-le nous savoir en écrivant à <www@NetBSD.org>.

Comment savoir si mon système est ELF ? (haut)

Si vous tournez sur un système ELF, votre compilateur définit la variable __ELF__. Vous pouvez évidemment l'utiliser dans vos programmes C mais vous pouvez aussi utiliser le script suivant :

if echo __ELF__ | ${CC:-cc} -E - | grep -q __ELF__
then echo "Pas ELF"
else echo "Le système est ELF"
fi

Commentaires sur la FAQ ELF de NetBSD ? (haut)

La faq ELF est désormais entretenue par Christos Zoulas <christos@NetBSD.org>

Accueil
Accueil Documentation

(Nous contacter) $NetBSD: elf.html,v 1.14 2006/06/22 15:49:07 jschauma Exp $
Copyright © 1998-2003 par la Fondation NetBSD, Inc. TOUS DROITS RÉSERVÉS.