strchr, memswap, blob vec

This commit is contained in:
janis 2025-10-20 16:35:00 +02:00
parent 669650ffea
commit 69bd77c8c0
Signed by: janis
SSH key fingerprint: SHA256:bB1qbbqmDXZNT0KKD5c2Dfjg53JGhj7B3CFcLIzSqq8
2 changed files with 218 additions and 15 deletions

View file

@ -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
@ -224,9 +252,6 @@ strchr:
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
e_is_dir_len equ $ - e_is_dir e_is_dir_len equ $ - e_is_dir
@ -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
View 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