Linking dinamico vs statico

Data: 12 set 2016


Sito on line dal 2003
Home page
email
Chi sono
Translation
𝒫er spiegare il linking dobbiamo fare qualche passo indietro.

I software, sappiamo tutti, fanno uso di librerie. Queste sono collezioni di funzioni che vengono utilizzate dai vari binari che compongono una applicazione.
Ogni libreria è composta da due elementi

  1. la parte binaria (i file .so presenti in /usr/lib)
  2. l'header (i file .h presenti in /usr/include)

L'header è usato a livello di codice sorgente tramite la direttiva #include e contiene al suo interno tutte le macro ed i prototipi di funzione, ovvero la dichiarazione di una funzione con i vari parametri che essa chiede.
Tuttavia bada bene: l'header NON contiene nessuna funzione, ma solo dichiarazioni.
Ciò serve al preprocessore (cpp) affinché, quando vada a processare il sorgente per poi passare la palla al compilatore, sappia che la funzione int pippo(int a, int b) non sia una roba uscita a caso, ma una roba definita in un contesto specifico, ovvero l'header a cui facciamo riferimento.

E come fa a sapere dove si trova l'header in questione? Dalle variabili CFLAGS e CXXFLAGS (la prima per il compilatore C e la seconda per quello C++) che contengono svariate direttive "-I/path/libreria", spesso ottenute in fase di configure tramite l'uso di pkg-config.
Una volta che l'header è stato trovato e quindi le funzioni e le macro sono state definite correttamente, il compilatore può provvedere a creare il codice oggetto (.o) di ogni file del sorgente.
Tuttavia il codice oggetto non è eseguibile. Per poterlo diventare occorre far sì che quelle funzioni definite nell'header vengano messe a disposizione a livello binario.

Mi spiego meglio: l'header pippo.h che abbiamo messo nel codice sorgente contiene solo una lista di funzioni. Ma non ne contiene la logica. Ecco perché si chiamano prototipi di funzione.
Immagina un registro scolastico con la lista degli alunni. Ecco è una cosa del genere.
In sostanza tu avrai definite cose come:

int somma(int a, int b);

che vanno benissimo al preprocessore in quanto lui ha solo bisogno di sapere se somma() sia una funzione esistente, tuttavia non vanno bene al software perché questo ha bisogno della logica, ovvero di ciò che succede in somma().
Ed ecco che interviene il linker (GNU ld nel nostro caso) che va quindi a legare il codice oggetto al binario contenente la funzione definita nell'header.

Come fa a sapere dove sta? Tramite la variabile d'ambiente LDFLAGS che ha parametri tipo "-L/path/libreria -lpippo"; anche in questo caso molto spesso LDFLAGS viene "riempita" da pkg-config.

Ora che differenza c'è tra il linking statico e quello dinamico?
Il linking dinamico scrive nel codice oggetto che sta per diventare eseguibile un riferimento alla libreria che contiene la funzione. Ovvero gli dice: "ciccio, la funzione somma la devi cercare in libpippo.so", che diventa quella che tutti noi conosciamo come DIPENDENZA e che è visibile tramite l'arcinoto comando ldd.

Nel linking statico le funzioni presenti in libpippo vengono integrate direttamente nel codice oggetto che diventa binario eseguibile rendendolo indipendente dalle dipendenze. Le librerie statiche infatti sono dei meri archivi AR, che riconosci in quanto hanno l'estensione .a. Esse sono persino esplorabili tramite il comando ar e contengono tutti i codici oggetto che compongono la libreria.

Erroneamente si pensa che il linking statico sia l'integrare tutta la libreria in un software, ma non è così.
Solo il codice oggetto che contiene la funzione desiderata viene integrato, non il resto.

Il vantaggio è che tutti i binari sono indipendenti e sono CROSS-DISTRO. Una applicazione compilata e linkata staticamente su Ubuntu 10.04 32-bit può funzionare su tutte le distro Linux anche a 64-bit prive di multilib senza bisogno di nient'altro.
Non si avranno MAI problemi di runtime, come dipendenze non soddisfatte o incompatibilità binarie.
Lo svantaggio è che il software è indipendente, e quindi in caso di vulnerabilità in una libreria usata va ricompilato.

Il vantaggio del linking dinamico non esiste. Si dice che occupi meno spazio su disco ma in realtà non è vero, perché il problema dello spazio eccessivo richiesto dai software statici è in realtà imputabile a GLIBC che è volutamente incompatibile con questo linking.
Di contro però introduce ENORMI falle di sicurezza: LD_LIBRARY_PATH ed LD_PRELOAD permettono di caricare al volo librerie e funzioni in memoria, andando incontro a iniezioni di codice malevolo che va a sostituire quello buono.

Kensan.it

Per quanto riguarda un recente problema di sicurezza dovuto al linking dinamico si veda questo articolo in inglese di una società di sicurezza. Trend Micro parla di un rootkit ring 3 di nome Umbreon ovvero di un rootkit (malware con ampie capacità stealth e comandabile da remoto) che agisce al livello utente e non necessita dei diritti di root. In pratica se installato come un normale programma dall'utente diventa un malware non rilevabile. L'unica possibilità per riconoscerlo è agire tramite una live CD oppure con opportuni comandi tipo ls che facciano uso di sole librerie kernel mode ovvero di livello 0. Un ls che sia compilato con linking statico non sarebbe stato taroccato da questi rootkit ring 3.

