GNU/Linux >> LINUX-Kenntnisse >  >> Linux

Mehrere glibc-Bibliotheken auf einem einzigen Host

Diese Frage ist alt, die anderen Antworten sind alt. Die Antwort von "Employed Russian" ist sehr gut und informativ, funktioniert aber nur, wenn Sie den Quellcode haben. Wenn Sie dies nicht tun, waren die Alternativen damals sehr schwierig. Glücklicherweise haben wir heutzutage eine einfache Lösung für dieses Problem (wie in einer seiner Antworten kommentiert), indem wir Patchelf verwenden. Alles, was Sie tun müssen, ist:

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

Und danach können Sie einfach Ihre Datei ausführen:

$ ./myapp

chroot ist nicht erforderlich oder Binärdateien zum Glück manuell bearbeiten. Denken Sie jedoch daran, Ihre Binärdatei zu sichern, bevor Sie sie patchen, wenn Sie sich nicht sicher sind, was Sie tun, da dies Ihre Binärdatei ändert. Nachdem Sie es gepatcht haben, können Sie den alten Pfad zu interpreter/rpath nicht wiederherstellen. Wenn es nicht funktioniert, müssen Sie es weiter patchen, bis Sie den Pfad finden, der tatsächlich funktioniert ... Nun, es muss kein Trial-and-Error-Prozess sein. Zum Beispiel benötigte er im Beispiel von OP GLIBC_2.3 , sodass Sie mithilfe von strings leicht herausfinden können, welche Bibliothek diese Version bereitstellt :

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

Theoretisch würde das erste grep leer bleiben, weil die System-Libc nicht die gewünschte Version hat, und das 2. sollte GLIBC_2.3 ausgeben, weil es die Version myapp hat verwendet, also wissen wir, dass wir patchelf können unsere Binärdatei, die diesen Pfad verwendet. Wenn Sie einen Segmentierungsfehler erhalten, lesen Sie den Hinweis am Ende.

Wenn Sie versuchen, eine Binärdatei unter Linux auszuführen, versucht die Binärdatei, den Linker und dann die Bibliotheken zu laden, und sie sollten sich alle im Pfad und/oder am richtigen Ort befinden. Wenn Ihr Problem mit dem Linker liegt und Sie herausfinden möchten, nach welchem ​​Pfad Ihre Binärdatei sucht, können Sie dies mit diesem Befehl herausfinden:

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

Wenn Ihr Problem mit den Bibliotheken zusammenhängt, sind die Befehle, die Ihnen die verwendeten Bibliotheken liefern:

$ readelf -d myapp | grep Shared
$ ldd myapp 

Dies listet die Bibliotheken auf, die Ihre Binärdatei benötigt, aber Sie kennen wahrscheinlich bereits die problematischen, da sie bereits Fehler liefern, wie im Fall von OP.

"Patchelf" funktioniert bei vielen verschiedenen Problemen, denen Sie beim Ausführen eines Programms begegnen können, die mit diesen 2 Problemen zusammenhängen. Beispiel:Sie erhalten:ELF file OS ABI invalid , kann es behoben werden, indem ein neuer Loader (der --set-interpreter Teil des Befehls), wie ich hier erkläre. Ein weiteres Beispiel ist das Problem, No such file or directory zu erhalten wenn Sie eine Datei ausführen, die vorhanden und ausführbar ist, wie hier beispielhaft dargestellt. In diesem speziellen Fall fehlte OP ein Link zum Loader, aber vielleicht haben Sie in Ihrem Fall keinen Root-Zugriff und können den Link nicht erstellen. Das Einstellen eines neuen Interpreters würde Ihr Problem lösen.

Danke an Employed Russian und Michael Pankov für den Einblick und die Lösung!

Hinweis für Segmentierungsfehler:Sie könnten in dem Fall sein, in dem myapp verwendet mehrere Bibliotheken, und die meisten davon sind in Ordnung, einige jedoch nicht; dann patchelf es in ein neues Verzeichnis, und Sie erhalten einen Segmentierungsfehler. Wenn Sie patchelf Ihrer Binärdatei ändern Sie den Pfad mehrerer Bibliotheken, auch wenn sich einige ursprünglich in einem anderen Pfad befanden. Schauen Sie sich mein Beispiel unten an:

$ 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)

Beachten Sie, dass die meisten Bibliotheken in /lib/x86_64-linux-gnu/ sind aber die problematische (libstdc++.so.6 ) ist auf /usr/lib/x86_64-linux-gnu . Nachdem ich myapp gepatcht habe auf /path/to/mylibs zeigen , ich habe einen Segmentierungsfehler. Aus irgendeinem Grund sind die Bibliotheken nicht vollständig mit der Binärdatei kompatibel. Seit myapp Ich habe mich nicht über die Originalbibliotheken beschwert, ich habe sie von /lib/x86_64-linux-gnu/ kopiert bis /path/to/mylibs2 , und ich habe auch libstdc++.so.6 kopiert ab /path/to/mylibs dort. Dann habe ich es auf /path/to/mylibs2 gepatcht , und myapp funktioniert jetzt. Wenn Ihre Binärdatei unterschiedliche Bibliotheken verwendet und Sie unterschiedliche Versionen haben, kann es vorkommen, dass Sie Ihre Situation nicht beheben können. :( Aber wenn es möglich ist, könnte das Mischen von Bibliotheken der Weg sein. Es ist nicht ideal, aber vielleicht es wird klappen. Viel Glück!


Verwenden Sie LD_PRELOAD:Legen Sie Ihre Bibliothek irgendwo außerhalb der man lib-Verzeichnisse ab und führen Sie Folgendes aus:

LD_PRELOAD='mylibc.so anotherlib.so' program

Siehe:Wikipedia-Artikel


Zunächst einmal ist die wichtigste Abhängigkeit jedes dynamisch gelinkten Programms der Linker. Alle so-Bibliotheken müssen mit der Version des Linkers übereinstimmen.

Nehmen wir ein einfaches Beispiel:Ich habe das Newset-Ubuntu-System, auf dem ich ein Programm ausführe (in meinem Fall ist es der D-Compiler - ldc2). Ich würde es gerne auf dem alten CentOS ausführen, aber wegen der älteren glibc-Bibliothek ist es unmöglich. Ich habe

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)

