Ich weiß, dass dies für Geeks ziemlich einfach erscheinen mag. Aber ich möchte es kristallklar machen.
Wenn ich eine Win32-DLL verwenden möchte, rufe ich normalerweise nur die APIs wie LoadLibrary () und GetProcAdderss () auf. Aber vor kurzem entwickle ich mit DirectX9 und muss Dateien d3d9.lib , d3dx9.lib usw. hinzufügen .
Ich habe genug gehört, dass LIB für statische Verknüpfung und DLL für dynamische Verknüpfung ist.
Mein derzeitiges Verständnis ist also, dass LIB die Implementierung der Methoden enthält und zum Zeitpunkt der Verknüpfung als Teil der endgültigen EXE-Datei statisch verknüpft ist. Während DLL zur Laufzeit dynamisch geladen wird und nicht Teil der endgültigen EXE-Datei ist.
Aber manchmal kommen einige LIB-Dateien mit den DLL-Dateien, also:
- Wofür sind diese LIB-Dateien gedacht?
- Wie erreichen sie, wofür sie bestimmt sind?
- Gibt es Tools, mit denen ich die Interna dieser LIB-Dateien überprüfen kann?
Update 1
Nachdem ich Wikipedia überprüft habe, erinnere ich mich, dass diese LIB-Dateien als Importbibliothek bezeichnet werden . Aber ich frage mich, wie es mit meiner Hauptanwendung und den DLLs funktioniert, dynamisch geladen zu werden.
Update 2
Wie RBerteig sagte, enthält die mit den DLLs geborene LIB-Datei einen Stub-Code. Die Aufrufsequenz sollte also folgendermaßen aussehen:
Meine Hauptanwendung -> Stub in der LIB -> echte Ziel-DLL
Welche Informationen sollten in diesen LIBs enthalten sein? Ich könnte mir Folgendes vorstellen:
- Die LIB-Datei sollte den vollständigen Pfad der entsprechenden DLL enthalten. Die DLL könnte also zur Laufzeit geladen werden.
- Die relative Adresse (oder der Dateiversatz?) Des Einstiegspunkts jeder DLL-Exportmethode sollte im Stub codiert werden. So könnten korrekte Sprünge / Methodenaufrufe gemacht werden.
Habe ich recht damit? Gibt es noch etwas?
Übrigens: Gibt es ein Tool, das eine Importbibliothek überprüfen kann? Wenn ich es sehen kann, wird es keine Zweifel mehr geben.
quelle
lib /list xxx.lib
undlink /dump /linkermember xxx.lib
. Siehe diese Frage zum Stapelüberlauf .Antworten:
Die Verknüpfung mit einer DLL-Datei kann implizit zur
Kompilierungsverknüpfungszeitoder explizit zur Laufzeit erfolgen. In beiden Fällen wird die DLL in den Speicher des Prozesses geladen, und alle exportierten Einstiegspunkte stehen der Anwendung zur Verfügung.Bei expliziter Verwendung zur Laufzeit verwenden Sie
LoadLibrary()
undGetProcAddress()
zum manuellen Laden der DLL und zum Abrufen von Zeigern auf die Funktionen, die Sie aufrufen müssen.Wenn beim Erstellen des Programms implizit eine Verknüpfung hergestellt wird, werden Stubs für jeden vom Programm verwendeten DLL-Export aus einer Importbibliothek mit dem Programm verknüpft, und diese Stubs werden aktualisiert, wenn EXE und DLL beim Start des Prozesses geladen werden. (Ja, ich habe hier mehr als ein bisschen vereinfacht ...)
Diese Stubs müssen von irgendwoher kommen, und in der Microsoft-Toolkette stammen sie aus einer speziellen Form einer .LIB-Datei, die als Importbibliothek bezeichnet wird . Die erforderliche .LIB wird normalerweise gleichzeitig mit der DLL erstellt und enthält einen Stub für jede aus der DLL exportierte Funktion.
Verwirrenderweise würde eine statische Version derselben Bibliothek auch als .LIB-Datei geliefert. Es gibt keine triviale Möglichkeit, sie voneinander zu unterscheiden, außer dass LIBs, die Importbibliotheken für DLLs sind, normalerweise kleiner (oft viel kleiner) sind als die passende statische LIB.
Wenn Sie die GCC-Toolchain verwenden, benötigen Sie übrigens keine Importbibliotheken, die Ihren DLLs entsprechen. Die auf Windows portierte Version des Gnu-Linkers versteht DLLs direkt und kann die meisten erforderlichen Stubs im laufenden Betrieb synthetisieren.
Aktualisieren
Wenn Sie einfach nicht widerstehen können, zu wissen, wo sich alle Schrauben und Muttern wirklich befinden und was wirklich los ist, gibt es bei MSDN immer etwas zu helfen. Matt Pietreks Artikel Ein detaillierter Blick auf das tragbare ausführbare Win32-Dateiformat bietet einen vollständigen Überblick über das Format der EXE-Datei und darüber, wie sie geladen und ausgeführt wird. Es wurde sogar aktualisiert, um .NET und mehr abzudecken, seit es ursprünglich im MSDN Magazine erschien. 2002.
Es kann auch hilfreich sein zu wissen, wie man genau lernt, welche DLLs von einem Programm verwendet werden. Das Tool dafür ist Dependency Walker, auch bekannt als abhängige.exe. Eine Version davon ist in Visual Studio enthalten, die neueste Version ist jedoch beim Autor unter http://www.dependencywalker.com/ erhältlich . Es kann alle DLLs identifizieren, die zur Verbindungszeit angegeben wurden (sowohl frühes Laden als auch verzögertes Laden), und es kann das Programm ausführen und nach zusätzlichen DLLs suchen, die es zur Laufzeit lädt.
Update 2
Ich habe einige der früheren Texte umformuliert, um sie beim erneuten Lesen zu verdeutlichen und die impliziten und expliziten Verknüpfungen der Kunstbegriffe zu verwenden , um die Konsistenz mit MSDN zu gewährleisten.
Wir haben also drei Möglichkeiten, Bibliotheksfunktionen zur Verwendung durch ein Programm zur Verfügung zu stellen. Die offensichtliche Folgefrage lautet dann: "Wie wähle ich welchen Weg?"
Durch statische Verknüpfung wird der Großteil des Programms selbst verknüpft. Alle Ihre Objektdateien werden aufgelistet und vom Linker in der EXE-Datei zusammengefasst. Unterwegs kümmert sich der Linker um kleinere Aufgaben wie das Korrigieren von Verweisen auf globale Symbole, damit Ihre Module die Funktionen des anderen aufrufen können. Bibliotheken können auch statisch verknüpft werden. Die Objektdateien, aus denen die Bibliothek besteht, werden von einem Bibliothekar in einer .LIB-Datei gesammelt, die der Linker nach Modulen sucht, die die benötigten Symbole enthalten. Ein Effekt der statischen Verknüpfung besteht darin, dass nur die Module aus der Bibliothek verknüpft werden, die vom Programm verwendet werden. andere Module werden ignoriert. Beispielsweise enthält die traditionelle C-Mathematikbibliothek viele Trigonometriefunktionen. Aber wenn Sie dagegen verlinken und verwenden
cos()
Sie erhalten keine Kopie des Codes fürsin()
oder, estan()
sei denn, Sie haben auch diese Funktionen aufgerufen. Für große Bibliotheken mit zahlreichen Funktionen ist diese selektive Einbeziehung von Modulen wichtig. Auf vielen Plattformen wie eingebetteten Systemen kann die Gesamtgröße des zur Verwendung in der Bibliothek verfügbaren Codes im Vergleich zu dem Speicherplatz, der zum Speichern einer ausführbaren Datei auf dem Gerät verfügbar ist, groß sein. Ohne selektive Einbeziehung wäre es schwieriger, die Details der Erstellung von Programmen für diese Plattformen zu verwalten.Wenn jedoch in jedem Programm eine Kopie derselben Bibliothek vorhanden ist, wird ein System belastet, auf dem normalerweise viele Prozesse ausgeführt werden. Mit der richtigen Art von virtuellem Speichersystem müssen Speicherseiten mit identischem Inhalt nur einmal im System vorhanden sein, können jedoch von vielen Prozessen verwendet werden. Dies schafft einen Vorteil für die Erhöhung der Wahrscheinlichkeit, dass die Seiten, die Code enthalten, in so vielen anderen laufenden Prozessen wie möglich mit einigen Seiten identisch sind. Wenn Programme jedoch statisch mit der Laufzeitbibliothek verknüpft sind, verfügt jedes Programm über einen anderen Funktionsmix, der die Speicherzuordnung an verschiedenen Speicherorten verarbeitet, und es gibt nicht viele gemeinsam nutzbare Codeseiten, es sei denn, es handelt sich um ein Programm, das für sich allein ist in mehr als prozess laufen. Die Idee einer DLL hat also einen weiteren großen Vorteil gebracht.
Eine DLL für eine Bibliothek enthält alle ihre Funktionen, die von jedem Client-Programm verwendet werden können. Wenn viele Programme diese DLL laden, können sie alle ihre Codepages gemeinsam nutzen. Jeder gewinnt. (Nun, bis Sie eine DLL mit einer neuen Version aktualisieren, aber das ist nicht Teil dieser Geschichte. Google DLL Hell für diese Seite der Geschichte.)
Die erste große Wahl bei der Planung eines neuen Projekts ist also die dynamische und statische Verknüpfung. Mit der statischen Verknüpfung müssen Sie weniger Dateien installieren und sind immun gegen die Aktualisierung einer von Ihnen verwendeten DLL durch Dritte. Ihr Programm ist jedoch größer und nicht ganz so gut wie das Windows-Ökosystem. Mit der dynamischen Verknüpfung müssen Sie mehr Dateien installieren. Möglicherweise haben Sie Probleme mit der Aktualisierung einer von Ihnen verwendeten DLL durch einen Drittanbieter, sind jedoch im Allgemeinen mit anderen Prozessen auf dem System freundlicher.
Ein großer Vorteil einer DLL ist, dass sie geladen und verwendet werden kann, ohne das Hauptprogramm neu zu kompilieren oder sogar neu zu verknüpfen. Auf diese Weise kann ein Drittanbieter (z. B. Microsoft und die C-Laufzeit) einen Fehler in seiner Bibliothek beheben und verteilen. Sobald ein Endbenutzer die aktualisierte DLL installiert hat, profitiert er sofort von dieser Fehlerbehebung in allen Programmen, die diese DLL verwenden. (Es sei denn, es bricht Dinge. Siehe DLL-Hölle.)
Der andere Vorteil ergibt sich aus der Unterscheidung zwischen implizitem und explizitem Laden. Wenn Sie sich die Mühe machen, explizit zu laden, war die DLL möglicherweise noch nicht einmal vorhanden, als das Programm geschrieben und veröffentlicht wurde. Dies ermöglicht Erweiterungsmechanismen, mit denen beispielsweise Plugins erkannt und geladen werden können.
quelle
Diese .LIB-Importbibliotheksdateien werden in der folgenden Projekteigenschaft verwendet
Linker->Input->Additional Dependencies
, wenn eine Reihe von DLLs erstellt werden, die zum Zeitpunkt der Verknüpfung zusätzliche Informationen benötigen, die von den .LIB-Dateien der Importbibliothek bereitgestellt werden. Im folgenden Beispiel muss ich über die lib-Dateien auf die DLLs A, B, C und D verweisen, um keine Linkerfehler zu erhalten. (Hinweis: Damit der Linker diese Dateien finden kann, müssen Sie möglicherweise ihren Bereitstellungspfad angeben.Linker->General->Additional Library Directories
Andernfalls wird ein Buildfehler angezeigt, wenn keine der bereitgestellten lib-Dateien gefunden werden kann.)Wenn Ihre Lösung alle dynamischen Bibliotheken erstellt, konnten Sie diese explizite Abhängigkeitsspezifikation möglicherweise vermeiden, indem Sie sich stattdessen auf die im
Common Properties->Framework and References
Dialogfeld angezeigten Referenzflags verlassen . Diese Flags scheinen die Verknüpfung in Ihrem Namen mithilfe der * .lib-Dateien automatisch durchzuführen.Dies ist jedoch eine allgemeine Eigenschaft, die nicht konfigurations- oder plattformspezifisch ist. Wenn Sie ein gemischtes Build-Szenario wie in unserer Anwendung unterstützen müssen, hatten wir eine Build-Konfiguration zum Rendern eines statischen Builds und eine spezielle Konfiguration, die einen eingeschränkten Build einer Teilmenge von Assemblys erstellt, die als dynamische Bibliotheken bereitgestellt wurden. Ich hatte die verwendete
Use Library Dependency Inputs
undLink Library Dependencies
Fahnen auf true gesetzt unter verschiedenen Fällen der Dinge zu bekommen , um zu bauen und später die Dinge zu vereinfachen realisieren, aber wenn mein Code zum statischen Einführung baut ich eine Tonne Linker Warnungen eingeführt und die Build war unglaublich langsam für die statische baut. Am Ende habe ich eine Reihe solcher Warnungen eingeführt ...Und ich habe die manuelle Spezifikation von verwendet
Additional Dependencies
, um den Linker für die dynamischen Builds zufrieden zu stellen und gleichzeitig die statischen Builder zufrieden zu stellen, indem ich keine gemeinsame Eigenschaft verwendet habe, die sie verlangsamt. Wenn ich den Build für dynamische Teilmengen bereitstelle, stelle ich nur die DLL-Dateien bereit, da diese lib-Dateien nur zur Verbindungszeit und nicht zur Laufzeit verwendet werden.quelle
Es gibt drei Arten von Bibliotheken: statische, gemeinsam genutzte und dynamisch geladene Bibliotheken.
Die statischen Bibliotheken werden in der Verknüpfungsphase mit dem Code verknüpft, sodass sie sich tatsächlich in der ausführbaren Datei befinden, im Gegensatz zur gemeinsam genutzten Bibliothek, die nur Stubs (Symbole) enthält, nach denen in der gemeinsam genutzten Bibliotheksdatei gesucht werden muss, die zur Laufzeit vor dem geladen wird Hauptfunktion wird aufgerufen.
Die dynamisch geladenen sind den gemeinsam genutzten Bibliotheken sehr ähnlich, außer dass sie geladen werden, wenn und wenn der von Ihnen geschriebene Code dies erfordert.
quelle
LoadLibrary()
und die zugehörigen APIs geladen .Hier sind einige verwandte MSDN-Themen, um meine Frage zu beantworten:
Verknüpfen einer ausführbaren Datei mit einer DLL
Implizite Verknüpfung
Bestimmen, welche Verknüpfungsmethode verwendet werden soll
Erstellen einer Importbibliothek und Exportieren einer Datei
quelle