Another day, another low-level challenge. This time we’re implementing the Collatz Conjecture in raw x86-64 NASM optimized with bit tricks and runtime integration. If you’re into bare-metal logic and tight loops, this one’s for you.

The prompt comes from Exercism.com. It’s simple on paper but forces you to reason through real control flow and register juggling.

The Problem: Collatz in Assembly

Rules are simple:

  • Start with a positive integer n
  • If it’s even → n = n / 2
  • If it’s odd → n = 3n + 1
  • Repeat until n == 1
  • Count how many steps that takes

Your job: write this in NASM.


Requirements

What we’re building:

  • Input via argv[]
  • Output via printf
  • Uses atoi to parse string to int

Highlights & Optimizations

Register Discipline

Register Purpose
edi argc
rsi argv pointer
eax return value, intermediate
edx Collatz value
ecx step counter

Fast Math, No Loops Wasted

  • Even check: test dl, 1 → avoids modulo
  • 3n+1: lea edx, [edx + edx*2 + 1] → no imul, no add
  • Divide by 2: shr edx, 1 → no division

The Code

section .data
fmt db "%d", 10, 0
usage db "Usage: ./program <number>", 10, 0

section .text
global main
extern printf
extern atoi

main:
    push rbp
    mov rbp, rsp
    sub rsp, 16

    cmp edi, 2
    jne .usage_error

    mov rdi, [rsi + 8]
    call atoi

    test eax, eax
    jle .input_error

    mov edx, eax
    xor ecx, ecx

.collatz_loop:
    cmp edx, 1
    je .print_result

    test dl, 1
    jz .even_case

    lea edx, [edx + edx*2 + 1]
    jmp .increment_counter

.even_case:
    shr edx, 1

.increment_counter:
    inc ecx
    jmp .collatz_loop

.input_error:
    mov ecx, -1
    jmp .print_result

.usage_error:
    mov rdi, usage
    xor eax, eax
    call printf
    mov eax, 1
    jmp .cleanup

.print_result:
    mov rdi, fmt
    mov esi, ecx
    xor eax, eax
    call printf
    xor eax, eax

.cleanup:
    add rsp, 16
    pop rbp
    ret

%ifidn __OUTPUT_FORMAT__,elf64
section .note.GNU-stack noalloc noexec nowrite progbits
%endif

This is a great warmup for writing tight loops and thinking like a CPU. Props to Exercism for the inspiration.

Next up: maybe we’ll write the inverse. Or optimize it into oblivion.

Until then—keep it minimal, fast, and aligned.