global _start section .bss NR_INPUT_BUFFER: resb 4 NR_INPUT_BUFFER_SIZE: equ 4 section .data RQ_NR_STR: db 'Please give me a number (0-999): ' RQ_NR_STR_SIZE: equ $ - RQ_NR_STR NR_STR: db '8' NR_STR_SIZE: equ 1 ZERO_ASCII_VALUE: equ 48 NINE_ASCII_VALUE: equ 57 INPUT_BASE: equ 10 STDOUT: equ 1 section .text _start: ; Write to STDOUT mov rax, 1 ; = write mov rdi, STDOUT mov rsi, RQ_NR_STR mov rdx, RQ_NR_STR_SIZE syscall ; Read from STDIN xor rax, rax ; 0 = read xor rdi, rdi ; 0 = stdin mov rsi, NR_INPUT_BUFFER mov rdx, NR_INPUT_BUFFER_SIZE syscall ; Parse number mov rdi, NR_INPUT_BUFFER ; array to loop dec rax mov rsi, rax ; loop limit call parseNR mov rdi, rax call collatz mov rdi, rax exit: mov rax, 60 syscall ; int ParseNumber(char * p, size_t length) ; IN ; - rdi = ptr to byte array ; - rsi = length of said array (greater than 0) ; OUT ; - rax = resulting number => returns 0 if it cannot parse parseNR: xor r8, r8 ; loop variable xor rcx, rcx ; sum .loop_body: mov rax, rcx mov rcx, qword INPUT_BASE mul rcx mov rcx, rax movzx rax, byte [rdi + r8] ; Check if the value is within ASCII numeric bounds cmp al, byte ZERO_ASCII_VALUE jb .exit_failure cmp al, byte NINE_ASCII_VALUE jnb .exit_failure ; Subtract zero to make it a number sub al, byte ZERO_ASCII_VALUE ; Store the sum add rcx, rax inc r8 cmp r8, rsi jb .loop_body ; Return the result mov rax, rcx jmp .exit .exit_failure: xor rax, rax .exit: ret ; int Collatz(int n) ; IN ; - rdi = number to "collatz" ; OUT ; - rax = number of "collatz" iterations it took to reach 0 collatz: xor r9, r9 ; iteration count .loop_start: cmp rdi, qword 1 jbe .loop_exit inc r9 ; Is rdi odd? mov rax, rdi and rax, qword 1 cmp rax, qword 1 je .uneven_routine ;.even_routine: shr rdi, 1 ; divide by two using right shift 1 jmp .loop_start .uneven_routine: mov rax, rdi add rdi, rdi ; rdi + rdi add rdi, rax ; rdi + rdi + rdi = 3 * rdi inc rdi jmp .loop_start .loop_exit: mov rax, r9 ret