diff --git a/lang/src/int_to_str.asm b/lang/src/int_to_str.asm index ad86d71..a28fe73 100644 --- a/lang/src/int_to_str.asm +++ b/lang/src/int_to_str.asm @@ -5,24 +5,32 @@ global int_to_str2 ;; rdi: input integer ;; rsi: pointer to output buffer (at least 21 bytes) ;; rdx: length of buffer -;; fn int_to_str2(value: i64, buffer: *mut u8, len: usize) -> (*mut u8, usize) +;; 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 - xor r12, r12 ; r12 = index - mov r13, rdx ; r13 = buffer length + sub rsp, 0x20 + mov [rsp], rdi ; save value + mov [rsp + 8], rdx ; save length + mov [rsp + 16], rcx ; save radix - test r13, r13 + 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: @@ -32,14 +40,22 @@ int_to_str2: jmp .epilogue .convert_loop: - cmp r12, r13 + mov rax, [rsp + 8] ; buffer length + cmp r12, rax jge .epilogue ; prevent buffer overflow mov rax, rdi xor rdx, rdx - mov rcx, 10 ; base 10 - div rcx ; rax = rdi / 10, rdx = rdi % 10 + 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 @@ -47,7 +63,6 @@ int_to_str2: jnz .convert_loop ; Reverse the digits - xor r13, r13 mov rdx, r12 dec r12 ; last digit index .reverse_loop: @@ -63,6 +78,7 @@ int_to_str2: .done_reverse: mov rax, rsi .epilogue: + add rsp, 0x20 pop r13 pop r12 pop rbp diff --git a/lang/tests/int_to_str.rs b/lang/tests/int_to_str.rs index 0183ad0..0f3b73d 100644 --- a/lang/tests/int_to_str.rs +++ b/lang/tests/int_to_str.rs @@ -19,16 +19,37 @@ impl FFISlice { } unsafe extern "C" { - unsafe fn int_to_str2(value: usize, buffer: *mut u8, buffer_len: usize) -> FFISlice; + unsafe fn int_to_str2(value: isize, buffer: *mut u8, buffer_len: usize, radix: u8) -> FFISlice; } fn main() { - let value = 1234567890usize; + let value = 1234567890isize; let mut buffer = [0u8; 32]; unsafe { - let slice = int_to_str2(value, buffer.as_mut_ptr(), buffer.len()); + let slice = int_to_str2(value, buffer.as_mut_ptr(), buffer.len(), 10); let s = slice.as_str(); println!("Integer: {}, String: {}", value, s); - assert_eq!(s, value.to_string()); + assert_eq!(s, format!("{value}")); + + let slice = int_to_str2(0 - value, buffer.as_mut_ptr(), buffer.len(), 10); + let s = slice.as_str(); + println!("Integer: {}, String: {}", 0 - value, s); + assert_eq!(s, format!("{}", 0 - value)); + + let slice = int_to_str2(value, buffer.as_mut_ptr(), buffer.len(), 16); + let s = slice.as_str(); + println!("Integer: {:x}, String: {}", value, s); + assert_eq!(s, format!("{value:x}")); + + let slice = int_to_str2(value, buffer.as_mut_ptr(), buffer.len(), 8); + let s = slice.as_str(); + println!("Integer: {:o}, String: {}", value, s); + assert_eq!(s, format!("{value:o}")); + + let value = 235isize; + let slice = int_to_str2(value, buffer.as_mut_ptr(), buffer.len(), 2); + let s = slice.as_str(); + println!("Integer: {:b}, String: {}", value, s); + assert_eq!(s, format!("{value:b}")); } }