diff --git a/lang/src/int_to_str.asm b/lang/src/int_to_str.asm index 1e1f71c..ad86d71 100644 --- a/lang/src/int_to_str.asm +++ b/lang/src/int_to_str.asm @@ -1,5 +1,72 @@ section .text global int_to_str +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) +int_to_str2: + push rbp + mov rbp, rsp + push r12 + push r13 + xor r12, r12 ; r12 = index + mov r13, rdx ; r13 = buffer length + + test r13, r13 + jz .epilogue ; if length is 0, return + + mov rcx, rdi + sar rcx, 63 ; check sign + cmp rcx, 0 + je .convert +.negative: + mov byte [rsi], '-' ; write minus sign + inc r12 + +.convert: + test rdi, rdi + jnz .convert_loop + mov byte [rsi + r12], '0' + jmp .epilogue + +.convert_loop: + cmp r12, r13 + jge .epilogue ; prevent buffer overflow + + mov rax, rdi + xor rdx, rdx + mov rcx, 10 ; base 10 + div rcx ; rax = rdi / 10, rdx = rdi % 10 + add rdx, '0' ; convert digit to ASCII + mov byte [rsi + r12], dl + inc r12 + mov rdi, rax + test rdi, rdi + jnz .convert_loop + + ; Reverse the digits + xor r13, r13 + 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: + pop r13 + pop r12 + pop rbp + ret ;; Converts integer in rcx to string at rdx ;; rcx: input integer diff --git a/lang/tests/int_to_str.rs b/lang/tests/int_to_str.rs new file mode 100644 index 0000000..0183ad0 --- /dev/null +++ b/lang/tests/int_to_str.rs @@ -0,0 +1,34 @@ +#[unsafe(no_mangle)] +extern "C" fn panic() -> ! { + panic!("Called panic from external code."); +} + +#[repr(C)] +struct FFISlice { + ptr: *const u8, + len: usize, +} + +impl FFISlice { + fn as_slice(&self) -> &[u8] { + unsafe { core::slice::from_raw_parts(self.ptr, self.len) } + } + fn as_str(&self) -> &str { + unsafe { core::str::from_utf8_unchecked(self.as_slice()) } + } +} + +unsafe extern "C" { + unsafe fn int_to_str2(value: usize, buffer: *mut u8, buffer_len: usize) -> FFISlice; +} + +fn main() { + let value = 1234567890usize; + let mut buffer = [0u8; 32]; + unsafe { + let slice = int_to_str2(value, buffer.as_mut_ptr(), buffer.len()); + let s = slice.as_str(); + println!("Integer: {}, String: {}", value, s); + assert_eq!(s, value.to_string()); + } +}