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).
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.
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
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
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.
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
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:
start: call Fact(10) call [printf](fmt, 10, eax) call FactLoop(5) call [printf](fmt, 5, eax) call [ExitProcess](0)
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 Thumbif, 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.
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
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:
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.
Ordner examples\func: Funktionen, Aufrufe, if und Schleifen für 32-Bit-Windows. Das Ergebnis ist die Ausgabe oder der Exit-Code (echo %errorlevel%).
| Datei | Zeigt | Ergebnis |
|---|---|---|
func_add.asm | Parameter und Stackframe, ohne Abstände zu zählen | Exit-Code 12 |
func_call.asm | call Name(Argumente): der Assembler legt die Argumente ab und räumt auf | Exit-Code 33 |
func_call_locals.asm | Lokale als Argumente: ein Feld, ein Byte, & für eine Adresse | Exit-Code 36 |
func_locals.asm | Lokale Variablen, ein Feld, uses und ein vorzeitiges ret | Exit-Code 39 |
func_cdecl.asm | cdecl-Funktionen: der Aufrufer räumt auf; wsprintfA in einen lokalen Puffer | Meldungsfenster |
func_if.asm | if / else / endif: das Größere von zwei Zahlen | Exit-Code 7 |
func_loop.asm | do … while: Schleifen ohne eigenes Label | Ausgabe |
func_fact.asm | die Fakultät rekursiv und als Schleife (oben) | 10! = 3628800 |
func_printf.asm | printf der C-Laufzeit ist cdecl: .import msvcrt.dll cdecl printf | Ausgabe |
func_console.asm | Text in die Konsole: GetStdHandle, lstrlenA, WriteFile | Ausgabe |
func_file.asm | Dateien: schreiben, lesen, schließen und löschen mit CreateFileA (sieben Argumente) | Exit-Code 11 |
func_computername.asm | der Name dieses Computers: GetComputerNameA(Puffer, &Größe) | Exit-Code = Länge |
func_time.asm | die Ortszeit in einem Meldungsfenster: GetLocalTime, wsprintfA | Meldungsfenster |
func_yesno.asm | MessageBoxA mit Ja / Nein; die Antwort ist der Exit-Code | Exit-Code 6 oder 7 |
| Ordner | Inhalt |
|---|---|
windows_intel | Hello 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_arm | Hello 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 |
dos | Hello World für DOS als .COM und als .EXE, dazu ein fertig gebautes HELLO.EXE zum Untersuchen in Dismonite |
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.
Parameter, Lokale, uses und call Name(...) mit den erzeugten Befehlen.