Ich selber hate vor dem Studium praktisch keine Ahung von Assembler, wollte aber meine Progrämmchen ausprobieren können. Daher habe ich hier zusammengetragen, was mir dabei zum Thema Assembler untergekommen ist.
Wir machen in TGI ja nur 16-Bit Real Mode Assembler,
weshalb die Programme unter Linux nicht direkt laufen.
Unter DOS ist das kein Problem. Daher habe ich meine
DosEmu eingerichtet, um da drin die Programme testen
zu können.
Die Beschreibungen hier drin gelten also für Windowser
und Linuxler gleichermaßen.
Ich bin gebeten worden, eine HowTo zur DosEmu zu schreiben. Mache ich vielleicht noch wenn ich mal Zeit dazu habe, aber ansich geht das recht leicht und existiert einiges an Dokumentation dazu.
Natürlich wollte ich nichts für den Assembler zahlen.
A86 hate ich getestet, ist soweit auch ganz in Ordnung,
aber leider ShareWare.
Daher bin ich jetzt bei NASM
gelandet. Der Netwide Assembler ist für diverse Plattformen
verfügbar, frei, und macht einen guten Eindruck.
Außerdem ist eine recht gute Dokumentation dabei.
Ich kann damit sogar meine Programme unter Linux assemblieren
(NASM ist bei SuSE Linux dabi, aber eine alte Version),
um sie dann unter DOS auszuführen.
Aufgerufen wird NASM unter DOS mit:
nasm16 -o file.com file.asm
und unter Linux mit:
nasm -f bin -o file.com file.asm
Die Datei beginnt mit dem Kommando org 0100h, da .COM-Dateien unter DOS an der Adresse 100H anfangen.
Um Aufteilung des Programmes in Code- und Datensegment kümmere ich mich nicht, ich schreibe einfach alles in ein Segment.
Dann kann gleich der erste Befehl kommen. Falls am Anfang der Datei noch Variablen definiert werden sollen, sollte der erste Befehl ein JMP zur Startadresse sein.
Die Schnittstelle zu DOS wird über Interrupt 33 (021H) hergestellt. Dabei sind besonders zwei Funktionen Interessant, die durch einen entsprechenden Wert in AH ausgewählt werden:
Funktion 04CH benndet das Programm, der Rückgabewert
(=Programmstatus=Errorlevel) steht in AL.
Ein "normales" Programmende sieht also so aus:
MOV AX, 04C00H
INT 33
Funktion 040H gibt Daten in eine Datei oder auf die Konsole aus. Dabei enthält DX die Speicheradresse der auszugebenden Bytes und CX die Anzahl der Bytes. BX bezeichnet das Ausgabeziel, dabei ist insbesondere 1 die Standard Ausgabe, also was auf dem Schirm ausgegeben wird bzw. in eine Datei umgeleitet werden kann.
Beispiel:
ORG 0100H JMP prog str: 'Hallo, Welt!',13,10 prog: MOV DX, str MOV CX, 14 MOV AH, 040H INT 33 MOV AX, 04C00H INT 33
Um mächtigere und einfachere Ausgaben vorzunehmen habe ich eine eigene printf-artige Funktion geschrieben, die auch in meinen Aufgabenlösungen zu finden ist. Allerdings bin ich noch nicht ganz zufrieden damit, ich denke ich werde die noch mal neu schreiben, und laufend weiterentwickeln.
Die Syntax von NASM ist in der Dokumentation erklärt, auf ein paar Punkte möchte ich dennoch kurz eingehen.
Zugriffe auf Speicherbereiche müßen immer in Eckigen Klammern stehen. Der Name der Speicherstelle alleine steht für die Adresse, nicht die darin enthaltenen Daten.
Daraus folgt auch, daß OFFSET überflüssig ist und daher aus dem Assembler-Sprachumfang entfernt wurde.
Außerdem muß alles, was zu einer Adresspezifikation gehört in ein Paar eckige Klammern, mehrere Klammern hintereinander oder Bezeichner außerhalb der Klammern sind nicht erlaubt.
Ist aus dem Zusammenhang nicht klar, welche Größe ein so adressiertes Speicherelement hat, so wird vor die eckigen Klammern BYTE oder WORD geschrieben.
NASM kann mit -f obj auch Objektdateien für Linker erzeugen, damit kann man Assembler mit Hochsprachen kombinieren. Da ich aber kein frei verfügbares 16-Bit C gefunden habe, habe ich diesen Weg nicht weiter verfolgt.
Soweit zu den Grundlagen, wenn's was neues gibt ergänze ich das hier.