Schnell-Kurs (Assembler)

Dies hier ist ein sehr kompakter Schnell-Kurs für Assembler.
Dabei werden die wichtigsten Eigenschaften zum Assembler-Programmieren erklärt.
In diesen Dokumenten sind grundsätzlich alle ASM-Funktionen und Register groß geschrieben, bei Variabeln und Namen wird nur der ersten Buchstaben groß geschrieben..

CPU-ASM ganz Kurz

ASM ist im wesentlichen der Code der in direkter Prozessor- oder Maschinensprache geschrieben ist. ASM Programmen können daher viel effizienter sein als Hochsprachen Programme, und eine Runtime oder Compiler muß seine Code-Basis in ASM zur Verfügung haben.
Gerechnet wird in Registern, jede Operation muß also die Werte, zuerst in den entsprechenden Register verfügbar haben. Die Register sind sozusagen die Speicherstellen direkt im Prozessor. Das heißt, dass alle Werte zuerst einmal in diese Register kopiert werden müssen, um mit ihnen Rechnen zu können.
Da nicht unbegrenzt Register zur Verfügung stehen müssen Werte zT. zwischengespeichert werden, um Registerplätze wieder freizumachen. Dies kann im RAM Speicher geschehen oder in einem speziell dafür organisierten Speicher, welcher Stack (Stapel) genannt wird. Dieser Stack wird verwendet um Parameter zu übergeben oder Werte temporär zu speichern.
Da ständig mit Registern gearbeitet wird, muß der Inhalt der Register gesichert werden, um sicherzustellen, dass keine Informationen, die noch benötigt werden, überschrieben wird. Um dies soweit wie möglich zu verhindern geht man von sogenannten flüchtigen Registern aus, das heißt alle Register, außer EAX welches als Rückgabe Register verwendet wird, gelten als flüchtig. Der Compiler ist verantwortlich vor dem Sprung in eine Prozedur den Inhalt der Register zu sichern.
Alles befindet sich im gleichen RAM Speicher worauf der Prozessor zugreifen kann. Code, Daten und Stack benutzen also den gleichen Speicher. Um diese Speicherbereiche organisieren zu können, werden sie in Segmente aufgeteilt. Diese Speicher-Segmente werden über speziell dafür vorgesehene Segment-Register angesprochen.

Beschreibung-Kurz-CPU
OpCodes-CPU
Mathe-Integer

Funktionen

Mnemonic (ASM-Codes)

Mnemonic werden die Assembler (ASM) Funktionen genannt, sie repräsentieren direkten Binären Maschinen/Prozessoren Code in Textform lesbar geschrieben. Sie werden direkt vom ASM-Kompiler in Binärcode übersetzt.
Die Funktionen können 0 bis 3 Parameter enthalten, wobei der Parameter ganz links als Operand Funktionieren kann und gleichzeitig das Resultat speichert. In Binärcode (OpCode) können die Funktionen unterschiedlich lang sein, von minimal 1 Byte bis zu 6 und mehr Byte.

Mnemonic Ziel, Quelle
Mnemonic Ziel, Quelle1, Quelle2, Quelle3

Speicher

Flat-Memory Model

In den alten 16Bit DOS-Systemen wurde der Speicher über die Kombination aus Segment-Register und Offset gebildet. Die Segmente konnten nur 64KB (65536 Byte) adressieren.
Das heutige Speichermodell ist Flat (Flach), das heißt das sich alle Informationen, Daten und Code, im gleichen Segment Befinden. Es ist ein Speicherzugriff auf 4GB direkt möglich. Dadurch wird ASM schneller und der Code übersichtlicher. Die Segment-Register FS GS werden normalerweise nicht verwendet, das Betriebssystem benutzt sie für bestimmte aufgaben.
Flat-Memory Model steht seit 386 zur Verfügung.

Protected-Mode Memory (Real-Mode)

Im Real-Mode unter DOS war es möglich das Programme andere Speicherbereiche überschreiben konnten wenn meistens Programmierfehler dies versuchten. So konnten auch Betriebssystem Prozeduren überschrieben werden und ein Systemabsturz verursachen.
Im Protected-Mode wird der Speicherbereich kontrolliert in welcher ein Programm schreiben darf.

