GNU/Linux >> Linux Esercitazione >  >> Linux

Più librerie glibc su un singolo host

Questa domanda è vecchia, le altre risposte sono vecchie. La risposta "Russo impiegato" è molto buona e istruttiva, ma funziona solo se si dispone del codice sorgente. Se non lo fai, allora le alternative erano molto complicate. Fortunatamente 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 binario prima di patcharlo, se non sei sicuro di cosa stai facendo, perché modifica il tuo file binario. Dopo averlo corretto, non è possibile ripristinare il vecchio percorso in interpreter/rpath. Se non funziona, dovrai continuare a correggerlo finché non trovi il percorso che funzionerà davvero ... 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 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 sarebbe vuoto perché la libc di sistema non ha la versione che desidera, e il secondo dovrebbe produrre GLIBC_2.3 perché ha la versione myapp sta usando, quindi sappiamo che possiamo patchelf il nostro binario usando quel percorso. Se riscontri un errore di segmentazione, leggi la nota alla fine.

Quando provi a eseguire un binario in Linux, il binario tenta di caricare il linker, quindi le librerie e dovrebbero essere tutte 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 scoprirlo con questo comando:

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

Se il tuo problema riguarda le librerie, i comandi che ti daranno le librerie in uso sono:

$ readelf -d myapp | grep Shared
$ ldd myapp 

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

"patchelf" funziona per molti problemi diversi che potresti incontrare durante il tentativo di eseguire un programma, correlato a questi 2 problemi. Ad esempio, se ottieni:ELF file OS ABI invalid , può essere risolto impostando un nuovo caricatore (il --set-interpreter parte del comando) come spiego qui. Un altro esempio riguarda il problema di ottenere No such file or directory quando esegui un file che è lì ed eseguibile, come esemplificato qui. In quel caso particolare, all'OP mancava un collegamento al caricatore, ma forse nel tuo caso non hai l'accesso root e non puoi creare il collegamento. Impostare un nuovo interprete risolverebbe il tuo problema.

Grazie a Employed Russian e Michael Pankov per l'intuizione e la soluzione!

Nota per errore di segmentazione:potresti trovarti nel caso in cui myapp utilizza diverse librerie e la maggior parte di esse va bene ma altre no; poi tu patchelf in una nuova directory e ottieni un errore di segmentazione. Quando fai patchelf il tuo binario, cambi il percorso di diverse librerie, anche se alcune erano originariamente in un percorso diverso. Dai un'occhiata al mio esempio qui sotto:

$ ldd myapp
./myapp: /usr/lib/x86_64-linux-gnu/libstdc++.so.6: version `GLIBCXX_3.4.20' not found (required by ./myapp)
./myapp: /usr/lib/x86_64-linux-gnu/libstdc++.so.6: version `GLIBCXX_3.4.21' not found (required by ./myapp)
        linux-vdso.so.1 =>  (0x00007fffb167c000)
        libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f9a9aad2000)
        libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f9a9a8ce000)
        libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f9a9a6af000)
        libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007f9a9a3ab000)
        libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f9a99fe6000)
        /lib64/ld-linux-x86-64.so.2 (0x00007f9a9adeb000)
        libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f9a99dcf000)

Nota che la maggior parte delle librerie sono in /lib/x86_64-linux-gnu/ ma quello problematico (libstdc++.so.6 ) è su /usr/lib/x86_64-linux-gnu . Dopo aver patchato myapp puntare a /path/to/mylibs , ho un errore di segmentazione. Per qualche ragione, le librerie non sono totalmente compatibili con il binario. Da myapp non mi sono lamentato delle librerie originali, le ho copiate da /lib/x86_64-linux-gnu/ a /path/to/mylibs2 , e ho anche copiato libstdc++.so.6 da /path/to/mylibs là. Poi l'ho modificato in /path/to/mylibs2 e myapp funziona ora. Se il tuo binario usa librerie diverse e hai versioni diverse, potrebbe succedere che non puoi risolvere la tua situazione. :( Ma se è possibile, mescolare librerie potrebbe essere la soluzione. Non è l'ideale, ma forse Funzionerà. Buona fortuna!


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


Prima di tutto, la dipendenza più importante di ogni programma collegato dinamicamente è il linker. Tutte le librerie devono quindi corrispondere alla versione del linker.

Prendiamo un semplice esempio:ho il sistema Ubuntu newset in cui eseguo un programma (nel mio caso è il compilatore D - ldc2). Mi piacerebbe eseguirlo sul vecchio CentOS, ma a causa della vecchia libreria glibc è impossibile. Ho

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, utilizzato da Linux per collegare l'eseguibile con tutte le librerie dinamiche.

Il resto dei file sono librerie reali e tutti insieme al linker devono essere copiati da qualche parte nei centos.

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 dinamica ma un eseguibile statico. Puoi eseguirlo e vedere che ha anche alcuni parametri, ad esempio --library-path (ci tornerò).

Su Linux, un programma collegato dinamicamente può essere richiamato 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 un sistema 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 a usare un linker specifico.

E ora possiamo tornare al parametro menzionato in precedenza --library-path

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

Eseguirà ldc2 e caricherà le librerie dinamiche da /mylibs.

Questo è il metodo per chiamare l'eseguibile con le librerie scelte (non predefinite di sistema).


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

Tuttavia, devi sapere che glibc è composto da molti pezzi (più di 200 librerie condivise) che devono corrispondere tutti. Uno dei pezzi è ld-linux.so.2, e deve corrisponda a libc.so.6 o vedrai gli errori che stai vedendo.

Il percorso assoluto a ld-linux.so.2 è codificato nell'eseguibile al momento del collegamento e non può essere modificato facilmente dopo che il collegamento è stato eseguito (Aggiornamento:può essere fatto con patchelf; vedi questa risposta sotto).

Per creare un eseguibile che funzioni con la nuova glibc, procedere come segue:

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

Il -rpath l'opzione linker farà in modo che il caricatore di runtime cerchi le librerie in /path/to/newglibc (quindi non dovresti impostare LD_LIBRARY_PATH prima di eseguirlo) e -dynamic-linker l'opzione "prepara" il percorso per correggere ld-linux.so.2 nell'applicazione.

Se non riesci a ricollegare il myapp applicazione (ad esempio perché è un binario di terze parti), non tutto è perduto, ma diventa più complicato. Una soluzione è impostare un chroot appropriato ambiente per esso. Un'altra possibilità è usare rtldi e un editor binario. Aggiornamento:oppure puoi usare patchelf.


Linux
  1. Ospita più siti Web su contenitori Docker

  2. Come eseguire un comando singolo su più sistemi remoti contemporaneamente

  3. Come dividere un singolo file in più file in base alle righe

  4. Come rinominare più file in un singolo comando o script in Unix??

  5. Ssh:più voci simili in Ssh Config?

Come ospitare più siti in un'unica installazione di Wordpress su Ubuntu 14.04

Come ospitare più siti in un'unica installazione di Wordpress su CentOS 7

Come eseguire più comandi Linux in un unico comando

Ospita più siti Web su un unico server con Apache su Ubuntu 18.04

Come unire più pagine PDF in una singola pagina

Come rinominare più file in un singolo comando o script in Unix?