Più librerie di glibc su un singolo host

Più librerie di glibc su un singolo host

Il mio server linux (SLES-8) ha attualmente glibc-2.2.5-235, ma ho un programma che non funzionerà su questa versione e richiede glibc-2.3.3.

È ansible avere più glibc installati nello stesso host?

Questo è l’errore che ottengo quando eseguo il mio programma sul vecchio glibc:

./myapp: /lib/i686/libc.so.6: version `GLIBC_2.3' not found (required by ./myapp) ./myapp: /lib/i686/libpthread.so.0: version `GLIBC_2.3.2' not found (required by ./myapp) ./myapp: /lib/i686/libc.so.6: version `GLIBC_2.3' not found (required by ./libxerces-c.so.27) ./myapp: /lib/ld-linux.so.2: version `GLIBC_2.3' not found (required by ./libstdc++.so.6) ./myapp: /lib/i686/libc.so.6: version `GLIBC_2.3' not found (required by ./libstdc++.so.6) 

Così ho creato una nuova directory chiamata newglibc e ho copiato i seguenti file in:

 libpthread.so.0 libm.so.6 libc.so.6 ld-2.3.3.so ld-linux.so.2 -> ld-2.3.3.so 

e

 export LD_LIBRARY_PATH=newglibc:$LD_LIBRARY_PATH 

Ma ottengo un errore:

 ./myapp: /lib/ld-linux.so.2: version `GLIBC_PRIVATE' not found (required by ./newglibc/libpthread.so.0) ./myapp: /lib/ld-linux.so.2: version `GLIBC_2.3' not found (required by libstdc++.so.6) ./myapp: /lib/ld-linux.so.2: version `GLIBC_PRIVATE' not found (required by ./newglibc/libm.so.6) ./myapp: /lib/ld-linux.so.2: version `GLIBC_2.3' not found (required by ./newglibc/libc.so.6) ./myapp: /lib/ld-linux.so.2: version `GLIBC_PRIVATE' not found (required by ./newglibc/libc.so.6) 

Quindi sembra che stiano ancora collegando a / lib e non raccogliendo da dove li ho messi?

Grazie

È molto ansible avere più versioni di glibc sullo stesso sistema (lo facciamo ogni giorno).

Tuttavia, è necessario sapere che glibc consiste di molti pezzi (oltre 200 librerie condivise) che devono essere tutti uguali. Uno dei pezzi è ld-linux.so.2, e deve corrispondere a libc.so.6, altrimenti vedrai gli errori che stai vedendo.

Il percorso assoluto per ld-linux.so.2 è hard-coded nell’eseguibile al momento del collegamento e non può essere facilmente modificato dopo il collegamento.

Per creare un eseguibile che funzioni con il nuovo glibc, fai questo:

 g++ main.o -o myapp ... \ -Wl,--rpath=/path/to/newglibc \ -Wl,--dynamic-linker=/path/to/newglibc/ld-linux.so.2 

L’opzione -rpath linker farà in modo che il loader runtime cerchi le librerie in /path/to/newglibc (quindi non dovrai impostare LD_LIBRARY_PATH prima di eseguirlo), e l’opzione -dynamic-linker eseguirà il percorso “bake” per correggere ld-linux.so.2 nell’applicazione.

Se non riesci a ricolbind l’applicazione myapp (ad esempio perché è un binario di terze parti), non tutto è perduto, ma diventa più complicato. Una soluzione è impostare un ambiente di chroot adeguato per questo. Un’altra possibilità è usare rtldi e un editor binario .

Usa LD_PRELOAD: metti la tua libreria da qualche parte fuori dalle directory man lib ed esegui:

 LD_PRELOAD='mylibc.so anotherlib.so' program 

Vedi: l’articolo di Wikipedia

