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}");