16

Analysieren this question Ich habe einiges über das Verhalten der schwachen Symbolauflösung im Kontext des dynamischen Ladens (dlopen) auf Linux herausgefunden. Jetzt suche ich nach den Spezifikationen, die das regeln.Dynamisches Laden und schwache Symbolauflösung

Nehmen wir an example. Angenommen, es gibt ein Programm a, das die Bibliotheken b.so und c.so in dieser Reihenfolge dynamisch lädt. Wenn c.so auf zwei andere Bibliotheken abhängig foo.so (eigentlich libgcc.so in diesem Beispiel) und bar.so (eigentlich libpthread.so), dann in der Regel durch bar.so exportierte Symbole können schwache Symbol Verbindungen verwendet wird, in foo.so gerecht zu werden. Aber wenn b.so auch von foo.so abhängt, aber nicht von bar.so, dann werden diese schwachen Symbole anscheinend nicht gegen bar.so verknüpft werden. Es scheint, als würden foo.so Tinten nur nach Symbolen aus a und b.so und all ihren Abhängigkeiten suchen.

Dies ist bis zu einem gewissen Grad sinnvoll, da sonst das Laden von c.so das Verhalten von foo.so irgendwann ändern könnte, wo b.so bereits die Bibliothek verwendet hat. Auf der anderen Seite, in der Frage, die mich angestoßen hat, verursachte das ziemlich viel Ärger, also frage ich mich, ob es einen Weg gibt, dieses Problem zu umgehen. Und um Wege zu finden, brauche ich zunächst ein gutes Verständnis über die sehr genauen Details, wie die Symbolauflösung in diesen Fällen spezifiziert wird.

Was ist die Spezifikation oder anderes technisches Dokument, um das richtige Verhalten in diesen Szenarien zu definieren?

+0

