section .text global int_to_str global int_to_str2 global str_to_int ;; rdi: pointer to input string ;; rsi: length of input string ;; dl: radix ;; fn str_to_int(s: *const u8, len: usize, radix: u8) -> i64 str_to_int: push rbp mov rbp, rsp push r12 push r13 sub rsp, 0x10 mov qword [rsp], 0 ; result = 0 mov [rsp + 8], dl ; multiplier = radix xor r12, r12 ; r12 = index .loop: cmp r12, rsi jge .epilogue mov rax, [rsp] movzx rcx, byte [rsp + 8] xor rdx, rdx imul rcx jo .overflow ; overflow mov [rsp], rax mov al, byte [rdi + r12] cmp al, '_' je .skip_underscore cmp al, '9' ja .check_alpha cmp al, '0' jb .not_a_digit sub al, '0' jmp .digit_parsed .check_alpha: cmp al, 'a' jb .not_a_digit cmp al, 'f' ja .not_a_digit sub al, 'a' - 10 jmp .digit_parsed .digit_parsed: cmp al, byte [rsp + 8] ja .not_a_digit movzx rax, al add [rsp], rax .skip_underscore: inc r12 jmp .loop .not_a_digit: mov qword [rsp], 0 jmp .epilogue .overflow: mov rax, -1 shr rax, 1 mov qword [rsp], rax .epilogue: mov rax, [rsp] add rsp, 0x10 pop r13 pop r12 pop rbp ret ;; rdi: input integer ;; rsi: pointer to output buffer (at least 21 bytes) ;; rdx: length of buffer ;; cl: radix ;; fn int_to_str2(value: i64, buffer: *mut u8, len: usize, radix: u8) -> (*mut u8, usize) int_to_str2: push rbp mov rbp, rsp push r12 push r13 sub rsp, 0x20 mov [rsp], rdi ; save value mov [rsp + 8], rdx ; save length mov [rsp + 16], rcx ; save radix xor r12, r12 ; r12 = index test rdx, rdx jz .epilogue ; if length is 0, return xor r13, r13 mov rcx, rdi sar rcx, 63 ; check sign cmp rcx, 0 je .convert .negative: mov byte [rsi], '-' ; write minus sign neg rdi inc r13 inc r12 .convert: test rdi, rdi jnz .convert_loop mov byte [rsi + r12], '0' jmp .epilogue .convert_loop: mov rax, [rsp + 8] ; buffer length cmp r12, rax jge .epilogue ; prevent buffer overflow mov rax, rdi xor rdx, rdx mov rcx, [rsp + 16] ; base 10 mov cl, cl div rcx ; rax = rdi / radix, rdx = rdi % radix cmp rdx, 10 jl .decimal add rdx, 'a' - 10 ; convert to 'a'-'f' jmp .phi .decimal: add rdx, '0' ; convert digit to ASCII .phi: mov byte [rsi + r12], dl inc r12 mov rdi, rax test rdi, rdi jnz .convert_loop ; Reverse the digits mov rdx, r12 dec r12 ; last digit index .reverse_loop: cmp r13, r12 jae .done_reverse mov al, [rsi + r13] mov bl, [rsi + r12] mov [rsi + r13], bl mov [rsi + r12], al inc r13 dec r12 jmp .reverse_loop .done_reverse: mov rax, rsi .epilogue: add rsp, 0x20 pop r13 pop r12 pop rbp ret ;; Converts integer in rcx to string at rdx ;; rcx: input integer ;; rdx: pointer to output buffer (at least 21 bytes) int_to_str: mov rbx, rdx ; rbx = buffer pointer mov r8, rbx ; r8 = start of buffer ; Check sign mov rdx, rcx ; copy value sar rdx, 63 ; rdx = 0 if positive, -1 if negative cmp rdx, 0 jne .negative .positive: mov rsi, rcx jmp .convert .negative: mov byte [rbx], '-' ; write minus sign inc rbx neg rcx mov rsi, rcx .convert: ; Count digits mov rax, rsi mov r9, rbx mov r10, 0 ; digit count mov r11, 10 test rax, rax jnz .digits_loop mov byte [rbx], '0' inc rbx mov r10, 1 jmp .done_digits .digits_loop: mov rdx, 0 div r11 ; rax = rax / 10, rdx = rax % 10 add rdx, '0' ; convert digit to ASCII mov byte [rbx + r10], dl inc r10 test rax, rax jnz .digits_loop .done_digits: ; Digits are in reverse order in [rbx..rbx+r10) ; Reverse them mov rsi, 0 mov rdi, rbx mov rdx, r10 dec rdx ; last digit index .reverse_loop: cmp rsi, rdx jae .done_reverse mov al, [rdi + rsi] mov bl, [rdi + rdx] mov [rdi + rsi], bl mov [rdi + rdx], al inc rsi dec rdx jmp .reverse_loop .done_reverse: add rbx, r10 ; move pointer past digits mov byte [rbx], 0 ; null-terminate ret