Beispiele zum Ausprobieren

Laden, mit F9 starten, mit F8 Schritt für Schritt durchgehen.

Im ZIP liegen kleine Programme für Windows (Intel und ARM) und DOS. Auf dieser Seite siehst du sie mit dem Code, den der Assembler daraus macht, und mit dem Ergebnis. Die Dateien sind im Ordner examples des ZIPs; jede lässt sich in Asmonite öffnen und mit F9 im Debugger starten.

Die Beispiele mit func sind für 32-Bit-Windows (.arch i386).

Die Fakultät, rekursiv

n! = n · (n−1)!, und 0! = 1! = 1. Die Funktion ruft sich selbst auf: func macht den Rahmen, if / else den Vergleich und die Sprünge. Datei: examples\func\func_fact.asm.

Du schreibst
func Fact(n) uses ebx
begin
  if unsigned n > 1
    mov ebx, n
    dec ebx
    call Fact(ebx)
    imul eax, n
  else
    mov eax, 1
  endif
end
Der Assembler erzeugt
Fact:
  push ebp
  mov ebp, esp
  push ebx
  cmp dword [ebp+8], 1
  jbe else1
  mov ebx, dword [ebp+8]
  dec ebx
  push ebx
  call Fact
  imul eax, dword [ebp+8]
  jmp end1
else1:
  mov eax, 1
end1:
  pop ebx
  pop ebp
  ret 4
vom Assembler ergänzt (func, if, else, call) deine Zeile, die Namen sind ersetzt unverändert

Drei Dinge sind mit Absicht so geschrieben. Es gibt keine Ausdrücke und keine Aufrufe in Aufrufen: call Fact(n-1) geht nicht, deshalb zählt dec ebx vorher herunter und call Fact(ebx) bekommt das Ergebnis. n bleibt im Rahmen der Funktion stehen, darum rechnet imul eax, n nach dem Aufruf mit dem eigenen n. ebx steht in uses, damit der Aufrufer es unverändert zurückbekommt. Ein Ordnungsvergleich sagt signed oder unsigned.

Dieselbe Rechnung als Schleife

Du schreibst
func FactLoop(n)
begin
  mov ecx, n
  mov eax, 1
  if unsigned ecx > 1
    do
      imul eax, ecx
      dec ecx
    while unsigned ecx > 1
  endif
end
Der Assembler erzeugt
FactLoop:
  push ebp
  mov ebp, esp
  mov ecx, dword [ebp+8]
  mov eax, 1
  cmp ecx, 1
  jbe end1
loop1:
  imul eax, ecx
  dec ecx
  cmp ecx, 1
  ja loop1
end1:
  pop ebp
  ret 4

Der if um die Schleife überspringt sie für 0 und 1; while springt, solange ecx größer als 1 ist, zurück zum do. Der Aufruf im Hauptteil und die Ausgabe:

Hauptteil
start:
  call Fact(10)
  call [printf](fmt, 10, eax)
  call FactLoop(5)
  call [printf](fmt, 5, eax)
  call [ExitProcess](0)
Ausgabe
10! = 3628800
5! = 120

.import msvcrt.dll cdecl printf sagt, dass printf die Argumente nicht selbst vom Stack nimmt; call [printf](...) räumt danach selbst auf. Die Argumente stehen in der Reihenfolge der Funktion: zuerst das Format.

if auf x64, ARM 64 und Thumb

if, else und do … while gibt es auch für .arch x64, .arch arm64 und .arch thumb (func und call Name(args) noch nicht). Du schreibst die Operanden so, wie die Architektur sie kennt; der Assembler macht daraus cmp (oder tst) und den Sprung mit der gegenteiligen Bedingung um den Block.

Du schreibst (ARM 64)
if w1 == 5
  add w0, w0, #1
endif

if signed w1 < 3
  add w0, w0, #100
else
  add w0, w0, #2
endif

if unsigned w2 > w1
  add w0, w0, #4
endif
Der Assembler erzeugt
  cmp w1, #5
  b.ne endif1
  add w0, w0, #1
endif1:
  cmp w1, #3
  b.ge else2
  add w0, w0, #100
  b end2
