Es gibt ein Geheimnis, das ich versuche zu verstehen:
Ich habe eine Anwendung entwickelt, die mit dynamischen Bibliotheken erweitert werden kann, die Code enthalten, der jedoch auf einige Funktionen zugreifen muss, die in der Anwendung selbst definiert sind. Um es klar zu machen:
Ich habe Anwendung nennen wir es APP, dann habe ich die Erweiterung EXT. APP ist um einige Funktionen erweitert, die in EXT implementiert sind, aber EXT muss einige Funktionen aufrufen, die in APP definiert sind, um sie zu "haken" (zum Beispiel um neue Elemente im APP-Layout zu registrieren usw.). In MS Windows wäre ich nicht in der Lage, EXT wegen unaufgelöster Symbole zu kompilieren - das macht Sinn - wie würde ich Funktionen aufrufen, die in APP sind, ohne tatsächlich etwas mit diesen zu verknüpfen, also habe ich eine DLL-Bibliothek von APP erstellt, die im Grunde genommen ist APP nur als DLL mit all diesen Funktionen gebaut, die ich mit __declspec (dllexport) exportiert haben muss (nennen wir es nur LIB), so funktioniert es wie folgt:
APP lädt EXT und EXT ruft APP-Funktionen über LIB auf. Es ist irgendwann eine unangenehme Lösung, aber mir fällt nichts Besseres ein. Und was am wichtigsten ist - es funktioniert perfekt.
Was mich jetzt verrückt macht, ist, wie funktioniert das alles unter Linux, ohne LIB erstellen zu müssen? Diese Windows-Sache ist fies, aber es macht durchaus Sinn, aber unter Linux kann ich EXT auch ohne APP oder LIB bauen, es ignoriert diese ungelösten Symbole einfach irgendwie und verlinkt sie trotzdem. Die ganze Bibliothek enthält sie, ich kann das überprüfen, indem ich folgendes anrufe:
%Vor%Sie können also sehen, dass das EXT sich auf einige Funktionen der APP bezieht, aber nie mit einer Bibliothek verbunden war, die sie implementieren würde. Sie sind einfach nicht gelöst.
Wenn ich EXT in APP lade, passiert irgendwie Magie im Kernel und alle funktionieren magisch. Warum benötigt die APP unter Linux keine LIB, während Windows sie benötigt? Warum ist es möglich, etwas auf Linux mit ungelösten externen Symbolen zu verknüpfen? Woher weiß es, auf welche Symbole ich mich beziehe? Findet es sie in APP und löse sie Laufzeit?
Für alle, die hier interessiert sind, gibt es eine vollständige Quelle: Ссылка , wenn Sie dies auf Linux klonen und ./configure --extension
ausführen. und dann werden Sie sehen, dass es zuerst eine der Erweiterungen erstellt (auch wenn es nichts zu verknüpfen gibt), dann erstellt es die Anwendung, und wenn Sie make install
ausführen und dann versuchen, es auszuführen, werden Sie sehen, dass es nur lädt fein und mit etwas Magie beheben sie die nicht aufgelösten Symbole in der Bibliothek zur Laufzeit. Wie funktioniert das? Und warum funktioniert es nicht in Windows?
Ich denke, es hängt mit dem ELF -Format zusammen, das für ausführbare Dateien und Bibliotheken in Linux (und vielen anderen * NIXes) und dynamic linker verwendet wird.
Wenn das dynamisch verknüpfte Programm gestartet wird (sein Prozess wird erstellt), bereitet der dynamische Linker den Adressraum dieses Prozesses vor. Linux-Bibliotheken werden mit PIC (positionsunabhängigem Code) kompiliert, sodass sie an beliebiger Stelle im Prozessadressraum platziert werden können. Verknüpfungen zwischen Funktionen verschiedener Module zur Laufzeit werden über die Tabellen PLT (Prozedursuche) und GOT (globaler Offset) aufgelöst. PLT (schreibgeschützter, ausführbarer Abschnitt) hält indirekte Sprungbefehle an Adressen in der GOT-Tabelle (schreibgeschützte, nicht ausführbare Sektion). Der erste Aufruf der Funktion über PLT führt zu einer Laufzeit-Linker-Funktion, die den GOT-Eintrag aktualisiert (und zur realen Adresse springt). Nachfolgende Aufrufe derselben Funktion springen direkt darauf.
Wie ich verstehe, hat der Compiler genügend Informationen (Funktionsprototypen und andere Daten aus Header-Dateien), um die Bibliothek korrekt zu erstellen. Um jedoch eine ausführbare Datei zu erstellen, müssen Sie alle erforderlichen Bibliotheken bereitstellen (zur Laufzeit können Sie die verwendeten Bibliotheken ändern, solange sie alle verwendeten Funktionen bereitstellen).
Ich nehme an, dynamische Verknüpfungen funktionieren wie diese anderen UNIX-ähnlichen Betriebssysteme, die das ELF-Format verwenden.
Ich bin mit dem ausführbaren Windows-Format nicht vertraut, daher kann ich nicht sagen, warum ein ähnlicher Trick dort nicht funktioniert.