wake-up-neo.com

Verknüpfen zweier gemeinsam genutzter Bibliotheken mit denselben Symbolen

Ich verbinde mit zwei verschiedenen gemeinsam genutzten Bibliotheken. Beide Bibliotheken definieren einige Symbole, die einen Namen teilen, aber unterschiedliche Implementierungen haben. Ich kann nicht jede Bibliothek dazu bringen, ihre eigene Implementierung über die andere zu verwenden.

Beispielsweise definieren beide Bibliotheken eine globale Funktion bar(), die jeweils intern aufgerufen wird. Bibliothek eins nennt es von foo1() und Bibliothek zwei nennt es von foo2().

Lib1.so:

T bar
T foo1()     // calls bar()

Lib2.so:

T bar
T foo2()     // calls bar()

Wenn ich meine Anwendung gegen Lib1.so und dann Lib2.so verlinke, wird die Bar-Implementierung von Lib1.so auch beim Aufruf von foo2() aufgerufen. Wenn ich andererseits meine Anwendung gegen Lib2.so und dann Lib1.so verlinke, dann wird der Balken immer aus Lib2.so aufgerufen.

Gibt es eine Möglichkeit, dass eine Bibliothek immer die eigene Implementierung einer anderen Bibliothek vorziehen kann?

43
drewag

Es gibt mehrere Möglichkeiten, dies zu lösen:

  • Übergeben Sie -Bsymbolic oder -Bsymbolic-functions an den Linker. Dies hat eine globale Auswirkung: Jede Referenz auf ein globales Symbol (vom Funktionstyp für -Bsymbolic-functions), das in ein Symbol in der Bibliothek aufgelöst werden kann, wird in dieses Symbol aufgelöst. Damit verlieren Sie die Möglichkeit, interne Bibliotheksaufrufe mit LD_PRELOAD an diese Symbole anzuhängen. Die Symbole werden weiterhin exportiert, sodass sie von außerhalb der Bibliothek referenziert werden können.

  • Verwenden Sie ein version script, um Symbole als local in der Bibliothek zu markieren, z. Verwenden Sie etwas wie: {local: bar;}; und übergeben Sie --version-script=versionfile an den Linker. Die Symbole werden nicht exportiert.

  • Markieren Sie Symbole mit einem gültigen Sichtbarkeit ( GCC-Infoseite für Sichtbarkeit ). Dies ist entweder ausgeblendet, intern oder geschützt. . geschützt Sichtbarkeitssymbole werden als .protected exportiert, ausgeblendet Symbole werden nicht exportiert und intern Symbole nicht exportiert, und Sie gehen davon aus, sie nicht außerhalb der Bibliothek aufzurufen, auch nicht indirekt über Funktionszeiger.

Mit objdump -T können Sie prüfen, welche Symbole exportiert werden.

44
ninjalj

Sie müssen zwei 'Wrapper'-Shared-Libs erstellen, eine für jede Ihrer vorhandenen Libs. Jeder sollte mit einer --dynamic-list erstellt werden, die nur einige nicht konfliktträchtige Symbole aufführt, die eine API definieren. Sie benötigen auch -Bsymbolic, um eine globale Kombination zu vermeiden.

Es ist möglicherweise weniger anstrengend, mit geeigneten Optionen auch über dlopen auf die resultierenden Bibliotheken zuzugreifen.

3
bmargulies

Eine andere Möglichkeit, dieses Problem zu lösen, ist die Verwendung eines Makros zum Ändern des Namespaces.

Voraussetzungen

  • Alle Elemente (Funktionen, Klassen, globale Variablen, ...) befinden sich in einem Namensraum.
  • Die Bibliothek ist nicht stark von Makros in Headern abhängig.

Lösung

  • Definieren Sie beim Kompilieren der Bibliothek ein Makro mit dem Namensraumnamen, um es anders zu definieren. Wenn der Namespace beispielsweise LibNS ist, verwenden Sie -DLibNS=LibNSv1 für einen Fall und -DLibNS=LibNSv2 für den anderen Fall.
  • Wenn Sie Bibliotheken im Code verwenden, definieren Sie das Makro entsprechend Ihrer aktuellen Situation.

    #define LibNS LibNSv1
    #include "my_lib.h"
    #undef LibNS
    

Gründe, warum dies anstelle von anderen Lösungen verwendet wird

  • Wenn die problematische Bibliothek (zumindest teilweise) in Header-Dateien verwendet wird (z. B. Vorlagen, Inlines usw.); Wenn Sie sie in den Code Ihrer ausführbaren Datei aufnehmen, hat der Resolver keine Ahnung, ob diese Funktionen von Lib1.so oder Lib2.so aufgerufen werden sollen.
  • Ihr Compiler unterstützt andere Lösungen nur schlecht/nicht (sollte nicht bei unseren Intel/AMD 32/64-Bit-CPUs der Fall sein, aber bei der Google-Suche scheinen einige andere Plattformen das Problem zu haben).

Potenzielle Probleme

  • Es kann problematisch sein, beide Versionen in einer CPP-Datei Ihrer ausführbaren Datei zu verwenden. #include "my_lib.h" verwendet wahrscheinlich ein Makro, um sich vor mehrfacher Inklusion zu schützen und deren Definition zu ändern, um zu verhindern, dass dies zu vielen verschiedenen Problemen führt (Bibliotheksautor kann den Makronamen in der Zukunft ändern, Header definiert einige andere Makros usw.).

Anmerkungen

  • Dies soll nicht die aktuell akzeptierte Antwort ersetzen (von ninjalj; Sie können es gerne kopieren und einfügen), sondern es mit einem anderen Ansatz erweitern.
  • Der Hauptgrund, warum ich diese Antwort gepostet habe, ist, dass ich heute auf dieses Problem gestoßen bin, aber die Antwort hat nicht geholfen, da sich in Quelldateien problematischer Code befindet.
  • Meine Quelle: https://spin.atomicobject.com/2014/06/03/static-linking-c-plus-plus/
0
Tom