|  | Assembler Tutor |  | 
  
    |  |  |  | 
  
    |  | Index |  | 
  
    |  | 1.
    Einleitung2. Hexadezimal, Dezimal und Binär
 3. Register
 4. Flags
 5. Interrupts
 6. Hello World (das erste Programm)
 7. Rechenoperationen
 8. Sprünge und Vergleiche
 9. Kleine Stack Spielereien
 10. Calls / Prozeduren
 11. Loops (Schleifen)
 12. Repeat it...
 13. Etwas Bewegung..
 14. Verschlüsselung und Anderes..
 15. Schieben und Rollen
 16. Indirekte Adressierung
 17. EXE-Dateien
 18. Datei-Handling
 19. Assembler Anweisungen
 20. Suchen nach Textstrings
 21. Graphiken
 22. Farbiger Text
 23. Outro
 |  | 
  
    |  | 1. Einleitung |  | 
  
    |  | Da mich ne Menge Leute nach einem
    deutschsprachigen Tutorial für Assembler gefragt haben und ich nie einen nennen konnte,
    hab ich mich entschlossen nun  selber einen zu schreiben, der die meisten Aspekte
    behandelt. Ausser diesem Tutorial benötigt ihr noch: Ralf Browns Interrupt List : http://www.pobox.com/~ralf Borlands Turbo Assembler 5.0 (keine freeware,für ne 'Testversion' sucht bei
    http://Astalavista.box.sk nach 'TASM')
 Notepad oder anderen Text-Editor Einen Taschenrechner ;) Ich werde mich in diesem Tutorial
    nur auf TASM beziehen und der Code wird nur bedingt unter anderen Assembler Compilern
    laufen.
  -- 1.1 Was ist Assembler ? Assembler ist Maschienensprache. Assembler ist die niedrigste Programmiersprache
    überhaupt, da man hier direkt den Prozessor und das OS anspricht. Man kann jeden
    Assemblerbefehl eins zu eins in Hexcode übersetzen, was für uns der Compiler übernimmt.
    Ein Beispiel hierfür ist der Befehl NOP = 90h (h für Hexadezimal). Da man hier genau
    bestimmen kann was für ein Code in der Datei nach dem Compilieren steht, kann man gerade
    in Assembler die Optimierung des Codes bis ins äuserste treiben. Auch hat man unter
    Assembler die größte Macht über den Computer.   *-- 1.2 Warum in Assembler programmieren ? Es gibt mehrere Gründe dafür warum man in Assembler programmiert, bzw warum man es
    lernen  möchte. Ein Grund ist zum Beispiel, das man den Code extrem klein halten
    kann und durch gezielte optimierung einen enormen Geschwindigkeitsvorteil zu Hochsprachen
    herausarbeiten  kann. Des weiteren ist Assembler natürlich interessant zum Cracken
    und Viren schreiben.  *-- 1.3 Anmerkungen zu TASM Es gibt in Borlands Turbo Assembler keinen Editor, wie man ihn zum Beispiel von Qbasic
    oder Turbo Pascal kennt. Man schreibt seinen Code per Text-Editor in eine .asm Datei und
      übergibt diese auf der DOS-Kommando Ebene dem Compiler und dem Linker. Die
    Parametereinstellungen kann man natürlich durch eine Batch Datei erleichtern. ---8<------ ( Compile.bat )---------@Echo Off if not exist %1.asm goto quit tasm %1 /n/p/t/w/z/m4 if errorlevel 1 goto quit tlink %1 /d/x/t del %1.obj :quit ---8<------------------------------- Diese Batch Datei wird gestartet mit Compile '<Dateiname des sources ohne .asm>'
    Achtet darauf, das sie in C:\TASM\BIN\ zusammen mit dem Source code liegt. Und startet
    dann den Compiler (TASM) und den Linker (TLINK) und fertig euch eine COM Datei an. Wie man
    EXE Dateien mit TASM erstellt erkläre ich später, COM Dateien reichen erstmal und sind
    viel kleiner als EXE Dateien. In TASM wird die Groß und Kleinschreibung ignoriert,
    schreibt wie ihr wollt. (jedenfalls solange ihr DOS-Programme schreibt) *-- 1.4 DOS Assembler Im ersten Teil dieses Tutorials werde ich euch zeigen, wie man DOS-Programme mit TASM
    schreibt, da diese immernoch zu verwenden sind und einfach besser in die Assembler Welt
    einführen. Später werde ich noch auf die Besonderheiten der Windows programmierung
    hinweisen.
       |  | 
  
    |  | 2.
    Hexadezimal, Dezimal und Binär |  | 
  
    |  | Ok das solltet ihr zwar alles schonmal in der
    Schule gemacht haben, aber ich weiß selber wie gut man in der Schule aufpasst, wenn man
    denkt das braucht man nicht ;)  Gut, es gibt verschiedenen Zahlensysteme. Das mit dem
    wir täglich rechnen basiert auf der Zahl 10. Es gibt 10 Grundzahlen: 0,1,2,3,4,5,6,7,8,9
    .. wenn man nun in diesem  System zählt, fängt man nach der 9 eine neue
    Zehnerpotenz an. Dezimalzahlen werden in Assemble durch ein kleines d gekennzeichnet (31d)
    Das sollte soweit klar sein, schauen wir uns mal das Binärsystem an. Hier haben wir nur
    zwei Grundzahlen, 0 und 1. Wenn wir beim hochzählen bei 1 angelangt sind machen wir eine
    0 draus und addieren vorne eine 1. Ok zählen wir binär bis 9: 
      
        | 0 | 1 | 10 | 11 | 100 | 101 | 110 | 111 | 1000 | 1001 |  
        | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Versucht mal mit euerem Taschenrechner weiterzuzählen ich denke den
    Dreh bekommt ihr schnell raus. Was machen wir nun, wenn wir eine Binärzahl ins Dezimale
    umrechnen wollen ? Wir zücken unseren Taschenrechner ;) oder machen es im Kopf nach
    folgender Methode:Schauen wir auf die Zahl 10011. Wir fangen bei der letzten stelle an 1, also 1 * 2^0 (das
    ^ bedeutet hoch, also die erste Potenz von 2), dann addieren wir die 2. Stelle (1 *
    2^0)+(1 * 2^1).. die nächsten beiden Stellen sind 0.. ok addieren wir sie zum  Spaß
    auch mal, damit ihr das Schema erkennt. (1 * 2^0)+(1 * 2^1)+(0 * 2^2)+(0 * 2^3) Also
    ändert sich die Zahl hier nicht. Nun noch die erste Stelle addieren und wir sind fertig
 (1 * 2^0)+(1 * 2^1)+(0 * 2^2)+(0 * 2^3)+(1 * 2^4) = 1 + 2 + 0 + 0 + 16 = 19
 In TASM kennzeichnet man Binärzahlen durch ein b am ende der Zahl (10011b).
 Ok nun zum Hexadezimalsystem. Dieses beruht auf 16 Grundzahlen:
    0,1,2,3,4,5,6,7,8,9,A,B,C,D,E. Das A entspricht der 10 im Dezimalsystem, das B der 11, das
    C der 12 und so weiter. Was passiert, wenn wir zu F noch eine 1 addieren wollen ?
 Dann landen wir bei 10. Diese 10 entspricht dann der Dezimalen 17. Auch für Hexzahlen
    gibt es unter Assembler eine Besondere Kennzeichnung, das h. Allerdings erwartet TASM,
      das eine Zahl mit einer Zahl anfängt, also muss man Eh als 0Eh schreiben, da TASM
    das E nicht als Zahl ansieht. Soviel zur Mathematik ;P
 |  | 
  
    |  | 3. Register |  | 
  
    |  | Register sind Speicherplätze, in denen wir
    Daten speichern können. Sie können jeweils 16 Bit speichern. Man kann die Basisregister
    in 2 Teile teilen, die jeweils 8 Bit speichern. 16 Bits sind zum Beispiel 2 Buchstaben im
    Ascii-Format 'ab' oder eine Zahl zwischen 0 und FFFF im Hexadezimal Format (also 0 bis
    65535 in Dezimal ;) ) Man benutzt die Register um mit Zahlen zu rechnen, um kurz etwas zu
    speichern oder um Variablen an Interrupts zu übergeben. Was Interrupts sind erklär ich
    später. Schauen wir uns erstmal die vier Grundregister an: 
      
        | ax | kann geteilt werden in : al und ah | -Accumulator(zum Addieren) |  
        | bx | bl und bh | -Base (Basisregister zum speichern) |  
        | cx | cl und ch | -Count(zum Zählen) |  
        | dx | dl und dh | -Data(zum Daten anzeigen) | Einfach zu merken oder ? Das kleine l steht für low, das h für high.
    Dann gibt es noch: SP - Stack Pointer (wird später erklärt)BP - Base Pointer (meistens unbenutzt)
 SI - Source Index (zeigt auf Quelle, wenn man Daten liest oder verschiebt)
 DI - Direction Index (zeigt auf das Ziel der Daten)
 IP - Instruction Pointer (zeigt auf den Befehl der gerade ausgeführt wird)
 CS - Code Segment (zeigt den Anfang des Codes)DS - Data Segment (zeigt den Anfang der Daten)
 SS - Stack Segment (kommt später)
 ES - Extra Segment (könnt ihr frei verwenden)
 FS - siehe ES ..
 GS - siehe ES ... ;)
 Das war es eigentlich schon mit den Registern, wenn euch etwas spanisch vorkommt, lest
    einfach erstmal weiter, mit dem ersten Programm sollte es euch klar werden. |  | 
  
    |  | 4. Flags |  | 
  
    |  | Wenn ein Befehl misling, gelingt oder sonstwas
    tut, werden Flags gesetzt. Ein paar dieser Flags zum nachlesen und vergessen (ich werde
    sie später nochmal erwähnen) 
 
      
        | CF | Carry Flag - Es gab einen Fehler |  
        | ZF | Zero Flag - Die letzte Operation ergab 0 |  
        | SF | Sign Flag - Positiver Wert / Negativer Wert |  
        | TF | Trap Flag - ermöglicht den Einzelschritt-Modus |  Die paar reichen für dieses Tutorial aus, sie können gesetzt sein 1 oder auch nicht
    0. Was man damit anfangen kann kommt später ich wollte sie mal erwähnen, das ihr
    wenigstens mal davon gehört habt. :) |  | 
  
    |  | 5. Interrupts |  | 
  
    |  | Ok eine Sache brauchen wir noch, bevor wir das
    erste Programm starten können.. die Interrupts. Mit einem Interrupt unterbrechen wir
    unser Programm und starten ein Unterprogramm von DOS. Je nachdem welchen Interrupt wir mit
    welchen Funktionen aufrufen, ein anderes. Die Liste über 'fast' alle Interrupts (INT'S)
    ist von Ralf Brown (siehe oben) wir werden uns hier fast nur mit dem DOS-Interrupt INT 21h
    beschäftigen, die Funktion erklär ich dann immer. Aber zum nachlesen ist die Liste nicht
    schlecht. Neben den Software INT's gibt es auch Hardware INT's die dann in Kraft treten,
    wenn ein Gerät (Drucker) dem Programm was wichtiges mitteilen muss.   |  | 
  
    |  | 6. Hello
    World (das erste Programm) |  | 
  
    |  | So, endlich in diesem Abschnitt
    kommt das erste Programm ! Was wollen wir machen ? Ein simples Hello world auf den
    Bildschirm schreiben. Was brauchen wir dafür ? Einmal eine Interrupt-Funktion, die was
    ausdruckt und einmal eine, mit der wir das Programm beenden. Die Funktion zum ausgeben von
    Text ist INT 21h mit 09h in ah (dem höheren Registerteil von ax) und nem Zeiger zum Text
    in DX. Wie setzen wir den Wert 09h nun in ah ? Mit dem Assemblerbefehl 'mov ah,09h'.
    Einfach simpel oder ? Ok.. das Programm, dann mehr Erklärung: --8<---(HelloW.asm)------Was ist das alles nun ? Die Sachen nach dem ; sind Kommentare ;)
    Ok.. das erste Statement '.model tiny' zeigt an, das wir nur ein kleines Programm
    schreiben wollen. Danach sagen wir Bescheid, das hier unser Code anfängt. Da wir eine COM
    Datei erstellen wollen, müssen wir das dem Compiler angeben, da COM Dateien erst bei
    Offset 100h anfangen, setzen wir ein org 100h vor den code. Ok, 'Start:' ist ein Label zu
    dem wir später mit Sprungbefehlen springen können, hier dient es nur zur Verschönerung,
    im Compilierten Programm taucht es eh nicht auf. Nun übergeben wir ah den ersten
    Parameter. (Wir hätten dies auch mit mov ax, 4c00h tun können, da sich ax aus ah und al
    zusammensetzt) Dann kommt in dx der Offset (die Adresse) unseres 'Hello World'. Nachdem
    wir den Parameter also in ah haben und die Adresse des Texts in dx können wir unseren
    Interupt aufrufen. Nun wieder ein Label zum verschönern ;) Danach geben wir den Parameter
    4Ch in ah und beenden das Programm durch den  Interrupt aufruf. Am Ende folgt noch
    unser Hello World-String, den wir mit 10d,13d verzieren, damit die nächste Zeile auch in
    der nächsten Zeile anfängt und nicht am Hello World. Dann schließen wir den String mit
    einem '$' ab, um zu zeigen das er hier zuende ist. Den String haben wir mit einem db
    (define Byte) definiert, die Hochkommas geben an das der Inhalt ASCII Zeichen sind. Wir
    hätten ihn aber auch folgendermaßen definieren können :.model tiny ;nur ein kleines Programm
 .code ;hier steht der code
 org 100h ;wir basteln ne COM Datei
 START: ;Label zum verzieren
 mov ah, 09h ;09h ist die INT21h Funktion zum ausgeben von Text
 mov dx, offset HelloWorld ;Wo steht der Text...
 INT 21h ;schreib ihn !
 ENDE: ;schönes Label oder ?
 mov ah,4ch ;4Ch zum Beenden
 INT 21h ;Beende !
 HelloWorld db 'Hello World !!',10d,13d,'$' ;Unser String..
 END START ;hier ist das ganze zuende..
 ----------ende-----------
 HelloWorld db 48h, 65h, 6Ch, 6Ch, 6Fh, 20h, ... etc
 Dann hätten wir die ASCII Codes für den String eingegeben. Also wie oben schon erklärt,
    tippt oder copy+pastet den Kram in einen Texteditor und speicher das ganze als HelloW.asm
    dann mit der Batchdatei von oben compilieren (Compile.bat hellow). Ihr solltet als Output
    von TASM folgendes bekommen:
 'Turbo Link Version 7.1.30.1. Copyright (c) 1987, 1996 Borland
    International'
 Dann seit ihr wieder auf der Commando-Ebene von DOS.. mit einem 'dir' seht ihr nun:
 HELLOW COM 28 15.09.99 15:23 HELLOW.COMHELLOW ASM 763 15.09.99 15:23 hellow.asm
 Nun könnt ihr das Hallo Welt Programm auch starten... ;) denke mal das könnt ihr auch
    so.. Und wir werden mit einem Hello World !! begrüßt.. War ganz einfach oder ?
       |  | 
  
    |  | 7. Rechenoperationen |  | 
  
    |  | Natürlich gibt es unter Assembler auch
    Kommandos für Rechenarten..  Damit ihr sie erstmal kennenlernt, werd ich sie hier
    auflisten, danach ein kleines Programm damit. Alle Beispiele sind mit ax, aber ihr könnt
    natürlich auch andere Register verwenden. 
 
 
      
        | INC AX - | Erhöhe AX um 1 |  
        | DEC AX - | Vermindere AX um 1 |  
        | ADD AX, 1h - | Addiere 1h zu AX |  
        | SUB AX, 1h - | Subtrahiere 1h von AX |  
        | MUL BX - | Multipliziere AL mit BX (hier wird immer AL verwendet !)
        Ergebnis steht in AX |  
        | DIV BX - | Dividiere AL durch BX (auch hier wird immer AL verwendet !)
        Ergebnis steht in AX |     Was kann man nun damit anfangen ? ;) .. Lasst uns unser Hello World etwas ändern.. ;) 
 
 
      
        | --8<---(HelloW2.asm)----- |  |  
        | .model tiny | ;nur ein kleines Programm |  
        | .code | ;hier steht der code |  
        | org 100h | ;wir basteln ne COM Datei |  
        |  |  |  
        | START: | ;Label zum verzieren |  
        |  |  |  
        | mov AH, 08h | ;09h ist die INT21h Funktion zum ausgeben von Text |  
        | inc AH | ;so das wir die 8h um 1s erhöhen müssen um 9h zu
        bekommen ;P |  
        | mov DX, offset HelloWorld | ;Wo steht der Text... |  
        | INT 21h | ;schreib ihn ! |  
        |  |  |  
        | WarteaufTaste: | ;Ein Label... |  
        |  |  |  
        | mov AH, 00h | ;Wenn wir ah = 1 setzen warten wir auf eine
        Tastatureingabe |  
        | add AH, 01h | ;von 1 Zeichen. Das Zeichen steht nach dem INT 21h
        in al |  
        | INT 21h | ;aber das ist für uns hier unwichtig... ;) |  
        |  |  |  
        | ENDE: | ;schönes Label oder ? |  
        |  |  |  
        | mov AL, 26h | ;2h * 26h = 4Ch zum Beenden |  
        | mov BX, 02h | ;die 2 speichern wir in BX.. |  
        | mul BX | ;mit BX (2) multiplizieren.. |  
        | mov AH, AL | ;nun schiebe den Inhalt von AL nach AH, wo unser |  
        |  | ;Parameter stehen muss |  
        | INT 21h | ;Beende ! |  
        |  |  |  
        | 'HelloWorld db 'Hello World !!',10d,13d,'$ | ;Unser String.. |  
        | END START | ;hier ist das ganze zuende.. |  
        | ----------ende----------- |  |  Das ganze ist wie ihr seht nur Spielerei und hat keinen Nutzen (ausser euch die Sache
    zu erklären) Wenn ich bei euch mal solchen Code sehen sollte werde ich euch sofort
    verbrennen ;P .. Ok was Passiert hier ? Wir schreiben unsere Nachricht, mit der bereits
    erklärten Funktion 09h des INT 21h. Die 9h erreichen wir über den Umweg, das wir zuerst
      8h in AH schreiben und diese 8h dann um eins erhöhen. Danach verwenden wir die
    für euch neue Funktion 01h des INT 21h. Mit dieser halten wir das Programm an, bis
    irgendeine Taste gedrückt wird. Der ASCII Code dieser Taste steht dann in AL, aber das
    ist in diesem Beispiel egal. Es ging nur darum das Programm anzuhalten.Am Schluß setzten
    wir wieder die 4Ch zum beenden in ah, indem wir AL mit 26h füllen, diese dann mit den 2h
    aus BX multiplizieren. Und das Ergebnis aus AL nach AH verschieben,  wo es
    hingehört.
       |  | 
  
    |  | 8. Sprünge und
    Vergleiche |  | 
  
    |  | Wir wollen in unserem Assembler Programm auch
    auf die Eingaben des Benutzers reagieren können oder ? Wir verwenden also den Befehl
    'cmp' um einen Register mit einem Wert oder einem anderen Register zu vergleichen. Führen
    wie die Funktion 01h des INT 21h aus, haben wir als Ergebnis den ASCII Wert der Taste in
    al. Nun können wir einen  Vergleich ausführen: cmp al, 'J' damit vergleichen wir al
    mit 'J'. Wir können AL auch mit einem Register vergleichen oder einer anderen Konstante
    (cmp al,bl / cmp al, 14h) Nun haben wir zwar den Wert mit einem anderen verglichen, aber
    was dann ? Je nach Ergebnis springen wir zu einem Label ( label: ) oder laufen im Code
    einfach weiter. Dafür gibt es jetzt einige Sprung-Befehle (da sich einige gleichen steht
    in Klammern hintendran, mit welchem sie sich gleichen) : jmp Label
    - Springe immer ! 
 (die Bezeichnungen größer und kleiner ignorieren das Vorzeichen)
 je Label - Springe wenn gleich (JZ)
 jne Label - Springe wenn ungleich (JNZ)
 ja Label - Springe wenn größer (JNBE)
 jna Label - Springe wenn nicht größer (JBE)
 jae Label - Springe wenn größer oder gleich (JNB)
 jnae Label - Springe wenn nicht größer oder gleich (JB)
 jb Label - Springe wenn kleiner (JNAE)
 jnb Label - Springe wenn nicht kleiner (JAE)
 jbe Label - Springe wenn kleiner oder gleich (JNA)
 jnbe Label - Springe wenn nicht kleiner oder gleich (JA)
 jz Label - Springe wenn 0 (JE)
 
 (nun wird auf die Vorzeichen geachtet)
 jg Label - Springe wenn größer (JNLE)
 jng Label - Springe wenn nicht größer (JLE)
 jge Label - Springe wenn größer oder gleich (JNL)
 jnge Label - Springe wenn nicht größer oder gleich (JL)
 jl Label - Springe wenn kleiner (JNGE)
 jnl Label - Springe wenn nicht kleiner (JGE)
 jle Label - Springe wenn kleiner oder gleich (JNG)
 jnle Label - Springe wenn nicht kleiner oder gleich (jg)
 jcxz Label - Springe wenn ex = 0
 
 js Label - Springe, wenn die letzte Operation ein negatives Ergebnis hatte
 jp Label - Springe wenn das Parity Flag gesetzt ist
 jnp Label - Springe wenn das Parity Flag nicht gesetzt ist
 jo Label - Springe wenn Overflow Flag gesetzt ist
 jno Label - Springe wenn Overflow Flag nicht gesetzt ist
 jc Label - Springe wenn Carriage Flag gesetzt ist
 jnc Label - Springe wenn Carriage Flag Flag nicht gesetzt ist
 Nein ihr müsst jetzt nicht alle Auswendig lernen.. Ihr dürft diese Tutorial auch
    etwas länger behalten, dann könnt ihr auch mal nachschlagen ;P Neben dem CMP Befehl gibt
    es noch einen weiteren Befehl, der 2 Register/Konstanten mit einander vergleicht. Dies ist
    der test-befehl, mit dem man allerdings nur auf Gleichheit bzw Ungleichheit überprüfen
    kann.  Nun wieder ein kleines, sinnloses Programm zum Verstehen: 
      
        | --8<------(kekse.asm)----------------- |  |  
        | .model tiny |  |  
        | .code |  |  
        | org 100h |  |  
        |  |  |  
        | START: | ;LABEL !! |  
        | mov ah, 09h | ;Schreiben der Frage auf den Bildschirm |  
        | mov dx, offset frage | ;hier steht die Frage |  
        | INT 21h | ;schreib ! |  
        | mov ah, 01h | ;Einlesen einer Taste |  
        | INT 21h | ;lies ! |  
        | cmp al,"1" | ;wurde eine 1 gedrückt ? |  
        | je eins | ;wenn ja, dann springe zu Label 'eins' |  
        | cmp al,"2" | ;wurde eine 2 gedrückt... |  
        | je zwei |  |  
        | cmp al,"3" |  |  
        | je drei |  |  
        | cmp al,"4" |  |  
        | je vier |  |  
        | jmp fehler | ;wurde keine der Zahlen gedrückt springe
        zum Fehler |  
        |  |  |  
        | eins: | ;schreibe die Nachricht für Tastendruck
        '1' |  
        | mov ah, 09h |  |  
        | mov dx, offset meins |  |  
        | INT 21h |  |  
        | jmp ende | ;springe zum Ende |  
        |  |  |  
        | zwei: | ;schreibe die Nachricht für Tastendruck
        '2' |  
        |  |  |  
        | mov ah, 09h |  |  
        | mov dx, offset mzwei |  |  
        | INT 21h |  |  
        | jmp ende | ;springe zum Ende |  
        | drei: | ;schreibe die Nachricht für Tastendruck
        '3' |  
        | mov ah, 09h |  |  
        | mov dx, offset mdrei |  |  
        | INT 21h |  |  
        | jmp ende | ;springe zum Ende |  
        |  |  |  
        | vier: | ;schreibe die Nachricht für Tastendruck
        '4' |  
        |  |  |  
        | mov ah, 09h |  |  
        | mov dx, offset mvier |  |  
        | INT 21h |  |  
        | jmp ende | ;springe zum Ende |  
        |  |  |  
        | fehler: | ;Schreibe, das der Benutzer etwas Falsches
        eingegeben hat.. |  
        |  |  |  
        | mov ah, 09h | mov dx, offset mfehler |  
        | INT 21h |  |  
        |  |  |  
        | ende: | ;Label für Ende |  
        |  |  |  
        | mov ax,4c00h | ;beende das Programm |  
        | INT 21h |  |  
        |  |  |  
        | ;Dies sind nun wieder unsere Daten... |  |  
        |  |  |  
        | frage db 'Wieviele Kekse wollen sie ?
        [1-4]',10,13,'$' |  |  
        | meins db ') Was nur einen ? ',10,13,'$' |  |  
        | mzwei db ') Nimm 2 ;-)',10,13,'$' |  |  
        | mdrei db ') 3 Sind ok',10,13,'$' |  |  
        | mvier db ') VIELFRAS',10,13,'$' |  |  
        | mfehler db ') Leider Falsche Eingabe... ;(
        ',10,13,'$' |  |  
        | END START |  |  
        | ---------------(ende)---------- |  |    Ok in diesem Beispiel verwenden wir nur die Interrupt Funktionen, die wir bereits
    kennen, 09h um etwas auf den Bildschirm auszugeben, 01h um eine Taste einzulesen und 4Ch
    um das Programm zu beenden. Das Programm arbeitet so, das es erst die Taste einliest (in
    al) und dann al nacheinander mit den verschiedenen erwünschten Tasten (1,2,3,4)
    vergleicht.  Wenn al mit einer der Tasten übereinstimmt, springt man zu dem
    jeweiligen Unterprogramm. Stimmt al mit keiner der Tasten überein, wird eine
    Fehlermeldung gezeigt, und das Programm beendet. So nun könnt ihr schon ein kleines
    Text-Adventure in Assembler schreiben ;) |  | 
  
    |  | 9. Kleine Stack
    Spielereien |  | 
  
    |  | Der Stack ist ein Speicher, in dem ihr die
    Daten aus euerem Programm speichern könnt. Mit dem Stack verhält es sich wie mit einem
    Stapel, man kann nur oben etwas drauflegen und von oben etwas herunternehmen. Einfach was
    aus der Mitte klauen geht nicht (ok, ok es geht, aber nur über Umwege.. ;] ) Gut wie
    legen wir eine Zahl auf den Stapel ? Mit 'push' ! 'Push ax' legt die Zahl in AX auf den
    Stapel. Mit 'pop ax' nehmen wir die Zahl vom Stapel und legen sie wieder in ax. Wir
    können natürlich auch ein 'Push ax' 'pop bx' achen und so die Zahl von ax nach bx
    übertragen, auch wenn ein mov bx,ax einfacher gewesen wäre. Für was braucht man den
    Stack ? Naja, man kann in ihm auch länger Daten abspeichern, die in einem der Register
    verlorengehen würden. Wo der Stack anfängt zeigt euch SS das Stack Segment. Also auch
    hier ein simples Programm.   
      
        | --8<---(CruelW.asm)------ |  |  
        | .model tiny ;nur ein kleines Programm |  |  
        | .code ;hier steht der code |  |  
        | org 100h | ;wir basteln ne COM Datei |  
        |  |  |  
        | START: | ;Label zum verzieren |  
        | mov dx, offset HelloWorld | ;Wo steht der Text... |  
        | push dx | ;nun speichern wir dx im Stack |  
        | mov dx, offset ByeCruelWorld | ;legen einen anderen offset in dx |  
        | pop dx | ;laden unseres offsets aus dem Stack.. |  
        | push 0900h | ;0900h ist die INT21h Funktion zum ausgeben
        von Text, deshalb speichern wir den Wert im Stack.. |  
        | pop ax | ;und poppen ihn nach ah... |  
        | INT 21h | ;schreib ihn ! |  
        |  |  |  
        | ENDE: | ;schönes Label oder ? |  
        | mov ah,4ch | ;4Ch zum Beenden |  
        | INT 21h | ;Beende ! |  
        | HelloWorld db 'Hello World !!',10d,13d,'$' | ;Unser String.. |  
        | ByeCruelWorld db 'Commit suicide now
        !!',10d,13d,'$' | ;Ein unerwünschter String.. ;) |  
        |  |  |  
        | END START | ;hier ist das ganze zuende.. |  
        | ----------ende----------- |  |    Das Programm gibt uns auch wieder ein Hello World !!! aus, diesmal aber haben wir um
    dies zu erreichen einige Umwege über den Stack gemacht, die eigentlich recht
    verständlich sind. Was genau passiert mit dem Stack Pointer, wenn wir etwas in den Stack
    legen, vom Namen her muss er doch was damit zu tun haben oder ? ;)  Also der Stack
    Pointer zeigt auf die Stelle im Speicher, an der die nächste Zahl in den Stack gelegt
    wird. Also an die Spitze des Stapels. Wenn man nun eine weitere 16Bit-Zahl pusht, werden 2
    Bytes vom SP (Stack Pointer) abgezogen. Wenn man etwas poppt, werden 2 Bytes dazugezählt.
    Versuchen wir doch einmal folgende Spielerei mit diesem Pointer: wir Pushen eine Zahl,
    dann Poppen wir sie wieder. Dann vermindern wir den SP um 2, so das er wieder auf unsere
    Zahl zeigen müsste. Dann poppen wir auch diese Zahl und vergleichen sie mit der ersten.
    Wenn beide Zahlen stimmen ist unsere Experiment geglückt. 
      
        | --8<---(SP_GAME.asm)------ |  |  
        | .model tiny | ;nur ein kleines Programm |  
        | .code | ;hier steht der code |  
        | org 100h | ;wir basteln ne COM Datei |  
        |  |  |  
        | START: | ;Label zum verzieren.. ;) ..wie oft hatten wir das
        schon *g* |  
        | push 'SB' | ;dies ist unsere Testzahl.. 53h, 42h |  
        | pop ax | ;diese steht nun in AX ! |  
        | sub sp, 2h | ;jetzt vermindern wir den Stack Pointer um 2 |  
        | pop bx | ;und versuchen die gleiche Zahl in bx zu erhalten |  
        | cmp ax,bx | ;ein vergleich ob beide gleich sind.. |  
        | je ErfolgMsg | ;sind sie gleich gehen wir zum Label ErfolgMsg |  
        | mov dx, offset Error | ;ansonsten laden wir die Error Nachricht |  
        | jmp Write | ;und geben sie bei Write: aus.. |  
        |  |  |  
        | ErfolgMsg: | ;wenn beide Zahlen gleich waren, |  
        | mov dx, offset Erfolg | ;laden wir die Erfolgsnachricht |  
        |  |  |  
        | Write: | ;hier wird die Nachricht, je nach dx |  
        | mov ah, 9h | ;ausgegeben |  
        | int 21h |  |  
        |  |  |  
        | ENDE: |  |  
        | mov ah,4ch | ;4Ch zum Beenden |  
        | INT 21h | ;Beende ! |  
        | Error db 'Leider stimmen die Zahlen nicht | ;( ',10d,13d,'$' |  
        | Erfolg db 'Glückwunsch es hat geklappt.. ;)
        ',10d,13d,'$' |  |  
        |  |  |  
        | END START | ;hier ist das ganze zuende.. |  
        | ----------ende----------- |  |  Was ein Zufall, unsere Überlegungen waren richtig.. ;) es klappt, wenn man das
    Programm compilert und ausführt... *g* |  | 
  
    |  | 10. Calls /
    Prozeduren |  | 
  
    |  | Prozeduren sind Unterprogramme, die dazu
    dienen, häufig verwendete Programmteile öfters auszuführen um Platz zu sparen.
    Prozeduren helfen dabei, den Code besser zu strukturieren und ihn dadurch zu optimieren.
    Aufgerufen wird eine Prozedur mit dem Call Befehl. Auch dieser Befehl orientiert sich, wie
    die Jump Befehle an einem Label zu dem er springt. Um das Unterprogramm zu beenden
    benutzen wir den RET Befehl, mit dem man zu dem Call zurückkehrt. Was genau passiert,
    wenn wir eine Prozedur callen ? Die Rückkehradresse wird in den Stack gepusht und der
    Instruction Pointer (IP) wird auf die neue Adresse, das Label, eingestellt. Dort wird nun
    der Code ausgeführt und wenn der Ret-Befehl kommt wird zu der Adresse aus dem Stack
    gesprungen. Ok schauen wir uns mal ein Programm an, das mit Prozeduren arbeitet...   
      
        | --8<---(Callit.asm)------ |  |  
        | .model tiny |  |  
        | .code |  |  
        | org 100h |  |  
        |  |  |  
        | START: |  |  
        | lea dx, MSG1 | ;das gleiche wie mov dx, offset MSG1 |  
        | call WriteMSG |  |  
        | call KEY |  |  
        |  |  |  
        | lea dx, MSG2 | ;mov dx, offset MSG2 |  
        | call WriteMSG |  |  
        | call KEY |  |  
        |  |  |  
        | ENDE: | ;schönes Label oder ? |  
        | mov ah,4ch | ;4Ch zum Beenden |  
        | INT 21h | ;Beende ! |  
        | WriteMSG: |  |  
        | mov ah,09h |  |  
        | int 21h |  |  
        | ret |  |  
        |  |  |  
        | KEY: |  |  
        | mov ah,1h |  |  
        | int 21h |  |  
        | ret |  |  
        | MSG1 db 'CALL-Programm',10d,13d,'$' | ;Ein String.. |  
        | MSG2 db ' by SnakeByte',10d,13d,'$' |  |  
        | END START | ;hier ist das ganze zuende.. |  
        |  |  |  
        | ----------ende----------- |  |  Schätze mal das ist soweit verständlich ;) Nun wissen wir wie ein Call
    funktioniert, doch uns fällt auf, das man die ganze Aktion auch anders hätte starten
    können (nur zur Information es bringt nicht viel *g* ) Das ist nur um nochmal zu
    verdeutlichen, was genau bei einem CALL passiert.. ;) 
      
        | --8<---(FakeCall.asm)------ |  |  
        | .model tiny |  |  
        | .code |  |  
        | org 100h |  |  
        |  |  |  
        | START: |  |  
        | lea dx, MSG1 | ;das gleiche wie mov dx, offset MSG1 |  
        | push offset RETURN |  |  
        | jmp WriteMSG |  |  
        |  |  |  
        | RETURN: |  |  
        | call KEY |  |  
        | lea dx, MSG2 | ;mov dx, offset MSG2 |  
        | push offset RETURN2 |  |  
        | jmp WriteMSG |  |  
        |  |  |  
        | RETURN2: |  |  
        | call KEY |  |  
        |  |  |  
        | ENDE: | ;schönes Label oder ? |  
        | mov ah,4ch | ;4Ch zum Beenden |  
        | INT 21h | ;Beende ! |  
        | WriteMSG: |  |  
        | mov ah,09h |  |  
        | int 21h |  |  
        | pop AX |  |  
        | jmp AX |  |  
        |  |  |  
        | KEY: |  |  
        | mov ah,1h |  |  
        | int 21h |  |  
        | ret |  |  
        | MSG1 db 'CALL-Programm',10d,13d,'$' | ;Ein String.. |  
        | MSG2 db ' by SnakeByte',10d,13d,'$' |  |  
        |  |  |  
        | END START | ;hier ist das ganze zuende.. |  
        | ----------ende----------- |  |  |  | 
  
    |  | 11. Loops (Schleifen) |  | 
  
    |  | Was sind Schleifen ? Wenn ihr schonmal in einer
    höheren Sprache programmiert habt, kennt ihr sicherlich 'do while' oder 'loop until'
    schleifen. Wenn nicht, dann erklär ich euch was eine Schleife macht: Eine Schleife führt
    einen bestimmten Codeabschnitt solange aus, bis eine vorher festgelegte Bedingung erfüllt
    ist. Bei uns verwenden wir den Register CX als Zähler für die Schleife. Wir setzen also
    in CX den Wert, der die Anzahl der Durchläufe enthält. CX wird mit jedem Durchlauf
    automatisch um eins vermindert. 
      
        | --8<---(LoopIT.asm)------ |  |  
        | .model tiny |  |  
        | .code |  |  
        | org 100h |  |  
        |  |  |  
        | START: |  |  
        | mov cx, 3h | ;wir setzen den Zähler auf 3 |  
        | Schleife: |  |  
        | lea dx, MSG1 | ;das gleiche wie mov dx, offset MSG1 |  
        | mov ah, 9h |  |  
        | int 21h |  |  
        | loop schleife | ;zurück zum Label Schleife |  
        |  |  |  
        | ENDE: | ;schönes Label oder ? |  
        | mov ah,4ch | ;4Ch zum Beenden |  
        | INT 21h | ;Beende ! |  
        | MSG1 db 'Schleife ..1,2,3..
        ',10d,13d,'$' | ;Ein String.. |  
        |  |  |  
        | END START | ;hier ist das ganze zuende.. |  
        | ---------ende----------- |  |  Hiermit zeigen wir den Text 3 mal.. Man kann Schleifen auch ineinander
    Verschachteln, man muss dann allerdings darauf achten, das man CX speichert (push/pop)    |  | 
  
    |  | 12. Repeat it... |  | 
  
    |  | Was aber, wenn man nur ein Commando wiederholen
    will ?  Lohnt sich der Aufwand mit loop ? Nein, dafür haben wir nämlich das
    REP-Kommando. Auch hier setzen wir wieder die Anzahl in CX und schreiben dann hinter das
    REP unseren Befehl, den wir mehrfach ausführen wollen... ;) 
      
        | --8<---(REP.asm)------ |  |  
        | .model tiny |  |  
        | .code |  |  
        | org 100h |  |  
        |  |  |  
        | START: |  |  
        | mov cx, 3h | ;wir setzen den Zähler auf 3 |  
        | rep call write | ;wiederhole den call zu write 3 mal.. |  
        |  |  |  
        | ENDE: | ;schönes Label oder ? |  
        | mov ah,4ch | ;4Ch zum Beenden |  
        | INT 21h | ;Beende ! |  
        |  |  |  
        | Write: |  |  
        | lea dx, MSG1 | ;das gleiche wie mov dx, offset MSG1 |  
        | mov ah, 9h |  |  
        | int 21h |  |  
        | ret |  |  
        | MSG1 db 'Schleife ..1,2,3.. ',10d,13d,'$' | ;Ein String.. |  
        |  |  |  
        | END START | ;hier ist das ganze zuende.. |  
        | ----------ende----------- |  |  |  | 
  
    |  | 13. Etwas Bewegung... |  | 
  
    |  | Nun geht es darum, eine größere Menge an
    Bytes von einem Ort zum anderen zu bewegen. Oder sie zu laden, zu ändern und dann wieder
    zu speichern. Dafür gibt es die drei Befehle movsb, lodsb und stosb. Diese drei Befehle
    arbeiten mit den Registern DI (Direction Index) und SI (Source Index). In diesen beiden
    Registern wird immer die Adresse (offset) der zu bearbeitenden Daten gespeichert. DI gibt
    den Platz an, an den Daten geschrieben werden, SI den Offset von dem sie kommen. MOVSB
    schreibt ein Byte von SI nach DI, wenn man mehrere Bytes copieren will, muss man vor das
    ganze ein REP setzen (siehe vorheriges Kapitel). Mit LODSB lädt man ein Byte von SI nach
    AL. Dabei wird SI um eins erhöht, so das SI nun auf das nächste Byte zeigt. STOSB
    dagegeb speichert das Byte aus AL an dem Offset auf den DI zeigt. Hier wird DI dabei um
    eins vergrößert. Schauen wir uns ein kleines Beispielprogramm an, das eine Zeichenkette
    entschlüsselt und dann ausgibt: 
      
        | --8<---(CRYPT.asm)------ |  |  
        | .model tiny |  |  
        | .code |  |  
        | org 100h |  |  
        | START: |  |  
        | mov cx, 9d | ;wir setzen den Zähler auf 9 |  
        | mov si, offset msg1 | ;laden des Offsets in SI |  
        | mov di, si | ;da Ziel = Quelle ist |  
        |  | ;muss si = di sein.. |  
        | Crypt: | ;unsere Schleife |  
        | lodsb | ;wir laden das erste Byte in al |  
        | dec al | ;vermindern es um 1 |  
        | stosb | ;speichern es wieder |  
        | loop Crypt | ;und machen das ganze 9 mal |  
        |  |  |  
        | Write: |  |  
        | lea dx, MSG1 | ;das gleiche wie mov dx, offset MSG1 |  
        | mov ah, 9h | ;nun zeigen wir die entschlüselte |  
        | int 21h | ;Nachricht auf dem Bildschirm.. |  
        |  |  |  
        | ENDE: | ;schönes Label oder ? |  
        | mov ah,4ch | ;4Ch zum Beenden |  
        | INT 21h | ;Beende ! |  
        | MSG1 db 'UPQTFDSFU' |  |  
        | StringEnde db 10d,13d,'$' | ;Ende des Strings.. |  
        |  |  |  
        | END START | ;hier ist das ganze zuende.. |  
        | ----------ende----------- |  |  Eine der Sachen, die mir an Assembler am Besten gefallen, ist, das man
    nicht nur die Daten verändern kann, sondern auch das Programm an sich, während es
    läuft. Und dies nicht nur auf der Festplatte, sondern auch im Speicher, wodurch sich zum
    Beispiel das gesamte Programm verschlüsseln lässt, oder man auf 'etwas' andere Art und
    Weise den Programmablauf ändern kann. Im folgenden Beispiel ändern wir einen JE in einen
    JNE, so das sich das Programm anders verhält.   
      
        | --8<---(JUMP.asm)------ |  |  
        | .model tiny |  |  
        | .code |  |  
        | org 100h |  |  
        | START: |  |  
        | mov di, offset JUMP | ;wir laden in DI die Adresse, die wir ändern |  
        | mov al, 75h | ;75h ist der HEX-Code für JNE |  
        | stosb | ;den schreiben wir über den JE |  
        | mov ax, 0h | ;Wir setzen AX und BX = 0 |  
        | mov bx, 0h |  |  
        | cmp ax,bx | ;Hier vergleichen wir 2 gleiche Zahlen |  
        |  |  |  
        | JUMP: |  |  
        | JE WriteMSG2 | ;sind sie gleich, dann springe.. (dies ist |  
        |  | ;der Befehl, den wir ändern.. ) |  
        | lea dx, MSG1 | ;ansonsten gib MSG1 aus.. |  
        | jmp WriteMSG |  |  
        |  |  |  
        | WriteMSG2: | ;hierher springt der JE |  
        | Lea dx, MSG2 | ;schreibe MSG2 |  
        |  |  |  
        | WriteMSG: | ;schreibe die Nachricht.. |  
        | mov ah, 9h |  |  
        | int 21h |  |  
        |  |  |  
        | ENDE: | ;schönes Label oder ? |  
        | mov ah,4ch | ;4Ch zum Beenden |  
        | INT 21h | ;Beende ! |  
        | MSG1 db 'Dies erscheint nur beim geänderten JNE !!!
        *g*',10d,13d,'$' | ;String |  
        | MSG2 db 'Dies erscheint wenn der Original JE
        ausgeführt wird..',10d,13d,'$' | ;String |  
        |  |  |  
        | END START | ;hier ist das ganze zuende.. |  
        | ----------ende----------- |  |  Dies ist nur eine der vielen Möglichkeiten, wie man den Code während der Ausführung
    ändert.. Ich werde später bei der Indirekten Adressierung nochmal genauer darauf
    eingehen. |  | 
  
    |  | 14.
    Verschlüsselung und anderes.. |  | 
  
    |  | Es gibt noch eine Menge anderer Funktionen in
    Assembler, die sich zum Verschlüsseln und Codieren des Codes oder anderer Daten eignen.
    Das Problem beim verschlüsseln von Programmen ist nicht die komplexität des
    Verschlüsselungsalgorithmusses, sondern der Schlüssel, der ja auch im Programm vorhanden
    sein muss. Da auch ein Cracker diesen Schlüssel im Programm findet, kann er auch das
    Programm entschlüsseln. Ok, ich erklär erstmal einige der Funktionen... XCHG AX,BX : Mit diesem Befehl tauscht man die Daten zweier RegisterNEG AX : Hier wird AX negiert aus 00000020h wird FFFFFFE0h
 NOT AX : Addiert 1 und multipliziert mit -1 ( 5 = -6)
 XOR AX,BX : Bitweise Verknüpfung mit einem exclusiven oder:
 16h XOR 20h = 36h10110b
 XOR 100000b
 =        110110b
 Im Klartext taucht im Ergebnis immer dort eine 1 auf, wo entweder im 1. oder 2. Operant
    eine 1 war. Dort wo an beiden Operanten eine 0 oder eine 1 war steht im Ergebnis eine 0. OR AX, BX : Bitweise Oder-Verknüpfung16h OR 20h = 36h
 10110b
 OR 100000b
 =    110110b
 Hier enthält das Ergebnis dort eine 1, wo in einem der beiden Operanten
    eine 1 stand. Aber es kommt nur dort eine 0 vor, wo in beiden Operanten eine 0 stand. NOR AX,BX : Verknüpfung über NOT und OR
 Diese Verknüpfungen kann man entweder dazu verwenden, irgendwelche Mathematischen
    Rechnungen auszuführen ( igitt ) oder um Texte oder ähnliches zu verschlüsseln damit
    nicht jeder Lamer seinen Namen in euer Programm mit nem Hexeditor schreiben kann...
 Dazu eignen sich besonders gut NEG, NOT und XOR. Wenn mal eine Zahl nämlich zweimal
    negiert oder zweimal ein NOT mit ihr durchführt erhält man die Ursprungszahl. Genauso
    ist es mit XOR, wodurch sich bei einer Byte-weisen Verschlüsselung FFh Möglichkeiten
    bieten, bei einer Word Verschlüsselung sogar FFFFh Möglichkeiten. Das Beispiel ist das
    gleiche wie vorher, nur statt dem dec benutzen wir diesmal XOR, NEG und NOR
 
      
        | --8<---(CRYPT2.asm)------ |  |  
        | .model tiny |  |  
        | .code |  |  
        | org 100h |  |  
        | START: |  |  
        | mov cx, 7d | ;wir setzen den Zähler auf 7 |  
        | mov si, offset msg1 | ;laden des Offsets in SI |  
        | mov di, si | ;da Ziel = Quelle ist |  
        |  | ;muss si = di sein.. |  
        | Crypt: | ;unsere Schleife |  
        | lodsb | ;wir laden das erste Byte in al |  
        | neg al |  |  
        | xor al, 34h |  |  
        | not al |  |  
        | stosb | ;speichern es wieder |  
        | loop Crypt | ;und machen das noch ein paar mal |  
        |  |  |  
        | Write: |  |  
        | lea dx, MSG1 | ;das gleiche wie mov dx, offset MSG1 |  
        | mov ah, 9h | ;nun zeigen wir die entschlüselte |  
        | int 21h | ;Nachricht auf dem Bildschirm.. |  
        |  |  |  
        | ENDE: | ;schönes Label oder ? |  
        |  |  |  
        | mov ah,4ch | ;4Ch zum Beenden |  
        | INT 21h | ;Beende ! |  
        | MSG1 db 7Dh, 56h, 59h, 59h, 5Ch, 1bh, 1bh |  |  
        | StringEnde db 10d,13d,'$' | ;Ende des Strings.. |  
        |  |  |  
        | END START | ;hier ist das ganze zuende.. |  
        | ---------ende----------- |  |     |  | 
  
    |  | 15. Schieben und
    Rollen |  | 
  
    |  | Jetzt geht es um 4 Befehle, die für Ordnung in
    den Registern sorgen:  ROR, ROL, SHR, SHL Jeder Register besteht aus 16 Bit. Da diese 16 Bit nicht immer so angeordnet sind, wie wir
    das brauchen muss man sie verschieben. Folgendes Beispiel an einem 8-Bit Register: (bin zu
    faul 16 stück zu malen *g*)
 [1|0|0|1|0|1|0|1] SHR AH,1 = [0|1|0|0|1|0|1|0]
 In ah befand
    sich der Wert 149, der durch das verschieben zu 10 geändert wird. Mit SHR verschieben wir
    die Bits von links nach rechts (sh_R_ wie rechts), dabei Fallen am rechten Ende die Bits
    heraus und von Links rücken immer nur Nullen nach. Genauso verhält es sich mit SHL, nur
    das hier von Rechts die Nullen nachrücken und die Bits am Linken Ende herausfallen.[1|0|0|1|0|1|0|1] SHL AH,1 = [0|0|1|0|1|0|1|0]
 Aus 149 wird in diesem Fall also 42. Was ist nun ROR und ROL ? Mit den beiden Befehlen
    rotieren die Register ;) Sie werden verwendet wie SHR und SHL aber bei ihnen fallen die
    Bits nicht am Ende weg, sondern werden am anderen Ende wieder drangefügt.[1|0|0|1|0|1|0|1] ROR AH,1 = [1|0|0|0|1|0|1|0]
 149 --> 138
 [1|0|0|1|0|1|0|1] ROL AH,1 = [0|0|1|0|1|0|1|1]149 --> 43
 So hier ein kleines Programm, das eine Dezimalzahl in Binärcode ausgibt. Der Befehl
    mov byte ptr cs:[si] einfach nicht beachten *g* er wird im nächsten Kapitel erklärt.. ;)
    Wenn ihr eine andere Zahl testen wollt (0-255) einfach unter dezimalzahl eintragen..  
      
        | --8<---(DEC2BIN.asm)------ |  |  
        | .model tiny |  |  
        | .code |  |  
        | org 100h |  |  
        |  |  |  
        | START: |  |  
        | mov cx, 8h |  |  
        | loopit: |  |  
        | dec cx |  |  
        | mov ah, dezimalzahl | ;lade die dezimalzahl in ah |  
        | shr ah, cl | ;verschiebe ah nach rechts, solange bis nur
        das cx'te |  
        |  | ;Byte übrig ist |  
        | and ah, 00000001h | ;setze alle bytes ausser dem letzten = 0 |  
        | add ah, 48d | ;als ascii zahl darstellen |  
        | mov si, offset bin + 8h | ;wo speichern wir die zahl ? |  
        | sub si, cx |  |  
        | mov byte ptr cs:[si],ah | ;speicher sie (mehr zu byte ptr später) |  
        | inc cx |  |  
        | loop loopit | ;wiederhole das ganze |  
        | lea dx, MSG1 | ;das gleiche wie mov dx, offset MSG1 |  
        | mov ah,09h |  |  
        | int 21h |  |  
        |  |  |  
        | ENDE: | ;schönes Label oder ? |  
        | mov ah,4ch | ;4Ch zum Beenden |  
        | INT 21h | ;Beende ! |  
        | MSG1 db 'Die Binaerzahl lautet :' |  |  
        | bin db ' ',10d,13d,'$' |  |  
        | dezimalzahl db 23d |  |  
        | END START | ;hier ist das ganze zuende.. |  
        |  |  |  
        | ----------ende----------- |  |  |  | 
  
    |  | 16. Indirekte
    Adressierung |  | 
  
    |  | Wie ihr weiter oben schon gelesen habt, gibt es
    innerhalb des Codes verschiedene Segmente, die ihr nach euerem belieben frei definieren
    könnt. Bisher haben wir nur mit CS, dem Code Segment und SS dem Stack Segment gearbeitet.
    Bisher standen auch die Daten im Code Segment, da dieses einfacher zu Handhaben ist. Nun
    wollen wir aber ein eigenes Segment für die Daten einrichten. Dies geschieht mit dem
    Befehl ASSUME. Ein Beispiel:
 --8<---(~~~~~~~~)------code segment
 assume cs:code,ds:data       ;Definiert die einzelnen
    Segmente
 ;euer code hierher..
 code ends
 data segment
 ;hier kommen die daten rein..
 data ends
 end
 ----------ende-----------
 Genauso könnt ihr auch das Stack Segment, oder ES, FS und GS definieren.  Ein
    Segment beginnt immer mit <Name> segment und endet mit <Name> ends. Wenn wir
    vom Code Segment auf ein anderes zugreifen wollen müssen wir dies dem Programm mitteilen.
    Dies geschieht durch Angabe des Segmentes mov ah, byte ptr ds:[offset value]mov ax, word ptr ds:[offset value2]
 Im ersten Beispiel wird der Wert des Bytes an Stelle value in ah geschoben in  
    Beispiel 2 der Wert des Words (2 bytes) an Offset value2 in ax.  Hier ein wirklich
    simples Beispiel, das mit 2 Segmenten arbeitet. Dies ist allerdings eine EXE-Datei (in COM
    Dateien ist alles ein Segment) und wird deshalb anders kompiliert. (Siehe dafür nächstes
    Kapitel) 
      
        | --8<---(Segments.asm)------ |  |  
        | code segment | ;dies ist CS |  
        | assume cs:code,ds:data,ss:stackSeg | ;Definiert die einzelnen Segmente |  
        |  |  |  
        | start: |  |  
        | push data | ;wir initialisieren die einzelnen |  
        | pop ds | ;Segmente... |  
        | push stackSeg |  |  
        | pop ss |  |  
        | mov ah,9h | ;wir laden den String aus DS |  
        | mov dx, ds:[offset string] |  |  
        | int 21h |  |  
        | mov ah, 4ch | ;ENDE |  
        | int 21h |  |  
        | code ends | ;hier endet unser Code |  
        | data segment | ;hier starten die Daten |  
        | string db 'Unser String.. ;)
        ',10d,13d, '$' |  |  
        | data ends | ;hier enden sie |  
        | stackSeg segment STACK | ;das ist unser Stack, wenn viel mit |  
        | db 50h dup (?) | ;dem Stack gearbeitet wird mehr als 50h |  
        | stackSeg ends | ;Bytes definieren ! |  
        | end start |  |  
        | end |  |  
        |  |  |  
        | ----------ende----------- |  |  
        |  |  |  Die Segmente kann man nur auf 2 Arten ändern, entweder über ax, indem
    man einen Wert in AX legt und dann ein mov DS, ax macht oder über push und pop.push cs
 pop ds
 setzt zum Beispiel DS = CS. Man kann auch später im Programm noch die Segmente, wenn man
      diese Arten benutzt verändern. Es ist egal, ob ihr euer Daten Segment vor oder
    nach das  Code Segment setzt, da beim Laden von EXE-Dateien zuerst im Header der EXE
    der Anfangspunkt des Codes gesucht wird und nicht direkt von vorne gestartet wird, wie in
    COM Dateien. Vielleicht sollte ich auch noch die Anweisung db 50h dup (?) erklären. Hier
    werden  50h, also 125 Bytes definiert, die noch nichts (0) enthalten. Ein dw 100h dup
    ('BS') würde zum Beispiel 256 Words mit den Buchstaben SB (für SnakeByte *g) definieren.
    SB deshalb, da ein Word immer umgedreht geschrieben wird. In der Datei steht dann
    SBSBSBS... ;P
 
 |  | 
  
    |  | 17. EXE-Dateien |  | 
  
    |  | Wo ist der Unterschied zwischen einer EXE-Datei
    und einer COM-Datei ? Für uns liegt er erstmal darin, das wir das org 100h weglassen
    müssen und nun unsere Segmente frei definieren können ! Hier können wir nun auch die
    Daten vor den Code oder zwischen 2 Code Abschnitte (dann aber CS neu setzen *g*) legen
    können. Auch müssen wir EXE-Dateien anders compilieren. Hier wieder eine Batch Datei: 
 ---8<------ ( CompEXE.bat )---------
 @Echo Off
 if not exist %1.asm goto quit
 tasm %1 /p/w/z/m4
 if errorlevel 1 goto quit
 tlink %1/d/l
 del %1.map
 del %1.obj
 :quit
 ---8<-------------------------------
 
 Durch diese Anweisungen weiß unser Compiler und Linker, das er eine EXE-Datei zu
    erzeugen hat. Diese ist normalerweise um 256 Bytes größer, da im Header noch wichtige
    Informationen  über die Ausführung und die Segmente der EXE enthalten sind. Eine
    EXE Datei beginnt immer mit MZ bzw ZM und wird selbst wenn sie in *.COM umbenannt wird
    laufen. (einige COM Dateien sind versteckte EXE Dateien -> command.com auf vielen
    Systemen) Auch kann eine EXE Datei nun größer sein als die 64kb die uns in COM Dateien
    eine Grenze setzen.
   |  | 
  
    |  | 18. Datei-Handling |  | 
  
    |  | Dateien sind immer brauchbar, wenn man etwas
    abspeichern oder lesen will. Deshalb werde ich euch hier zeigen, wie man über den
    DOS-Interrupt 21h Dateien erstellt und ändert. Was ihr dazu braucht sind folgende
    Funktionen (immer den Wert in ah legen.. ;) ) ich liste sie nur kurz auf, am Besten also
    nochmal in PPC oder Ralf Browns Interrupt List nachlesen, da im folgenden Sourcecode auch
    nicht alle dieser Interruptfunktionen angesprochen werden. 
 
      
        | 4eh | Find First File | Suche nach einer Datei |  
        | 4fh | Find Next File | Sucht die nächste Datei, wenn Wildcards
        (*.txt) verwendet werden |  
        | 3ch | Create File | Erstelle neue Datei |  
        | 3dh | Open File | Öffnet eine Datei (al ist Modus -> 02h
        read/write) |  
        | * 3eh | Close File | Schließt die Datei wieder |  
        | 41h | Delete File | Lösche eine Datei |  
        | * 42h | Set File Pointer | Bewegt einen Zeiger in der Datei |  
        | * 40h | Write File | Schreibt etwas in die Datei an die Stelle auf
        die der Zeiger zeigt |  Die Funktionen 3dh und 3ch geben in ax den sogenannten File Handle aus,
    der die Datei  identifiziert, wenn man zum Beispiel mehrere Dateien geöffnet hat.
    Dieser wird für  einige dieser Int-Funktionen (mit * gekennzeichnet) in BX
    benötigt. Also am besten gleich nach dem Öffnen oder Erstellen irgendwo speichern. 
      
        | ---8<------ ( Files.asm )--------- |  |  
        | .model tiny |  |  
        | .code |  |  
        | org 100h |  |  
        |  |  |  
        | Start: |  |  
        | mov ah, 3Ch | ;erstelle eine neue Datei (immer) |  
        | lea dx, filename | ;Zeiger zum Dateinamen |  
        | xor cx, cx | ;keine attribute |  
        | int 21h |  |  
        | xchg ax,bx | ;schiebe das Handle in bx |  
        | mov ah, 40h | ;schreibe etwas in die Datei |  
        | lea dx, Text | ;was soll hineingeschrieben werden ? |  
        | mov cx, (offset endText-offset Text) | ;wieviel soll geschrieben werden ? |  
        | int 21h | mov ah, 3eh ;nun schließen wir die Datei
        wieder.. ;) |  
        | int 21h |  |  
        | mov ah, 3dh | ;und nun wird es wieder geöffnet.. ;) |  
        | xor al, al | ;nur zum lesen.. |  
        | lea dx, filename | int 21h |  
        | jc ENDE | ;ist carriage flag gesetzt beende das Ganze |  
        | xchg ax, bx | ;speichern des Handles |  
        | mov ax, 4202h | ;gehe zum Ende der Datei.. |  
        | xor cx, cx | ;cx = dx = 0 |  
        | xor dx, dx |  |  
        | int 21h |  |  
        | push ax | ;ax ist die Länge des Dateiinhaltes, wenn |  
        |  | ;sie kleiner als 64kb ist.. ;) |  
        | mov ax, 4200h | ;gehe zum anfang der Datei |  
        | xor cx,cx |  |  
        | xor dx,dx |  |  
        | int 21h |  |  
        | mov ah, 3fh | ;lesen der gesamten Datei |  
        | pop cx | ;in den Buffer |  
        | push cx | lea dx, buffer |  
        | int 21h |  |  
        | mov ah, 3eh | ;die Datei wird geschlossen |  
        | int 21h |  |  
        | mov si, offset buffer | ;hänge an die Daten der Datei |  
        | pop cx | ;ein '$', damit wir sie auf dem |  
        | add si, cx | ;Bildschirm ausgeben können |  
        | mov byte ptr [si],'$' |  |  
        | mov ah, 9h | ;Zeige die gelesenen Daten auf dem |  
        | lea dx, buffer | ;Bildschirm |  
        | int 21h |  |  
        |  |  |  
        | ENDE: |  |  
        | mov ah, 4ch | ;beende das Programm |  
        | int 21h |  |  
        | filename db 'testit.txt',0h |  |  
        | Text db 'Doller Text oder ??
        *g*',10d,13d |  |  
        | endText: |  |  
        | buffer: |  |  
        | end start |  |  
        | ---8<------------------------------- |  |  |  | 
  
    |  | 19. Assembler
    Anweisungen |  | 
  
    |  | Es gibt auch Anweisungen, die man dem Compiler
    / Linker im Programmtext mitgeben kann, die einem die Arbeit erleichtern. diese werden
    einfach an den Anfang des Programmes geschrieben. Hier liste ich einfach mal einige auf: 
      
        | .model tiny | Hiermit legt ihr die Größe eueres Programms fest.
        Mögliche Einstellungen sind: tiny -> insgesamt max 64kb small -> code & data
        jeweils < 64kb medium -> code > 64kb, data < 64kb compact -> code <
        64kb, data > 64kb large / huge -> code & data > 64 kb Normal reicht 'small'
        oder tiny aber für die meisten Programme dicke.. ;) |  
        | .code | Art der Sektion ( code / data / stack ) |  
        | org 100h | Wo soll das Programm starten ? 100h für COM 0h für EXE,
        0h für SYS.. |  
        | jumps | Alle Sprünge über 256 Bytes, die normal als FAR JMP
        declariert werden müssten, werden automatisch berechnet (Sehr hilfreich !) |  
        | radix 10 | Diese Anweisung gibt an, in welchem Zahlenformat Zahlen
        ohne Angabe sind (h für hex, d für dezimal b für binär). Wenn man hier 10 angibt wird
        das Dezimalsystem verwendet, bei 16 das hexadezimale System. (schützt vor vergessenen
        h's, nach denen man sich totsuchen kann *g* ) |  
        | dreizehn equ 13d | Hiermit kann man Konstanten deklarieren, die man öfters
        ändert. Im Programmtext steht dann zum Beispiel ein ' mov ax, dreizehn' der Kompiler
        setzt dann automatisch die Zahl ein, die man mit equ definiert hat. |  
        | .286 | Hiermit kann man den Prozessortyp angeben, der  
        benötigt wird um das Programm zu starten. Je höher der Prozessortyp ist, umso mehr
        zusätzliche Befehle können verwendet werden, da mit jeder neuen Prozessorklasse weitere
        Befehle eingeführt werden. (mögliche Werte: .286, .386, .486, .586, .286P, 386P ..) |  
        | include xyz.inc | Mit diesem Befehl könnt ihr Include Dateien in euer
        Programm einbinden diese können auch andere Dateinamenerweiterungen haben (.asm, .pal...)
        und enthalten auch Assemblerquelltext. Darin stehen dann zum Beispiel andere Prozeduren,
        Daten etc. Diese könnt ihr dann auch aus euerem Programm aufrufen. Dies hilft größere
        Projekte übersichtlich zu halten. |  |  | 
  
    |  | 20. Suchen nach
    Text-Strings |  | 
  
    |  | Was ist wenn wir Texte bearbeiten wollen ? Dann
    müssen wir die Möglichkeit haben in diesen Texten nach Strings zu suchen. Dies geschieht
    mit dem Befehlt scasb. Er vergleicht das Byte in al mit dem Inhalt des Offsets auf den di
    zeigt. Nach dem Vergleichen wird di um 1 erhöht. Um nun mehrere Vergleiche
    durchzuführen, wiederholt man diese Anweisung solange bis, entweder die Länge des Textes
    erreicht ist, oder man Erfolg hat. Danach wird mit cmp der Rest des zu suchenden Strings
    verglichen. Aber genug der Worte,  lasst uns das ganze wieder an einem Beispiel
    betrachten. Wir durchsuchen die Datei C:\Autoexec.bat
    nach dem String 'rem' , welcher ein Kommentar einleitet... 
      
        | ---8<------ ( scasb.asm
        )--------- |  |  
        |  |  |  
        | .model tiny | ;nur ein kleines Programm |  
        | .code | ;hier steht der code |  
        | org 100h | ;wir basteln ne COM Datei |  
        |  |  |  
        | START: | ;Label zum verzieren |  
        | mov ah, 3dh | ;öffnen der autoexec.bat |  
        | xor al, al | ;nur zum lesen.. |  
        | lea dx, filename | ;dx zeigt auf den Dateinamen |  
        | int 21h |  |  
        | jc Ende | ;wenn es irgendwelche Fehler
        gibt beenden wir.. |  
        | mov bx, ax | ;speichern des Handels |  
        | mov ax, 4202h | ;gehe zum Ende der Datei.. |  
        | xor cx, cx ;cx = dx = 0 |  |  
        | xor dx, dx |  |  
        | int 21h |  |  
        | push ax | ;ax ist die Länge des
        Dateiinhaltes, wenn |  
        |  | ;sie kleiner als 64kb ist.. ;) |  
        |  | ;der Rest steht in DX |  
        | mov ax, 4200h | ;gehe zum anfang der Datei |  
        | xor cx,cx ;CX=DX=0 |  |  
        | xor dx,dx |  |  
        | int 21h |  |  
        | mov ah, 3fh | ;lesen der gesamten Datei |  
        | pop cx | ;in den Buffer |  
        | push cx | ;speicher die Dateilänge
        wieder im Stack |  
        | lea dx, buffer |  |  
        | int 21h |  |  
        | mov ah, 3eh | ;die Datei wird geschlossen |  
        | int 21h |  |  
        | mov dx, 0h | ;Setze dx als Zähler auf 0 |  
        | lea di, buffer | ;hier fangen wir an zu suchen |  
        | SearchOn: |  |  
        | pop cx | ;Dateilänge in cx |  
        | lea si, string | ;was wollen wir finden ? |  
        | lodsb | ;lade das erste Byte in ax |  
        | repnz scasb | ;Suche starten |  
        | cmp cx,0 | ;wenn cx=0 dann wurde alles
        durchsucht.. |  
        | jz disp | ;Ergebnisse anzeigen |  
        | push cx |  |  
        | mov cx, laenge | ;den Rest des Strings
        vergleichen |  
        | repz cmpsb |  |  
        | cmp cx,0 | ;kompletter String gleich ? |  
        | jnz SearchOn | ;wenn nicht weitersuchen |  
        | inc dx | ;Zähler erhöhen |  
        | pop cx | ;Restliche Länge überprüfen |  
        | push cx |  |  
        | cmp cx, 0 |  |  
        | jne SearchOn | ;weitersuchen |  
        | mp dispj | ;anzeigen |  
        |  |  |  
        | disp: |  |  
        | lea di, showstring | ;in di ist der String den wir
        anzeigen wollen |  
        | mov ax, dx | ;wenn dx < 10 dann wird er
        umgerechnet in Dezimal |  
        | cmp ax, 10d |  |  
        | jnae showit |  |  
        | cmp ax, 100d |  |  
        | jae toogreat |  |  
        | xor dx, dx |  |  
        | mov cl, 10d |  |  
        | div cl |  |  
        | add dl, 48d |  |  
        | mov byte ptr cs:[di], dl |  |  
        | add al, 48d |  |  
        | mov byte ptr cs:[di], al |  |  
        | inc di |  |  
        |  |  |  
        | showit: |  |  
        | add dl, 48d |  |  
        | mov byte ptr cs:[di], dl |  |  
        | lea dx, showstring | ;Anzeigen |  
        | mov ah, 9h |  |  
        | int 21h |  |  
        |  |  |  
        | Ende: |  |  
        | mov ah, 4ch | ;Beenden.. |  
        | int 21h |  |  
        | toogreat: | ;Zahl ist größer als 9 |  
        | lea dx, toogre |  |  
        | mov ah, 9h |  |  
        | int 21h |  |  
        | jmp Ende |  |  
        | filename db
        'C:\Autoexec.bat',0h |  |  
        | string db 'rem' |  |  
        | laenge equ $-offset string |  |  
        | toogre db 'String öfters als 9
        mal gefunden',10d,13d,'$' |  |  
        | showstring db ' ',10d,13d,'$' |  |  
        | buffer: |  |  
        | END START | ;hier ist das ganze zuende.. |  
        |  |  |  
        | ---8<------------------------------- |  |    |  | 
  
    |  | 21. Graphiken |  | 
  
    |  | Ok, das letzte Thema mit dem ich mich hier
    beschäftigen will, sind Graphiken. Hier werde ich euch zeigen, wie man einen Pixel auf
    den Bildschirm schreibt, und eine Linie zieht. Wir verwenden hier einen neuen Interrupt.
    Der Interrupt 10h ist für all das zuständig, was die Ausgabe auf den Bildschirm
    betrifft. (man kann mit ihm auch Text ausgeben...). Was uns interessiert, sind die
    Funktionen 0h (Video-Modus Wechsel) und 0ch (Put-Pixel). Da wir  normalerweise im
    Text-Modus arbeiten, müssen wir zuerst einmal den Bildschirmmodus wechsel, so das wir
    vernünftige Bilder zeigen können (*g*) Wir wechseln also in den MCGA Modus. Dieser
    lässt uns 255 Farben darstellen, auf einem Bildschirm von 320*200 Pixeln Größe. Die
    Interruptfunktion 0h wird dazu benutzt um in diesen Modus zu gelangen und auch um wieder
    den Text-Modus einzustellen. Mit 0Ch werden wir dann ein Pixel auf den Bildschirm
    ausgeben. Solange, bis wir ein Rechteck erhalten. 
 
      
        | ---8<------ ( grafix.asm )--------- |  |  
        | .model tiny | ;nur ein kleines Programm |  
        | .code | ;hier steht der code |  
        | org 100h | ;wir basteln ne COM Datei |  
        |  |  |  
        | START: | ;Label zum verzieren |  
        | mov ax, 0013h | ;setzen des Video Modus (MCGA) |  
        | int 10h ;320*200*256 |  |  
        |  | ;wir zeichnen eine Linie |  
        | mov word ptr [startlinex], 20h |  |  
        | mov word ptr [endlinex], 30h |  |  
        | mov word ptr [startliney], 50h |  |  
        | mov word ptr [endliney], 50h |  |  
        | call drawline |  |  
        |  | ;und noch eine.. |  
        | mov word ptr [startlinex], 30h |  |  
        | mov word ptr [endlinex], 30h |  |  
        | mov word ptr [startliney], 40h |  |  
        | mov word ptr [endliney], 50h |  |  
        | call drawline |  |  
        | mov word ptr [startlinex], 20h |  |  
        | mov word ptr [endlinex], 30h |  |  
        | mov word ptr [startliney], 40h |  |  
        | mov word ptr [endliney], 40h |  |  
        | call drawline |  |  
        |  | ;bis wir ein Quadrat haben.. ;P |  
        | mov word ptr [startlinex], 20h |  |  
        | mov word ptr [endlinex], 20h |  |  
        | mov word ptr [startliney], 40h |  |  
        | mov word ptr [endliney], 50h |  |  
        | call drawline |  |  
        | mov ah,1h | ;auf Tastendruck warten.. |  
        | int 21h |  |  
        | mov ax, 0003h | ;zurück zum Textmodus |  
        | int 10h |  |  
        | Ende: |  |  
        | mov ah, 4ch | ;Beenden.. |  
        | int 21h |  |  
        |  |  |  
        | drawline: |  |  
        | call putpixel |  |  
        | mov ax, word ptr [startlinex] |  |  
        | sub ax, word ptr [endlinex] |  |  
        | mov bx, word ptr [startliney] |  |  
        | sub bx, word ptr [endliney] |  |  
        | cmp ax, bx |  |  
        | ja putx ;x - Pixel malen |  |  
        | jb puty ;y - Pixel malen |  |  
        | cmp ax, 0h | ;wenn ax = bx = 0, dann haben wir genug |  
        | je return | ;gezeichnet |  
        | inc word ptr [startlinex] | ;sowohl x, als auch y, um 1 verschieben |  
        | inc word ptr [startliney] | ;(für Schrägen) |  
        | call putpixel | jmp drawline |  
        | putx: | ;Pixel auf X-Koordinate zeichnen |  
        | inc word ptr [startlinex] |  |  
        | call putpixel |  |  
        | jmp drawline |  |  
        |  |  |  
        | puty: | ;Pixel auf Y-Koordinate zeichnen |  
        | inc word ptr [startliney] |  |  
        | call putpixel |  |  
        | jmp drawline |  |  
        | return: |  |  
        | ret |  |  
        | putpixel: | ;cx,dx sind die Koordinaten |  
        | mov ah, 0Ch | ;Pixel zeichen |  
        | mov cx, word ptr [startlinex] |  |  
        | mov dx, word ptr [startliney] |  |  
        | mov al, 1 ;Farbe |  |  
        | mov bx, 1h |  |  
        | int 10h |  |  
        | ret |  |  
        | startlinex dw 0h | ;unsere Koordinaten |  
        | endlinex dw 0h | ;sind hier gespeichert |  
        | startliney dw 0h |  |  
        | endliney dw 0h |  |  
        | buffer: |  |  
        |  |  |  
        | END START | ;hier ist das ganze zuende.. |  
        |  |  |  
        | ---8<------------------------------- |  |    |  | 
  
    |  | 22. Farbiger Text |  | 
  
    |  | Ok, wenn wir schon bei bunten Pixeln sind, hier
    noch eine kleine Anleitung, wie man farbigen Text auf dem Bildschirm ausgibt. Auch hier
    verwenden wir wieder den Interrupt 10h, der für die Bildschirmausgabe zuständig ist.
    Diesmal verwenden wir den Bildschirmmodus 12h. Mit der Funktion 2h des Int 10h legen wir
    die Position des Cursors auf dem Bildschrim fest, an der der Text erscheinen soll. Dann
    wird mit der Funktion 9h der Buchstabe ausgegeben. Dann wird der Cursor wieder verschoben
    und der nächste Buchstabe wird angezeigt.   
      
        | ---8<------ ( Farbe.asm
        )--------- |  |  
        | .model tiny | ;nur ein kleines Programm |  
        | .code | ;hier steht der code |  
        | org 100h | ;wir basteln ne COM Datei |  
        | START: | ;Label zum verzieren |  
        | mov ah, 0h | ;wir ändern den
        Bildschirmmodus |  
        | mov al, 12h |  |  
        | int 10h |  |  
        | lea si, HelloWorld | ;si zeigt auf unseren String |  
        | mov cx, lenght | ;cx = Stringlänge |  
        |  |  |  
        | LoopIt: |  |  
        | push cx | ;cx speichern |  
        | lodsb | ;Buchstaben des Strings in al
        lesen |  
        | mov ah, 2h | ;Cursor setzen |  
        | mov bh, 0h | ;auf Page 0 |  
        | mov dh, 2h | ;Zeile |  
        | mov dl, byte ptr XXX | ;XXX ist die Spalte |  
        | int 10h |  |  
        | inc byte ptr XXX | ;Farbe erhöhen |  
        | mov ah, 09h | ;Farbiger Charakter ausgeben |  
        | mov bh, 0h | ;Page 0 |  
        | mov bl, byte ptr XXX | ;Farbe |  
        | mov cx, 1h | ;schreibe ihn einmal.. |  
        | int 10h |  |  
        | pop cx | ;cx laden |  
        | loop LoopIt | ;wiederholen, bis der komplette |  
        |  | ;String geschrieben ist |  
        | mov ah, 2h | ;Cursor setzen |  
        | mov bh, 0h | ;auf Page 0 |  
        | mov dh, 3h | ;Zeile |  
        | mov dl, 3h | ;Spalte |  
        | int 10h |  |  
        | mov ah,1h | ;auf Tastatureingabe warten |  
        | int 21h |  |  
        | mov ah, 4Ch |  |  
        | INT 21h | ;Beende ! |  
        | HelloWorld db 'Hello World !!' |  |  
        | lenght equ $ - offset
        HelloWorld | ;Unser String.. |  
        | xxx db 0h |  |  
        | END START | ;hier ist das ganze zuende.. |  
        |  |  |  
        | ---8<------------------------------- |  |  |  | 
  
    |  | 23. Outro... |  | 
  
    |  | Ok, das wars für dieses Mal. Ich hoffe ich
    habe es geschafft euch einen Einstieg in die Assembler Programmierung zu verschaffen. Wenn
    ihr Fragen habt oder Vorschläge, was man noch in dieses Tutorial packen sollte schreibt
    mir einfach eine Mail (SnakeByte@kryptocrew.de). Neue Versionen dieses Tutorials und
    anderen interessanten Kram findet ihr auf meiner  Website: http://www.kryptocrew.de/snakebyte/ Das
    wars dann auch.. cu soon SnakeByte |  |