Questa domanda è vecchia, le altre risposte sono vecchie. “La risposta del russo impiegato è molto buona e informativa, ma funziona solo se hai il codice sorgente. Se non lo fai, le alternative allora erano molto difficili. Per fortuna al giorno d’oggi abbiamo una soluzione semplice a questo problema (come commentato in una delle sue risposte), usando patchelf . Tutto quello che devi fare è:

 $ ./patchelf --set-interpreter /path/to/newglibc/ld-linux.so.2 --set-rpath /path/to/newglibc/ myapp 

E dopo, puoi semplicemente eseguire il tuo file:

 $ ./myapp 

Non c’è bisogno di chroot o modificare manualmente i binari, per fortuna. Ma ricorda di eseguire il backup del tuo file binario prima di applicarlo, se non sei sicuro di quello che stai facendo, perché modifica il tuo file binario. Dopo averlo applicato, non è ansible ripristinare il vecchio percorso all’interpreter / rpath. Se non funziona, dovrai continuare a ripararlo fino a trovare il percorso che funzionerà effettivamente … Beh, non deve essere un processo per tentativi ed errori. Ad esempio, nell’esempio di OP, aveva bisogno di GLIBC_2.3 , così puoi facilmente trovare quale lib fornisce quella versione usando le strings :

 $ strings /lib/i686/libc.so.6 | grep GLIBC_2.3 $ strings /path/to/newglib/libc.so.6 | grep GLIBC_2.3 

In teoria, il primo grep verrebbe vuoto perché la libc di sistema non ha la versione che vuole, e la seconda dovrebbe generare GLIBC_2.3 perché ha la versione che usa myapp , quindi sappiamo che possiamo patchelf nostro binario usando quello sentiero.

Quando si tenta di eseguire un binario in linux, il binario tenta di caricare il linker, quindi le librerie e dovrebbero essere tutti nel percorso e / o nel posto giusto. Se il tuo problema è con il linker e vuoi scoprire quale percorso sta cercando il tuo binario, puoi scoprire con questo comando:

 $ readelf -l myapp | grep interpreter [Requesting program interpreter: /lib/ld-linux.so.2] 

Se il tuo problema è con la lib, i comandi che ti daranno le librerie libere usate sono:

 $ readelf -d myapp | grep Shared $ ldd myapp 

Questo elencherà le librerie che il tuo binario ha bisogno, ma probabilmente conosci già quelle problematiche, poiché stanno già producendo errori come nel caso dell’OP.

“patchelf” funziona per molti diversi problemi che potresti incontrare durante il tentativo di eseguire un programma, relativo a questi 2 problemi. Ad esempio, se si ottiene: ELF file OS ABI invalid , potrebbe essere risolto impostando un nuovo loader (la parte --set-interpreter del comando) come spiegato qui . Un altro esempio è relativo al problema di ottenere No such file or directory quando si esegue un file che è lì ed eseguibile, come esemplificato qui . In quel caso particolare, OP mancava un link al loader, ma forse nel tuo caso non hai accesso root e non puoi creare il link. Impostare un nuovo interprete risolverebbe il tuo problema.

Grazie impiegato russo e Michael Pankov per l’intuizione e la soluzione!

Puoi prendere in considerazione l’utilizzo di Nix http://nixos.org/nix/ ?

Nix supporta la gestione dei pacchetti per più utenti: più utenti possono condividere in modo sicuro un archivio Nix comune, non devono disporre dei privilegi di root per installare il software e possono installare e utilizzare versioni diverse di un pacchetto.

Prima di tutto, la dipendenza più importante di ogni programma collegato in modo dinamico è il linker. Tutte le librerie di questo tipo devono corrispondere alla versione del linker.

Facciamo un semplice esempio: ho il nuovo sistema di Ubuntu dove eseguo qualche programma (nel mio caso è D compilatore – ldc2). Mi piacerebbe eseguirlo sul vecchio CentOS, ma a causa della vecchia libreria di glibc è imansible. ho ottenuto

 ldc2-1.5.0-linux-x86_64/bin/ldc2: /lib64/libc.so.6: version `GLIBC_2.15' not found (required by ldc2-1.5.0-linux-x86_64/bin/ldc2) ldc2-1.5.0-linux-x86_64/bin/ldc2: /lib64/libc.so.6: version `GLIBC_2.14' not found (required by ldc2-1.5.0-linux-x86_64/bin/ldc2) 

