home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD1.mdf / assemblr / disasm / re86 / r86.doc < prev    next >
Text File  |  1993-07-27  |  29KB  |  661 lines

  1.  
  2.                          ■══════════════════════════════════■
  3.                          ║                                  ║
  4.                          ║   R86 Reassembler Version 1.00   ║
  5.                          ║                                  ║
  6.                          ■══════════════════════════════════■
  7.  
  8.  
  9.                             Copyright (c) 1992 Stefan Bion
  10.  
  11.                                    Bruktererstraße 2
  12.                                      5000 Köln 21
  13.                                    Tel. 0221/881825
  14.                                         Germany
  15.  
  16.  
  17.  
  18.         Dieses Programm ist "Freeware" (nicht Public Domain!), d.h. es darf
  19.         frei kopiert und in unmodifizierter Form weitergegeben werden. Eine
  20.         Registrierungsgebühr ist für die private Nutzung nicht erforderlich.
  21.         Alle Rechte vorbehalten.
  22.  
  23.  
  24.  
  25.         R86 ist ein Reassembler, der 80x86/80x87-Assembler-Quelltext aus
  26.         ausführbaren Programmdateien vom Typ .COM produziert. Im Einzeln
  27.         werden folgende Prozessoren unterstützt:
  28.  
  29.  
  30.             - 8088/86, 80186, 80286, NEC V20, NEC V30
  31.             - 8087, 80287, 80387, IIT-2C87
  32.  
  33.  
  34.         Die Syntax des generierten Quelltextes ist kompatibel zu der des
  35.         Shareware-Assemblers A86 von Eric Isaacson. Dabei werden die Verein-
  36.         fachungen verschiedener Assembleranweisungen des A86 berücksichtigt,
  37.         wie Mehrfachoperanden bei PUSH, POP, INC und DEC, oder B, W und D
  38.         statt BYTE PTR, WORD PTR und DWORD PTR. MASM oder TASM können ohne
  39.         Änderungen mit dem Quelltext nichts anfangen. Aber für diese Assembler
  40.         existieren bereits Disassembler - für A86 nicht.
  41.  
  42.  
  43.  
  44.         Inhalt
  45.         ======
  46.  
  47.  
  48.         1. Aufruf des Reassemblers ....................................... 2
  49.         2. Analysieren des Programmcodes ................................. 3
  50.         3. Aufbereiten des Assembler-Quelltextes ......................... 5
  51.         4. Floatingpoint-Anweisungen ..................................... 6
  52.         5. Sonderfälle ................................................... 7
  53.         6. Kapazitätsgrenzen von R86 ..................................... 9
  54.         7. Bug in A86 .................................................... 9
  55.         8. Literaturhinweise ............................................ 10
  56.  
  57.  
  58.  
  59.  
  60.  
  61.  
  62.  
  63.  
  64.  
  65.  
  66.         Dokumentation zu R86                                         Seite 1
  67.         1. Aufruf des Reassemblers
  68.         ==========================
  69.  
  70.  
  71.         Die zum Betrieb des Reassemblers notwendigen Parameter und Schalter
  72.         werden in der Kommandozeile übergeben. Erfolgt der Aufruf des
  73.         Programms ohne Kommandozeilenparameter, dann wird ein Hilfstext in
  74.         englischer Sprache ausgegeben.
  75.  
  76.  
  77.         Der Reassembler wird folgendermaßen aufgerufen:
  78.  
  79.  
  80.             R86 [-d] [-s] infile[.COM] [outfile[.ASM]]
  81.  
  82.  
  83.         Dabei steht infile für den Namen der zu reassemblierenden Programm-
  84.         datei, wobei die Erweiterung .COM voreingestellt ist und nicht
  85.         explizit angegeben werden muß. Durch Angabe einer Erweiterung können
  86.         Sie diesen voreingestellten Wert überschreiben. Der Parameter infile
  87.         muß in jedem Fall immer angegeben werden. Die Programmdatei darf
  88.         maximal 64 KByte groß sein.
  89.  
  90.         Der Name der zu produzierenden Quelldatei outfile ist standardmäßig
  91.         derselbe wie der der Programmdatei, jedoch mit der Endung .ASM. Durch
  92.         Angabe eines anderen Namens oder einer anderen Erweiterung können Sie
  93.         auch hier die voreingestellten Werte überschrieben werden.
  94.  
  95.         Ebenfalls optional können Sie noch zwei Schalter mit angeben:
  96.  
  97.         Durch Angabe des Schalters -d wird die zu reassemblierende Programm-
  98.         datei in einen Hex/ASCII-Editor geladen, der es Ihnen auf komfortable
  99.         Weise ermöglicht, die Code- und Datenbereiche zu bestimmen. Dazu
  100.         später mehr.
  101.  
  102.         Der Schalter -s ist dann nützlich, wenn die produzierte .ASM-Datei
  103.         größer als 64 KByte ist. Dann nämlich kann diese von A86 nicht mehr
  104.         in einem Stück verarbeitet werden und muß in mehrere Stücke aufgeteilt
  105.         werden. Im Allgemeinen kann man sagen, daß die .ASM-Datei die rund
  106.         zehnfache Größe der .COM-Datei erreicht. Durch Angabe des Schalters
  107.         -s werden statt einer großen Quelltext-Datei mehrere kleine Dateien zu
  108.         jeweils ca. 60 kByte erzeugt, deren Erweiterungen dann mit .001, .002,
  109.         usw. fortlaufend durchnumeriert werden. Um die einzelnen Quelltext-
  110.         Teile zu assemblieren, ist A86 folgendermaßen aufzurufen:
  111.  
  112.  
  113.             A86 outfile.00*
  114.  
  115.  
  116.         In der Regel werden Sie den generierten Quelltext jedoch erst mit
  117.         einem Texteditor nachbearbeiten wollen (müssen). Damit sich Änderungen
  118.         durch die Suchen/Ersetzen-Funktion des Editors auf den gesamten Text
  119.         auswirken, sollte dieser zunächst an einem Stück abgespeichert und
  120.         erst nachher in kleinere Häppchen aufgeteilt werden.
  121.  
  122.  
  123.  
  124.  
  125.  
  126.  
  127.  
  128.  
  129.  
  130.  
  131.  
  132.         Dokumentation zu R86                                         Seite 2
  133.         2. Analysieren des Programmcodes
  134.         ================================
  135.  
  136.  
  137.         Voraussetzung für das Generieren von sinnvollem Assembler-Quelltext
  138.         ist die richtige Interpretation des Programmcodes. Bevor Sie ein
  139.         Programm mit R86 reassemblieren, müssen Sie daher bestimmen, welche
  140.         Teile der Programmdatei ausführbare Anweisungen und welche Daten
  141.         enthalten. Ohne diese Differenzierung wurden fälschlicherweise als
  142.         Programmcode interpretierte Daten unsinnigen Chaos-Code ergeben. Zwar
  143.         mögen diese Anweisungen beim Assemblieren wieder in die ursprünglichen
  144.         Bytes zurückverwandelt werden können, aber das ist in der Praxis
  145.         meistens nicht der Fall, weil nämlich für ein und dieselbe Assembler-
  146.         anweisung mehrere Codierungsmöglichkeiten bestehen. Das Ergebnis wären
  147.         falsche Daten.
  148.  
  149.         Um R86 mitzuteilen, an welchen Adressen Datenbereiche welchen Typs
  150.         beginnen, und welche Bereiche als ausführbare Anweisungen interpre-
  151.         tiert werden sollen, wird eine zusätzliche Textdatei benötigt, die
  152.         nacheinander die hexadezimalen Adressen, gefolgt vom Datentyp, ent-
  153.         hält. Die Datei hat immer denselben Namen wie die zu disassemblierende
  154.         Programmdatei (infile), allerdings mit der Endung .R86. Es folgt ein
  155.         Beispiel für den Aufbau der Datei:
  156.  
  157.  
  158.             103 a     ; ASCII-Daten beginnen bei Offset 103h
  159.             1BE w     ; Word-Daten beginnen bei Offset 1BEh
  160.             1F0 b     ; Byte-Daten beginnen bei Offset 1F0h
  161.             200 c     ; Ausführbarer Code beginnt bei Offset 200h
  162.  
  163.  
  164.         In der Datei selbst dürfen keine Kommentare enthalten sein.
  165.  
  166.         Die hexadezimalen Adressen in der Datei müssen aufsteigend sortiert
  167.         sein. Außerdem dürfen maximal 2048 Bereiche definiert werden (maximal
  168.         2048 Zeilen), was allerdings völlig ausreicht.
  169.  
  170.  
  171.         Um die einzelnen Bereiche bestimmen zu können, benötigen Sie einen
  172.         Datei-Betrachter, der den Inhalt der Programmdatei in hexadezimaler
  173.         Form und als ASCII-Zeichen darstellt. Wenn Sie geübt sind, dann wird
  174.         es für Sie nicht schwer sein, festzustellen, welche Teile der Datei
  175.         ausführbaren Programmcode enthalten und welche Daten. Textbereiche
  176.         sind an ihrem Klartext ja noch eindeutig auszumachen, ebenso mit 0
  177.         initialisierte Datenbereiche und Puffer.
  178.  
  179.         Nun wäre es ja mühsam, sich den Inhalt der Datei anzusehen und dabei
  180.         die Adressen und den dazugehörigen Datentyp auf irgendeinen Zettel
  181.         aufzuschreiben, um diese dann nachher mit einem Texteditor abzutippen
  182.         und so die .R86-Datei zu erstellen. Deshalb besitzt R86 einen einge-
  183.         bauten Hex/ASCII-Dateibetrachter mit speziellen Funktionen zum bild-
  184.         schirmorientierten Bearbeiten der Datei. Sie aktivieren diesen Editor,
  185.         indem Sie beim Aufruf des Reassemblers den Schalter -d, gefolgt vom
  186.         Programmnamen, angeben.
  187.  
  188.         Mit den Tasten <PgUp> und <PgDn> können Sie in der Datei bildschirm-
  189.         weise blättern (± 256 Bytes), mit <Home> und <End> gelangen Sie an den
  190.         Anfang bzw. an das Ende der Datei. Die Datei beginnt immer bei Offset
  191.         100h, da dies die Startadresse bei .COM-Programmen ist. Mit den
  192.         Cursortasten können Sie den Cursor auf eine bestimmte Byteposition
  193.         innerhalb der Datei, an der z.B. ein Datenbereich beginnt, setzen und
  194.         diese dann mit der Funktionstaste <F1> markieren. Anschließend setzen
  195.         Sie den Cursor auf das letzte Byte dieses Bereiches und markieren die
  196.         Endadresse mit Funktionstaste <F2>.
  197.  
  198.         Dokumentation zu R86                                         Seite 3
  199.         Die Anfangs- und Endadresse des so markierten Bereiches wird in der
  200.         untersten Zeile angezeigt. Anschließend können Sie durch Eingabe des
  201.         Anfangsbuchstabens den Datentyp des markierten Bereiches bestimmen,
  202.         der dann auch farblich dargestellt wird:
  203.  
  204.  
  205.             a    ASCII-Daten         (gelb)
  206.             b    Byte-Daten          (grün)
  207.             c    Ausführbarer Code   (rot)
  208.             w    Word-Daten          (blau)
  209.  
  210.  
  211.         Falls Sie keinen Farbmonitor besitzen, können Sie sich auch an den in
  212.         der untersten Zeile angezeigten Werten (hinter "Current area:") orien-
  213.         tieren. Hier werden Anfangs- und Endadresse sowie der Datentyp des
  214.         aktuellen Bereiches angezeigt, in dem sich der Cursor gerade befindet.
  215.         Allerdings ist die farbige Anzeige wesentlich schöner, da man hier den
  216.         jeweiligen Datentyp auf einen Blick erkennt, ohne mit dem Cursor durch
  217.         die Gegend wandern zu müssen und dabei die Anzeige zu beobachten.
  218.  
  219.  
  220.         Haben Sie alle Bereiche bestimmt, dann können Sie den Editor mit der
  221.         <ESC>-Taste verlassen. Sie werden daraufhin gefragt, ob Sie die
  222.         eingegebenen Daten sichern wollen. Mit 'Y' oder <CR> können Sie dies
  223.         bestätigen oder aber mit 'N' oder <ESC> ablehnen. Die Daten werden in
  224.         eine Datei mit der Endung .R86 geschrieben. Bei einem erneuten Aufruf
  225.         des Reassemblers mit dem Schalter -d werden die Daten auch wieder aus
  226.         dieser Datei gelesen, so daß Sie hier Änderungen vornehmen können.
  227.         Die nächste Frage lautet, ob nun mit der Disassemblierung begonnen
  228.         werden soll oder nicht.
  229.  
  230.         Wenn Sie beim ersten Analysieren nicht gleich alles identifizieren
  231.         können, dann machen Sie einfach eine Probe-Disassemblierung und sehen
  232.         sich den Quelltext in einem Texteditor an. Wenn Sie evtl. sinnlose
  233.         Anweisungen entdecken, dann haben Sie möglicherweise noch
  234.         Datenbereiche übersehen. Falls ein Label davorsteht, können Sie die
  235.         Adresse und den Datentyp direkt in die Datei infile.R86 einfügen,
  236.         ansonsten rufen Sie R86 noch einmal mit dem Schalter -d auf.
  237.  
  238.         In der Regel läßt sich der Quelltext dann ohne Fehler von A86
  239.         assemblieren und funktioniert sogar, auch wenn ein byteweiser
  240.         Vergleich Unterschiede ergibt. Letzteres ist meistens dann der Fall,
  241.         wenn die Original-Programmdatei von MASM oder TASM erzeugt wurde, und
  242.         nicht von A86 selbst. In Verbindung mit dem sogenannten ModRM-Byte,
  243.         welches die Adressierungsart eines Assemblerbefehls festlegt, kann ein
  244.         und derselbe Befehl nämlich mit unterschiedlichen Opcodes codiert
  245.         werden. Eric Isaacson benutzt bei seinem A86 ein eigenes System, die
  246.         Befehle zu codieren, um daran erkennen, ob ein beliebiges Programm von
  247.         seinem Assembler übersetzt worden ist, oder nicht ("footprint").
  248.  
  249.         Die Größe der ursprünglichen und der neu übersetzten Programmdatei muß
  250.         allerdings dieselbe sein, sonst brauchen Sie das Programm gar nicht
  251.         erst zu starten. Dann nämlich sind bestimmte Bereiche des Programms
  252.         verschoben, und durch falsche Referenzierung kommt es dann zu Fehlern.
  253.         Bevor Sie in einem solchen Fall mit dem im Folgenden beschriebenen
  254.         Aufbereiten des Assembler-Quelltextes weitermachen, untersuchen Sie
  255.         den Quelltext noch einmal auf Datenbereiche, die Sie vielleicht
  256.         übersehen haben, oder auf zweideutige Anweisungen (Kapitel "Sonder-
  257.         fälle").
  258.  
  259.  
  260.  
  261.  
  262.  
  263.  
  264.         Dokumentation zu R86                                         Seite 4
  265.         3. Aufbereiten des Assembler-Quelltextes
  266.         ========================================
  267.  
  268.  
  269.         Haben Sie alle Datenbereiche des Programms richtig bestimmt und dann
  270.         eine .ASM-Datei erzeugt, die auch fehlerlos assembliert wird und sogar
  271.         lauffähig ist, dann beginnt erst die eigentliche Arbeit, die Ihnen
  272.         kein Programm abnehmen kann: Das Verstehen des Programmablaufes und
  273.         möglichst das Einfügen von erklärenden Kommentaren. Kommentieren Sie
  274.         jedes Unterprogramm, beginnen Sie dabei mit den am einfachsten zu
  275.         erkennenden Teilen. Wenn Sie einmal eine Anweisung oder einen MS-DOS-
  276.         Funktionsaufruf nicht verstehen, dann sehen Sie in entsprechender
  277.         Literatur nach. Ersetzen Sie dann das Label jedes identifizierten
  278.         Unterprogramms und von Variablen, deren Funktion durch die Verwendung
  279.         im Unterprogramm offensichtlich geworden ist, mit der Suchen/Ersetzen-
  280.         Funktion Ihres Texteditors durch aussagekräftige Namen. Diese Namen
  281.         erscheinen dann auch an den Programmstellen, von denen aus sie
  282.         referenziert werden und erleichtern so die Identifizierung weiterer
  283.         Programmteile.
  284.  
  285.  
  286.         Wollen Sie außerdem selbst Änderungen und Erweiterungen an dem
  287.         Programm vornehmen, dann ist es unerläßlich, den Quelltext zuvor
  288.         entsprechend aufzubereiten. Eine Hauptaufgabe dabei ist es, Symbole
  289.         durch Festwerte zu ersetzen, wo dies nötig ist. Hierzu zunächst
  290.         einige Erläuterungen:
  291.  
  292.  
  293.         Beim Generieren von Assembler-Quelltext geht R86 in zwei Schritten
  294.         vor: Beim ersten Durchgang werden alle Word-Referenzen in einer
  295.         internen Tabelle gespeichert. Anschließend wird im zweiten Durchgang
  296.         der Quelltext in die Ausgabedatei geschrieben und die Referenzen dabei
  297.         durch Symbole bzw. Labels ersetzt. Als Referenzen werden alle Sprung-
  298.         ziele (bedingte Sprünge, JMP, CALL, LOOP) und alle 16-Bit-Direkt-
  299.         operanden (falls größer als 0FFh) angesehen. Bei den Direktoperanden
  300.         kann R86 allerdings nicht wissen, ob der Programmierer damit einen
  301.         festen Wert oder eine Offsetadresse innerhalb des Programms gemeint
  302.         hat. Beispiel:
  303.  
  304.  
  305.                            mov ax,offset l2523h
  306.                            mov dx,offset l0653h
  307.                            int 21h
  308.  
  309.  
  310.         Der geübte Assembler-Programmierer wird sofort erkennen, daß l2523h
  311.         ein Festwert ist (DOS-Funktion 25h, Interruptvektor 23h setzen), und
  312.         l0653h eine Referenz (Offsetadresse des Int-23h-Handlers). Beim
  313.         nachträglichen Bearbeiten des Quelltextes mit einem Editor gilt es
  314.         nun, alle Symbole, die eigentlich Festwerte sind, zu entfernen. Im
  315.         obigen Beispiel würden Sie die erste Zeile also ändern in:
  316.  
  317.  
  318.                            mov ax,2523h
  319.  
  320.  
  321.         Das Label l2523h, das irgendwo im Programm definiert ist, kann dann
  322.         gelöscht werden. Erst dann, wenn kein Festwert mehr als vermeintliche
  323.         Referenzadresse angegeben ist und deren Werte somit nicht mehr von der
  324.         Adresse der Labels im Programm abhängen, dürfen Sie Ergänzungen am
  325.         Programm vornehmen. Denn würden Sie beispielsweise hinter den obigen
  326.         drei Quelltextzeilen einige Anweisungen einfügen, dann würden sich
  327.         auch die Offsetadressen aller nachfolgenden Symbole verschieben.
  328.  
  329.  
  330.         Dokumentation zu R86                                         Seite 5
  331.         Auch Festwerte, die als Symbol angegeben sind, bekämen einen anderen
  332.         Wert zugewiesen. Bei einer Verschiebung um 3 Bytes würde das Symbol
  333.         l2523h z.B. den Wert 2526h repräsentieren, so daß nun nicht mehr Int
  334.         23h, sondern Int 26h verbogen werden würde. Aus diesem Grund ist es
  335.         auch nicht ratsam, das Programm zu starten, wenn sich dessen Größe von
  336.         der Größe der ursprünglichen Programmdatei unterscheidet und der von
  337.         R86 erzeugte Quelltext noch nicht dahingehend geändert wurde.
  338.  
  339.         Normalerweise jedoch ist die Größe der ursprünglichen und der neu
  340.         übersetzten Programmdatei dieselbe. Nur in Sonderfällen dürften sich
  341.         Unterschiede ergeben - doch dazu mehr im Kapitel "Sonderfälle".
  342.  
  343.  
  344.  
  345.         4. Floatingpoint-Anweisungen
  346.         ============================
  347.  
  348.  
  349.         Assembleranweisungen für den mathematischen Coprozessor bis hin zum
  350.         80387 werden von R86 ebenfalls disassembliert. Außerdem wird der IIT-
  351.         2C87 unterstützt (dies entspricht exakt dem Sprachumfang von A86 in
  352.         der Version 3.22). Wenn R86 eine Coprozessor-Anweisung in der
  353.         Programmdatei entdeckt, wird zu Beginn des Quelltextes die .287-
  354.         Direktive ausgegeben.
  355.  
  356.         Beim Coprozessor 8087 mußte noch vor jede Anweisung ein FWAIT-Befehl
  357.         geschrieben werden (ein Byte, 9Bh). Bei den neueren Prozessoren ab dem
  358.         80287 ist dies nicht mehr erforderlich. MASM, TASM und A86 codieren
  359.         implizit vor jede Coprozessor-Anweisung dieses FWAIT-Byte. Bei A86
  360.         läßt sich dies aber durch Angeben der Direktive .287 oder durch Aufruf
  361.         mit dem Schalter +F abschalten.
  362.  
  363.         Wenn in der von R86 disassemblierten Programmdatei FWAIT-Anweisungen
  364.         enthalten sind, dann werden diese immer explizit ausgegeben. Durch die
  365.         .287-Direktive wird bewirkt, daß A86 die FWAITs bei den Floatingpoint-
  366.         Befehlen nicht nochmal codiert. Sie können die Direktive und alle
  367.         FWAITS, die direkt vor Coprozessor-Anweisungen stehen, auch entfernen.
  368.  
  369.  
  370.  
  371.  
  372.  
  373.  
  374.  
  375.  
  376.  
  377.  
  378.  
  379.  
  380.  
  381.  
  382.  
  383.  
  384.  
  385.  
  386.  
  387.  
  388.  
  389.  
  390.  
  391.  
  392.  
  393.  
  394.  
  395.  
  396.         Dokumentation zu R86                                         Seite 6
  397.         5. Sonderfälle
  398.         ==============
  399.  
  400.  
  401.         Das Rückübersetzen von Maschinencode in Assembleranweisungen kann
  402.         manchmal eine knifflige Angelegenheit sein. Es existieren theoretisch
  403.         einige Sonderfälle, in denen der Assembler die Anweisungen anders
  404.         interpretiert, als sie gemeint sind, so daß sich der vom Assembler
  405.         produzierte Code vom Original unterscheidet.
  406.  
  407.  
  408.         Häufig benutzte Anweisungen des 8086-Prozessors existieren z.B. zu-
  409.         sätzlich zur Normalform auch in einer Kurzform. Dazu gehören u.a. die
  410.         Anweisungen "MOV Register,Direktoperand" (Opcodes B0...BF), welche
  411.         auch mit den Opcodes C6 und C7 codiert werden können, was aber wegen
  412.         des zusätzlichen ModRM-Bytes um 1 Byte länger und außerdem langsamer
  413.         wäre. Für Befehle, die das Register AX bzw. AL als Operand haben,
  414.         existiert vielfach neben der Langform auch ein extra Opcode ohne das
  415.         ModRM-Byte zum Auswählen der Adressierungsart. Manchmal ist es pro-
  416.         grammtechnisch jedoch erforderlich, die Langform zu verwenden. Da
  417.         beide Formen dieselbe Schreibweise besitzen, können sie bei einem
  418.         disassemblierten Quelltext äußerlich nicht mehr unterschieden werden.
  419.         Um explizit die Langform eines Befehls zu codieren, müssen die Opcodes
  420.         in Form von Bytes mit der DB-Anweisung oder mit Hilfe eines Macros
  421.         angegeben werden. A86 und auch die anderen Assembler versuchen immer,
  422.         eine Anweisung mit so wenigen Bytes wie möglich zu codieren.
  423.         Langformen von Anweisungen werden von R86 kommentiert, wobei der
  424.         tatsächlich verwendete Opcode angegeben wird. Falls die Verwendung der
  425.         Langform für den Programmablauf wichtig ist und beibehalten werden
  426.         muß, dann sollten Sie die entsprechenden Bytes von Opcode und Operand
  427.         als Datenbereich definieren (DB- oder DW-Anweisung). Ansonsten können
  428.         Sie nach der betreffenden Anweisung ein NOP einfügen, um eine
  429.         Verschiebung der nachfolgenden referenzierten Offsetadressen zu
  430.         vermeiden. Letzteres kann jedoch entfallen, falls Sie bei Festwerten
  431.         als Direktoperanden die Symbole entfernt haben, so daß deren Werte
  432.         nicht mehr von der Adresse der Labels im Programm abhängen.
  433.  
  434.  
  435.         Auch effektive Adressen als Operanden einer Anweisung, bei denen das
  436.         Displacement 0 beträgt, werden vom Assembler in die kürzere Form ohne
  437.         Displacement übersetzt. Die Anweisung "mov al,b[bx+di+0]" wird also
  438.         beispielsweise zu "mov al,b[bx+di]" (Ausnahme: Eine Kurzform von
  439.         "[bp]" existiert nicht und wird daher immer als "[bp+0]" codiert.
  440.         Falls es sich um ein 16-Bit-Displacement handelt, das jedoch kleiner
  441.         als 100h ist und somit in 8 Bit passen würde, dann wird vom Assembler
  442.         auch automatisch ein 8-Bit-Displacement codiert, womit sich schon
  443.         wieder Unterschiede in der Codelänge ergeben. Die beiden zuletzt
  444.         geschilderten Fälle sind mir jedoch in der Praxis noch nicht begegnet.
  445.  
  446.  
  447.         Bei Direktoperanden gibt es noch eine Besonderheit, die beachtet
  448.         werden muß: A86 interpretiert diese als vorzeichenbehaftete Integer-
  449.         werte, was manchmal zu überraschenden Ergebnissen führen kann. Dazu
  450.         ein Beispiel: Ein Programm enthält die Anweisung
  451.  
  452.  
  453.                            cmp bx,0FFF7h
  454.  
  455.  
  456.  
  457.  
  458.  
  459.  
  460.  
  461.  
  462.         Dokumentation zu R86                                         Seite 7
  463.         Assembliert man diese Anweisung, dann codiert A86 daraus die drei
  464.         Bytes 83 FB F7, was jedoch wieder disassembliert die Anweisung
  465.  
  466.  
  467.                            cmp bx,0F7h
  468.  
  469.  
  470.         ergeben würde. Diese Anweisung wiederum assembliert ergibt jedoch
  471.         diesmal vier Bytes, und zwar 81 FB F7 00. Der Grund ist, daß A86 die
  472.         Zahl 0FFF7h als vorzeichenbehaftete Integerzahl mit dem Wert -9 be-
  473.         trachtet. Den Wert -9 kann man aber auch als 8-Bit-Integer darstellen
  474.         (0F7h). Der 80x86 kennt zudem für verschiedene Anweisungen, die als
  475.         ersten Parameter einen Word-Operanden haben, zwei unterschiedliche
  476.         Opcodes: Opcode 81h mit einem 16-Bit-Direktoperanden als zweitem
  477.         Parameter und Opcode 83h mit einem 8-Bit-Direktoperanden als zweitem
  478.         Parameter. Da -9 gleich -9 ist, codiert A86 die kürzere beider
  479.         Sequenzen. Der Ausdruck "0F7h" ist für A86 allerdings eine positive
  480.         Zahl und wird daher in 16 Bit (1 Word) dargestellt (der *Wert* 0F7h
  481.         wäre ja -9). Statt mit negativen Zahlen zu hantieren, gibt R86 in
  482.         solchen Fällen einfach zwei hexadezimale Fs vor der betreffenden Zahl
  483.         aus, was in vielen Fällen übersichtlicher ist.
  484.  
  485.  
  486.         Die folgende Tabelle faßt die Interpretation von vorzeichenbehafteten
  487.         Bytes (XX) bzw. Words (XXXX) durch A86 noch einmal zusammen:
  488.  
  489.  
  490.               |  Schreibweise   |   Interpretation  |   Codierung  | Opcode
  491.           ----+-----------------+-------------------+--------------+--------
  492.               |                 |                   |              |
  493.           1.) |    00...7F      |      0...7F       |    00...7F   |   83
  494.           2.) |    80...FF      |      80...FF      |  0080...00FF |   81
  495.               |                 |                   |              |
  496.           3.) |  0000...007F    |      0...7F       |    00...7F   |   83
  497.           4.) |  0080...FF7F    |      80...FF7F    |  0080...FF7F |   81
  498.           5.) |  FF80...FFFF    |      -80...-1     |    80...FF   |   83
  499.  
  500.  
  501.         Im Fall 3.) in der Tabelle fügt R86 direkt hinter dem betreffenden
  502.         Befehl den Aufruf eines Makros "patch83" ein, welches bei Auftreten
  503.         dieses Falles am Anfang der .ASM-Datei definiert wird. Dieses Makro
  504.         sorgt dafür, daß statt des Opcodes 83h, den der Assembler aufgrund
  505.         seiner Interpretation des Operanden nehmen würde, der richtige Opcode
  506.         81h verwendet wird, wie es auch im Originalprogramm der Fall war.
  507.         Falls es für den Programmablauf nicht wichtig ist, können Sie dieses
  508.         Makro auch wieder entfernen.
  509.  
  510.         Im Fall 5.) wird der Operand als Symbol definiert sein - aufgrund
  511.         seines hohen Wertes vermutlich irgendwo am Schluß des .ASM-Listings,
  512.         also erst nach der Verwendung dieses Symbols. Da A86 ein 1-Pass-
  513.         Assembler ist, kann er zum Zeitpunkt der Verwendung des Symbols noch
  514.         nicht wissen, welcher Wert ihm zugewiesen werden wird (Vorwärts-
  515.         referenz) und reserviert daher vorsichtshalber 1 Word für den
  516.         Operanden. A86 codiert also 5.) mit Opcode 81h, so wie es dem
  517.         Original-Programm entspricht. Ändern Sie das Symbol jedoch in einen
  518.         Festwert um, dann verwendet A86 Opcode 83h. Falls dies programm-
  519.         technisch irrelevant ist, kann Ihnen das egal sein. Ansonsten müßten
  520.         Sie entweder den Befehl byteweise mit der DB-Anweisung codieren, oder
  521.         Sie verwenden ein Makro, ähnlich patch83.
  522.  
  523.         Zum Glück sind dies aber alles äußerst seltene Fälle, die eigentlich
  524.         nur dann auftreten, wenn der Programmierer mit fiesen Tricks
  525.         gearbeitet hat.
  526.  
  527.  
  528.         Dokumentation zu R86                                         Seite 8
  529.         6. Kapazitätsgrenzen von R86
  530.         ============================
  531.  
  532.  
  533.         Die von R86 zu reassemblierende .COM-Datei darf eine maximale Größe
  534.         von 65280 (FF00h) Bytes haben und entspricht damit auch der Maximal-
  535.         größe einer .COM-Datei unter DOS. Dateien vom Typ .EXE werden von R86
  536.         nicht unterstützt, zumal auch A86 mit Multisegmentprogrammen nichts
  537.         anfangen kann.
  538.  
  539.  
  540.         R86 liest den gesamten Inhalt der .R86-Datei in den Hauptspeicher ein.
  541.         Dort ist Platz für 2048 Einträge reserviert - in der Datei dürfen also
  542.         maximal 2048 Adressen mit Datendefinitionen angegeben werden, was
  543.         normalerweise mehr als ausreicht.
  544.  
  545.  
  546.         Eine weitere Einschränkung betrifft die maximale Anzahl von Symbolen
  547.         bzw. Referenzadressen. Diese liegt bei 8192 und stellt somit ungefähr
  548.         das Doppelte von der in der Praxis benötigten Kapazität bei einer
  549.         64 KByte großen .COM-Datei dar. Außerdem ist dies mehr, als A86
  550.         verkraften kann. Eine ca. 50 KByte große .COM-Datei ergab reassem-
  551.         bliert mit dem Schalter -s beispielsweise 7½ einzelne Quelltextteile
  552.         zu je 60 KByte. A86 brach die Übersetzung bei der letzten Datei mit
  553.         der Fehlermeldung ~99 Symbol Table Overflow~ ab. Hier müßte man die
  554.         Quelltextteile dann einzeln in .OBJ-Module übersetzen lassen und zu
  555.         einer ausführbaren Datei linken.
  556.  
  557.  
  558.  
  559.         7. Bug in A86
  560.         =============
  561.  
  562.  
  563.         Zum Schluß noch ein Hinweis auf einen Fehler von A86, der mir beim
  564.         Entwickeln von R86 aufgefallen ist. Bei den Datentypen Byte und Word
  565.         faßt R86 gleiche aufeinanderfolgende Werte mit dem DUP-Operator
  566.         zusammen. Bei Word-Daten werden ebenso wie bei Direktoperanden von
  567.         Assemblerbefehlen statt Festwerten Labels verwendet, sofern die Werte
  568.         größer als 100h sind, da sie Offsetadressen auf andere Programmteile
  569.         darstellen könnten. Ist der Wert größer als die Offsetadresse, an der
  570.         dieses Word definiert ist, dann ist das entsprechende Label erst
  571.         hinter dieser Offsetadresse definiert (Vorwärtsreferenz). Wenn nun ein
  572.         solches Symbol hinter einem DUP-Operator steht, dann wird nur das
  573.         erste Element dieses Feldes von A86 mit diesem Wert initialisiert und
  574.         der Rest mit 0 aufgefüllt:
  575.  
  576.  
  577.                       dw 8 dup symbol     ; => dw 1234h,0,0,0,0,0,0,0
  578.         symbol        equ 1234h
  579.                       dw 8 dup symbol     ; => dw 1234h,1234h,1234h,1234h,
  580.                                           ;       1234h,1234h,1234h,1234h
  581.  
  582.  
  583.         Aus diesem Grunde verwendet R86 den DUP-Operator außer bei Bytes nur
  584.         bei solchen Words, die kleiner als 100h sind und somit nicht durch
  585.         Symbole dargestellt werden.
  586.  
  587.         Dasselbe Phänomen zeigt sich zwar auch bei Bytes, wenn ein Label
  588.         verwendet wird, das erst nach der Verwendung definiert wird. Bei
  589.         Byte-Daten setzt R86 allerdings keine Symbole ein.
  590.  
  591.  
  592.  
  593.  
  594.         Dokumentation zu R86                                         Seite 9
  595.         8. Literaturhinweise
  596.         ====================
  597.  
  598.  
  599.         Die Informationen für die Entwicklung von R86 wurden aus folgenden
  600.         Quellen bezogen:
  601.  
  602.  
  603.         1.) DOS Extra Nr. 8/1989, DMV-Verlag
  604.             (Seite 64ff, "Die Assemblerbefehle des 8086/8088")
  605.  
  606.         2.) Dokumentation zum A86/D86-Assembler/Debugger-Paket V3.22
  607.             von Eric Isaacson (Shareware)
  608.  
  609.  
  610.  
  611.  
  612.  
  613.  
  614.  
  615.  
  616.  
  617.  
  618.  
  619.  
  620.  
  621.  
  622.  
  623.  
  624.  
  625.  
  626.  
  627.  
  628.  
  629.  
  630.  
  631.  
  632.  
  633.  
  634.  
  635.  
  636.  
  637.  
  638.  
  639.  
  640.  
  641.  
  642.  
  643.  
  644.  
  645.  
  646.  
  647.  
  648.  
  649.  
  650.  
  651.  
  652.  
  653.  
  654.  
  655.  
  656.  
  657.  
  658.  
  659.  
  660.         Dokumentation zu R86                                         Seite 10
  661.