strchr, memswap, blob vec
This commit is contained in:
parent
669650ffea
commit
69bd77c8c0
|
|
@ -14,8 +14,10 @@ global oom
|
|||
global panic
|
||||
global strlen
|
||||
global strcmp
|
||||
global strchr
|
||||
global streq
|
||||
global memcpy
|
||||
global memswap
|
||||
global eprint_str
|
||||
global exit
|
||||
global error_to_str
|
||||
|
|
@ -33,8 +35,8 @@ global is_id_start
|
|||
|
||||
;; Abort the program with a default panic message
|
||||
panic:
|
||||
mov rcx, panic_msg
|
||||
mov rdx, panic_msg_len
|
||||
mov rdi, panic_msg
|
||||
mov rsi, panic_msg_len
|
||||
call eprint_str
|
||||
; exit with error code 1
|
||||
mov rax, 60 ; syscall: exit
|
||||
|
|
@ -187,6 +189,32 @@ memcpy:
|
|||
.done:
|
||||
ret
|
||||
|
||||
|
||||
;; Swap bytes between two memory locations
|
||||
;; rdi: pointer to first memory location
|
||||
;; rsi: pointer to second memory location
|
||||
;; rdx: number of bytes to swap
|
||||
;; fn memswap(a: *mut u8, b: *mut u8, n: usize)
|
||||
memswap:
|
||||
; for i in 0..n {
|
||||
xor r8, r8
|
||||
.loop:
|
||||
cmp r8, rdx
|
||||
jge .done
|
||||
; let temp = a[i];
|
||||
mov al, [rdi + r8]
|
||||
; a[i] = b[i];
|
||||
mov cl, [rsi + r8]
|
||||
mov [rdi + r8], cl
|
||||
; b[i] = temp;
|
||||
mov [rsi + r8], al
|
||||
inc r8
|
||||
jmp .loop
|
||||
; }
|
||||
.done:
|
||||
ret
|
||||
|
||||
|
||||
;; Returns a pointer to the first occurrence of c in s, or null if not found
|
||||
;; rdi: pointer to byte slice
|
||||
;; rsi: length of byte slice
|
||||
|
|
@ -223,9 +251,6 @@ strchr:
|
|||
mov rdx, rsi
|
||||
sub rdx, r8
|
||||
ret
|
||||
|
||||
|
||||
|
||||
|
||||
section .rdata
|
||||
e_is_dir db "Is a directory", 10
|
||||
|
|
@ -286,26 +311,22 @@ eprint_error:
|
|||
call eprint_str
|
||||
ret
|
||||
|
||||
|
||||
;; Allocates n pages of memory
|
||||
;; rcx: number of pages
|
||||
;; Returns:
|
||||
;; rax: pointer to allocated memory
|
||||
alloc_pages:
|
||||
;; rdi: number of bytes to allocate
|
||||
;; fn allocate(bytes: usize) -> *mut u8
|
||||
allocate:
|
||||
mov rax, 9 ; syscall: mmap
|
||||
mov rsi, rdi ; length: number of bytes
|
||||
xor rdi, rdi ; addr: NULL
|
||||
mov rsi, rcx ; length: number of pages
|
||||
shl rsi, 12 ; length in bytes (page size = 4096)
|
||||
mov rdx, 3 ; prot: PROT_READ | PROT_WRITE
|
||||
mov r10, 34 ; flags: MAP_PRIVATE | MAP_ANONYMOUS
|
||||
mov r8, -1 ; fd: -1
|
||||
xor r9, r9 ; offset: 0
|
||||
syscall
|
||||
cmp rax, -4095 ; check for error
|
||||
cmp rax, -1 ; check for error
|
||||
jae .alloc_error
|
||||
ret
|
||||
.alloc_error:
|
||||
mov rcx, rax ; error code
|
||||
mov rdi, rax
|
||||
call eprint_error
|
||||
call oom
|
||||
|
||||
|
|
|
|||
182
lang/src/vec.asm
Normal file
182
lang/src/vec.asm
Normal file
|
|
@ -0,0 +1,182 @@
|
|||
section .rdata
|
||||
INIT_CAPACITY equ 4096
|
||||
|
||||
section .text
|
||||
extern memcpy
|
||||
extern memswap
|
||||
extern oom
|
||||
extern panic
|
||||
extern eprint_str
|
||||
extern allocate
|
||||
|
||||
global vec_init
|
||||
global vec_push
|
||||
global vec_pop
|
||||
global vec_swap
|
||||
global vec_remove
|
||||
global vec_get
|
||||
global vec_free
|
||||
|
||||
|
||||
;; Byte vector structure
|
||||
;; struct Vec {
|
||||
;; data: *mut u8,
|
||||
;; len: usize,
|
||||
;; capacity: usize,
|
||||
;; }
|
||||
|
||||
|
||||
;; Initialize a new vector
|
||||
;; rdi: pointer to Vec struct
|
||||
;; fn vec_init(vec: *mut Vec)
|
||||
vec_init:
|
||||
push rdi
|
||||
; (*vec).data = allocate(INIT_CAPACITY);
|
||||
mov rdi, INIT_CAPACITY
|
||||
call allocate
|
||||
pop r15
|
||||
mov [r15], rax
|
||||
; (*vec).len = 0;
|
||||
mov qword [r15 + 8], 0
|
||||
; (*vec).capacity = INIT_CAPACITY;
|
||||
mov qword [r15 + 16], INIT_CAPACITY
|
||||
ret
|
||||
|
||||
;; rdi: pointer to Vec struct
|
||||
;; rsi: pointer to data to push
|
||||
;; rdx: size of data to push
|
||||
;; fn vec_push(vec: *mut Vec, data: &[u8])
|
||||
vec_push:
|
||||
; let vec, ptr, size;
|
||||
sub rsp, 24
|
||||
mov [rsp], rdi ; save vec
|
||||
mov [rsp + 8], rsi ; save data ptr
|
||||
mov [rsp + 16], rdx ; save data size
|
||||
; vec_try_grow(vec, size);
|
||||
mov rsi, rdx
|
||||
call vec_try_grow
|
||||
; memcpy(&vec.data[vec.len], data, size);
|
||||
mov rax, [rsp] ; vec
|
||||
mov rdi, [rax] ; vec.data
|
||||
add rdi, [rax + 8] ; vec.data + vec.len
|
||||
mov rsi, [rsp + 8] ; data ptr
|
||||
mov rdx, [rsp + 16] ; data size
|
||||
call memcpy
|
||||
; vec.len += size;
|
||||
mov rax, [rsp] ; vec
|
||||
mov rbx, [rsp + 16] ; size
|
||||
add [rax + 8], rbx
|
||||
add rsp, 24
|
||||
ret
|
||||
|
||||
|
||||
;; rdi: pointer to Vec struct
|
||||
;; rsi: size of data to pop
|
||||
;; fn vec_pop(vec: *mut Vec, size: usize)
|
||||
vec_pop:
|
||||
mov rax, [rdi + 8] ; len
|
||||
cmp rax, rsi
|
||||
jl .underflow
|
||||
sub rax, rsi
|
||||
mov [rdi + 8], rax
|
||||
ret
|
||||
.underflow:
|
||||
call panic
|
||||
ret
|
||||
|
||||
|
||||
;; rdi: pointer to Vec struct
|
||||
;; rsi: index a
|
||||
;; rdx: index b
|
||||
;; rcx: step size
|
||||
;; fn vec_swap(vec: *mut Vec, a: usize, b: usize, step: usize)
|
||||
vec_swap:
|
||||
sub rsp, 32
|
||||
mov [rsp], rdi
|
||||
mov [rsp + 8], rcx
|
||||
; let a = a * step;
|
||||
imul rsi, rcx
|
||||
mov [rsp + 16], rax
|
||||
; let b = b * step;
|
||||
imul rdx, rcx
|
||||
mov [rsp + 24], rbx
|
||||
|
||||
; let max_index = max(a, b);
|
||||
mov rbx, rsi
|
||||
cmp rbx, rdx
|
||||
cmovl rbx, rdx
|
||||
; if (max_index >= vec.len) panic();
|
||||
mov rax, [rdi + 8] ; len
|
||||
cmp rbx, rax
|
||||
jge .panic
|
||||
; // a and b must not overlap
|
||||
lea rdi, [rdi] ; vec.data
|
||||
mov rsi, rdi
|
||||
add rdi [rsp + 16] ; data + a
|
||||
add rsi, [rsp + 24] ; data + b
|
||||
mov rcx, [rsp + 8] ; step
|
||||
call memswap
|
||||
add rsp, 32
|
||||
ret
|
||||
|
||||
|
||||
;; rdi: pointer to Vec struct
|
||||
;; rsi: index
|
||||
;; rdx: step size
|
||||
;; fn vec_remove(vec: *mut Vec, index: usize, step: usize)
|
||||
vec_remove:
|
||||
; if (index * step >= vec.len) panic();
|
||||
; if (vec.len - step == index * step {
|
||||
; vec.len -= step;
|
||||
; } else {
|
||||
; vec_swap(vec, index, vec.len / step - 1, step);
|
||||
; }
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
;; rdi: pointer to Vec struct
|
||||
;; rsi: push size
|
||||
;; fn vec_try_grow(vec: *mut Vec, push_size: usize) -> bool
|
||||
vec_try_grow:
|
||||
mov rax, [rdi + 16] ; capacity
|
||||
mov rbx, [rdi + 8] ; len
|
||||
add rbx, rsi
|
||||
cmp rbx, rax
|
||||
jg .grow
|
||||
xor rax, rax
|
||||
ret
|
||||
.grow:
|
||||
; let vec;
|
||||
; let new_capacity;
|
||||
sub rsp, 16
|
||||
mov [rsp], rdi
|
||||
; new_capacity = max(capacity * 2, len + push_size)
|
||||
mov rcx, [rdi + 16] ; capacity
|
||||
shl rcx, 1 ; capacity * 2
|
||||
cmp rcx, rbx
|
||||
cmovl rcx, rbx ; rcx = new_capacity
|
||||
mov [rsp + 8], rcx
|
||||
; new_data = allocate(new_capacity);
|
||||
mov rdi, rcx
|
||||
call allocate
|
||||
mov rdi, [rsp]
|
||||
; memcpy(new_data, old_data, len);
|
||||
mov rbx, [rdi + 8] ; len
|
||||
mov rsi, [rdi] ; old_data
|
||||
mov rdi, rax ; new_data
|
||||
mov rdx, rbx ; len
|
||||
call memcpy
|
||||
; free(old_data) // TODO
|
||||
; update vec
|
||||
mov rdi, [rsp]
|
||||
mov [rdi], rax ; data = new_data
|
||||
mov rcx, [rsp + 8]
|
||||
mov [rdi + 16], rcx ; capacity = new_capacity
|
||||
add rsp, 16
|
||||
xor rax, rax
|
||||
ret
|
||||
|
||||
|
||||
|
||||
Loading…
Reference in a new issue