Little-Endian, Big-Endian

Die Daten werden im Speichern mit dem kleinsten Wert/Byte zuerst geschrieben, also umgekehrt als die Zahlen im Dezimalsystem.
Der Wert "4 3 2 1" (viertausend-dreihundert-einundzwanzig) würde im Speichern so abgelegt "01 02 03 04".

Register

Die Register sind die im Prozessor vorhandenen Speicherfelder die für alle Operationen verwendet werden. Der Prozessor kann keine Operationen zB. aus dem RAM-Speicher direkt durchführen, alle Werte müssen zuerst in die entsprechenden Register kopiert werden.
Es gibt 8 Register mit zum Teil speziellen Aufgabenbereichen EAX EBX ECX EDX, ESI EDI, ESP EBP.

EAX EBX ECX EDXOperations-Register
ESI EDIString Index-Register
ESP EBPStack-Register


Für alle Register gilt:
8Bit Register bestehen aus 1 Zeichen und werden in Niedriges und Hohes Byte (Low Hight) unterteilt, also ?L ?H zB. AL.
16Bit Register bestehen aus 2 Zeichen, also ?X zB. AX.
32Bit Register erhalten noch ein zusätzliches E, also E?? zB. EAX.

? --> A B C D

Da diese mit allen Programmen und auch dem Betriebssystem in Multitasking geteilt werden, und es nur so wenige sind, gelten spezielle regeln zur effizienten und Sicheren Nutzung.

ESP EBPWerden von Stack verwendet und dürfen nicht manipuliert werden.
EBX ESI EDIwerden vom Betriebssystem verwendet und müssen bei Manipulationen in Prozeduren gesichert werden.
EAX ECX EDXdürfen Frei verwendet werden.


Dabei gilt...

EAXWird als Standard Rückgabe-Register verwendet.
EBXWird als Speicherzeiger verwendet
EDXWird in Verbindung zB. mit Multiplikation Division als zusätzliche Rückgabe zu EAX verwendet.
ECXWird meistens als Zähler verwendet.


Bei einem Call in eine Windows-API Funktion sollten sicherheitshalber alle Register gesichert werden die relevante Daten enthalten, welche nach dem Call noch benötigt werden.

Programm-Register

Das Programm-Register enthält die aktuelle Position im Programmlauf. Es kann nicht direkt beeinflußt werden sondern nur indirekt über ASM-Funktionen die den Programmlauf beeinflussen.
Wird eine Funktion vom Prozessor ausgeführt, wird das Programm-Register um dessen Länge erhöht und zeigt somit auf die nächste Codeposition. (Nicht alle ProzessorFunktionen sind gleich lang.)
Die Zweite Möglichkeit sind Sprung-Funktionen wie Jump oder Loop.

Programm-Register
IPInstruktion-PointerZeigt auf die Stelle in der sich der Programmcode gerade befindet. Jede Funktionsausführung verschiebt den Zeiger um die Länge der ASM-Funktion oder springt über ein Sprung-Funktion

Haupt-Register

Register können aber auf eine Stelle im Speicher zeigen, der Prozessor rechnet also direkt mit dem Wert im Register, oder holt sich den Wert von der Adresse aus dem RAM-Speicher auf die das Register Zeigt.
Es gibt mehrere Register die Heute fast alle Funktionen durchführen können. Doch sind bestimmte Register für spezielle Aufgaben besonders gut geeignet. Einige Operationen können nur über bestimmte Register durchgeführt werden.

Haupt-Register
A?AkkumulatorIst für mathematische und logische Operationen, am besten. Multiplikation/Division ist auf A? angewiesen da das Resultat dort gespeichert wird
B?BasisWird als Speicher-Zeiger verwendet. Meistens wir B? verwendet um direkt aus dem Speicher Daten zu laden oder um Strings zu verarbeiten. B=Adresse / [B]=Wert in der Adresse
C?Counter (Zähler)Ist ein Zähler-Regsier, also am besten geeignet für Zähl Operationen oder Schleifen. LOOP verwendet automatisch das C-Register
D?Datawird für Langzahl Operationen verwandet. In Verbindung mit A?. D? enthält bei einem großen Wert den größeren Anteil in D. Zu können 2 16 oder 32 Bit Wörter kombiniert werden um das LongLong Resultat über D auszudehnen.

(? --> LHX)

Die Register können unterschiedlich Lang sein, 8 16 32 Bit. Je nach Längen gibt es verschiedene Zeichen. Diese gelten für alle 4 Haupt-Regsiter.
(? --> A B C D)

......?H 8Bit?L 8Bit
......?X 16Bit
E?X 32Bit


Oder

?L8Bit, in 1 Byte
?H8Bit, in 2 Byte
?X16Bit, in 1-2 Byte
E?X32Bit, in 1-4 Byte

Segmente und Segment-Register

Der Speicher ist eigentlich ein einziger riesiger Block. Um diese aber besser organisieren zu können verwendet ein Programm ein speziell Deklarierten Bereich für ein bestimmten Zweck. Diese Bereiche werden Segmente genannt. Zur Handhabung dieser Segmente gibt es spezielle Segment-Register.

Segment-Register
CSCodeZeigt auf den Speicherbereich in dem sich der Programmcode befindet. IP zeigt auf eine stelle in diesem Bereich
DSDatenHier befinden sich die Daten des Programms, also alle Werte und Strings
ESExtraFür zusätzliche Daten
SSStapelZeigt auf den Stapel, der verwendet wird um Werte Prozessor nahe aus den Registern zu Speichern oder Parameter von Calls zu übergeben. BP und SP zeigen in diesen Bereich
FSZusatzWeitere Zusatz-Segmente, eingeführt seit 386-CPU
GSZusatz...

Stack und Stack-Register

Stack funktioniert, wie der Name (Stack = Stapel) schon sagt, wie eine Liste von Werten die auf diesen Stapel gelegt oder entfernt werden können.
Der Stack dient als temporärer Zwischenspeicher. Er ist dem Prozessor näher als der RAM Speicher und deshalb effizienter nutzbar. Zudem gibt es spezielle Prozessorfunktionen und -register, die den Stack verwenden können, um Werte zu speichern oder zu löschen. Diese Werte können wie eine Speicheradresse auch in Register geladen werden.
Der Speicherbereich des Stacks ist im Vergleich zum Arbeitsspeicher sehr begrenzt; wird zuviel Stackspeicher verwendet, kann ein Stacküberlauf-Fehler auftreten. Besonders kritisch sind dabei rekursive Prozeduren (Prozeduren, die sich selbst aufrufen), da bei jedem Aufruf Parameter, Rücksprungadresse und die lokalen Variabeln im Stack abgelegt werden. Es kann passieren, daß bei einer zu tiefen Rekursion der Stack überläuft und das Programm hart abstürzt.

Der Stack wird auch für die Parameterübergabe an Prozeduren (CALL, RET) verwendet. Wird also über ein CALL eine Prozedur aufgerufen, werden die Parameter (Werte, Referenzen, Zeiger) auf dem Stack abgelegt. Obwohl die aufrufende Prozedur dafür verantwortlich wäre, das, was sie auf den Stack gelegt hat, auch wieder von diesem zu entfernen, wird dies in der Praxis normalerweise über die Funktion RET erledigt, welche die zur aufgerufenen Prozedur gehörigen Parameter wieder vom Stack löscht und dann aus der Prozedur heraus springt. Eigentlich kann nur die aufrufende Prozedur wissen ob diese Parameter nicht vielleicht breites in der nächsten Operation wieder in gleicher Reihenfolge im Stack benötigt werden.

Erwähnenswert ist vielleicht noch, daß Stacküberlauf-Fehler auch von schädlicher Software genutzt werden können, um Code in Programme einzuschleusen. Dazu wird ein Stacküberlauf genutzt, um gezielt Programmcode so zu überschreiben, daß am Ende der fremde eingeschleuste Code statt des eigentlichen Programms ausgeführt wird. Besonders Programmierer von Sprachen wie C müssen besonders darauf achten, daß durch fehlerhafte Daten keine solchen Fehler im Programmcode auftreten können. Da C einen allfälligen Stacküberlauf nicht prüft und somit auch nicht als Fehler erkennt, ist es sogar möglich, daß manipulierte passive Daten wie Bilder, Musik usw. verwendet werden können, um Viren und andere schädliche Software auf andere Computer einzuschleusen.

Stack Register
BPBase-PointerZeigt auf den Stack Anfang.
SPStack-PointerZeigt auf das Stack Ende.


Stack ASM
PUSHSchreibenLegt ein Wert auf den Stack und Rechnet auf das Register EBP-Länge
POPLesenNimmt ein Wert vom Stack und rechnet auf das Register EBP+Länge

Index-Register

Die Index-Register werden für Bereichsoperationen verwendet, also zB. Für String- oder Tabellen-Operationen.

Index Register
SIQuell-Index?+
DIZiel-Index?+


Index ASM
?+
?+

Flag

Flags dienen dem Prozessor um zusätzliche Resultate zu den Registern zu speichern oder zu lesen. Ein Flag kann nur 2 Zustände speichern 0=Ungesetzt 1=Gestezt.
Jede ASM-Funktion kann so zB. Markieren ob das Resultat 0 oder Negativ ist, oder diese Information auswerten. Die Auswertung muß deshalb gleich nach der Funktion erfolgen.

ZF PF AF OF CF SF sind die Status-Flags, werden durch Operationen vom CPU gesetzt.
???alle Status-Flags werden vor einer Operation auf 0 gesetzt. Ihre Resultate geben Auskunft über die Eigenschaft des Resultats.

DF TF IF sind Steuerungsflags und werden vom Programm gesetzt um den Programmlauf zu beeinflussen.

FlagBitNameBeschreibung
ZF06Zero=1 wenn das Ergebnis einer Berechnung oder Test 0 ist. LOOP Test CMP oder vergleiche benutzen Z ebenfalls.
SF07Sign=1 wenn das höchstwertige Bit 1 ist und damit der Wert als negativ interpretiert wird, wenn sie Signet-Type ist.
PF02Parity=1 wenn das Ergebnis ungerade also erstes Bit auf 1 steht. Wird bei Datenübertragung als Checksummen Bit verwendet.
CF00Carry=1 wenn der Wert einer Operation um 1Bit des Register Typs überschritten wurde. Der Wert kann verwendet werden um zB. bei Addition den übertrag zu speichern oder ein Überlauf zu erkennen.
OF11Overflow=1 wenn das höchstwertige Bit, das als Vorzeichen-Bit verwendet werden kann, verändert wurde. Das bedeutet das Resultat ist zerstört wenn eine negative Zahl aus zB. Addition 2 positiver Zahlen entsteht. Overflow wird also gesetzt wenn das höchstwertige Bit geändert wurde während Carry gesetzt wird wenn über das höchstwertige Bit hinaus ein Bit verloren ginge. Overflow wird also nur bei signed geprüft, bei unsigned nicht.
AF04Auxiliaryähnlich dem Carry-Flag für BCD-Operationen. Hilfsübertragsflag bei einem übertrag von 3 auf 4 Bits, in 8bit Operation. Wird in BCD Arithmetik verwendet.
DF10Direction=1 String-Zeichenketten Verarbeitung aufsteigend in Adresse behandeln, =0 absteigend. SI DI +-
IF09InterruptInterrupt-Kontrolle. =1 alle Unterbrechungen zulassen / =0 keine maskierbaren Unterbrechungen zulassen. Damit kann zB. in DOS das Abruch-Kommando Strg+C verhindert werden.
TF08Trap=1 Setzt den Prozessor in dein Einzelschrit-Modus. Nach jedem Schritt wird Interrupt 1 aufgerufen und verzweigt in eine spezielle Prozedur. Wird von Debugger oder Interpreter verwendet um Programmlauf zu kontrollieren
IOPL12-13I/O Privilege Level?+
NT14Nested-Task?+
RF16Resume?+
VM17Virtual 8086?+
AC18Aligment Check?+
VIF19Virtual Interrupt?+
VIP20Virtual Interrupt Pending?+
IF21Identification?+
-01(Reserviert)
-03(Reserviert)
-05(Reserviert)
-15(Reserviert)
-22(Reserviert)
-31(Reserviert)


FlagFunktionZweck
AllePUSHFDSpeichert das EFLAG-Register im Stack.
AllePOPFDLiest das EFLAG-Register aus dem Stack.
CFCLC CF=0, STC CF=1Setzen zum steuern von Carry Operationen wie ADC SBB
ZFTEST JZ LOOPEinige Funktionen benutzen den Inhalt des Z-Flags zur Steuerung
DFCLD DF=0, STD DF=1Setzen zum steuern von String-Funktionen
IFCLI IF=0, STI IF=1Setzen zum steuern von Interrupts

Werte in Register kopieren

Register = Register
  MOV EAX, ECX   ; EAX = ECX
Register = Speicher
  MOV EAX, [ECX]        ; EAX = Var1 (Wert auf die ECX im Speicher zeigt)
  MOV EAX, Var1         ; EAX = Var1 (Wert auf die Var1 im Speicher zeigt)
  MOV [EBX], EAX        ; EBX Adresse = EAX
  MOV Var1, EAX         ; Var1 Adresse = EAX
 
  LEA EAX, Var1         ; EAX = Adresse-Var (Kopiert die Adresse und nicht den Wert von Var1)
 
  LEA EAX, Var1         ; EAX = Adresse-Var (Kopiert die Adresse und nicht den Wert von Var1)
  MOV Var1P, EAX        ; Var1P = ist nun ein Pointer/Zeiger der auf Var1 Zeigt
 
  MOV EAX, Var1P        ; EAX = Var1P
  MOV EAX, [EAX]        ; Var1 (Wert auf die Var1P im Speicher zeigt, dereferenzieren)
Register = Konstante
  MOV EAX, 1            ; EAX = 1
  MOV EAX, "1"          ; EAX = ASCII(1)
  MOV EAX, 01h          ; EAX = HEX(1)
Speicher = Speicher
  MOV Var2, Var1        ;!!! Speicher-Adresse kann nicht direkt kopiert werden
  ;
  MOV EAX, Var1         ; über Register kopieren
  MOV Var2, EAX
  ;
  PUSH Var1             ; über Stack kopieren
  POP Var2
Fehler-Quellen
;Es können nur gleich lange Wörter miteinander berechnet werden
 
  MOV EAX, CL           ; FEHLER: da EAX 32-Bit und CL 8-Bit ist
 
;Diese müssen erst Konvertiert werden
 
  MOVZX EAX, CL         ; Mit 0 erweiterter Unsigned-Integer
  MOVSX EAX, CL         ; Signed-Integer (mit 00 oder FF erweitert je nach Vorzeichen.)
 
;(Alte Variante)
 
  MOV  AL, CL           ; copy CL INTO AL
  CBW                   ; convert BYTE in AL to WORD in AX
  CWDE                  ; convert WORD in AX to DWORD in EAX
Adress-Berechnungen für Arrays
;Um zB. in Tabellen eine Adresse im Speicher verwalten zu können, gibt es spezielle Adressierungs-Funktionen
 
  MOV EAX, [ BasisAddresse + Index * Skalierung + Offset ]  ; ([ BaseAddress + Index * Scale + Displacement ])
 
  MOV EAX, [EBX + ECX * 4 + 8]


WertBeschreibung
BasisAddresseZeiger auf erstes Feld im Array
IndexIndex-Positon im Array
SkalierungGröße der Felder im Array in Byte
OffsetOffsetVerschiebung zur BasisAddresse


  MOV AL, [EBX+ECX]        ; Für ein Byte-Array ohne Offset
 
  MOV EAX, [EBX+ECX*4]     ; Für ein Long-Array ohne Offset
 
 
;Für Lokale Arrays die als Parameter übergeben werden
    MOV EAX, [EBP-(displacement)]
 
;Diese Schreibweise ist erlaubt
    MOV EAX, Arr1[ECX*4]   ;=[EBP-(displacement)+ECX*4]

Signed und Unsigned

Signed bedeutet das die Zahl ein Negativ-Zeichen enthalten kann, dafür wird das letze Bit der Zahl verwendet, das anzeigt ob die Zahl positiv oder 0 ist (=0) oder negativ (=1). Dem Zahlenwert geht also ein Bit verloren.
Unsigned Werte verwenden alle Bits für den Zahlenwert und können deshalb nur 0 und Positive Werte abbilden.

Der Prozessor selbst unterscheiden nicht zwischen Signed- und Unsigned-Werten, es werden die gleichen Register verwendet. Für Addition und Subtraktion existieren noch nicht einmal besondere Funktionen, da sie nicht zwangsläufig notwendig sind wie bei Multiplikation und Division. Der Programmierer oder der Compiler ist dafür verantwortlich die Funktionen gemäß der Deklarationen der Variablen korrekt anzuwenden. zB. wird für eine Überlaufsprüfung bei einem Signed-Typ das Overflow-Flag OF geprüft, bei einem Unsigned-Typ das Carry-Flag CF.

Operationsarten, Adressierung

WRITEME

Viele Operationen ermöglichen es nicht nur die Register zu verwenden, sondern auch Daten aus dem Speicher zu holen, und es sind auch Funktionen für Array/String möglich. Ebenso ist es möglich mit einem Register auf eine Speicheradresse zu verweisen. Hier sind nun eine Liste zusammengestellt, auf welche Weise der OpCode in Assembler umgesetzt werden kann. Aus denn Tabellen läßt sich ablesen welche Kombinationen erlaubt sind.
Zu beachtet ins ebenfalls das die Bitlängen nicht gemischt werden dürfen, alle Operatoren müssen die gleiche Bitlängen haben. Falls 16-Bit Daten mit 32-Bit Daten verarbeitet werden sollen, müssen diese erst über Konvertierungs-Funktionen aufeinander angepaßt werden.
Die Beispiele hier sind alle für 32-Bit Funktionen.

Adressioerung

ParameterBeschreibung
reg3232-bit allzweck Register CPU
mem3232-bit Speicher Zeiger
rm32kurz für reg32/mem32
imm3232-bit immediate Konstanten Operand


MOV Beispiel

ASMPar1Par2
Opreg32reg32
Opreg32mem
Opreg32imm
Oprm32imm
Opmemreg32
Opmemimm32


Speicher Adressierung

[Base + Index * Scale + Displacement]


TeileInhalt
BaseEAX, EBX, ECX, EDX, ESP, EBP, ESI, EDI
IndexEAX, EBX, ECX, EDX, EBP, ESI, EDI
Scale1, 2, 4, 8
DisplacementName, Konstante
Beispiele
    MOV   EAX, EBX                  ;Op   reg32, reg32
 
    MOV   EAX, DWord Ptr [Name1]    ;Op   reg32, mem
 
    MOV   EAX, [EBX]                ;Op   reg32, mem
    MOV   EAX, [EBX+ECX]            ;Op   reg32, mem
    MOV   EAX, [EBX+ECX*4]          ;Op   reg32, mem
    MOV   EAX, [EBX+ECX*4+1]        ;Op   reg32, mem
    MOV   EAX, [EBX+1]              ;Op   reg32, mem
    MOV   EAX, [ECX*4+1]            ;Op   reg32, mem
 
    MOV   EAX, -2                   ;Op   reg32, imm
    MOV   EAX, 0xFFFFFFFE           ;Op   reg32, imm
 
 
    MOV   DWord Ptr [Name1], EAX    ;Op   reg32, mem
    ;...

Call Übergabe von Parametern

  PUSH Var2
  PUSH Var1
  CALL Proc1
 
  Proc1:
  MOV EAX, Var1         ; Var1 = [EBP+8]
  RET
 
