← Zurück zum Blog
Code Snippets Low-Level #Fibonacci #NASM #x86

Fibonacci in x86 ASM

A small assembly program that prints the next Fibonacci number after each key press.

Veröffentlicht am 02.02.2026
BITS 64
default rel
global _start

; ------------------------------------------------------------
; Fibonacci sequence
; ENTER shows next number
; 'q' exits the program
; ------------------------------------------------------------

section .text
_start:
    xor     eax, eax            ; RAX = 0
    xor     ebx, ebx            ; RBX = 0
    mov     al, 1               ; Initial value: 1

fiboloop:
    xchg    rax, rbx            ; RAX <-> RBX
    add     rax, rbx            ; RAX = RAX + RBX (next Fibonacci number)
    call    print               ; Print number (decimal, without newline)
    call    input               ; Wait for input
    jmp     fiboloop

; ------------------------------------------------------------
; print
; Expects: RAX = unsigned number (0..2^64-1)
; Effect:  Prints the number in decimal (without newline).
; Clobbers: RAX, RCX, RDX, RSI, RDI, R10, BL
; Preserves: RBX (callee-saved) is preserved
; ------------------------------------------------------------
print:
    push    rax                 ; Save Fibonacci value
    push    rbx                 ; Save RBX (callee-saved)

    mov     r10, rsp            ; Marker: digits will be printed up to this stack state

    ; Special case 0 -> push '0'
    test    rax, rax
    jnz     .gen
    sub     rsp, 1
    mov     byte [rsp], '0'
    jmp     .emit

.gen:
    ; Decompose number into decimal digits (least significant digit first)
    mov     rcx, 10             ; Divisor 10
    mov     rsi, digits         ; RSI = base address of digit table "0123456789"

.l1:
    xor     rdx, rdx            ; RDX=0 because div uses (RDX:RAX)/RCX
                                ; -> we want N/10, so high part must be 0

    div     rcx                 ; UNSIGNED division: (RDX:RAX) / RCX
                                ; After: RAX = quotient q = floor(N/10)
                                ;        RDX = remainder r = N % 10 (0..9)

    mov     bl, [rsi + rdx]     ; r as index into "0123456789": BL = ASCII digit

    sub     rsp, 1              ; reserve 1 byte on the stack
    mov     [rsp], bl           ; push digit on stack (LSD -> MSD)

    test    rax, rax            ; is quotient q == 0?
    jnz     .l1                 ; if q != 0: compute next digit, else finished

.emit:
    ; Digits in correct order: top-of-stack -> write -> pop
.l2:
    mov     eax, 1              ; SYS_write
    mov     edi, 1              ; fd = stdout
    mov     rsi, rsp            ; buf = &digit
    mov     edx, 1              ; len = 1
    syscall

    add     rsp, 1              ; pop printed digit
    cmp     rsp, r10            ; all digits printed?
    jne     .l2

    pop     rbx                 ; restore RBX
    pop     rax                 ; restore original RAX
    ret

; ------------------------------------------------------------
; input
; Effect: Reads 1 byte from stdin into usrinput.
;         If 'q' was read, the program exits.
; Clobbers: RAX, RDI, RSI, RDX
; ------------------------------------------------------------
input:
    push    rax                 ; Save RAX
    push    rbx                 ; Save RBX

    xor     rax, rax            ; RAX = 0  (SYS_read)
    xor     rdi, rdi            ; RDI = 0  (fd = stdin)
    mov     rsi, usrinput       ; RSI = &usrinput
    mov     rdx, 1              ; RDX = 1  (read 1 byte)
    syscall

    movzx   eax, byte [usrinput] ; EAX = read byte (zero-extended)
    xor     al, 'q'              ; AL ^ 'q' == 0 -> 'q' detected
    jz      exit

    pop     rbx                 ; Restore RBX
    pop     rax                 ; Restore RAX
    ret

; ------------------------------------------------------------
; exit
; ------------------------------------------------------------
exit:
    pop     rbx                 ; cleanup
    pop     rax                 ; cleanup
    mov     eax, 60             ; SYS_exit
    xor     edi, edi            ; Exit code 0
    syscall

section .bss
    usrinput  resb 1            ; 1-byte input buffer

section .data
    digits    db "0123456789"   ; Lookup table for digits