This commit is contained in:
nub31
2025-06-15 00:50:31 +02:00
parent 6121334ab2
commit 6d3c241368
8 changed files with 209 additions and 129 deletions

View File

@@ -14,12 +14,14 @@
<ProjectReference Include="..\Syntax\Syntax.csproj" /> <ProjectReference Include="..\Syntax\Syntax.csproj" />
</ItemGroup> </ItemGroup>
<ItemGroup>
</ItemGroup>
<ItemGroup> <ItemGroup>
<EmbeddedResource Include="Runtime\entry.s" /> <EmbeddedResource Include="Runtime\entry.s" />
<EmbeddedResource Include="Runtime\nub_memcpy.s" /> <EmbeddedResource Include="Runtime\nub_mem.s" />
<EmbeddedResource Include="Runtime\nub_memset.s" />
<EmbeddedResource Include="Runtime\nub_panic.s" /> <EmbeddedResource Include="Runtime\nub_panic.s" />
<EmbeddedResource Include="Runtime\nub_strcmp.s" /> <EmbeddedResource Include="Runtime\nub_string.s" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@@ -1,63 +1,61 @@
.intel_syntax noprefix .intel_syntax noprefix
.extern main
.section .text
.global _start .equ SYS_EXIT, 60
.text
.globl _start
_start: _start:
# On entry, the stack contains: mov rdi, [rsp] # rdi = argc
# [rsp] = argc (argument count)
# [rsp+8] = argv[0] (program name)
# [rsp+16] = argv[1] (first argument)
# ...
# Get argc from stack # Calculate the size of the array
mov rdi, [rsp] # rdi = argc mov rax, rdi # Start with argc
shl rax, 3 # Multiply argc by 8
add rax, 8 # Add space for the array size
# Calculate space needed for our array structure # Allocate array size on the stack (aligned to 16 bytes)
# We need: 8 bytes (length) + argc * 8 bytes (pointers) add rax, 15
mov rax, rdi # rax = argc and rax, -16
shl rax, 3 # rax = argc * 8 (each pointer is 8 bytes) sub rsp, rax
add rax, 8 # rax = 8 + argc * 8 (add space for length)
# Allocate space on stack (align to 16 bytes) # Store number of elements at the start of the array
add rax, 15 # Round up to nearest 16 mov [rsp], rdi
and rax, -16 # Align to 16 bytes
sub rsp, rax # Allocate space
# Store array length at beginning mov rcx, rdi # rcx = loop counter
mov [rsp], rdi # Store argc as array length lea rsi, [rsp + rax + 8] # rsi = argv[0]
lea rdi, [rsp + 8] # rdi = destination_array[0]
# Copy argv pointers to our array convert_loop:
lea rsi, [rsp + 8] # rsi points to start of argv in stack test rcx, rcx
lea rdi, [rsp + 8] # rdi points to our array data (after length) jz done_converting
mov rcx, [rsp] # rcx = argc (loop counter)
copy_loop: # Convert current cstring using nub_cstring_to_string
test rcx, rcx # Check if we're done push rcx # Save loop counter
jz done_copying push rsi # Save argv[i]
push rdi # Save destination_array[i]
mov rax, [rsi] # Load argv[i] pointer mov rdi, [rsi] # Load current argv[i] (cstring)
mov [rdi], rax # Store in our array call nub_cstring_to_string
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: pop rdi # Restore destination pointer
# Now rsp points to our array: [length][ptr0][ptr1]...[ptrN-1] pop rsi # Restore argv pointer
mov rdi, rsp # Pass array pointer to main 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 call main
mov rdi, rax
# Clean up stack (restore original rsp) mov rax, SYS_EXIT
# 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
syscall syscall
conversion_failed:
call nub_panic

View File

@@ -1,8 +1,15 @@
.intel_syntax noprefix .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 # func nub_memset(destination: ^u8, value: i8, count: u64): ^u8
.global nub_memset
nub_memset: nub_memset:
push rdi push rdi
mov rcx, rdx mov rcx, rdx

View File

@@ -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

View File

@@ -1,19 +1,47 @@
.intel_syntax noprefix .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 .align 8
array_out_of_bounds: array_oob_msg:
.ascii "Index is out of bounds of array\n" .ascii "Index is out of bounds of array\n"
.section .text .data
.global nub_panic_array_oob .align 8
nub_panic_array_oob: oom_msg:
mov rax, 1 # syscall = sys_write .ascii "Out of memory\n"
mov rdi, 2 # fd = stderr
lea rsi, [rip + array_out_of_bounds] # message .text
mov rdx, 32 # message length .globl nub_panic
nub_panic:
mov rax, SYS_EXIT
mov rdi, NUB_PANIC_ERROR_CODE
syscall syscall
mov rax, 60 # sys_exit .text
mov rdi, 101 # exit code .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 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

View File

@@ -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

View File

@@ -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

View File

@@ -849,12 +849,6 @@ public static class QBEGenerator
return outputName; 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)) if (binaryExpression.Left.Type.Equals(NubPrimitiveType.Bool))
{ {
_builder.AppendLine($" {outputName} =w ceqw {left}, {right}"); _builder.AppendLine($" {outputName} =w ceqw {left}, {right}");
@@ -877,13 +871,6 @@ public static class QBEGenerator
return outputName; 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)) if (binaryExpression.Left.Type.Equals(NubPrimitiveType.Bool))
{ {
_builder.AppendLine($" {outputName} =w cnew {left}, {right}"); _builder.AppendLine($" {outputName} =w cnew {left}, {right}");