;Alle Regster und Flags vor einem API-Call sichern (Ist langsam aber in Entwicklungszeit sinnvoll)
 
  PUSHAD                ; Sichert Alle Register (ohne Flags)
    ; Code zum Call
  POPAD
 
  PUSHFD                ; Sichert Alle Register und Flags
    ; Code zum Call
  POPFD
Unterschied zwischen Adresse und Wert

Man kann direkt mit Werten Arbeiten oder mit Werten auf die eine Adress-Zeiger verweist.

WRITEME Dereferenzieren

Daten-Deklaration

Um Explizit anzugeben um welchen Daten-Typ es sich handelt gibt es Schlüsselwörter die Angeben wie Lang das Wort ist.

Byte-LängeKurzLang
1DBByte
2DWWord
4DDDWord
6DFFWord
6DPPWord
8DQQWord
10DTTWord

Struct

WRITEME

    RECT STRUCT
      left    DWORD  ?
      top     DWORD  ?
      right   DWORD  ?
      bottom  DWORD  ?
    RECT ENDS

Schleifen

WRITEME

Anmerkung :
Die Beispiele sind auch für eine aufsteigende Zählschleifen möglich.
In dem Fall wird das Zählregister vorher auf 0 gesetzt, statt dec, inc verwendet und der Schleifenabschluss wie bei der Fußgesteuerten Schleife mit einem vorher festgelegten Register verglichen.

Kopfgesteuerte Schleife
; Hier Anfangwerte für Register 1 und 2 festlegen
 
Schleifenanfang:
CMP Register1,Register2
JNZ Schleifenende          ; Schleife umgehen, falls Register 1 und 2 unterschiedlich sind
 
   ; beliebig viele Anweisungen
   ; sinnvollerweise entweder Register 1 oder 2 auch verändern, sonst droht Endlosschleife
 
JMP Schleifenanfang
Schleifenende:
Fußgesteuerte Schleife
; Hier Anfangwerte für Register 1 und 2 festlegen
 
Schleifenanfang:
 
   ; beliebig viele Anweisungen
   ; sinnvollerweise entweder Register 1 oder 2 auch verändern, sonst droht Endlosschleife
 
CMP Register1,Register2
JNZ Schleifenanfang       ; Schleife wiederholen bis Register 1 = Register 2
Zählschleife
 
; Hier ein Register zum Zählen vergeben
; und auf den gewünschten Maximalwert setzen(wie oft soll die Schleife durchlaufen ?)
 
Schleifenanfang:
 
   ; beliebig viele Anweisungen
   DEC reg_zaehlen ; Anzahl der noch durchzuführenden Durchläufe um 1 verringern
 
JNZ Schleifenanfang       ; Schleife wiederholen bis reg_zaehlen auf 0 gesunken ist

Anmerkung :
Das Ganze ist auch für eine aufsteigende Zählschleife möglich.
In dem Fall wird das Zählregister vorher auf 0 gesetzt, statt dec, inc verwendet
und der Schleifenabschluss wie bei der Fußgesteuerten Schleife mit einem vorher festgelegten
Register verglichen.

Segmente im Speicher

Daten ------------

Daten-Ende --------
Stack-Anfang EBP -----

Stack-Pointer ESP -----

Stack-Ende ----------

Code -----------

Code-Ende -----

WRITEME

Weitergehende Informationen

Exception

Exceptions sind Fehler die der Prozessor erzeugt und die entweder abgefangen werden müssen, oder sogar zu einem Programmhalt führen können. Ein Typischer solcher Fehler ist zB. "Teilung durch 0" die in vielen Programmen auftreten kann wenn ein Wert 0 ist, obwohl dies nicht erwartet wurde.
Durch Fehlerabfang-Routinen können einige Exceptions abgefangen oder ein Programm beendet werden, je nach Compilierung mit Debuger-Informationen die beim Aufspüren des Fehlers helfen können.

Exceptions

Control-Register

WRITEME

Debug-Register

WRITEME


Assembler/Schnell-Kurs.txt · Zuletzt geändert: 2009/05/08 20:14 (Externe Bearbeitung)