102.3 Leçon 1
Certification: |
LPIC-1 |
---|---|
Version : |
5.0 |
Thème : |
102 Installer Linux et gérer les paquets |
Objectif : |
102.3 Gérer les bibliothèques partagées |
Leçon : |
1 sur 1 |
Introduction
Dans cette leçon, nous allons parler des bibliothèques partagées, également connues sous le nom d’objets partagés (shared objects) : des bouts de code compilés et réutilisables comme des fonctions ou des classes, et qui sont utilisés de manière récurrente par différents programmes.
Pour commencer, nous allons expliquer ce que sont les bibliothèques partagées, comment les identifier et où les trouver. Ensuite, nous allons voir comment configurer leurs emplacements de stockage. Enfin, nous allons montrer comment rechercher les bibliothèques partagées dont dépend un programme particulier.
Le concept des bibliothèques partagées
Tout comme leurs équivalents matériels, les bibliothèques logicielles sont des collections de code destinées à être utilisées par une multitude de programmes différents ; tout comme les bibliothèques physiques conservent des livres et d’autres ressources qui peuvent être utilisés par une foule de gens différents.
Pour construire un fichier exécutable à partir du code source d’un programme, deux étapes importantes sont nécessaires. Pour commencer, le compilateur transforme le code source en code machine qui est stocké dans ce qu’on appelle des fichiers objets. Ensuite, l’éditeur de liens (linker) combine les fichiers objets et les lie aux bibliothèques afin de générer le fichier exécutable final. Cette édition des liens peut se faire de manière statique ou dynamique. Selon la méthode choisie, nous parlerons de bibliothèques statiques ou, dans le cas d’une édition de liens dynamique, de bibliothèques partagées. Expliquons leurs différences.
- Bibliothèques statiques
-
Une bibliothèque statique est intégrée au programme au moment de la création du lien. Une copie du code de la bibliothèque est embarquée dans le programme pour en faire partie. Ainsi, le programme ne dépend pas de la bibliothèque au moment de l’exécution car il contient déjà le code de la bibliothèque. L’absence de dépendances peut être considérée comme un avantage, étant donné que vous n’avez pas à vous soucier de la disponibilité des bibliothèques utilisées. L’inconvénient, c’est que les programmes liés statiquement sont plus lourds.
- Bibliothèques partagées (ou dynamiques)
-
Dans le cas des bibliothèques partagées, l’éditeur de liens veille simplement à ce que le programme référence correctement les bibliothèques. En revanche, l’éditeur de liens ne copie aucun code de la bibliothèque dans le fichier du programme. Au moment de l’exécution, la bibliothèque partagée doit cependant être disponible pour satisfaire les dépendances du programme. C’est donc une approche économique de la gestion des ressources du système qui permet de réduire la taille des fichiers des programmes en ne chargeant qu’une seule copie de la bibliothèque en mémoire, même si elle est utilisée par plusieurs programmes.
Conventions de nommage des fichiers objets partagés
Le nom d’une bibliothèque partagée (soname) respecte un schéma composé de trois éléments :
-
Nom de la bibliothèque (normalement préfixé par
lib
) -
so
(qui signifie “shared object”) -
Numéro de version de la bibliothèque
Voici un exemple : libpthread.so.0
En comparaison, les noms des bibliothèques statiques se terminent en .a
, par exemple libpthread.a
.
Note
|
Comme les fichiers contenant les bibliothèques partagées doivent être disponibles lorsque le programme est exécuté, la plupart des systèmes Linux contiennent des bibliothèques partagées. Puisque les bibliothèques statiques ne sont requises dans un fichier dédié que lorsqu’un programme est lié, elles peuvent ne pas être présentes sur un système d’utilisateur final. |
La glibc
(GNU C library) est un bon exemple de bibliothèque partagée. Sur un système Debian GNU/Linux 9.9, son fichier est nommé libc.so.6
. Ces noms de fichiers plutôt génériques sont normalement des liens symboliques qui pointent vers le fichier réel contenant une bibliothèque, dont le nom contient le numéro de version exact. Dans le cas de la glibc
, ce lien symbolique ressemble à ceci :
$ ls -l /lib/x86_64-linux-gnu/libc.so.6 lrwxrwxrwx 1 root root 12 feb 6 22:17 /lib/x86_64-linux-gnu/libc.so.6 -> libc-2.24.so
Cette façon de référencer les fichiers de bibliothèques partagées nommés selon une version spécifique par des noms de fichiers plus généraux constitue une pratique courante.
D’autres exemples de bibliothèques partagées comprennent libreadline
(qui permet aux utilisateurs de modifier les lignes de commande au fur et à mesure qu’elles sont tapées et inclut le support des modes d’édition Emacs et vi), libcrypt
(qui contient des fonctions liées au chiffrement, au hachage et à l’encodage), ou libcurl
(qui est une bibliothèque de transfert de fichiers multiprotocole).
Voici les emplacements habituels des bibliothèques partagées dans un système Linux :
-
/lib
-
/lib32
-
/lib64
-
/usr/lib
-
/usr/local/lib
Note
|
Le concept des bibliothèques partagées n’est pas spécifique à Linux. Sous Windows, par exemple, elles sont appelées DLL, ce qui signifie Dynamic Link Library (bibliothèque de liens dynamiques). |
Configuration des chemins de bibliothèques partagées
Les références contenues dans les programmes liés dynamiquement sont résolues par le chargeur de liens dynamiques (ld.so
ou ld-linux.so
) lorsque le programme est exécuté. Le chargeur de liens dynamiques recherche les bibliothèques dans une série de répertoires. Ces répertoires sont spécifiés par le chemin des bibliothèques. Le chemin des bibliothèques est configuré dans le répertoire /etc
, à savoir dans le fichier /etc/ld.so.conf
et, plus couramment de nos jours, dans les fichiers qui se trouvent dans le répertoire /etc/ld.so.conf.d
. Normalement, le premier ne comprend qu’une seule ligne include
pour les fichiers *.conf
dans le second :
$ cat /etc/ld.so.conf include /etc/ld.so.conf.d/*.conf
Le répertoire /etc/ld.so.conf.d
contient des fichiers *.conf
:
$ ls /etc/ld.so.conf.d/ libc.conf x86_64-linux-gnu.conf
Ces fichiers *.conf
doivent inclure les chemins absolus vers les répertoires des bibliothèques partagées :
$ cat /etc/ld.so.conf.d/x86_64-linux-gnu.conf # Multiarch support /lib/x86_64-linux-gnu /usr/lib/x86_64-linux-gnu
La commande ldconfig
se charge de lire ces fichiers de configuration, de créer l’ensemble des liens symboliques ci-dessus qui aident à localiser les différentes bibliothèques et enfin de mettre à jour le fichier cache /etc/ld.so.cache
. Ainsi, ldconfig
doit être exécuté chaque fois que des fichiers de configuration sont ajoutés ou mis à jour.
Voici quelques options utiles pour ldconfig
:
-v
,--verbose
-
Afficher les numéros de version des bibliothèques, le nom de chaque répertoire et les liens qui sont créés :
$ sudo ldconfig -v /usr/local/lib: /lib/x86_64-linux-gnu: libnss_myhostname.so.2 -> libnss_myhostname.so.2 libfuse.so.2 -> libfuse.so.2.9.7 libidn.so.11 -> libidn.so.11.6.16 libnss_mdns4.so.2 -> libnss_mdns4.so.2 libparted.so.2 -> libparted.so.2.0.1 (...)
Nous voyons donc, par exemple, comment
libfuse.so.2
est lié au fichier d’objets partagés effectiflibfuse.so.2.9.7
. -p
,--print-cache
-
Afficher les listes de répertoires et de bibliothèques candidates stockées dans le cache actuel :
$ sudo ldconfig -p 1094 libs found in the cache `/etc/ld.so.cache' libzvbi.so.0 (libc6,x86-64) => /usr/lib/x86_64-linux-gnu/libzvbi.so.0 libzvbi-chains.so.0 (libc6,x86-64) => /usr/lib/x86_64-linux-gnu/libzvbi-chains.so.0 libzmq.so.5 (libc6,x86-64) => /usr/lib/x86_64-linux-gnu/libzmq.so.5 libzeitgeist-2.0.so.0 (libc6,x86-64) => /usr/lib/x86_64-linux-gnu/libzeitgeist-2.0.so.0 (...)
Notez comment le cache utilise le soname pleinement qualifié des liens :
$ sudo ldconfig -p |grep libfuse libfuse.so.2 (libc6,x86-64) => /lib/x86_64-linux-gnu/libfuse.so.2
Si nous faisons un listing détaillé de /lib/x86_64-linux-gnu/libfuse.so.2
, nous voyons la référence au fichier d’objet partagé réel libfuse.so.2.9.7
stocké dans le même répertoire :
$ ls -l /lib/x86_64-linux-gnu/libfuse.so.2 lrwxrwxrwx 1 root root 16 Aug 21 2018 /lib/x86_64-linux-gnu/libfuse.so.2 -> libfuse.so.2.9.7
Note
|
Puisqu’il faut un accès en écriture au cache |
En complément des fichiers de configuration décrits ci-dessus, la variable d’environnement LD_LIBRARY_PATH
peut être utilisée pour ajouter temporairement de nouveaux chemins pour les bibliothèques partagées. Elle est constituée d’un ensemble de répertoires séparés par deux points (:
) où les bibliothèques sont recherchées. Par exemple, pour ajouter /usr/local/mylib
au chemin des bibliothèques dans la session shell courante, vous pouvez taper :
$ LD_LIBRARY_PATH=/usr/local/mylib
Vous pouvez maintenant vérifier sa valeur :
$ echo $LD_LIBRARY_PATH /usr/local/mylib
Pour ajouter /usr/local/mylib
au chemin des bibliothèques dans la session shell actuelle en l’exportant vers tous les processus enfants créés à partir de ce shell, vous devez taper :
$ export LD_LIBRARY_PATH=/usr/local/mylib
Pour supprimer la variable d’environnement LD_LIBRARY_PATH
, il suffit de taper :
$ unset LD_LIBRARY_PATH
Pour rendre les changements permanents, vous pouvez écrire la ligne
export LD_LIBRARY_PATH=/usr/local/mylib
dans un des scripts d’initialisation de Bash tels que /etc/bash.bashrc
ou ~/.bashrc
.
Note
|
|
Chercher les dépendances d’un exécutable donné
Pour rechercher les bibliothèques partagées requises par un programme spécifique, utilisez la commande ldd
suivie du chemin absolu vers le programme. Le résultat indique le chemin du fichier de la bibliothèque partagée ainsi que l’adresse mémoire hexadécimale à laquelle il est chargé :
$ ldd /usr/bin/git linux-vdso.so.1 => (0x00007ffcbb310000) libpcre.so.3 => /lib/x86_64-linux-gnu/libpcre.so.3 (0x00007f18241eb000) libz.so.1 => /lib/x86_64-linux-gnu/libz.so.1 (0x00007f1823fd1000) libresolv.so.2 => /lib/x86_64-linux-gnu/libresolv.so.2 (0x00007f1823db6000) libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f1823b99000) librt.so.1 => /lib/x86_64-linux-gnu/librt.so.1 (0x00007f1823991000) libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f18235c7000) /lib64/ld-linux-x86-64.so.2 (0x00007f182445b000)
De même, nous utilisons ldd
pour rechercher les dépendances d’un objet partagé :
$ ldd /lib/x86_64-linux-gnu/libc.so.6 /lib64/ld-linux-x86-64.so.2 (0x00007fbfed578000) linux-vdso.so.1 (0x00007fffb7bf5000)
Avec l’option -u
(ou --unused
), ldd
affiche les dépendances directes inutilisées (si elles existent) :
$ ldd -u /usr/bin/git Unused direct dependencies: /lib/x86_64-linux-gnu/libz.so.1 /lib/x86_64-linux-gnu/libpthread.so.0 /lib/x86_64-linux-gnu/librt.so.1
La présence de dépendances inutilisées est liée aux options utilisées par l’éditeur de liens lors de la construction du binaire. Même si le programme n’a pas besoin d’une bibliothèque inutilisée, il a quand même été lié et étiqueté comme NEEDED
(requis) dans les informations sur le fichier objet. Vous pouvez explorer ce sujet en utilisant des commandes comme readelf
ou objdump
, que vous utiliserez bientôt dans l’exercice d’approfondissement.
Exercices guidés
-
Séparez les noms des bibliothèques partagées suivantes en leurs composantes :
Nom complet du fichier Nom de la bibliothèque suffixe so Numéro de version linux-vdso.so.1
libprocps.so.6
libdl.so.2
libc.so.6
libsystemd.so.0
ld-linux-x86-64.so.2
-
Vous avez développé un logiciel et vous souhaitez ajouter un nouveau répertoire de bibliothèques partagées à votre système (
/opt/lib/mylib
). Vous écrivez son chemin absolu dans un fichier appelémylib.conf
.-
Dans quel répertoire devez-vous ranger ce fichier ?
-
Quelle commande devez-vous exécuter pour que les changements soient pleinement pris en compte ?
-
-
Quelle commande utiliseriez-vous pour recenser les bibliothèques partagées requises par
kill
?
Exercices d’approfondissement
-
objdump
est un outil en ligne de commande qui affiche les informations relatives aux fichiers objets. Vérifiez s’il est installé sur votre système avecwhich objdump
. Si ce n’est pas le cas, veuillez l’installer.-
Utilisez
objdump
avec l’optionp
(ou--private-headers
) etgrep
pour afficher les dépendances deglibc
: -
Utilisez
objdump
avec l’optionp
(ou--private-headers
) etgrep
pour afficher le soname deglibc
: -
Utilisez
objdump
avec l’optionp
(ou--private-headers
) etgrep
pour afficher les dépendances de Bash :
-
Résumé
Dans cette leçon, nous avons appris :
-
Qu’est-ce qu’une bibliothèque partagée (ou dynamique).
-
Les différences entre les bibliothèques partagées et les bibliothèques statiques.
-
Les noms des bibliothèques partagées (sonames).
-
Les emplacements préférés pour les bibliothèques partagées dans un système Linux comme
/lib
ou/usr/lib
. -
La fonction de l’éditeur de liens dynamiques
ld.so
(ould-linux.so
). -
Comment configurer les chemins des bibliothèques partagées par le biais de fichiers dans
/etc/
commeld.so.conf
ou ceux dans le répertoireld.so.conf.d
. -
Comment configurer les chemins des bibliothèques partagées au moyen de la variable d’environnement
LD_LIBRARY_PATH
. -
Comment rechercher les dépendances des exécutables et des bibliothèques partagées.
Les commandes suivantes ont été abordées dans cette leçon :
ls
-
Afficher le contenu d’un répertoire.
cat
-
Concaténer des fichiers et afficher sur la sortie standard.
sudo
-
Faire exécuter une commande par le super-utilisateur avec les privilèges de l’administrateur.
ldconfig
-
Configurer les dépendances d’exécution de l’éditeur de liens.
echo
-
Afficher la valeur d’une variable d’environnement.
export
-
Exporter la valeur d’une variable d’environnement vers les shells enfants.
unset
-
Supprimer une variable d’environnement.
ldd
-
Afficher les dépendances en objets partagés d’un programme.
readelf
-
Afficher les informations sur les fichiers ELF (ELF signifie executable and linkable format).
objdump
-
Afficher les informations des fichiers objets.
Réponses aux exercices guidés
-
Séparez les noms des bibliothèques partagées suivantes en leurs composantes :
Nom complet du fichier Nom de la bibliothèque suffixe so Numéro de version linux-vdso.so.1
linux-vdso
so
1
libprocps.so.6
libprocps
so
6
libdl.so.2
libdl
so
2
libc.so.6
libc
so
6
libsystemd.so.0
libsystemd
so
0
ld-linux-x86-64.so.2
ld-linux-x86-64
so
2
-
Vous avez développé un logiciel et vous souhaitez ajouter un nouveau répertoire de bibliothèques partagées à votre système (
/opt/lib/mylib
). Vous écrivez son chemin absolu dans un fichier appelémylib.conf
.-
Dans quel répertoire devez-vous ranger ce fichier ?
/etc/ld.so.conf.d
-
Quelle commande devez-vous exécuter pour que les changements soient pleinement pris en compte ?
ldconfig
-
-
Quelle commande utiliseriez-vous pour recenser les bibliothèques partagées requises par
kill
?ldd /bin/kill
Réponses aux exercices d’approfondissement
-
objdump
est un outil en ligne de commande qui affiche les informations relatives aux fichiers objets. Vérifiez s’il est installé sur votre système avecwhich objdump
. Si ce n’est pas le cas, veuillez l’installer.-
Utilisez
objdump
avec l’optionp
(ou--private-headers
) etgrep
pour afficher les dépendances deglibc
:objdump -p /lib/x86_64-linux-gnu/libc.so.6 | grep NEEDED
-
Utilisez
objdump
avec l’optionp
(ou--private-headers
) etgrep
pour afficher le soname deglibc
:objdump -p /lib/x86_64-linux-gnu/libc.so.6 | grep SONAME
-
Utilisez
objdump
avec l’optionp
(ou--private-headers
) etgrep
pour afficher les dépendances de Bash :objdump -p /bin/bash | grep NEEDED
-