home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Power-Programmierung
/
CD1.mdf
/
assemblr
/
disasm
/
re86
/
r86.doc
< prev
next >
Wrap
Text File
|
1993-07-27
|
29KB
|
661 lines
■══════════════════════════════════■
║ ║
║ R86 Reassembler Version 1.00 ║
║ ║
■══════════════════════════════════■
Copyright (c) 1992 Stefan Bion
Bruktererstraße 2
5000 Köln 21
Tel. 0221/881825
Germany
Dieses Programm ist "Freeware" (nicht Public Domain!), d.h. es darf
frei kopiert und in unmodifizierter Form weitergegeben werden. Eine
Registrierungsgebühr ist für die private Nutzung nicht erforderlich.
Alle Rechte vorbehalten.
R86 ist ein Reassembler, der 80x86/80x87-Assembler-Quelltext aus
ausführbaren Programmdateien vom Typ .COM produziert. Im Einzeln
werden folgende Prozessoren unterstützt:
- 8088/86, 80186, 80286, NEC V20, NEC V30
- 8087, 80287, 80387, IIT-2C87
Die Syntax des generierten Quelltextes ist kompatibel zu der des
Shareware-Assemblers A86 von Eric Isaacson. Dabei werden die Verein-
fachungen verschiedener Assembleranweisungen des A86 berücksichtigt,
wie Mehrfachoperanden bei PUSH, POP, INC und DEC, oder B, W und D
statt BYTE PTR, WORD PTR und DWORD PTR. MASM oder TASM können ohne
Änderungen mit dem Quelltext nichts anfangen. Aber für diese Assembler
existieren bereits Disassembler - für A86 nicht.
Inhalt
======
1. Aufruf des Reassemblers ....................................... 2
2. Analysieren des Programmcodes ................................. 3
3. Aufbereiten des Assembler-Quelltextes ......................... 5
4. Floatingpoint-Anweisungen ..................................... 6
5. Sonderfälle ................................................... 7
6. Kapazitätsgrenzen von R86 ..................................... 9
7. Bug in A86 .................................................... 9
8. Literaturhinweise ............................................ 10
Dokumentation zu R86 Seite 1
1. Aufruf des Reassemblers
==========================
Die zum Betrieb des Reassemblers notwendigen Parameter und Schalter
werden in der Kommandozeile übergeben. Erfolgt der Aufruf des
Programms ohne Kommandozeilenparameter, dann wird ein Hilfstext in
englischer Sprache ausgegeben.
Der Reassembler wird folgendermaßen aufgerufen:
R86 [-d] [-s] infile[.COM] [outfile[.ASM]]
Dabei steht infile für den Namen der zu reassemblierenden Programm-
datei, wobei die Erweiterung .COM voreingestellt ist und nicht
explizit angegeben werden muß. Durch Angabe einer Erweiterung können
Sie diesen voreingestellten Wert überschreiben. Der Parameter infile
muß in jedem Fall immer angegeben werden. Die Programmdatei darf
maximal 64 KByte groß sein.
Der Name der zu produzierenden Quelldatei outfile ist standardmäßig
derselbe wie der der Programmdatei, jedoch mit der Endung .ASM. Durch
Angabe eines anderen Namens oder einer anderen Erweiterung können Sie
auch hier die voreingestellten Werte überschrieben werden.
Ebenfalls optional können Sie noch zwei Schalter mit angeben:
Durch Angabe des Schalters -d wird die zu reassemblierende Programm-
datei in einen Hex/ASCII-Editor geladen, der es Ihnen auf komfortable
Weise ermöglicht, die Code- und Datenbereiche zu bestimmen. Dazu
später mehr.
Der Schalter -s ist dann nützlich, wenn die produzierte .ASM-Datei
größer als 64 KByte ist. Dann nämlich kann diese von A86 nicht mehr
in einem Stück verarbeitet werden und muß in mehrere Stücke aufgeteilt
werden. Im Allgemeinen kann man sagen, daß die .ASM-Datei die rund
zehnfache Größe der .COM-Datei erreicht. Durch Angabe des Schalters
-s werden statt einer großen Quelltext-Datei mehrere kleine Dateien zu
jeweils ca. 60 kByte erzeugt, deren Erweiterungen dann mit .001, .002,
usw. fortlaufend durchnumeriert werden. Um die einzelnen Quelltext-
Teile zu assemblieren, ist A86 folgendermaßen aufzurufen:
A86 outfile.00*
In der Regel werden Sie den generierten Quelltext jedoch erst mit
einem Texteditor nachbearbeiten wollen (müssen). Damit sich Änderungen
durch die Suchen/Ersetzen-Funktion des Editors auf den gesamten Text
auswirken, sollte dieser zunächst an einem Stück abgespeichert und
erst nachher in kleinere Häppchen aufgeteilt werden.
Dokumentation zu R86 Seite 2
2. Analysieren des Programmcodes
================================
Voraussetzung für das Generieren von sinnvollem Assembler-Quelltext
ist die richtige Interpretation des Programmcodes. Bevor Sie ein
Programm mit R86 reassemblieren, müssen Sie daher bestimmen, welche
Teile der Programmdatei ausführbare Anweisungen und welche Daten
enthalten. Ohne diese Differenzierung wurden fälschlicherweise als
Programmcode interpretierte Daten unsinnigen Chaos-Code ergeben. Zwar
mögen diese Anweisungen beim Assemblieren wieder in die ursprünglichen
Bytes zurückverwandelt werden können, aber das ist in der Praxis
meistens nicht der Fall, weil nämlich für ein und dieselbe Assembler-
anweisung mehrere Codierungsmöglichkeiten bestehen. Das Ergebnis wären
falsche Daten.
Um R86 mitzuteilen, an welchen Adressen Datenbereiche welchen Typs
beginnen, und welche Bereiche als ausführbare Anweisungen interpre-
tiert werden sollen, wird eine zusätzliche Textdatei benötigt, die
nacheinander die hexadezimalen Adressen, gefolgt vom Datentyp, ent-
hält. Die Datei hat immer denselben Namen wie die zu disassemblierende
Programmdatei (infile), allerdings mit der Endung .R86. Es folgt ein
Beispiel für den Aufbau der Datei:
103 a ; ASCII-Daten beginnen bei Offset 103h
1BE w ; Word-Daten beginnen bei Offset 1BEh
1F0 b ; Byte-Daten beginnen bei Offset 1F0h
200 c ; Ausführbarer Code beginnt bei Offset 200h
In der Datei selbst dürfen keine Kommentare enthalten sein.
Die hexadezimalen Adressen in der Datei müssen aufsteigend sortiert
sein. Außerdem dürfen maximal 2048 Bereiche definiert werden (maximal
2048 Zeilen), was allerdings völlig ausreicht.
Um die einzelnen Bereiche bestimmen zu können, benötigen Sie einen
Datei-Betrachter, der den Inhalt der Programmdatei in hexadezimaler
Form und als ASCII-Zeichen darstellt. Wenn Sie geübt sind, dann wird
es für Sie nicht schwer sein, festzustellen, welche Teile der Datei
ausführbaren Programmcode enthalten und welche Daten. Textbereiche
sind an ihrem Klartext ja noch eindeutig auszumachen, ebenso mit 0
initialisierte Datenbereiche und Puffer.
Nun wäre es ja mühsam, sich den Inhalt der Datei anzusehen und dabei
die Adressen und den dazugehörigen Datentyp auf irgendeinen Zettel
aufzuschreiben, um diese dann nachher mit einem Texteditor abzutippen
und so die .R86-Datei zu erstellen. Deshalb besitzt R86 einen einge-
bauten Hex/ASCII-Dateibetrachter mit speziellen Funktionen zum bild-
schirmorientierten Bearbeiten der Datei. Sie aktivieren diesen Editor,
indem Sie beim Aufruf des Reassemblers den Schalter -d, gefolgt vom
Programmnamen, angeben.
Mit den Tasten <PgUp> und <PgDn> können Sie in der Datei bildschirm-
weise blättern (± 256 Bytes), mit <Home> und <End> gelangen Sie an den
Anfang bzw. an das Ende der Datei. Die Datei beginnt immer bei Offset
100h, da dies die Startadresse bei .COM-Programmen ist. Mit den
Cursortasten können Sie den Cursor auf eine bestimmte Byteposition
innerhalb der Datei, an der z.B. ein Datenbereich beginnt, setzen und
diese dann mit der Funktionstaste <F1> markieren. Anschließend setzen
Sie den Cursor auf das letzte Byte dieses Bereiches und markieren die
Endadresse mit Funktionstaste <F2>.
Dokumentation zu R86 Seite 3
Die Anfangs- und Endadresse des so markierten Bereiches wird in der
untersten Zeile angezeigt. Anschließend können Sie durch Eingabe des
Anfangsbuchstabens den Datentyp des markierten Bereiches bestimmen,
der dann auch farblich dargestellt wird:
a ASCII-Daten (gelb)
b Byte-Daten (grün)
c Ausführbarer Code (rot)
w Word-Daten (blau)
Falls Sie keinen Farbmonitor besitzen, können Sie sich auch an den in
der untersten Zeile angezeigten Werten (hinter "Current area:") orien-
tieren. Hier werden Anfangs- und Endadresse sowie der Datentyp des
aktuellen Bereiches angezeigt, in dem sich der Cursor gerade befindet.
Allerdings ist die farbige Anzeige wesentlich schöner, da man hier den
jeweiligen Datentyp auf einen Blick erkennt, ohne mit dem Cursor durch
die Gegend wandern zu müssen und dabei die Anzeige zu beobachten.
Haben Sie alle Bereiche bestimmt, dann können Sie den Editor mit der
<ESC>-Taste verlassen. Sie werden daraufhin gefragt, ob Sie die
eingegebenen Daten sichern wollen. Mit 'Y' oder <CR> können Sie dies
bestätigen oder aber mit 'N' oder <ESC> ablehnen. Die Daten werden in
eine Datei mit der Endung .R86 geschrieben. Bei einem erneuten Aufruf
des Reassemblers mit dem Schalter -d werden die Daten auch wieder aus
dieser Datei gelesen, so daß Sie hier Änderungen vornehmen können.
Die nächste Frage lautet, ob nun mit der Disassemblierung begonnen
werden soll oder nicht.
Wenn Sie beim ersten Analysieren nicht gleich alles identifizieren
können, dann machen Sie einfach eine Probe-Disassemblierung und sehen
sich den Quelltext in einem Texteditor an. Wenn Sie evtl. sinnlose
Anweisungen entdecken, dann haben Sie möglicherweise noch
Datenbereiche übersehen. Falls ein Label davorsteht, können Sie die
Adresse und den Datentyp direkt in die Datei infile.R86 einfügen,
ansonsten rufen Sie R86 noch einmal mit dem Schalter -d auf.
In der Regel läßt sich der Quelltext dann ohne Fehler von A86
assemblieren und funktioniert sogar, auch wenn ein byteweiser
Vergleich Unterschiede ergibt. Letzteres ist meistens dann der Fall,
wenn die Original-Programmdatei von MASM oder TASM erzeugt wurde, und
nicht von A86 selbst. In Verbindung mit dem sogenannten ModRM-Byte,
welches die Adressierungsart eines Assemblerbefehls festlegt, kann ein
und derselbe Befehl nämlich mit unterschiedlichen Opcodes codiert
werden. Eric Isaacson benutzt bei seinem A86 ein eigenes System, die
Befehle zu codieren, um daran erkennen, ob ein beliebiges Programm von
seinem Assembler übersetzt worden ist, oder nicht ("footprint").
Die Größe der ursprünglichen und der neu übersetzten Programmdatei muß
allerdings dieselbe sein, sonst brauchen Sie das Programm gar nicht
erst zu starten. Dann nämlich sind bestimmte Bereiche des Programms
verschoben, und durch falsche Referenzierung kommt es dann zu Fehlern.
Bevor Sie in einem solchen Fall mit dem im Folgenden beschriebenen
Aufbereiten des Assembler-Quelltextes weitermachen, untersuchen Sie
den Quelltext noch einmal auf Datenbereiche, die Sie vielleicht
übersehen haben, oder auf zweideutige Anweisungen (Kapitel "Sonder-
fälle").
Dokumentation zu R86 Seite 4
3. Aufbereiten des Assembler-Quelltextes
========================================
Haben Sie alle Datenbereiche des Programms richtig bestimmt und dann
eine .ASM-Datei erzeugt, die auch fehlerlos assembliert wird und sogar
lauffähig ist, dann beginnt erst die eigentliche Arbeit, die Ihnen
kein Programm abnehmen kann: Das Verstehen des Programmablaufes und
möglichst das Einfügen von erklärenden Kommentaren. Kommentieren Sie
jedes Unterprogramm, beginnen Sie dabei mit den am einfachsten zu
erkennenden Teilen. Wenn Sie einmal eine Anweisung oder einen MS-DOS-
Funktionsaufruf nicht verstehen, dann sehen Sie in entsprechender
Literatur nach. Ersetzen Sie dann das Label jedes identifizierten
Unterprogramms und von Variablen, deren Funktion durch die Verwendung
im Unterprogramm offensichtlich geworden ist, mit der Suchen/Ersetzen-
Funktion Ihres Texteditors durch aussagekräftige Namen. Diese Namen
erscheinen dann auch an den Programmstellen, von denen aus sie
referenziert werden und erleichtern so die Identifizierung weiterer
Programmteile.
Wollen Sie außerdem selbst Änderungen und Erweiterungen an dem
Programm vornehmen, dann ist es unerläßlich, den Quelltext zuvor
entsprechend aufzubereiten. Eine Hauptaufgabe dabei ist es, Symbole
durch Festwerte zu ersetzen, wo dies nötig ist. Hierzu zunächst
einige Erläuterungen:
Beim Generieren von Assembler-Quelltext geht R86 in zwei Schritten
vor: Beim ersten Durchgang werden alle Word-Referenzen in einer
internen Tabelle gespeichert. Anschließend wird im zweiten Durchgang
der Quelltext in die Ausgabedatei geschrieben und die Referenzen dabei
durch Symbole bzw. Labels ersetzt. Als Referenzen werden alle Sprung-
ziele (bedingte Sprünge, JMP, CALL, LOOP) und alle 16-Bit-Direkt-
operanden (falls größer als 0FFh) angesehen. Bei den Direktoperanden
kann R86 allerdings nicht wissen, ob der Programmierer damit einen
festen Wert oder eine Offsetadresse innerhalb des Programms gemeint
hat. Beispiel:
mov ax,offset l2523h
mov dx,offset l0653h
int 21h
Der geübte Assembler-Programmierer wird sofort erkennen, daß l2523h
ein Festwert ist (DOS-Funktion 25h, Interruptvektor 23h setzen), und
l0653h eine Referenz (Offsetadresse des Int-23h-Handlers). Beim
nachträglichen Bearbeiten des Quelltextes mit einem Editor gilt es
nun, alle Symbole, die eigentlich Festwerte sind, zu entfernen. Im
obigen Beispiel würden Sie die erste Zeile also ändern in:
mov ax,2523h
Das Label l2523h, das irgendwo im Programm definiert ist, kann dann
gelöscht werden. Erst dann, wenn kein Festwert mehr als vermeintliche
Referenzadresse angegeben ist und deren Werte somit nicht mehr von der
Adresse der Labels im Programm abhängen, dürfen Sie Ergänzungen am
Programm vornehmen. Denn würden Sie beispielsweise hinter den obigen
drei Quelltextzeilen einige Anweisungen einfügen, dann würden sich
auch die Offsetadressen aller nachfolgenden Symbole verschieben.
Dokumentation zu R86 Seite 5
Auch Festwerte, die als Symbol angegeben sind, bekämen einen anderen
Wert zugewiesen. Bei einer Verschiebung um 3 Bytes würde das Symbol
l2523h z.B. den Wert 2526h repräsentieren, so daß nun nicht mehr Int
23h, sondern Int 26h verbogen werden würde. Aus diesem Grund ist es
auch nicht ratsam, das Programm zu starten, wenn sich dessen Größe von
der Größe der ursprünglichen Programmdatei unterscheidet und der von
R86 erzeugte Quelltext noch nicht dahingehend geändert wurde.
Normalerweise jedoch ist die Größe der ursprünglichen und der neu
übersetzten Programmdatei dieselbe. Nur in Sonderfällen dürften sich
Unterschiede ergeben - doch dazu mehr im Kapitel "Sonderfälle".
4. Floatingpoint-Anweisungen
============================
Assembleranweisungen für den mathematischen Coprozessor bis hin zum
80387 werden von R86 ebenfalls disassembliert. Außerdem wird der IIT-
2C87 unterstützt (dies entspricht exakt dem Sprachumfang von A86 in
der Version 3.22). Wenn R86 eine Coprozessor-Anweisung in der
Programmdatei entdeckt, wird zu Beginn des Quelltextes die .287-
Direktive ausgegeben.
Beim Coprozessor 8087 mußte noch vor jede Anweisung ein FWAIT-Befehl
geschrieben werden (ein Byte, 9Bh). Bei den neueren Prozessoren ab dem
80287 ist dies nicht mehr erforderlich. MASM, TASM und A86 codieren
implizit vor jede Coprozessor-Anweisung dieses FWAIT-Byte. Bei A86
läßt sich dies aber durch Angeben der Direktive .287 oder durch Aufruf
mit dem Schalter +F abschalten.
Wenn in der von R86 disassemblierten Programmdatei FWAIT-Anweisungen
enthalten sind, dann werden diese immer explizit ausgegeben. Durch die
.287-Direktive wird bewirkt, daß A86 die FWAITs bei den Floatingpoint-
Befehlen nicht nochmal codiert. Sie können die Direktive und alle
FWAITS, die direkt vor Coprozessor-Anweisungen stehen, auch entfernen.
Dokumentation zu R86 Seite 6
5. Sonderfälle
==============
Das Rückübersetzen von Maschinencode in Assembleranweisungen kann
manchmal eine knifflige Angelegenheit sein. Es existieren theoretisch
einige Sonderfälle, in denen der Assembler die Anweisungen anders
interpretiert, als sie gemeint sind, so daß sich der vom Assembler
produzierte Code vom Original unterscheidet.
Häufig benutzte Anweisungen des 8086-Prozessors existieren z.B. zu-
sätzlich zur Normalform auch in einer Kurzform. Dazu gehören u.a. die
Anweisungen "MOV Register,Direktoperand" (Opcodes B0...BF), welche
auch mit den Opcodes C6 und C7 codiert werden können, was aber wegen
des zusätzlichen ModRM-Bytes um 1 Byte länger und außerdem langsamer
wäre. Für Befehle, die das Register AX bzw. AL als Operand haben,
existiert vielfach neben der Langform auch ein extra Opcode ohne das
ModRM-Byte zum Auswählen der Adressierungsart. Manchmal ist es pro-
grammtechnisch jedoch erforderlich, die Langform zu verwenden. Da
beide Formen dieselbe Schreibweise besitzen, können sie bei einem
disassemblierten Quelltext äußerlich nicht mehr unterschieden werden.
Um explizit die Langform eines Befehls zu codieren, müssen die Opcodes
in Form von Bytes mit der DB-Anweisung oder mit Hilfe eines Macros
angegeben werden. A86 und auch die anderen Assembler versuchen immer,
eine Anweisung mit so wenigen Bytes wie möglich zu codieren.
Langformen von Anweisungen werden von R86 kommentiert, wobei der
tatsächlich verwendete Opcode angegeben wird. Falls die Verwendung der
Langform für den Programmablauf wichtig ist und beibehalten werden
muß, dann sollten Sie die entsprechenden Bytes von Opcode und Operand
als Datenbereich definieren (DB- oder DW-Anweisung). Ansonsten können
Sie nach der betreffenden Anweisung ein NOP einfügen, um eine
Verschiebung der nachfolgenden referenzierten Offsetadressen zu
vermeiden. Letzteres kann jedoch entfallen, falls Sie bei Festwerten
als Direktoperanden die Symbole entfernt haben, so daß deren Werte
nicht mehr von der Adresse der Labels im Programm abhängen.
Auch effektive Adressen als Operanden einer Anweisung, bei denen das
Displacement 0 beträgt, werden vom Assembler in die kürzere Form ohne
Displacement übersetzt. Die Anweisung "mov al,b[bx+di+0]" wird also
beispielsweise zu "mov al,b[bx+di]" (Ausnahme: Eine Kurzform von
"[bp]" existiert nicht und wird daher immer als "[bp+0]" codiert.
Falls es sich um ein 16-Bit-Displacement handelt, das jedoch kleiner
als 100h ist und somit in 8 Bit passen würde, dann wird vom Assembler
auch automatisch ein 8-Bit-Displacement codiert, womit sich schon
wieder Unterschiede in der Codelänge ergeben. Die beiden zuletzt
geschilderten Fälle sind mir jedoch in der Praxis noch nicht begegnet.
Bei Direktoperanden gibt es noch eine Besonderheit, die beachtet
werden muß: A86 interpretiert diese als vorzeichenbehaftete Integer-
werte, was manchmal zu überraschenden Ergebnissen führen kann. Dazu
ein Beispiel: Ein Programm enthält die Anweisung
cmp bx,0FFF7h
Dokumentation zu R86 Seite 7
Assembliert man diese Anweisung, dann codiert A86 daraus die drei
Bytes 83 FB F7, was jedoch wieder disassembliert die Anweisung
cmp bx,0F7h
ergeben würde. Diese Anweisung wiederum assembliert ergibt jedoch
diesmal vier Bytes, und zwar 81 FB F7 00. Der Grund ist, daß A86 die
Zahl 0FFF7h als vorzeichenbehaftete Integerzahl mit dem Wert -9 be-
trachtet. Den Wert -9 kann man aber auch als 8-Bit-Integer darstellen
(0F7h). Der 80x86 kennt zudem für verschiedene Anweisungen, die als
ersten Parameter einen Word-Operanden haben, zwei unterschiedliche
Opcodes: Opcode 81h mit einem 16-Bit-Direktoperanden als zweitem
Parameter und Opcode 83h mit einem 8-Bit-Direktoperanden als zweitem
Parameter. Da -9 gleich -9 ist, codiert A86 die kürzere beider
Sequenzen. Der Ausdruck "0F7h" ist für A86 allerdings eine positive
Zahl und wird daher in 16 Bit (1 Word) dargestellt (der *Wert* 0F7h
wäre ja -9). Statt mit negativen Zahlen zu hantieren, gibt R86 in
solchen Fällen einfach zwei hexadezimale Fs vor der betreffenden Zahl
aus, was in vielen Fällen übersichtlicher ist.
Die folgende Tabelle faßt die Interpretation von vorzeichenbehafteten
Bytes (XX) bzw. Words (XXXX) durch A86 noch einmal zusammen:
| Schreibweise | Interpretation | Codierung | Opcode
----+-----------------+-------------------+--------------+--------
| | | |
1.) | 00...7F | 0...7F | 00...7F | 83
2.) | 80...FF | 80...FF | 0080...00FF | 81
| | | |
3.) | 0000...007F | 0...7F | 00...7F | 83
4.) | 0080...FF7F | 80...FF7F | 0080...FF7F | 81
5.) | FF80...FFFF | -80...-1 | 80...FF | 83
Im Fall 3.) in der Tabelle fügt R86 direkt hinter dem betreffenden
Befehl den Aufruf eines Makros "patch83" ein, welches bei Auftreten
dieses Falles am Anfang der .ASM-Datei definiert wird. Dieses Makro
sorgt dafür, daß statt des Opcodes 83h, den der Assembler aufgrund
seiner Interpretation des Operanden nehmen würde, der richtige Opcode
81h verwendet wird, wie es auch im Originalprogramm der Fall war.
Falls es für den Programmablauf nicht wichtig ist, können Sie dieses
Makro auch wieder entfernen.
Im Fall 5.) wird der Operand als Symbol definiert sein - aufgrund
seines hohen Wertes vermutlich irgendwo am Schluß des .ASM-Listings,
also erst nach der Verwendung dieses Symbols. Da A86 ein 1-Pass-
Assembler ist, kann er zum Zeitpunkt der Verwendung des Symbols noch
nicht wissen, welcher Wert ihm zugewiesen werden wird (Vorwärts-
referenz) und reserviert daher vorsichtshalber 1 Word für den
Operanden. A86 codiert also 5.) mit Opcode 81h, so wie es dem
Original-Programm entspricht. Ändern Sie das Symbol jedoch in einen
Festwert um, dann verwendet A86 Opcode 83h. Falls dies programm-
technisch irrelevant ist, kann Ihnen das egal sein. Ansonsten müßten
Sie entweder den Befehl byteweise mit der DB-Anweisung codieren, oder
Sie verwenden ein Makro, ähnlich patch83.
Zum Glück sind dies aber alles äußerst seltene Fälle, die eigentlich
nur dann auftreten, wenn der Programmierer mit fiesen Tricks
gearbeitet hat.
Dokumentation zu R86 Seite 8
6. Kapazitätsgrenzen von R86
============================
Die von R86 zu reassemblierende .COM-Datei darf eine maximale Größe
von 65280 (FF00h) Bytes haben und entspricht damit auch der Maximal-
größe einer .COM-Datei unter DOS. Dateien vom Typ .EXE werden von R86
nicht unterstützt, zumal auch A86 mit Multisegmentprogrammen nichts
anfangen kann.
R86 liest den gesamten Inhalt der .R86-Datei in den Hauptspeicher ein.
Dort ist Platz für 2048 Einträge reserviert - in der Datei dürfen also
maximal 2048 Adressen mit Datendefinitionen angegeben werden, was
normalerweise mehr als ausreicht.
Eine weitere Einschränkung betrifft die maximale Anzahl von Symbolen
bzw. Referenzadressen. Diese liegt bei 8192 und stellt somit ungefähr
das Doppelte von der in der Praxis benötigten Kapazität bei einer
64 KByte großen .COM-Datei dar. Außerdem ist dies mehr, als A86
verkraften kann. Eine ca. 50 KByte große .COM-Datei ergab reassem-
bliert mit dem Schalter -s beispielsweise 7½ einzelne Quelltextteile
zu je 60 KByte. A86 brach die Übersetzung bei der letzten Datei mit
der Fehlermeldung ~99 Symbol Table Overflow~ ab. Hier müßte man die
Quelltextteile dann einzeln in .OBJ-Module übersetzen lassen und zu
einer ausführbaren Datei linken.
7. Bug in A86
=============
Zum Schluß noch ein Hinweis auf einen Fehler von A86, der mir beim
Entwickeln von R86 aufgefallen ist. Bei den Datentypen Byte und Word
faßt R86 gleiche aufeinanderfolgende Werte mit dem DUP-Operator
zusammen. Bei Word-Daten werden ebenso wie bei Direktoperanden von
Assemblerbefehlen statt Festwerten Labels verwendet, sofern die Werte
größer als 100h sind, da sie Offsetadressen auf andere Programmteile
darstellen könnten. Ist der Wert größer als die Offsetadresse, an der
dieses Word definiert ist, dann ist das entsprechende Label erst
hinter dieser Offsetadresse definiert (Vorwärtsreferenz). Wenn nun ein
solches Symbol hinter einem DUP-Operator steht, dann wird nur das
erste Element dieses Feldes von A86 mit diesem Wert initialisiert und
der Rest mit 0 aufgefüllt:
dw 8 dup symbol ; => dw 1234h,0,0,0,0,0,0,0
symbol equ 1234h
dw 8 dup symbol ; => dw 1234h,1234h,1234h,1234h,
; 1234h,1234h,1234h,1234h
Aus diesem Grunde verwendet R86 den DUP-Operator außer bei Bytes nur
bei solchen Words, die kleiner als 100h sind und somit nicht durch
Symbole dargestellt werden.
Dasselbe Phänomen zeigt sich zwar auch bei Bytes, wenn ein Label
verwendet wird, das erst nach der Verwendung definiert wird. Bei
Byte-Daten setzt R86 allerdings keine Symbole ein.
Dokumentation zu R86 Seite 9
8. Literaturhinweise
====================
Die Informationen für die Entwicklung von R86 wurden aus folgenden
Quellen bezogen:
1.) DOS Extra Nr. 8/1989, DMV-Verlag
(Seite 64ff, "Die Assemblerbefehle des 8086/8088")
2.) Dokumentation zum A86/D86-Assembler/Debugger-Paket V3.22
von Eric Isaacson (Shareware)
Dokumentation zu R86 Seite 10