Adok's Way to Assembler
Folge 2

Nun sind wir endlich bei unserem ersten Beispielprogramm angelangt!

MODEL TINY    ;Fr COM-Files
CODE SEGMENT  ;Beginn Code-Seg
ASSUME CS:CODE;Zuweisung an CS
ORG 100h      ;Startadresse COM
start:        ;Startlabel
 MOV AX,0902h ;Funkt. 9h, ASCII-Code 2h
 MOV BX,15    ;Farbcode Wei
 MOV CX,1     ;Anzahl der Zeichen = 1
 INT 10h      ;Zeichen auf Screen bringen
 MOV AX,4C00h ;Funkt. 4Ch
 INT 21h      ;DOS-Exit
CODE ENDS     ;Ende Code-Seg
END start     ;Ende des Proggys

Um aus diesem Listing eine ausfhrbare COM-Datei zu erzeugen, tippt es mit dem
MS-DOS-Editor ab, speichert es in eurem TASM-Verzeichnis ab und gebt unter DOS
folgendes ein:

TASM /T/L progname      => erzeugt die Datei progname.OBJ
TLINK progname /t       => linkt die OBJ-Datei zu COM

'progname'  steht  hierbei fr den  Namen des Programms ohne Dateierweiterung.
Habt  ihr  das Listing beispielsweise  als  KURS0001.ASM gespeichert, mt ihr
statt progname KURS0001 schreiben.

+++ Interrupt 10h Funktion 9 +++

Wenn  ihr anschlieend das COM-File startet,  erscheint ein schner Smiley auf
eurem  Bildschirm! Wie funktioniert das? Ganz  einfach: Das Proggy benutzt den
Funktion 9 des Interrupts 10h, welche ein einzelnes Zeichen auf dem Bildschirm
ausgibt, ohne die Cursorposition zu ndern. Das heit, wenn danach noch einmal
dieser  Interrupt aufgerufen wird, berschreibt das  neue das alte Zeichen. So
funktioniert's:  AH=9,  AL=ASCII-Code des Zeichens  (im Beispiel 2), BH=Nummer
der Bildschirmseite, auf die geschrieben werden soll (i.B. 0), BL=Farbattribut
des  Zeichens  (i.B. 15), CX=wie oft  das Zeichen ausgegeben werden soll (i.B.
1).  Doch  bevor wir auf den "Sinn"  des Programms nher eingehen, schauen wir
uns an Hand dieses Beispiels den Aufbau einer COM-Datei an.

+++ Aufbau einer COM-Datei +++

Zeile 1:  MODEL TINY     Gibt das Speichermodell an. Fr COMs kommt  nur  TINY
                         in Frage. Fr EXEs gibt's auch:
                         SMALL:    Codeseg und Dataseg zusammen kleiner 64 KB
                         MEDIUM:   Code < 64 KB, Summe aller Datasegs > 64 KB
                         COMPACT:  ein Codeseg, mehrere Datasegs
                         LARGE:    Summe der Segmente > 64 KB
                         HUGE:     alles ist erlaubt!
                         Summe bedeutet, da das Proggy mehrere  Codesegmente,
                         Datasegmente,...  haben kann,  aber ein einzelnes Seg
                         nicht grer als 64 KB sein darf.
Zeile 2:  CODE SEGMENT:  Das ist der Anfang des Codesegs,  in  dem  (normaler-
                         weise) die Befehle eines Programms stehen!
Zeile 3:  ASSUME CS:CODE Dadurch wird dem CS-Register befohlen,  auf das Code-
                         segment zu zeigen.
Zeile 4:  ORG 100h       Besonders wichtig  bei  COM-Dateien!  Diese  beginnen
                         immer  bei  der  Adresse CS:100h. (Erinnert ihr euch?
                         Das ist Segment:Offset-Schreibweise!) Der Grund dafr
                         ist, da DOS beim Starten eines Programms  ein  soge-
                         nanntes PSP einfgt, das von CS:0 bis CS:FFh reicht.
Zeile 5:  start:         Ein  Label!  Genauso  wie  in  Basic bestehen sie aus
                         einem Namen und  einem  Doppelpunkt.  Jede  COM-Datei
                         bentigt  ein  solches Label am Anfang des Programms.
                         Bei EXEs ist es nicht notwendig. Man  kann  natrlich
                         auch innerhalb  des Programms  Labels verwenden,  die
                         sich mit den verschiedenen  Jump-Befehlen  anspringen
                         lassen.
Zeile 12: CODE ENDS      Ende des Codesegs.
Zeile 13: END start      Ende des Programms.

+++ Der MOV-Befehl und seine Varianten +++

So, das ist es! Auf den ersten Blick scheint es sehr viel zu sein, ist es aber
nicht. Nun zum eigentlichen Programm... Die 6. Zeile lautet MOV AX,0902h. Hier
haben   wir   einen  neuen  ASM-Befehl.   MOV   entspricht  der  Zuweisung  in
Hochsprachen,  man  kann damit einer  Speicheradresse oder Register einen Wert
zuweisen.  Syntax:  MOV  Ziel,Quelle. Die Quelle  ist  der  Wert, der dem Ziel
zugewiesen werden soll. Dabei gibt es mehrere Varianten:

MOV AX,0902h          Eine   Konstante   wird   einem   allgemeinen   Register
                      zugewiesen.
MOV AX,BX             Der  Inhalt  eines   allgemeinen  Registers  wird  einem
                      anderen allgemeinen Reg zugewiesen.
