Assembler-Beispiel 1


Ausgabe "Hello World" auf dem Bildschirm

Im ersten Beispiel sollen alle Schritte exakt beschrieben werden.
Zunächst starten wir die Oberfläche und vereinbaren das Programm:
    hallo.asm
(Groß- oder Kleinschreibung spielt keine Rolle; Erweiterung muss "asm" sein; Name (vor Punkt) darf max. 8 Zerichen lang sein)
Die Oberfläche hat nun folgendes Aussehen:

Editor
Mit dem Kommando <e> kommen wir zum systemeigenen Editor und schreiben das folgende Programm:

In der Zukunft wollen wir soweit wie möglich zur Darstellung immer den WINDOWS-Editor nutzen, die Sichtbarkeit ist besser, also sieht das nun so aus:

Als Programm-AblaufPlan (PAP):

    Die erste Zeile beginnt mit einem ";", alles was diesem Zeichen folgt ist bis zum Ende der Zeile Kommentar, ";hallo.asm" ist also nur der Name des Programms!

Die zweite Zeile beginnt mit einem ".", also folgen jetzt Segment-Direktiven.
Es wird das "Tiny-Modell" vereinbart und in der nächsten Zeile ein entsprechendes Code-Segment. Ab nächster Zeile folgen nun die Befehle (die im Code-Segment gespeichert werden; auch die Daten müssen hier liegen).

Leerzeilen können beliebig sein.

Die nächste Zeile beginnt mit einer Zeichenkette, die mit ":" beendet wird.
Solche Folgen werden als Marke bezeichnet. Danach folgt mindest ein Leerzeichen oder Tabulator und dann der Befehl. In diesem Fall ein 16Bit Transportbefehl, was in CS (Register Code-Segment) steht wird ins Register AX transportiert. Die Marke "start" deutet an, dass hier das Programm gestartet wird, "start" kann auch entfallen, dann beginnt das Programm in der ersten Zeile, und die Marke muss auch nicht "start" heißen.

Die nächste Zeile beginnt gleich mit mindest einem Trennzeichen, sonst würde versucht werden, den Befehl als Marke zu interpretieren, das ist natürlich falsch.
Und es wird der Inhalt von AX nach DS (Register Daten-Segment) transportiert.
Die beiden Befehle sind eigentlich unsinnig, denn es wird CS nach DS transportiert, also doch: MOV DS,AS -
richtig, den Befehl gibt es aber nicht, also der Umweg.
CS und DS haben nun den gleichen Wert, Daten und Befehle liegen im gleichen Segment!
Genau genommen, haben wir nun wieder eine "von Neumann" Maschine, denn Code und Daten liegen in einem Speicher!

Bei der Interrupt-Betrachtung hatten wir schon festgestellt, dass die Nutzung des Bildschirmes und der Tastatur besser über Systemfunktionen zu realisieren ist, als alles selbst zu organisieren.
So sind dann auch die nächsten 3 Befehle zu verstehen.
Es soll eine Ausgabe eines Textes auf den Bildschirm durchgeführt werden. Dazu nutzen wir den Interrupt 21h mit der Funktion 9. Die Funktion hat folgende Regeln:

In AH muss die Funktions-Nummer gespeichert werden: MOV AH,09h
(das h muss nicht sein, da 9h = 9(dez) ist). Nach DX (16Bit D-Register) muss die Anfangsadresse vom Text - die kennen wir exakt nicht. In der vorletzten Zeile steht der Text. Das ist eine Konstanten-Vereinbarung in Byte (db - definiere Byte). Und wieder eine gute Sache, denn wir können den Text einfach als ASCII-Zeichenfolge aufschreiben, das System wandelt das alleine in hex um. Die Folge muss in "Text" stehen. Am Zeilenanfang gibt es eine Kennung, damit man die Stelle findet (die Kennung, in diesem Fall "text", hat am Ende keinen ":"). Deshalb nun: MOV DX,OFFSET text
Also von der Basisadresse Datensegment weiter bis "text" (muss der Assembler selbst berechnen) und da beginnt der Text.

Dann folgt der Aufruf eines weiteren Interrupts 21h mit der Funktion 8 - das ist eine Tastatur-Eingabe, das System wartet darauf.

Diese Aktion muss nicht sein, ist aber sinnvoll, denn er würde sofort nach der Ausgabe das Programm beenden, man sieht nichts.

Der nächste Interrupt 21h Funktion 4ch muss unbedingt sein, das Programm gibt die Steuerung wieder ans Betriebssystem ab, anderenfalls wird das Fenster geschlossen.

Den Befehl muss man immer schreiben!

In der letzten Zeile steht die Segment-Direktive "end" und danach das Startsymbol. Hier könnte man in Übereinstimmung mit dem Anfang auch etwas anderes schreiben

Assembler
Der Assembler wird mit dem Kommando <a> aktiviert. Das System zeigt dann Folgendes an (Ausschnitt):


Es gibt keine Fehlermeldung und auch keine Warnung. Fehler wollen wir später auch betrachten.
In der Oberfläche entsteht nun ein Eintrag mehr, die Datei "HALLO.obj":

Nicht sichtbar aber eben so interessant ist die ebenfalls entstandene "LST-Datei". Wir wollen diese wieder wegen der besseren Lesbarkeit mit dem WINDOWS-Editor darstellen. Man könnte sie hier auch bearbeiten, das bringt aber keinen Nutzen, das ist eine Ergebnis-Datei:

    Im oberen rechten Teil finden wir wieder unser Programm.

