Einleitung
Im Normalfall ist die Assemblerprogrammierung heute nicht mehr ganz zeitgemäß und kommerziell sicher nur noch in Spezialfällen rentabel. Als Kunde hat man sich schließlich an ständig zunehmende Programmgrößen gewöhnt, ja erwartet sie sogar. Wir Portfolio-Anwender wollen uns freilich eine derartige Verschwendungssucht nicht leisten und hier bietet sich die Assemblerprogrammierung zur Erstellung effizienter Programme an. Dieser Kurs soll zunächst eine allgemeine Einführung in diese "Programmiersprache" geben und später portfoliospezifische Lösungen vorstellen. Da viele Leser bereits mit Pascal oder Basic vertraut sind, werden gewisse Programmiererfahrungen vorausgesetzt. Andererseits wird sich sicher die eine oder andere Stelle finden, die nicht jeder kritischen Prüfung standhält.
Doch jetzt zur Sache. Bekanntlich tut im Portfolio ein Intel-Prozessor namens 8088 seinen Dienst. Das Faszinierende an dieser 1979 mit dem 8086 (16-Bit-Datenbus, sonst wie 8088) eingeführten Architektur ist, daß sie uns bis in heutige PCs verfolgt. Wenn man aus einem Pentium-PC das Letzte herausholen möchte, ist deshalb auch heute das Erlernen der 8086-Maschinensprache durchaus noch aktuell.
Maschinensprache und Assembler
Jedes ausführbare Programm besteht letztlich aus einer Aneinanderreihung von Maschinenbefehlen, wobei ein Maschinenbefehl je nach Zahl der Operanden zwischen einem und sechs Bytes lang ist. Man kann ein Programm also als Folge von Byte-Werten (0...255) darstellen, vorzugsweise im hexadezimalen Zahlenformat, weil man dann mit 2 Ziffern pro Byte auskommt. Folgende 15 Bytes sind z.B. der Maschinencode für ein Programm, das einen kurzen Soundeffekt auf dem Portfolio erzeugt:
BA 20 80 31 C0 EE 48 75 FC B8 80 4C EE CD 21
In den Zeiten als die Programme noch kurz, Disketten Luxus und Mailboxen die Domäne von Hackern waren, wurden Listings ja gern in so einer Form gedruckt. Zur Programmentwicklung ist diese Darstellung jedoch denkbar ungeeignet. Um sich nicht für jeden Maschinenbefehl eine Zahl merken zu müssen, bedient man sich einer anderen Schreibweise. Für alle Maschinenbefehle des Prozessors existieren eingängige Abkürzungen, die meist aus drei Buchstaben bestehen und Mnemonics genannt werden. Ein Assemblerquelltext besteht hauptsächlich aus diesen Mnemonics und den zum jeweiligen Maschinenbefehl gehörenden Parametern. Dabei beginnt man für jeden Befehl eine neue Zeile, läßt links Platz für Sprungmarken und fügt eventuell rechts nach einem Strichpunkt einen Kommentar an. Obiges Beispiel stellt sich damit wie folgt dar:
mov dx,8020h ; Portadresse
xor ax,ax ; Zähler auf 0
Marke: out dx,al
; Ton erzeugen
dec ax ; Zähler -1
jnz Marke ; Schleife
mov ax,4c80h
out dx,al ; Ton aus
int 21h ; beenden
Unser Handwerkszeug
Dieser Quelltext muß nun in zwei Schritten mit einem Assembler
und einem Linker in ein lauffähiges Programm übersetzt werden.
Man kann diese zwei Schritte mit einem Batchprogramm zusammenfassen. Die
bekanntesten Assembler sind MASM von Microsoft (zugehöriger Linker:
LINK), TASM (Linker: TLINK) von Borland sowie der Sharewareassembler A86.
Ich selbst benutze Borlands Turbo Assembler, jedoch scheint mir A86 den
einfachsten Einstieg zu ermöglichen, denn dieser kann ohne externen
Linker obigen Beispielquelltext direkt in ein .com-Programm übersetzen.
Zudem ist er mit 23kB (Version 3.22) mit Abstand der kleinste Vertreter
seiner Gattung und läuft damit sogar direkt auf dem Portfolio. A86.COM
befand sich auf der Begleitdiskette zur ersten Ausgabe der Pofoinfo, ist
aber auch auf der Club-CD, in der Club-Mailbox und in vielen Shareware-Archiven
vorhanden. Turbo-Pascal (6.0ff) wartet mit einem integrierten Assembler auf.
Allerdings bettet es den damit erzeugten Code in ein unhandliches
EXE-Programm ein. Wer noch keines dieser Programme besitzt, kann zum Experimentieren
vorerst auf DEBUG zurückgreifen.
Neben einem Assembler sollten zur Grundausstattung aber auch Nachschlagewerke
zu den Themen Prozessorarchitektur, Befehlssatz und Betriebssystem gehören,
denn eine ausführliche Behandlung im Rahmen dieses Kurses ist kaum
möglich. Eine große Hilfe ist hier eine Online-Referenz, wie
z.B. das Shareware-Programm HelpPC für DOS von David Jurgens, das
alle genannten Themenkomplexe abdeckt (Quelle z.B.: ftp://ftp.simtel.net/pub/simtelnet/msdos/info/helppc21.zip, Größe ca. 255K)
Das erste Programm
Um unser Beispielprogramm zu erzeugen gibt es nun folgende Möglichkeiten:
1. Verwendung von DEBUG.COM
Das Dienstprogramm Debug gehört zum Lieferumfang von MSDOS und eignet sich vor allem zur Fehlersuche in Maschinenprogrammen. Es ermöglicht aber auch die Eingabe von Bytefolgen und sogar Mnemonics. Trotzdem haben wir es nicht mit einem ausgewachsenen Assembler zu tun, da z.B. keine symbolischen Adressen verwendet werden dürfen, wie oben mit "Marke" geschehen.
Die wichtigsten Befehle, die in Debug immer hinter einem Minuszeichen
als Prompt eingegeben werden, lauten:
? Hilfe (nur neuere
Versionen)
e Adr Eingabe einer Bytefolge
a Assemble
u Unassemble
nName Dateiname festlegen
r cx Dateilänge festlegen
w Write
Weiterführende Erläuterungen zu Debug sowie eine ältere
Version (knapp 10KB), die auch auf dem PF funktioniert, finden sich auf
der Club-CD. Unser Programm können wir damit bereits eingeben, und
alle Debug-Neulinge sollten dies jetzt einmal versuchen. Zur Orientierung
diene dabei das folgende Bildschirmprotokoll:
C:\>debug ton.com
File not found
-a
0F38:0100 mov dx,8020
0F38:0103 xor ax,ax
0F38:0105 out dx,al
0F38:0106 dec ax
0F38:0107 jnz 105
0F38:0109 mov ax,4c80
0F38:010C out dx,al
0F38:010D int 21
0F38:010F
-r cx
CX 0000
:f
-w
Writing 0000F bytes
-q
Fertig! Anstelle der Sprungmarke "Marke" mußte hier eine der Speicheradressen eingesetzt werden, die vor jedem Befehl am linken Rand erscheinen. Nach dem Verlassen von Debug sollte das Programm TON.COM mit einer Länge von 15 Bytes im aktuellen Directory zu finden sein. Noch etwas schneller gelangt man ans Ziel, wenn man die 15 Bytes mit Hilfe des E-Kommandos von Debug direkt im Hexcode eingibt. Hierbei ist zu beachten, daß nach den zwei Zeichen jedes Bytes Space betätigt werden muß, nach dem letzten Byte stattdessen Enter. Ach ja: Dieses Programm läuft nur auf dem Portfolio und könnte einen normalen PC zum Absturz bringen.
2. Assemblierung mit A86
Vor der Anwendung eines Assemblers muß man den Quelltext mit einem normalen ASCII-Editor in eine Datei schreiben, die man gewöhnlich mit der Endung .ASM versieht. Zur Demonstration tippe man hierzu unser Beispiel (in der Form wie es vor "Unser Handwerkszeug" steht) ab und nenne es TON.ASM. Der Rest ist wirklich kinderleicht:
C:\>a86 ton.asm
A86 macro assembler, V3.22 Copyright 1990
Eric Isaacson
Sources:
ton.asm
Object: ton.COM
Symbols: ton.SYM
Das Resultat ist unser gewünschtes Programm TON.COM. Die Symbollistendatei TON.SYM benötigen wir nicht und können sie auch löschen. Wer sich den generierten Code genauer ansieht, wird feststellen, daß das vierte Byte von der mit Debug erzeugten Version abweicht (33h statt 31h). Das liegt daran, daß sich manche Assemblerbefehle unterschiedlich codieren lassen. Der Autor des A86 verwendet bewußt ungewöhnliche Codierungen, um feststellen zu können, ob ein Programm mit seinem Assembler erzeugt wurde. Diese Spuren lassen sich aber leicht verwischen, indem man den Code z.B. mit Debug erst disassembliert und dann wieder assembliert.
3. Das Borland-Gespann TASM und TLINK
Der klassische Weg vom Quelltext zum Code führt über die sogenannte Objektdatei. Sie wird vom Assembler aus dem Quelltext erzeugt und enthält einen Mix aus Symbolen und Code. Erst durch das anschließende Linken gelangt man zum ausführbaren Programm. Dieses Verfahren ist zwar vielseitiger (man kann z.B. mehrere Objektdateien zusammenlinken), für den Einsteiger allerdings erst einmal umständlicher als die direkte Methode von A86. Damit aber nicht genug: Der Quelltext bedarf noch ein paar Ergänzungen:
.model tiny
.code
ORG 100h
Start: mov dx,8020h ; Portadresse
xor ax,ax ; Zähler auf 0
Marke: out dx,al
; Ton erzeugen
dec ax ; Zähler -1
jnz Marke ; Schleife
mov ax,4c80h
out dx,al ; Ton aus
int 21h ; beenden
END Start
Die hinzugekommenen Assemblerdirektiven machen Angaben über das Speichermodell, den Beginn des Codesegments und die Einsprungadresse. Die hier verwendeten Minimaleinstellungen dürften für jedes Portfolioprogramm ausreichend sein und können jedesmal so übernommen werden. Hat man TON.ASM wie oben ergänzt, kann die Assemblierung folgen (hier auf dem Desktop-PC):
C:\>tasm ton.asm
Turbo Assembler Version 2.0 Copyright
(c) 1988, 1990 Borland International
Assembling file: ton.asm
Error messages: None
Warning messages: None
Passes:
1
Remaining memory: 474k
Die erzeugte Objektdatei muß jetzt gelinkt werden. Die Option /t gibt an, daß ein .COM-Programm erstellt werden soll:
C:\>tlink /t ton.obj
Turbo Link Version 3.0 Copyright (c) 1987,
1990 Borland International
Das fertige TON.COM ist übrigens identisch zu der mit A86 erzeugten Version (was nicht selbstverständlich ist). Die zusätzlich entstandenen Dateien TON.OBJ und TON.MAP können gelöscht werden.
4. Microsoft MASM und LINK
Das umständlichste - pardon professionellste - Werkzeug stammt, wie sollte es anders sein, aus dem Hause Microsoft. Die hier verwendete MASM-Version 1.25 ist allerdings schon leicht in die Jahre gekommen, so daß das Beispiel eventuell nicht mit aktuelleren Versionen nachvollziehbar ist. Trotzdem hier der angepaßte Quelltext:
code SEGMENT
ASSUME CS:code
ORG 100h
Start: mov dx,8020h ; Portadresse
xor ax,ax ; Zähler auf 0
Marke: out dx,al
; Ton erzeugen
dec ax ; Zähler -1
jnz Marke ; Schleife
mov ax,4c80h
out dx,al ; Ton aus
int 21h ; beenden
code ENDS
END Start
Bis zum Endprodukt sind jetzt drei Schritte erforderlich. Zunächst wie beim Borland-Produkt die Assemblierung und das Linken. LINK erzeugt allerdings eine ausführbare Datei im .EXE-Format (783 Bytes), die danach noch ins COM-Format konvertiert werden muß:
C:\>masm ton.asm
The Microsoft MACRO Assembler , Version 1.25
Copyright (C) Microsoft Corp 1981,82,83
Object filename [ton.OBJ]:
Source listing [NUL.LST]:
Cross reference [NUL.CRF]:
Warning Severe
Errors Errors
0 0
C:\>link ton.obj
Microsoft Object Linker V2.01
(Large)
(C) Copyright 1982, 1983 by Microsoft Inc.
Run File [TON.EXE]:
List File [NUL.MAP]:
Libraries [.LIB]:
Warning: No STACK segment
There was 1 error detected.
C:\>exe2bin ton.exe ton.com
Die Warnung können wir ignorieren, und die Dateien TON.OBJ, TON.MAP, TON.EXE löschen. Das Resultat ist wieder genau die selbe 15 Bytes lange Datei TON.COM, die auch schon die beiden anderen Assembler geliefert haben.
5. Der integrierte Assembler von Turbo Pascal
Mit der Anweisung ASM lassen sich Assemblerbefehle auch in ein Pascalprogramm einbauen. Dabei ist zu beachten, daß Labels mit dem Klammeraffen beginnen müssen und Kommentare in geschweifte Klammern gestellt werden müssen:
begin
ASM
mov dx,8020h {Portadresse }
xor ax,ax {Zähler auf 0 }
@Marke: out dx,al {Ton erzeugen
}
dec ax {Zähler -1
}
jnz @Marke {Schleife }
mov ax,4c80h
out dx,al {Ton aus }
int 21h {beenden
}
end;
end.
Kompiliert mit TP 6.0 ergibt dieser Quelltext ein 1488 Bytes langes .EXE-Programm. Da der Befehl int 21h das Programm vorzeitig beendet, sollte man diese Zeile besser weglassen. Es ist aber auch möglich (z.B. mit DEBUG), unsere 15 Bytes aus dem .EXE Programm herauszuschneiden und als .COM-Programm zu speichern. Der betreffende Abschnitt reicht übrigens vom 16. bis zum 30. der 1488 Bytes.
Wie geht's weiter?
Wer selbst Assemblerprogramme für den Portfolio entwickeln will,
kommt nicht umhin, sich ein wenig mit der Architektur (insbes. Registersatz)
des 8086 vertraut zu machen. Außerdem benötigen wir einen gewissen
Vorrat an Befehlen. Zum Glück ist man hier mit einem guten Dutzend
schon recht gut gewappnet. Ein weiterer Schwerpunkt ist die Ein- und Ausgabe,
sowohl über das Betriebssystem als auch durch direkte Hardwarezugriffe.
Aus Platzgründen können diese Themen leider erst in den kommenden
Heften behandelt werden.
Fragen und Anmerkungen bitte an .
Eventuelle Korrekturen oder Ergänzungen werden zu finden sein
auf der WWW-Seite:
http://leute.server.de/peichl/pf.htm