From a6d44ec5e0fefb990cf3de7d2f338b341c1f3530 Mon Sep 17 00:00:00 2001 From: Toni Date: Fri, 5 Jun 2026 20:24:50 +0200 Subject: [PATCH] calculate needed stack space with a disgusting hack --- examples/puzzles/aoc2024_07.zr | 2 +- src/codegen_x86_64.rs | 15 +++++++++------ src/main.rs | 2 +- src/std/{syscalls.zr => linux_constants.zr} | 14 +++++++++++++- src/std/std.zr | 21 ++++----------------- 5 files changed, 28 insertions(+), 26 deletions(-) rename src/std/{syscalls.zr => linux_constants.zr} (97%) diff --git a/examples/puzzles/aoc2024_07.zr b/examples/puzzles/aoc2024_07.zr index 35986df..91f8b71 100644 --- a/examples/puzzles/aoc2024_07.zr +++ b/examples/puzzles/aoc2024_07.zr @@ -1,5 +1,5 @@ func concat[a: i64, b: i64] : i64 - ab_str := _stackalloc(50) + ab_str := _stackalloc(50) as str io.snprintf(ab_str, 50, "%d%d", a, b) return str.parse_i64(ab_str) diff --git a/src/codegen_x86_64.rs b/src/codegen_x86_64.rs index 33d6e13..52bf49b 100644 --- a/src/codegen_x86_64.rs +++ b/src/codegen_x86_64.rs @@ -12,8 +12,6 @@ struct Var { pub var_type: String, } -const STACK_SIZE: usize = 256; // TODO: eww - pub struct Env { scopes: Vec>, next_offset: usize, @@ -173,9 +171,8 @@ _start: mov [rax], rdx ; align stack and rsp, -16 - ; main() + ; exit(main()) call main - ; exit mov rdi, rax mov rax, 60 syscall @@ -354,8 +351,9 @@ _builtin_environ: emit!(&mut self.output, "{}:", name.lexeme); emit!(&mut self.output, " push rbp"); emit!(&mut self.output, " mov rbp, rsp"); - let stack_size = (STACK_SIZE + 15) & !15; - emit!(&mut self.output, " sub rsp, {}", stack_size); + + let prologue_offset = self.output.len(); + emit!(&mut self.output, " sub rsp, {:<10}", 0); match params { Params::Normal(params) => { @@ -399,6 +397,11 @@ _builtin_environ: emit!(&mut self.output, " pop rbp"); emit!(&mut self.output, " ret"); } + + // patch the stack size after we know how much we actually need + let patch = format!(" sub rsp, {:<10}", (env.next_offset + 15) & !15); + self.output + .replace_range(prologue_offset..prologue_offset + patch.len(), &patch); } Stmt::Return { keyword: _, exprs } => { if exprs.len() == 2 { diff --git a/src/main.rs b/src/main.rs index 2d3ce4a..cc10322 100644 --- a/src/main.rs +++ b/src/main.rs @@ -35,9 +35,9 @@ fn compile_file(args: Args) -> Result<(), ZernError> { let mut statements = Vec::new(); if args.include_stdlib { - parse_std_file!(statements, "std/syscalls.zr"); parse_std_file!(statements, "std/std.zr"); parse_std_file!(statements, "std/net.zr"); + parse_std_file!(statements, "std/linux_constants.zr"); } let tokenizer = tokenizer::Tokenizer::new(filename.to_owned(), source); diff --git a/src/std/syscalls.zr b/src/std/linux_constants.zr similarity index 97% rename from src/std/syscalls.zr rename to src/std/linux_constants.zr index 3d5c8b2..3bbff16 100644 --- a/src/std/syscalls.zr +++ b/src/std/linux_constants.zr @@ -1,4 +1,16 @@ -// https://github.com/torvalds/linux/blob/19272b37aa4f83ca52bdf9c16d5d81bdd1354494/arch/x86/entry/syscalls/syscall_64.tbl +const S_IFDIR = 0o040000 +const S_IFMT = 0o170000 +const PROT_READ = 1 +const PROT_WRITE = 2 +const MAP_PRIVATE = 2 +const MAP_ANONYMOUS = 32 +const O_RDONLY = 0 +const O_WRONLY = 1 +const O_CREAT = 64 +const O_TRUNC = 512 +const SEEK_SET = 0 +const SEEK_END = 2 + const SYS_read = 0 const SYS_write = 1 const SYS_open = 2 diff --git a/src/std/std.zr b/src/std/std.zr index 625cacf..590104c 100644 --- a/src/std/std.zr +++ b/src/std/std.zr @@ -1,16 +1,3 @@ -const S_IFDIR = 0o040000 -const S_IFMT = 0o170000 -const PROT_READ = 1 -const PROT_WRITE = 2 -const MAP_PRIVATE = 2 -const MAP_ANONYMOUS = 32 -const O_RDONLY = 0 -const O_WRONLY = 1 -const O_CREAT = 64 -const O_TRUNC = 512 -const SEEK_SET = 0 -const SEEK_END = 2 - func panic[msg: str] : void io.print("PANIC: ") io.println(msg) @@ -26,7 +13,7 @@ struct mem.Block next: mem.Block prev: mem.Block -func mem._align[x: i64] : i64 +func mem.align[x: i64] : i64 return (x + 7) & -8 func mem._split_block[blk: mem.Block, needed: i64] : void @@ -70,7 +57,7 @@ func mem.alloc[size: i64] : ptr if size <= 0 panic("mem.alloc: called with nonpositive size") - size = mem._align(size) + size = mem.align(size) cur := mem.read64(_builtin_heap_head()) as mem.Block while cur as ptr @@ -145,7 +132,7 @@ func mem.realloc[x: ptr, new_size: i64] : ptr mem.free(x) return 0 as ptr - new_size = mem._align(new_size) + new_size = mem.align(new_size) blk := (x - MEM_BLOCK_SIZE) as mem.Block if blk->size >= new_size @@ -1081,7 +1068,7 @@ func os.run_shell_command[command: str] : i64, bool if pid == 0 argv := ["sh", "-c", command, 0] // gets freed after child process exits _builtin_syscall(SYS_execve, "/bin/sh", argv->data, _builtin_environ()) - _builtin_syscall(SYS_exit, 1) + os.exit(1) else status := 0 wp := _builtin_syscall(SYS_wait4, pid, ^status, 0, 0)