
ASM: Beispiele und Erklärung
Es gibt zwei Arbeitsweisen: #ASM-Blöcke innerhalb von BASIC und eigenständige .asm-Quelldateien. Das erste Beispiel nutzt einen BASIC-Rahmen; die weiteren Beispiele den separaten ASM-Eingang.
Zwölf Kurzbeispiele und ein größeres Programm. Wählen Sie ein Thema oder arbeiten Sie die Beispiele der Reihe nach durch.
1. 1 + 2 + 3 + 4 + 5 = 15
Die Zahlen 1 bis 5 werden zu 15 addiert. Der Rückgabewert 15 wird als Prozess-Exitcode geprüft.
FUNCTION PBMAIN() AS LONG
LOCAL sum AS LONG
#ASM
xor eax, eax ; sum = 0
mov ecx, 5 ; counter = 5
add_loop:
add eax, ecx ; sum += counter
dec ecx ; counter--
jnz add_loop ; loop until 0
mov %sum, eax ; store result
#ENDASM
FUNCTION = sum ' = 15
END FUNCTIONErwarteter Exitcode: 15
PBXB64.exe sum15-asm.pb -O2 -o example.exe .\example.exe $LASTEXITCODE
Nativ geprüft mit dem V22-Kandidaten vom 30.09.2026; Prüfung mit dem finalen Compiler noch ausstehend.
2. Eigenständiges ASM: EAX als Ergebnis
global main markiert den Einstieg. mov eax, 42 setzt das Ergebnisregister; ret kehrt zurück. Das ist eine .asm-Datei und kein eingebetteter #ASM-Block.
// Test: Basic ASM syntax and compilation
section .data
msg db "Test", 0
text section .text
global main
main:
mov eax, 42
retErwarteter Exitcode: 42
PBXB64.exe test_basic_asm.asm -O2 -o example.exe .\example.exe $LASTEXITCODE
Kanonischer Testfall mit erwartetem Ergebnis; hier keine neue native V22-Prüfung. Finale Ausführung noch ausstehend.
3. Einen Wert aus der Datensektion laden
value dd 123 legt einen 32-Bit-Wert an. mov eax, [value] liest diesen Speicherwert, während mov eax, 123 eine unmittelbare Zahl verwenden würde. Der erwartete Exitcode ist 123.
// Test: ASM data sections and global symbols
section .data
value dd 123
msg db "Hello", 0
text section .text
global main
main:
mov eax, [value]
retErwarteter Exitcode: 123
PBXB64.exe test_data_sections.asm -O2 -o example.exe .\example.exe $LASTEXITCODE
Kanonischer Testfall mit erwartetem Ergebnis; hier keine neue native V22-Prüfung. Finale Ausführung noch ausstehend.
4. Makroparameter und Wiederholung beim Assemblieren
Ablauf Schritt für Schritt
- MAGIC ist die Konstante 40; SETEAX setzt eax auf diesen Wert.
- .rep 4 vervielfacht die add-Anweisung bereits beim Assemblieren: eax wird 44.
- Das parametrisierte ADDI32 zieht 2 ab. PROLOG und leave bilden den Rahmen für den Rückgabewert 42.
// Wave-6 slice 6-assembler: macro assembler (.macro/.endm with params,
// .equ equates, .rep/.endr repeat) — asm_macro.c port
// Expected exit code: 42
.equ MAGIC, 40
.macro PROLOG
push rbp
mov rbp, rsp
.endm
.macro SETEAX val
mov eax, \val
.endm
.macro ADDI32 reg, amount
add \reg, \amount
.endm
section .text
global main
main:
PROLOG
SETEAX MAGIC
.rep 4
add eax, 1
.endr
ADDI32 eax, -2
leave
ret
Erwarteter Exitcode: 42
PBXB64.exe asm-w6_macro.asm -O2 -o example.exe .\example.exe $LASTEXITCODE
Ergebnisvertrag aus tests/validate.toml. Keine neue native Compilerprüfung in dieser Website-Erweiterung. Finale Ausführung mit dem freigegebenen Compiler steht aus.
5. Bedingtes Kopieren mit CMOV
Ablauf Schritt für Schritt
- cmp setzt die Flags; cmovl übernimmt 20, weil 10 kleiner als 20 ist.
- Beim anschließenden Gleichvergleich unterbleibt cmovne; cmove liest dagegen den DWORD-Wert 7 aus der Daten-Sektion.
- 7 + 35 ergibt 42. Die CMOV-Bedingung hängt jeweils vom unmittelbar vorherigen Vergleich ab.
// Wave-6 slice 6-assembler: cmovcc + [rel] data access (encoder expansion group)
// Expected exit code: 42
section .data
seven: dd 7
section .text
global main
main:
mov eax, 10
mov ecx, 20
cmp eax, ecx
cmovl eax, ecx ; 10 < 20 -> eax = 20
cmp eax, ecx
cmovne eax, dword [rel seven] ; equal -> no move, eax stays 20
cmp eax, ecx
cmove eax, dword [rel seven] ; equal -> eax = 7
add eax, 35 ; 7 + 35 = 42
ret
Erwarteter Exitcode: 42
PBXB64.exe asm-w6_enc_cmovcc.asm -O2 -o example.exe .\example.exe $LASTEXITCODE
Ergebnisvertrag aus tests/validate.toml. Keine neue native Compilerprüfung in dieser Website-Erweiterung. Finale Ausführung mit dem freigegebenen Compiler steht aus.
6. Zählschleife, Funktionsaufruf und Sprungmarken
Ablauf Schritt für Schritt
- loop verringert den Zähler und führt zehn Erhöhungen von eax aus.
- call add_seven erhöht 10 auf 17; bei rcx = 0 nimmt jrcxz den nächsten Pfad.
- Weitere Additionen von 9 und 16 ergeben 42; falsche Zwischenwerte führen zum Fehlerpfad.
// Wave-6 slice 6-assembler: branch group (loop/loope/loopne, jrcxz/jecxz,
// short jcc, call rel32, jcxz) — encoder expansion group
// Expected exit code: 42
section .text
global main
add_seven:
add eax, 7
ret
main:
xor eax, eax
; loop: count down from 10, eax += 1 each time
mov ecx, 10
count_loop:
add eax, 1
loop count_loop ; 10 iterations -> eax = 10
cmp eax, 10
jne fail
; call rel32 through a local function
call add_seven ; eax = 17
; jrcxz: rcx is 0 here -> taken
jrcxz rcxz_taken
jmp fail
rcxz_taken:
add eax, 9 ; eax = 26
; short forward jump (rel8)
cmp eax, 26
je short_target
jmp fail
short_target:
add eax, 16 ; eax = 42
ret
fail:
mov eax, 1
ret
Erwarteter Exitcode: 42
PBXB64.exe asm-w6_enc_branch.asm -O2 -o example.exe .\example.exe $LASTEXITCODE
Ergebnisvertrag aus tests/validate.toml. Keine neue native Compilerprüfung in dieser Website-Erweiterung. Finale Ausführung mit dem freigegebenen Compiler steht aus.
7. Bytes, String-Endzeichen und UTF-16-Daten
Ablauf Schritt für Schritt
- Die Direktiven legen AB ohne Abschluss sowie HI und YO mit Nullabschluss ab; .unicode erzeugt UTF-16LE-Daten.
- movzx liest einzelne Bytes ohne Vorzeichenerweiterung; die geprüften Nullbytes tragen 0 zur Summe bei.
- 65 + 66 + 77 + 78 ergibt 286. Erst nach diesem Vergleich wird der Erfolgswert 42 zurückgegeben.
// Wave-6 slice 6-assembler: .ascii/.asciz/.string/.unicode directives
// Expected exit code: 42
section .data
a_bytes: .ascii "AB" // 2 bytes, no terminator
z_bytes: .asciz "HI" // 3 bytes incl NUL
s_bytes: .string "YO" // 3 bytes incl NUL
u_bytes: .unicode "MN" // UTF-16LE: 4D 00 4E 00 00 00
section .text
global main
main:
xor ebx, ebx
movzx eax, byte [rel a_bytes] ; 'A' = 65
add ebx, eax
movzx eax, byte [rel a_bytes+1] ; 'B' = 66
add ebx, eax
movzx eax, byte [rel z_bytes+2] ; NUL terminator of .asciz
add ebx, eax ; +0
movzx eax, byte [rel s_bytes+2] ; NUL terminator of .string
add ebx, eax ; +0
movzx eax, byte [rel u_bytes] ; 0x4D = 77 ('M')
add ebx, eax
movzx eax, byte [rel u_bytes+1] ; 0x00 high byte
add ebx, eax ; +0
movzx eax, byte [rel u_bytes+2] ; 0x4E = 78 ('N')
add ebx, eax
movzx eax, byte [rel u_bytes+4] ; NUL16 low byte
add ebx, eax ; +0
; ebx = 65 + 66 + 77 + 78 = 286
cmp ebx, 286
jne fail
mov eax, 42
ret
fail:
mov eax, 1
ret
Erwarteter Exitcode: 42
PBXB64.exe asm-w6_directives.asm -O2 -o example.exe .\example.exe $LASTEXITCODE
Ergebnisvertrag aus tests/validate.toml. Keine neue native Compilerprüfung in dieser Website-Erweiterung. Finale Ausführung mit dem freigegebenen Compiler steht aus.
8. Bitpositionen, Bitanzahl und XADD
Ablauf Schritt für Schritt
- BTS, BT, BTR und BTC setzen, lesen, löschen und invertieren einzelne Bits; BSF/BSR finden die Position 3.
- POPCNT zählt die vier gesetzten Bits von 0xF0; SHRD und SHLD bilden hier jeweils 16.
- XADD macht aus 2 und 3 die Werte 5 und 2. Die folgenden Additionen ergeben 42; dieses Programm setzt eine CPU mit POPCNT voraus.
// Wave-6 slice 6-assembler: bit-manipulation group (bt/bts/btr/btc, bsf/bsr,
// popcnt, shld/shrd, xadd) — encoder expansion group
// Expected exit code: 42
section .text
global main
main:
xor eax, eax
bts rax, 5 ; rax = 32
bt rax, 5 ; CF = 1
setc cl ; cl = 1
btr rax, 5 ; rax = 0, CF = 1
btc rax, 3 ; rax = 8
bsf rdx, rax ; rdx = 3 (index of lowest set bit)
bsr rdx, rax ; rdx = 3 (index of highest set bit)
mov r8, 0xF0
popcnt r9, r8 ; r9 = 4
; shrd dest, src, n: dest = (dest >> n) | (src << (64-n))
mov r10, 0
mov r11, 1
shrd r10, r11, 60 ; r10 = 0 | (1 << 4) = 16
; shld dest, src, n: dest = (dest << n) | (src >> (64-n))
mov r14, 1
xor r15, r15
shld r14, r15, 4 ; r14 = 16 | 0 = 16
cmp r14, 16
jne fail
mov r12, 2
mov r13, 3
xadd r12, r13 ; r12 = 5, r13 = 2
add eax, edx ; 8 + 3 = 11
add eax, r9d ; 15
add eax, r10d ; 31
add eax, r12d ; 36
add eax, r13d ; 38
movzx ecx, cl ; ecx = 1 (from setc cl)
add eax, ecx ; 39
add eax, 3 ; 42
ret
fail:
mov eax, 1
ret
Erwarteter Exitcode: 42
PBXB64.exe asm-w6_enc_bitops.asm -O2 -o example.exe .\example.exe $LASTEXITCODE
Ergebnisvertrag aus tests/validate.toml. Keine neue native Compilerprüfung in dieser Website-Erweiterung. Finale Ausführung mit dem freigegebenen Compiler steht aus.
9. Fünf Argumente nach Win64-Konvention
Ablauf Schritt für Schritt
- INVOKE übergibt die ersten vier Integerargumente über ecx, edx, r8d und r9d.
- Das fünfte Argument wird im aufgerufenen Code an [rsp + 40] geprüft.
- main reserviert 40 Byte und gibt sie nach dem Aufruf wieder frei; check_args liefert 42 bei den erwarteten Werten.
; Help-backed INVOKE contract: Win64 register and stack argument placement.
section .text
global main
check_args:
cmp ecx, 1
jne fail
cmp edx, 2
jne fail
cmp r8d, 3
jne fail
cmp r9d, 4
jne fail
cmp dword [rsp + 40], 5
jne fail
mov eax, 42
ret
fail:
mov eax, 1
ret
main:
sub rsp, 40
invoke check_args, 1, 2, 3, 4, 5
add rsp, 40
ret
Erwarteter Exitcode: 42
PBXB64.exe asm-w7_invoke_abi.asm -O2 -o example.exe .\example.exe $LASTEXITCODE
Ergebnisvertrag aus tests/validate.toml. Keine neue native Compilerprüfung in dieser Website-Erweiterung. Finale Ausführung mit dem freigegebenen Compiler steht aus.
10. GAS-Direktiven mit Intel-Operanden
Ablauf Schritt für Schritt
- .intel_syntax noprefix verbindet Intel-Operanden mit GAS-Direktiven und COFF-Symbolangaben.
- Die vier RIP-relativen Bytezugriffe lesen 65, 66, 77 und 78; die Summe muss 286 sein.
- Ein Semikolon trennt mov eax, 40 und add eax, 2. Der resultierende Exitcode ist 42.
.intel_syntax noprefix
/* Wave-9 GAS Intel-syntax acceptance contract for the runtime .S closure
work: block comments, ';' statement separators, the COFF symbol
definition family, and quoted .section flags. The same file assembles
under host GNU as, so the script lane compares emitted COFF symbol
records against the host reference. Expected exit code: 42. */
.section .rdata,"dr"
table_bytes: .byte 65, 66, 77, 78
.text
.globl main
.def main; .scl 2; .type 32; .endef
main:
xor ebx, ebx
movzx eax, byte ptr [rip+table_bytes]
add ebx, eax
movzx eax, byte ptr [rip+table_bytes+1]
add ebx, eax
movzx eax, byte ptr [rip+table_bytes+2]
add ebx, eax
movzx eax, byte ptr [rip+table_bytes+3]
add ebx, eax
# 65 + 66 + 77 + 78 = 286
cmp ebx, 286
jne fail
mov eax, 40; add eax, 2
ret
fail:
mov eax, 1; ret
Erwarteter Exitcode: 42
PBXB64.exe asm-w9_gas_intel_syntax.asm -O2 -o example.exe .\example.exe $LASTEXITCODE
Ergebnisvertrag aus tests/validate.toml. Keine neue native Compilerprüfung in dieser Website-Erweiterung. Finale Ausführung mit dem freigegebenen Compiler steht aus.
11. Zu einer anderen Stelle derselben Code-Sektion springen
Ablauf Schritt für Schritt
- jmp verweist auf target, obwohl zwischen den beiden Textabschnitten eine Daten-Sektion steht.
- Das Datenbyte gehört zu .data und wird nicht als Code ausgeführt.
- Nach der Rückkehr zu .text setzt target eax auf 48 und beendet das Programm.
.intel_syntax noprefix
/* A branch resumes in .text after intervening .data bytes. The object
builder owns the section-relative fixup. Expected exit code: 48. */
.text
.globl main
main:
jmp target
.data
.byte 1
.text
target:
mov eax, 48
ret
Erwarteter Exitcode: 48
PBXB64.exe asm-w9_interleaved_section_relax.asm -O2 -o example.exe .\example.exe $LASTEXITCODE
Ergebnisvertrag aus tests/validate.toml. Keine neue native Compilerprüfung in dieser Website-Erweiterung. Finale Ausführung mit dem freigegebenen Compiler steht aus.
12. Die Wirkung eines ASM-Blocks beschreiben
Ablauf Schritt für Schritt
- #ASM EFFECTS macht die angegebenen Register-, Flag- und Speicherwirkungen ausdrücklich sichtbar.
- STACK PRESERVE und CONTROL FALLTHROUGH beschreiben den erwarteten Ablauf des Blocks.
- mov rax, rax verändert den Wert nicht. Die Metadaten werden nicht automatisch zum Beweis für beliebig eingesetzten ASM-Code.
' Explicit ASM EFFECTS metadata is opt-in. Ordinary #ASM remains opaque.
FUNCTION PBMAIN() AS LONG
#ASM EFFECTS
READ RAX
WRITE RAX
CLOBBER R10
FLAGS_WRITE ZF, CF
MEMORY READWRITE
STACK PRESERVE
CONTROL FALLTHROUGH
FEATURES SSE2
CODE
mov rax, rax
#ENDASM
FUNCTION = 0
END FUNCTION
Erwarteter Exitcode: 0
PBXB64.exe asm-test_inline_asm_effects.pb -O2 -o example.exe .\example.exe $LASTEXITCODE
Ergebnisvertrag aus tests/validate.toml. Keine neue native Compilerprüfung in dieser Website-Erweiterung. Finale Ausführung mit dem freigegebenen Compiler steht aus.
Großes Beispiel: Zwei ASM-Blöcke mit BASIC-Variablen
Ablauf Schritt für Schritt
- {a}, {b} und {c} binden Speicheroperanden an die Adressen lokaler BASIC-Variablen.
- Der erste Block berechnet 7 + 100 + 5 = 112 in c; der zweite verdoppelt c zu a = 224.
- DWORD-Operationen bearbeiten 32 Bit, QUAD-Zugriffe 64 Bit. Die Werte sind hier positiv und die LONG-Variable war vollständig initialisiert; die BASIC-Prüfung erwartet c = 112, a = 224 und b = 100.
' Wave-1 inline-asm slice: `{ var }` binding plus multi-block temp-name race.
' Two inline asm blocks read and write LOCAL variables via { var }. Each
' bound variable's address is passed in a Win64 argument register (rcx, rdx,
' r8, r9 in order of first appearance within the block) and { var } becomes
' a memory operand on that register. Both blocks are assembled to per-block
' unique temp objects (_inline_asm_0.obj, _inline_asm_1.obj, ...) so neither
' overwrites the other. Expected exit code: 0
FUNCTION PBMAIN() AS LONG
LOCAL a AS LONG
LOCAL b AS QUAD
LOCAL c AS DWORD
a = 7
b = 100
c = 5
' Block 1 (#ASM): c = a + b + c = 7 + 100 + 5 = 112
#ASM
mov eax, {a}
add rax, {b}
add eax, {c}
mov {c}, eax
#ENDASM
' Block 2 (#ASM): a = c * 2 = 224
#ASM
mov eax, {c}
add eax, eax
mov {a}, eax
#ENDASM
IF c = 112 AND a = 224 AND b = 100 THEN
PRINT "inline asm binding OK"
PBMAIN = 0
ELSE
PRINT "inline asm binding FAIL: a="; a; " b="; b; " c="; c
PBMAIN = 1
END IF
END FUNCTION
Erwarteter Exitcode: 0
Kanonisches Ausgabe-Prüfmuster (Regex)
inline asm binding OK
PBXB64.exe asm-test_inline_asm_binding.pb -O2 -o example.exe .\example.exe $LASTEXITCODE
Ergebnisvertrag aus tests/validate.toml. Keine neue native Compilerprüfung in dieser Website-Erweiterung. Finale Ausführung mit dem freigegebenen Compiler steht aus.
Alle Quellen dieser Lernseite
Jedes Beispiel hat einen eigenen Ordner; die README nennt die jeweiligen Compileraufrufe. Enthaltene Includes behalten ihre passenden Pfade.
Alle 13 Beispiele als ZIPBridging
Mit global wird ein Symbol sichtbar; extern bezeichnet ein anderswo definiertes Symbol. Ein gemeinsamer Compileraufruf verbindet ASM und BASIC. Datenbreite und Speicherlayout bleiben Teil des Vertrags.
Vollständige Quellenpaare ansehen