10.2. Verwaltung der Module
10.2.1. Aufbau der Modulketten
Die einzelnen residenten Module werden über zwei Ketten miteinander verbunden. Eine Kette ist iterativ, d.h. vorwärts gerichtet, die andere rekursiv, also rückwärts gerichtet. Was dies genau bedeutet, kann am besten an einem kleinen Beispiel aus der Praxis veranschaulicht werden :
Die Applikation DASM32 benötigt zwei DLLs, um korrekt ausgeführt zu werden : CRTD.DLL und SYS4G.DLL. Beide DLLs befinden sich im BIN-Verzeichnis nach der Installation, also dort, wo sich auch alle anderen DiceRTE-Anwendungen befinden. Das DASM32-Modul in der Programmdatei besteht aus insgesamt 4 Objektimages: '.text' (=Codesegment), '.data' (=initialisierte Daten), '.reloc' (=Relokationstabelle) und '.idata'. Nachdem alle Images eingeladen wurden, wird das Modul 'DASM32' an die iterative Modulkette gehängt (in diesem Fall ist es noch das einzige Modul). Nachdem die Relokation anhand des '.reloc'-Objekts durchgeführt wurde, wird das '.idata'-Objekt analysiert. Hier sind nun die beiden DLLs und die aus ihnen benötigten Symbole aufgelistet. Der Programmlader beginnt nun seine Suche nach der ersten DLL (CRTD.DLL) in der iterativen Liste. Da sie noch nicht vorhanden ist, wird sie aus dem BIN-Verzeichnis eingeladen. Nun spielt sich dasselbe wie oben ab: die Objektimages von CRTD.DLL werden geladen, das Modul wird an die iterative Kette gehängt, die Relokation wird durchgeführt und das Importimage wird analysiert. Hier sind nun Referenzen auf Symbole aus SYS4G.DLL aufgelistet. Das Spiel beginnt nun wieder von vorne :
Am Ende dieses (ziemlich komplexen) Vorgangs stehen also zwei Modulketten, die die Abhängigkeiten zwischen den einzelnen Modulen widerspiegeln. Aufgrund des obigen Algorithmus wird ein Modul also immer vor der Auflösung seines Importimages an die iterative und danach an die rekursive Modulkette gehängt.
Die rekursive Kette dient dazu, Abhängigkeiten zwischen einzelnen Modulen zu berücksichtigen, was bei der folgenden Ausführung der DllInit-Funktionen äußerst wichtig ist. So ist es in diesem Beispiel wichtig, daß zuerst das Modul SYS4G.DLL initialisiert wird, da es selbst keine Abhängigkeiten vorzuweisen hat. Danach kommt CRTD.DLL, da es auf SYS4G.DLL-Symbolen basiert und schließlich DASM32, das von beiden vorherigen Modulen abhängig ist. Die Module werden also bei der nun folgenden Initialisierung in der Reihenfolge der rekursiven Kette durchgearbeitet.
Die iterative Kette dient dazu, bei der Auflösung externer Referenzen bereits eingeladene Module zu finden. Die fertige Verarbeitung des Importimages dieser gesuchten Module ist dabei irrelevant. Ferner dient die iterative Kette zur Ausführung der DllExit-Funktionen, da hier die Module in umgekehrter Reihenfolge entfernt werden müssen.
Die DllInit-Funktion dient dazu, Variablen einer DLL zu initialisieren, bevor deren
Funktionen verwendet werden. Hier können z.B. Dateien geöffnet,
Speicherbereiche reserviert und Datenstrukturen gefüllt werden. Die Funktion bekommt
keine Parameter übergeben, muß aber einen Integer-Rückgabewert liefern,
der anzeigt, ob die Initialisierung erfolgreich war ( <>3 ) oder nicht
( =3 ). Liefert eine der DllInit-Funktionen den Wert 3 zurück, wird die
Ausführung sofort abgebrochen und die DllExit-Funktion der bereits aktivierten
Module in umgekehrter Reihenfolge ausgeführt. Dadurch kann verhindert werden, daß
die Applikation ausgeführt wird, obwohl die Initialisierung einer
oder mehrerer DLLs fehlgeschlug (z.B. Datei konnte nicht angelegt werden, kein
Speicher mehr frei etc.).
Die DllExit-Funktionen bekommen den Rückgabewert der
jeweiligen DllInit-Funktion als Integer-Parameter übergeben. Einen Rückgabewert
gibt es hier nicht, da das Scheitern einer Aktion hier keine Konsequenzen für die
Ausführung der folgenden DllExits hat, denn diese sind in umgekehrter Reihenfolge
voneinander abhängig. Die DllInit und -Exit-Funktionen können (wie in C
üblich) auch mit exit oder
abort beendet werden.
10.2.3. Struktur residenter Module
Die Struktur eines geladenen und im Speicher resident installierten Moduls ist identisch mit der Struktur innerhalb der Programmdatei. Am Anfang befindet sich also wieder der Kopfsatz (256 Bytes), gefolgt von der Objekttabelle und den Objektimages. Die ersten 204 Bytes im Kopfsatz entsprechen den Daten aus der Programmdatei, dahinter sind nun die folgenden Felder :
Offset | Typ | Bedeutung |
204 | Dword | Applikations-ID |
208 | Byte[16] | Modulname (terminiert mit '\0') |
224 | Dword | nächstes Modul (iterative Kette) |
228 | Dword | nächstes Modul (rekursive Kette) |
232 | Dword | Rückgabewert von DllInit |
236 | Dword[5] | momentan unbenutzt |
256- | ??? | Objekttabelle |