This commit is contained in:
janis 2025-10-20 22:32:24 +02:00
parent e9f634bca5
commit 9a235e625a
Signed by: janis
SSH key fingerprint: SHA256:bB1qbbqmDXZNT0KKD5c2Dfjg53JGhj7B3CFcLIzSqq8
5 changed files with 141 additions and 36 deletions

View file

@ -1,21 +1,45 @@
# Makefile: Compile and link main.asm using nasm and mold, intermediate files in target/
TARGET_DIR := target
SRC := src/main.asm src/lib.asm src/int_to_str.asm
OBJ := $(addprefix $(TARGET_DIR)/, $(notdir $(SRC:.asm=.o)))
SRC := src/lib.asm src/int_to_str.asm src/vec.asm
OBJ := $(patsubst src/%.asm,$(TARGET_DIR)/%.o,$(SRC))
BIN_SRC := src/main.asm
BIN_OBJ := $(patsubst src/%.asm,$(TARGET_DIR)/%.o,$(BIN_SRC))
BIN := $(TARGET_DIR)/main
TEST_SRCS := $(wildcard tests/*.rs)
TEST_BINS := $(patsubst tests/%.rs,$(TARGET_DIR)/tests/%,$(TEST_SRCS))
OBJ_LINK_ARGS := $(foreach o,$(OBJ),-C link-arg=$(o))
.PHONY: all clean
all: $(BIN)
test-bins: $(TEST_BINS)
test: test-bins
@echo "Running all tests.."
@for b in $(TEST_BINS); do \
echo "==> Running $$b"; \
"$$b" || exit $$?; \
done
# pattern rule: compile each .rs into a binary with the same base name
$(TARGET_DIR)/tests/%: tests/%.rs | $(OBJ) $(TARGET_DIR)/tests
@echo "[$(RUSTC)] $< -> $@"
rustc -Clink-arg=-fuse-ld=mold $(OBJ_LINK_ARGS) -g -o $@ $<
$(TARGET_DIR):
mkdir -p $(TARGET_DIR)
mkdir -p $(TARGET_DIR)/tests
$(TARGET_DIR)/tests: $(TARGET_DIR)
mkdir -p $(TARGET_DIR)/tests
$(TARGET_DIR)/%.o: src/%.asm | $(TARGET_DIR)
nasm -f elf64 -g $< -o $@
$(BIN): $(OBJ)
$(BIN): $(OBJ) $(BIN_OBJ)
mold -run ld -o $(BIN) $(OBJ)
run: $(BIN)

View file

@ -1,10 +1,10 @@
default rel
section .rdata
panic_msg db "panic occured!", 10
panic_msg_len equ $ - panic_msg
oom_msg db "panic: oom!", 10
oom_msg_len equ $ - oom_msg
file_error_msg db "Could not open file: "
file_error_msg_len equ $ - file_error_msg
error_msg db "Error: "
error_msg_len equ $ - error_msg
@ -23,6 +23,7 @@ global exit
global error_to_str
global eprint_error
global alloc_pages
global allocate
global is_alpha
global is_numeric
@ -35,8 +36,8 @@ global is_id_start
;; Abort the program with a default panic message
panic:
mov rdi, panic_msg
mov rsi, panic_msg_len
lea rdi, [panic_msg]
lea rsi, [panic_msg_len]
call eprint_str
; exit with error code 1
mov rax, 60 ; syscall: exit
@ -45,8 +46,8 @@ panic:
;; Abort the program with a default panic message
oom:
mov rdi, oom_msg
mov rsi, oom_msg_len
lea rdi, [oom_msg]
lea rsi, [oom_msg_len]
call eprint_str
; exit with error code 1
mov rax, 60 ; syscall: exit
@ -64,9 +65,9 @@ exit:
;; rsi: length of string
eprint_str:
mov rax, 1 ; syscall: write
mov rdi, 2 ; fd: stderr
mov rdx, rsi ; len: length
mov rsi, rdi ; buf: str
mov rdi, 2 ; fd: stderr
syscall
ret
@ -95,7 +96,7 @@ streq:
jne .false
; for i in 0..a.len() {
xor r8, r8
.loop
.loop:
cmp r8, rsi
jge .true
; if a[i] != b[i] {
@ -136,10 +137,10 @@ strcmp:
.loop:
cmp r8, rax
jge .length_check
mov r9l, [rdi + r8]
mov r10l, [rdx + r8]
mov r9b, [rdi + r8]
mov r10b, [rdx + r8]
; if a[i] < b[i] {
cmp r9l, r10l
cmp r9b, r10b
; return Ordering::Less;
jb .less
; } else if a[i] > b[i] {
@ -299,8 +300,8 @@ eprint_error:
; let err_code = err_code;
push rdi
; eprint_str(ERROR_STR, ERROR_STR.len());
mov rdi, error_msg
mov rsi, error_msg_len
lea rdi, [error_msg]
lea rsi, [error_msg_len]
call eprint_str
; let (err, len) = error_to_str(err_code);
pop rdi

View file

@ -12,21 +12,35 @@ extern exit
extern error_to_str
extern eprint_error
extern alloc_pages
extern allocate
extern is_alpha
extern is_numeric
extern is_id_continue
extern is_id_start
extern vec_tests
section .data
hello_msg db "Hello, World!", 10
hello_msg_len equ $ - hello_msg
file_error_msg db "Could not open file: "
file_error_msg_len equ $ - file_error_msg
test_success db "All tests passed!", 10
test_success_len equ $ - test_success
section .text
global _start
_start:
mov rdi, test_success
mov rsi, test_success_len
call eprint_str
mov rdi, 0
call exit
compiler_entry:
; get filename from argv[1]
; argv is at rsp + 8
; check if argc > 1
@ -158,9 +172,7 @@ tokeniser_init:
; allocate buffer
mov rcx, r15
add rcx, 4095
shr rcx, 12 ; divide by 4096
call alloc_pages
call allocate
mov [buffer], rax
mov [buffer_len], r15

View file

@ -17,6 +17,8 @@ global vec_remove
global vec_get
global vec_drop
global vec_tests
;; Byte vector structure
;; struct Vec {
@ -50,7 +52,8 @@ vec_init:
mov qword [r15 + 24], rsi ; item_size
; (*vec).capacity = INIT_CAPACITY / item_size;
mov rax, INIT_CAPACITY
idiv rax, rsi
xor rdx, rdx
div rsi
mov qword [r15 + 16], rax
pop rdx
mov qword [r15 + 32], rdx ; drop
@ -66,7 +69,7 @@ vec_get:
jge .panic
; return &mut vec.data[index * vec.item_size];
mov rax, [rdi + 24] ; item_size
imul rax, rsi ; index * item_size
mul rsi ; index * item_size
mov rsi, [rdi] ; data
add rax, rsi ; data + index * item_size
ret
@ -90,7 +93,6 @@ vec_push:
mov [rsp + 8], rsi ; save data ptr
mov [rsp + 16], rdx ; save data size
; vec_try_grow(vec, size);
mov rsi, [rdi + 24] ; item_size
call vec_try_grow
; memcpy(&vec.data[vec.len], data, size);
mov rax, [rsp] ; vec
@ -101,7 +103,7 @@ vec_push:
call memcpy
; vec.len += 1;
mov rax, [rsp] ; vec
add [rax + 8], 1
add qword [rax + 8], 1
add rsp, 24
ret
.panic:
@ -124,9 +126,9 @@ vec_pop:
test r8, r8
je .ret
; drop(&mut vec.data[vec.len..vec.len + vec.item_size]);
imul rax, [rdi + 24] ; len * item_size
mul qword [rdi + 24] ; len * item_size
mov rsi, [rdi] ; data
add rsi, rax ; data + len * item_size
add rax, rsi ; data + len * item_size
mov rdi, rsi
call r8
.ret:
@ -156,11 +158,12 @@ vec_swap:
jge .panic
; a = a * item_size;
mov rbx, [rdi + 24] ; item_size
imul rdx, rbx ; b * item_size
mov rax, [rdi + 24] ; item_size
mul rbx ; b * item_size
mov [rsp + 16], rax
; b = b * item_size;
imul rsi, rbx ; a * item_size
mov rax, rsi
mul rbx ; a * item_size
mov [rsp + 8], rax
; // SAFETY: a and b must not overlap
@ -168,7 +171,7 @@ vec_swap:
mov rcx, [rdi + 24] ; item_size
lea rdi, [rdi] ; vec.data
mov rsi, rdi
add rdi [rsp + 16] ; data + a
add rdi, [rsp + 16] ; data + a
add rsi, [rsp + 24] ; data + b
call memswap
add rsp, 24
@ -205,22 +208,23 @@ vec_remove:
test r8, r8
je .ret
; drop(&mut vec.data[vec.len..vec.len + vec.item_size]);
imul rax, [rdi + 24] ; len * item_size
mul qword [rdi + 24] ; len * item_size
lea rdi, [rdi] ; data
add rdi, rax ; data + len * item_size
call r8
; }
.ret:
ret
.panic:
call panic
ret
;; rdi: pointer to Vec struct
;; rsi: push size
;; fn vec_try_grow(vec: *mut Vec, push_size: usize) -> bool
vec_try_grow:
push rbx
mov rax, [rdi + 16] ; capacity
mov rbx, [rdi + 8] ; len
add rbx, rsi
cmp rbx, rax
jg .grow
pop rbx
@ -238,7 +242,8 @@ vec_try_grow:
cmp rcx, rbx
cmovl rcx, rbx ; rcx = new_capacity
mov [rsp + 8], rcx
imul rcx, [rdi + 24] ; new_capacity * item_size
mov rax, rcx
mul qword [rdi + 24] ; new_capacity * item_size
; new_data = allocate(new_capacity);
mov rdi, rax
call allocate
@ -246,7 +251,7 @@ vec_try_grow:
mov rdi, [rsp]
; memcpy(new_data, old_data, len * vec.item_size);
mov rax, [rdi + 8] ; len
imul rax, [rdi + 24] ; len * item_size
mul qword [rdi + 24] ; len * item_size
mov rdx, rax ; len
mov rsi, [rdi] ; old_data
mov rdi, [rsp + 16] ; new_data
@ -281,7 +286,8 @@ vec_drop:
jge .ret
mov rdi, [rsp]
; drop(&mut vec.data[i * vec.item_size..(i + 1) * vec.item_size]);
imul r13, [rdi + 24] ; i * item_size
mov rax, r13
mul qword [rdi + 24] ; i * item_size
mov rdi, [rdi] ; data
add rdi, rax
call r12

62
lang/tests/vec.rs Normal file
View file

@ -0,0 +1,62 @@
#[repr(C)]
pub struct BlobVec {
pub data: *mut u8,
pub len: usize,
pub cap: usize,
pub elem_size: usize,
pub drop: Option<extern "C" fn(*mut u8)>,
}
unsafe impl Send for BlobVec {}
unsafe impl Sync for BlobVec {}
unsafe extern "C" {
unsafe fn vec_init(vec: *mut BlobVec, elem_size: usize, drop: Option<extern "C" fn(*mut u8)>);
unsafe fn vec_push(vec: *mut BlobVec, elem: *const u8);
unsafe fn vec_pop(vec: *mut BlobVec);
unsafe fn vec_get(vec: *mut BlobVec, index: usize) -> *mut u8;
unsafe fn vec_remove(vec: *mut BlobVec, index: usize);
unsafe fn vec_drop(vec: *mut BlobVec);
unsafe fn exit(code: i32) -> !;
}
fn main() {
static mut DROPS: usize = 1;
let mut vec = BlobVec {
data: core::ptr::null_mut(),
len: 0,
cap: 0,
elem_size: 1,
drop: None,
};
extern "C" fn drop(ptr: *mut u8) {
unsafe {
DROPS *= ptr.cast::<u32>().read() as usize;
}
}
unsafe {
vec_init(&mut vec, 4, Some(drop));
let mut value: u32 = 2;
assert_eq!(vec.len, 0);
vec_push(&mut vec, &value as *const u32 as *const u8);
assert_eq!(vec.len, 1);
let retrieved = *(vec_get(&mut vec, 0) as *mut u32);
assert_eq!(retrieved, 2);
assert_eq!(DROPS, 1);
vec_pop(&mut vec);
assert_eq!(vec.len, 0);
assert_eq!(DROPS, 2);
value = 3;
vec_push(&mut vec, &value as *const u32 as *const u8);
value = 5;
vec_push(&mut vec, &value as *const u32 as *const u8);
assert_eq!(vec.len, 2);
vec_pop(&mut vec);
vec_pop(&mut vec);
assert_eq!(DROPS, 2 * 3 * 5);
eprintln!("Push/pop test passed\n");
}
}