Compare commits
No commits in common. "edc4f4e5767ceb8b91561432e7fcd8da06cdca9d" and "6a6af5366751eee1da80adc4e7f34071396f591b" have entirely different histories.
edc4f4e576
...
6a6af53667
|
|
@ -1,155 +1,5 @@
|
||||||
section .text
|
section .text
|
||||||
global int_to_str
|
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
|
;; Converts integer in rcx to string at rdx
|
||||||
;; rcx: input integer
|
;; rcx: input integer
|
||||||
|
|
|
||||||
|
|
@ -1,80 +0,0 @@
|
||||||
#[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: isize, buffer: *mut u8, buffer_len: usize, radix: u8) -> FFISlice;
|
|
||||||
unsafe fn str_to_int(s: *const u8, len: usize, radix: u8) -> isize;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
let value = 1234567890isize;
|
|
||||||
let mut buffer = [0u8; 32];
|
|
||||||
unsafe {
|
|
||||||
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, 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}"));
|
|
||||||
|
|
||||||
let s = "1234567890";
|
|
||||||
let parsed = str_to_int(s.as_ptr(), s.len(), 10);
|
|
||||||
println!("String: {}, Integer: {}", s, parsed);
|
|
||||||
assert_eq!(parsed, 1234567890isize);
|
|
||||||
|
|
||||||
let s = "499602d2";
|
|
||||||
let parsed = str_to_int(s.as_ptr(), s.len(), 16);
|
|
||||||
println!("String: {}, Integer: {}", s, parsed);
|
|
||||||
assert_eq!(parsed, 1234567890isize);
|
|
||||||
|
|
||||||
let s = "11145401322";
|
|
||||||
let parsed = str_to_int(s.as_ptr(), s.len(), 8);
|
|
||||||
println!("String: {}, Integer: {}", s, parsed);
|
|
||||||
assert_eq!(parsed, 1234567890isize);
|
|
||||||
let s = "11101011";
|
|
||||||
let parsed = str_to_int(s.as_ptr(), s.len(), 2);
|
|
||||||
println!("String: {}, Integer: {}", s, parsed);
|
|
||||||
assert_eq!(parsed, 235isize);
|
|
||||||
|
|
||||||
let s = "9999999999999999999999999999999999999999";
|
|
||||||
let parsed = str_to_int(s.as_ptr(), s.len(), 10);
|
|
||||||
println!("String: {}, Integer: {}", s, parsed);
|
|
||||||
assert_eq!(parsed, isize::MAX);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Loading…
Reference in a new issue