Devo copiare tutte le dipendenze da ubuntu a centos. Il metodo corretto è il seguente:

Innanzitutto, controlliamo tutte le dipendenze:

 ldd ldc2-1.5.0-linux-x86_64/bin/ldc2 linux-vdso.so.1 => (0x00007ffebad3f000) librt.so.1 => /lib/x86_64-linux-gnu/librt.so.1 (0x00007f965f597000) libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f965f378000) libz.so.1 => /lib/x86_64-linux-gnu/libz.so.1 (0x00007f965f15b000) libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f965ef57000) libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f965ec01000) libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f965e9ea000) libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f965e60a000) /lib64/ld-linux-x86-64.so.2 (0x00007f965f79f000) 

linux-vdso.so.1 non è una vera libreria e non dobbiamo preoccuparcene.

/lib64/ld-linux-x86-64.so.2 è il linker, che viene usato da Linux per colbind l’eseguibile con tutte le librerie dinamiche.

Il resto dei file sono vere e proprie librerie e tutti insieme con il linker devono essere copiati da qualche parte nei centri.

Supponiamo che tutte le librerie e il linker siano nella directory “/ mylibs”.

ld-linux-x86-64.so.2 – come ho già detto – è il linker. Non è una libreria dynamic ma è eseguibile statico. Puoi eseguirlo e vedere che ha anche alcuni parametri, es. –Library-path (tornerò ad esso).

Sul Linux, il programma collegato dynamicmente può essere pranzato solo con il suo nome, ad es

 /bin/ldc2 

Linux carica tale programma nella RAM e controlla quale linker è impostato per esso. Di solito, su sistemi a 64 bit, è /lib64/ld-linux-x86-64.so.2 (nel tuo filesystem è un collegamento simbolico al vero eseguibile). Quindi linux esegue il linker e carica le librerie dinamiche.

Puoi anche cambiarlo un po ‘e fare questo trucco:

 /mylibs/ld-linux-x86-64.so.2 /bin/ldc2 

È il metodo per forzare linux ad usare un linker specifico.

E ora possiamo tornare al precedente parametro –library-path

 /mylibs/ld-linux-x86-64.so.2 --library-path /mylibs /bin/ldc2 

Avvia ldc2 e carica le librerie dinamiche da / mylibs.

Questo è il metodo per chiamare l’eseguibile con le librerie scelte (non di default del sistema).

Se osservi da vicino il secondo output puoi vedere che viene utilizzata la nuova posizione per le librerie. Forse mancano ancora le librerie che fanno parte di glibc.

Penso anche che tutte le librerie usate dal tuo programma dovrebbero essere compilate contro quella versione di glibc. Se si ha accesso al codice sorgente del programma, una nuova compilazione sembra essere la soluzione migliore.

“Il russo impiegato” è tra le migliori risposte e penso che tutte le altre risposte suggerite potrebbero non funzionare. Il motivo è semplicemente perché quando un’applicazione viene creata per la prima volta, tutte le API di cui ha bisogno vengono risolte in fase di compilazione. Usando “ldd” puoi vedere tutte le dipendenze collegate staticamente:

 ldd /usr/lib/firefox/firefox linux-vdso.so.1 => (0x00007ffd5c5f0000) libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f727e708000) libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f727e500000) libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007f727e1f8000) libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f727def0000) libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f727db28000) /lib64/ld-linux-x86-64.so.2 (0x00007f727eb78000) libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f727d910000) 

