strchr, memswap, blob vec
This commit is contained in:
parent
669650ffea
commit
69bd77c8c0
|
|
@ -14,8 +14,10 @@ global oom
|
||||||
global panic
|
global panic
|
||||||
global strlen
|
global strlen
|
||||||
global strcmp
|
global strcmp
|
||||||
|
global strchr
|
||||||
global streq
|
global streq
|
||||||
global memcpy
|
global memcpy
|
||||||
|
global memswap
|
||||||
global eprint_str
|
global eprint_str
|
||||||
global exit
|
global exit
|
||||||
global error_to_str
|
global error_to_str
|
||||||
|
|
@ -33,8 +35,8 @@ global is_id_start
|
||||||
|
|
||||||
;; Abort the program with a default panic message
|
;; Abort the program with a default panic message
|
||||||
panic:
|
panic:
|
||||||
mov rcx, panic_msg
|
mov rdi, panic_msg
|
||||||
mov rdx, panic_msg_len
|
mov rsi, panic_msg_len
|
||||||
call eprint_str
|
call eprint_str
|
||||||
; exit with error code 1
|
; exit with error code 1
|
||||||
mov rax, 60 ; syscall: exit
|
mov rax, 60 ; syscall: exit
|
||||||
|
|
@ -187,6 +189,32 @@ memcpy:
|
||||||
.done:
|
.done:
|
||||||
ret
|
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
|
;; Returns a pointer to the first occurrence of c in s, or null if not found
|
||||||
;; rdi: pointer to byte slice
|
;; rdi: pointer to byte slice
|
||||||
;; rsi: length of byte slice
|
;; rsi: length of byte slice
|
||||||
|
|
@ -223,9 +251,6 @@ strchr:
|
||||||
mov rdx, rsi
|
mov rdx, rsi
|
||||||
sub rdx, r8
|
sub rdx, r8
|
||||||
ret
|
ret
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
section .rdata
|
section .rdata
|
||||||
e_is_dir db "Is a directory", 10
|
e_is_dir db "Is a directory", 10
|
||||||
|
|
@ -286,26 +311,22 @@ eprint_error:
|
||||||
call eprint_str
|
call eprint_str
|
||||||
ret
|
ret
|
||||||
|
|
||||||
|
;; rdi: number of bytes to allocate
|
||||||
;; Allocates n pages of memory
|
;; fn allocate(bytes: usize) -> *mut u8
|
||||||
;; rcx: number of pages
|
allocate:
|
||||||
;; Returns:
|
|
||||||
;; rax: pointer to allocated memory
|
|
||||||
alloc_pages:
|
|
||||||
mov rax, 9 ; syscall: mmap
|
mov rax, 9 ; syscall: mmap
|
||||||
|
mov rsi, rdi ; length: number of bytes
|
||||||
xor rdi, rdi ; addr: NULL
|
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 rdx, 3 ; prot: PROT_READ | PROT_WRITE
|
||||||
mov r10, 34 ; flags: MAP_PRIVATE | MAP_ANONYMOUS
|
mov r10, 34 ; flags: MAP_PRIVATE | MAP_ANONYMOUS
|
||||||
mov r8, -1 ; fd: -1
|
mov r8, -1 ; fd: -1
|
||||||
xor r9, r9 ; offset: 0
|
xor r9, r9 ; offset: 0
|
||||||
syscall
|
syscall
|
||||||
cmp rax, -4095 ; check for error
|
cmp rax, -1 ; check for error
|
||||||
jae .alloc_error
|
jae .alloc_error
|
||||||
ret
|
ret
|
||||||
.alloc_error:
|
.alloc_error:
|
||||||
mov rcx, rax ; error code
|
mov rdi, rax
|
||||||
call eprint_error
|
call eprint_error
|
||||||
call oom
|
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