else2:
  add w0, w0, #2
end2:
  cmp w2, w1
  b.ls endif3
  add w0, w0, #4
endif3:
vom Assembler ergänzt (if, else, endif); die Namen der Labels sind hier vereinfacht unverändert

Ein Wort wie signed oder unsigned sagt, wie verglichen wird (siehe Kurs, Lektion 3); if w3 & w4 ist tst; if zero benutzt die Flags des Befehls davor. Bei ARM gibt es keine Speicheroperanden in if: erst in ein Register laden. Die vollständigen Programme: examples\windows_intel\if_x64.asm, examples\windows_arm\if_arm64.asm und examples\windows_arm\if_arm32.asm. Jedes endet mit dem Exit-Code 31 (= 1 + 2 + 4 + 8 + 16): Jeder Block, der läuft, addiert seine Zahl, so zeigt der Exit-Code, welche Bedingungen wahr waren.

Alle Beispiele

Ordner examples\func: Funktionen, Aufrufe, if und Schleifen für 32-Bit-Windows. Das Ergebnis ist die Ausgabe oder der Exit-Code (echo %errorlevel%).

DateiZeigtErgebnis
func_add.asmParameter und Stackframe, ohne Abstände zu zählenExit-Code 12
func_call.asmcall Name(Argumente): der Assembler legt die Argumente ab und räumt aufExit-Code 33
func_call_locals.asmLokale als Argumente: ein Feld, ein Byte, & für eine AdresseExit-Code 36
func_locals.asmLokale Variablen, ein Feld, uses und ein vorzeitiges retExit-Code 39
func_cdecl.asmcdecl-Funktionen: der Aufrufer räumt auf; wsprintfA in einen lokalen PufferMeldungsfenster
func_if.asmif / else / endif: das Größere von zwei ZahlenExit-Code 7
func_loop.asmdo … while: Schleifen ohne eigenes LabelAusgabe
func_fact.asmdie Fakultät rekursiv und als Schleife (oben)10! = 3628800
func_printf.asmprintf der C-Laufzeit ist cdecl: .import msvcrt.dll cdecl printfAusgabe
func_console.asmText in die Konsole: GetStdHandle, lstrlenA, WriteFileAusgabe
func_file.asmDateien: schreiben, lesen, schließen und löschen mit CreateFileA (sieben Argumente)Exit-Code 11
func_computername.asmder Name dieses Computers: GetComputerNameA(Puffer, &Größe)Exit-Code = Länge
func_time.asmdie Ortszeit in einem Meldungsfenster: GetLocalTime, wsprintfAMeldungsfenster
func_yesno.asmMessageBoxA mit Ja / Nein; die Antwort ist der Exit-CodeExit-Code 6 oder 7

Weitere Ordner

OrdnerInhalt
windows_intelHello World, ein Meldungsfenster und ein Fenster, jeweils für 32 Bit (.arch i386) und 64 Bit (.arch x64); demo.asm zählt von 1 bis 5 und eignet sich zum ersten Schritt durch den Debugger; if_x64.asm zeigt if / else
windows_armHello World und ein Meldungsfenster für Windows on ARM, 32 Bit (Thumb-2) und 64 Bit (ARM64); if_arm32.asm und if_arm64.asm zeigen if / else
dosHello World für DOS als .COM und als .EXE, dazu ein fertig gebautes HELLO.EXE zum Untersuchen in Dismonite

Ausprobieren

In Asmonite eine Datei aus examples öffnen (Strg+O) und F9 drücken: assemblieren und im Debugger starten. F8 geht einen Schritt weiter; bei func, if und call ist eine Zeile deines Textes ein Schritt, nicht die erzeugten Befehle. Ohne die Oberfläche: asmoc func_fact.asm schreibt die .exe neben die Datei.

Weiter

func und call

Parameter, Lokale, uses und call Name(...) mit den erzeugten Befehlen.

Die func-Seite →

if und Schleifen

if, else, do … while mit den Bytes, die daraus werden.

Die if-Seite →

Die Syntax

Zahlen, Ausdrücke, Adressen, Sprünge und Daten mit den Bytes dazu.

Die Syntax-Seite →