Die ersten Programmierschritte in Assembler

Zurück

Jetzt wird es ernst :) Nein, keine Angst, Assembler ist gar nicht so schwer. Ich muss zugeben, dass ich Assembler am Anfang auch erschreckend fand. Lauter Befehle mit JMP, MOV, CALL, LOOP usw... und das in einer Schlange untereinander. Wie soll denn da was gehen? Hmmm... warum schauen wir uns das nicht mal an ;)

Es gibt ein Programm, dass jeder Programmierer am Anfang schreiben muss. Ich rede von dem Programm "Hello world!". Das ist so Tradition! übrigens: Alle Programme, die man hier sieht, findet man im Ordner "Beispiele".

Geh doch mal in die Eingabeaufforderung und ruf den Editor auf. Gib danach den folgenden Code ein. Wie er funktioniert, erklauml;re ich dann. Gleich zum Merken: In Assembler funktioniert sehr viel mit Adressen.

hello.asm (Windows-1250 Zeichenkodierung)

    .MODEL Small             ;wir basteln eine kleine EXE Datei :) 
    .STACK 100h              ;100h (im Dezimalen 256) gibt die Grouml;ße des Stacks an
    
    .DATA                    ;hier beginnt der Datenabschnitt
Nachricht DB "Hello world!$" die Zeile, die wir ausgeben wollen

    .CODE                    ;hier beginnt der Codeabschnitt

Start:                       ;Einsprungspunkt (wo gestartet wird)
                             ;zuerst müssen wir mal unser Datensegment vorbereiten

    mov ax,@data             ;die Segmentadresse des Datensegmentes ins Register AX
    mov ds,ax                ;DS die Segmentadresse des Datensegmentes mitteilen

    mov dx,OFFSET Nachricht  ;Offsetadresse von Nachricht dem Datenregister mitteilen
    mov ah,09h               ;ins Register AH die Funktion 9 reinschreiben
    int 21h                  ;die Funktion (9=Text ausgeben) im Register AH ausführen

    mov ah,4Ch               ;nun schreiben wir die Funktion 4C (Beenden) nach AH
    int 21h                  ;Funktion im Register AH ausführen

END Start                    ;Ende des Einsprungpunktes angeben

Gehen wir mal Schritt für Schritt jede Zeile durch. Das ";" für ein Kommentar steht, ist glaub ich nicht schwer zu erraten ;)

.MODEL Small
Mit .MODEL wird angegeben, um was für einen Typ von Datei es sich handelt. Da wir wir nur eine kleine EXE Datei programmieren, die nicht mehr als 64KB hat, wauml;hlen wir Small. Bei dieser Art von EXE, wird dem Programm im Arbeitsspeicher ein Segment für die Daten und ein Segment für den Code zugewiesen, was bedeutet, dass die Daten ein eigenes Segment haben und der Code auch.

.STACK 100h
Mit .STACK wird die Grouml;ße des Stacks in Byte angegeben, den wir benouml;tigen. 100h ist Hexadezimal und hat im Dezimalen den Wert 256. Wird kein Wert angegeben, werden automatisch 1024 Byte festgelegt.

.DATA
Mit
.DATA teilen wir dem Assembler mit, dass hier der Datenabschnitt beginnt. Das Ende des Datenabschnittes müssen wir nicht kennzeichnen, da dieser automatisch aufhouml;rt, sobald ein neuer Abschnitt anfauml;ngt.

Nachricht DB "Hello world!$"
Hier erstellen wir eine Variable vom Typ Byte (
DB=Define Byte)und weisen dieser den Text "Hello world!$" zu. Zuerst kommt der Name der Variable, also "Nachricht" dann der Typ, was "DB" ist und dann der Wert der Variable, was in unserem Falle "Hello World!" ist. Halt! Da fehlt doch das $ Zeichen. Richtig :), dass gehouml;rt ja nicht zum Text. Das $ Zeichen teilt dem Assembler mit, wo sich das Ende unseres Textes befindet. Hier der komplette Aufbau einer Variable im überblick: 
<
Name der Variable> <Typ> <Inhalt bzw. Wert>

.CODE
Mit .CODE teilen wir dem Assembler mit, dass nun der Code kommt, also die Befehle.

Start:
Mit dem Label Start: geben wir den Einsprungspunkt in der Datei an. Was ist ein Einsprungspunkt? Wenn man ein Programm startet, muss es ja irgendwo in der Datei mit der Ausführung der Befehle beginnen. Tja, mit
Start: legen wir diesen Punkt fest, also den Punkt, wo in die Datei gesprungen wird und angefangen wird, Befehle auszuführen. Das Ende dieses Abschnittes geben wir dann spauml;ter mit END Start an.

mov ax,@data
Wir müssen jetzt angeben, wo sich was befindet. Die Konstante @data enthauml;lt die Adresse unseres Datensegmentes, welches wir DS mitteilen müssen. Nun kouml;nnen wir aber nicht einfach so DS die Adresse unserer Daten mitteilen, da man einem Register nicht direkt den Wert einer Konstanten mit MOV übertragen kann. Wir müssen einen Umweg über die Register machen. Dazu nehmen wir das Register
AX. Mit dem Befehl mov, kann ich Werte hin und her moven (übertragen). Die Quelle wird dabei nicht verauml;ndert. mov ax,@data bedeutet dann also, dass die Adresse von @data nach ax übertragen (eher kopiert) wird. Hier der komplette Aufbau von dem Befehl mov:
mov <Ziel>,<Quelle>

