rewrite int_to_str
This commit is contained in:
parent
6a6af53667
commit
15c2aea16a
|
|
@ -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
|
||||
|
|
|
|||
34
lang/tests/int_to_str.rs
Normal file
34
lang/tests/int_to_str.rs
Normal file
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue