Wenn ich unter Windows C / C ++ - Code in einem DLL-Projekt in MSVC kompiliere, erhalte ich zwei Dateien:
MyDll.dll
MyDll.lib
Soweit ich weiß, MyDll.lib
enthält es eine Art Zeigertabelle, die die Positionen der Funktionen in der DLL angibt. Bei Verwendung dieser DLL, beispielsweise in einer Exe-Datei, MyDll.lib
wird sie während der Verknüpfung in die Exe-Datei eingebettet, sodass sie zur Laufzeit "weiß", wo sich die Funktionen befinden, MyDll.dll
und sie verwenden kann.
Wenn ich jedoch denselben Code unter Linux kompiliere, erhalte ich nur eine Datei MySo.so
ohne MySo.a
(das entspricht einer lib
Datei unter Linux). Woher weiß eine ausführbare Datei unter Linux, wo sich die Funktionen befinden, MySo.so
wenn während der Verknüpfung nichts darin eingebettet ist?
Der MSVC-Linker kann Objektdateien (.obj) und Objektbibliotheken (.lib) miteinander verknüpfen, um eine .EXE- oder eine .DLL-Datei zu erstellen.
Für die Verknüpfung mit einer DLL wird in MSVC eine sogenannte Importbibliothek (.LIB) verwendet, die als Klebstoff zwischen den C-Funktionsnamen und der Exporttabelle der DLL fungiert (in einer DLL kann eine Funktion nach Namen oder exportiert werden per Ordnungszahl - letzteres wurde häufig für undokumentierte APIs verwendet).
In den meisten Fällen enthält die DLL-Exporttabelle jedoch alle Funktionsnamen, und daher enthält die Importbibliothek (.LIB) weitgehend redundante Informationen (" Importfunktion ABC -> exportierte Funktion ABC " usw.).
Es ist sogar möglich, eine .LIB aus einer vorhandenen .DLL zu generieren .
Linker auf anderen Plattformen verfügen nicht über diese "Funktion" und können direkt mit dynamischen Bibliotheken verknüpft werden.
quelle
Der Unterschied, den Sie sehen, ist eher ein Implementierungsdetail - unter der Haube funktionieren sowohl Linux als auch Windows ähnlich - Sie rufen eine Stub-Funktion auf, die statisch in Ihrer ausführbaren Datei verknüpft ist, und dieser Stub lädt dann bei Bedarf DLL / shlib (im Falle einer Verzögerung) Laden , andernfalls wird die Bibliothek beim Programmstart geladen) und (beim ersten Aufruf) wird das Symbol über
GetProcAddress
/ aufgelöstdlsym
.Der einzige Unterschied besteht darin, dass diese Stub-Funktionen (die als PLT-Stubs bezeichnet werden) unter Linux dynamisch generiert werden, wenn Sie Ihre App mit einer dynamischen Bibliothek verknüpfen (die Bibliothek enthält genügend Informationen, um sie zu generieren), während sie unter Linux stattdessen generiert werden, wenn die DLL selbst vorhanden ist erstellt, in einer separaten
.lib
Datei.Die beiden Ansätze sind so ähnlich, dass es tatsächlich möglich ist, Windows-Importbibliotheken unter Linux nachzuahmen (siehe Implib.so- Projekt).
quelle
Unter Linux übergeben Sie
MySo.so
den Linker und er kann nur das extrahieren, was für die Linkphase benötigt wird, und eine Referenz eingeben,MySo.so
die zur Laufzeit benötigt wird.quelle
.dll
oder.so
sind gemeinsam genutzte Bibliotheken (zur Laufzeit verknüpft), während.a
und.lib
eine statische Bibliothek ist (zur Kompilierungszeit verknüpft). Dies ist kein Unterschied zwischen Windows und Linux.Der Unterschied ist, wie sie behandelt werden. Hinweis: Der Unterschied besteht nur im Zoll, wie werden sie verwendet. Es wäre nicht allzu schwer, Linux-Builds auf Windows-Art und umgekehrt zu erstellen, außer dass dies praktisch niemand tut.
Wenn wir eine DLL verwenden oder eine Funktion sogar aus unserer eigenen Binärdatei aufrufen, gibt es einen einfachen und klaren Weg. In C sehen wir zum Beispiel Folgendes:
Auf asm-Ebene kann es jedoch viele Unterschiede geben. Auf x86 wird beispielsweise ein
call
Opcode ausgeführt und der42
auf dem Stapel angegeben. Oder in einigen Registern. Oder irgendwo. Niemand weiß, bevor er die DLL schreibt , wie sie verwendet wird. Oder wie die Projekte es verwenden wollen, möglicherweise mit einem Compiler (oder in einer Sprache!) Geschrieben, der noch nicht einmal existiert (oder für die Entwickler der DLL unbekannt ist).Standardmäßig setzen sowohl C als auch Pascal die Argumente (und erhalten die Rückgabewerte) vom Stapel - aber sie tun dies in einer anderen Reihenfolge . Sie können auch Argumente zwischen Ihren Funktionen in den Registern durch eine vom Compiler abhängige Optimierung austauschen.
Wie Sie richtig sehen, ist der Windows-Brauch, dass beim Erstellen einer DLL auch ein Minimal
.a
/.lib
damit erstellt wird. Diese minimale statische Bibliothek ist nur ein Wrapper, über den die Symbole (Funktionen) dieser DLL erreicht werden. Dadurch werden die erforderlichen Aufrufkonvertierungen auf ASM-Ebene durchgeführt.Ihr Vorteil ist die Kompatibilität. Der Nachteil ist, dass es schwierig sein kann, herauszufinden, wie die Funktionen aufgerufen werden sollen, wenn Sie nur eine DLL haben. Dies macht die Verwendung von DLLs zu einer Hacking-Aufgabe, wenn der Entwickler der DLL Ihnen die nicht gibt
.a
. So dient es hauptsächlich Schließungszwecken, zum Beispiel ist es einfacher, zusätzliches Geld für die SDKs zu erhalten.Ein weiterer Nachteil ist, dass Sie diesen kleinen Wrapper statisch kompilieren müssen, selbst wenn Sie eine dynamische Bibliothek verwenden.
Unter Linux ist die binäre Schnittstelle der DLLs Standard und folgt der C-Konvention. Daher ist kein
.a
erforderlich und es besteht eine binäre Kompatibilität zwischen den gemeinsam genutzten Bibliotheken. Im Gegenzug haben wir nicht die Vorteile des Microsoft Custom.quelle