diff --git a/a.out b/a.out index 8fc096a..692068c 100755 Binary files a/a.out and b/a.out differ diff --git a/build/a.asm b/build/a.asm index 2cc2435..9b91637 100644 --- a/build/a.asm +++ b/build/a.asm @@ -37,104 +37,11 @@ word_r_40: 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 @@ -399,6 +306,270 @@ word_rpick: 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_read_stdin: + ; stack: max_len + mov r14, [r12] ; max_len + add r12, 8 ; pop max_len + + ; mmap(NULL, max_len, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) + mov rax, 9 ; syscall: mmap + xor rdi, rdi ; addr = NULL + mov rsi, r14 ; length + mov rdx, 3 ; PROT_READ|PROT_WRITE + mov r10, 34 ; MAP_PRIVATE|MAP_ANONYMOUS + mov r8, -1 ; fd = -1 + xor r9, r9 ; offset = 0 + syscall + cmp rax, -4095 + jae .fail_mmap + mov rbx, rax ; buffer addr + xor r9, r9 ; bytes_read = 0 + +.read_loop: + mov rax, 0 ; syscall: read + mov rdi, 0 ; fd = stdin + lea rsi, [rbx + r9] ; buf + offset + mov rdx, r14 + sub rdx, r9 ; remaining = max_len - bytes_read + syscall + cmp rax, 0 + je .done_read + js .read_error + add r9, rax + jl .read_loop + +.done_read: + ; push len (rcx) then addr (rbx) + cmp r9, r14 + je .done_no_null + mov byte [rbx + r9], 0 +.done_no_null: + sub r12, 16 + mov [r12], r9 + mov [r12 + 8], rbx + ret + +.read_error: + ; return negative errno in rax, addr = 0 + sub r12, 16 + mov [r12], rax + mov qword [r12 + 8], 0 + ret + +.fail_mmap: + sub r12, 16 + mov qword [r12], -1 + mov qword [r12 + 8], 0 + 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_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_main: ; push str_0 sub r12, 8 diff --git a/build/a.o b/build/a.o index f77941f..9dda115 100644 Binary files a/build/a.o and b/build/a.o differ diff --git a/build/hello.asm b/build/hello.asm index 2cc2435..9b91637 100644 --- a/build/hello.asm +++ b/build/hello.asm @@ -37,104 +37,11 @@ word_r_40: 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 @@ -399,6 +306,270 @@ word_rpick: 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_read_stdin: + ; stack: max_len + mov r14, [r12] ; max_len + add r12, 8 ; pop max_len + + ; mmap(NULL, max_len, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) + mov rax, 9 ; syscall: mmap + xor rdi, rdi ; addr = NULL + mov rsi, r14 ; length + mov rdx, 3 ; PROT_READ|PROT_WRITE + mov r10, 34 ; MAP_PRIVATE|MAP_ANONYMOUS + mov r8, -1 ; fd = -1 + xor r9, r9 ; offset = 0 + syscall + cmp rax, -4095 + jae .fail_mmap + mov rbx, rax ; buffer addr + xor r9, r9 ; bytes_read = 0 + +.read_loop: + mov rax, 0 ; syscall: read + mov rdi, 0 ; fd = stdin + lea rsi, [rbx + r9] ; buf + offset + mov rdx, r14 + sub rdx, r9 ; remaining = max_len - bytes_read + syscall + cmp rax, 0 + je .done_read + js .read_error + add r9, rax + jl .read_loop + +.done_read: + ; push len (rcx) then addr (rbx) + cmp r9, r14 + je .done_no_null + mov byte [rbx + r9], 0 +.done_no_null: + sub r12, 16 + mov [r12], r9 + mov [r12 + 8], rbx + ret + +.read_error: + ; return negative errno in rax, addr = 0 + sub r12, 16 + mov [r12], rax + mov qword [r12 + 8], 0 + ret + +.fail_mmap: + sub r12, 16 + mov qword [r12], -1 + mov qword [r12 + 8], 0 + 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_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_main: ; push str_0 sub r12, 8 diff --git a/build/hello.o b/build/hello.o index e3e581a..2a1766a 100644 Binary files a/build/hello.o and b/build/hello.o differ diff --git a/build/main.asm b/build/main.asm index 0305d97..1c290da 100644 --- a/build/main.asm +++ b/build/main.asm @@ -37,104 +37,11 @@ word_r_40: 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 @@ -399,6 +306,270 @@ word_rpick: 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_read_stdin: + ; stack: max_len + mov r14, [r12] ; max_len + add r12, 8 ; pop max_len + + ; mmap(NULL, max_len, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) + mov rax, 9 ; syscall: mmap + xor rdi, rdi ; addr = NULL + mov rsi, r14 ; length + mov rdx, 3 ; PROT_READ|PROT_WRITE + mov r10, 34 ; MAP_PRIVATE|MAP_ANONYMOUS + mov r8, -1 ; fd = -1 + xor r9, r9 ; offset = 0 + syscall + cmp rax, -4095 + jae .fail_mmap + mov rbx, rax ; buffer addr + xor r9, r9 ; bytes_read = 0 + +.read_loop: + mov rax, 0 ; syscall: read + mov rdi, 0 ; fd = stdin + lea rsi, [rbx + r9] ; buf + offset + mov rdx, r14 + sub rdx, r9 ; remaining = max_len - bytes_read + syscall + cmp rax, 0 + je .done_read + js .read_error + add r9, rax + jl .read_loop + +.done_read: + ; push len (rcx) then addr (rbx) + cmp r9, r14 + je .done_no_null + mov byte [rbx + r9], 0 +.done_no_null: + sub r12, 16 + mov [r12], r9 + mov [r12 + 8], rbx + ret + +.read_error: + ; return negative errno in rax, addr = 0 + sub r12, 16 + mov [r12], rax + mov qword [r12 + 8], 0 + ret + +.fail_mmap: + sub r12, 16 + mov qword [r12], -1 + mov qword [r12 + 8], 0 + 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_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_main: ; push 2 sub r12, 8 diff --git a/build/main.o b/build/main.o index e49159b..9008a99 100644 Binary files a/build/main.o and b/build/main.o differ diff --git a/main.py b/main.py index b8580c3..25b4950 100644 --- a/main.py +++ b/main.py @@ -476,7 +476,6 @@ class Parser: def _execute_immediate_word(self, word: Word) -> None: try: - print(f"[ct] invoking {word.name}") self.compile_time_vm.invoke(word) except ParseError: raise @@ -1075,7 +1074,6 @@ class CompileTimeVM: word = self.dictionary.lookup(name) if word is None: raise ParseError(f"unknown word '{name}' during compile-time execution") - print(f"[ct-call] {name} stack={self.stack}") self._call_word(word) def _execute_nodes(self, nodes: Sequence[ASTNode]) -> None: @@ -2294,6 +2292,7 @@ class Compiler: self.parser = Parser(self.dictionary, self.reader) self.assembler = Assembler(self.dictionary) + def compile_source(self, source: str) -> Emission: tokens = self.reader.tokenize(source) module = self.parser.parse(tokens, source) @@ -2328,12 +2327,19 @@ class Compiler: return "\n".join(lines) + "\n" -def run_nasm(asm_path: Path, obj_path: Path) -> None: - subprocess.run(["nasm", "-f", "elf64", "-o", str(obj_path), str(asm_path)], check=True) +def run_nasm(asm_path: Path, obj_path: Path, debug: bool = False) -> None: + cmd = ["nasm", "-f", "elf64"] + if debug: + cmd.append("-g") + cmd += ["-o", str(obj_path), str(asm_path)] + subprocess.run(cmd, check=True) -def run_linker(obj_path: Path, exe_path: Path) -> None: - subprocess.run(["ld", "-o", str(exe_path), str(obj_path)], check=True) +def run_linker(obj_path: Path, exe_path: Path, debug: bool = False) -> None: + cmd = ["ld", "-o", str(exe_path), str(obj_path)] + if debug: + cmd.append("-g") + subprocess.run(cmd, check=True) def cli(argv: Sequence[str]) -> int: @@ -2342,6 +2348,8 @@ def cli(argv: Sequence[str]) -> int: parser.add_argument("-o", dest="output", type=Path, default=Path("a.out")) parser.add_argument("--emit-asm", action="store_true", help="stop after generating asm") parser.add_argument("--temp-dir", type=Path, default=Path("build")) + parser.add_argument("--debug", action="store_true", help="compile with debug info") + args = parser.parse_args(argv) compiler = Compiler() @@ -2356,8 +2364,8 @@ def cli(argv: Sequence[str]) -> int: print(f"[info] wrote {asm_path}") return 0 - run_nasm(asm_path, obj_path) - run_linker(obj_path, args.output) + run_nasm(asm_path, obj_path, debug=args.debug) + run_linker(obj_path, args.output, debug=args.debug) print(f"[info] built {args.output}") return 0