10.1. Das Programmdateiformat
Ausführbare DiceRTE-Programme, die von BIND2EXE
erzeugt wurden, bestehen aus mehreren Komponenten, von denen die eigentliche
Applikation nur ein Teil ist. Eine ausführbare DiceRTE-Programmdatei besitzt
das folgende Format :
10.1.1. Startup-Code
Der Startup-Code ist der Programmteil, der die gesamte Initialisierung
und Vorbereitung zur Ausführung der eigentlichen Applikation vornimmt.
Im einzelnen werden folgende Schritte durchgeführt :
-
Ermittlung des Betriebssystems und Prüfung des jeweiligen Speichermanagers
Als Betriebssysteme kommen MS-DOS ab Version 5.0, Windows 3.x (Standard-
oder Erweiterter-Modus)/ 95 / 98 / ME / 2000 / NT 3.x/4.0 und OS/2 3.x/4.x in Frage. Unter
MS-DOS können folgende Speichermanagertypen eingesetzt werden : XMS
(z.B. HIMEM.SYS ohne EMM386.EXE), VCPI (z.B. EMM386.EXE), DPMI (bereits
laufender Extender, siehe 10.1.2.DOS-Extender") oder INT15 (=BIOS)
als Speichermanager. Alle anderen oben genannten Betriebssysteme besitzen bereits einen
eingebauten DPMI-Host.
-
Bestimmung des Prozessortyps
Als Minimum ist ein 80386- oder kompatibler Prozessor zwingend erforderlich.
Nach oben sind keine Grenzen gesetzt, solange die CPU 80386-kompatibel
ist.
-
Installierung des eigenen DPMI-Hosts, falls ein solcher noch nicht
vorhanden ist
Wurde kein bereits laufender DPMI-Host gefunden, wird der DOS-Extender
mit eigener DPMI-Schnittstelle initialisiert.
-
Umschaltung des Clients in den 32Bit-Protected Mode
Die Umschaltung in den Protected Mode geschieht über einen standardisierten
Funktionsaufruf über den DPMI-Host und durch das Anlegen von 32Bit-Segmentbeschreibern.
-
Reservierung des benötigten Speichers und Installation der Verwaltungsstrukturen
Als Minimum werden 2MB erweiterter Speicher benötigt, um die
benötigten Tabellen zu installieren. Wieviel darüber hinaus gebraucht
wird, hängt vom Speicherbedarf der Applikation und der DLLs ab. Ist
nicht genug Speicher verfügbar, bricht der Startup-Code an dieser
Stelle ab.
-
Initialisierung der Beschreiber für die Applikation
Es werden zwei Beschreiber für die Applikation eingerichtet :
einer für das Codesegment und ein zweiter für das Datensegment.
Beide Beschreiber werden mit einer Größe von 4G und der Basisadresse
Null initialisiert. Damit läuft die Applikation im reinen Flat-Speichermodell,
was prinzipiell einer Ausschaltung der Segmentierung gleichkommt. Im weiteren
wird der vorher reservierte Datensegment-Selektor den fünf Segmentregistern
DS, ES, FS, GS und SS zugewiesen (dies ist auch die Grundvoraussetzung zur Ausführung
von C-Funktionen).
-
Einladen der Applikation und aller referenzierten DLLs
Der Startup-Code übergibt nun die Kontrolle an den Programmlader,
der zunächst die Applikation aus der Programmdatei extrahiert und
in den Speicher lädt. Danach werden die einzelnen Importdaten der
Applikation durchgegangen und dabei alle DLLs geladen, die benötigt
werden. Nach einer DLL wird in folgender Reihenfolge gesucht :
-
Suche in der Programmdatei nach der integrierten DLL
-
Suche im aktuellen Verzeichnis
-
Suche im Verzeichnis, in dem sich die Programmdatei befindet
-
Suche im Verzeichnis, das in der Umgebungsvariable DICERTEHOME angegeben
wurde
Nachdem alle DLLs geladen wurden, werden die 'DllInit'-Funktionen der
DLLs aufgerufen. Der Programmlader hat damit seine Aufgabe erfüllt
und gibt die Ausführung an den Startup-Code zurück. Eine genaue
Beschreibung über das Einladen und Verwalten von DLLs wird in
Abschnitt 10.2. gegeben.
-
Applikation ausführen
Nachdem die Applikation mit allen DLLs vorbereitet wurde, wird Sie
vom Startup-Code ausgeführt. Dazu werden vorher die beiden Register
EAX und EDX mit Zeigern auf den Namen der Programmdatei und den String
mit den Kommandozeilenparametern gefüllt. Der Start des Programms
geschieht über einen FAR-Sprung mit Segment und 32Bit-Offset. Das
aufgerufene Programm muß die Ausführung daher mit einem FAR-Return
an den Startup-Code zurückgeben.
DLL-Module entfernen
Nach Beendigung der Applikation werden die 'DllExit'-Funktionen der
einzelnen DLLs aufgerufen und diese danach aus dem Speicher entfernt.
-
Speicher aufräumen und Zurückschalten in den DOS-Modus
Im letzten Schritt wird der Speicher für die Systemstrukturen
freigegeben, der eventuell installierte DOS-Extender entfernt und das Programm beendet.
10.1.2. DOS-Extender
Zu den Aufgaben des DOS-Extenders zählt hauptsächlich die
Verwaltung der Interrupts und des Speichers. Zur Herstellung einer Schnittstelle
zwischen einer Applikation und dem DOS-Extender wurde das DPMI
(DOS Protected Mode Interface) in der Version 0.9 herangezogen, um so Kompatibilität
zu anderen DOS-Extendern zu wahren. Das DPMI ist eine vom DPMI-Kommitee
genormte Schnittstelle, die einem DPMI-Client (einer Applikation) bestimmte
Funktionen durch einen DPMI-Host (dem DOS-Extender) zur Verfügung
stellt. Dazu gehören Funktionen zur Speicher-, Interrupt- und Deskriptorenverwaltung
sowie Funktionen zur Umschaltung zwischen Protected- und Real Mode sowie
Ausführung von Routinen im Protected- und Real Mode. Zum genauen Studium
der einzelnen DPMI-Funktionen konsultieren Sie bitte die entsprechende
Dokumentation.
10.1.3. Modulverzeichnis
Hinter dem Startup-Code und dem DOS-Extender befindet sich das Modulverzeichnis. Es
enthält Informationen über den Namen, Offset, Typ und die Größe der einzelnen
integrierten Module. Vor dem eigentlichen Modulverzeichnis ist ein Dword, das die
Länge des Verzeichnisses enthält. Jeder Eintrag im folgenden Modulverzeichnis
umfaßt 32 Bytes :
Offset |
Typ |
Bedeutung |
+0 |
BYTE[16] |
Name des Moduls |
+16 |
DWORD |
physikalischer Offset des Moduls in Programmdatei |
+20 |
DWORD |
physikalische Größe des Moduls in Programmdatei |
+24 |
BYTE |
Modultyp (1:Applikation, 0:DLL) |
+25 |
BYTE[3] |
reserviert |
+28 |
DWORD |
reserviert |
10.1.4. Module
Hinter dem Modulverzeichnis befinden sich die einzelnen Module. Neben der eigentlichen
Applikation können bis zu 64 weitere Module/DLLs in die Programmdatei integriert werden.
Dadurch ist es möglich, die Applikation fest an bestimmte DLLs zu binden.
Jedes einzelne Modul besteht aus einem Kopfsatz, einer Objekttabelle und einigen
Objektimages. Das Format der einzelnen Module entspricht im Prinzip den vom Linker
erzeugten PE-Programmdateien, aus denen BIND2EXE diese DiceRTE-Programmdatei erstellt
hat. Der Kopfsatz umfaßt hier allerdings 256 statt 248 Bytes. Die ersten 200
Bytes sind identisch mit dem Kopfsatz der ursprünglichen PE-Programmdatei. Dahinter
folgt ein DWORD, das die Größe des DOS-Teils der PE-Programmdatei enthält.
Die restlichen 52 Bytes sind für spätere Erweiterungen reserviert.
Hinter dem Kopfsatz folgt die Objekttabelle. Sie wurde 1:1 aus der PE-Programmdatei
entnommen, genau wie die dahinter folgenden Objektimages.