Ich muss alle Abhängigkeiten von Ubuntu nach Centos kopieren. Die richtige Methode ist folgende:

Lassen Sie uns zuerst alle Abhängigkeiten überprüfen:

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 ist keine echte Bibliothek und wir müssen uns nicht darum kümmern.

/lib64/ld-linux-x86-64.so.2 ist der Linker, der von Linux verwendet wird, um die ausführbare Datei mit allen dynamischen Bibliotheken zu verknüpfen.

Die restlichen Dateien sind echte Bibliotheken und alle zusammen mit dem Linker müssen irgendwo in den Centos kopiert werden.

Nehmen wir an, alle Bibliotheken und Linker befinden sich im Verzeichnis "/mylibs".

ld-linux-x86-64.so.2 ist - wie ich bereits sagte - der Linker. Es ist keine dynamische Bibliothek, sondern eine statische ausführbare Datei. Sie können es ausführen und sehen, dass es sogar einige Parameter hat, zB --library-path (ich komme darauf zurück).

Unter Linux kann ein dynamisch gelinktes Programm nur mit seinem Namen angezeigt werden, z. B.

/bin/ldc2

Linux lädt ein solches Programm in den Arbeitsspeicher und prüft, welcher Linker dafür eingestellt ist. Auf 64-Bit-Systemen ist es normalerweise /lib64/ld-linux-x86-64.so.2 (in Ihrem Dateisystem ist es ein symbolischer Link zur echten ausführbaren Datei). Dann führt Linux den Linker aus und lädt dynamische Bibliotheken.

Sie können dies auch ein wenig ändern und diesen Trick ausführen:

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

Es ist die Methode, um Linux zu zwingen, einen bestimmten Linker zu verwenden.

Und jetzt können wir zu dem zuvor erwähnten Parameter --library-path

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

Es führt ldc2 aus und lädt dynamische Bibliotheken von /mylibs.

Dies ist die Methode, um die ausführbare Datei mit ausgewählten (nicht standardmäßigen) Bibliotheken aufzurufen.


Es ist durchaus möglich, mehrere Versionen von glibc auf demselben System zu haben (das machen wir jeden Tag).

Sie müssen jedoch wissen, dass glibc aus vielen Teilen besteht (mehr als 200 gemeinsam genutzte Bibliotheken), die alle übereinstimmen müssen. Eines der Stücke ist ld-linux.so.2, und es muss mit libc.so.6 übereinstimmen, oder Sie sehen die Fehler, die Sie sehen.

Der absolute Pfad zu ld-linux.so.2 ist zum Zeitpunkt des Links fest in die ausführbare Datei codiert und kann nach dem Link nicht einfach geändert werden (Update:kann mit Patchelf durchgeführt werden; siehe diese Antwort unten). P>

Um eine ausführbare Datei zu erstellen, die mit der neuen glibc funktioniert, tun Sie dies:

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

Die -rpath linker-Option lässt den Runtime-Loader nach Bibliotheken in /path/to/newglibc suchen (Sie müssten also nicht LD_LIBRARY_PATH einstellen bevor es ausgeführt wird) und -dynamic-linker Die Option "backt" den Pfad, um ld-linux.so.2 zu korrigieren in die Anwendung.

Wenn Sie den myapp nicht erneut verknüpfen können Anwendung (z. B. weil es sich um eine Binärdatei eines Drittanbieters handelt), ist nicht alles verloren, aber es wird schwieriger. Eine Lösung besteht darin, einen richtigen chroot zu setzen Umfeld dafür. Eine andere Möglichkeit ist die Verwendung von rtldi und einem binären Editor. Update:oder Sie können Patchelf verwenden.


Linux
  1. So teilen Sie eine einzelne Datei basierend auf Zeilen in mehrere Dateien auf

  2. Ssh – Mehrere ähnliche Einträge in der Ssh-Konfiguration?

  3. Wie kann ich mehrere Domains hosten?

  4. Verwenden von SNI zum Hosten mehrerer SSL-Zertifikate in Apache

  5. Mounten mehrerer img-Dateien als Single-Loop-Gerät

So hosten Sie mehrere Sites in einer einzigen Wordpress-Installation unter Ubuntu 14.04

So hosten Sie mehrere Websites in einer einzigen Wordpress-Installation unter CentOS 7

So führen Sie mehrere Linux-Befehle in einem einzigen Befehl aus

Hosten Sie mehrere Websites auf einem einzigen Server mit Apache unter Ubuntu 18.04

So verbinden Sie mehrere PDF-Seiten zu einer einzigen Seite

scp eine einzelne Datei an mehrere Speicherorte