102.3 Lektion 1
Zertifikat: |
LPIC-1 |
---|---|
Version: |
5.0 |
Thema: |
102 Linux-Installation und -Paketverwaltung |
Lernziel: |
102.3 Shared Libraries verwalten |
Lektion: |
1 von 1 |
Einführung
In dieser Lektion werden wir uns mit Shared Libraries beschäftigen, auch als Shared Objects bekannt: Teile von kompiliertem, wiederverwendbarem Code wie Funktionen oder Klassen, die von verschiedenen Programmen immer wieder verwendet werden.
Zunächst werden wir erklären, was geteilte Bibliotheken sind, wie man sie identifiziert und wo sie zu finden sind. Anschließend gehen wir darauf ein, wie man die entsprechenden Speicherorte konfiguriert. Abschließend zeigen wir, wie man nach Shared Librarys sucht, von denen ein bestimmtes Programm abhängt.
Konzept von Shared Libraries
Ähnlich wie ihre physischen Äquivalente sind Softwarebibliotheken Sammlungen von Code, die von vielen verschiedenen Programmen genutzt werden sollen; genauso wie in physischen Bibliotheken Bücher und andere Ressourcen für die Nutzung von vielen verschiedenen Personen aufbewahrt werden.
Um eine ausführbare Datei aus dem Quellcode eines Programms zu erstellen, sind zwei wichtige Schritte erforderlich. Erstens wandelt der Kompiler den Quellcode in Maschinencode um, der in sogenannten Objektdateien gespeichert wird. Zweitens kombiniert der Linker die Objektdateien und verlinkt diese mit Bibliotheken, um die endgültige ausführbare Datei zu erzeugen. Dieses Verknüpfen kann statisch oder dynamisch erfolgen. Je nachdem, welche Methode wir wählen, sprechen wir von Static Libraries oder, im Falle der dynamischen Verknüpfung, von Shared Libraries. Lassen Sie uns die Unterschiede genauer beleuchten.
- Static libraries
-
Eine statische Bibliothek wird zur Verknüpfungszeit mit dem Programm zusammengeführt. Eine Kopie des Bibliothekscodes wird in das Programm eingebettet und wird Teil des Programms. Somit hat das Programm zur Laufzeit keine Abhängigkeiten von der Bibliothek, da das Programm bereits den Bibliothekscode enthält. Die Unabhängigkeit von externen Bibliotheken kann als Vorteil angesehen werden, da ein Nutzer sich nicht darum kümmern muss, dass die verwendeten Bibliotheken immer zur Verfügung stehen. Der Nachteil ist, dass statisch gelinkte Programme speicherplatzintensiver sind.
- Shared (or dynamic) Libraries
-
Im Falle von Shared Libraries sorgt der Linker lediglich dafür, dass das Programm Bibliotheken korrekt referenziert. Der Linker kopiert jedoch keinen Bibliothekscode in die Programmdatei. Zur Laufzeit muss die Shared Library jedoch verfügbar sein, um die Abhängigkeiten des Programms zu erfüllen. Dies ist ein ökonomischer Ansatz für die Verwaltung von Systemressourcen, da dieser dazu beiträgt, die Größe der Programmdateien zu verringern, und nur eine Kopie der Bibliothek in den Speicher geladen wird, selbst wenn diese von mehreren Programmen verwendet wird.
Namenskonventionen für gemeinsam genutzte Objektdateien
Der Name einer gemeinsam genutzten Bibliothek, auch soname genannt, folgt einem Muster, das sich aus drei Elementen zusammensetzt:
-
Bibliotheksname (normalerweise mit dem Präfix
lib
) -
so
(was für “shared object” steht) -
Versionsnummer der Bibliothek
Hier ein Beispiel: libpthread.so.0
Im Gegensatz dazu enden statische Bibliotheksnamen auf .a
, z.B. libpthread.a
.
Note
|
Da die Dateien mit den gemeinsam genutzten Bibliotheken zum Zeitpunkt der Programmausführung verfügbar sein müssen, enthalten die meisten Linux-Systeme gemeinsam genutzte Bibliotheken. Da statische Bibliotheken nur dann in einer dedizierten Datei erforderlich sind, wenn ein Programm gelinkt wird, sind diese auf einem Endbenutzersystem möglicherweise nicht vorhanden. |
glibc
(GNU C-Bibliothek) ist ein gutes Beispiel für eine gemeinsam genutzte Bibliothek. Auf einem Debian GNU/Linux 9.9 System heißt die Datei libc.so.6
. Solche eher allgemeinen Dateinamen sind normalerweise symbolische Links, die auf die eigentliche Datei verweisen, welche zu einer Bibliothek führen, deren Name die genaue Versionsnummer enthält. Im Falle von glibc
sieht dieser symbolische Link wie folgt aus:
$ 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
Dieses Muster des Verweises auf gemeinsam genutzte Bibliotheksdateien, die nach einer bestimmten Version mit allgemeineren Dateinamen benannt sind, entspricht der gängigen Praxis.
Andere Beispiele für gemeinsam genutzte Bibliotheken sind libreadline
(die es Benutzern erlaubt, Befehlszeilen während der Eingabe zu editieren und sowohl Emacs- als auch vi
-Editiermodi unterstützt), libcrypt
(die Funktionen zur Verschlüsselung, zum Hashing und zur Kodierung enthält) oder libcurl
(eine Multiprotokollbibliothek zur Dateiübertragung).
Übliche Speicherorte für gemeinsam genutzte Bibliotheken in einem Linux-System sind:
-
/lib
-
/lib32
-
/lib64
-
/usr/lib
-
/usr/local/lib
Note
|
Das Konzept der gemeinsamen Bibliotheken ist nicht ausschließlich auf Linux beschränkt. Unter Windows werden diese beispielsweise DLL genannt, was für dynamic linked libraries steht. |
Konfiguration gemeinsam genutzter Bibliothekspfade
Die Referenzen, welche in dynamisch gelinkten Programmen enthalten sind, werden durch den dynamischen Linker (ld.so
oder ld-linux.so
) aufgelöst, wenn das Programm ausgeführt wird. Der dynamische Linker sucht in einer Reihe von Verzeichnissen nach Bibliotheken. Diese Verzeichnisse werden durch den Bibliothekspfad angegeben. Der Bibliothekspfad wird im Verzeichnis /etc
konfiguriert und zwar in der Datei /etc/ld.so.conf
. Heutzutage jedoch häufiger vorkommend auch durch Dateien, welche sich im Verzeichnis /etc/ld.so.conf.d
befinden. Normalerweise enthält Erstere nur eine einzige include
Zeile für *.conf
-Dateien mit dem entsprechendem Verzeichnisverweis:
$ cat /etc/ld.so.conf include /etc/ld.so.conf.d/*.conf
Das Verzeichnis /etc/ld.so.conf.d
enthält *.conf
Dateien:
$ ls /etc/ld.so.conf.d/ libc.conf x86_64-linux-gnu.conf
Diese *.conf
-Dateien müssen die absoluten Pfade zu den Verzeichnissen der freigegebenen Bibliothek enthalten:
$ cat /etc/ld.so.conf.d/x86_64-linux-gnu.conf # Multiarch support /lib/x86_64-linux-gnu /usr/lib/x86_64-linux-gnu
Der Befehl ldconfig
kümmert sich um das Lesen dieser Konfigurationsdateien, das Erstellen des oben erwähnten Satzes symbolischer Links, welche helfen, die einzelnen Bibliotheken zu finden, und schließlich um die Aktualisierung der Cachedatei /etc/ld.so.cache
. Daher muss ldconfig
jedes Mal ausgeführt werden, wenn Konfigurationsdateien hinzugefügt oder aktualisiert werden.
Nützliche Optionen für ldconfig
sind:
-v
,--verbose
-
Zeigt die Versionsnummern der Bibliothek, den Namen jedes Verzeichnisses und die erstellten Links an:
$ 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 (...)
So können wir zum Beispiel erkennen, wie
libfuse.so.2
mit der geteilten Objektdateilibfuse.so.2.9.7
verknüpft ist. -p
,--print-cache
-
Zeigt eine Liste der Verzeichnisse und Kandidatenbibliotheken, welche im aktuellen Cache gespeichert sind:
$ 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 (...)Beachten Sie, wie der Cache den vollständigen soname der Links verwendet:
$ sudo ldconfig -p |grep libfuse libfuse.so.2 (libc6,x86-64) => /lib/x86_64-linux-gnu/libfuse.so.2
Wenn wir /lib/x86_64-linux-gnu/libfuse.so.2
ausführlich auflisten, finden wir den Verweis auf die eigentliche geteilte Objektdatei libfuse.so.2.9.7
, die im selben Verzeichnis abgelegt ist:
$ 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
|
Da das Ausführen von |
Zusätzlich zu den oben beschriebenen Konfigurationsdateien kann die Umgebungsvariable LD_LIBRARY_PATH
verwendet werden, um temporär neue Pfade für gemeinsam genutzte Bibliotheken hinzuzufügen. Sie besteht aus einem durch Doppelpunkte getrennten (:
) Satz von Verzeichnissen, in denen nach Bibliotheken gesucht wird. Um z.B. /usr/local/mylib
zum Bibliothekspfad in der aktuellen Shellsitzung hinzuzufügen, kann folgender Befehl genutzt werden:
$ LD_LIBRARY_PATH=/usr/local/mylib
Anschließend kann der Wert wie folgt überprüfen werden:
$ echo $LD_LIBRARY_PATH /usr/local/mylib
Um /usr/local/mylib
zum Bibliothekspfad in der aktuellen Shellsitzung hinzuzufügen und ihn in alle Kindprozesse exportieren zu lassen, die von dieser Shell aus erzeugt wurden, erfordert es folgenden Befehl:
$ export LD_LIBRARY_PATH=/usr/local/mylib
Um die Umgebungsvariable LD_LIBRARY_PATH
zu entfernen, geben Sie einfach folgendes ein:
$ unset LD_LIBRARY_PATH
Um die Änderungen dauerhaft zu machen, können Sie die Zeile
export LD_LIBRARY_PATH=/usr/local/mylib
in einem von Bash’s Initialisierungsskripten wie /etc/bash.bashrc
oder ~/.bashrc
hinzufügen.
Note
|
|
Suche nach den Abhängigkeiten einer auszuführenden Datei
Um die von einem bestimmten Programm benötigten Shared Libraries nachzuschlagen, verwenden Sie den Befehl ldd
, gefolgt vom absoluten Pfad des Programms. Die Ausgabe zeigt den Pfad der Shared Library sowie die hexadezimale Speicheradresse, an der diese geladen ist:
$ 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)
Gleichermaßen verwenden wir ldd
, um nach den Abhängigkeiten eines gemeinsam genutzten Objekts zu suchen:
$ ldd /lib/x86_64-linux-gnu/libc.so.6 /lib64/ld-linux-x86-64.so.2 (0x00007fbfed578000) linux-vdso.so.1 (0x00007fffb7bf5000)
Mit der Option -u
(oder --unused
) zeigt ldd
die unbenutzten direkten Abhängigkeiten (falls diese existieren) an:
$ 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
Der Grund für nicht verwendete Abhängigkeiten hängt mit den Optionen zusammen, die der Linker beim Erstellen der Binärdatei verwendet. Obwohl das Programm keine unbenutzte Bibliothek benötigt, wurden diese dennoch gelinkt und in den Informationen über die Objektdatei als NEEDED
gekennzeichnet. Sie können dies mit Befehlen wie readelf
oder objdump
untersuchen, welche Sie folgend in den offenen Übungen verwenden werden.
Geführte Übungen
-
Teilen Sie die folgenden Namen von gemeinsam genutzten Bibliotheken in ihre Bestandteile auf:
Vollständiger Dateiname Bibliotheksname so Suffix Versionsnummer linux-vdso.so.1
libprocps.so.6
libdl.so.2
libc.so.6
libsystemd.so.0
ld-linux-x86-64.so.2
-
Sie haben eine Software entwickelt und möchten Ihrem System ein neues freigegebenes Bibliotheksverzeichnis hinzufügen (
/opt/lib/mylib
). Sie schreiben seinen absoluten Pfad in eine Datei namensmylib.conf
.-
In welchem Verzeichnis muss diese Datei ablegt werden?
-
Welchen Befehl sollten Sie ausführen, damit die Änderungen wirksam werden?
-
-
Welchen Befehl würden Sie verwenden, um die von
kill
benötigten Shared Libraries aufzulisten?
Offene Übungen
-
objdump
ist ein Befehlszeilendienstprogramm, das Informationen aus Objektdateien anzeigt. Prüfen Sie mitwhich objdump
, ob es in Ihrem System installiert ist. Wenn dies nicht der Fall ist, installieren Sie es bitte.-
Verwenden Sie
objdump
mit der Option-p
(oder--private-headers
) undgrep
, um die Abhängigkeiten vonglibc
anzuzeigen: -
Verwenden Sie
objdump
mit der Option-p
(oder--private-headers
) undgrep
, um den soname vonglibc
anzugeigen: -
Benutzen Sie
objdump
mit der Option-p
(oder--private-headers
) undgrep
, um die Abhängigkeiten von Bash anzugeigen:
-
Zusammenfassung
In dieser Lektion haben Sie gelernt:
-
Was eine gemeinsam genutzte (oder dynamische) Bibliothek ist.
-
Die Unterschiede zwischen gemeinsam genutzten und statischen Bibliotheken.
-
Die Namen der gemeinsam genutzten Bibliotheken (sonamen).
-
Die bevorzugten Speicherorte für gemeinsam genutzte Bibliotheken in einem Linux-System wie
/lib
oder/usr/lib
. -
Der Zweck des dynamischen Linkers
ld.so
(oderld-linux.so
). -
Wie man die Pfade der gemeinsam genutzten Bibliotheken mit Hilfe von Dateien in
/etc/
wield.so.conf
oder denjenigen im Verzeichnisld.so.conf.d
konfiguriert. -
Wie man gemeinsam genutzte Bibliothekspfade mit Hilfe der Umgebungsvariablen
LD_LIBRARY_PATH
konfiguriert. -
Wie man nach Abhängigkeiten zwischen ausführbaren Dateien und gemeinsam genutzten Bibliotheken sucht.
In dieser Lektion verwendete Befehle:
ls
-
Verzeichnisinhalte auflisten.
cat
-
Dateien verketten und auf der Standardausgabe ausgeben.
sudo
-
Lassen Sie den Superuser den Befehl mit administrativen Rechten ausführen.
ldconfig
-
Konfigurieren und anzeigen dynamischer Abhängigkeiten.
echo
-
Wert von Umgebungsvariablen anzeigen.
export
-
Exportieren von Werten bestimmter Umgebungsvariablen in Kindprozesse.
unset
-
Umgebungsvariable entfernen.
ldd
-
Abhängigkeiten eines Programms von gemeinsam genutzten Objekten anzeigen.
readelf
-
Informationen über ELF-Dateien anzeigen (ELF steht für executable and linkable format).
objdump
-
Informationen aus Objektdateien anzeigen.
Lösungen zu den geführten Übungen
-
Teilen Sie die folgenden Namen von gemeinsam genutzten Bibliotheken in ihre Bestandteile auf:
Vollständiger Dateiname Bibliotheksname so Suffix Versionsnummer 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
-
Sie haben eine Software entwickelt und möchten Ihrem System ein neues freigegebenes Bibliotheksverzeichnis hinzufügen (
/opt/lib/mylib
). Sie schreiben seinen absoluten Pfad in eine Datei namensmylib.conf
.-
In welchem Verzeichnis muss diese Datei ablegt werden?
/etc/ld.so.conf.d
-
Welchen Befehl sollten Sie ausführen, damit die Änderungen wirksam werden?
ldconfig
-
-
Welchen Befehl würden Sie verwenden, um die von
kill
benötigten Shared Libraries aufzuzählen?ldd /bin/kill
Lösungen zu den offenen Übungen
-
objdump
ist ein Befehlszeilendienstprogramm, das Informationen aus Objektdateien anzeigt. Prüfen Sie mitwhich objdump
, ob es in Ihrem System installiert ist. Wenn dies nicht der Fall ist, installieren Sie es bitte.-
Verwenden Sie
objdump
mit der Option-p
(oder--private-headers
) undgrep
, um die Abhängigkeiten vonglibc
anzuzeigen:objdump -p /lib/x86_64-linux-gnu/libc.so.6 | grep NEEDED
-
Verwenden Sie
objdump
mit der Option-p
(oder--private-headers
) undgrep
, um den soname vonglibc
anzugeigen:objdump -p /lib/x86_64-linux-gnu/libc.so.6 | grep SONAME
-
Benutzen Sie
objdump
mit der Option-p
(oder--private-headers
) undgrep
, um die Abhängigkeiten von Bash anzugeigen:objdump -p /bin/bash | grep NEEDED
-