Links davon, immer in der gleichen Zeile, erscheint die Codierung der Befehle. Da sieht man auch sofort, dass die Segmentdirektiven, das sind Assemblerbefehle, nicht codiert werden, das sind ja auch nur Organisationen.
Nur ein Hinweis, die Liste sieht etwa so aus wie bei ERNA, zuerst die Zeilen-Nummer (dez), dann die Befehls-Nummer (hex), die Befehls-Codierung (hex) und die Operenden (hex).
Das Programm geht erst in Zeile 5 los. In Zeile 8 erfolgt der Verweis auf die Adresse 13(hex)(es gibt 4 Zeichen, also 2Byte-Adresse und damit max 64K). Schaut man zur Adresse 13(hex), so stehen da die ASCII-Werte der Zeichenkette. Interessant ist, was das Zeichen "$" da soll, es wird auch codiert, das testen wir später noch! Das "+" sagt nur aus, dass es in der nächsten Zeile weiter geht.
Das Maschinen-Programm wird wie bei "ERNA" aus Spalte 3 und 4 erzeugt (!Adr. werden anders generiert!):

8C C8 8E D8 BA 00 13 B4 09 CD 21 B4 08 CD 21 68 65 6C 6C 20 77 6F 72 6C 64 21 24

Da wir hier mit Byte arbeiten, sind die Werte nun immer 2 Ziffern lang.

Im unteren Teil gibt es Informationen zum Programm, der Profi wird das sicher gut nutzen können, wir brauchen es im Moment nicht.

Die "LST-Datei" erweist sich auch sehr nützlich bei der Fehlersuche, denn nur hier wird die Fehlerposition etwas genauer beschrieben!

Interessant ist auch, dass die "obj-Datei" vorhanden ist, die möchte man sich auch vielleicht ansehen. Das sollte man aber nur mit dem Kommando <o> tun, hier wird der Viewer von Norton aufgerufen, nur der kann solche Dateien ordentlich darstellen. Ruft man den auf, erscheint folgendes Bild:


Das ist natürlich nur wirres Zeug, aber es gibt die sehr nützliche Taste <F4>, dann erscheint von diesen Teil der lesbare "hex-dump":


Zugegeben, so viel besser ist es auch nicht, hier steht eben noch alles drinn, es ist noch keine "exe-Datei". Was man aber merken sollte ist, dass die Adresse mit einer 5-stelligen hex-Zahl angegeben wird, nun also 1MByte Speicherbereich!
Das eigentliche Programm beginnt ab Speicherplatz: 000A2 und endet bei 000C1.

Linker
Mit <l> wird der Linker aufgerufen. Nach der Abarbeitung zeigt er folgende Ausschrift:


Er warnt, dass kein Stack vorhanden ist, brauchen wir ja auch nicht. Für die Abarbeitung hat das keinen Einfluß.
Folgerichtig erscheint in der Oberfläche die Ausschrift zur "exe-Datei":


exe.Datei
Nun können wir uns auch die "exe-Datei" ansehen. Dazu nutzen wir das Kommando <h>. Der "hex-dump" bezieht sich nur auf die "exe-Datei". Wieder wird der Viewer genutzt:


Das bringt natürlich erst was, wenn wir die <F4> Taste nutzen:


In der ersten Zeile gibt es auch noch Informationen, wichtig ist es für uns ab Adresse 00200h. Das ist nun die feste Adresse, so wird das Programm immer in den Speicher geladen.
auf Adresse 205h und 206h steht die Adresse des Anfangs der Zeichenkette (nieder-, höher-wertiger Teil), also um 13 Plätze weiter, also 207(1) ... 209(3) 20A(4) ... 20F(9) 210(10) 211(11) 212(12) 213(13) - da muss der erste Wert vom Text stehen - stimmt!
Auch das "$"-Zeichen ist noch vorhanden.

Nun wollen wir natürlich auch sehen, ob es funktioniert, dazu geben wir mit <r> das Kommando zum Abarbeiten - und es geht:


Interessant ist, dass das Programm nur 32 Byte lang ist, das kriegt man mit der Sprache C nicht und mit C++ schon gar nicht so kurz hin, da braucht man immer mehrere KByte.

Eigentlich können wir zufrieden sein, es bleiben aber ein paar Fragen:


Die letzte Frage kann man ganz schnell beantworten, das geht nur mit BIOS-Funktionen, also INT 10h. Das müsste man vor der Ausgabe durchführen.

Zur zweiten Frage ist zu sagen, dass die Ausgabe an der aktuellen Kursor-Position erfolgt. Eine Steuerung ist nur möglich, wenn entsprechend viele Leerzeichen und Zeilen ausgegeben werden (ist umständlich) oder wieder mit BIOS-Funktionen, da muss man aber wissen, wie der Bildschirm organisiert ist!

Zur ersten Frage
Die Ausgabefunktion überträgt stur Byte-weise alle Zeichen auf den Bildschirm (der Bildschirm ist Teil des Hauptspeichers, also werden nur Werte von einem Speicherbereich in einen anderen transportiert). Das "$"-Zeichen ist die Endekennung des Textes, die wird gesucht und dann hört die Funktion mit der Übertragung auf.
Im folgenden Beispiel wurde das "$" entfernt, nun durchläuft das System den 64K Sektor, findet er eine Endekennung hört er auf, findet er Nichts, läuft das Programm unendlich! Im Beispiel wurde eine Endekennung gefunden.


Im Beispiel 2 wollen wir auf weitere Eigenschaften des Systems eingehen, es ist eine Erweteirung dieses Beispiels.

zurück zur Start-Seite (Beispiele)   /   weiter Beispiel 2
zurück zur Start-Seite