MOV AX,[0A000h]       Einem allgemeinen Reg wird der Inhalt der Speicherstelle
                      DS:0A000h zugewiesen. Was in eckigen Klammern steht, ist
                      also der Offset.
MOV AX,ES:[0A000h]    Mit Segment-Override: Statt DS:0A000h wird AX der Inhalt
                      von ES:0A000h zugewiesen.
MOV AX,[BX]           Besonders tricky: indirekte Adressierung.  AX  wird  der
                      Inhalt  der  Speicherstelle zugewiesen, deren Segment DS
                      und deren Offset der Inhalt von BX  sind.  Ist  BX  also
                      beispielsweise  1000h,  wird  AX der Inhalt von DS:1000h
                      zugewiesen. Doch Vorsicht:  Die  indirekte  Adressierung
                      funktioniert  nur  mit  einigen Registern wie BX und BP!
                      Man kann also nicht MOV AX,[DX]  schreiben.  Dafr  geht
                      indirekte Adressierung auch mit Segment Override.
MOV WORD PTR 1000h,AX Der  Inhalt von AX  wird auf die Speicherstelle DS:1000h
                      geschreiben.
MOV AX,0              HOT TIP! Diese Variante ist zwar nicht verboten, aber es
                      gibt eine viel schnellere Mglichkeit,  ein  allgemeines
                      Register  auf  0 zu setzen: XOR AX,AX! Hiermit wird eine
                      XOR-Bitverknpfung zwischen AX und sich selbst  durchge-
                      fhrt. Folge: Der Inhalt von AX wird gelscht.

Folgende Varianten funktionieren jedoch NICHT:

MOV ES,0A000h         Einem  Segmentregister  kann  keine  Konstante  oder der
                      Inhalt einer Speicherstelle zugewiesen werden!  Hier mu
                      man  den  Umweg  mit  einem allgemeinen Register machen,
                      also: MOV CX,0A000h und dann MOV ES,CX.
MOV DX,[AX]           Indirekte Adressierung funktioniert  nur  mit  Registern
                      wie BX, BP, DI und SI.

Noch  etwas zu WORD PTR: Wenn man einer Speicherstelle/Variablen etwas zuweist
oder  ihren Inhalt einem Register zuweist, ist es manchmal unklar, ob ein Byte
oder ein Word (2 Bytes) gelesen/geschrieben werden soll. Aus diesem Grund kann
man vor einer Speicherstelle BYTE PTR bzw. WORD PTR schreiben. Beispiel:

MOV WORD PTR 1000h,AX schreibt 2 Bytes an die Adresse 1000h. Dadurch wird auch
                      der Inhalt der Adresse 1001h verndert!
MOV BYTE PTR 1000h,AL schreibt 1 Byte an die Adresse 1000h.  Hier  bleibt  die
                      Adresse 1001h unverndert.

+++ Zum Beispielprogramm +++

ENDLICH!  Das hat gedauert. Aber Theorie mu sein, besonders in Assembler. Nun
knnen wir uns das Proggy unter die Lupe nehmen.

Zeile 6:  MOV AX,0902h   Damit wird AX der Wert 0902h zugewiesen. Hm, was soll
                         das bedeuten? Genau nachdenken, bevor ihr weiterlest!
                         Ein Tip: Um ein  Zeichen  mittels  INT  10h  Funktion
                         (Ufo :-) ) 9 auszugeben,  mssen in AH die Funktions-
                         nummer (also 9) und in AL der ASCII-Code  stehen.  AH
                         und AL sind... Na, ein Licht aufgegangen? Richtig, AH
                         ist  das  Hi-  und  AL das Lo-Byte von AX! Wie wir in
                         Folge 1 festgestellt haben, ist ein  Word  vier  Hex-
                         Stellen  gro.  Die  oberen  zwei  sind  das Hi-, die
                         unteren das Lo-Byte. Genau das ntzen wir  hier  aus:
                         Wenn wir AX die vierstellige Hex-Zahl 0902h zuweisen,
                         erhlt automatisch AH den Wert 9 und AL 2.  Das spart
                         einige  Nanosekunden  Rechenzeit! (Wir ASM-Coder sind
                         alle so optimierungswtig... :-) )
Zeile 7:  MOV BX,15      Weist BX den Wert 15 zu. Damit wenden wir  den  Trick
                         noch einmal an:  BL erhlt den Farbcode von Wei, und
                         BH (die Bildschirmseite) wird auf 0 gesetzt.
Zeile 8:  MOV CX,1       Weist CX den Wert 1 zu. Also  wird  das  Zeichen  nur
                         einmal ausgegeben.
Zeile 9:  INT 10h        Ruft den Interrupt 10h auf, der den Smiley ausgibt!

+++ Interrupt 21h Funktion 4Ch +++

Gaaaanz  wichtig sind Zeilen 10 und 11!  Diese rufen den Interrupt 21h Ufo 4Ch
auf.  Dieser beendet das Programm und gibt  den Wert, der sich in AL befindet,
als Errorlevel zurck. Der Errorlevel kann dann beispielsweise von BAT-Dateien
mit IF ERRORLEVEL GOTO abgefragt werden. Wenn ihr diesen Interrupt am Ende des
Programms verget, wird das Programm nicht beendet, und der Computer fhrt die
Befehle aus, die sich im Speicher NACH dem Programm befinden - das kann leicht
zu einem Systemabsturz fhren!

Das  war... Moment, die Strichpunkte, die  Semikolons. Das sind nichts anderes
als  Kommentare.  Und somit ist Schlu fr  heute.  Bis zur dritten Folge viel
Spa wnscht euch (wieder einmal) euer Adok!
