convert lib.asm to sysv cc
This commit is contained in:
parent
81417de6ca
commit
208e05b1e6
291
lang/src/lib.asm
291
lang/src/lib.asm
|
|
@ -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
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue