commit 0144208765bd20759c266409ba65da1c33fc5152
parent 2348316509a4db74a1563384cde7bb91dc7b4215
Author: Lorenz (xha) <me@xha.li>
Date: Thu, 25 Jan 2024 10:12:34 +0100
debug: partial +openbsd support
Diffstat:
15 files changed, 103 insertions(+), 25 deletions(-)
diff --git a/debug/+freebsd/translate.ha b/debug/+freebsd/translate.ha
@@ -0,0 +1,12 @@
+// SPDX-License-Identifier: MPL-2.0
+// (c) Hare authors <https://harelang.org>
+
+use rt;
+use types::c;
+
+// Tries to translate a pointer into an ELF address of the currently running
+// binary.
+export fn translate(ptr: uintptr) (uintptr | void) = {
+ // TODO FreeBSD (will break when enabling PIE code)
+ return ptr;
+};
diff --git a/debug/+linux/translate.ha b/debug/+linux/translate.ha
@@ -0,0 +1,12 @@
+// SPDX-License-Identifier: MPL-2.0
+// (c) Hare authors <https://harelang.org>
+
+use rt;
+use types::c;
+
+// Tries to translate a pointer into an ELF address of the currently running
+// binary.
+export fn translate(ptr: uintptr) (uintptr | void) = {
+ // TODO Linux (will break when enabling PIE code)
+ return ptr;
+};
diff --git a/debug/+openbsd/translate.ha b/debug/+openbsd/translate.ha
@@ -0,0 +1,24 @@
+// SPDX-License-Identifier: MPL-2.0
+// (c) Hare authors <https://harelang.org>
+
+use rt;
+use types::c;
+
+// Tries to translate a pointer into an ELF address of the currently running
+// binary.
+export fn translate(ptr: uintptr) (uintptr | void) = {
+ let dl_info = rt::dl_info { ... };
+
+ // In order to avoid translating symbols in shared libaries and
+ // producing invalid results, use the current function (which should be
+ // in the main binary) to get the base image address.
+ //
+ // Theoretically, it should be possible to get symbol names from shared
+ // libaries. You would have to load the ELF shared libary at the path
+ // [[dl_info.fname]] as an ELF image and resolve the symbol name
+ // from there. Then you could do "s/&translate/ptr" below.
+ const ret = rt::dladdr(&translate: *opaque, &dl_info);
+ if (ret != 0) {
+ return ptr - dl_info.fbase: uintptr;
+ };
+};
diff --git a/debug/backtrace.ha b/debug/backtrace.ha
@@ -64,6 +64,14 @@ fn printframe(
) void = {
const pc = frame_pc(frame);
+ // Try to translate the address
+ match (translate(pc: uintptr)) {
+ case let ptr: uintptr =>
+ pc = ptr;
+ case =>
+ void;
+ };
+
const sym = match (symbol_byaddr(self, pc)) {
case let sym: elf::sym64 =>
yield sym;
diff --git a/debug/fault.ha b/debug/fault.ha
@@ -15,7 +15,7 @@ def ALTSTACK_SIZE: size = 16384;
@init fn init_overflow() void = {
rt::sigaltstack(&rt::stack_t {
- ss_sp = &altstack,
+ ss_sp = rt::malloc(ALTSTACK_SIZE): *opaque,
ss_flags = 0,
ss_size = ALTSTACK_SIZE,
}, null)!;
diff --git a/makefiles/freebsd.aarch64.mk b/makefiles/freebsd.aarch64.mk
@@ -4,13 +4,13 @@ TDENV = env HARE_TD_rt=$(HARECACHE)/rt.td HARE_TD_encoding::utf8=$(HARECACHE)/en
RTSCRIPT = rt/+freebsd/hare.sc
OBJS = $(HARECACHE)/rt.o $(HARECACHE)/encoding_utf8.o $(HARECACHE)/types.o $(HARECACHE)/bytes.o $(HARECACHE)/sort_cmp.o $(HARECACHE)/strings.o $(HARECACHE)/ascii.o $(HARECACHE)/errors.o $(HARECACHE)/io.o $(HARECACHE)/bufio.o $(HARECACHE)/crypto_math.o $(HARECACHE)/endian.o $(HARECACHE)/hash.o $(HARECACHE)/crypto_sha256.o $(HARECACHE)/math.o $(HARECACHE)/memio.o $(HARECACHE)/path.o $(HARECACHE)/time.o $(HARECACHE)/fs.o $(HARECACHE)/types_c.o $(HARECACHE)/os.o $(HARECACHE)/strconv.o $(HARECACHE)/fmt.o $(HARECACHE)/encoding_hex.o $(HARECACHE)/sort.o $(HARECACHE)/hare_lex.o $(HARECACHE)/hare_ast.o $(HARECACHE)/hare_parse.o $(HARECACHE)/hare_unparse.o $(HARECACHE)/time_chrono.o $(HARECACHE)/time_date.o $(HARECACHE)/hare_module.o $(HARECACHE)/unix.o $(HARECACHE)/unix_signal.o $(HARECACHE)/os_exec.o $(HARECACHE)/shlex.o $(HARECACHE)/unix_tty.o $(HARECACHE)/cmd_hare_build.o $(HARECACHE)/dirs.o $(HARECACHE)/getopt.o $(HARECACHE)/cmd_hare.o
-rt_ha = rt/+aarch64/arch_jmp.ha rt/+aarch64/backtrace.ha rt/+aarch64/cpuid.ha rt/+freebsd/+aarch64.ha rt/+freebsd/env.ha rt/+freebsd/errno.ha rt/+freebsd/initfini.ha rt/+freebsd/platform_abort.ha rt/+freebsd/platformstart-libc.ha rt/+freebsd/segmalloc.ha rt/+freebsd/signal.ha rt/+freebsd/socket.ha rt/+freebsd/start.ha rt/+freebsd/syscallno.ha rt/+freebsd/syscalls.ha rt/+freebsd/types.ha rt/abort.ha rt/ensure.ha rt/fenv_defs.ha rt/jmp.ha rt/malloc.ha rt/memcpy.ha rt/memfunc_ptr.ha rt/memmove.ha rt/memset.ha rt/strcmp.ha rt/u64tos.ha rt/unknown_errno.ha
+rt_ha = rt/+aarch64/arch_jmp.ha rt/+aarch64/cpuid.ha rt/+freebsd/+aarch64.ha rt/+freebsd/env.ha rt/+freebsd/errno.ha rt/+freebsd/initfini.ha rt/+freebsd/platform_abort.ha rt/+freebsd/platformstart-libc.ha rt/+freebsd/segmalloc.ha rt/+freebsd/signal.ha rt/+freebsd/socket.ha rt/+freebsd/start.ha rt/+freebsd/syscallno.ha rt/+freebsd/syscalls.ha rt/+freebsd/types.ha rt/abort.ha rt/ensure.ha rt/fenv_defs.ha rt/jmp.ha rt/malloc.ha rt/memcpy.ha rt/memfunc_ptr.ha rt/memmove.ha rt/memset.ha rt/strcmp.ha rt/u64tos.ha rt/unknown_errno.ha
$(HARECACHE)/rt.ssa: $(rt_ha)
@mkdir -p -- "$(HARECACHE)"
@printf 'HAREC\t%s\n' "$@"
@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/rt.ssa -t $(HARECACHE)/rt.td.tmp -N rt $(rt_ha)
-rt_s = $(HARECACHE)/rt.s rt/+aarch64/cpuid.s rt/+aarch64/fenv.s rt/+aarch64/getfp.s rt/+aarch64/longjmp.s rt/+aarch64/setjmp.s rt/+freebsd/start+aarch64-libc.s rt/+freebsd/syscall+aarch64.s
+rt_s = $(HARECACHE)/rt.s rt/+aarch64/cpuid.s rt/+aarch64/fenv.s rt/+aarch64/longjmp.s rt/+aarch64/setjmp.s rt/+freebsd/start+aarch64-libc.s rt/+freebsd/syscall+aarch64.s
$(HARECACHE)/rt.o: $(rt_s)
@printf 'AS\t%s\n' "$@"
@$(AS) $(ASFLAGS) -o $@ $(rt_s)
@@ -214,7 +214,7 @@ $(HARECACHE)/unix_signal.ssa: $(unix_signal_ha) $(HARECACHE)/io.td $(HARECACHE)/
@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/unix_signal.ssa -t $(HARECACHE)/unix_signal.td.tmp -N unix::signal $(unix_signal_ha)
os_exec_ha = os/exec/+freebsd/exec.ha os/exec/+freebsd/platform_cmd.ha os/exec/+freebsd/process.ha os/exec/cmd.ha os/exec/types.ha
-$(HARECACHE)/os_exec.ssa: $(os_exec_ha) $(HARECACHE)/ascii.td $(HARECACHE)/errors.td $(HARECACHE)/fmt.td $(HARECACHE)/fs.td $(HARECACHE)/io.td $(HARECACHE)/os.td $(HARECACHE)/rt.td $(HARECACHE)/strings.td $(HARECACHE)/time.td $(HARECACHE)/types_c.td $(HARECACHE)/unix.td $(HARECACHE)/unix_signal.td
+$(HARECACHE)/os_exec.ssa: $(os_exec_ha) $(HARECACHE)/ascii.td $(HARECACHE)/errors.td $(HARECACHE)/fmt.td $(HARECACHE)/fs.td $(HARECACHE)/io.td $(HARECACHE)/os.td $(HARECACHE)/path.td $(HARECACHE)/rt.td $(HARECACHE)/strings.td $(HARECACHE)/time.td $(HARECACHE)/types_c.td $(HARECACHE)/unix.td $(HARECACHE)/unix_signal.td
@mkdir -p -- "$(HARECACHE)"
@printf 'HAREC\t%s\n' "$@"
@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/os_exec.ssa -t $(HARECACHE)/os_exec.td.tmp -N os::exec $(os_exec_ha)
diff --git a/makefiles/freebsd.riscv64.mk b/makefiles/freebsd.riscv64.mk
@@ -4,13 +4,13 @@ TDENV = env HARE_TD_rt=$(HARECACHE)/rt.td HARE_TD_encoding::utf8=$(HARECACHE)/en
RTSCRIPT = rt/+freebsd/hare.sc
OBJS = $(HARECACHE)/rt.o $(HARECACHE)/encoding_utf8.o $(HARECACHE)/types.o $(HARECACHE)/bytes.o $(HARECACHE)/sort_cmp.o $(HARECACHE)/strings.o $(HARECACHE)/ascii.o $(HARECACHE)/errors.o $(HARECACHE)/io.o $(HARECACHE)/bufio.o $(HARECACHE)/crypto_math.o $(HARECACHE)/endian.o $(HARECACHE)/hash.o $(HARECACHE)/crypto_sha256.o $(HARECACHE)/math.o $(HARECACHE)/memio.o $(HARECACHE)/path.o $(HARECACHE)/time.o $(HARECACHE)/fs.o $(HARECACHE)/types_c.o $(HARECACHE)/os.o $(HARECACHE)/strconv.o $(HARECACHE)/fmt.o $(HARECACHE)/encoding_hex.o $(HARECACHE)/sort.o $(HARECACHE)/hare_lex.o $(HARECACHE)/hare_ast.o $(HARECACHE)/hare_parse.o $(HARECACHE)/hare_unparse.o $(HARECACHE)/time_chrono.o $(HARECACHE)/time_date.o $(HARECACHE)/hare_module.o $(HARECACHE)/unix.o $(HARECACHE)/unix_signal.o $(HARECACHE)/os_exec.o $(HARECACHE)/shlex.o $(HARECACHE)/unix_tty.o $(HARECACHE)/cmd_hare_build.o $(HARECACHE)/dirs.o $(HARECACHE)/getopt.o $(HARECACHE)/cmd_hare.o
-rt_ha = rt/+freebsd/+riscv64.ha rt/+freebsd/env.ha rt/+freebsd/errno.ha rt/+freebsd/initfini.ha rt/+freebsd/platform_abort.ha rt/+freebsd/platformstart-libc.ha rt/+freebsd/segmalloc.ha rt/+freebsd/signal.ha rt/+freebsd/socket.ha rt/+freebsd/start.ha rt/+freebsd/syscallno.ha rt/+freebsd/syscalls.ha rt/+freebsd/types.ha rt/+riscv64/arch_jmp.ha rt/+riscv64/backtrace.ha rt/+riscv64/cpuid.ha rt/abort.ha rt/ensure.ha rt/fenv_defs.ha rt/jmp.ha rt/malloc.ha rt/memcpy.ha rt/memfunc_ptr.ha rt/memmove.ha rt/memset.ha rt/strcmp.ha rt/u64tos.ha rt/unknown_errno.ha
+rt_ha = rt/+freebsd/+riscv64.ha rt/+freebsd/env.ha rt/+freebsd/errno.ha rt/+freebsd/initfini.ha rt/+freebsd/platform_abort.ha rt/+freebsd/platformstart-libc.ha rt/+freebsd/segmalloc.ha rt/+freebsd/signal.ha rt/+freebsd/socket.ha rt/+freebsd/start.ha rt/+freebsd/syscallno.ha rt/+freebsd/syscalls.ha rt/+freebsd/types.ha rt/+riscv64/arch_jmp.ha rt/+riscv64/cpuid.ha rt/abort.ha rt/ensure.ha rt/fenv_defs.ha rt/jmp.ha rt/malloc.ha rt/memcpy.ha rt/memfunc_ptr.ha rt/memmove.ha rt/memset.ha rt/strcmp.ha rt/u64tos.ha rt/unknown_errno.ha
$(HARECACHE)/rt.ssa: $(rt_ha)
@mkdir -p -- "$(HARECACHE)"
@printf 'HAREC\t%s\n' "$@"
@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/rt.ssa -t $(HARECACHE)/rt.td.tmp -N rt $(rt_ha)
-rt_s = $(HARECACHE)/rt.s rt/+freebsd/start+riscv64-libc.s rt/+freebsd/syscall+riscv64.s rt/+riscv64/cpuid.s rt/+riscv64/fenv.s rt/+riscv64/getfp.s rt/+riscv64/longjmp.s rt/+riscv64/setjmp.s
+rt_s = $(HARECACHE)/rt.s rt/+freebsd/start+riscv64-libc.s rt/+freebsd/syscall+riscv64.s rt/+riscv64/cpuid.s rt/+riscv64/fenv.s rt/+riscv64/longjmp.s rt/+riscv64/setjmp.s
$(HARECACHE)/rt.o: $(rt_s)
@printf 'AS\t%s\n' "$@"
@$(AS) $(ASFLAGS) -o $@ $(rt_s)
@@ -214,7 +214,7 @@ $(HARECACHE)/unix_signal.ssa: $(unix_signal_ha) $(HARECACHE)/io.td $(HARECACHE)/
@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/unix_signal.ssa -t $(HARECACHE)/unix_signal.td.tmp -N unix::signal $(unix_signal_ha)
os_exec_ha = os/exec/+freebsd/exec.ha os/exec/+freebsd/platform_cmd.ha os/exec/+freebsd/process.ha os/exec/cmd.ha os/exec/types.ha
-$(HARECACHE)/os_exec.ssa: $(os_exec_ha) $(HARECACHE)/ascii.td $(HARECACHE)/errors.td $(HARECACHE)/fmt.td $(HARECACHE)/fs.td $(HARECACHE)/io.td $(HARECACHE)/os.td $(HARECACHE)/rt.td $(HARECACHE)/strings.td $(HARECACHE)/time.td $(HARECACHE)/types_c.td $(HARECACHE)/unix.td $(HARECACHE)/unix_signal.td
+$(HARECACHE)/os_exec.ssa: $(os_exec_ha) $(HARECACHE)/ascii.td $(HARECACHE)/errors.td $(HARECACHE)/fmt.td $(HARECACHE)/fs.td $(HARECACHE)/io.td $(HARECACHE)/os.td $(HARECACHE)/path.td $(HARECACHE)/rt.td $(HARECACHE)/strings.td $(HARECACHE)/time.td $(HARECACHE)/types_c.td $(HARECACHE)/unix.td $(HARECACHE)/unix_signal.td
@mkdir -p -- "$(HARECACHE)"
@printf 'HAREC\t%s\n' "$@"
@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/os_exec.ssa -t $(HARECACHE)/os_exec.td.tmp -N os::exec $(os_exec_ha)
diff --git a/makefiles/freebsd.x86_64.mk b/makefiles/freebsd.x86_64.mk
@@ -4,13 +4,13 @@ TDENV = env HARE_TD_rt=$(HARECACHE)/rt.td HARE_TD_encoding::utf8=$(HARECACHE)/en
RTSCRIPT = rt/+freebsd/hare.sc
OBJS = $(HARECACHE)/rt.o $(HARECACHE)/encoding_utf8.o $(HARECACHE)/types.o $(HARECACHE)/bytes.o $(HARECACHE)/sort_cmp.o $(HARECACHE)/strings.o $(HARECACHE)/ascii.o $(HARECACHE)/errors.o $(HARECACHE)/io.o $(HARECACHE)/bufio.o $(HARECACHE)/crypto_math.o $(HARECACHE)/endian.o $(HARECACHE)/hash.o $(HARECACHE)/crypto_sha256.o $(HARECACHE)/math.o $(HARECACHE)/memio.o $(HARECACHE)/path.o $(HARECACHE)/time.o $(HARECACHE)/fs.o $(HARECACHE)/types_c.o $(HARECACHE)/os.o $(HARECACHE)/strconv.o $(HARECACHE)/fmt.o $(HARECACHE)/encoding_hex.o $(HARECACHE)/sort.o $(HARECACHE)/hare_lex.o $(HARECACHE)/hare_ast.o $(HARECACHE)/hare_parse.o $(HARECACHE)/hare_unparse.o $(HARECACHE)/time_chrono.o $(HARECACHE)/time_date.o $(HARECACHE)/hare_module.o $(HARECACHE)/unix.o $(HARECACHE)/unix_signal.o $(HARECACHE)/os_exec.o $(HARECACHE)/shlex.o $(HARECACHE)/unix_tty.o $(HARECACHE)/cmd_hare_build.o $(HARECACHE)/dirs.o $(HARECACHE)/getopt.o $(HARECACHE)/cmd_hare.o
-rt_ha = rt/+freebsd/+x86_64.ha rt/+freebsd/env.ha rt/+freebsd/errno.ha rt/+freebsd/initfini.ha rt/+freebsd/platform_abort.ha rt/+freebsd/platformstart-libc.ha rt/+freebsd/segmalloc.ha rt/+freebsd/signal.ha rt/+freebsd/socket.ha rt/+freebsd/start.ha rt/+freebsd/syscallno.ha rt/+freebsd/syscalls.ha rt/+freebsd/types.ha rt/+x86_64/arch_jmp.ha rt/+x86_64/backtrace.ha rt/+x86_64/cpuid.ha rt/abort.ha rt/ensure.ha rt/fenv_defs.ha rt/jmp.ha rt/malloc.ha rt/memcpy.ha rt/memfunc_ptr.ha rt/memmove.ha rt/memset.ha rt/strcmp.ha rt/u64tos.ha rt/unknown_errno.ha
+rt_ha = rt/+freebsd/+x86_64.ha rt/+freebsd/env.ha rt/+freebsd/errno.ha rt/+freebsd/initfini.ha rt/+freebsd/platform_abort.ha rt/+freebsd/platformstart-libc.ha rt/+freebsd/segmalloc.ha rt/+freebsd/signal.ha rt/+freebsd/socket.ha rt/+freebsd/start.ha rt/+freebsd/syscallno.ha rt/+freebsd/syscalls.ha rt/+freebsd/types.ha rt/+x86_64/arch_jmp.ha rt/+x86_64/cpuid.ha rt/abort.ha rt/ensure.ha rt/fenv_defs.ha rt/jmp.ha rt/malloc.ha rt/memcpy.ha rt/memfunc_ptr.ha rt/memmove.ha rt/memset.ha rt/strcmp.ha rt/u64tos.ha rt/unknown_errno.ha
$(HARECACHE)/rt.ssa: $(rt_ha)
@mkdir -p -- "$(HARECACHE)"
@printf 'HAREC\t%s\n' "$@"
@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/rt.ssa -t $(HARECACHE)/rt.td.tmp -N rt $(rt_ha)
-rt_s = $(HARECACHE)/rt.s rt/+freebsd/start+x86_64-libc.s rt/+freebsd/syscall+x86_64.s rt/+x86_64/cpuid.s rt/+x86_64/fenv.s rt/+x86_64/getfp.s rt/+x86_64/longjmp.s rt/+x86_64/setjmp.s
+rt_s = $(HARECACHE)/rt.s rt/+freebsd/start+x86_64-libc.s rt/+freebsd/syscall+x86_64.s rt/+x86_64/cpuid.s rt/+x86_64/fenv.s rt/+x86_64/longjmp.s rt/+x86_64/setjmp.s
$(HARECACHE)/rt.o: $(rt_s)
@printf 'AS\t%s\n' "$@"
@$(AS) $(ASFLAGS) -o $@ $(rt_s)
@@ -214,7 +214,7 @@ $(HARECACHE)/unix_signal.ssa: $(unix_signal_ha) $(HARECACHE)/io.td $(HARECACHE)/
@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/unix_signal.ssa -t $(HARECACHE)/unix_signal.td.tmp -N unix::signal $(unix_signal_ha)
os_exec_ha = os/exec/+freebsd/exec.ha os/exec/+freebsd/platform_cmd.ha os/exec/+freebsd/process.ha os/exec/cmd.ha os/exec/types.ha
-$(HARECACHE)/os_exec.ssa: $(os_exec_ha) $(HARECACHE)/ascii.td $(HARECACHE)/errors.td $(HARECACHE)/fmt.td $(HARECACHE)/fs.td $(HARECACHE)/io.td $(HARECACHE)/os.td $(HARECACHE)/rt.td $(HARECACHE)/strings.td $(HARECACHE)/time.td $(HARECACHE)/types_c.td $(HARECACHE)/unix.td $(HARECACHE)/unix_signal.td
+$(HARECACHE)/os_exec.ssa: $(os_exec_ha) $(HARECACHE)/ascii.td $(HARECACHE)/errors.td $(HARECACHE)/fmt.td $(HARECACHE)/fs.td $(HARECACHE)/io.td $(HARECACHE)/os.td $(HARECACHE)/path.td $(HARECACHE)/rt.td $(HARECACHE)/strings.td $(HARECACHE)/time.td $(HARECACHE)/types_c.td $(HARECACHE)/unix.td $(HARECACHE)/unix_signal.td
@mkdir -p -- "$(HARECACHE)"
@printf 'HAREC\t%s\n' "$@"
@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/os_exec.ssa -t $(HARECACHE)/os_exec.td.tmp -N os::exec $(os_exec_ha)
diff --git a/makefiles/linux.aarch64.mk b/makefiles/linux.aarch64.mk
@@ -4,13 +4,13 @@ TDENV = env HARE_TD_rt=$(HARECACHE)/rt.td HARE_TD_encoding::utf8=$(HARECACHE)/en
RTSCRIPT = rt/+linux/hare.sc
OBJS = $(HARECACHE)/rt.o $(HARECACHE)/encoding_utf8.o $(HARECACHE)/types.o $(HARECACHE)/bytes.o $(HARECACHE)/sort_cmp.o $(HARECACHE)/strings.o $(HARECACHE)/ascii.o $(HARECACHE)/errors.o $(HARECACHE)/io.o $(HARECACHE)/bufio.o $(HARECACHE)/crypto_math.o $(HARECACHE)/endian.o $(HARECACHE)/hash.o $(HARECACHE)/crypto_sha256.o $(HARECACHE)/math.o $(HARECACHE)/memio.o $(HARECACHE)/path.o $(HARECACHE)/format_elf.o $(HARECACHE)/linux.o $(HARECACHE)/types_c.o $(HARECACHE)/linux_vdso.o $(HARECACHE)/time.o $(HARECACHE)/fs.o $(HARECACHE)/os.o $(HARECACHE)/strconv.o $(HARECACHE)/fmt.o $(HARECACHE)/encoding_hex.o $(HARECACHE)/sort.o $(HARECACHE)/hare_lex.o $(HARECACHE)/hare_ast.o $(HARECACHE)/hare_parse.o $(HARECACHE)/hare_unparse.o $(HARECACHE)/time_chrono.o $(HARECACHE)/time_date.o $(HARECACHE)/hare_module.o $(HARECACHE)/unix.o $(HARECACHE)/unix_signal.o $(HARECACHE)/os_exec.o $(HARECACHE)/shlex.o $(HARECACHE)/unix_tty.o $(HARECACHE)/cmd_hare_build.o $(HARECACHE)/dirs.o $(HARECACHE)/getopt.o $(HARECACHE)/cmd_hare.o
-rt_ha = rt/+aarch64/arch_jmp.ha rt/+aarch64/backtrace.ha rt/+aarch64/cpuid.ha rt/+linux/+aarch64.ha rt/+linux/env.ha rt/+linux/errno.ha rt/+linux/initfini.ha rt/+linux/platform_abort.ha rt/+linux/platformstart-libc.ha rt/+linux/prctl.ha rt/+linux/segmalloc.ha rt/+linux/signal.ha rt/+linux/socket.ha rt/+linux/start.ha rt/+linux/stat.ha rt/+linux/syscallno+aarch64.ha rt/+linux/syscalls.ha rt/+linux/types.ha rt/abort.ha rt/ensure.ha rt/fenv_defs.ha rt/jmp.ha rt/malloc.ha rt/memcpy.ha rt/memfunc_ptr.ha rt/memmove.ha rt/memset.ha rt/strcmp.ha rt/u64tos.ha rt/unknown_errno.ha
+rt_ha = rt/+aarch64/arch_jmp.ha rt/+aarch64/cpuid.ha rt/+linux/+aarch64.ha rt/+linux/env.ha rt/+linux/errno.ha rt/+linux/initfini.ha rt/+linux/platform_abort.ha rt/+linux/platformstart-libc.ha rt/+linux/prctl.ha rt/+linux/segmalloc.ha rt/+linux/signal.ha rt/+linux/socket.ha rt/+linux/start.ha rt/+linux/stat.ha rt/+linux/syscallno+aarch64.ha rt/+linux/syscalls.ha rt/+linux/types.ha rt/abort.ha rt/ensure.ha rt/fenv_defs.ha rt/jmp.ha rt/malloc.ha rt/memcpy.ha rt/memfunc_ptr.ha rt/memmove.ha rt/memset.ha rt/strcmp.ha rt/u64tos.ha rt/unknown_errno.ha
$(HARECACHE)/rt.ssa: $(rt_ha)
@mkdir -p -- "$(HARECACHE)"
@printf 'HAREC\t%s\n' "$@"
@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/rt.ssa -t $(HARECACHE)/rt.td.tmp -N rt $(rt_ha)
-rt_s = $(HARECACHE)/rt.s rt/+aarch64/cpuid.s rt/+aarch64/fenv.s rt/+aarch64/getfp.s rt/+aarch64/longjmp.s rt/+aarch64/setjmp.s rt/+linux/restore+aarch64.s rt/+linux/start+aarch64-libc.s rt/+linux/syscall+aarch64.s
+rt_s = $(HARECACHE)/rt.s rt/+aarch64/cpuid.s rt/+aarch64/fenv.s rt/+aarch64/longjmp.s rt/+aarch64/setjmp.s rt/+linux/restore+aarch64.s rt/+linux/start+aarch64-libc.s rt/+linux/syscall+aarch64.s
$(HARECACHE)/rt.o: $(rt_s)
@printf 'AS\t%s\n' "$@"
@$(AS) $(ASFLAGS) -o $@ $(rt_s)
@@ -232,7 +232,7 @@ $(HARECACHE)/unix_signal.ssa: $(unix_signal_ha) $(HARECACHE)/errors.td $(HARECAC
@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/unix_signal.ssa -t $(HARECACHE)/unix_signal.td.tmp -N unix::signal $(unix_signal_ha)
os_exec_ha = os/exec/+linux/exec.ha os/exec/+linux/platform_cmd.ha os/exec/+linux/process.ha os/exec/cmd.ha os/exec/types.ha
-$(HARECACHE)/os_exec.ssa: $(os_exec_ha) $(HARECACHE)/ascii.td $(HARECACHE)/errors.td $(HARECACHE)/fmt.td $(HARECACHE)/fs.td $(HARECACHE)/io.td $(HARECACHE)/os.td $(HARECACHE)/rt.td $(HARECACHE)/strings.td $(HARECACHE)/time.td $(HARECACHE)/types_c.td $(HARECACHE)/unix.td $(HARECACHE)/unix_signal.td
+$(HARECACHE)/os_exec.ssa: $(os_exec_ha) $(HARECACHE)/ascii.td $(HARECACHE)/errors.td $(HARECACHE)/fmt.td $(HARECACHE)/fs.td $(HARECACHE)/io.td $(HARECACHE)/os.td $(HARECACHE)/path.td $(HARECACHE)/rt.td $(HARECACHE)/strings.td $(HARECACHE)/time.td $(HARECACHE)/types_c.td $(HARECACHE)/unix.td $(HARECACHE)/unix_signal.td
@mkdir -p -- "$(HARECACHE)"
@printf 'HAREC\t%s\n' "$@"
@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/os_exec.ssa -t $(HARECACHE)/os_exec.td.tmp -N os::exec $(os_exec_ha)
diff --git a/makefiles/linux.riscv64.mk b/makefiles/linux.riscv64.mk
@@ -4,13 +4,13 @@ TDENV = env HARE_TD_rt=$(HARECACHE)/rt.td HARE_TD_encoding::utf8=$(HARECACHE)/en
RTSCRIPT = rt/+linux/hare.sc
OBJS = $(HARECACHE)/rt.o $(HARECACHE)/encoding_utf8.o $(HARECACHE)/types.o $(HARECACHE)/bytes.o $(HARECACHE)/sort_cmp.o $(HARECACHE)/strings.o $(HARECACHE)/ascii.o $(HARECACHE)/errors.o $(HARECACHE)/io.o $(HARECACHE)/bufio.o $(HARECACHE)/crypto_math.o $(HARECACHE)/endian.o $(HARECACHE)/hash.o $(HARECACHE)/crypto_sha256.o $(HARECACHE)/math.o $(HARECACHE)/memio.o $(HARECACHE)/path.o $(HARECACHE)/format_elf.o $(HARECACHE)/linux.o $(HARECACHE)/types_c.o $(HARECACHE)/linux_vdso.o $(HARECACHE)/time.o $(HARECACHE)/fs.o $(HARECACHE)/os.o $(HARECACHE)/strconv.o $(HARECACHE)/fmt.o $(HARECACHE)/encoding_hex.o $(HARECACHE)/sort.o $(HARECACHE)/hare_lex.o $(HARECACHE)/hare_ast.o $(HARECACHE)/hare_parse.o $(HARECACHE)/hare_unparse.o $(HARECACHE)/time_chrono.o $(HARECACHE)/time_date.o $(HARECACHE)/hare_module.o $(HARECACHE)/unix.o $(HARECACHE)/unix_signal.o $(HARECACHE)/os_exec.o $(HARECACHE)/shlex.o $(HARECACHE)/unix_tty.o $(HARECACHE)/cmd_hare_build.o $(HARECACHE)/dirs.o $(HARECACHE)/getopt.o $(HARECACHE)/cmd_hare.o
-rt_ha = rt/+linux/+riscv64.ha rt/+linux/env.ha rt/+linux/errno.ha rt/+linux/initfini.ha rt/+linux/platform_abort.ha rt/+linux/platformstart-libc.ha rt/+linux/prctl.ha rt/+linux/segmalloc.ha rt/+linux/signal.ha rt/+linux/socket.ha rt/+linux/start.ha rt/+linux/stat.ha rt/+linux/syscallno+riscv64.ha rt/+linux/syscalls.ha rt/+linux/types.ha rt/+riscv64/arch_jmp.ha rt/+riscv64/backtrace.ha rt/+riscv64/cpuid.ha rt/abort.ha rt/ensure.ha rt/fenv_defs.ha rt/jmp.ha rt/malloc.ha rt/memcpy.ha rt/memfunc_ptr.ha rt/memmove.ha rt/memset.ha rt/strcmp.ha rt/u64tos.ha rt/unknown_errno.ha
+rt_ha = rt/+linux/+riscv64.ha rt/+linux/env.ha rt/+linux/errno.ha rt/+linux/initfini.ha rt/+linux/platform_abort.ha rt/+linux/platformstart-libc.ha rt/+linux/prctl.ha rt/+linux/segmalloc.ha rt/+linux/signal.ha rt/+linux/socket.ha rt/+linux/start.ha rt/+linux/stat.ha rt/+linux/syscallno+riscv64.ha rt/+linux/syscalls.ha rt/+linux/types.ha rt/+riscv64/arch_jmp.ha rt/+riscv64/cpuid.ha rt/abort.ha rt/ensure.ha rt/fenv_defs.ha rt/jmp.ha rt/malloc.ha rt/memcpy.ha rt/memfunc_ptr.ha rt/memmove.ha rt/memset.ha rt/strcmp.ha rt/u64tos.ha rt/unknown_errno.ha
$(HARECACHE)/rt.ssa: $(rt_ha)
@mkdir -p -- "$(HARECACHE)"
@printf 'HAREC\t%s\n' "$@"
@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/rt.ssa -t $(HARECACHE)/rt.td.tmp -N rt $(rt_ha)
-rt_s = $(HARECACHE)/rt.s rt/+linux/restore+riscv64.s rt/+linux/start+riscv64-libc.s rt/+linux/syscall+riscv64.s rt/+riscv64/cpuid.s rt/+riscv64/fenv.s rt/+riscv64/getfp.s rt/+riscv64/longjmp.s rt/+riscv64/setjmp.s
+rt_s = $(HARECACHE)/rt.s rt/+linux/restore+riscv64.s rt/+linux/start+riscv64-libc.s rt/+linux/syscall+riscv64.s rt/+riscv64/cpuid.s rt/+riscv64/fenv.s rt/+riscv64/longjmp.s rt/+riscv64/setjmp.s
$(HARECACHE)/rt.o: $(rt_s)
@printf 'AS\t%s\n' "$@"
@$(AS) $(ASFLAGS) -o $@ $(rt_s)
@@ -232,7 +232,7 @@ $(HARECACHE)/unix_signal.ssa: $(unix_signal_ha) $(HARECACHE)/errors.td $(HARECAC
@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/unix_signal.ssa -t $(HARECACHE)/unix_signal.td.tmp -N unix::signal $(unix_signal_ha)
os_exec_ha = os/exec/+linux/exec.ha os/exec/+linux/platform_cmd.ha os/exec/+linux/process.ha os/exec/cmd.ha os/exec/types.ha
-$(HARECACHE)/os_exec.ssa: $(os_exec_ha) $(HARECACHE)/ascii.td $(HARECACHE)/errors.td $(HARECACHE)/fmt.td $(HARECACHE)/fs.td $(HARECACHE)/io.td $(HARECACHE)/os.td $(HARECACHE)/rt.td $(HARECACHE)/strings.td $(HARECACHE)/time.td $(HARECACHE)/types_c.td $(HARECACHE)/unix.td $(HARECACHE)/unix_signal.td
+$(HARECACHE)/os_exec.ssa: $(os_exec_ha) $(HARECACHE)/ascii.td $(HARECACHE)/errors.td $(HARECACHE)/fmt.td $(HARECACHE)/fs.td $(HARECACHE)/io.td $(HARECACHE)/os.td $(HARECACHE)/path.td $(HARECACHE)/rt.td $(HARECACHE)/strings.td $(HARECACHE)/time.td $(HARECACHE)/types_c.td $(HARECACHE)/unix.td $(HARECACHE)/unix_signal.td
@mkdir -p -- "$(HARECACHE)"
@printf 'HAREC\t%s\n' "$@"
@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/os_exec.ssa -t $(HARECACHE)/os_exec.td.tmp -N os::exec $(os_exec_ha)
diff --git a/makefiles/linux.x86_64.mk b/makefiles/linux.x86_64.mk
@@ -4,13 +4,13 @@ TDENV = env HARE_TD_rt=$(HARECACHE)/rt.td HARE_TD_encoding::utf8=$(HARECACHE)/en
RTSCRIPT = rt/+linux/hare.sc
OBJS = $(HARECACHE)/rt.o $(HARECACHE)/encoding_utf8.o $(HARECACHE)/types.o $(HARECACHE)/bytes.o $(HARECACHE)/sort_cmp.o $(HARECACHE)/strings.o $(HARECACHE)/ascii.o $(HARECACHE)/errors.o $(HARECACHE)/io.o $(HARECACHE)/bufio.o $(HARECACHE)/crypto_math.o $(HARECACHE)/endian.o $(HARECACHE)/hash.o $(HARECACHE)/crypto_sha256.o $(HARECACHE)/math.o $(HARECACHE)/memio.o $(HARECACHE)/path.o $(HARECACHE)/format_elf.o $(HARECACHE)/linux.o $(HARECACHE)/types_c.o $(HARECACHE)/linux_vdso.o $(HARECACHE)/time.o $(HARECACHE)/fs.o $(HARECACHE)/os.o $(HARECACHE)/strconv.o $(HARECACHE)/fmt.o $(HARECACHE)/encoding_hex.o $(HARECACHE)/sort.o $(HARECACHE)/hare_lex.o $(HARECACHE)/hare_ast.o $(HARECACHE)/hare_parse.o $(HARECACHE)/hare_unparse.o $(HARECACHE)/time_chrono.o $(HARECACHE)/time_date.o $(HARECACHE)/hare_module.o $(HARECACHE)/unix.o $(HARECACHE)/unix_signal.o $(HARECACHE)/os_exec.o $(HARECACHE)/shlex.o $(HARECACHE)/unix_tty.o $(HARECACHE)/cmd_hare_build.o $(HARECACHE)/dirs.o $(HARECACHE)/getopt.o $(HARECACHE)/cmd_hare.o
-rt_ha = rt/+linux/+x86_64.ha rt/+linux/env.ha rt/+linux/errno.ha rt/+linux/initfini.ha rt/+linux/platform_abort.ha rt/+linux/platformstart-libc.ha rt/+linux/prctl.ha rt/+linux/segmalloc.ha rt/+linux/signal.ha rt/+linux/socket.ha rt/+linux/start.ha rt/+linux/stat.ha rt/+linux/syscallno+x86_64.ha rt/+linux/syscalls.ha rt/+linux/types.ha rt/+x86_64/arch_jmp.ha rt/+x86_64/backtrace.ha rt/+x86_64/cpuid.ha rt/abort.ha rt/ensure.ha rt/fenv_defs.ha rt/jmp.ha rt/malloc.ha rt/memcpy.ha rt/memfunc_ptr.ha rt/memmove.ha rt/memset.ha rt/strcmp.ha rt/u64tos.ha rt/unknown_errno.ha
+rt_ha = rt/+linux/+x86_64.ha rt/+linux/env.ha rt/+linux/errno.ha rt/+linux/initfini.ha rt/+linux/platform_abort.ha rt/+linux/platformstart-libc.ha rt/+linux/prctl.ha rt/+linux/segmalloc.ha rt/+linux/signal.ha rt/+linux/socket.ha rt/+linux/start.ha rt/+linux/stat.ha rt/+linux/syscallno+x86_64.ha rt/+linux/syscalls.ha rt/+linux/types.ha rt/+x86_64/arch_jmp.ha rt/+x86_64/cpuid.ha rt/abort.ha rt/ensure.ha rt/fenv_defs.ha rt/jmp.ha rt/malloc.ha rt/memcpy.ha rt/memfunc_ptr.ha rt/memmove.ha rt/memset.ha rt/strcmp.ha rt/u64tos.ha rt/unknown_errno.ha
$(HARECACHE)/rt.ssa: $(rt_ha)
@mkdir -p -- "$(HARECACHE)"
@printf 'HAREC\t%s\n' "$@"
@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/rt.ssa -t $(HARECACHE)/rt.td.tmp -N rt $(rt_ha)
-rt_s = $(HARECACHE)/rt.s rt/+linux/restore+x86_64.s rt/+linux/start+x86_64-libc.s rt/+linux/syscall+x86_64.s rt/+x86_64/cpuid.s rt/+x86_64/fenv.s rt/+x86_64/getfp.s rt/+x86_64/longjmp.s rt/+x86_64/setjmp.s
+rt_s = $(HARECACHE)/rt.s rt/+linux/restore+x86_64.s rt/+linux/start+x86_64-libc.s rt/+linux/syscall+x86_64.s rt/+x86_64/cpuid.s rt/+x86_64/fenv.s rt/+x86_64/longjmp.s rt/+x86_64/setjmp.s
$(HARECACHE)/rt.o: $(rt_s)
@printf 'AS\t%s\n' "$@"
@$(AS) $(ASFLAGS) -o $@ $(rt_s)
@@ -232,7 +232,7 @@ $(HARECACHE)/unix_signal.ssa: $(unix_signal_ha) $(HARECACHE)/errors.td $(HARECAC
@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/unix_signal.ssa -t $(HARECACHE)/unix_signal.td.tmp -N unix::signal $(unix_signal_ha)
os_exec_ha = os/exec/+linux/exec.ha os/exec/+linux/platform_cmd.ha os/exec/+linux/process.ha os/exec/cmd.ha os/exec/types.ha
-$(HARECACHE)/os_exec.ssa: $(os_exec_ha) $(HARECACHE)/ascii.td $(HARECACHE)/errors.td $(HARECACHE)/fmt.td $(HARECACHE)/fs.td $(HARECACHE)/io.td $(HARECACHE)/os.td $(HARECACHE)/rt.td $(HARECACHE)/strings.td $(HARECACHE)/time.td $(HARECACHE)/types_c.td $(HARECACHE)/unix.td $(HARECACHE)/unix_signal.td
+$(HARECACHE)/os_exec.ssa: $(os_exec_ha) $(HARECACHE)/ascii.td $(HARECACHE)/errors.td $(HARECACHE)/fmt.td $(HARECACHE)/fs.td $(HARECACHE)/io.td $(HARECACHE)/os.td $(HARECACHE)/path.td $(HARECACHE)/rt.td $(HARECACHE)/strings.td $(HARECACHE)/time.td $(HARECACHE)/types_c.td $(HARECACHE)/unix.td $(HARECACHE)/unix_signal.td
@mkdir -p -- "$(HARECACHE)"
@printf 'HAREC\t%s\n' "$@"
@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/os_exec.ssa -t $(HARECACHE)/os_exec.td.tmp -N os::exec $(os_exec_ha)
diff --git a/makefiles/openbsd.aarch64.mk b/makefiles/openbsd.aarch64.mk
@@ -4,13 +4,13 @@ TDENV = env HARE_TD_rt=$(HARECACHE)/rt.td HARE_TD_encoding::utf8=$(HARECACHE)/en
RTSCRIPT = rt/+openbsd/hare.sc
OBJS = $(HARECACHE)/rt.o $(HARECACHE)/encoding_utf8.o $(HARECACHE)/types.o $(HARECACHE)/bytes.o $(HARECACHE)/sort_cmp.o $(HARECACHE)/strings.o $(HARECACHE)/ascii.o $(HARECACHE)/errors.o $(HARECACHE)/io.o $(HARECACHE)/bufio.o $(HARECACHE)/crypto_math.o $(HARECACHE)/endian.o $(HARECACHE)/hash.o $(HARECACHE)/crypto_sha256.o $(HARECACHE)/math.o $(HARECACHE)/memio.o $(HARECACHE)/path.o $(HARECACHE)/time.o $(HARECACHE)/fs.o $(HARECACHE)/types_c.o $(HARECACHE)/os.o $(HARECACHE)/strconv.o $(HARECACHE)/fmt.o $(HARECACHE)/encoding_hex.o $(HARECACHE)/sort.o $(HARECACHE)/hare_lex.o $(HARECACHE)/hare_ast.o $(HARECACHE)/hare_parse.o $(HARECACHE)/hare_unparse.o $(HARECACHE)/time_chrono.o $(HARECACHE)/time_date.o $(HARECACHE)/hare_module.o $(HARECACHE)/unix.o $(HARECACHE)/unix_signal.o $(HARECACHE)/os_exec.o $(HARECACHE)/shlex.o $(HARECACHE)/unix_tty.o $(HARECACHE)/cmd_hare_build.o $(HARECACHE)/dirs.o $(HARECACHE)/getopt.o $(HARECACHE)/cmd_hare.o
-rt_ha = rt/+aarch64/arch_jmp.ha rt/+aarch64/backtrace.ha rt/+aarch64/cpuid.ha rt/+openbsd/env.ha rt/+openbsd/errno.ha rt/+openbsd/libc.ha rt/+openbsd/platform_abort.ha rt/+openbsd/signal.ha rt/+openbsd/socket.ha rt/+openbsd/start.ha rt/+openbsd/syscalls.ha rt/+openbsd/types.ha rt/abort.ha rt/ensure.ha rt/fenv_defs.ha rt/jmp.ha rt/malloc+libc.ha rt/memcpy.ha rt/memfunc_ptr.ha rt/memmove.ha rt/memset.ha rt/strcmp.ha rt/u64tos.ha rt/unknown_errno.ha
+rt_ha = rt/+aarch64/arch_jmp.ha rt/+aarch64/cpuid.ha rt/+openbsd/+aarch64.ha rt/+openbsd/dynamic_linker.ha rt/+openbsd/env.ha rt/+openbsd/errno.ha rt/+openbsd/libc.ha rt/+openbsd/platform_abort.ha rt/+openbsd/signal.ha rt/+openbsd/socket.ha rt/+openbsd/start.ha rt/+openbsd/syscalls.ha rt/+openbsd/types.ha rt/abort.ha rt/ensure.ha rt/fenv_defs.ha rt/jmp.ha rt/malloc+libc.ha rt/memcpy.ha rt/memfunc_ptr.ha rt/memmove.ha rt/memset.ha rt/strcmp.ha rt/u64tos.ha rt/unknown_errno.ha
$(HARECACHE)/rt.ssa: $(rt_ha)
@mkdir -p -- "$(HARECACHE)"
@printf 'HAREC\t%s\n' "$@"
@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/rt.ssa -t $(HARECACHE)/rt.td.tmp -N rt $(rt_ha)
-rt_s = $(HARECACHE)/rt.s rt/+aarch64/cpuid.s rt/+aarch64/fenv.s rt/+aarch64/getfp.s rt/+aarch64/longjmp.s rt/+aarch64/setjmp.s rt/+openbsd/start.s
+rt_s = $(HARECACHE)/rt.s rt/+aarch64/cpuid.s rt/+aarch64/fenv.s rt/+aarch64/longjmp.s rt/+aarch64/setjmp.s rt/+openbsd/start.s
$(HARECACHE)/rt.o: $(rt_s)
@printf 'AS\t%s\n' "$@"
@$(AS) $(ASFLAGS) -o $@ $(rt_s)
diff --git a/makefiles/openbsd.riscv64.mk b/makefiles/openbsd.riscv64.mk
@@ -4,13 +4,13 @@ TDENV = env HARE_TD_rt=$(HARECACHE)/rt.td HARE_TD_encoding::utf8=$(HARECACHE)/en
RTSCRIPT = rt/+openbsd/hare.sc
OBJS = $(HARECACHE)/rt.o $(HARECACHE)/encoding_utf8.o $(HARECACHE)/types.o $(HARECACHE)/bytes.o $(HARECACHE)/sort_cmp.o $(HARECACHE)/strings.o $(HARECACHE)/ascii.o $(HARECACHE)/errors.o $(HARECACHE)/io.o $(HARECACHE)/bufio.o $(HARECACHE)/crypto_math.o $(HARECACHE)/endian.o $(HARECACHE)/hash.o $(HARECACHE)/crypto_sha256.o $(HARECACHE)/math.o $(HARECACHE)/memio.o $(HARECACHE)/path.o $(HARECACHE)/time.o $(HARECACHE)/fs.o $(HARECACHE)/types_c.o $(HARECACHE)/os.o $(HARECACHE)/strconv.o $(HARECACHE)/fmt.o $(HARECACHE)/encoding_hex.o $(HARECACHE)/sort.o $(HARECACHE)/hare_lex.o $(HARECACHE)/hare_ast.o $(HARECACHE)/hare_parse.o $(HARECACHE)/hare_unparse.o $(HARECACHE)/time_chrono.o $(HARECACHE)/time_date.o $(HARECACHE)/hare_module.o $(HARECACHE)/unix.o $(HARECACHE)/unix_signal.o $(HARECACHE)/os_exec.o $(HARECACHE)/shlex.o $(HARECACHE)/unix_tty.o $(HARECACHE)/cmd_hare_build.o $(HARECACHE)/dirs.o $(HARECACHE)/getopt.o $(HARECACHE)/cmd_hare.o
-rt_ha = rt/+openbsd/env.ha rt/+openbsd/errno.ha rt/+openbsd/libc.ha rt/+openbsd/platform_abort.ha rt/+openbsd/signal.ha rt/+openbsd/socket.ha rt/+openbsd/start.ha rt/+openbsd/syscalls.ha rt/+openbsd/types.ha rt/+riscv64/arch_jmp.ha rt/+riscv64/backtrace.ha rt/+riscv64/cpuid.ha rt/abort.ha rt/ensure.ha rt/fenv_defs.ha rt/jmp.ha rt/malloc+libc.ha rt/memcpy.ha rt/memfunc_ptr.ha rt/memmove.ha rt/memset.ha rt/strcmp.ha rt/u64tos.ha rt/unknown_errno.ha
+rt_ha = rt/+openbsd/+riscv64.ha rt/+openbsd/dynamic_linker.ha rt/+openbsd/env.ha rt/+openbsd/errno.ha rt/+openbsd/libc.ha rt/+openbsd/platform_abort.ha rt/+openbsd/signal.ha rt/+openbsd/socket.ha rt/+openbsd/start.ha rt/+openbsd/syscalls.ha rt/+openbsd/types.ha rt/+riscv64/arch_jmp.ha rt/+riscv64/cpuid.ha rt/abort.ha rt/ensure.ha rt/fenv_defs.ha rt/jmp.ha rt/malloc+libc.ha rt/memcpy.ha rt/memfunc_ptr.ha rt/memmove.ha rt/memset.ha rt/strcmp.ha rt/u64tos.ha rt/unknown_errno.ha
$(HARECACHE)/rt.ssa: $(rt_ha)
@mkdir -p -- "$(HARECACHE)"
@printf 'HAREC\t%s\n' "$@"
@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/rt.ssa -t $(HARECACHE)/rt.td.tmp -N rt $(rt_ha)
-rt_s = $(HARECACHE)/rt.s rt/+openbsd/start.s rt/+riscv64/cpuid.s rt/+riscv64/fenv.s rt/+riscv64/getfp.s rt/+riscv64/longjmp.s rt/+riscv64/setjmp.s
+rt_s = $(HARECACHE)/rt.s rt/+openbsd/start.s rt/+riscv64/cpuid.s rt/+riscv64/fenv.s rt/+riscv64/longjmp.s rt/+riscv64/setjmp.s
$(HARECACHE)/rt.o: $(rt_s)
@printf 'AS\t%s\n' "$@"
@$(AS) $(ASFLAGS) -o $@ $(rt_s)
diff --git a/makefiles/openbsd.x86_64.mk b/makefiles/openbsd.x86_64.mk
@@ -4,13 +4,13 @@ TDENV = env HARE_TD_rt=$(HARECACHE)/rt.td HARE_TD_encoding::utf8=$(HARECACHE)/en
RTSCRIPT = rt/+openbsd/hare.sc
OBJS = $(HARECACHE)/rt.o $(HARECACHE)/encoding_utf8.o $(HARECACHE)/types.o $(HARECACHE)/bytes.o $(HARECACHE)/sort_cmp.o $(HARECACHE)/strings.o $(HARECACHE)/ascii.o $(HARECACHE)/errors.o $(HARECACHE)/io.o $(HARECACHE)/bufio.o $(HARECACHE)/crypto_math.o $(HARECACHE)/endian.o $(HARECACHE)/hash.o $(HARECACHE)/crypto_sha256.o $(HARECACHE)/math.o $(HARECACHE)/memio.o $(HARECACHE)/path.o $(HARECACHE)/time.o $(HARECACHE)/fs.o $(HARECACHE)/types_c.o $(HARECACHE)/os.o $(HARECACHE)/strconv.o $(HARECACHE)/fmt.o $(HARECACHE)/encoding_hex.o $(HARECACHE)/sort.o $(HARECACHE)/hare_lex.o $(HARECACHE)/hare_ast.o $(HARECACHE)/hare_parse.o $(HARECACHE)/hare_unparse.o $(HARECACHE)/time_chrono.o $(HARECACHE)/time_date.o $(HARECACHE)/hare_module.o $(HARECACHE)/unix.o $(HARECACHE)/unix_signal.o $(HARECACHE)/os_exec.o $(HARECACHE)/shlex.o $(HARECACHE)/unix_tty.o $(HARECACHE)/cmd_hare_build.o $(HARECACHE)/dirs.o $(HARECACHE)/getopt.o $(HARECACHE)/cmd_hare.o
-rt_ha = rt/+openbsd/env.ha rt/+openbsd/errno.ha rt/+openbsd/libc.ha rt/+openbsd/platform_abort.ha rt/+openbsd/signal.ha rt/+openbsd/socket.ha rt/+openbsd/start.ha rt/+openbsd/syscalls.ha rt/+openbsd/types.ha rt/+x86_64/arch_jmp.ha rt/+x86_64/backtrace.ha rt/+x86_64/cpuid.ha rt/abort.ha rt/ensure.ha rt/fenv_defs.ha rt/jmp.ha rt/malloc+libc.ha rt/memcpy.ha rt/memfunc_ptr.ha rt/memmove.ha rt/memset.ha rt/strcmp.ha rt/u64tos.ha rt/unknown_errno.ha
+rt_ha = rt/+openbsd/+x86_64.ha rt/+openbsd/dynamic_linker.ha rt/+openbsd/env.ha rt/+openbsd/errno.ha rt/+openbsd/libc.ha rt/+openbsd/platform_abort.ha rt/+openbsd/signal.ha rt/+openbsd/socket.ha rt/+openbsd/start.ha rt/+openbsd/syscalls.ha rt/+openbsd/types.ha rt/+x86_64/arch_jmp.ha rt/+x86_64/cpuid.ha rt/abort.ha rt/ensure.ha rt/fenv_defs.ha rt/jmp.ha rt/malloc+libc.ha rt/memcpy.ha rt/memfunc_ptr.ha rt/memmove.ha rt/memset.ha rt/strcmp.ha rt/u64tos.ha rt/unknown_errno.ha
$(HARECACHE)/rt.ssa: $(rt_ha)
@mkdir -p -- "$(HARECACHE)"
@printf 'HAREC\t%s\n' "$@"
@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/rt.ssa -t $(HARECACHE)/rt.td.tmp -N rt $(rt_ha)
-rt_s = $(HARECACHE)/rt.s rt/+openbsd/start.s rt/+x86_64/cpuid.s rt/+x86_64/fenv.s rt/+x86_64/getfp.s rt/+x86_64/longjmp.s rt/+x86_64/setjmp.s
+rt_s = $(HARECACHE)/rt.s rt/+openbsd/start.s rt/+x86_64/cpuid.s rt/+x86_64/fenv.s rt/+x86_64/longjmp.s rt/+x86_64/setjmp.s
$(HARECACHE)/rt.o: $(rt_s)
@printf 'AS\t%s\n' "$@"
@$(AS) $(ASFLAGS) -o $@ $(rt_s)
diff --git a/rt/+openbsd/dynamic_linker.ha b/rt/+openbsd/dynamic_linker.ha
@@ -0,0 +1,22 @@
+// SPDX-License-Identifier: MPL-2.0
+// (c) Hare authors <https://harelang.org>
+
+// Functions and types for interacting with the dynamic linker.
+export type dl_info = struct {
+ fname: nullable *u8,
+ fbase: nullable *opaque,
+ sname: nullable *u8,
+ saddr: nullable *opaque,
+};
+
+// dlopen
+// dlclose
+// dlsym
+// dladdr
+
+export @symbol("dladdr") fn dladdr(addr: *opaque, info: *dl_info) int;
+
+// dlctl
+// dlerror
+
+export @symbol("dlerror") fn dlerror() nullable *const u8;