0. Vorvorwort:
Ich zeige in diesen Workshop, wie man mit den Borland Turbo Assembler arbeitet und ich beziehe mich natürlich auf die Computer, die fast jeder haben sollte, also ein x86. Ich habe jedenfalls einen Intel Processor, aber ich weiß nicht, wenn ihr ein anderen habt, dann kann da was nicht funktionieren, aber sollte eigentlich schon, wenn es x86er sind, man weiß ja nie. Man sollte sich QuickBasic 7.1 downloaden, dort ist alles drin.
1. Vorwort:
Da es mein erster Kurs ist, werde ich praktisch bei Null anfangen. Die Vorraussetzung ist, dass ihr den Turbo Assembler von Borland (TASM) oder einen anderen, wie z.B. den Mikro Assembler von Microsoft habt. Aber bei den Micro Assembler werden wahrscheinlich ein paar Syntaxfehler auftreten, weil ich euch hier zeige, wie man mit den TASM arbeitet. Und da werden auch die Aufrufe für das kompilieren und linken anders aussehen. Es ist empfehlenswert, wenn ihr euch mit den Computern schon etwas auskennt, muss nicht unbedingt sein, weil wir fangen bei Null an. Außerdem wäre es hilfreich eine andere Sprache zu beherrschen, weil man es dann besser verstehen kann. Assembler sollten nur kluge Köpfe lernen, weil es sich für Noobs nicht lohnt. Assembler ist sehr, sehr schwer. Jetzt kommt der theoretische Teil ran, also über den Aufbau des Computers, usw. Ok, das war das Vorwort.
2. Der Computer:
Das Herz des Computers ist der Processor, die sogenannte CPU, wie jeder wissen sollte. Da werden die Assembler Befehle verarbeitet. Das funktioniert folgendermaßen: Die CPU ist in zwei Teile geteilt. Der erste Teil holt sich die Assembler Befehle aus den Arbeitsspeicher und gibt sie in eine Warteschlange des Processors. Der zweite Teil holt sich dann die Befehle und verarbeitet sie. Dabei rechnet er, je nach Befehl, arthematische Operationen aus, spricht den Arbeitsspeicher an, sendet Daten an Drucker, usw... Bis jetzt brauchen wir nichts mehr über den Processor zu wissen. Nun kommen wir zum Arbeitsspeicher, nämlich den RAM. Jede Speicherstelle im RAM wird Adresse genannt, die frei beschrieben und gelesen werden kann. Wie jeder weiß, wird das RAM nach dem Ausschalten des Computers gelöscht oder auch in meiner Sprache freigegeben.
3. Real Mode Adressierung:
Der Real Mode ist der Processor Modus, in dem DOS normalerweise arbeitet, und er hat nur 16 Bit. Der Speicher wird im Real Mode nicht linear, sondern über einen Offset adressiert. Dazu gibt es ein Segment. Das Segment wird mit 16 mal genommen und der Offset wird dazuaddiert, dann hat man eine physikalische Adresse. Ein Segment ist hier 64 KB (Kilobyte) groß. Daraus können wir schließen, dass die Offsetadresse zwischen 0h und ffffh groß sein muss. Hinter einer Hexadezimalen Zahl wird immer ein "h" hinten rangehängt; das macht die Sache einfacher. Die Adresse wird immer in dieser Form geschrieben xxxx:xxxx. Es ist zu beachten, dass sie in der hexadezimalen Schreibweise geschrieben wird. Wer nicht weiß, was das Hexadezimales Zahlensystem ist, den kann ich das hier kurz erklären. Unser Zahlen System, was wir eigentlich in der Schule am Anfang lernen, hat die Basis 10, also die Zahlen von 0 - 9, logischerweise. Das Hexa-Zahlensystem hat aber die Basis 16, also nach der 9 kommt ein Buchstabe, oder auch genauer gesa tabe A. Dann im Alphabet: A - F. Also darauf schließt man, dass das Hexa-Zahlensys von 0 - F geht, wobei A = 11, B = 12, C = 13, D = 14, E = 15 und F = 16 ist. Ist doch einfach, oder? Und wenn man im Hexa z.B. 17 ausgeben will, also die Zahl nach F, dann schreibt man 10h hin. Darauf folgt natürlich: 11h = 18, 12h = 19, 13h = 20, ..., 19h = 26, 1Ah = 27, 1Bh = 28, usw. So, ich hoffe, dass ihr es verstanden habt. Wenn nicht, dann fragt nochmal irgendwo nach, wie z.B. in einen Mathe Buch.
4. I/O Ports:
Oder auch deutsch: E/A Ports, also Ein-, Ausgabeports. Wenn wir Peripheriegeräte ansprechen wollen, also z.B. Tastatur oder Drucker, oder z.B. Grafikkarte dann benutzen wir dafür diese E/A Ports. Ich werde jetzt auf das Thema nicht länger eingehen, weil ich es später besser erklären kann. Jetzt ist es noch zu früh dazu. Noch ein bisschen Theorie, dann können wir bereits das erste Programm schreiben.
5. Register:
Die Register vom Processor haben eigentlich immer breite von 16 Bit Integer-Variable Breite, die normalerweise von 0h - ffffh gehen, also von 0 bis 65535. Sie sind viel schneller als normale Variablen, die im RAM abgelegt sind, weil sie ja ein Hauptbestandteil des Processors sind. Es gibt verschiedene Arten von Registern:
Allgemeine Register: Sie sind frei verwendbar. Es gibt:
AX = Der Akkumulator heißt das Ding. Er kann in zwei 8 Bit Register aufgeteilt werden, und diese heißen dann AH und AL (Erklärung folgt später). Dieses Register wird zur Abwicklung von 16 Bit Multiplikationen und Divisionen verwendet. Für die 8 Bit Multiplikation und Division werden nur die Register AH und AL verwendet.
BX = Das Base Register lässt sich bei Speicherzugriffen als Zeiger verwenden. Natürlich lässt es sich auch in zwei 8 Bit Register unterteilen. Also in BL und BH.
CX = Das Count Register dient als Zähler für Schleifen. Es lässt sich in CL und CH aufteilen.
DX = Das Daten Register wird von Befehlen, die die I/O Ports ansprechen und dient dazu auch Rechenoperationen durchzuführen. Es lässt sich ebenfalls in DL und DH aufteilen.
Wie ihr bereits gesehen habt, lassen sich alle allgemeinen Registerin zwei 8 Bit große Register aufteilen. Also wenn in AX sich zumBeispiel die Zahl 12CDh aufhält, dann steht in AH 12h und in AL steht dann CDh. Ist ganz einfach, oder? Mann nimmt das X von AX weg, dann setzt man dafür ein H für Heigh Register oder ein L für Low Register ein. Also darauf folgt, dass das Heigh Register die zwei linken Hexadezimalzahlen nimmt und das Low Register die am Ende stehenden. Es gibt noch weitere Register, nämlich die Segment Register. Ihr wisst ja von den Kapitel Real Mode Adressierung, was Segmente sind. In diesen Registern wird nun die Segment Adresse des Segments angegeben. So kann man in ein beliebigen Segment Daten ablegen.
CS = Pointer auf Codesegment. Dort stehen eigentlich die Assembler Befehle. Aber später kann man da auch ein bisschen tricksen.
DS = Pointer auf das Daten Segment, wo die Variablen stehen. Also Pointer ist ein Zeiger.
ES = Darf auf jedes beliebige Segment im RAM zeigen.
SS = Zeigt auf das Stacksegment, wo die Daten zwischen gespeichert werden können.
Es gibt noch den Base Pointer (BP), SI und DI, die meistens für Stringbefehle eingesetzt werden. Aber es gibt noch den IP (Instruction Pointer), der den Programmierern nicht zusteht. Dort steht ein Zeiger, der auf die nähste Anweisung im Programm steht. Wenn man den verändert, dann kann was schlimmes passieren, wenn du Glück hast, dann nur ein Absturz, aber wenn du kein Glück hast, dann... Noch ist von den SP, den Stack Pointer abzuraten. Da kann das gleiche passieren.
6. Interrupts:
Interrupts sind einfache Unterprogramme. Davon gibt es zwei Arten, Nämlich die Software Interrupts und die Hardware Interrupts. Die Hardware Interrupts werden aufgerufen, wenn auf einen Peripherie Gerät eine Taste gedrückt wird. Wie z.B. auf den Drucker. Doch man kann einige Hardware Interrupts ausschalten, indem man einfach den Assembler Befehl cli benutzt, und fürs einschalten sti. Die Software Interrupts sind eigentlich nur die Unterroutinen. Sie kommen vom Bios und von DOS. Diese werden in Assembler mit den Befehl int aufgerufen. Meistens haben diese Interrupts mehrere Funktionen. Die Funktionsnummer wird meistens im AH Register angegeben (siehe Kapitel Register). Das war vorerst Schluss mit der Theorie.
7. Interrupt 10h Funktion 9h:
Das hier wird unser erstes Beispielprogramm sein. Keine Sorge, es wird alles genau erklärt.
MODEL TINY ;So beginnen COM-Dateien
CODE SEGMENT ;Beginn des Code Segments
ASSUME CS:CODE;Zuweisung an CS
ORG 100h ;Startadresse für COM-Dateien
start: ;Startlabel
MOV AX,0903h ;Funk. 9h, ASCII-Zeichen 2
MOV BX,15 ;Farbcode Weiß, also 15
MOV CX,1 ;1 Zeichen ausgeben
INT 10h ;Zeichen auf Bildschirm schreiben
MOV AX,4C00h ;Funk. 4Ch
INT 21h ;DOS-Exit
CODE ENDS ;Ende des Code Segments
END start ;Ende des Programms
Nun, um das Programm zu kompilieren und Linken, braucht ihr den TASM, der mit QuickBasic 7.1 mitgeliefert wird. Am besten ihr speichert die Datei im QB7.1 Ordner unter test.asm, und dort macht ihr eine Batchdatei (compile.bat) und in sie schreibt ihr folgendes rein:
TASM /T/L test.asm
LINK /t test
Nun, wenn ihr sie startet, also die Batchdatei, dann erscheint etwas, wo ihr was eingeben müsst, also die OBJ Datei, die vom assemblieren rausgekommen ist, ist schon eingegeben. Dort schreibt ihr gar nichts rein. Alles lasst ihr einfach so, einfach immer Enter drücken. Nun hab ihr eine Ausführbare Com Datei. Das /t beim linken sagt aus, dass es eine kleine Datei sein soll, also eine Com Datei. Wenn ihr dann die Datei startet, dann erscheint ein schönes Herz. Windows macht manchmal die Dos Fenster ganz schnell weg, deshalb solltet ihr das per Batch oder Dos aufrufen. Doch wie funktionierts? Ganz simpel: Das Programm benutzt die Funktion 9h des Interrupts 10h. Diese Funktion gibt ein ASCII Zeichen aus, ohne die Cursor Position zu verändern. AH ist hier die Funktionsnummer, also 9, AL das ASCII Zeichen, BL die Farbe, BH, die Bildschirmseite und CX, wie oft das Zeichen ausgegeben wird. Hier nochmal eine ganz genaue Erläuterung zum Programm: Zeile 1: Gibt das Speichermodell an. Coms dürfen nur TINY benutzen. Für normale Exe Dateien gibt es
SMALL: Codeseg und Dataseg sind zusammen kleiner 64 KB
MEDIUM: Code ist größer als 64 KB, Summe aller Datasegs ist kleiner als 64 KB
COMPACT: ein Codeseg, mehrere Datasegmente
LARGE: Mehrere Code Segmente > 64 KB
HUGE: alles kommt in Frage
Z.2: Anfang von Codeseg. Hier sollten die Befehle des Programms stehen
Z.3: CS soll auf Codeseg zeigen
Z.4: Anfangs Adresse ist CS:100h, das ist die Offset schreibweise. Am anfang der Coms steht noch etwas ffh langes am Anfang. Ist aber nur für Betriebssystementwickler relevant.
Z.5: Das ist ein Label, wie es in anderen Programmiersprachen den auch gibt. Zu den kann man durch ein jmp Befehl springen.
Z.6: Hier wird das ASCII Zeichen und die Funktionsnummer angegeben. Das Register teilt sich ja in zwei 8 Bits. AH ist die Funktionsnummer, also 09h und AL 03h, das ASCII Zeichen.
Z.7: Damit teilen wir den BX 0015 ein. 00 ist BH, die Bildschirmseite und BL die Farbe 15. Mit dieser Methode spart man ein paar Microsekunden Zeit.
Z.8: CX wird der Wert 1 zugeteilt, sodass das Zeichen nur einmal an der selben Stelle ausgegeben wird.
Z.9: Ruft den Interrupt 10h auf, der das Herz ausgibt.
Z.10+11: Beendet das Programm vollständig. Wenn man das nicht macht, dann führt dein Programm die Befehle nach deinen Programm aus und das ist sehr gefährlich. Du solltest das immer machen.
Z.12: Ende Codesegment
Z.13: Ende vom Programm
8. Der Befehl MOV:
Es ist wohlmöglich der wichtigste Befehl in Assembler. Die Syntax ist ganz einfach zu lernen: mov Ziel, Quelle. Hier gibt es jetzt einige Varianten zu diesen Befehl:
mov ax,0903h
Eine Konstante wird den Register AX zugewiesen.
mov ax,bx
Der Inhalt von bx wird den Register ax zugewiesen.
mov bx,[0B001h]
bx wird der Inhalt der Speicherstelle DS:0B001h zugewiesen.
mov bx,es:[0B001h]
Nennt sich Segment Override. bx wird der Inhalt der Speicherstelle
ES:0B001h zugewiesen.
Ende:
So, ich habe euch Einbisschen zu Assembler gezeigt, aber das ist erst die Nummer 1. Also später zeige ich euch noch weitere Varianten mit den MOV Befehl, ein paar neue Interrupts, die Bitverknüpfungen, usw. Bis dahin könnt ihr mit den mov Befehl rumspielen, aber auf keinen Fall auf IP oder SP zugreifen. Siehe in den Kapiteln nochmal nach. Ansonsten wünsche ich dir noch viel Spaß.
javadomi