Haben Sie sich [dieses PDF] (http://refspecs.linuxbase.org/elf/elf.pdf) angesehen? Viele interessante Daten, aber nicht sicher, ob es enthält, wonach Sie suchen. – rodrigo

+0

@rodrigo: Nicht sicher, ob dies oder etwas ähnliches war, aber bisher beschrieben alle ELF-Dokumente, die ich gefunden habe, nur die dynamische Verknüpfung vor der Ausführung einer Binärdatei, nicht die Verknüpfung in dynamisch geladenen Objekten. Es ist ein langes Dokument, und ich hätte vielleicht an den falschen Stellen nachgesehen, aber bisher scheint es nicht das zu sein, wonach ich suche. – MvG

+0

Und was ist das [Drepper Beitrag] (http://www.sourceware.org/ml/libc-hacker/2000-06/msg00029.html) und seine mehr oder weniger [verwandten Dokument] (http: // www. akkadia.org/drepper/dsohowto.pdf) (siehe Abschnitt 1.5.2)? Wie ich es interpretiere, werden schwache Symbole nur für statische Verknüpfungen verwendet. So würde 'dlopen()' keinen Unterschied zwischen schwachen und starken Symbolen machen. – rodrigo

Antwort

11

Leider ist die maßgebliche Dokumentation der Quellcode. Die meisten Linux-Distributionen verwenden glibc oder seinen Fork, eglibc. Im Quellcode für beide, die Datei, die dokumentieren dlopen sollte() lautet wie folgt:

manual/libdl.texi

@c FIXME these are undocumented: 
@c dladdr 
@c dladdr1 
@c dlclose 
@c dlerror 
@c dlinfo 
@c dlmopen 
@c dlopen 
@c dlsym 
@c dlvsym 

Welche technische Spezifikation wird von der ELF specification und der POSIX-Standard gezogen werden kann, . Die ELF-Spezifikation macht ein schwaches Symbol sinnvoll. POSIX ist das eigentliche specification for dlopen() selbst.

Dies ist, was ich finde, der relevanteste Teil der ELF-Spezifikation zu sein.

Wenn der Linkeditor Archivbibliotheken durchsucht, extrahiert er das Archiv Mitglieder, die Definitionen nicht definierter globaler Symbole enthalten. Die Memberdefinition kann entweder ein globales oder ein schwaches Symbol sein.

Die ELF-Spezifikation bezieht sich nicht auf dynamisches Laden, so dass der Rest dieses Absatzes meine eigene Interpretation ist. Der Grund, warum ich das oben genannte relevant finde, ist, dass das Auflösen von Symbolen bei einem einzigen "wenn" auftritt. In dem von Ihnen angegebenen Beispiel versucht das dynamische Ladeprogramm a, b.so dynamisch zu laden, nicht definierte Symbole aufzulösen. Dies kann am Ende mit globalen oder schwachen Symbolen enden. Wenn das Programm dann dynamisch c.so lädt, versucht der dynamische Lader erneut, nicht definierte Symbole aufzulösen. In dem von Ihnen beschriebenen Szenario wurden Symbole in b.so mit schwachen Symbolen aufgelöst. Sobald diese aufgelöst sind, sind diese Symbole nicht länger undefiniert. Es spielt keine Rolle, ob globale oder schwache Symbole verwendet wurden, um sie zu definieren. Sie sind bereits nicht mehr definiert, wenn c.so geladen ist.

Die ELF-Spezifikation gibt keine genaue Definition, was ein Link-Editor ist oder wann der Link-Editor Objektdateien kombinieren muss. Vermutlich ist dies kein Problem, da das Dokument dynamisch verknüpft ist.

POSIX beschreibt einige der dlopen() - Funktionalität, aber lässt viel bis zur Implementierung, einschließlich der Substanz Ihrer Frage. POSIX bezieht sich nicht auf das ELF-Format oder schwache Symbole im Allgemeinen. Für Systeme, die dlopen() implementieren, braucht es keine Vorstellung von schwachen Symbolen zu geben.

http://pubs.opengroup.org/onlinepubs/9699919799/functions/dlopen.html

POSIX-Konformität ist Teil eines anderen Standard, der Linux Standard Base. Linux-Distributionen können diesen Standards folgen oder auch nicht und können oder werden möglicherweise nicht in Schwierigkeiten geraten, zertifiziert zu werden. Zum Beispiel verstehe ich, dass eine formelle Unix-Zertifizierung durch Open Group ziemlich teuer ist - daher die Fülle von "Unix-ähnlichen" Systemen.

Ein interessanter Punkt über die Einhaltung der Standards von dlopen() ist auf der Wikipedia article for dynamic loading gemacht. dlopen(), wie von POSIX gefordert, gibt void * zurück, aber C, wie von ISO gefordert, sagt, dass void * ein Zeiger auf ein Objekt ist und ein solcher Zeiger nicht notwendigerweise mit einem Funktionszeiger kompatibel ist.

Es bleibt die Tatsache, dass jede Umwandlung zwischen Funktion und Objekt Zeiger als (von Natur aus nicht-portable) Umsetzung Erweiterung betrachtet werden muss, und dass kein „richtiger“ Weg für eine direkte Umwandlung vorhanden ist, da in In dieser Hinsicht widersprechen sich die POSIX- und ISO-Standards .

Die Standards, die existieren, widersprechen und welche Standards Dokumente dort sind möglicherweise nicht besonders sinnvoll. Hier schreibt Ulrich Drepper über seine Verachtung für die Open Group und ihre "Spezifikationen".

http://udrepper.livejournal.com/8511.html

ähnliche Stimmung wird von rodrigo in der Post verbunden ausgedrückt.

Der Grund, warum ich diese Änderung vorgenommen habe, ist wirklich nicht mehr konformen (es ist schön, aber kein Grund, da niemand über das alte Verhalten beschwert) zu sein.

Nach hinein suchen, glaube ich, die richtige Antwort auf die Frage, wie Sie es, dass es gefragt haben, ist für dlopen() in dieser Hinsicht keine richtige oder falsche Verhalten. Sobald eine Suche ein Symbol aufgelöst hat, ist es nicht länger undefiniert und bei nachfolgenden Suchen versucht der dynamische Lader nicht, das bereits definierte Symbol aufzulösen.

Schließlich, wie Sie in den Kommentaren angeben, ist das, was Sie im ursprünglichen Beitrag beschreiben, nicht korrekt. Dynamisch geladene, gemeinsam genutzte Bibliotheken können verwendet werden, um undefinierte Symbole in zuvor dynamisch geladenen, gemeinsam genutzten Bibliotheken aufzulösen. Tatsächlich ist dies nicht auf nicht definierte Symbole in dynamisch geladenem Code beschränkt. Hier ist ein Beispiel, in dem die ausführbare Datei selbst ein nicht definiertes Symbol enthält, das durch dynamisches Laden aufgelöst wird.

main.c

#include <dlfcn.h> 

void say_hi(void); 

int main(void) { 
    void* symbols_b = dlopen("./dyload.so", RTLD_NOW | RTLD_GLOBAL); 
    /* uh-oh, forgot to define this function */ 
    /* better remember to define it in dyload.so */ 
    say_hi(); 
    return 0; 
} 

dyload.c

#include <stdio.h> 
void say_hi(void) { 
    puts("dyload.so: hi"); 
} 

Kompilieren und ausführen.

gcc-4.8 main -fpic -ldl -Wl,--unresolved-symbols=ignore-all -o main 
gcc-4.8 dyload.c -shared -fpic -o dyload.so 
$ ./main 
dyload.so: hi 

Beachten Sie, dass die Hauptdatei selbst als PIC kompiliert wurde.

+0

Das nenne ich eine ausgezeichnete Antwort! – paulotorrens