Direkt mit dem Prozessor sprechen
Ausführen: Datei hallo.asm speichern, mit nasm -f elf64 hallo.asm übersetzen und mit ld hallo.o -o hallo binden, dann ./hallo (Linux, NASM-Syntax).
ld bindet; Programme starten bei _start.data, .bss, .text; Labels, db/dq, equrax, Argumente in rdi, rsi, rdx, dann syscallbefehl ziel, quellenasm -f elf64 hallo.asm -o hallo.o # Assemblieren
ld hallo.o -o hallo # Binden
./hallo # Ausführen
objdump -d -M intel hallo # Maschinencode ansehen (Disassemblieren)
gdb ./hallo # Debuggerrax, rbx, rcx, rdx, rsi, rdi, rsp, rbp, r8 bis r15eax (32 Bit), ax (16), al (8)add, sub, inc, dec, imul, div, neg; Bits: and, or, xor, not, shl, shrdiv nutzt rdx:rax, Quotient in rax, Rest in rdxZF, SF, CF, OF) halten das Ergebnis fest und steuern Sprüngesection .bss
puffer resb 32
section .text
global _start
_start:
mov rax, 40 ; Zahl in ein Register laden
call ausgabe_zahl
mov rax, 5
add rax, 37 ; rax = rax + 37
call ausgabe_zahl
mov rbx, 100
mov rax, rbx ; Register nach Register kopieren
sub rax, 58 ; rax = rax - 58
call ausgabe_zahl
mov rax, 41
inc rax ; +1
call ausgabe_zahl
dec rax ; -1
dec rax
call ausgabe_zahl
mov rax, 5
neg rax ; Vorzeichen umkehren (Zweierkomplement)
neg rax
call ausgabe_zahl
mov rax, 60
xor rdi, rdi
syscall
; --- Hilfsroutine: gibt die Zahl in RAX dezimal aus (mit Zeilenumbruch), alle Register bleiben erhalten ---
ausgabe_zahl:
push rax
push rbx
push rcx
push rdx
push rsi
push rdi
mov rcx, puffer + 20 ; Ende des Puffers
mov byte [rcx], 10 ; Zeilenumbruch ans Ende
mov rbx, 10
.schleife:
xor rdx, rdx
div rbx ; RAX = RAX / 10, RDX = Rest
add dl, '0' ; Ziffer in ASCII umwandeln
dec rcx
mov [rcx], dl
test rax, rax
jnz .schleife
mov rax, 1 ; write
mov rdi, 1
mov rsi, rcx
lea rdx, [puffer + 21]
sub rdx, rcx
syscall
pop rdi
pop rsi
pop rdx
pop rcx
pop rbx
pop rax
retcmp vergleicht, test prüft Bits; danach je/jne/jl/jg/jle/jge (vorzeichenbehaftet), jb/ja (vorzeichenlos)jmp springt immer; Labels markieren Ziele, .name sind lokaldec + jnz (oder loop)if/else und while sind in Assembler nur Sprungmustersection .bss
puffer resb 32
section .text
global _start
_start:
mov rax, 7
cmp rax, 10
jl .kleiner
mov rbx, 0
jmp .weiter
.kleiner:
mov rbx, 1 ; rax ist kleiner als 10
.weiter:
mov rax, rbx
call ausgabe_zahl
; Maximum von zwei Zahlen
mov rax, 15
mov rbx, 42
cmp rax, rbx
jge .rax_ist_max
mov rax, rbx ; rbx ist größer
.rax_ist_max:
call ausgabe_zahl
; Betrag (abs)
mov rax, -17
test rax, rax ; setzt Flags wie "and rax, rax"
jns .positiv
neg rax
.positiv:
call ausgabe_zahl
; gerade oder ungerade?
mov rax, 27
test rax, 1 ; unterstes Bit
jz .gerade
mov rax, 1 ; ungerade
jmp .fertig
.gerade:
mov rax, 0
.fertig:
call ausgabe_zahl
mov rax, 60
xor rdi, rdi
syscall
; --- Hilfsroutine: gibt die Zahl in RAX dezimal aus (mit Zeilenumbruch), alle Register bleiben erhalten ---
ausgabe_zahl:
push rax
push rbx
push rcx
push rdx
push rsi
push rdi
mov rcx, puffer + 20 ; Ende des Puffers
mov byte [rcx], 10 ; Zeilenumbruch ans Ende
mov rbx, 10
.schleife:
xor rdx, rdx
div rbx ; RAX = RAX / 10, RDX = Rest
add dl, '0' ; Ziffer in ASCII umwandeln
dec rcx
mov [rcx], dl
test rax, rax
jnz .schleife
mov rax, 1 ; write
mov rdi, 1
mov rsi, rcx
lea rdx, [puffer + 21]
sub rdx, rcx
syscall
pop rdi
pop rsi
pop rdx
pop rcx
pop rbx
pop rax
ret[adresse] liest/schreibt Speicher, lea berechnet nur Adressen[Basis + Index*Faktor + Verschiebung]db/dw/dd/dq in .data, resb/resq in .bssrep movsb/stosb kopieren und füllen Blöckesection .data
zahl dq 41
liste dq 10, 20, 30, 40, 50
bytes db 1, 2, 3
text db "Assembler", 0
section .bss
puffer resb 32
ergebnis resq 1
section .text
global _start
_start:
mov rax, [zahl] ; Inhalt laden
inc rax
mov [zahl], rax ; zurückschreiben
mov rax, [zahl]
call ausgabe_zahl
mov rax, liste ; Adresse (ohne Klammern)
mov rbx, [rax] ; erstes Element
mov rax, [liste + 8] ; zweites Element (jedes ist 8 Byte)
call ausgabe_zahl
lea rsi, [liste] ; lea berechnet die Adresse, ohne zu lesen
mov rax, [rsi + 2*8] ; drittes Element (Basis + Index*Größe)
call ausgabe_zahl
movzx rax, byte [bytes + 2] ; 1 Byte laden und auf 64 Bit erweitern
call ausgabe_zahl
mov qword [ergebnis], 123
mov rax, [ergebnis]
call ausgabe_zahl
mov rax, text
movzx rax, byte [text] ; erster Buchstabe 'A'
call ausgabe_zahl
mov rax, 60
xor rdi, rdi
syscall
; --- Hilfsroutine: gibt die Zahl in RAX dezimal aus (mit Zeilenumbruch), alle Register bleiben erhalten ---
ausgabe_zahl:
push rax
push rbx
push rcx
push rdx
push rsi
push rdi
mov rcx, puffer + 20 ; Ende des Puffers
mov byte [rcx], 10 ; Zeilenumbruch ans Ende
mov rbx, 10
.schleife:
xor rdx, rdx
div rbx ; RAX = RAX / 10, RDX = Rest
add dl, '0' ; Ziffer in ASCII umwandeln
dec rcx
mov [rcx], dl
test rax, rax
jnz .schleife
mov rax, 1 ; write
mov rdi, 1
mov rsi, rcx
lea rdx, [puffer + 21]
sub rdx, rcx
syscall
pop rdi
pop rsi
pop rdx
pop rcx
pop rbx
pop rax
retpush/pop, rsp; call speichert die Rücksprungadresse, ret kehrt zurückrdi, rsi, rdx, rcx, r8, r9, Ergebnis in raxrbx, rbp, r12-r15; alle anderen dürfen überschrieben werdenpush rbp / mov rbp, rsp / sub rsp, n ... leave / retsection .bss
puffer resb 32
section .text
global _start
_start:
mov rax, 1
mov rbx, 2
mov rcx, 3
push rax
push rbx
push rcx ; Stack: 3 (oben), 2, 1
pop rax ; rax = 3
call ausgabe_zahl
pop rax ; rax = 2
call ausgabe_zahl
pop rax ; rax = 1
call ausgabe_zahl
mov rax, 10
push rax
mov rax, [rsp] ; oberstes Element lesen, ohne zu entfernen
call ausgabe_zahl
add rsp, 8 ; Element verwerfen (wie pop ohne Ziel)
mov rax, rsp
and rax, 0xF
call ausgabe_zahl ; rsp ist beim Start ausgerichtet
mov rax, 60
xor rdi, rdi
syscall
; --- Hilfsroutine: gibt die Zahl in RAX dezimal aus (mit Zeilenumbruch), alle Register bleiben erhalten ---
ausgabe_zahl:
push rax
push rbx
push rcx
push rdx
push rsi
push rdi
mov rcx, puffer + 20 ; Ende des Puffers
mov byte [rcx], 10 ; Zeilenumbruch ans Ende
mov rbx, 10
.schleife:
xor rdx, rdx
div rbx ; RAX = RAX / 10, RDX = Rest
add dl, '0' ; Ziffer in ASCII umwandeln
dec rcx
mov [rcx], dl
test rax, rax
jnz .schleife
mov rax, 1 ; write
mov rdi, 1
mov rsi, rcx
lea rdx, [puffer + 21]
sub rdx, rcx
syscall
pop rdi
pop rsi
pop rdx
pop rcx
pop rbx
pop rax
retread, write, open, close, exitraxargc, argv und die Umgebung auf dem Stackobjdump, gdb, strace, Ghidra, Compiler Explorersection .data
pfad db "/tmp/asm_demo.txt", 0
inhalt db "Hallo aus einer Datei", 10
laenge equ $ - inhalt
section .bss
puffer resb 64
zeile resb 32
section .text
global _start
_start:
; open(pfad, O_WRONLY|O_CREAT|O_TRUNC, 0644)
mov rax, 2
mov rdi, pfad
mov rsi, 0x241
mov rdx, 0644o
syscall
mov r12, rax ; Dateideskriptor merken
; write(fd, inhalt, laenge)
mov rax, 1
mov rdi, r12
mov rsi, inhalt
mov rdx, laenge
syscall
; close(fd)
mov rax, 3
mov rdi, r12
syscall
; open(pfad, O_RDONLY)
mov rax, 2
mov rdi, pfad
xor rsi, rsi
xor rdx, rdx
syscall
mov r12, rax
; read(fd, puffer, 64)
xor rax, rax
mov rdi, r12
mov rsi, puffer
mov rdx, 64
syscall
mov r13, rax ; Anzahl gelesener Bytes
; Ausgabe auf stdout
mov rax, 1
mov rdi, 1
mov rsi, puffer
mov rdx, r13
syscall
; close und unlink (Datei löschen)
mov rax, 3
mov rdi, r12
syscall
mov rax, 87 ; unlink
mov rdi, pfad
syscall
mov rax, 60
xor rdi, rdi
syscalladdsd, mulsd, sqrtsd)cvtsi2sd (int → double), cvttsd2si (double → int)paddd, addps, AVX) bearbeitet mehrere Werte pro Befehlsection .data
a dq 3.5
b dq 2.0
hun dq 100.0
section .bss
puffer resb 32
section .text
global _start
_start:
movsd xmm0, [a]
addsd xmm0, [b] ; 3.5 + 2.0 = 5.5
mulsd xmm0, [hun] ; * 100 = 550
cvttsd2si rax, xmm0
call ausgabe_zahl
movsd xmm0, [a]
mulsd xmm0, xmm0 ; 3.5² = 12.25
mulsd xmm0, [hun]
cvttsd2si rax, xmm0 ; 1225 (zwei Nachkommastellen als Ganzzahl)
call ausgabe_zahl
mov rax, 2
cvtsi2sd xmm1, rax
sqrtsd xmm1, xmm1 ; sqrt(2)
movsd xmm2, [hun]
mulsd xmm2, xmm2 ; 10000
mulsd xmm1, xmm2
cvttsd2si rax, xmm1 ; 14142 → sqrt(2) = 1.4142
call ausgabe_zahl
movsd xmm0, [a]
movsd xmm1, [b]
comisd xmm0, xmm1
ja .groesser
xor rax, rax
jmp .ausgeben
.groesser:
mov rax, 1 ; 3.5 > 2.0
.ausgeben:
call ausgabe_zahl
mov rax, 60
xor rdi, rdi
syscall
; --- Hilfsroutine: gibt die Zahl in RAX dezimal aus (mit Zeilenumbruch), alle Register bleiben erhalten ---
ausgabe_zahl:
push rax
push rbx
push rcx
push rdx
push rsi
push rdi
mov rcx, puffer + 20 ; Ende des Puffers
mov byte [rcx], 10 ; Zeilenumbruch ans Ende
mov rbx, 10
.schleife:
xor rdx, rdx
div rbx ; RAX = RAX / 10, RDX = Rest
add dl, '0' ; Ziffer in ASCII umwandeln
dec rcx
mov [rcx], dl
test rax, rax
jnz .schleife
mov rax, 1 ; write
mov rdi, 1
mov rsi, rcx
lea rdx, [puffer + 21]
sub rdx, rcx
syscall
pop rdi
pop rsi
pop rdx
pop rcx
pop rbx
pop rax
retbefehl ziel, quelle; Systemaufrufe über rax + syscallcmp: vorzeichenbehaftet jl/jg, vorzeichenlos jb/janasm, ld, objdump, gdb, strace, Compiler ExplorerAllgemein: rax rbx rcx rdx rsi rdi rbp rsp r8-r15
32 Bit: eax ebx ecx edx esi edi ebp esp r8d-r15d
16/8 Bit: ax bx cx dx / al bl cl dl (ah bh ch dh)
Sonstige: rip (Befehlszeiger) rflags (Flags) xmm0-xmm15 / ymm0-ymm15
System-V-Argumente: rdi rsi rdx rcx r8 r9 (Rückgabe: rax)
Syscall-Argumente: rax=Nr rdi rsi rdx r10 r8 r9 (Rückgabe: rax)
Callee-saved: rbx rbp r12 r13 r14 r15