mov ds,ax
Hier übertragen wir nun den Wert von
AX, welches die Segmentadresse von unserem Datensegment beinhaltet, nach DS. Wie wir wissen, ist ja eine Adresse folgend aufgebaut: Segmentadresse:Offsetadresse Nun ja, die Segmentadresse hauml;tten wir von @data über den Umweg mit den Registern schon mal übertragen. Unser Datensegment ist bereit und als nauml;chstes geben wir an, auf welche Daten wir im Datensegment zeigen wollen.

mov dx,OFFSET Nachricht
Durch den Befehl
OFFSET, wird die Offsetadresse von Nachricht nach DX übertragen, womit wir nun auf unsere Nachricht zeigen. DS hat ja die Adresse von unserem Datensegment und DX zeigt im Datensegment auf unsere Nachricht.

Falls es ein wenig verwirrend war, kouml;nnte die folgende Tabelle einen kleinen überblick vermitteln:

Segmentadresse : Offsetadresse
DS : DX

Wie man vielleicht sieht, kouml;nnten wir nun mit DS:DX auf beliebige Daten zeigen. Hauml;tten wir nun noch eine zweite Nachricht, müssten wir nur DX den Offset der zweiten Nachricht übertragen und wir würden auf die zweite Nachricht zeigen. Merken wir uns vorerst nur mal, dass man mit DS:DX auf Daten zeigen kann.

mov ah,09h
Unser Datensegment haben wir bereits angegeben und wir zeigen auch schon auf unsere Nachricht. Jetzt fehlt nur noch, dass der Datensatz ausgegeben wird. Für solche Operationen gibt es Interrupts mit Funktionen. Ein Interrupt ist eine Unterbrechung des Programmes, um ein Unterprogramm (z.B. Text ausgeben) aufzurufen. Es gibt verschiedene Intertupts mit verschiedenen Funktionen. Da es sehr viele sind, ist es wohl am Besten, sich eine Interruptliste herunterzuladen. Wir brauchen jetzt die Funktion
9 vom Interrupt 21h, die Texte ausgibt. Die Funktionsnummer 9 wird mit mov ah,09h nach AH übertragen.

int 21h
Mit int 21h führen wir nun den Interrupt 21h aus. Der Interrupt schaut in AH nach, wo er die 9 findet und weis, dass er die Daten ausgeben soll, auf welche DS:DX zeigt.

mov ah,4Ch
Der Text wurde ausgegeben und nun müssen wir unser Programm noch beenden. Hier gibt es wieder eine Funktion, die das für uns erledigt. Es ist die Funktion
4Ch des Interrupts 21h, also setzen wir in AH den Wert 4Ch.

int 21h
Wie es zu erwarten war, führen wir den Interrupt
21h aus, der in AH 4Ch vorfindet und somit weis, dass er die Funktion 4Ch ausführen soll => Programm beenden :)

END Start
Diese Zeile haben wir oben schon besprochen. Sie gibt nur an, dass hier der Einsprungspunkt zu ende ist.

Puhhh... war nicht gerade leicht, oder? Es ist aber wichtig, dieses erste Programm zu verstehen. Lest es so lange durch, bis ihr es verstanden habt. Da kann ich nur hoffen, dass ich keinen Unsinn geschrieben habe ;) - bei mir funktioniert das Programm zumindestens. Ah ja, ausführen wollen wir das Proggi ja auch noch. Speichert die Datei unter dem Namen hello.asm ab und beendet den Editor.

Um das Programm zu assemblieren schreiben wir "ml /c hello.asm". Das /c schreiben wir deshalb, dass er nur die Objektdatei erzeugt und sie nicht mit LINK.EXE linkt, da wir ja DLINK.EXE für's DOS brauchen.

F:\Assembler Tutorial\Beispiele\Hello_world>ml /c hello.asm
Microsoft (R) Macro Assembler Version 6.14.8444
Copyright (C) Microsoft Corp 1981-1997. All rights reserved.

Assembling: hello.asm

F:\Assembler Tutorial\Beispiele\Hello_world>

Assembliert hauml;tten wir das Programm. Nun haben wir eine Objekt Datei mit dem Namen hello.obj. Warum macht der eine Objektdatei? Ganz einfach. Man kouml;nnte jetzt verschiedene kleine Programme erstellen und die Objekt Dateien miteinander linken. Das bedeutet, dass man z.B. eine Anwendung schreibt, die auch eine Info ausgibt. Die Objektdatei dafür kouml;nnte info.obj heißen. Wenn man nun irgendwann mal eine Anwendung schreibt, braucht man die Info nicht immer neu zu schreiben, sondern kann die info.obj einfach mitlinken. Man kann die Objektdateien als Bausteine betrachten, die der Linker zusammenfügen kann. Wir haben in unserem Fall nur hello.obj, welche wir durch den Befehl dlink hello linken. Wie man sieht, braucht man hier die Erweiterung bei hello.asm, also das .asm, nicht angeben. Beim Linken wartet er 4 mal auf Eingaben. Einfach immer nur Enter drücken.

F:\Assembler Tutorial\Beispiele\Hello_world>dlink hello

Microsoft (R) Segmented Executable Linker Version 5.60.339 Dec 5 1994
Copyright (C) Microsoft Corp 1984-1993. All rights reserved.

Run File [hello.exe]:
List File [nul.map]:
Libraries [.lib]:
Definitions File [nul.def]:

F:\Assembler Tutorial\Beispiele\Hello_world>

Und zum Abschluss probieren wir unser Meisterwerk aus:

F:\Assembler Tutorial\Beispiele\Hello_world>hello
Hello world!
F:\ASSEMB~1\BEISPI~1\HELLO_~1>

Wie man sieht, funktioniert alles :) Gratulation! Du hast soeben dein erstes Assemblerprogramm geschrieben.

 

Letzte auml;nderung: 29. Mai 2003]