Da DLLs im Wesentlichen die gleichen wie EXEs sind, ist die Wahl, welche als Teil des Verknüpfungsprozesses erzeugt werden soll, der Klarheit halber, da es möglich ist, Funktionen und Daten von beiden zu exportieren.
Es ist nicht möglich, eine DLL direkt auszuführen, da das Betriebssystem eine EXE-Datei benötigt, um sie über einen Einstiegspunkt zu laden, weshalb Dienstprogramme wie RUNDLL vorhanden sind.EXE oder RUNDLL32.EXE, die den Einstiegspunkt und das minimale Framework für DLLs bieten, die genügend Funktionen enthalten, um ohne viel Unterstützung ausgeführt zu werden.,
DLLs bieten einen Mechanismus für gemeinsam genutzten Code und Daten, der es einem Entwickler von gemeinsam genutztem Code/Daten ermöglicht, die Funktionalität zu aktualisieren, ohne dass Anwendungen neu verknüpft oder neu kompiliert werden müssen. Aus Sicht der Anwendungsentwicklung können Windows und OS/2 als eine Sammlung von DLLs betrachtet werden, die aktualisiert werden, sodass Anwendungen für eine Version des Betriebssystems in einer späteren Version funktionieren können, vorausgesetzt, der Betriebssystemhersteller hat sichergestellt, dass die Schnittstellen und Funktionen kompatibel sind.,
DLLs werden im Speicherbereich des aufrufenden Prozesses und mit den gleichen Zugriffsberechtigungen ausgeführt, was bedeutet, dass ihre Verwendung wenig Aufwand verursacht, aber auch, dass die aufrufende EXE keinen Schutz bietet, wenn die DLL einen Fehler aufweist.
Speicherverwaltungedit
In der Windows-API sind die DLL-Dateien in Abschnitte unterteilt. Jeder Abschnitt verfügt über einen eigenen Satz von Attributen, z. B. schreibbar oder schreibgeschützt, ausführbar (für Code) oder nicht ausführbar (für Daten) usw.,
Der Code in einer DLL wird normalerweise von allen Prozessen gemeinsam genutzt, die die DLL verwenden.das heißt, sie belegen einen einzigen Platz im physischen Speicher und belegen keinen Speicherplatz in der Seitendatei. Windows verwendet keinen positionsunabhängigen Code für seine DLLs; Stattdessen wird der Code beim Laden verschoben, wobei Adressen für alle seine Einstiegspunkte an Orten festgelegt werden, die im Speicherplatz des ersten Prozesses zum Laden der DLL frei sind., In älteren Windows-Versionen, in denen alle laufenden Prozesse einen einzigen gemeinsamen Adressraum belegen, reicht für alle Prozesse immer eine einzige Kopie des DLL-Codes aus. In neueren Windows-Versionen, die für jedes Programm separate Adressräume verwenden, ist es jedoch nur möglich, dieselbe verlagerte Kopie der DLL in mehreren Programmen zu verwenden, wenn jedes Programm dieselben virtuellen Adressen hat, die für den DLL-Code frei sind., Wenn einige Programme (oder deren Kombination bereits geladener DLLs) diese Adressen nicht frei haben, muss eine zusätzliche physische Kopie des DLL-Codes erstellt werden, wobei ein anderer Satz verlagerter Einstiegspunkte verwendet wird. Wenn der physische Speicher, der von einem Codeabschnitt belegt wird, zurückgewonnen werden soll, wird sein Inhalt verworfen und später bei Bedarf direkt aus der DLL-Datei neu geladen.
Im Gegensatz zu Codeabschnitten sind die Datenabschnitte einer DLL normalerweise privat; Das heißt, jeder Prozess, der die DLL verwendet, hat eine eigene Kopie aller DLL-Daten., Optional können Datenabschnitte gemeinsam genutzt werden, was eine prozessübergreifende Kommunikation über diesen freigegebenen Speicherbereich ermöglicht. Da Benutzerbeschränkungen jedoch nicht für die Verwendung von gemeinsam genutztem DLL-Speicher gelten, entsteht eine Sicherheitslücke.nämlich, ein Prozess kann die gemeinsam genutzten Daten beschädigen, was wahrscheinlich dazu führt, dass sich alle anderen Freigabeprozesse unerwünscht verhalten. Beispielsweise kann ein Prozess, der unter einem Gastkonto ausgeführt wird, auf diese Weise einen anderen Prozess beschädigen, der unter einem privilegierten Konto ausgeführt wird. Dies ist ein wichtiger Grund, um die Verwendung freigegebener Abschnitte in DLLs zu vermeiden.,
Wenn eine DLL von bestimmten ausführbaren Packern (z. B. UPX) komprimiert wird, werden alle Codeabschnitte als Lesen und Schreiben markiert und nicht geteilt. Lese – und Schreibcodeabschnitte, ähnlich wie private Datenabschnitte, sind für jeden Prozess privat. Daher sollten DLLs mit gemeinsam genutzten Datenabschnitten nicht komprimiert werden, wenn sie gleichzeitig von mehreren Programmen verwendet werden sollen, da jede Programminstanz eine eigene Kopie der DLL tragen müsste, was zu einem erhöhten Speicherverbrauch führt.
Import librariesEdit
Wie statische Bibliotheken werden Importbibliotheken für DLLs von der notiert .,lib-Dateierweiterung. Für Beispiel, kernel32.dll, die primäre dynamische Bibliothek für Windows-Basisfunktionen wie Dateierstellung und Speicherverwaltung, ist über kernel32 verknüpft.lib. Die übliche Methode, um eine Importbibliothek aus einer richtigen statischen Bibliothek anzuzeigen, ist die Größe: Die Importbibliothek ist viel kleiner, da sie nur Symbole enthält, die sich auf die tatsächliche DLL beziehen und zur Verknüpfungszeit verarbeitet werden sollen. Beide Dateien sind Unix-AR-Format-Dateien.
Das Verknüpfen mit dynamischen Bibliotheken wird normalerweise durch Verknüpfen mit einer Importbibliothek beim Erstellen oder Verknüpfen zum Erstellen einer ausführbaren Datei behandelt., Die erstellte ausführbare Datei enthält dann eine Importadressentabelle (IAT), mit der auf alle DLL-Funktionsaufrufe verwiesen wird (jede referenzierte DLL-Funktion enthält einen eigenen Eintrag im IAT). Zur Laufzeit wird der IAT mit entsprechenden Adressen gefüllt, die direkt auf eine Funktion in der separat geladenen DLL verweisen.
In Cygwin/MSYS und MinGW erhalten Importbibliotheken üblicherweise das Suffix .dll.a
, wobei sowohl das Windows-DLL-Suffix als auch das Unix-ar-Suffix kombiniert werden., Das Dateiformat ist ähnlich, aber die Symbole, die zum Markieren der Importe verwendet werden, sind unterschiedlich (_head_foo_dll vs __IMPORT_DESCRIPTOR_foo). Obwohl seine GNU Binutils Toolchain Importbibliotheken generieren und mit ihnen verknüpfen kann, ist es schneller, direkt auf die DLL zu verlinken. Ein experimentelles Tool in MinGW namens genlib kann verwendet werden, um Import-Bibliotheken mit MSVC-Symbolen zu generieren.
Symbolauflösung und bindingEdit
Jede von einer DLL exportierte Funktion wird durch eine numerische Ordnungszahl und optional einen Namen identifiziert. Ebenso können Funktionen entweder ordinal oder namentlich aus einer DLL importiert werden., Die Ordnungszahl stellt die Position des Adresszeigers der Funktion in der DLL-Exportadressentabelle dar. Es ist üblich, dass interne Funktionen nur nach Ordinal exportiert werden. Für die meisten Windows-API-Funktionen bleiben nur die Namen in verschiedenen Windows-Versionen erhalten; Die Ordinale können sich ändern. Daher kann man Windows-API-Funktionen nicht zuverlässig nach ihren Ordinalen importieren.
Das Importieren von Funktionen nach Ordinal bietet nur eine geringfügig bessere Leistung als das Importieren nach Namen: Exporttabellen von DLLs sind nach Namen geordnet, sodass eine binäre Suche zum Auffinden einer Funktion verwendet werden kann., Der Index des gefundenen Namens wird dann verwendet, um die Ordnungszahl in der Exportordnungstabelle nachzuschlagen. In 16-Bit-Fenstern wurde die Namenstabelle nicht sortiert, sodass der Overhead der Namenssuche viel deutlicher wurde.
Es ist auch möglich, eine ausführbare Datei an eine bestimmte Version einer DLL zu binden, dh die Adressen importierter Funktionen zur Kompilierungszeit aufzulösen. Bei gebundenen Importen speichert der Linker den Zeitstempel und die Prüfsumme der DLL, an die der Import gebunden ist. Zur Laufzeit überprüft Windows, ob dieselbe Version der Bibliothek verwendet wird, und wenn ja, umgeht Windows die Verarbeitung der Importe., Andernfalls verarbeitet Windows die Importe auf normale Weise, wenn sich die Bibliothek von der Bibliothek unterscheidet, an die gebunden wurde.
Gebundene ausführbare Dateien werden etwas schneller geladen, wenn sie in derselben Umgebung ausgeführt werden, für die sie kompiliert wurden, und genau zur gleichen Zeit, wenn sie in einer anderen Umgebung ausgeführt werden. Beispielsweise sind alle Standard-Windows-Anwendungen an die System-DLLs ihrer jeweiligen Windows-Version gebunden. Eine gute Möglichkeit, die Importe einer Anwendung an ihre Zielumgebung zu binden, besteht während der Installation der Anwendung., Dadurch bleiben die Bibliotheken bis zum nächsten Betriebssystemupdate „gebunden“. Es ändert jedoch die Prüfsumme der ausführbaren Datei, sodass dies nicht mit signierten Programmen oder Programmen möglich ist, die von einem Konfigurationsmanagementtool verwaltet werden, das Prüfsummen (z. B. MD5-Prüfsummen) zum Verwalten von Dateiversionen verwendet. Da neuere Windows-Versionen (aus Sicherheitsgründen) keine festen Adressen für jede geladene Bibliothek mehr haben, nimmt die Möglichkeit und der Wert der Bindung einer ausführbaren Datei ab.,
Explizite Laufzeitverknüpfungedit
DLL-Dateien können zur Laufzeit explizit geladen werden, ein Prozess, der von Microsoft einfach als dynamische Laufzeitverknüpfung bezeichnet wird, indem die API-Funktion LoadLibrary
(oder LoadLibraryEx
) verwendet wird. Die API-Funktion GetProcAddress
wird zum Nachschlagen exportierter Symbole nach Namen und FreeLibrary
zum Entladen der DLL verwendet. Diese Funktionen sind analog zu dlopen
, dlsym
und in der POSIX Standard API.,
Die Prozedur für die explizite Laufzeitverknüpfung ist in jeder Sprache, die Zeiger auf Funktionen unterstützt, dieselbe, da sie von der Windows-API und nicht von Sprachkonstrukten abhängt.
Verzögertes loadingEdit
Normalerweise kann eine Anwendung, die mit der Importbibliothek einer DLL verknüpft ist, nicht gestartet werden, wenn die DLL nicht gefunden werden kann, da Windows die Anwendung nur dann ausführt, wenn sie alle DLLs findet, die die Anwendung möglicherweise benötigt. Eine Anwendung kann jedoch mit einer Importbibliothek verknüpft werden, um ein verzögertes Laden der dynamischen Bibliothek zu ermöglichen.,In diesem Fall versucht das Betriebssystem nicht, die DLL zu finden oder zu laden, wenn die Anwendung gestartet wird; Stattdessen wird ein Stub vom Linker in die Anwendung aufgenommen, der versucht, die DLL über LoadLibrary und GetProcAddress zu finden und zu laden, wenn eine ihrer Funktionen aufgerufen wird. Wenn die DLL nicht gefunden oder geladen werden kann oder die aufgerufene Funktion nicht vorhanden ist, generiert die Anwendung eine Ausnahme, die möglicherweise abgefangen und entsprechend behandelt wird. Wenn die Anwendung die Ausnahme nicht behandelt, wird sie vom Betriebssystem abgefangen, wodurch das Programm mit einer Fehlermeldung beendet wird.,
Der Verzögerungslademechanismus bietet auch Benachrichtigungs-Hooks, mit denen die Anwendung beim Laden der DLL und/oder beim Aufruf einer DLL-Funktion zusätzliche Verarbeitungs-oder Fehlerbehandlungen durchführen kann.
Schreibe einen Kommentar