Ma in fase di esecuzione, firefox caricherà anche molte altre librerie dinamiche, ad esempio (per firefox) ci sono molte librerie “glib” con etichette caricate (anche se collegate staticamente non ce ne sono):

  /usr/lib/x86_64-linux-gnu/libdbus-glib-1.so.2.2.2 /lib/x86_64-linux-gnu/libglib-2.0.so.0.4002.0 /usr/lib/x86_64-linux-gnu/libavahi-glib.so.1.0.2 

Molte volte, è ansible vedere i nomi di una versione collegata in un’altra versione. Per esempio:

 lrwxrwxrwx 1 root root 23 Dec 21 2014 libdbus-glib-1.so.2 -> libdbus-glib-1.so.2.2.2 -rw-r--r-- 1 root root 160832 Mar 1 2013 libdbus-glib-1.so.2.2.2 

Ciò significa quindi che esiste una versione diversa di “librerie” in un sistema, che non è un problema in quanto è lo stesso file e fornirà compatibilità quando le applicazioni hanno più dipendenze di versioni.

Pertanto, a livello di sistema, tutte le librerie sono quasi interdipendenti l’una con l’altra, e la semplice modifica della priorità di caricamento delle librerie tramite la manipolazione di LD_PRELOAD o LD_LIBRARY_PATH non aiuta – anche se può essere caricata, il runtime potrebbe ancora bloccarsi.

http://lightofdawn.org/wiki/wiki.cgi/-wiki/NewAppsOnOldGlibc

La migliore alternativa è chroot (menzionata brevemente da ER): ma per questo è necessario ricreare l’intero ambiente in cui è eseguito l’originale binario – di solito a partire da / lib, / usr / lib /, / usr / lib / x86, ecc. Puoi usare “Buildroot”, o YoctoProject, o semplicemente tar da un ambiente Distro esistente. (come Fedora / Suse ecc.).

Non sono sicuro che la domanda sia ancora pertinente, ma esiste un altro modo per risolvere il problema: Docker. È ansible installare un contenitore quasi vuoto di Source Distribution (la distribuzione utilizzata per lo sviluppo) e copiare i file nel contenitore. In questo modo non è necessario creare il filesystem necessario per chroot.

Quando volevo eseguire un browser chromium su Ubuntu preciso (glibc-2.15), ho ricevuto il messaggio (tipico) “… libc.so.6: versione` GLIBC_2.19 ‘non trovata … “. Ho considerato il fatto che i file non sono necessari in modo permanente, ma solo all’inizio. Così ho raccolto i file necessari per il browser e sudo e creato un ambiente mini-glibc-2.19-, ho avviato il browser e poi ho copiato di nuovo i file originali. I file necessari sono in RAM e l’glibc originale è lo stesso.

 as root the files (*-2.15.so) already exist 

mkdir -p /glibc-2.19/i386-linux-gnu

 /glibc-2.19/ld-linux.so.2 -> /glibc-2.19/i386-linux-gnu/ld-2.19.so /glibc-2.19/i386-linux-gnu/libc.so.6 -> libc-2.19.so /glibc-2.19/i386-linux-gnu/libdl.so.2 -> libdl-2.19.so /glibc-2.19/i386-linux-gnu/libpthread.so.0 -> libpthread-2.19.so 

mkdir -p /glibc-2.15/i386-linux-gnu

 /glibc-2.15/ld-linux.so.2 -> (/glibc-2.15/i386-linux-gnu/ld-2.15.so) /glibc-2.15/i386-linux-gnu/libc.so.6 -> (libc-2.15.so) /glibc-2.15/i386-linux-gnu/libdl.so.2 -> (libdl-2.15.so) /glibc-2.15/i386-linux-gnu/libpthread.so.0 -> (libpthread-2.15.so) 

lo script per eseguire il browser:

 #!/bin/sh sudo cp -r /glibc-2.19/* /lib /path/to/the/browser & sleep 1 sudo cp -r /glibc-2.15/* /lib sudo rm -r /lib/i386-linux-gnu/*-2.19.so