diff --git a/src/CLI/CLI.csproj b/src/CLI/CLI.csproj index 85d1ac5..b1f4bc4 100644 --- a/src/CLI/CLI.csproj +++ b/src/CLI/CLI.csproj @@ -14,12 +14,14 @@ + + + - - + - + diff --git a/src/CLI/Runtime/entry.s b/src/CLI/Runtime/entry.s index 9c66ed7..d8a2312 100644 --- a/src/CLI/Runtime/entry.s +++ b/src/CLI/Runtime/entry.s @@ -1,63 +1,61 @@ .intel_syntax noprefix -.extern main -.section .text -.global _start +.equ SYS_EXIT, 60 + +.text +.globl _start _start: - # On entry, the stack contains: - # [rsp] = argc (argument count) - # [rsp+8] = argv[0] (program name) - # [rsp+16] = argv[1] (first argument) - # ... - - # Get argc from stack - mov rdi, [rsp] # rdi = argc - - # Calculate space needed for our array structure - # We need: 8 bytes (length) + argc * 8 bytes (pointers) - mov rax, rdi # rax = argc - shl rax, 3 # rax = argc * 8 (each pointer is 8 bytes) - add rax, 8 # rax = 8 + argc * 8 (add space for length) - - # Allocate space on stack (align to 16 bytes) - add rax, 15 # Round up to nearest 16 - and rax, -16 # Align to 16 bytes - sub rsp, rax # Allocate space - - # Store array length at beginning - mov [rsp], rdi # Store argc as array length - - # Copy argv pointers to our array - lea rsi, [rsp + 8] # rsi points to start of argv in stack - lea rdi, [rsp + 8] # rdi points to our array data (after length) - mov rcx, [rsp] # rcx = argc (loop counter) - -copy_loop: - test rcx, rcx # Check if we're done - jz done_copying - - mov rax, [rsi] # Load argv[i] pointer - mov [rdi], rax # Store in our array - add rsi, 8 # Move to next argv entry - add rdi, 8 # Move to next array slot - dec rcx # Decrement counter - jmp copy_loop - -done_copying: - # Now rsp points to our array: [length][ptr0][ptr1]...[ptrN-1] - mov rdi, rsp # Pass array pointer to main + mov rdi, [rsp] # rdi = argc + + # Calculate the size of the array + mov rax, rdi # Start with argc + shl rax, 3 # Multiply argc by 8 + add rax, 8 # Add space for the array size + + # Allocate array size on the stack (aligned to 16 bytes) + add rax, 15 + and rax, -16 + sub rsp, rax + + # Store number of elements at the start of the array + mov [rsp], rdi + + mov rcx, rdi # rcx = loop counter + lea rsi, [rsp + rax + 8] # rsi = argv[0] + lea rdi, [rsp + 8] # rdi = destination_array[0] + +convert_loop: + test rcx, rcx + jz done_converting + + # Convert current cstring using nub_cstring_to_string + push rcx # Save loop counter + push rsi # Save argv[i] + push rdi # Save destination_array[i] + + mov rdi, [rsi] # Load current argv[i] (cstring) + call nub_cstring_to_string + + pop rdi # Restore destination pointer + pop rsi # Restore argv pointer + pop rcx # Restore loop counter + + test rax, rax + jz conversion_failed + + # Store converted string pointer in our array + mov [rdi], rax # Store converted string pointer + add rdi, 8 # Move to next destination_array entry + add rsi, 8 # Move to next argv entry + dec rcx # Decrement counter + jmp convert_loop + +done_converting: + mov rdi, rsp call main - - # Clean up stack (restore original rsp) - # Calculate how much we allocated - mov rdi, [rsp] # Get argc back - shl rdi, 3 # argc * 8 - add rdi, 8 # + 8 for length - add rdi, 15 # Round up - and rdi, -16 # Align - add rsp, rdi # Restore stack - - # Exit with main's return value - mov rdi, rax # rax contains main's return value - mov rax, 60 # sys_exit + mov rdi, rax + mov rax, SYS_EXIT syscall + +conversion_failed: + call nub_panic diff --git a/src/CLI/Runtime/nub_memset.s b/src/CLI/Runtime/nub_mem.s similarity index 65% rename from src/CLI/Runtime/nub_memset.s rename to src/CLI/Runtime/nub_mem.s index 4c29263..d2b5f72 100644 --- a/src/CLI/Runtime/nub_memset.s +++ b/src/CLI/Runtime/nub_mem.s @@ -1,8 +1,15 @@ .intel_syntax noprefix -.section .text +.text +.globl nub_memcpy +# func nub_memcpy(destination: ^u8, source: ^u8, count: u64): ^u8 +nub_memcpy: + mov rcx, rdx + rep movsb + +.text +.globl nub_memset # func nub_memset(destination: ^u8, value: i8, count: u64): ^u8 -.global nub_memset nub_memset: push rdi mov rcx, rdx diff --git a/src/CLI/Runtime/nub_memcpy.s b/src/CLI/Runtime/nub_memcpy.s deleted file mode 100644 index 9fdf4b6..0000000 --- a/src/CLI/Runtime/nub_memcpy.s +++ /dev/null @@ -1,20 +0,0 @@ -.intel_syntax noprefix -.section .text - -# func nub_memcpy(destination: ^u8, source: ^u8, count: u64): ^u8 -.global nub_memcpy -nub_memcpy: - push rdi - mov rcx, rdx - test rcx, rcx - jz memcpy_done -memcpy_loop: - mov al, BYTE PTR [rsi] - mov BYTE PTR [rdi], al - inc rsi - inc rdi - dec rcx - jnz memcpy_loop -memcpy_done: - pop rax - ret diff --git a/src/CLI/Runtime/nub_panic.s b/src/CLI/Runtime/nub_panic.s index f7a7c73..51332e2 100644 --- a/src/CLI/Runtime/nub_panic.s +++ b/src/CLI/Runtime/nub_panic.s @@ -1,19 +1,47 @@ .intel_syntax noprefix -.section .data +.equ NUB_PANIC_ERROR_CODE, 101 + +.equ SYS_WRITE, 1 +.equ SYS_EXIT, 60 + +.equ FD_STDIN, 0 +.equ FD_STDOUT, 1 +.equ FD_STDERR, 2 + +.data .align 8 -array_out_of_bounds: +array_oob_msg: .ascii "Index is out of bounds of array\n" -.section .text -.global nub_panic_array_oob -nub_panic_array_oob: - mov rax, 1 # syscall = sys_write - mov rdi, 2 # fd = stderr - lea rsi, [rip + array_out_of_bounds] # message - mov rdx, 32 # message length +.data +.align 8 +oom_msg: + .ascii "Out of memory\n" + +.text +.globl nub_panic +nub_panic: + mov rax, SYS_EXIT + mov rdi, NUB_PANIC_ERROR_CODE syscall - mov rax, 60 # sys_exit - mov rdi, 101 # exit code +.text +.globl nub_panic_array_oob +nub_panic_array_oob: + mov rax, SYS_WRITE + mov rdi, FD_STDERR + lea rsi, [rip + array_oob_msg] + mov rdx, 32 syscall + call nub_panic + +.text +.globl nub_panic_oom +nub_panic_oom: + mov rax, SYS_WRITE + mov rdi, FD_STDERR + lea rsi, [rip + oom_msg] + mov rdx, 14 + syscall + call nub_panic diff --git a/src/CLI/Runtime/nub_strcmp.s b/src/CLI/Runtime/nub_strcmp.s deleted file mode 100644 index da502ec..0000000 --- a/src/CLI/Runtime/nub_strcmp.s +++ /dev/null @@ -1,22 +0,0 @@ -.intel_syntax noprefix -.section .text - -# func nub_strcmp(lhs: ^u8, rhs: ^u8): bool -.global nub_strcmp -nub_strcmp: - xor rdx, rdx -strcmp_loop: - mov al, BYTE PTR [rsi + rdx] - mov bl, BYTE PTR [rdi + rdx] - inc rdx - cmp al, bl - jne strcmp_not_equal - cmp al, 0 - je strcmp_equal - jmp strcmp_loop -strcmp_not_equal: - mov rax, 0 - ret -strcmp_equal: - mov rax, 1 - ret diff --git a/src/CLI/Runtime/nub_string.s b/src/CLI/Runtime/nub_string.s new file mode 100644 index 0000000..f6e9205 --- /dev/null +++ b/src/CLI/Runtime/nub_string.s @@ -0,0 +1,100 @@ +.intel_syntax noprefix + +.equ SYS_MMAP, 9 +.equ SYS_MUNMAP, 11 + +.text +.globl nub_strlen +# func nub_strlen(string: cstring): u64 +nub_strlen: + test rdi, rdi + jz null_string + xor rax, rax +strlen_loop: + cmp byte ptr [rdi + rax], 0 + je strlen_exit + inc rax + jmp strlen_loop +null_string: + xor rax, rax +strlen_exit: + ret + +.text +.globl nub_cstring_to_string +# func nub_cstring_to_string(string: cstring): []u8 +nub_cstring_to_string: + push rbx + push r12 + push r13 + + mov rbx, rdi # Save original pointer + call nub_strlen + mov r12, rax # r12 = string length + + # Calculate total space needed: 8 bytes (length) + string length + mov r13, r12 + add r13, 8 # r13 = total bytes needed + + # Round up to page size (4096 bytes) for mmap + add r13, 4095 # Add page_size - 1 + and r13, -4096 # Align to page boundary + + mov rax, SYS_MMAP + xor rdi, rdi # addr = 0 (let kernel choose) + mov rsi, r13 # length = aligned size + mov rdx, 3 # prot = PROT_READ | PROT_WRITE + mov r10, 34 # flags = MAP_PRIVATE | MAP_ANONYMOUS (0x22) + mov r8, -1 # fd = -1 + xor r9, r9 # offset = 0 + syscall + + # Check if mmap failed + cmp rax, -1 + je mmap_failed + + mov r13, rax # r13 = pointer to mapped memory + + # Store length at beginning of mapped memory + mov [r13], r12 # Store string length + + # Copy string data if not empty + test r12, r12 # Check if length is 0 + jz copy_done + + lea rdi, [r13 + 8] + mov rsi, rbx + mov rcx, r12 + call nub_memcpy + +copy_done: + mov rax, r13 + jmp function_exit + +mmap_failed: + xor rax, rax + +function_exit: + pop r13 + pop r12 + pop rbx + ret + +.text +.globl nub_string_free +# func nub_string_free(string: []u8): void +nub_string_free: + test rdi, rdi + jz free_exit + + mov rsi, [rdi] + add rsi, 8 + + # Round up to page size + add rsi, 4095 + and rsi, -4096 + + mov rax, SYS_MUNMAP + syscall +free_exit: + ret diff --git a/src/Generation/QBE/QBEGenerator.cs b/src/Generation/QBE/QBEGenerator.cs index 2489c3e..997d806 100644 --- a/src/Generation/QBE/QBEGenerator.cs +++ b/src/Generation/QBE/QBEGenerator.cs @@ -849,12 +849,6 @@ public static class QBEGenerator return outputName; } - // if (binaryExpression.Left.Type.Equals(NubPrimitiveType.String)) - // { - // _builder.AppendLine($" {outputName} =w call $nub_strcmp(l {left}, l {right})"); - // return outputName; - // } - if (binaryExpression.Left.Type.Equals(NubPrimitiveType.Bool)) { _builder.AppendLine($" {outputName} =w ceqw {left}, {right}"); @@ -877,13 +871,6 @@ public static class QBEGenerator return outputName; } - // if (binaryExpression.Left.Type.Equals(NubPrimitiveType.String)) - // { - // _builder.AppendLine($" {outputName} =w call $nub_strcmp(l {left}, l {right})"); - // _builder.AppendLine($" {outputName} =w xor {outputName}, 1"); - // return outputName; - // } - if (binaryExpression.Left.Type.Equals(NubPrimitiveType.Bool)) { _builder.AppendLine($" {outputName} =w cnew {left}, {right}");