Linux, GNU GCC, ld, Versionsskripte und das ELF-Binärformat - Wie funktioniert es?

13

Ich versuche, mehr über die Bibliotheksversionierung unter Linux zu erfahren und zu erfahren, wie alles funktioniert. Hier ist der Kontext:

- Ich habe zwei Versionen einer dynamischen Bibliothek, die denselben Satz von Schnittstellen verfügbar machen, sagen wir libsome1.sound libsome2.so.

- Eine Anwendung ist mit verknüpft libsome1.so.

- Diese Anwendung libdl.solädt beispielsweise dynamisch ein anderes Modul libmagic.so.

- Jetzt libmagic.soist dagegen verlinkt libsome2.so. Ohne Verwendung von Linker-Skripten zum Ausblenden von Symbolen libmagic.sowerden zur Laufzeit alle Aufrufe von Interfaces in libsome2.soaufgelöst libsome1.so. Dies kann bestätigt werden, indem der von zurückgegebene Wert mit libVersion()dem Wert des Makros verglichen wird LIB_VERSION.

- Also versuche ich als nächstes, libmagic.soein Linker-Skript zu kompilieren und zu verknüpfen, das alle Symbole mit Ausnahme von 3 verbirgt, die darin definiert libmagic.sosind und von diesem exportiert werden. Das funktioniert ... oder zumindest libVersion()und LIB_VERSIONWerte stimmen überein (und es wird Version 2 und nicht 1 gemeldet).

- Als jedoch einige Datenstrukturen auf die Festplatte serialisiert wurden, bemerkte ich eine Beschädigung. Wenn ich im Verzeichnis der Anwendung libsome1.soeinen Softlink lösche und an seiner Stelle einen solchen erstelle libsome2.so, funktioniert alles wie erwartet, und die gleiche Beschädigung tritt nicht auf.

Ich kann nicht anders, als zu glauben, dass dies auf einen Konflikt in der Symbolauflösung des Laufzeit-Linkers zurückzuführen ist. Ich habe viele Dinge ausprobiert, wie den Versuch, eine Verknüpfung zu libsome2.soerstellen, damit alle Symbole gleich sind symbol@@VER_2(worüber ich immer noch verwirrt bin, weil der Befehl nm -CD libsome2.soimmer noch Symbole als symbolund nicht auflistet symbol@@VER_2) ... Nichts scheint zu funktionieren !!! Hilfe!!!!!!

der andere strahl
quelle
Ihr letzter Ansatz ist der, mit dem ich begonnen hätte. Und ich stimme zu, dass die Korruption wahrscheinlich eine Symbolverwirrung ist. Leider habe ich keine Antwort für Sie.
RobotHumans
Dies könnte auf SO besser sein, obwohl ich es nicht genug verstehe, um es mit Sicherheit zu sagen. kennzeichnen Sie es, wenn Sie möchten, dass wir es bewegen.
Xenoterracid
1
Probieren Sie die RTLD_LOCALund RTLD_DEEPBINDdlopen Flags in Ihrer App. Ich habe jetzt keine Zeit, dies zu testen, aber es sollte basierend auf der Manpage funktionieren.
Stribika

Antworten:

13

Dies beantwortet Ihre Frage nicht genau, aber ...

Zuallererst ist ELF die Spezifikation, die von Linux für ausführbare Dateien (Programme), gemeinsam genutzte Bibliotheken und auch Objektdateien verwendet wird, die die Zwischendateien sind, die beim Kompilieren von Software gefunden werden. Objektdateien enden mit .o, gemeinsam genutzte Bibliotheken enden mit .so, gefolgt von null oder mehr durch Punkte getrennten Ziffern, und ausführbare Dateien haben normalerweise keine Erweiterung.

Es gibt normalerweise drei Formulare, um eine gemeinsam genutzte Bibliothek zu benennen. Das erste Formular endet einfach mit .so. Beispielsweise wird eine Bibliothek mit dem Namen readline in einer Datei mit dem Namen libreadline.so gespeichert und befindet sich normalerweise unter / lib, / usr / lib oder / usr / local / lib. Diese Datei befindet sich beim Kompilieren von Software mit einer Option wie -lreadline. -l weist den Compiler an, eine Verknüpfung mit der folgenden Bibliothek herzustellen. Da sich Bibliotheken von Zeit zu Zeit ändern, kann dies veralten, sodass Bibliotheken einen so genannten SONAME einbetten. Der SONAME für readline könnte für die Hauptversion von libreadline wie libreadline.so.2 aussehen. Möglicherweise sind auch viele kleinere Versionen von readline kompatibel und erfordern keine Neukompilierung der Software. Eine kleinere Version von readline könnte libreadline.so.2.14 heißen. Normalerweise libreadline. In diesem Fall ist dies nur ein symbolischer Link zur neuesten Hauptversion von readline, libreadline.so.2. libreadline.so.2 ist auch ein symbolischer Link zu libreadline.so.2.14, bei dem es sich tatsächlich um die verwendete Datei handelt.

Der SONAME einer Bibliothek ist in die Bibliotheksdatei selbst eingebettet. Irgendwo in der Datei libreadline.so.2.14 befindet sich der String libreadline.so.2. Wenn ein Programm kompiliert und mit readline verknüpft wird, sucht es nach der Datei libreadline.so und liest den darin eingebetteten SONAME. Später, wenn das Programm tatsächlich ausgeführt wird, wird libreadline.so.2 geladen, nicht nur libreadline.so, da dies der SONAME war, der beim ersten Verknüpfen gelesen wurde. Auf diese Weise können auf einem System mehrere inkompatible Versionen von readline installiert werden, und jedes Programm lädt die entsprechende Hauptversion, mit der es verknüpft wurde. Wenn ich beispielsweise readline auf 2.17 aktualisiere, kann ich libreadline.so.2.17 einfach neben der vorhandenen Bibliothek installieren und den symbolischen Link libreadline.so.2 von libreadline.so.2.13 nach libreadline.so.2.17 verschieben.

penguin359
quelle