Il rootkit di nome Umbreon sfrutta proprio le enormi falle di sicurezza dovute al linking dinamico. Anziché sfruttare le due variabili d'ambiente a runtime (LD_LIBRARY_PATH ed LD_PRELOAD), va direttamente a modificare il loader e la libc, andando così a corrompere in maniera perenne il sistema. Con un modello statico non ci sarebbero MAI stati danni di questo tipo, perché ld-linux.so non viene affatto usato e di conseguenza ogni software sarebbe stato al sicuro.

Il linking statico è DA SEMPRE mal visto dalla FSF in quanto viola palesemente la clausola di mixing di codice con differente licenza.

Come già detto quando compili staticamente un software non fai altro che unire il codice oggetto della libreria a quello del software creando un binario eseguibile completo. Ma questo vuol dire che se il codice della libreria è sotto licenza incompatibile con la LGPL tu stai creando un binario ILLEGALE in quanto girano nello stesso spazio di allocazione parti di codice non combinabili.

Diverso è con il linking dinamico che invece permette la cosa in quanto la libreria è vista come una sorta di plug-in. Tant'è che l'unica soluzione è o distribuire tutto sotto LGPL (anche il tuo software proprietario) oppure permettere agli utenti di re-linkare il software sotto differente libreria, ovvero linkarla dinamicamente.

ATTENZIONE: sto parlando di LGPL. Con la GPL non potresti nemmeno fare linking dinamico, perché non siamo in presenza di un fork.

Ma la FSF non si è limitata a parlare male del linking statico ma ha cercato di impedirlo. Come? Rendendo bloat la GLIBC, aggiungendoci simboli inutili, in modo che un software linkato staticamente sia esageratamente voluminoso anche se contiene un semplice "Hello World".
In aggiunta a questo, GLIBC è piena zeppa di estensioni non standard al linguaggio, rendendo molti software incompatibili con altri OS o libc, a meno di patch custom.
Per questo ho spesso detto che GLIBC è spazzatura e GNU è un cancro.
E le critiche a GLIBC sono arrivate da più parti, tipo da Torvalds.

Naturalmente per giustificare la cosa, per anni Ulrich Drepper (ex-sviluppatore Red Hat e sviluppatore di GLIBC) andò a dire in giro le famose stupidaggini relative alla migliore sicurezza del linking dinamico derivata dal fatto che si patcha una volta e tutti i software sono al sicuro.
Ed è per questo che oggi su Linux ci ritroviamo ancora le dipendenze a ragnatela con tutti i problemi che ne derivano: repository di terze parti che incasinano il sistema, applicazioni vecchie, impossibilità di avere una versione più recente di un software senza aggiornare la distro ecc.
Non possiamo tecnicamente uscire da questa spirale finché qualcuno non avrà le palle (permettimi il termine) di mandare GNU a quel paese e rendere Linux un SISTEMA OPERATIVO completo.
E intanto Mac OS X da 25 anni (se contiamo il suo antenato NeXTSTEP) impone il linking statico salvo rare e limitate eccezioni nei bundle senza problemi di spazio su disco o delle minchiate di sicurezza paventate da Drepper sviluppatore delle GLIBC.

articolo scritto da Samael con una mia integrazione sul virus Umbreon




Non dimenticatevi di mettere la vostra opinione: scrivete il commento, premete "Inserisci" e il commento è immediatamente pubblicato nell'area qui sotto: grazie!




Questo articolo è stato commentato 5 volte.

Ultimo commento inserito da kensan mercoledì 10 febbraio con il titolo: Consiglio.

Commento:

Scusa se ti prendo un po' di tempo. Hai consigli su che tag è bene ammettere, una lista?



Altri testi sullo stesso argomento li trovate elencati di seguito sotto l'argomento Linux

Diaspora* button
-
Facebook button
0
Twitter button
-
Google+ button
0
LinkedIn button
0
TzeTze button
voti: 0
Data: 12 set 2016
Letture di questo articolo: 8
...a partire da 2024-01-16
argomento: Linux, articoli: Linux e i Negozianti, Configurare una Internet key, PC assemblato per Linux, Passare da XP a Linux Lubuntu, Linux e i virus, Chiavetta Wi-Fi TL-WN722N, Il trucco di Linux

ball animated




Firefox: Riprenditi il web






A proposito dei giornalisti...

Non dico affatto che lei menta, dico che lei non sarebbe nel posto che occupa se non scrivesse quello che scrive.






La legge determina le condizioni in cui si esercita la libertà garantita alla donna di ricorrere all'interruzione volontaria della gravidanza.

Nuovo articolo della costituzione francese: libertà garantita
kensan logo Licenza Creative Commons 3.0
I miei testi sono sotto la Licenza "Creative Commons 3.0 Italia": se sei interessato a pubblicare i miei articoli leggi le note aggiuntive (Licenza di kensan.it) dove troverai anche le attribuzioni dei diritti per tutte le immagini pubblicate.
Questo sito memorizza sul tuo pc uno o più cookie di tipo tecnico, leggi l'informativa estesa.
Kensan site

e-mail
e-mail cifrata