102.3 Lezione 1
Certificazione: |
LPIC-1 |
---|---|
Versione: |
5.0 |
Argomento: |
102 L’Installazione di Linux e la Gestione Pacchetti |
Obiettivo: |
102.3 Gestire le Librerie Condivise |
Lezione: |
1 di 1 |
Introduzione
In questa lezione discuteremo di librerie condivise, anche conosciute come oggetti condivisi: sequenze di codice compilato e riutilizzabile come funzioni o classi, che vengono utilizzati di frequente da vari programmi.
Per iniziare, spiegheremo cosa sono le librerie condivise, come identificarle e dove si trovano. Successivamente, esamineremo come configurare le loro posizioni di archiviazione; infine, mostreremo come cercare le librerie condivise da cui dipende un determinato programma.
Le Librerie Condivise
Similmente alle loro controparti fisiche, le librerie di software sono raccolte di codice che possono essere utilizzate da molti programmi diversi; così come, nel mondo reale, le biblioteche mantengono libri e altre risorse che possono essere utilizzate da molte persone diverse.
Per creare un file eseguibile dal codice sorgente di un programma, è necessario eseguire due passaggi importanti. Innanzitutto, il compilatore che trasforma il codice sorgente in codice macchina generando i cosiddetti file oggetto. In secondo luogo, il linker che combina i vari file oggetto e li collega alle librerie per generare il file eseguibile finale. Questo collegamento può essere eseguito in maniera statica o dinamica. A seconda del metodo scelto, parleremo di librerie statiche o, in caso di collegamento dinamico, di librerie condivise. Spieghiamone le differenze.
- Librerie Statiche
-
Una libreria statica viene unita al programma al momento del collegamento. Una copia del codice della libreria è incorporata nel programma e ne diventa parte. Pertanto, il programma non ha dipendenze dalla libreria in fase di esecuzione perché il programma contiene già il codice delle librerie. Non avere dipendenze può essere visto come un vantaggio poiché non ci si deve preoccupare che le librerie utilizzate siano sempre disponibili. L’aspetto negativo è che i programmi collegati staticamente sono più pesanti.
- Librerie condivise (o dinamiche)
-
Nel caso di librerie condivise, il linker si occupa semplicemente che il programma faccia riferimento correttamente alle librerie. Il linker, tuttavia, non copia alcun codice di libreria nel file di programma. In fase di esecuzione, tuttavia, la libreria condivisa deve essere disponibile per soddisfare le dipendenze del programma. Questo è un approccio economico alla gestione delle risorse di sistema in quanto aiuta a ridurre le dimensioni dei file di programma e solo una copia della libreria viene caricata in memoria, anche quando viene utilizzata da più programmi.
Convenzioni di Denominazione dei File Oggetto Condivisi
Il nome di una libreria condivisa, noto anche come soname, segue uno schema composto da tre elementi:
-
Nome della libreria (normalmente preceduto da
lib
) -
so
(che sta per “oggetto condiviso”) -
Numero di versione della libreria
Ecco un esempio: libpthread.so.0
Al contrario, i nomi delle librerie statiche terminano in .a
, ad es. libpthread.a
.
Note
|
Poiché i file contenenti librerie condivise devono essere disponibili quando viene eseguito il programma, la maggior parte dei sistemi Linux contiene librerie condivise. Al contrario le librerie statiche sono invece richieste in un file dedicato solo quando un programma è collegato a essa, quindi, data la loro scarsa diffusione, potrebbero non essere presenti sul sistema dell’utente finale. |
glibc
(libreria GNU C) è un buon esempio di libreria condivisa. Su un sistema Debian GNU/Linux 9.9, il suo file è chiamato libc.so.6
. Tali nomi di file piuttosto generici sono normalmente collegamenti simbolici che puntano al file effettivo contenente una libreria, il cui nome contiene il numero esatto di versione. Nel caso di glibc
, questo collegamento simbolico è simile al seguente:
$ 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
Questo modo di riferirsi ai file di libreria condivisa con nomi di file più generali è una pratica piuttosto comune.
Altri esempi di librerie condivise includono libreadline
(che consente agli utenti di modificare le righe di comando durante la digitazione e include il supporto per entrambe le modalità di modifica di Emacs e vi), libcrypt
(che contiene funzioni relative a crittografia, hash e codifica) , o libcurl
(che è una libreria di trasferimento file multiprotocollo).
Le posizioni comuni per le librerie condivise in un sistema Linux sono:
-
/lib
-
/lib32
-
/lib64
-
/usr/lib
-
/usr/local/lib
Note
|
Il concetto di librerie condivise non è esclusivo di Linux. In Windows, per esempio, sono chiamate DLL, che significa dynamic linked libraries. |
Configurazione dei Percorsi delle Librerie Condivise
I riferimenti alle librerie collegate dinamicamente vengono risolti dal linker dinamico (ld.so
o ld-linux.so
) quando il programma viene eseguito. Il linker dinamico cerca le librerie in una serie di directory. Queste directory sono specificate dal library path. Il percorso della libreria è configurato nella directory /etc
, vale a dire nel file /etc/ld.so.conf
e a oggi più comunemente nei file che risiedono nella directory /etc/ld.so.conf.d
. Normalmente, il file include solo una singola riga include
per i file * .conf
che verranno a trovarsi nella directory precedentemente indicata:
$ cat /etc/ld.so.conf include /etc/ld.so.conf.d/*.conf
La directory /etc/ld.so.conf.d
contiene diversi file *.conf
:
$ ls /etc/ld.so.conf.d/ libc.conf x86_64-linux-gnu.conf
Questi file * .conf
hanno al loro interno i percorsi assoluti delle directory che contengono le librerie condivise:
$ cat /etc/ld.so.conf.d/x86_64-linux-gnu.conf # Multiarch support /lib/x86_64-linux-gnu /usr/lib/x86_64-linux-gnu
Il comando ldconfig
si occupa della lettura di questi file di configurazione, creando i collegamenti simbolici, precedentemente descritti, che aiutano a localizzare le singole librerie effettuando infine l’aggiornamento del file di cache /etc/ld.so.cache
. Pertanto, ldconfig
deve essere eseguito ogni volta che vengono aggiunti o aggiornati i file di configurazione.
Opzioni utili per ldconfig
sono:
-v
,--verbose
-
Visualizza le attività in dettaglio svolte dal comando durante la sua esecuzione:
$ 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 (...)
Quindi come possiamo vedere per esempio,
libfuse.so.2
è collegato all’oggetto file condivisolibfuse.so.2.9.7
. -p
,--print-cache
-
Stampa gli elenchi di directory e librerie archiviati nella cache corrente:
$ 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 (...)
Nota come la cache utilizza il soname completo dei collegamenti:
$ sudo ldconfig -p |grep libfuse libfuse.so.2 (libc6,x86-64) => /lib/x86_64-linux-gnu/libfuse.so.2
Se visualizziamo in formato long /lib/x86_64-linux-gnu/libfuse.so.2
, troveremo il riferimento all’effettivo file oggetto condiviso libfuse.so.2.9.7
che è memorizzato nella stessa directory:
$ 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
|
Dato che è richiesto l’accesso in scrittura al file |
Oltre ai file di configurazione sopra descritti, la variabile d’ambiente LD_LIBRARY_PATH
può essere usata per aggiungere temporaneamente nuovi percorsi per librerie condivise. È costituito da una serie di directory separate da due punti (:
) in cui vengono cercate le librerie. Per aggiungere, per esempio, /usr/local/mylib
al percorso delle librerie nella sessione di shell corrente, è possibile digitare:
$ LD_LIBRARY_PATH=/usr/local/mylib
Ora possiamo verificarne il valore:
$ echo $LD_LIBRARY_PATH /usr/local/mylib
Per aggiungere /usr/local/mylib
al percorso delle librerie condivise nella sessione di shell corrente e farlo esportare in tutti i processi figlio generati da quella shell, si dovrebbe digitare:
$ export LD_LIBRARY_PATH=/usr/local/mylib
Per rimuovere la variabile d’ambiente LD_LIBRARY_PATH
, basta digitare:
$ unset LD_LIBRARY_PATH
Per rendere permanenti le modifiche, è possibile scrivere la riga
export LD_LIBRARY_PATH=/usr/local/mylib
in uno degli script di inizializzazione di Bash come /etc/bash.bashrc
o ~/.bashrc
.
Note
|
|
Ricerca delle Dipendenze di un Eseguibile Specifico
Per cercare le librerie condivise richieste da un programma specifico, usare il comando ldd
seguito dal percorso assoluto del programma. L’output mostra il percorso del file della libreria condivisa e l’indirizzo di memoria esadecimale in cui è caricato:
$ 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)
Allo stesso modo, usiamo ldd
per cercare le dipendenze di un oggetto condiviso:
$ ldd /lib/x86_64-linux-gnu/libc.so.6 /lib64/ld-linux-x86-64.so.2 (0x00007fbfed578000) linux-vdso.so.1 (0x00007fffb7bf5000)
Con l’opzione -u
(o --unused
) ldd
visualizza le dipendenze dirette inutilizzate (se presenti):
$ 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
Il motivo delle dipendenze non utilizzate è correlato alle opzioni utilizzate dal linker durante la creazione del file binario. Sebbene il programma non abbia bisogno di una libreria inutilizzata, è stato comunque collegato ed etichettato come "NECESSARIO" nelle informazioni sul file oggetto. È possibile verificarne la presenza usando comandi readelf
o objdump
, che verranno mostrati negli esercizi esplorativi.
Esercizi Guidati
-
Dividere i seguenti nomi di libreria condivisa nelle loro parti:
Nome completo del file Nome della libreria Suffisso so Numero della versione linux-vdso.so.1
libprocps.so.6
libdl.so.2
libc.so.6
libsystemd.so.0
ld-linux-x86-64.so.2
-
È stato sviluppato un software e si vuole aggiungere una nuova directory di libreria condivisa al sistema (
/opt/lib/mylib
). Scrivere il suo percorso assoluto in un file chiamatomylib.conf
.-
In quale directory si deve inserire questo file?
-
Quale comando si deve eseguire per rendere le modifiche pienamente operative?
-
-
Quale comando si utilizza per elencare le librerie condivise richieste dal comando
kill
?
Esercizi Esplorativi
-
objdump
è un’utilità della riga di comando che visualizza le informazioni dai file oggetto. Controlla se è installato nel tuo sistema conwhich objdump
. In caso contrario, installalo.-
Utilizza
objdump
con l’opzione-p
(o--private-headers
) egrep
per visualizzare le dipendenze diglibc
: -
Utilizza
objdump
con l’opzione-p
(o--private-headers
) e` grep` per stampare il soname diglibc
: -
Usa
objdump
con l’opzione-p
(o--private-headers
) egrep
per stampare le dipendenze di Bash:
-
Sommario
In questa lezione abbiamo imparato:
-
Che cos’è una libreria condivisa (o dinamica).
-
Le differenze tra librerie condivise e statiche.
-
I nomi delle librerie condivise (sonames).
-
Le posizioni predefinite per le librerie condivise in un sistema Linux come
/lib
o/usr/lib
. -
Lo scopo del linker dinamico
ld.so
(old-linux.so
). -
Come configurare i percorsi delle librerie condivise tramite i file
/etc/ld.so.conf
o quelli nella directoryld.so.conf.d
. -
Come configurare i percorsi delle librerie condivise mediante la variabile d’ambiente
LD_LIBRARY_PATH
. -
Come cercare le dipendenze di libreria per eseguibili e oggetti condivisi.
Commandi utilizzati in questa lezione:
ls
-
Elenca i contenuti della directory.
cat
-
Concatena i file e visualiza sullo standard output.
sudo
-
Consente a un utente autorizzato di eseguire un comando con privilegi amministrativi.
ldconfig
-
Configura i collegamenti di runtime del linker dinamico.
echo
-
Visualizza il valore di una variabile d’ambiente.
export
-
Esporta il valore di una variabile d’ambiente in shell figlie.
unset
-
Rimuove variabile d’ambiente.
ldd
-
Visualizza le dipendenze di un programma.
readelf
-
Visualizza informazioni sui file ELF (ELF sta per executable and linkable format).
objdump
-
Visualizza le informazioni dei file oggetto.
Risposte agli Esercizi Guidati
-
Dividere i seguenti nomi di libreria condivisa nelle loro parti:
Nome completo del file Nome della libreria Suffisso so Numero della versione 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
-
È stato sviluppato un software e si vuole aggiungere una nuova directory di libreria condivisa al sistema (
/opt/lib/mylib
). Scrivere il suo percorso assoluto in un file chiamatomylib.conf
.-
In quale directory si deve inserire questo file?
/etc/ld.so.conf.d
-
Quale comando si deve eseguire per rendere le modifiche pienamente operative?
ldconfig
-
-
Quale comando si utilizza per elencare le librerie condivise richieste dal comando
kill
?ldd /bin/kill
Risposte agli Esercizi Esplorativi
-
objdump
è un’utilità della riga di comando che visualizza le informazioni dai file oggetto. Controlla se è installato nel tuo sistema conwhich objdump
. In caso contrario, installalo.-
Utilizza
objdump
con l’opzione-p
(o--private-headers
) e` grep` per stampare il soname diglibc
:objdump -p /lib/x86_64-linux-gnu/libc.so.6 | grep NEEDED
-
Utilizza
objdump
con l’opzione-p
(o--private-headers
) e` grep` per stampare il soname diglibc
:objdump -p /lib/x86_64-linux-gnu/libc.so.6 | grep SONAME
-
Usa
objdump
con l’opzione-p
(o--private-headers
) egrep
per stampare le dipendenze di Bash:objdump -p /bin/bash | grep NEEDED
-