Recursive factorial
Implement factorial(n) recursively with a proper stack frame.
Code
; fact(n) -> n! rdi = n, result in rax
section .text
global fact
fact:
; prologue
push rbp
mov rbp, rsp
push rbx ; save callee-saved rbx (we use it for n)
mov rbx, rdi ; rbx = n
cmp rbx, 1
jle .base ; if n <= 1, return 1
; recursive case: n * fact(n-1)
lea rdi, [rbx - 1] ; arg = n-1
call fact ; rax = fact(n-1)
imul rax, rbx ; rax = n * fact(n-1)
jmp .epi
.base:
mov rax, 1
.epi:
pop rbx ; restore rbx
pop rbp ; restore rbp (epilogue)
ret
; Tail-recursive form compiled to a loop (no stack growth)
global fact_iter
fact_iter:
mov rax, 1 ; accumulator
.loop:
test rdi, rdi
jle .done
imul rax, rdi
dec rdi
jmp .loop
.done:
retExplanation
Each recursive call sets up a full stack frame: push rbp; mov rbp,rsp (frame pointer); push rbx (callee-saved, used to hold n across the recursive call). The base case returns 1; otherwise we recurse with n-1 and multiply the result. The iterative version uses tail-recursion-style accumulation and never grows the stack — preferable for deep recursion. imul is the two-operand signed multiply.
More Assembly Snippets
Hello World via Linux syscall
A freestanding x86-64 program that prints and exits using only kernel syscalls.
Function Call Convention (System V AMD64)
Pass args in registers, preserve callee-saved regs, keep rsp 16-byte aligned.
Loop Summation (1..N)
Sum integers 1..N with a counted loop using dec/jnz.
strlen — Scan Until NUL
Compute C-string length by scanning memory until a zero byte.
memcpy — Copy with rep movsb
Use the rep movsb string instruction for a tight memory copy.
Bit Manipulation: popcount, ctz, abs
Use BMI/ABM instructions for branchless bit operations.