diff --git a/a.out b/a.out index 84b793a..9c30d5e 100755 Binary files a/a.out and b/a.out differ diff --git a/a.sl b/a.sl index f18d4fc..7588dc1 100644 --- a/a.sl +++ b/a.sl @@ -1,4 +1,4 @@ -import stdlib.sl +import stdlib/stdlib.sl : main "hello world" puts diff --git a/build/a.asm b/build/a.asm index 12c9dff..bf532f2 100644 --- a/build/a.asm +++ b/build/a.asm @@ -18,6 +18,19 @@ _start: mov rdi, rax mov rax, 60 syscall +word_strlen: + mov rsi, [r12] ; addr + mov rcx, 0 +strlen_loop: + mov al, [rsi + rcx] + cmp al, 0 + je strlen_done + inc rcx + jmp strlen_loop +strlen_done: + mov [r12], rcx ; len + ret + ret word_puts: ; detects string if top is len>=0 and next is a pointer in [data_start, data_end] mov rax, [r12] ; len or int value diff --git a/build/a.o b/build/a.o index 9d06821..6e22e17 100644 Binary files a/build/a.o and b/build/a.o differ diff --git a/build/debug_addresses.asm b/build/debug_addresses.asm new file mode 100644 index 0000000..baf9c7f --- /dev/null +++ b/build/debug_addresses.asm @@ -0,0 +1,521 @@ +section .text +%define DSTK_BYTES 65536 +%define RSTK_BYTES 65536 +%define PRINT_BUF_BYTES 128 +global _start +_start: + ; initialize data/return stack pointers + lea r12, [rel dstack_top] + mov r15, r12 + lea r13, [rel rstack_top] + call word_main + mov rax, 0 + cmp r12, r15 + je .no_exit_value + mov rax, [r12] + add r12, 8 +.no_exit_value: + mov rdi, rax + mov rax, 60 + syscall +word_c_40: + mov rax, [r12] + movzx rax, byte [rax] + mov [r12], rax + ret + ret +word_c_21: + mov rax, [r12] + add r12, 8 + mov rbx, [r12] + mov [rbx], al + ret + ret +word_r_40: + mov rax, [r13] + sub r12, 8 + mov [r12], rax + ret + ret +word_strlen: + mov rax, [r12] ; addr + mov rcx, [r12 + 8] ; len + add r12, 16 ; pop len and addr + mov [r12], rcx ; push len + ret + ret +word_puts: + ; detects string if top is len>=0 and next is a pointer in [data_start, data_end] + mov rax, [r12] ; len or int value + mov rbx, [r12 + 8] ; possible address + cmp rax, 0 + jl puts_print_int + lea r8, [rel data_start] + lea r9, [rel print_buf_end] + cmp rbx, r8 + jl puts_print_int + cmp rbx, r9 + jge puts_print_int + ; treat as string: (addr below len) + mov rdx, rax ; len + mov rsi, rbx ; addr + add r12, 16 ; pop len + addr + test rdx, rdx + jz puts_str_newline_only + mov rax, 1 + mov rdi, 1 + syscall +puts_str_newline_only: + mov byte [rel print_buf], 10 + mov rax, 1 + mov rdi, 1 + lea rsi, [rel print_buf] + mov rdx, 1 + syscall + ret + +puts_print_int: + mov rax, [r12] + add r12, 8 + mov rbx, rax + mov r8, 0 + cmp rbx, 0 + jge puts_abs + neg rbx + mov r8, 1 +puts_abs: + lea rsi, [rel print_buf_end] + mov rcx, 0 + mov r10, 10 + cmp rbx, 0 + jne puts_digits + dec rsi + mov byte [rsi], '0' + inc rcx + jmp puts_sign +puts_digits: +puts_loop: + xor rdx, rdx + mov rax, rbx + div r10 + add dl, '0' + dec rsi + mov [rsi], dl + inc rcx + mov rbx, rax + test rbx, rbx + jne puts_loop +puts_sign: + cmp r8, 0 + je puts_finish_digits + dec rsi + mov byte [rsi], '-' + inc rcx +puts_finish_digits: + mov byte [rsi + rcx], 10 + inc rcx + mov rax, 1 + mov rdi, 1 + mov rdx, rcx + mov r9, rsi + mov rsi, r9 + syscall + ret +word_print_int: + mov rax, [r12] + add r12, 8 + mov rbx, rax + mov r8, 0 + cmp rbx, 0 + jge .print_abs + neg rbx + mov r8, 1 +.print_abs: + lea rsi, [rel print_buf_end] + mov rcx, 0 + mov r10, 10 + cmp rbx, 0 + jne .print_digits + dec rsi + mov byte [rsi], '0' + inc rcx + jmp .print_sign +.print_digits: +.print_loop: + xor rdx, rdx + mov rax, rbx + div r10 + add dl, '0' + dec rsi + mov [rsi], dl + inc rcx + mov rbx, rax + test rbx, rbx + jne .print_loop +.print_sign: + cmp r8, 0 + je .print_finish + dec rsi + mov byte [rsi], '-' + inc rcx +.print_finish: + mov byte [rsi + rcx], 10 + inc rcx + mov rax, 1 + mov rdi, 1 + mov rdx, rcx + mov r9, rsi + mov rsi, r9 + syscall + ret + ret +word_push_data_start: + lea rax, [rel data_start] + sub r12, 8 + mov [r12], rax + ret + ret +word_push_print_buf_addr: + lea rax, [rel print_buf] + sub r12, 8 + mov [r12], rax + ret + ret +word_dup: + mov rax, [r12] + sub r12, 8 + mov [r12], rax + ret +word_write_buf: + mov rdx, [r12] ; len + mov rsi, [r12 + 8] ; addr + add r12, 16 ; pop len + addr + mov rax, 1 ; syscall: write + mov rdi, 1 ; fd = stdout + syscall + ret + ret +word_drop: + add r12, 8 + ret +word_over: + mov rax, [r12 + 8] + sub r12, 8 + mov [r12], rax + ret +word_swap: + mov rax, [r12] + mov rbx, [r12 + 8] + mov [r12], rbx + mov [r12 + 8], rax + ret +word_mkstr: + mov rax, [r12] ; ptr + mov rbx, [r12 + 8] ; len + mov [r12], rbx ; top = len + mov [r12 + 8], rax ; next = ptr + ret + ret +word_mkstr_copy: + mov rdx, [r12] ; len + mov rsi, [r12 + 8] ; addr (source) + add r12, 16 ; pop len+addr + + ; compute cap = PRINT_BUF_BYTES - 1 (leave room for newline or NUL) + lea rdi, [rel print_buf] + mov rcx, 127 ; PRINT_BUF_BYTES-1 (PRINT_BUF_BYTES=128) + cmp rdx, rcx + cmova rdx, rcx ; rdx = min(len, cap) + + ; copy rdx bytes from rsi -> rdi using rep movsb + test rdx, rdx + jz .done_copy + ; save callee-saved r14, use it to hold base dest pointer + push r14 + mov r14, rdi ; r14 = base dest (print_buf) + mov rcx, rdx ; counter = copied length + cld + rep movsb + mov rbx, r14 ; move saved base into rbx for return + pop r14 ; restore original r14 + +.done_copy: + ; push copied length and pointer to print_buf (use saved rbx) + sub r12, 8 + mov [r12], rdx ; len + sub r12, 8 + mov [r12], rbx ; addr -> print_buf base + ret + ret +word_rot: + mov rax, [r12] ; x3 + mov rbx, [r12 + 8] ; x2 + mov rcx, [r12 + 16] ; x1 + mov [r12], rcx ; top = x1 + mov [r12 + 8], rax ; next = x3 + mov [r12 + 16], rbx ; third = x2 + ret +word__2drot: + mov rax, [r12] ; x3 + mov rbx, [r12 + 8] ; x2 + mov rcx, [r12 + 16] ; x1 + mov [r12], rbx ; top = x2 + mov [r12 + 8], rcx ; next = x1 + mov [r12 + 16], rax ; third = x3 + ret +word_nip: + mov rax, [r12] + add r12, 8 ; drop lower element + mov [r12], rax ; keep original top + ret +word_tuck: + mov rax, [r12] ; x2 + mov rbx, [r12 + 8] ; x1 + sub r12, 8 ; make room + mov [r12], rax ; x2 + mov [r12 + 8], rbx ; x1 + mov [r12 + 16], rax ; x2 + ret +word_2dup: + mov rax, [r12] ; b + mov rbx, [r12 + 8] ; a + sub r12, 8 + mov [r12], rbx ; push a + sub r12, 8 + mov [r12], rax ; push b + ret +word_2drop: + add r12, 16 + ret +word_2swap: + mov rax, [r12] ; d + mov rbx, [r12 + 8] ; c + mov rcx, [r12 + 16] ; b + mov rdx, [r12 + 24] ; a + mov [r12], rcx ; top = b + mov [r12 + 8], rdx ; next = a + mov [r12 + 16], rax ; third = d + mov [r12 + 24], rbx ; fourth = c + ret +word_2over: + mov rax, [r12 + 16] ; b + mov rbx, [r12 + 24] ; a + sub r12, 8 + mov [r12], rbx ; push a + sub r12, 8 + mov [r12], rax ; push b + ret +word__2b: + mov rax, [r12] + add r12, 8 + add qword [r12], rax + ret +word__2d: + mov rax, [r12] + add r12, 8 + sub qword [r12], rax + ret +word__2a: + mov rax, [r12] + add r12, 8 + imul qword [r12] + mov [r12], rax + ret +word__2f: + mov rbx, [r12] + add r12, 8 + mov rax, [r12] + cqo + idiv rbx + mov [r12], rax + ret +word__25: + mov rbx, [r12] + add r12, 8 + mov rax, [r12] + cqo + idiv rbx + mov [r12], rdx + ret +word__3d_3d: + mov rax, [r12] + add r12, 8 + mov rbx, [r12] + cmp rbx, rax + mov rbx, 0 + sete bl + mov [r12], rbx + ret +word__21_3d: + mov rax, [r12] + add r12, 8 + mov rbx, [r12] + cmp rbx, rax + mov rbx, 0 + setne bl + mov [r12], rbx + ret +word__3c: + mov rax, [r12] + add r12, 8 + mov rbx, [r12] + cmp rbx, rax + mov rbx, 0 + setl bl + mov [r12], rbx + ret +word__3e: + mov rax, [r12] + add r12, 8 + mov rbx, [r12] + cmp rbx, rax + mov rbx, 0 + setg bl + mov [r12], rbx + ret +word__3c_3d: + mov rax, [r12] + add r12, 8 + mov rbx, [r12] + cmp rbx, rax + mov rbx, 0 + setle bl + mov [r12], rbx + ret +word__3e_3d: + mov rax, [r12] + add r12, 8 + mov rbx, [r12] + cmp rbx, rax + mov rbx, 0 + setge bl + mov [r12], rbx + ret +word__40: + mov rax, [r12] + mov rax, [rax] + mov [r12], rax + ret +word__21: + mov rax, [r12] + add r12, 8 + mov rbx, [r12] + mov [rax], rbx + add r12, 8 + ret +word_mmap: + ; Save rsp and align to 16 bytes for syscall ABI + mov rax, rsp + and rsp, -16 + mov rdi, [r12+40] ; addr + mov rsi, [r12+32] ; length + mov rdx, [r12+24] ; prot + mov r10, [r12+16] ; flags + mov r8, [r12+8] ; fd + mov r9, [r12] ; offset + add r12, 48 ; pop 6 args + mov rax, 9 ; syscall: mmap + syscall + mov rsp, rax ; restore rsp + sub r12, 8 + mov [r12], rax ; push result + ret + ret +word_munmap: + mov rsi, [r12] + add r12, 8 + mov rdi, [r12] + mov rax, 11 + syscall + mov [r12], rax + ret +word_exit: + mov rdi, [r12] + add r12, 8 + mov rax, 60 + syscall + ret +word_and: + mov rax, [r12] + add r12, 8 + mov rbx, [r12] + test rax, rax + setz cl + test rbx, rbx + setz dl + movzx rcx, cl + movzx rdx, dl + and rcx, rdx + mov [r12], rcx + ret +word_or: + mov rax, [r12] + add r12, 8 + mov rbx, [r12] + test rax, rax + setz cl + test rbx, rbx + setz dl + movzx rcx, cl + movzx rdx, dl + or rcx, rdx + mov [r12], rcx + ret +word_not: + mov rax, [r12] + test rax, rax + setz al + movzx rax, al + mov [r12], rax + ret +word__3er: + mov rax, [r12] + add r12, 8 + sub r13, 8 + mov [r13], rax + ret +word_r_3e: + mov rax, [r13] + add r13, 8 + sub r12, 8 + mov [r12], rax + ret +word_rdrop: + add r13, 8 + ret +word_pick: + mov rcx, [r12] + add r12, 8 + mov rax, [r12 + rcx * 8] + sub r12, 8 + mov [r12], rax + ret +word_rpick: + mov rcx, [r12] + add r12, 8 + mov rax, [r13 + rcx * 8] + sub r12, 8 + mov [r12], rax + ret +word_main: + call word_push_print_buf_addr + call word_print_int + call word_push_data_start + call word_print_int + ; push 0 + sub r12, 8 + mov qword [r12], 0 + ret +section .data +data_start: +data_end: +section .bss +align 16 +dstack: resb DSTK_BYTES +dstack_top: +align 16 +rstack: resb RSTK_BYTES +rstack_top: +align 16 +print_buf: resb PRINT_BUF_BYTES +print_buf_end: \ No newline at end of file diff --git a/build/debug_addresses.o b/build/debug_addresses.o new file mode 100644 index 0000000..b9fa930 Binary files /dev/null and b/build/debug_addresses.o differ diff --git a/build/str.asm b/build/str.asm new file mode 100644 index 0000000..aba2433 --- /dev/null +++ b/build/str.asm @@ -0,0 +1,503 @@ +section .text +%define DSTK_BYTES 65536 +%define RSTK_BYTES 65536 +%define PRINT_BUF_BYTES 128 +global _start +_start: + ; initialize data/return stack pointers + lea r12, [rel dstack_top] + mov r15, r12 + lea r13, [rel rstack_top] + call word_main + mov rax, 0 + cmp r12, r15 + je .no_exit_value + mov rax, [r12] + add r12, 8 +.no_exit_value: + mov rdi, rax + mov rax, 60 + syscall +word_c_40: + mov rax, [r12] + movzx rax, byte [rax] + mov [r12], rax + ret + ret +word_c_21: + mov rax, [r12] + add r12, 8 + mov rbx, [r12] + mov [rbx], al + ret + ret +word_r_40: + mov rax, [r13] + sub r12, 8 + mov [r12], rax + ret + ret +word_strlen: + mov rax, [r12] ; addr + mov rcx, [r12 + 8] ; len + add r12, 16 ; pop len and addr + mov [r12], rcx ; push len + ret + ret +word_puts: + ; detects string if top is len>=0 and next is a pointer in [data_start, data_end] + mov rax, [r12] ; len or int value + mov rbx, [r12 + 8] ; possible address + cmp rax, 0 + jl puts_print_int + lea r8, [rel data_start] + lea r9, [rel data_end] + cmp rbx, r8 + jl puts_print_int + cmp rbx, r9 + jge puts_print_int + ; treat as string: (addr below len) + mov rdx, rax ; len + mov rsi, rbx ; addr + add r12, 16 ; pop len + addr + test rdx, rdx + jz puts_str_newline_only + mov rax, 1 + mov rdi, 1 + syscall +puts_str_newline_only: + mov byte [rel print_buf], 10 + mov rax, 1 + mov rdi, 1 + lea rsi, [rel print_buf] + mov rdx, 1 + syscall + ret + +puts_print_int: + mov rax, [r12] + add r12, 8 + mov rbx, rax + mov r8, 0 + cmp rbx, 0 + jge puts_abs + neg rbx + mov r8, 1 +puts_abs: + lea rsi, [rel print_buf_end] + mov rcx, 0 + mov r10, 10 + cmp rbx, 0 + jne puts_digits + dec rsi + mov byte [rsi], '0' + inc rcx + jmp puts_sign +puts_digits: +puts_loop: + xor rdx, rdx + mov rax, rbx + div r10 + add dl, '0' + dec rsi + mov [rsi], dl + inc rcx + mov rbx, rax + test rbx, rbx + jne puts_loop +puts_sign: + cmp r8, 0 + je puts_finish_digits + dec rsi + mov byte [rsi], '-' + inc rcx +puts_finish_digits: + mov byte [rsi + rcx], 10 + inc rcx + mov rax, 1 + mov rdi, 1 + mov rdx, rcx + mov r9, rsi + mov rsi, r9 + syscall + ret +word_dup: + mov rax, [r12] + sub r12, 8 + mov [r12], rax + ret +word_write_buf: + mov rdx, [r12] ; len + mov rsi, [r12 + 8] ; addr + add r12, 16 ; pop len + addr + mov rax, 1 ; syscall: write + mov rdi, 1 ; fd = stdout + syscall + ret + ret +word_drop: + add r12, 8 + ret +word_over: + mov rax, [r12 + 8] + sub r12, 8 + mov [r12], rax + ret +word_swap: + mov rax, [r12] + mov rbx, [r12 + 8] + mov [r12], rbx + mov [r12 + 8], rax + ret +word_rot: + mov rax, [r12] ; x3 + mov rbx, [r12 + 8] ; x2 + mov rcx, [r12 + 16] ; x1 + mov [r12], rcx ; top = x1 + mov [r12 + 8], rax ; next = x3 + mov [r12 + 16], rbx ; third = x2 + ret +word__2drot: + mov rax, [r12] ; x3 + mov rbx, [r12 + 8] ; x2 + mov rcx, [r12 + 16] ; x1 + mov [r12], rbx ; top = x2 + mov [r12 + 8], rcx ; next = x1 + mov [r12 + 16], rax ; third = x3 + ret +word_nip: + mov rax, [r12] + add r12, 8 ; drop lower element + mov [r12], rax ; keep original top + ret +word_tuck: + mov rax, [r12] ; x2 + mov rbx, [r12 + 8] ; x1 + sub r12, 8 ; make room + mov [r12], rax ; x2 + mov [r12 + 8], rbx ; x1 + mov [r12 + 16], rax ; x2 + ret +word_2dup: + mov rax, [r12] ; b + mov rbx, [r12 + 8] ; a + sub r12, 8 + mov [r12], rbx ; push a + sub r12, 8 + mov [r12], rax ; push b + ret +word_2drop: + add r12, 16 + ret +word_2swap: + mov rax, [r12] ; d + mov rbx, [r12 + 8] ; c + mov rcx, [r12 + 16] ; b + mov rdx, [r12 + 24] ; a + mov [r12], rcx ; top = b + mov [r12 + 8], rdx ; next = a + mov [r12 + 16], rax ; third = d + mov [r12 + 24], rbx ; fourth = c + ret +word_2over: + mov rax, [r12 + 16] ; b + mov rbx, [r12 + 24] ; a + sub r12, 8 + mov [r12], rbx ; push a + sub r12, 8 + mov [r12], rax ; push b + ret +word__2b: + mov rax, [r12] + add r12, 8 + add qword [r12], rax + ret +word__2d: + mov rax, [r12] + add r12, 8 + sub qword [r12], rax + ret +word__2a: + mov rax, [r12] + add r12, 8 + imul qword [r12] + mov [r12], rax + ret +word__2f: + mov rbx, [r12] + add r12, 8 + mov rax, [r12] + cqo + idiv rbx + mov [r12], rax + ret +word__25: + mov rbx, [r12] + add r12, 8 + mov rax, [r12] + cqo + idiv rbx + mov [r12], rdx + ret +word__3d_3d: + mov rax, [r12] + add r12, 8 + mov rbx, [r12] + cmp rbx, rax + mov rbx, 0 + sete bl + mov [r12], rbx + ret +word__21_3d: + mov rax, [r12] + add r12, 8 + mov rbx, [r12] + cmp rbx, rax + mov rbx, 0 + setne bl + mov [r12], rbx + ret +word__3c: + mov rax, [r12] + add r12, 8 + mov rbx, [r12] + cmp rbx, rax + mov rbx, 0 + setl bl + mov [r12], rbx + ret +word__3e: + mov rax, [r12] + add r12, 8 + mov rbx, [r12] + cmp rbx, rax + mov rbx, 0 + setg bl + mov [r12], rbx + ret +word__3c_3d: + mov rax, [r12] + add r12, 8 + mov rbx, [r12] + cmp rbx, rax + mov rbx, 0 + setle bl + mov [r12], rbx + ret +word__3e_3d: + mov rax, [r12] + add r12, 8 + mov rbx, [r12] + cmp rbx, rax + mov rbx, 0 + setge bl + mov [r12], rbx + ret +word__40: + mov rax, [r12] + mov rax, [rax] + mov [r12], rax + ret +word__21: + mov rax, [r12] + add r12, 8 + mov rbx, [r12] + mov [rax], rbx + add r12, 8 + ret +word_mmap: + ; Save rsp and align to 16 bytes for syscall ABI + mov rax, rsp + and rsp, -16 + mov rdi, [r12+40] ; addr + mov rsi, [r12+32] ; length + mov rdx, [r12+24] ; prot + mov r10, [r12+16] ; flags + mov r8, [r12+8] ; fd + mov r9, [r12] ; offset + add r12, 48 ; pop 6 args + mov rax, 9 ; syscall: mmap + syscall + mov rsp, rax ; restore rsp + sub r12, 8 + mov [r12], rax ; push result + ret + ret +word_munmap: + mov rsi, [r12] + add r12, 8 + mov rdi, [r12] + mov rax, 11 + syscall + mov [r12], rax + ret +word_exit: + mov rdi, [r12] + add r12, 8 + mov rax, 60 + syscall + ret +word_and: + mov rax, [r12] + add r12, 8 + mov rbx, [r12] + test rax, rax + setz cl + test rbx, rbx + setz dl + movzx rcx, cl + movzx rdx, dl + and rcx, rdx + mov [r12], rcx + ret +word_or: + mov rax, [r12] + add r12, 8 + mov rbx, [r12] + test rax, rax + setz cl + test rbx, rbx + setz dl + movzx rcx, cl + movzx rdx, dl + or rcx, rdx + mov [r12], rcx + ret +word_not: + mov rax, [r12] + test rax, rax + setz al + movzx rax, al + mov [r12], rax + ret +word__3er: + mov rax, [r12] + add r12, 8 + sub r13, 8 + mov [r13], rax + ret +word_r_3e: + mov rax, [r13] + add r13, 8 + sub r12, 8 + mov [r12], rax + ret +word_rdrop: + add r13, 8 + ret +word_pick: + mov rcx, [r12] + add r12, 8 + mov rax, [r12 + rcx * 8] + sub r12, 8 + mov [r12], rax + ret +word_rpick: + mov rcx, [r12] + add r12, 8 + mov rax, [r13 + rcx * 8] + sub r12, 8 + mov [r12], rax + ret +word_read_file: + ; stack: path_ptr (top), path_len (next) + mov rsi, [r12] ; path_ptr + mov rdx, [r12 + 8] ; path_len + add r12, 16 ; pop args + + ; open(path_ptr, O_RDONLY=0, mode=0) + mov rax, 2 ; syscall: open + mov rdi, rsi ; filename + xor rsi, rsi ; flags = O_RDONLY + xor rdx, rdx ; mode = 0 + syscall + mov r10, rax ; save open() result + cmp rax, 0 + jl .fail_open + mov r8, rax ; fd + + ; use lseek to determine file size: lseek(fd, 0, SEEK_END) + mov rax, 8 ; syscall: lseek + mov rdi, r8 ; fd + xor rsi, rsi ; offset = 0 + mov rdx, 2 ; SEEK_END + syscall + mov r11, rax ; save lseek() result + cmp rax, 0 + jl .close_fail_lseek + mov rsi, rax ; length = size + + ; mmap(NULL, size, PROT_READ=1, MAP_PRIVATE=2, fd, 0) + mov rax, 9 ; syscall: mmap + xor rdi, rdi ; addr = NULL + ; rsi already holds length + mov rdx, 1 ; PROT_READ + mov r10, 2 ; MAP_PRIVATE + mov r8, r8 ; fd + xor r9, r9 ; offset = 0 + syscall + mov rbx, rax ; addr + mov r12, r12 ; (no-op, for debug) + mov rax, 3 ; syscall: close + mov rdi, r8 ; fd + syscall + cmp rbx, -4095 + jae .fail_mmap + sub r12, 16 + mov [r12], rsi ; len (rsi held length across syscall) + mov [r12 + 8], rbx ; addr + ret + +.close_fail_lseek: + mov rax, 3 + mov rdi, r8 + syscall + mov rax, r11 ; return lseek() error code + sub r12, 16 + mov [r12], rax + mov qword [r12 + 8], -1 + ret + +.fail_open: + mov rax, r10 ; return open() error code + sub r12, 16 + mov [r12], rax + mov qword [r12 + 8], -2 + ret + +.fail_mmap: + mov rax, -1 ; return mmap() error + sub r12, 16 + mov [r12], rax + mov qword [r12 + 8], -3 + ret + ret +word_main: + ; push str_0 + sub r12, 8 + mov qword [r12], str_0 + ; push 6 + sub r12, 8 + mov qword [r12], 6 + call word_swap + call word_read_file + call word_write_buf + ; push 0 + sub r12, 8 + mov qword [r12], 0 + ret +section .data +data_start: +str_0: db 115, 116, 114, 46, 115, 108, 0 +str_0_len equ 6 +data_end: +section .bss +align 16 +dstack: resb DSTK_BYTES +dstack_top: +align 16 +rstack: resb RSTK_BYTES +rstack_top: +align 16 +print_buf: resb PRINT_BUF_BYTES +print_buf_end: \ No newline at end of file diff --git a/build/str.o b/build/str.o new file mode 100644 index 0000000..5c58829 Binary files /dev/null and b/build/str.o differ diff --git a/build/test_read_file.asm b/build/test_read_file.asm new file mode 100644 index 0000000..7b7ee8c --- /dev/null +++ b/build/test_read_file.asm @@ -0,0 +1,592 @@ +section .text +%define DSTK_BYTES 65536 +%define RSTK_BYTES 65536 +%define PRINT_BUF_BYTES 128 +global _start +_start: + ; initialize data/return stack pointers + lea r12, [rel dstack_top] + mov r15, r12 + lea r13, [rel rstack_top] + call word_main + mov rax, 0 + cmp r12, r15 + je .no_exit_value + mov rax, [r12] + add r12, 8 +.no_exit_value: + mov rdi, rax + mov rax, 60 + syscall +word_c_40: + mov rax, [r12] + movzx rax, byte [rax] + mov [r12], rax + ret + ret +word_c_21: + mov rax, [r12] + add r12, 8 + mov rbx, [r12] + mov [rbx], al + ret + ret +word_r_40: + mov rax, [r13] + sub r12, 8 + mov [r12], rax + ret + ret +word_strlen: + mov rax, [r12] ; addr + mov rcx, [r12 + 8] ; len + add r12, 16 ; pop len and addr + mov [r12], rcx ; push len + ret + ret +word_puts: + ; detects string if top is len>=0 and next is a pointer in [data_start, data_end] + mov rax, [r12] ; len or int value + mov rbx, [r12 + 8] ; possible address + cmp rax, 0 + jl puts_print_int + lea r8, [rel data_start] + lea r9, [rel data_end] + cmp rbx, r8 + jl puts_print_int + cmp rbx, r9 + jge puts_print_int + ; treat as string: (addr below len) + mov rdx, rax ; len + mov rsi, rbx ; addr + add r12, 16 ; pop len + addr + test rdx, rdx + jz puts_str_newline_only + mov rax, 1 + mov rdi, 1 + syscall +puts_str_newline_only: + mov byte [rel print_buf], 10 + mov rax, 1 + mov rdi, 1 + lea rsi, [rel print_buf] + mov rdx, 1 + syscall + ret + +puts_print_int: + mov rax, [r12] + add r12, 8 + mov rbx, rax + mov r8, 0 + cmp rbx, 0 + jge puts_abs + neg rbx + mov r8, 1 +puts_abs: + lea rsi, [rel print_buf_end] + mov rcx, 0 + mov r10, 10 + cmp rbx, 0 + jne puts_digits + dec rsi + mov byte [rsi], '0' + inc rcx + jmp puts_sign +puts_digits: +puts_loop: + xor rdx, rdx + mov rax, rbx + div r10 + add dl, '0' + dec rsi + mov [rsi], dl + inc rcx + mov rbx, rax + test rbx, rbx + jne puts_loop +puts_sign: + cmp r8, 0 + je puts_finish_digits + dec rsi + mov byte [rsi], '-' + inc rcx +puts_finish_digits: + mov byte [rsi + rcx], 10 + inc rcx + mov rax, 1 + mov rdi, 1 + mov rdx, rcx + mov r9, rsi + mov rsi, r9 + syscall + ret +word_dup: + mov rax, [r12] + sub r12, 8 + mov [r12], rax + ret +word_write_buf: + mov rdx, [r12] ; len + mov rsi, [r12 + 8] ; addr + add r12, 16 ; pop len + addr + mov rax, 1 ; syscall: write + mov rdi, 1 ; fd = stdout + syscall + ret + ret +word_drop: + add r12, 8 + ret +word_over: + mov rax, [r12 + 8] + sub r12, 8 + mov [r12], rax + ret +word_swap: + mov rax, [r12] + mov rbx, [r12 + 8] + mov [r12], rbx + mov [r12 + 8], rax + ret +word_rot: + mov rax, [r12] ; x3 + mov rbx, [r12 + 8] ; x2 + mov rcx, [r12 + 16] ; x1 + mov [r12], rcx ; top = x1 + mov [r12 + 8], rax ; next = x3 + mov [r12 + 16], rbx ; third = x2 + ret +word__2drot: + mov rax, [r12] ; x3 + mov rbx, [r12 + 8] ; x2 + mov rcx, [r12 + 16] ; x1 + mov [r12], rbx ; top = x2 + mov [r12 + 8], rcx ; next = x1 + mov [r12 + 16], rax ; third = x3 + ret +word_nip: + mov rax, [r12] + add r12, 8 ; drop lower element + mov [r12], rax ; keep original top + ret +word_tuck: + mov rax, [r12] ; x2 + mov rbx, [r12 + 8] ; x1 + sub r12, 8 ; make room + mov [r12], rax ; x2 + mov [r12 + 8], rbx ; x1 + mov [r12 + 16], rax ; x2 + ret +word_2dup: + mov rax, [r12] ; b + mov rbx, [r12 + 8] ; a + sub r12, 8 + mov [r12], rbx ; push a + sub r12, 8 + mov [r12], rax ; push b + ret +word_2drop: + add r12, 16 + ret +word_2swap: + mov rax, [r12] ; d + mov rbx, [r12 + 8] ; c + mov rcx, [r12 + 16] ; b + mov rdx, [r12 + 24] ; a + mov [r12], rcx ; top = b + mov [r12 + 8], rdx ; next = a + mov [r12 + 16], rax ; third = d + mov [r12 + 24], rbx ; fourth = c + ret +word_2over: + mov rax, [r12 + 16] ; b + mov rbx, [r12 + 24] ; a + sub r12, 8 + mov [r12], rbx ; push a + sub r12, 8 + mov [r12], rax ; push b + ret +word__2b: + mov rax, [r12] + add r12, 8 + add qword [r12], rax + ret +word__2d: + mov rax, [r12] + add r12, 8 + sub qword [r12], rax + ret +word__2a: + mov rax, [r12] + add r12, 8 + imul qword [r12] + mov [r12], rax + ret +word__2f: + mov rbx, [r12] + add r12, 8 + mov rax, [r12] + cqo + idiv rbx + mov [r12], rax + ret +word__25: + mov rbx, [r12] + add r12, 8 + mov rax, [r12] + cqo + idiv rbx + mov [r12], rdx + ret +word__3d_3d: + mov rax, [r12] + add r12, 8 + mov rbx, [r12] + cmp rbx, rax + mov rbx, 0 + sete bl + mov [r12], rbx + ret +word__21_3d: + mov rax, [r12] + add r12, 8 + mov rbx, [r12] + cmp rbx, rax + mov rbx, 0 + setne bl + mov [r12], rbx + ret +word__3c: + mov rax, [r12] + add r12, 8 + mov rbx, [r12] + cmp rbx, rax + mov rbx, 0 + setl bl + mov [r12], rbx + ret +word__3e: + mov rax, [r12] + add r12, 8 + mov rbx, [r12] + cmp rbx, rax + mov rbx, 0 + setg bl + mov [r12], rbx + ret +word__3c_3d: + mov rax, [r12] + add r12, 8 + mov rbx, [r12] + cmp rbx, rax + mov rbx, 0 + setle bl + mov [r12], rbx + ret +word__3e_3d: + mov rax, [r12] + add r12, 8 + mov rbx, [r12] + cmp rbx, rax + mov rbx, 0 + setge bl + mov [r12], rbx + ret +word__40: + mov rax, [r12] + mov rax, [rax] + mov [r12], rax + ret +word__21: + mov rax, [r12] + add r12, 8 + mov rbx, [r12] + mov [rax], rbx + add r12, 8 + ret +word_mmap: + ; Save rsp and align to 16 bytes for syscall ABI + mov rax, rsp + and rsp, -16 + mov rdi, [r12+40] ; addr + mov rsi, [r12+32] ; length + mov rdx, [r12+24] ; prot + mov r10, [r12+16] ; flags + mov r8, [r12+8] ; fd + mov r9, [r12] ; offset + add r12, 48 ; pop 6 args + mov rax, 9 ; syscall: mmap + syscall + mov rsp, rax ; restore rsp + sub r12, 8 + mov [r12], rax ; push result + ret + ret +word_munmap: + mov rsi, [r12] + add r12, 8 + mov rdi, [r12] + mov rax, 11 + syscall + mov [r12], rax + ret +word_exit: + mov rdi, [r12] + add r12, 8 + mov rax, 60 + syscall + ret +word_and: + mov rax, [r12] + add r12, 8 + mov rbx, [r12] + test rax, rax + setz cl + test rbx, rbx + setz dl + movzx rcx, cl + movzx rdx, dl + and rcx, rdx + mov [r12], rcx + ret +word_or: + mov rax, [r12] + add r12, 8 + mov rbx, [r12] + test rax, rax + setz cl + test rbx, rbx + setz dl + movzx rcx, cl + movzx rdx, dl + or rcx, rdx + mov [r12], rcx + ret +word_not: + mov rax, [r12] + test rax, rax + setz al + movzx rax, al + mov [r12], rax + ret +word__3er: + mov rax, [r12] + add r12, 8 + sub r13, 8 + mov [r13], rax + ret +word_r_3e: + mov rax, [r13] + add r13, 8 + sub r12, 8 + mov [r12], rax + ret +word_rdrop: + add r13, 8 + ret +word_pick: + mov rcx, [r12] + add r12, 8 + mov rax, [r12 + rcx * 8] + sub r12, 8 + mov [r12], rax + ret +word_rpick: + mov rcx, [r12] + add r12, 8 + mov rax, [r13 + rcx * 8] + sub r12, 8 + mov [r12], rax + ret +word_read_file: + ; stack: path_ptr (top), path_len (next) + mov rsi, [r12] ; path_ptr + mov rdx, [r12 + 8] ; path_len + add r12, 16 ; pop args + + ; open(path_ptr, O_RDONLY=0, mode=0) + mov rax, 2 ; syscall: open + mov rdi, rsi ; filename + xor rsi, rsi ; flags = O_RDONLY + xor rdx, rdx ; mode = 0 + syscall + mov r10, rax ; save open() result + cmp rax, 0 + jl .fail_open + mov r8, rax ; fd + + ; use lseek to determine file size: lseek(fd, 0, SEEK_END) + mov rax, 8 ; syscall: lseek + mov rdi, r8 ; fd + xor rsi, rsi ; offset = 0 + mov rdx, 2 ; SEEK_END + syscall + mov r11, rax ; save lseek() result + cmp rax, 0 + jl .close_fail_lseek + mov rsi, rax ; length = size + + ; mmap(NULL, size, PROT_READ=1, MAP_PRIVATE=2, fd, 0) + mov rax, 9 ; syscall: mmap + xor rdi, rdi ; addr = NULL + ; rsi already holds length + mov rdx, 1 ; PROT_READ + mov r10, 2 ; MAP_PRIVATE + mov r8, r8 ; fd + xor r9, r9 ; offset = 0 + syscall + mov rbx, rax ; addr + mov r12, r12 ; (no-op, for debug) + mov rax, 3 ; syscall: close + mov rdi, r8 ; fd + syscall + cmp rbx, -4095 + jae .fail_mmap + sub r12, 16 + mov [r12], rsi ; len (rsi held length across syscall) + mov [r12 + 8], rbx ; addr + ret + +.close_fail_lseek: + mov rax, 3 + mov rdi, r8 + syscall + mov rax, r11 ; return lseek() error code + sub r12, 16 + mov [r12], rax + mov qword [r12 + 8], -1 + ret + +.fail_open: + mov rax, r10 ; return open() error code + sub r12, 16 + mov [r12], rax + mov qword [r12 + 8], -2 + ret + +.fail_mmap: + mov rax, -1 ; return mmap() error + sub r12, 16 + mov [r12], rax + mov qword [r12 + 8], -3 + ret + ret +word_main: + ; push str_0 + sub r12, 8 + mov qword [r12], str_0 + ; push 13 + sub r12, 8 + mov qword [r12], 13 + call word_swap + call word_read_file + call word_dup + ; push 0 + sub r12, 8 + mov qword [r12], 0 + call word__3e + mov rax, [r12] + add r12, 8 + test rax, rax + jz L_if_false_0 + call word_write_buf + ; push 0 + sub r12, 8 + mov qword [r12], 0 + call word_exit +L_if_false_0: + call word_dup + ; push -2 + sub r12, 8 + mov qword [r12], -2 + call word__3d_3d + mov rax, [r12] + add r12, 8 + test rax, rax + jz L_if_false_1 + call word_drop + ; push str_1 + sub r12, 8 + mov qword [r12], str_1 + ; push 21 + sub r12, 8 + mov qword [r12], 21 + call word_puts + call word_swap + call word_puts + call word_exit +L_if_false_1: + call word_dup + ; push -1 + sub r12, 8 + mov qword [r12], -1 + call word__3d_3d + mov rax, [r12] + add r12, 8 + test rax, rax + jz L_if_false_2 + call word_drop + ; push str_2 + sub r12, 8 + mov qword [r12], str_2 + ; push 22 + sub r12, 8 + mov qword [r12], 22 + call word_puts + call word_swap + call word_puts + call word_exit +L_if_false_2: + call word_dup + ; push -3 + sub r12, 8 + mov qword [r12], -3 + call word__3d_3d + mov rax, [r12] + add r12, 8 + test rax, rax + jz L_if_false_3 + call word_drop + ; push str_3 + sub r12, 8 + mov qword [r12], str_3 + ; push 13 + sub r12, 8 + mov qword [r12], 13 + call word_puts + call word_exit +L_if_false_3: + ; push str_4 + sub r12, 8 + mov qword [r12], str_4 + ; push 25 + sub r12, 8 + mov qword [r12], 25 + call word_puts + call word_dup + call word_exit + ret +section .data +data_start: +str_0: db 47, 101, 116, 99, 47, 104, 111, 115, 116, 110, 97, 109, 101, 0 +str_0_len equ 13 +str_1: db 111, 112, 101, 110, 40, 41, 32, 102, 97, 105, 108, 101, 100, 58, 32, 101, 114, 114, 110, 111, 61, 0 +str_1_len equ 21 +str_2: db 102, 115, 116, 97, 116, 40, 41, 32, 102, 97, 105, 108, 101, 100, 58, 32, 101, 114, 114, 110, 111, 61, 0 +str_2_len equ 22 +str_3: db 109, 109, 97, 112, 40, 41, 32, 102, 97, 105, 108, 101, 100, 0 +str_3_len equ 13 +str_4: db 117, 110, 107, 110, 111, 119, 110, 32, 114, 101, 97, 100, 95, 102, 105, 108, 101, 32, 102, 97, 105, 108, 117, 114, 101, 0 +str_4_len equ 25 +data_end: +section .bss +align 16 +dstack: resb DSTK_BYTES +dstack_top: +align 16 +rstack: resb RSTK_BYTES +rstack_top: +align 16 +print_buf: resb PRINT_BUF_BYTES +print_buf_end: \ No newline at end of file diff --git a/build/test_read_file.o b/build/test_read_file.o new file mode 100644 index 0000000..4d50246 Binary files /dev/null and b/build/test_read_file.o differ diff --git a/build/test_write_buf.asm b/build/test_write_buf.asm new file mode 100644 index 0000000..dba1bc8 --- /dev/null +++ b/build/test_write_buf.asm @@ -0,0 +1,555 @@ +section .text +%define DSTK_BYTES 65536 +%define RSTK_BYTES 65536 +%define PRINT_BUF_BYTES 128 +global _start +_start: + ; initialize data/return stack pointers + lea r12, [rel dstack_top] + mov r15, r12 + lea r13, [rel rstack_top] + call word_main + mov rax, 0 + cmp r12, r15 + je .no_exit_value + mov rax, [r12] + add r12, 8 +.no_exit_value: + mov rdi, rax + mov rax, 60 + syscall +word_c_40: + mov rax, [r12] + movzx rax, byte [rax] + mov [r12], rax + ret + ret +word_c_21: + mov rax, [r12] + add r12, 8 + mov rbx, [r12] + mov [rbx], al + ret + ret +word_r_40: + mov rax, [r13] + sub r12, 8 + mov [r12], rax + ret + ret +word_strlen: + mov rax, [r12] ; addr + mov rcx, [r12 + 8] ; len + add r12, 16 ; pop len and addr + mov [r12], rcx ; push len + ret + ret +word_puts: + ; detects string if top is len>=0 and next is a pointer in [data_start, data_end] + mov rax, [r12] ; len or int value + mov rbx, [r12 + 8] ; possible address + cmp rax, 0 + jl puts_print_int + lea r8, [rel data_start] + lea r9, [rel data_end] + cmp rbx, r8 + jl puts_print_int + cmp rbx, r9 + jge puts_print_int + ; treat as string: (addr below len) + mov rdx, rax ; len + mov rsi, rbx ; addr + add r12, 16 ; pop len + addr + test rdx, rdx + jz puts_str_newline_only + mov rax, 1 + mov rdi, 1 + syscall +puts_str_newline_only: + mov byte [rel print_buf], 10 + mov rax, 1 + mov rdi, 1 + lea rsi, [rel print_buf] + mov rdx, 1 + syscall + ret + +puts_print_int: + mov rax, [r12] + add r12, 8 + mov rbx, rax + mov r8, 0 + cmp rbx, 0 + jge puts_abs + neg rbx + mov r8, 1 +puts_abs: + lea rsi, [rel print_buf_end] + mov rcx, 0 + mov r10, 10 + cmp rbx, 0 + jne puts_digits + dec rsi + mov byte [rsi], '0' + inc rcx + jmp puts_sign +puts_digits: +puts_loop: + xor rdx, rdx + mov rax, rbx + div r10 + add dl, '0' + dec rsi + mov [rsi], dl + inc rcx + mov rbx, rax + test rbx, rbx + jne puts_loop +puts_sign: + cmp r8, 0 + je puts_finish_digits + dec rsi + mov byte [rsi], '-' + inc rcx +puts_finish_digits: + mov byte [rsi + rcx], 10 + inc rcx + mov rax, 1 + mov rdi, 1 + mov rdx, rcx + mov r9, rsi + mov rsi, r9 + syscall + ret +word_dup: + mov rax, [r12] + sub r12, 8 + mov [r12], rax + ret +word_write_buf: + mov rdx, [r12] ; len + mov rsi, [r12 + 8] ; addr + add r12, 16 ; pop len + addr + mov rax, 1 ; syscall: write + mov rdi, 1 ; fd = stdout + syscall + ret + ret +word_drop: + add r12, 8 + ret +word_over: + mov rax, [r12 + 8] + sub r12, 8 + mov [r12], rax + ret +word_swap: + mov rax, [r12] + mov rbx, [r12 + 8] + mov [r12], rbx + mov [r12 + 8], rax + ret +word_rot: + mov rax, [r12] ; x3 + mov rbx, [r12 + 8] ; x2 + mov rcx, [r12 + 16] ; x1 + mov [r12], rcx ; top = x1 + mov [r12 + 8], rax ; next = x3 + mov [r12 + 16], rbx ; third = x2 + ret +word__2drot: + mov rax, [r12] ; x3 + mov rbx, [r12 + 8] ; x2 + mov rcx, [r12 + 16] ; x1 + mov [r12], rbx ; top = x2 + mov [r12 + 8], rcx ; next = x1 + mov [r12 + 16], rax ; third = x3 + ret +word_nip: + mov rax, [r12] + add r12, 8 ; drop lower element + mov [r12], rax ; keep original top + ret +word_tuck: + mov rax, [r12] ; x2 + mov rbx, [r12 + 8] ; x1 + sub r12, 8 ; make room + mov [r12], rax ; x2 + mov [r12 + 8], rbx ; x1 + mov [r12 + 16], rax ; x2 + ret +word_2dup: + mov rax, [r12] ; b + mov rbx, [r12 + 8] ; a + sub r12, 8 + mov [r12], rbx ; push a + sub r12, 8 + mov [r12], rax ; push b + ret +word_2drop: + add r12, 16 + ret +word_2swap: + mov rax, [r12] ; d + mov rbx, [r12 + 8] ; c + mov rcx, [r12 + 16] ; b + mov rdx, [r12 + 24] ; a + mov [r12], rcx ; top = b + mov [r12 + 8], rdx ; next = a + mov [r12 + 16], rax ; third = d + mov [r12 + 24], rbx ; fourth = c + ret +word_2over: + mov rax, [r12 + 16] ; b + mov rbx, [r12 + 24] ; a + sub r12, 8 + mov [r12], rbx ; push a + sub r12, 8 + mov [r12], rax ; push b + ret +word__2b: + mov rax, [r12] + add r12, 8 + add qword [r12], rax + ret +word__2d: + mov rax, [r12] + add r12, 8 + sub qword [r12], rax + ret +word__2a: + mov rax, [r12] + add r12, 8 + imul qword [r12] + mov [r12], rax + ret +word__2f: + mov rbx, [r12] + add r12, 8 + mov rax, [r12] + cqo + idiv rbx + mov [r12], rax + ret +word__25: + mov rbx, [r12] + add r12, 8 + mov rax, [r12] + cqo + idiv rbx + mov [r12], rdx + ret +word__3d_3d: + mov rax, [r12] + add r12, 8 + mov rbx, [r12] + cmp rbx, rax + mov rbx, 0 + sete bl + mov [r12], rbx + ret +word__21_3d: + mov rax, [r12] + add r12, 8 + mov rbx, [r12] + cmp rbx, rax + mov rbx, 0 + setne bl + mov [r12], rbx + ret +word__3c: + mov rax, [r12] + add r12, 8 + mov rbx, [r12] + cmp rbx, rax + mov rbx, 0 + setl bl + mov [r12], rbx + ret +word__3e: + mov rax, [r12] + add r12, 8 + mov rbx, [r12] + cmp rbx, rax + mov rbx, 0 + setg bl + mov [r12], rbx + ret +word__3c_3d: + mov rax, [r12] + add r12, 8 + mov rbx, [r12] + cmp rbx, rax + mov rbx, 0 + setle bl + mov [r12], rbx + ret +word__3e_3d: + mov rax, [r12] + add r12, 8 + mov rbx, [r12] + cmp rbx, rax + mov rbx, 0 + setge bl + mov [r12], rbx + ret +word__40: + mov rax, [r12] + mov rax, [rax] + mov [r12], rax + ret +word__21: + mov rax, [r12] + add r12, 8 + mov rbx, [r12] + mov [rax], rbx + add r12, 8 + ret +word_mmap: + ; Save rsp and align to 16 bytes for syscall ABI + mov rax, rsp + and rsp, -16 + mov rdi, [r12+40] ; addr + mov rsi, [r12+32] ; length + mov rdx, [r12+24] ; prot + mov r10, [r12+16] ; flags + mov r8, [r12+8] ; fd + mov r9, [r12] ; offset + add r12, 48 ; pop 6 args + mov rax, 9 ; syscall: mmap + syscall + mov rsp, rax ; restore rsp + sub r12, 8 + mov [r12], rax ; push result + ret + ret +word_munmap: + mov rsi, [r12] + add r12, 8 + mov rdi, [r12] + mov rax, 11 + syscall + mov [r12], rax + ret +word_exit: + mov rdi, [r12] + add r12, 8 + mov rax, 60 + syscall + ret +word_and: + mov rax, [r12] + add r12, 8 + mov rbx, [r12] + test rax, rax + setz cl + test rbx, rbx + setz dl + movzx rcx, cl + movzx rdx, dl + and rcx, rdx + mov [r12], rcx + ret +word_or: + mov rax, [r12] + add r12, 8 + mov rbx, [r12] + test rax, rax + setz cl + test rbx, rbx + setz dl + movzx rcx, cl + movzx rdx, dl + or rcx, rdx + mov [r12], rcx + ret +word_not: + mov rax, [r12] + test rax, rax + setz al + movzx rax, al + mov [r12], rax + ret +word__3er: + mov rax, [r12] + add r12, 8 + sub r13, 8 + mov [r13], rax + ret +word_r_3e: + mov rax, [r13] + add r13, 8 + sub r12, 8 + mov [r12], rax + ret +word_rdrop: + add r13, 8 + ret +word_pick: + mov rcx, [r12] + add r12, 8 + mov rax, [r12 + rcx * 8] + sub r12, 8 + mov [r12], rax + ret +word_rpick: + mov rcx, [r12] + add r12, 8 + mov rax, [r13 + rcx * 8] + sub r12, 8 + mov [r12], rax + ret +word_read_file: + ; stack: path_ptr (top), path_len (next) + mov rsi, [r12] ; path_ptr + mov rdx, [r12 + 8] ; path_len + add r12, 16 ; pop args + + ; open(path_ptr, O_RDONLY=0, mode=0) + mov rax, 2 ; syscall: open + mov rdi, rsi ; filename + xor rsi, rsi ; flags = O_RDONLY + xor rdx, rdx ; mode = 0 + syscall + mov r10, rax ; save open() result + cmp rax, 0 + jl .fail_open + mov r8, rax ; fd + + ; use lseek to determine file size: lseek(fd, 0, SEEK_END) + mov rax, 8 ; syscall: lseek + mov rdi, r8 ; fd + xor rsi, rsi ; offset = 0 + mov rdx, 2 ; SEEK_END + syscall + mov r11, rax ; save lseek() result + cmp rax, 0 + jl .close_fail_lseek + mov rsi, rax ; length = size + + ; mmap(NULL, size, PROT_READ=1, MAP_PRIVATE=2, fd, 0) + mov rax, 9 ; syscall: mmap + xor rdi, rdi ; addr = NULL + ; rsi already holds length + mov rdx, 1 ; PROT_READ + mov r10, 2 ; MAP_PRIVATE + mov r8, r8 ; fd + xor r9, r9 ; offset = 0 + syscall + mov rbx, rax ; addr + mov r12, r12 ; (no-op, for debug) + mov rax, 3 ; syscall: close + mov rdi, r8 ; fd + syscall + cmp rbx, -4095 + jae .fail_mmap + sub r12, 16 + mov [r12], rsi ; len (rsi held length across syscall) + mov [r12 + 8], rbx ; addr + ret + +.close_fail_lseek: + mov rax, 3 + mov rdi, r8 + syscall + mov rax, r11 ; return lseek() error code + sub r12, 16 + mov [r12], rax + mov qword [r12 + 8], -1 + ret + +.fail_open: + mov rax, r10 ; return open() error code + sub r12, 16 + mov [r12], rax + mov qword [r12 + 8], -2 + ret + +.fail_mmap: + mov rax, -1 ; return mmap() error + sub r12, 16 + mov [r12], rax + mov qword [r12 + 8], -3 + ret + ret +word_write_file: + ; stack: path_ptr (top), path_len, buf_ptr, buf_len + mov rsi, [r12] ; path_ptr + mov rdx, [r12 + 8] ; path_len + mov r14, [r12 + 16] ; buf_len + mov rbx, [r12 + 24] ; buf_ptr + add r12, 32 ; pop 4 args + + ; preserve buffer info in callee-saved regs (syscall clobbers rcx/r11) + mov r15, r14 ; r15 = buf_ptr + mov r13, rbx ; r13 = buf_len + + ; open(path_ptr, O_WRONLY|O_CREAT|O_TRUNC, 0666) + mov rdi, rsi ; filename + mov rsi, 577 ; flags = O_WRONLY(1)|O_CREAT(64)|O_TRUNC(512) + mov rdx, 438 ; mode = 0o666 + mov rax, 2 ; syscall: open + syscall + cmp rax, 0 + jl .fail_open + mov r9, rax ; save fd + + ; write(fd, buf_ptr, buf_len) -- use r15/r13 which survive syscalls + mov rax, 1 ; syscall: write + mov rdi, r9 ; fd + mov rsi, r15 ; buf_ptr + mov rdx, r13 ; buf_len + syscall + mov r10, rax ; save write result + cmp r10, 0 + jl .fail_write + + ; close(fd) + mov rax, 3 ; syscall: close + mov rdi, r9 + syscall + + sub r12, 8 + mov [r12], r10 ; return bytes_written + ret + +.fail_write: + mov rax, 3 ; close before returning error + mov rdi, r9 + syscall + sub r12, 8 + mov [r12], r10 ; return negative errno from write + ret + +.fail_open: + sub r12, 8 + mov [r12], rax ; return negative errno from open + ret + ret +word_main: + ; push str_0 + sub r12, 8 + mov qword [r12], str_0 + ; push 26 + sub r12, 8 + mov qword [r12], 26 + call word_write_buf + ; push 0 + sub r12, 8 + mov qword [r12], 0 + ret +section .data +data_start: +str_0: db 104, 101, 108, 108, 111, 32, 102, 114, 111, 109, 32, 119, 114, 105, 116, 101, 95, 98, 117, 102, 32, 116, 101, 115, 116, 10, 0 +str_0_len equ 26 +data_end: +section .bss +align 16 +dstack: resb DSTK_BYTES +dstack_top: +align 16 +rstack: resb RSTK_BYTES +rstack_top: +align 16 +print_buf: resb PRINT_BUF_BYTES +print_buf_end: \ No newline at end of file diff --git a/build/test_write_buf.o b/build/test_write_buf.o new file mode 100644 index 0000000..ca032b0 Binary files /dev/null and b/build/test_write_buf.o differ diff --git a/build/test_write_file.asm b/build/test_write_file.asm new file mode 100644 index 0000000..841bc91 --- /dev/null +++ b/build/test_write_file.asm @@ -0,0 +1,594 @@ +section .text +%define DSTK_BYTES 65536 +%define RSTK_BYTES 65536 +%define PRINT_BUF_BYTES 128 +global _start +_start: + ; initialize data/return stack pointers + lea r12, [rel dstack_top] + mov r15, r12 + lea r13, [rel rstack_top] + call word_main + mov rax, 0 + cmp r12, r15 + je .no_exit_value + mov rax, [r12] + add r12, 8 +.no_exit_value: + mov rdi, rax + mov rax, 60 + syscall +word_c_40: + mov rax, [r12] + movzx rax, byte [rax] + mov [r12], rax + ret + ret +word_c_21: + mov rax, [r12] + add r12, 8 + mov rbx, [r12] + mov [rbx], al + ret + ret +word_r_40: + mov rax, [r13] + sub r12, 8 + mov [r12], rax + ret + ret +word_strlen: + mov rax, [r12] ; addr + mov rcx, [r12 + 8] ; len + add r12, 16 ; pop len and addr + mov [r12], rcx ; push len + ret + ret +word_puts: + ; detects string if top is len>=0 and next is a pointer in [data_start, data_end] + mov rax, [r12] ; len or int value + mov rbx, [r12 + 8] ; possible address + cmp rax, 0 + jl puts_print_int + lea r8, [rel data_start] + lea r9, [rel data_end] + cmp rbx, r8 + jl puts_print_int + cmp rbx, r9 + jge puts_print_int + ; treat as string: (addr below len) + mov rdx, rax ; len + mov rsi, rbx ; addr + add r12, 16 ; pop len + addr + test rdx, rdx + jz puts_str_newline_only + mov rax, 1 + mov rdi, 1 + syscall +puts_str_newline_only: + mov byte [rel print_buf], 10 + mov rax, 1 + mov rdi, 1 + lea rsi, [rel print_buf] + mov rdx, 1 + syscall + ret + +puts_print_int: + mov rax, [r12] + add r12, 8 + mov rbx, rax + mov r8, 0 + cmp rbx, 0 + jge puts_abs + neg rbx + mov r8, 1 +puts_abs: + lea rsi, [rel print_buf_end] + mov rcx, 0 + mov r10, 10 + cmp rbx, 0 + jne puts_digits + dec rsi + mov byte [rsi], '0' + inc rcx + jmp puts_sign +puts_digits: +puts_loop: + xor rdx, rdx + mov rax, rbx + div r10 + add dl, '0' + dec rsi + mov [rsi], dl + inc rcx + mov rbx, rax + test rbx, rbx + jne puts_loop +puts_sign: + cmp r8, 0 + je puts_finish_digits + dec rsi + mov byte [rsi], '-' + inc rcx +puts_finish_digits: + mov byte [rsi + rcx], 10 + inc rcx + mov rax, 1 + mov rdi, 1 + mov rdx, rcx + mov r9, rsi + mov rsi, r9 + syscall + ret +word_dup: + mov rax, [r12] + sub r12, 8 + mov [r12], rax + ret +word_write_buf: + mov rdx, [r12] ; len + mov rsi, [r12 + 8] ; addr + add r12, 16 ; pop len + addr + mov rax, 1 ; syscall: write + mov rdi, 1 ; fd = stdout + syscall + ret + ret +word_drop: + add r12, 8 + ret +word_over: + mov rax, [r12 + 8] + sub r12, 8 + mov [r12], rax + ret +word_swap: + mov rax, [r12] + mov rbx, [r12 + 8] + mov [r12], rbx + mov [r12 + 8], rax + ret +word_rot: + mov rax, [r12] ; x3 + mov rbx, [r12 + 8] ; x2 + mov rcx, [r12 + 16] ; x1 + mov [r12], rcx ; top = x1 + mov [r12 + 8], rax ; next = x3 + mov [r12 + 16], rbx ; third = x2 + ret +word__2drot: + mov rax, [r12] ; x3 + mov rbx, [r12 + 8] ; x2 + mov rcx, [r12 + 16] ; x1 + mov [r12], rbx ; top = x2 + mov [r12 + 8], rcx ; next = x1 + mov [r12 + 16], rax ; third = x3 + ret +word_nip: + mov rax, [r12] + add r12, 8 ; drop lower element + mov [r12], rax ; keep original top + ret +word_tuck: + mov rax, [r12] ; x2 + mov rbx, [r12 + 8] ; x1 + sub r12, 8 ; make room + mov [r12], rax ; x2 + mov [r12 + 8], rbx ; x1 + mov [r12 + 16], rax ; x2 + ret +word_2dup: + mov rax, [r12] ; b + mov rbx, [r12 + 8] ; a + sub r12, 8 + mov [r12], rbx ; push a + sub r12, 8 + mov [r12], rax ; push b + ret +word_2drop: + add r12, 16 + ret +word_2swap: + mov rax, [r12] ; d + mov rbx, [r12 + 8] ; c + mov rcx, [r12 + 16] ; b + mov rdx, [r12 + 24] ; a + mov [r12], rcx ; top = b + mov [r12 + 8], rdx ; next = a + mov [r12 + 16], rax ; third = d + mov [r12 + 24], rbx ; fourth = c + ret +word_2over: + mov rax, [r12 + 16] ; b + mov rbx, [r12 + 24] ; a + sub r12, 8 + mov [r12], rbx ; push a + sub r12, 8 + mov [r12], rax ; push b + ret +word__2b: + mov rax, [r12] + add r12, 8 + add qword [r12], rax + ret +word__2d: + mov rax, [r12] + add r12, 8 + sub qword [r12], rax + ret +word__2a: + mov rax, [r12] + add r12, 8 + imul qword [r12] + mov [r12], rax + ret +word__2f: + mov rbx, [r12] + add r12, 8 + mov rax, [r12] + cqo + idiv rbx + mov [r12], rax + ret +word__25: + mov rbx, [r12] + add r12, 8 + mov rax, [r12] + cqo + idiv rbx + mov [r12], rdx + ret +word__3d_3d: + mov rax, [r12] + add r12, 8 + mov rbx, [r12] + cmp rbx, rax + mov rbx, 0 + sete bl + mov [r12], rbx + ret +word__21_3d: + mov rax, [r12] + add r12, 8 + mov rbx, [r12] + cmp rbx, rax + mov rbx, 0 + setne bl + mov [r12], rbx + ret +word__3c: + mov rax, [r12] + add r12, 8 + mov rbx, [r12] + cmp rbx, rax + mov rbx, 0 + setl bl + mov [r12], rbx + ret +word__3e: + mov rax, [r12] + add r12, 8 + mov rbx, [r12] + cmp rbx, rax + mov rbx, 0 + setg bl + mov [r12], rbx + ret +word__3c_3d: + mov rax, [r12] + add r12, 8 + mov rbx, [r12] + cmp rbx, rax + mov rbx, 0 + setle bl + mov [r12], rbx + ret +word__3e_3d: + mov rax, [r12] + add r12, 8 + mov rbx, [r12] + cmp rbx, rax + mov rbx, 0 + setge bl + mov [r12], rbx + ret +word__40: + mov rax, [r12] + mov rax, [rax] + mov [r12], rax + ret +word__21: + mov rax, [r12] + add r12, 8 + mov rbx, [r12] + mov [rax], rbx + add r12, 8 + ret +word_mmap: + ; Save rsp and align to 16 bytes for syscall ABI + mov rax, rsp + and rsp, -16 + mov rdi, [r12+40] ; addr + mov rsi, [r12+32] ; length + mov rdx, [r12+24] ; prot + mov r10, [r12+16] ; flags + mov r8, [r12+8] ; fd + mov r9, [r12] ; offset + add r12, 48 ; pop 6 args + mov rax, 9 ; syscall: mmap + syscall + mov rsp, rax ; restore rsp + sub r12, 8 + mov [r12], rax ; push result + ret + ret +word_munmap: + mov rsi, [r12] + add r12, 8 + mov rdi, [r12] + mov rax, 11 + syscall + mov [r12], rax + ret +word_exit: + mov rdi, [r12] + add r12, 8 + mov rax, 60 + syscall + ret +word_and: + mov rax, [r12] + add r12, 8 + mov rbx, [r12] + test rax, rax + setz cl + test rbx, rbx + setz dl + movzx rcx, cl + movzx rdx, dl + and rcx, rdx + mov [r12], rcx + ret +word_or: + mov rax, [r12] + add r12, 8 + mov rbx, [r12] + test rax, rax + setz cl + test rbx, rbx + setz dl + movzx rcx, cl + movzx rdx, dl + or rcx, rdx + mov [r12], rcx + ret +word_not: + mov rax, [r12] + test rax, rax + setz al + movzx rax, al + mov [r12], rax + ret +word__3er: + mov rax, [r12] + add r12, 8 + sub r13, 8 + mov [r13], rax + ret +word_r_3e: + mov rax, [r13] + add r13, 8 + sub r12, 8 + mov [r12], rax + ret +word_rdrop: + add r13, 8 + ret +word_pick: + mov rcx, [r12] + add r12, 8 + mov rax, [r12 + rcx * 8] + sub r12, 8 + mov [r12], rax + ret +word_rpick: + mov rcx, [r12] + add r12, 8 + mov rax, [r13 + rcx * 8] + sub r12, 8 + mov [r12], rax + ret +word_read_file: + ; stack: path_ptr (top), path_len (next) + mov rsi, [r12] ; path_ptr + mov rdx, [r12 + 8] ; path_len + add r12, 16 ; pop args + + ; open(path_ptr, O_RDONLY=0, mode=0) + mov rax, 2 ; syscall: open + mov rdi, rsi ; filename + xor rsi, rsi ; flags = O_RDONLY + xor rdx, rdx ; mode = 0 + syscall + mov r10, rax ; save open() result + cmp rax, 0 + jl .fail_open + mov r8, rax ; fd + + ; use lseek to determine file size: lseek(fd, 0, SEEK_END) + mov rax, 8 ; syscall: lseek + mov rdi, r8 ; fd + xor rsi, rsi ; offset = 0 + mov rdx, 2 ; SEEK_END + syscall + mov r11, rax ; save lseek() result + cmp rax, 0 + jl .close_fail_lseek + mov rsi, rax ; length = size + + ; mmap(NULL, size, PROT_READ=1, MAP_PRIVATE=2, fd, 0) + mov rax, 9 ; syscall: mmap + xor rdi, rdi ; addr = NULL + ; rsi already holds length + mov rdx, 1 ; PROT_READ + mov r10, 2 ; MAP_PRIVATE + mov r8, r8 ; fd + xor r9, r9 ; offset = 0 + syscall + mov rbx, rax ; addr + mov r12, r12 ; (no-op, for debug) + mov rax, 3 ; syscall: close + mov rdi, r8 ; fd + syscall + cmp rbx, -4095 + jae .fail_mmap + sub r12, 16 + mov [r12], rsi ; len (rsi held length across syscall) + mov [r12 + 8], rbx ; addr + ret + +.close_fail_lseek: + mov rax, 3 + mov rdi, r8 + syscall + mov rax, r11 ; return lseek() error code + sub r12, 16 + mov [r12], rax + mov qword [r12 + 8], -1 + ret + +.fail_open: + mov rax, r10 ; return open() error code + sub r12, 16 + mov [r12], rax + mov qword [r12 + 8], -2 + ret + +.fail_mmap: + mov rax, -1 ; return mmap() error + sub r12, 16 + mov [r12], rax + mov qword [r12 + 8], -3 + ret + ret +word_write_file: + ; stack: path_ptr (top), path_len, buf_ptr, buf_len + mov rsi, [r12] ; path_ptr + mov rdx, [r12 + 8] ; path_len + mov r15, [r12 + 16] ; buf_ptr (save in callee-saved r15) + mov r13, [r12 + 24] ; buf_len (save in callee-saved r13) + add r12, 32 ; pop 4 args (we saved buf info) + + ; open(path_ptr, O_WRONLY|O_CREAT|O_TRUNC, 0666) + mov rdi, rsi ; filename + mov rsi, 577 ; flags = O_WRONLY|O_CREAT|O_TRUNC + mov rdx, 438 ; mode = 0o666 + mov rax, 2 ; syscall: open + syscall + cmp rax, 0 + jl .fail_open + mov r9, rax ; save fd + + ; write(fd, buf_ptr, buf_len) -- use preserved r15/r13 which survive syscalls + mov rax, 1 ; syscall: write + mov rdi, r9 ; fd + mov rsi, r15 ; buf_ptr + mov rdx, r13 ; buf_len + syscall + mov r10, rax ; save write result + cmp r10, 0 + jl .fail_write + + ; close(fd) + mov rax, 3 ; syscall: close + mov rdi, r9 + syscall + + sub r12, 8 + mov [r12], r10 + ret + +.fail_write: + mov rax, 3 + mov rdi, r9 + syscall + sub r12, 8 + mov [r12], r10 + ret + +.fail_open: + sub r12, 8 + mov [r12], rax + ret + ret +word_main: + ; push str_0 + sub r12, 8 + mov qword [r12], str_0 + ; push 22 + sub r12, 8 + mov qword [r12], 22 + call word_swap + ; push str_1 + sub r12, 8 + mov qword [r12], str_1 + ; push 27 + sub r12, 8 + mov qword [r12], 27 + call word_swap + call word_2swap + call word_write_file + call word_dup + ; push 0 + sub r12, 8 + mov qword [r12], 0 + call word__3e + mov rax, [r12] + add r12, 8 + test rax, rax + jz L_if_false_0 + ; push str_2 + sub r12, 8 + mov qword [r12], str_2 + ; push 13 + sub r12, 8 + mov qword [r12], 13 + call word_puts + call word_puts + ; push 0 + sub r12, 8 + mov qword [r12], 0 + call word_exit +L_if_false_0: + ; push str_3 + sub r12, 8 + mov qword [r12], str_3 + ; push 19 + sub r12, 8 + mov qword [r12], 19 + call word_puts + call word_puts + call word_exit + ret +section .data +data_start: +str_0: db 47, 116, 109, 112, 47, 108, 50, 95, 116, 101, 115, 116, 95, 119, 114, 105, 116, 101, 46, 116, 120, 116, 0 +str_0_len equ 22 +str_1: db 104, 101, 108, 108, 111, 32, 102, 114, 111, 109, 32, 119, 114, 105, 116, 101, 95, 102, 105, 108, 101, 32, 116, 101, 115, 116, 10, 0 +str_1_len equ 27 +str_2: db 119, 114, 111, 116, 101, 32, 98, 121, 116, 101, 115, 58, 32, 0 +str_2_len equ 13 +str_3: db 119, 114, 105, 116, 101, 32, 102, 97, 105, 108, 101, 100, 32, 101, 114, 114, 110, 111, 61, 0 +str_3_len equ 19 +data_end: +section .bss +align 16 +dstack: resb DSTK_BYTES +dstack_top: +align 16 +rstack: resb RSTK_BYTES +rstack_top: +align 16 +print_buf: resb PRINT_BUF_BYTES +print_buf_end: \ No newline at end of file diff --git a/build/test_write_file.o b/build/test_write_file.o new file mode 100644 index 0000000..b6082c5 Binary files /dev/null and b/build/test_write_file.o differ diff --git a/hello.sl b/hello.sl index 9f3cb37..c60fb3a 100644 --- a/hello.sl +++ b/hello.sl @@ -1,4 +1,4 @@ -import stdlib.sl +import stdlib/stdlib.sl : main "hello world" puts diff --git a/main.py b/main.py index d853ce9..b8580c3 100644 --- a/main.py +++ b/main.py @@ -2138,7 +2138,6 @@ def _register_compile_time_primitives(dictionary: Dictionary) -> None: register("list-new", _ct_list_new, compile_only=True) register("list-clone", _ct_list_clone, compile_only=True) register("list-append", _ct_list_append, compile_only=True) - register("drop", _ct_drop) register("list-pop", _ct_list_pop, compile_only=True) register("list-pop-front", _ct_list_pop_front, compile_only=True) register("list-peek-front", _ct_list_peek_front, compile_only=True) diff --git a/main.sl b/main.sl index 7548779..2779b0b 100644 --- a/main.sl +++ b/main.sl @@ -1,4 +1,4 @@ -import stdlib.sl +import stdlib/stdlib.sl import fn.sl : main diff --git a/stat_offset b/stat_offset new file mode 100755 index 0000000..7556586 Binary files /dev/null and b/stat_offset differ diff --git a/stat_offset.c b/stat_offset.c new file mode 100644 index 0000000..6e4f6fd --- /dev/null +++ b/stat_offset.c @@ -0,0 +1,8 @@ +#include +#include +#include + +int main() { + printf("st_size offset: %zu\n", offsetof(struct stat, st_size)); + return 0; +} diff --git a/stdlib/io.sl b/stdlib/io.sl new file mode 100644 index 0000000..02764c2 --- /dev/null +++ b/stdlib/io.sl @@ -0,0 +1,134 @@ + +# L2 IO Primitives + +# : read_file ( path_ptr path_len -- len addr | 0 0 ) +# Reads the file at the given path (pointer+length, not null-terminated), +# returns (len addr) of mapped file, or (0 0) on error. + +:asm read_file { + ; stack: path_ptr (top), path_len (next) + mov rsi, [r12] ; path_ptr + mov rdx, [r12 + 8] ; path_len + add r12, 16 ; pop args + + ; open(path_ptr, O_RDONLY=0, mode=0) + mov rax, 2 ; syscall: open + mov rdi, rsi ; filename + xor rsi, rsi ; flags = O_RDONLY + xor rdx, rdx ; mode = 0 + syscall + mov r10, rax ; save open() result + cmp rax, 0 + jl .fail_open + mov r8, rax ; fd + + ; use lseek to determine file size: lseek(fd, 0, SEEK_END) + mov rax, 8 ; syscall: lseek + mov rdi, r8 ; fd + xor rsi, rsi ; offset = 0 + mov rdx, 2 ; SEEK_END + syscall + mov r11, rax ; save lseek() result + cmp rax, 0 + jl .close_fail_lseek + mov rsi, rax ; length = size + + ; mmap(NULL, size, PROT_READ=1, MAP_PRIVATE=2, fd, 0) + mov rax, 9 ; syscall: mmap + xor rdi, rdi ; addr = NULL + ; rsi already holds length + mov rdx, 1 ; PROT_READ + mov r10, 2 ; MAP_PRIVATE + mov r8, r8 ; fd + xor r9, r9 ; offset = 0 + syscall + mov rbx, rax ; addr + mov r12, r12 ; (no-op, for debug) + mov rax, 3 ; syscall: close + mov rdi, r8 ; fd + syscall + cmp rbx, -4095 + jae .fail_mmap + sub r12, 16 + mov [r12], rsi ; len (rsi held length across syscall) + mov [r12 + 8], rbx ; addr + ret + +.close_fail_lseek: + mov rax, 3 + mov rdi, r8 + syscall + mov rax, r11 ; return lseek() error code + sub r12, 16 + mov [r12], rax + mov qword [r12 + 8], -1 + ret + +.fail_open: + mov rax, r10 ; return open() error code + sub r12, 16 + mov [r12], rax + mov qword [r12 + 8], -2 + ret + +.fail_mmap: + mov rax, -1 ; return mmap() error + sub r12, 16 + mov [r12], rax + mov qword [r12 + 8], -3 + ret +} +; + +# : write_file ( path_ptr path_len buf_ptr buf_len -- bytes_written | neg_errno ) +:asm write_file { + ; stack: path_ptr (top), path_len, buf_ptr, buf_len + mov rsi, [r12] ; path_ptr + mov rdx, [r12 + 8] ; path_len + mov r15, [r12 + 16] ; buf_ptr (save in callee-saved r15) + mov r13, [r12 + 24] ; buf_len (save in callee-saved r13) + add r12, 32 ; pop 4 args (we saved buf info) + + ; open(path_ptr, O_WRONLY|O_CREAT|O_TRUNC, 0666) + mov rdi, rsi ; filename + mov rsi, 577 ; flags = O_WRONLY|O_CREAT|O_TRUNC + mov rdx, 438 ; mode = 0o666 + mov rax, 2 ; syscall: open + syscall + cmp rax, 0 + jl .fail_open + mov r9, rax ; save fd + + ; write(fd, buf_ptr, buf_len) -- use preserved r15/r13 which survive syscalls + mov rax, 1 ; syscall: write + mov rdi, r9 ; fd + mov rsi, r15 ; buf_ptr + mov rdx, r13 ; buf_len + syscall + mov r10, rax ; save write result + cmp r10, 0 + jl .fail_write + + ; close(fd) + mov rax, 3 ; syscall: close + mov rdi, r9 + syscall + + sub r12, 8 + mov [r12], r10 + ret + +.fail_write: + mov rax, 3 + mov rdi, r9 + syscall + sub r12, 8 + mov [r12], r10 + ret + +.fail_open: + sub r12, 8 + mov [r12], rax + ret +} +; \ No newline at end of file diff --git a/stdlib.sl b/stdlib/stdlib.sl similarity index 81% rename from stdlib.sl rename to stdlib/stdlib.sl index a25fa30..37d4e7f 100644 --- a/stdlib.sl +++ b/stdlib/stdlib.sl @@ -1,3 +1,41 @@ +# : c@ ( addr -- byte ) +:asm c@ { + mov rax, [r12] + movzx rax, byte [rax] + mov [r12], rax + ret +} +; + +# : c! ( byte addr -- ) +:asm c! { + mov rax, [r12] + add r12, 8 + mov rbx, [r12] + mov [rbx], al + ret +} +; + +# : r@ ( -- x ) +:asm r@ { + mov rax, [r13] + sub r12, 8 + mov [r12], rax + ret +} +; + +# : strlen ( addr len -- len ) +:asm strlen { + mov rax, [r12] ; addr + mov rcx, [r12 + 8] ; len + add r12, 16 ; pop len and addr + mov [r12], rcx ; push len + ret +} +; + :asm puts { ; detects string if top is len>=0 and next is a pointer in [data_start, data_end] mov rax, [r12] ; len or int value @@ -84,6 +122,18 @@ puts_finish_digits: } ; +# : write_buf ( len addr -- ) +:asm write_buf { + mov rdx, [r12] ; len + mov rsi, [r12 + 8] ; addr + add r12, 16 ; pop len + addr + mov rax, 1 ; syscall: write + mov rdi, 1 ; fd = stdout + syscall + ret +} +; + :asm drop { add r12, 8 } @@ -303,20 +353,22 @@ puts_finish_digits: ; :asm mmap { - mov r9, [r12] - add r12, 8 - mov r8, [r12] - add r12, 8 - mov r10, [r12] - add r12, 8 - mov rdx, [r12] - add r12, 8 - mov rsi, [r12] - add r12, 8 - mov rdi, [r12] - mov rax, 9 - syscall - mov [r12], rax + ; Save rsp and align to 16 bytes for syscall ABI + mov rax, rsp + and rsp, -16 + mov rdi, [r12+40] ; addr + mov rsi, [r12+32] ; length + mov rdx, [r12+24] ; prot + mov r10, [r12+16] ; flags + mov r8, [r12+8] ; fd + mov r9, [r12] ; offset + add r12, 48 ; pop 6 args + mov rax, 9 ; syscall: mmap + syscall + mov rsp, rax ; restore rsp + sub r12, 8 + mov [r12], rax ; push result + ret } ; diff --git a/str.out b/str.out new file mode 100755 index 0000000..fab96b1 Binary files /dev/null and b/str.out differ diff --git a/str.sl b/str.sl new file mode 100644 index 0000000..d713da5 --- /dev/null +++ b/str.sl @@ -0,0 +1,8 @@ +import stdlib/stdlib.sl +import stdlib/io.sl + +: main + "str.sl" swap read_file + write_buf + 0 +; \ No newline at end of file diff --git a/t.sl b/t.sl index 7eee533..998dad5 100644 --- a/t.sl +++ b/t.sl @@ -1,4 +1,4 @@ -import stdlib.sl +import stdlib/stdlib.sl import fn.sl fn foo(int a, int b){ diff --git a/test.sl b/test.sl index 5dd56e1..9b8fbf7 100644 --- a/test.sl +++ b/test.sl @@ -1,4 +1,4 @@ -import stdlib.sl +import stdlib/stdlib.sl import fn.sl :asm mem-slot { diff --git a/test_read_file.out b/test_read_file.out new file mode 100755 index 0000000..dbf7c09 Binary files /dev/null and b/test_read_file.out differ diff --git a/test_read_file.sl b/test_read_file.sl new file mode 100644 index 0000000..98ed46d --- /dev/null +++ b/test_read_file.sl @@ -0,0 +1,33 @@ +import stdlib/stdlib.sl +import stdlib/io.sl + +: main + "/etc/hostname" # (len addr) + swap # (addr len) + read_file # (file_len file_addr) + dup 0 > if # if file_len > 0, success + write_buf # print file contents (file_len file_addr) + 0 + exit + then + dup -2 == if # open() failed + drop + "open() failed: errno=" puts + swap puts + exit + then + dup -1 == if # fstat() failed + drop + "fstat() failed: errno=" puts + swap puts + exit + then + dup -3 == if # mmap() failed + drop + "mmap() failed" puts + exit + then + "unknown read_file failure" puts + dup # file_len file_len file_addr + exit # Exit with returned file_len as the program exit code (debug) +; diff --git a/test_write_buf.sl b/test_write_buf.sl new file mode 100644 index 0000000..72720b1 --- /dev/null +++ b/test_write_buf.sl @@ -0,0 +1,8 @@ +import stdlib/stdlib.sl +import stdlib/io.sl + +: main + "hello from write_buf test\n" + write_buf + 0 +; diff --git a/test_write_file.sl b/test_write_file.sl new file mode 100644 index 0000000..002f8f4 --- /dev/null +++ b/test_write_file.sl @@ -0,0 +1,20 @@ +import stdlib/stdlib.sl +import stdlib/io.sl + +: main + "/tmp/l2_test_write.txt" # push path (len addr) + swap # -> (addr len) = path_ptr path_len + "hello from write_file test\n" # push buf (len addr) + swap # -> (addr len) = buf_ptr buf_len + 2swap # reorder pairs -> path_ptr path_len buf_ptr buf_len + write_file + dup 0 > if + "wrote bytes: " puts + puts + 0 + exit + then + "write failed errno=" puts + puts + exit +; diff --git a/tests/run_tests.py b/tests/run_tests.py index cb66aa3..3a7f36b 100644 --- a/tests/run_tests.py +++ b/tests/run_tests.py @@ -30,7 +30,7 @@ CASES: List[TestCase] = [ TestCase( name="call_syntax_parens", source=f""" -import {ROOT / 'stdlib.sl'} +import {ROOT / 'stdlib/stdlib.sl'} import {ROOT / 'fn.sl'} : main @@ -51,7 +51,7 @@ fn foo(int a, int b){{ TestCase( name="loops_and_cmp", source=f""" -import {ROOT / 'stdlib.sl'} +import {ROOT / 'stdlib/stdlib.sl'} : main 0 @@ -69,7 +69,7 @@ import {ROOT / 'stdlib.sl'} TestCase( name="override_dup_compile_time", source=f""" -import {ROOT / 'stdlib.sl'} +import {ROOT / 'stdlib/stdlib.sl'} : dup 6 @@ -102,7 +102,7 @@ compile-only TestCase( name="string_puts", source=f""" -import {ROOT / 'stdlib.sl'} +import {ROOT / 'stdlib/stdlib.sl'} : main \"hello world\" puts diff --git a/write b/write new file mode 100755 index 0000000..7daac9d Binary files /dev/null and b/write differ diff --git a/write_buf_test b/write_buf_test new file mode 100755 index 0000000..3f474ae Binary files /dev/null and b/write_buf_test differ