221 lines
4.5 KiB
NASM
221 lines
4.5 KiB
NASM
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
|