convert lib.asm to sysv cc

This commit is contained in:
janis 2025-10-20 00:43:03 +02:00
parent 81417de6ca
commit 208e05b1e6
Signed by: janis
SSH key fingerprint: SHA256:bB1qbbqmDXZNT0KKD5c2Dfjg53JGhj7B3CFcLIzSqq8

View file

@ -43,8 +43,8 @@ panic:
;; Abort the program with a default panic message ;; Abort the program with a default panic message
oom: oom:
mov rcx, oom_msg mov rdi, oom_msg
mov rdx, oom_msg_len mov rsi, oom_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
@ -52,28 +52,28 @@ oom:
syscall syscall
;; abort the program ;; abort the program
;; rcx: status code ;; rdi: status code
exit: exit:
mov rax, 60 ; syscall: exit mov rax, 60 ; syscall: exit
mov rdi, rcx
syscall syscall
;; Writes a string to stderr: ;; Writes a string to stderr:
;; rcx: pointer to string ;; rdi: pointer to string
;; rdx: length of string ;; rsi: length of string
eprint_str: eprint_str:
mov rax, 1 ; syscall: write mov rax, 1 ; syscall: write
mov rdi, 2 ; fd: stderr mov rdi, 2 ; fd: stderr
mov rsi, rcx ; buf: str mov rdx, rsi ; len: length
mov rsi, rdi ; buf: str
syscall syscall
ret ret
;; calculates length of null-terminated string ;; calculates length of null-terminated string
;; rcx: pointer to string ;; rdi: pointer to string
strlen: strlen:
xor rax, rax ; length counter xor rax, rax ; length counter
.strlen_loop: .strlen_loop:
cmp byte [rcx + rax], 0 cmp byte [rdi + rax], 0
je .strlen_done je .strlen_done
inc rax inc rax
jmp .strlen_loop jmp .strlen_loop
@ -81,109 +81,110 @@ strlen:
ret ret
;; Checks two byte slices for equality ;; Checks two byte slices for equality
;; rcx: pointer to first slice ;; rdi: pointer to first slice
;; rdx: length of first slice ;; rsi: length of first slice
;; r8: pointer to second slice ;; rdx: pointer to second slice
;; r9: length of second slice ;; rcx: length of second slice
;; returns: 1 if equal, 0 if not equal ;; returns: 1 if equal, 0 if not equal
;; fn streq(a: &[u8], b: &[u8]) -> bool
streq: streq:
cmp rdx, r9 ; if a.len() == b.len() {
jne .not_equal ; lengths differ cmp rsi, rcx
jne .false
xor r10, r10 ; index = 0 ; for i in 0..a.len() {
.loop: xor r8, r8
cmp r10, rdx .loop
jge .equal ; done all bytes cmp r8, rsi
jge .true
mov al, [rcx + r10] ; char from a ; if a[i] != b[i] {
mov bl, [r8 + r10] ; char from b mov al, [rdi + r8]
cmp al, bl mov cl, [rdx + r8]
jne .not_equal ; chars differ cmp al, cl
; return false;
inc r10 jne .false
; }
inc r8
jmp .loop jmp .loop
.equal: ; }
mov rax, 1 ; equal ; return true;
.true:
mov rax, 1
ret ret
.not_equal: ; } else {
xor rax, rax ; not equal ; return false;
.false:
xor rax, rax
ret ret
; }
;; Compares two byte slices ;; Compares two byte slices
;; rcx: pointer to first slice ;; rdi: pointer to first slice
;; rdx: length of first slice ;; rsi: length of first slice
;; r8: pointer to second slice ;; rdx: pointer to second slice
;; r9: length of second slice ;; rcx: length of second slice
; returns: -1, 0, or 1 in rax ;; returns: -1, 0, or 1 in rax
;; fn strcmp(a: &[u8], b: &[u8]) -> Ordering
strcmp: strcmp:
xor rax, rax ; result = 0 (assume equal) ; let min_len = min(a.len(), b.len());
test rdx, rdx mov rax, rsi
jz .check_empty_b ; if len a == 0 cmp rsi, rcx
test r9, r9 cmovg rax, rcx
jz .check_empty_a ; if len b == 0 ; for i in 0..min_len {
xor r8, r8
mov r10, rdx ; min(len a, len b) in r10
cmp r9, rdx
cmovb r10, r9
xor r11, r11 ; index = 0
.loop: .loop:
cmp r11, r10 cmp r8, rax
jge .after_loop ; done min(len a, len b) bytes jge .length_check
mov r9l, [rdi + r8]
mov al, [rcx + r11] ; char from a mov r10l, [rdx + r8]
mov bl, [r8 + r11] ; char from b ; if a[i] < b[i] {
cmp al, bl cmp r9l, r10l
jb .less ; if al < bl: return -1 ; return Ordering::Less;
ja .greater ; if al > bl: return 1 jb .less
; } else if a[i] > b[i] {
inc r11 ; return Ordering::Greater;
ja .greater
; }
inc r8
jmp .loop jmp .loop
; }
.after_loop: ; if a.len() < b.len() {
cmp rdx, r9 .length_check:
je .equal ; lengths equal, strings equal cmp rsi, rcx
jb .less ; a shorter than b ; return Ordering::Less;
ja .greater ; a longer than b jb .less
; } else if a.len() > b.len() {
.equal: ; return Ordering::Greater;
xor rax, rax ; 0 ja .greater
; } else {
; return Ordering::Equal;
xor rax, rax
ret ret
; }
.less: .less:
mov rax, -1 mov rax, -1
ret ret
.greater: .greater:
mov rax, 1 mov rax, 1
ret ret
.check_empty_a:
test rdx, rdx
jz .equal ; both empty
jmp .greater ; a not empty, b empty
.check_empty_b:
test r9, r9
jz .equal ; both empty
jmp .less ; b not empty, a empty
;; Copy bytes from one memory location to another ;; Copy bytes from one memory location to another
;; rcx: destination pointer ;; rdi: destination pointer
;; rdx: source pointer ;; rsi: source pointer
;; r8: number of bytes to copy ;; rdx: number of bytes to copy
;; fn memcpy(dest: *mut u8, src: *const u8, n: usize)
memcpy: memcpy:
xor r10, r10 ; for i in 0..n {
.memcpy_loop_byte: xor r8, r8
cmp r10, r8 .loop:
jge .memcpy_done cmp r8, rdx
mov al, [rdx + r10] jge .done
mov [rcx + r10], al ; dest[i] = src[i];
inc r10 mov al, [rsi + r8]
jmp .memcpy_loop_byte mov [rdi + r8], al
.memcpy_done: inc r8
jmp .loop
; }
.done:
ret ret
section .rdata section .rdata
@ -198,16 +199,16 @@ section .rdata
section .text section .text
;; Converts an error code to a str (pointer, length) pair ;; Converts an error code to a str (pointer, length) pair
;; rcx: error code ;; rdi: error code
;; Returns: ;; Returns:
;; rax: pointer to string ;; rax: pointer to string
;; rdx: length of string ;; rdx: length of string
error_to_str: error_to_str:
cmp rcx, -21 cmp rdi, -21
je .e_is_dir je .e_is_dir
cmp rcx, -5 cmp rdi, -5
je .e_io je .e_io
cmp rcx, -9 cmp rdi, -9
je .e_bad_fd je .e_bad_fd
; unknown error ; unknown error
@ -227,48 +228,25 @@ error_to_str:
mov rdx, e_bad_fd_len mov rdx, e_bad_fd_len
ret ret
;; rcx: error code ;; rdi: error code
;; fn eprint_error(err_code: isize)
eprint_error: eprint_error:
; prologue ; let err_code = err_code;
push rsi push rdi
; eprint_str(ERROR_STR, ERROR_STR.len());
; get error string mov rdi, error_msg
call error_to_str mov rsi, error_msg_len
mov r12, rax ; r12 = pointer to error string call eprint_str
mov r13, rdx ; r13 = length of error string ; let (err, len) = error_to_str(err_code);
mov rsi, r13 pop rdi
add rsi, error_msg_len call error_to_str
add rsi, 1 ; eprint_str(err, len);
add rsi, 15 mov rdi, rax
and rsi, -16 ; align up to 16 mov rsi, rdx
sub rsp, rsi ; allocate buffer
push rsi ; save allocation size
; copy error_msg
lea rcx, [rsp + 8]
mov rdx, error_msg
mov r8, error_msg_len
call memcpy
; copy error string
lea rcx, [rsp + 8 + error_msg_len]
mov rdx, r12
mov r8, r13
call memcpy
; trailing newline
lea rdx, [rsp + 8 + error_msg_len + r13]
mov byte [rdx], 10
; print error message
lea rcx, [rsp + 8]
mov rdx, error_msg_len
add rdx, r13
add rdx, 1 ; include newline
call eprint_str call eprint_str
pop rsi
add rsp, rsi ; dealloc
; epilogue
pop rsi
ret ret
;; Allocates n pages of memory ;; Allocates n pages of memory
;; rcx: number of pages ;; rcx: number of pages
;; Returns: ;; Returns:
@ -292,27 +270,36 @@ alloc_pages:
call oom call oom
;; Returns 1 if cl is an ASCII alphabetic character, 0 otherwise ;; Returns 1 if cl is an ASCII alphabetic character, 0 otherwise
;; cl: byte to check ;; rdi: byte to check
;; fn is_alpha(c: u8) -> bool
is_alpha: is_alpha:
cmp cl, 'A' ; if ('A' <= c
jb .not_alpha cmp dil, 'A'
cmp cl, 'Z' jb .false
jbe .is_alpha_ret ; && c <= 'Z')
cmp cl, 'a' cmp dil, 'Z'
jb .not_alpha jbe .true
cmp cl, 'z' ; || ('a' <= c
jbe .is_alpha_ret cmp dil, 'a'
.is_alpha_ret: jb .false
; && c <= 'z') {
cmp dil, 'z'
jbe .true
; return true;
.true:
mov rax, 1 mov rax, 1
ret ret
.not_alpha: ; } else {
; return false;
.false:
xor rax, rax xor rax, rax
ret ret
;; check if dil is numeric (decimal)
is_numeric: is_numeric:
cmp cl, '0' cmp dil, '0'
jb .not_numeric jb .not_numeric
cmp cl, '9' cmp dil, '9'
jbe .is_numeric_ret jbe .is_numeric_ret
.is_numeric_ret: .is_numeric_ret:
mov rax, 1 mov rax, 1
@ -321,13 +308,13 @@ is_numeric:
xor rax, rax xor rax, rax
ret ret
;; cl: byte to check ;; dil: byte to check
is_id_continue: is_id_continue:
call is_alpha call is_alpha
cmp rax, 1 test rax, rax
je .is_id_continue_ret je .is_id_continue_ret
call is_numeric call is_numeric
cmp rax, 1 test rax, rax
je .is_id_continue_ret je .is_id_continue_ret
cmp cl, '_' cmp cl, '_'
je .is_id_continue_ret je .is_id_continue_ret
@ -337,10 +324,10 @@ is_id_continue:
mov rax, 1 mov rax, 1
ret ret
;; cl: byte to check ;; dil: byte to check
is_id_start: is_id_start:
call is_alpha call is_alpha
cmp rax, 1 test rax, rax
je .is_ret je .is_ret
cmp cl, '_' cmp cl, '_'
je .is_ret je .is_ret