commit 08368a2643f3d8604d7c299089dda3aa5c22dc64
parent fa6d196321fe4e34ed4dc1d084d2c6e6f3ad590b
Author: Brian Callahan <bcallah@posteo.net>
Date: Fri, 29 Apr 2022 03:56:07 +0000
Add OpenBSD port
Signed-off-by: Brian Callahan <bcallah@posteo.net>
Diffstat:
20 files changed, 781 insertions(+), 47 deletions(-)
diff --git a/config.sh b/config.sh
@@ -8,6 +8,11 @@ LDFLAGS=${LDFLAGS:-}
LD=${LD:-ld}
QBE=${QBE:-qbe}
+if [ `uname -s` = "OpenBSD" ]
+then
+ LD="${LD:-ld} -nopie"
+fi
+
for arg
do
case "$arg" in
diff --git a/include/gen.h b/include/gen.h
@@ -83,7 +83,7 @@ void gen(const struct unit *unit,
// genutil.c
char *gen_name(struct gen_context *ctx, const char *fmt);
-struct gen_value mktemp(struct gen_context *ctx,
+struct gen_value mkgtemp(struct gen_context *ctx,
const struct type *type, const char *fmt);
struct qbe_value mkqval(struct gen_context *ctx, struct gen_value *value);
struct qbe_value mklval(struct gen_context *ctx, struct gen_value *value);
diff --git a/rt/+openbsd/errno.ha b/rt/+openbsd/errno.ha
@@ -0,0 +1,97 @@
+export def EPERM: int = 1;
+export def ENOENT: int = 2;
+export def ESRCH: int = 3;
+export def EINTR: int = 4;
+export def EIO: int = 5;
+export def ENXIO: int = 6;
+export def E2BIG: int = 7;
+export def ENOEXEC: int = 8;
+export def EBADF: int = 9;
+export def ECHILD: int = 10;
+export def EDEADLK: int = 11;
+export def ENOMEM: int = 12;
+export def EACCES: int = 13;
+export def EFAULT: int = 14;
+export def ENOTBLK: int = 15;
+export def EBUSY: int = 16;
+export def EEXIST: int = 17;
+export def EXDEV: int = 18;
+export def ENODEV: int = 19;
+export def ENOTDIR: int = 20;
+export def EISDIR: int = 21;
+export def EINVAL: int = 22;
+export def ENFILE: int = 23;
+export def EMFILE: int = 24;
+export def ENOTTY: int = 25;
+export def ETXTBSY: int = 26;
+export def EFBIG: int = 27;
+export def ENOSPC: int = 28;
+export def ESPIPE: int = 29;
+export def EROFS: int = 30;
+export def EMLINK: int = 31;
+export def EPIPE: int = 32;
+export def EDOM: int = 33;
+export def ERANGE: int = 34;
+export def EAGAIN: int = 35;
+export def EWOULDBLOCK: int = EAGAIN;
+export def EINPROGRESS: int = 36;
+export def EALREADY: int = 37;
+export def ENOTSOCK: int = 38;
+export def EDESTADDRREQ: int = 39;
+export def EMSGSIZE: int = 40;
+export def EPROTOTYPE: int = 41;
+export def ENOPROTOOPT: int = 42;
+export def EPROTONOSUPPORT: int = 43;
+export def ESOCKTNOSUPPORT: int = 44;
+export def EOPNOTSUPP: int = 45;
+export def EPFNOSUPPORT: int = 46;
+export def EAFNOSUPPORT: int = 47;
+export def EADDRINUSE: int = 48;
+export def EADDRNOTAVAIL: int = 49;
+export def ENETDOWN: int = 50;
+export def ENETUNREACH: int = 51;
+export def ENETRESET: int = 52;
+export def ECONNABORTED: int = 53;
+export def ECONNRESET: int = 54;
+export def ENOBUFS: int = 55;
+export def EISCONN: int = 56;
+export def ENOTCONN: int = 57;
+export def ESHUTDOWN: int = 58;
+export def ETOOMANYREFS: int = 59;
+export def ETIMEDOUT: int = 60;
+export def ECONNREFUSED: int = 61;
+export def ELOOP: int = 62;
+export def ENAMETOOLONG: int = 63;
+export def EHOSTDOWN: int = 64;
+export def EHOSTUNREACH: int = 65;
+export def ENOTEMPTY: int = 66;
+export def EPROCLIM: int = 67;
+export def EUSERS: int = 68;
+export def EDQUOT: int = 69;
+export def ESTALE: int = 70;
+export def EREMOTE: int = 71;
+export def EBADRPC: int = 72;
+export def ERPCMISMATCH: int = 73;
+export def EPROGUNAVAIL: int = 74;
+export def EPROGMISMATCH: int = 75;
+export def EPROCUNAVAIL: int = 76;
+export def ENOLCK: int = 77;
+export def ENOSYS: int = 78;
+export def EFTYPE: int = 79;
+export def EAUTH: int = 80;
+export def ENEEDAUTH: int = 81;
+export def EIPSEC: int = 82;
+export def ENOATTR: int = 83;
+export def EILSEQ: int = 84;
+export def ENOMEDIUM: int = 85;
+export def EMEDIUMTYPE: int = 86;
+export def EOVERFLOW: int = 87;
+export def ECANCELED: int = 88;
+export def EIDRM: int = 89;
+export def ENOMSG: int = 90;
+export def ENOTSUP: int = 91;
+export def EBADMSG: int = 92;
+export def ENOTRECOVERABLE: int = 93;
+export def EOWNERDEAD: int = 94;
+export def EPROTO: int = 95;
+export def ELAST: int = 95;
diff --git a/rt/+openbsd/segmalloc.ha b/rt/+openbsd/segmalloc.ha
@@ -0,0 +1,10 @@
+// Allocates a segment.
+fn segmalloc(n: size) nullable *void = {
+ let p: *void = mmap(null, n,
+ PROT_READ | PROT_WRITE,
+ MAP_PRIVATE | MAP_ANON, -1, 0);
+ return if (p: uintptr: int == -ENOMEM) null else p;
+};
+
+// Frees a segment allocated with segmalloc.
+fn segfree(p: *void, s: size) int = munmap(p, s);
diff --git a/rt/+openbsd/start+aarch64.s b/rt/+openbsd/start+aarch64.s
@@ -0,0 +1,8 @@
+.text
+.global _start
+_start:
+ mov x29, #0
+ mov x30, #0
+ mov x0, sp
+ add sp, x0, #-16
+ b rt.start_ha
diff --git a/rt/+openbsd/start+riscv64.s b/rt/+openbsd/start+riscv64.s
@@ -0,0 +1,6 @@
+.text
+.global _start
+_start:
+ mv a0, sp
+ andi sp, sp, -16
+ tail rt.start_ha
diff --git a/rt/+openbsd/start+x86_64.s b/rt/+openbsd/start+x86_64.s
@@ -0,0 +1,15 @@
+ .section ".note.openbsd.ident", "a"
+ .p2align 2
+ .long 0x8
+ .long 0x4
+ .long 0x1
+ .asciz "OpenBSD"
+ .long 0x0
+ .previous
+
+.text
+.global _start
+_start:
+ xor %rbp, %rbp
+ movq %rsp, %rdi
+ call rt.start_ha
diff --git a/rt/+openbsd/syscall+aarch64.s b/rt/+openbsd/syscall+aarch64.s
@@ -0,0 +1,69 @@
+.section .text.rt.syscall0
+.global rt.syscall0
+rt.syscall0:
+ mov x8, x0
+ svc 0
+ ret
+
+.section .text.rt.syscall1
+.global rt.syscall1
+rt.syscall1:
+ mov x8, x0
+ mov x0, x1
+ svc 0
+ ret
+
+.section .text.rt.syscall2
+.global rt.syscall2
+rt.syscall2:
+ mov x8, x0
+ mov x0, x1
+ mov x1, x2
+ svc 0
+ ret
+
+.section .text.rt.syscall3
+.global rt.syscall3
+rt.syscall3:
+ mov x8, x0
+ mov x0, x1
+ mov x1, x2
+ mov x2, x3
+ svc 0
+ ret
+
+.section .text.rt.syscall4
+.global rt.syscall4
+rt.syscall4:
+ mov x8, x0
+ mov x0, x1
+ mov x1, x2
+ mov x2, x3
+ mov x3, x4
+ svc 0
+ ret
+
+.section .text.rt.syscall5
+.global rt.syscall5
+rt.syscall5:
+ mov x8, x0
+ mov x0, x1
+ mov x1, x2
+ mov x2, x3
+ mov x3, x4
+ mov x4, x5
+ svc 0
+ ret
+
+.section .text.rt.syscall6
+.global rt.syscall6
+rt.syscall6:
+ mov x8, x0
+ mov x0, x1
+ mov x1, x2
+ mov x2, x3
+ mov x3, x4
+ mov x4, x5
+ mov x5, x6
+ svc 0
+ ret
diff --git a/rt/+openbsd/syscall+riscv64.s b/rt/+openbsd/syscall+riscv64.s
@@ -0,0 +1,69 @@
+.section .text.rt.syscall0
+.global rt.syscall0
+rt.syscall0:
+ mv a7, a0
+ ecall
+ ret
+
+.section .text.rt.syscall1
+.global rt.syscall1
+rt.syscall1:
+ mv a7, a0
+ mv a0, a1
+ ecall
+ ret
+
+.section .text.rt.syscall2
+.global rt.syscall2
+rt.syscall2:
+ mv a7, a0
+ mv a0, a1
+ mv a1, a2
+ ecall
+ ret
+
+.section .text.rt.syscall3
+.global rt.syscall3
+rt.syscall3:
+ mv a7, a0
+ mv a0, a1
+ mv a1, a2
+ mv a2, a3
+ ecall
+ ret
+
+.section .text.rt.syscall4
+.global rt.syscall4
+rt.syscall4:
+ mv a7, a0
+ mv a0, a1
+ mv a1, a2
+ mv a2, a3
+ mv a3, a4
+ ecall
+ ret
+
+.section .text.rt.syscall5
+.global rt.syscall5
+rt.syscall5:
+ mv a7, a0
+ mv a0, a1
+ mv a1, a2
+ mv a2, a3
+ mv a3, a4
+ mv a4, a5
+ ecall
+ ret
+
+.section .text.rt.syscall6
+.global rt.syscall6
+rt.syscall6:
+ mv a7, a0
+ mv a0, a1
+ mv a1, a2
+ mv a2, a3
+ mv a3, a4
+ mv a4, a5
+ mv a5, a6
+ ecall
+ ret
diff --git a/rt/+openbsd/syscall+x86_64.s b/rt/+openbsd/syscall+x86_64.s
@@ -0,0 +1,69 @@
+.section .text.rt.syscall0
+.global rt.syscall0
+rt.syscall0:
+ movq %rdi, %rax
+ syscall
+ ret
+
+.section .text.rt.syscall1
+.global rt.syscall1
+rt.syscall1:
+ movq %rdi, %rax
+ movq %rsi, %rdi
+ syscall
+ ret
+
+.section .text.rt.syscall2
+.global rt.syscall2
+rt.syscall2:
+ movq %rdi, %rax
+ movq %rsi, %rdi
+ movq %rdx, %rsi
+ syscall
+ ret
+
+.section .text.rt.syscall3
+.global rt.syscall3
+rt.syscall3:
+ movq %rdi, %rax
+ movq %rsi, %rdi
+ movq %rdx, %rsi
+ movq %rcx, %rdx
+ syscall
+ ret
+
+.section .text.rt.syscall4
+.global rt.syscall4
+rt.syscall4:
+ movq %rdi, %rax
+ movq %r8, %r10
+ movq %rsi, %rdi
+ movq %rdx, %rsi
+ movq %rcx, %rdx
+ syscall
+ ret
+
+.section .text.rt.syscall5
+.global rt.syscall5
+rt.syscall5:
+ movq %rdi, %rax
+ movq %r8, %r10
+ movq %rsi, %rdi
+ movq %r9, %r8
+ movq %rdx, %rsi
+ movq %rcx, %rdx
+ syscall
+ ret
+
+.section .text.rt.syscall6
+.global rt.syscall6
+rt.syscall6:
+ movq %rdi, %rax
+ movq %r8, %r10
+ movq %rsi, %rdi
+ movq %r9, %r8
+ movq %rdx, %rsi
+ movq 8(%rsp), %r9
+ movq %rcx, %rdx
+ syscall
+ ret
diff --git a/rt/+openbsd/syscallno.ha b/rt/+openbsd/syscallno.ha
@@ -0,0 +1,222 @@
+export def SYS_syscall: u64 = 0;
+export def SYS_exit: u64 = 1;
+export def SYS_fork: u64 = 2;
+export def SYS_read: u64 = 3;
+export def SYS_write: u64 = 4;
+export def SYS_open: u64 = 5;
+export def SYS_close: u64 = 6;
+export def SYS_getentropy: u64 = 7;
+export def SYS___tfork: u64 = 8;
+export def SYS_link: u64 = 9;
+export def SYS_unlink: u64 = 10;
+export def SYS_wait4: u64 = 11;
+export def SYS_chdir: u64 = 12;
+export def SYS_fchdir: u64 = 13;
+export def SYS_mknod: u64 = 14;
+export def SYS_chmod: u64 = 15;
+export def SYS_chown: u64 = 16;
+export def SYS_break: u64 = 17;
+export def SYS_getdtablecount: u64 = 18;
+export def SYS_getrusage: u64 = 19;
+export def SYS_getpid: u64 = 20;
+export def SYS_mount: u64 = 21;
+export def SYS_unmount: u64 = 22;
+export def SYS_setuid: u64 = 23;
+export def SYS_getuid: u64 = 24;
+export def SYS_geteuid: u64 = 25;
+export def SYS_ptrace: u64 = 26;
+export def SYS_recvmsg: u64 = 27;
+export def SYS_sendmsg: u64 = 28;
+export def SYS_recvfrom: u64 = 29;
+export def SYS_accept: u64 = 30;
+export def SYS_getpeername: u64 = 31;
+export def SYS_getsockname: u64 = 32;
+export def SYS_access: u64 = 33;
+export def SYS_chflags: u64 = 34;
+export def SYS_fchflags: u64 = 35;
+export def SYS_sync: u64 = 36;
+export def SYS_msyscall: u64 = 37;
+export def SYS_stat: u64 = 38;
+export def SYS_getppid: u64 = 39;
+export def SYS_lstat: u64 = 40;
+export def SYS_dup: u64 = 41;
+export def SYS_fstatat: u64 = 42;
+export def SYS_getegid: u64 = 43;
+export def SYS_profil: u64 = 44;
+export def SYS_ktrace: u64 = 45;
+export def SYS_sigaction: u64 = 46;
+export def SYS_getgid: u64 = 47;
+export def SYS_sigprocmask: u64 = 48;
+export def SYS_mmap: u64 = 49;
+export def SYS_setlogin: u64 = 50;
+export def SYS_acct: u64 = 51;
+export def SYS_sigpending: u64 = 52;
+export def SYS_fstat: u64 = 53;
+export def SYS_ioctl: u64 = 54;
+export def SYS_reboot: u64 = 55;
+export def SYS_revoke: u64 = 56;
+export def SYS_symlink: u64 = 57;
+export def SYS_readlink: u64 = 58;
+export def SYS_execve: u64 = 59;
+export def SYS_umask: u64 = 60;
+export def SYS_chroot: u64 = 61;
+export def SYS_getfsstat: u64 = 62;
+export def SYS_statfs: u64 = 63;
+export def SYS_fstatfs: u64 = 64;
+export def SYS_fhstatfs: u64 = 65;
+export def SYS_vfork: u64 = 66;
+export def SYS_gettimeofday: u64 = 67;
+export def SYS_settimeofday: u64 = 68;
+export def SYS_setitimer: u64 = 69;
+export def SYS_getitimer: u64 = 70;
+export def SYS_select: u64 = 71;
+export def SYS_kevent: u64 = 72;
+export def SYS_munmap: u64 = 73;
+export def SYS_mprotect: u64 = 74;
+export def SYS_madvise: u64 = 75;
+export def SYS_utimes: u64 = 76;
+export def SYS_futimes: u64 = 77;
+export def SYS_mquery: u64 = 78;
+export def SYS_getgroups: u64 = 79;
+export def SYS_setgroups: u64 = 80;
+export def SYS_getpgrp: u64 = 81;
+export def SYS_setpgid: u64 = 82;
+export def SYS_futex: u64 = 83;
+export def SYS_utimensat: u64 = 84;
+export def SYS_futimens: u64 = 85;
+export def SYS_kbind: u64 = 86;
+export def SYS_clock_gettime: u64 = 87;
+export def SYS_clock_settime: u64 = 88;
+export def SYS_clock_getres: u64 = 89;
+export def SYS_dup2: u64 = 90;
+export def SYS_nanosleep: u64 = 91;
+export def SYS_fcntl: u64 = 92;
+export def SYS_accept4: u64 = 93;
+export def SYS___thrsleep: u64 = 94;
+export def SYS_fsync: u64 = 95;
+export def SYS_setpriority: u64 = 96;
+export def SYS_socket: u64 = 97;
+export def SYS_connect: u64 = 98;
+export def SYS_getdents: u64 = 99;
+export def SYS_getpriority: u64 = 100;
+export def SYS_pipe2: u64 = 101;
+export def SYS_dup3: u64 = 102;
+export def SYS_sigreturn: u64 = 103;
+export def SYS_bind: u64 = 104;
+export def SYS_setsockopt: u64 = 105;
+export def SYS_listen: u64 = 106;
+export def SYS_chflagsat: u64 = 107;
+export def SYS_pledge: u64 = 108;
+export def SYS_ppoll: u64 = 109;
+export def SYS_pselect: u64 = 110;
+export def SYS_sigsuspend: u64 = 111;
+export def SYS_sendsyslog: u64 = 112;
+export def SYS_unveil: u64 = 114;
+export def SYS___realpath: u64 = 115;
+export def SYS_getsockopt: u64 = 118;
+export def SYS_thrkill: u64 = 119;
+export def SYS_readv: u64 = 120;
+export def SYS_writev: u64 = 121;
+export def SYS_kill: u64 = 122;
+export def SYS_fchown: u64 = 123;
+export def SYS_fchmod: u64 = 124;
+export def SYS_setreuid: u64 = 126;
+export def SYS_setregid: u64 = 127;
+export def SYS_rename: u64 = 128;
+export def SYS_flock: u64 = 131;
+export def SYS_mkfifo: u64 = 132;
+export def SYS_sendto: u64 = 133;
+export def SYS_shutdown: u64 = 134;
+export def SYS_socketpair: u64 = 135;
+export def SYS_mkdir: u64 = 136;
+export def SYS_rmdir: u64 = 137;
+export def SYS_adjtime: u64 = 140;
+export def SYS_getlogin_r: u64 = 141;
+export def SYS_setsid: u64 = 147;
+export def SYS_quotactl: u64 = 148;
+export def SYS_nfssvc: u64 = 155;
+export def SYS_getfh: u64 = 161;
+export def SYS___tmpfd: u64 = 164;
+export def SYS_sysarch: u64 = 165;
+export def SYS_lseek: u64 = 166;
+export def SYS_truncate: u64 = 167;
+export def SYS_ftruncate: u64 = 168;
+export def SYS_pread: u64 = 169;
+export def SYS_pwrite: u64 = 170;
+export def SYS_preadv: u64 = 171;
+export def SYS_pwritev: u64 = 172;
+export def SYS_pad_pread: u64 = 173;
+export def SYS_pad_pwrite: u64 = 174;
+export def SYS_setgid: u64 = 181;
+export def SYS_setegid: u64 = 182;
+export def SYS_seteuid: u64 = 183;
+export def SYS_pathconf: u64 = 191;
+export def SYS_fpathconf: u64 = 192;
+export def SYS_swapctl: u64 = 193;
+export def SYS_getrlimit: u64 = 194;
+export def SYS_setrlimit: u64 = 195;
+export def SYS_pad_mmap: u64 = 197;
+export def SYS___syscall: u64 = 198;
+export def SYS_pad_lseek: u64 = 199;
+export def SYS_pad_truncate: u64 = 200;
+export def SYS_pad_ftruncate: u64 = 201;
+export def SYS_sysctl: u64 = 202;
+export def SYS_mlock: u64 = 203;
+export def SYS_munlock: u64 = 204;
+export def SYS_getpgid: u64 = 207;
+export def SYS_utrace: u64 = 209;
+export def SYS_semget: u64 = 221;
+export def SYS_msgget: u64 = 225;
+export def SYS_msgsnd: u64 = 226;
+export def SYS_msgrcv: u64 = 227;
+export def SYS_shmat: u64 = 228;
+export def SYS_shmdt: u64 = 230;
+export def SYS_minherit: u64 = 250;
+export def SYS_poll: u64 = 252;
+export def SYS_issetugid: u64 = 253;
+export def SYS_lchown: u64 = 254;
+export def SYS_getsid: u64 = 255;
+export def SYS_msync: u64 = 256;
+export def SYS_pipe: u64 = 263;
+export def SYS_fhopen: u64 = 264;
+export def SYS_pad_preadv: u64 = 267;
+export def SYS_pad_pwritev: u64 = 268;
+export def SYS_pad_kqueue: u64 = 269;
+export def SYS_mlockall: u64 = 271;
+export def SYS_munlockall: u64 = 272;
+export def SYS_getresuid: u64 = 281;
+export def SYS_setresuid: u64 = 282;
+export def SYS_getresgid: u64 = 283;
+export def SYS_setresgid: u64 = 284;
+export def SYS_pad_mquery: u64 = 286;
+export def SYS_closefrom: u64 = 287;
+export def SYS_sigaltstack: u64 = 288;
+export def SYS_shmget: u64 = 289;
+export def SYS_semop: u64 = 290;
+export def SYS_fhstat: u64 = 294;
+export def SYS___semctl: u64 = 295;
+export def SYS_shmctl: u64 = 296;
+export def SYS_msgctl: u64 = 297;
+export def SYS_sched_yield: u64 = 298;
+export def SYS_getthrid: u64 = 299;
+export def SYS___thrwakeup: u64 = 301;
+export def SYS___threxit: u64 = 302;
+export def SYS___thrsigdivert: u64 = 303;
+export def SYS___getcwd: u64 = 304;
+export def SYS_adjfreq: u64 = 305;
+export def SYS_setrtable: u64 = 310;
+export def SYS_getrtable: u64 = 311;
+export def SYS_faccessat: u64 = 313;
+export def SYS_fchmodat: u64 = 314;
+export def SYS_fchownat: u64 = 315;
+export def SYS_linkat: u64 = 317;
+export def SYS_mkdirat: u64 = 318;
+export def SYS_mkfifoat: u64 = 319;
+export def SYS_mknodat: u64 = 320;
+export def SYS_openat: u64 = 321;
+export def SYS_readlinkat: u64 = 322;
+export def SYS_renameat: u64 = 323;
+export def SYS_symlinkat: u64 = 324;
+export def SYS_unlinkat: u64 = 325;
+export def SYS___set_tcb: u64 = 329;
+export def SYS___get_tcb: u64 = 330;
diff --git a/rt/+openbsd/syscalls.ha b/rt/+openbsd/syscalls.ha
@@ -0,0 +1,81 @@
+fn syscall0(_: u64) u64;
+fn syscall1(_: u64, _: u64) u64;
+fn syscall2(_: u64, _: u64, _: u64) u64;
+fn syscall3(_: u64, _: u64, _: u64, _: u64) u64;
+fn syscall4(_: u64, _: u64, _: u64, _: u64, _: u64) u64;
+fn syscall5(_: u64, _: u64, _: u64, _: u64, _: u64, _: u64) u64;
+fn syscall6(_: u64, _: u64, _: u64, _: u64, _: u64, _: u64, _: u64) u64;
+
+export fn write(fd: int, buf: *const void, count: size) size =
+ syscall3(SYS_write, fd: u64, buf: uintptr: u64, count: u64): size;
+
+export fn close(fd: int) int = syscall1(SYS_close, fd: u64): int;
+
+export fn dup2(old: int, new: int) int =
+ syscall2(SYS_dup2, old: u64, new: u64): int;
+
+export fn getpid() int = syscall0(SYS_getpid): int;
+
+export @noreturn fn exit(status: int) void = { syscall1(SYS_exit, status: u64); };
+
+export fn fork() int = syscall0(SYS_fork): int;
+
+export fn execve(
+ path: *const char,
+ argv: *[*]nullable *const char,
+ envp: *[*]nullable *const char,
+) int = syscall3(SYS_execve,
+ path: uintptr: u64,
+ argv: uintptr: u64,
+ envp: uintptr: u64): int;
+
+export fn wait4(pid: int, status: *int, options: int, rusage: nullable *void) void = {
+ syscall4(SYS_wait4, pid: u64, status: uintptr: u64,
+ options: u64, rusage: uintptr: u64);
+};
+
+export fn wifexited(status: int) bool = wtermsig(status) == 0;
+export fn wexitstatus(status: int) int = (status & 0xff00) >> 8;
+
+export fn wtermsig(status: int) int = status & 0x7f;
+export fn wifsignaled(status: int) bool =
+ wtermsig(status) != 0o177 && wtermsig(status) != 0 && status != 0x13;
+
+export fn kill(pid: int, signal: int) int =
+ syscall2(SYS_kill, pid: u64, signal: u64): int;
+
+export fn pipe2(pipefd: *[2]int, flags: int) int =
+ syscall2(SYS_pipe2, pipefd: uintptr: u64, flags: u64): int;
+
+export def MAP_SHARED: uint = 0x0001;
+export def MAP_PRIVATE: uint = 0x0002;
+export def MAP_FIXED: uint = 0x0010;
+export def __MAP_NOREPLACE: uint = 0x0800;
+export def MAP_ANON: uint = 0x1000;
+export def MAP_ANONYMOUS: uint = MAP_ANON;
+export def __MAP_NOFAULT: uint = 0x2000;
+export def MAP_STACK: uint = 0x4000;
+export def MAP_CONCEAL: uint = 0x8000;
+
+def PROT_NONE: uint = 0x00;
+def PROT_READ: uint = 0x01;
+def PROT_WRITE: uint = 0x02;
+def PROT_EXEC: uint = 0x04;
+
+export fn mmap(
+ addr: nullable *void,
+ length: size,
+ prot: uint,
+ flags: uint,
+ fd: int,
+ offs: size
+) *void = {
+ return syscall6(SYS_mmap, addr: uintptr: u64, length: u64, prot: u64,
+ flags: u64, fd: u64, offs: u64): uintptr: *void;
+};
+
+export fn munmap(addr: *void, length: size) int =
+ syscall2(SYS_munmap, addr: uintptr: u64, length: u64): int;
+
+export def SIGABRT: int = 6;
+export def SIGCHLD: int = 20;
diff --git a/rt/configure b/rt/configure
@@ -48,6 +48,33 @@ rt() {
rt: libhart.a rt/+freebsd/start+$arch.o
EOF
;;
+ OpenBSD)
+ case $arch in
+ amd64)
+ arch=x86_64
+ ;;
+ aarch64|riscv64)
+ ;;
+ *)
+ printf "unsupported OpenBSD arch %s\n" "$(uname)" >&2
+ ;;
+ esac
+ rtstart=rt/+openbsd/start+$arch.o
+ cat <<-EOF
+ rtstart=rt/+openbsd/start+$arch.o
+
+ libhart_srcs=\
+ rt/+openbsd/errno.ha \
+ rt/+openbsd/segmalloc.ha \
+ rt/+openbsd/syscallno.ha \
+ rt/+openbsd/syscalls.ha \
+
+ libhart_objs=\
+ rt/+openbsd/syscall+$arch.o
+
+ rt: libhart.a rt/+openbsd/start+$arch.o
+ EOF
+ ;;
*)
printf "rt not supported for %s\n" "$(uname)" >&2
exit 1
diff --git a/rt/hare+openbsd.sc b/rt/hare+openbsd.sc
@@ -0,0 +1,47 @@
+PHDRS {
+ headers PT_PHDR PHDRS;
+ text PT_LOAD FILEHDR PHDRS;
+ data PT_LOAD;
+ note PT_NOTE;
+}
+ENTRY(_start);
+SECTIONS {
+ . = 0x8000000;
+ .text : {
+ KEEP (*(.text))
+ *(.text.*)
+ } :text
+ . = 0x80000000;
+ .data : {
+ KEEP (*(.data))
+ *(.data.*)
+ } :data
+
+ .init_array : {
+ PROVIDE_HIDDEN (__init_array_start = .);
+ KEEP (*(.init_array))
+ PROVIDE_HIDDEN (__init_array_end = .);
+ } :data
+
+ .fini_array : {
+ PROVIDE_HIDDEN (__fini_array_start = .);
+ KEEP (*(.fini_array))
+ PROVIDE_HIDDEN (__fini_array_end = .);
+ } :data
+
+ .test_array : {
+ PROVIDE_HIDDEN (__test_array_start = .);
+ KEEP (*(.test_array))
+ PROVIDE_HIDDEN (__test_array_end = .);
+ } :data
+
+ .note.openbsd.ident : {
+ KEEP (*(.note.openbsd.ident))
+ *(.note.openbsd.*)
+ } :data :note
+
+ .bss : {
+ KEEP (*(.bss))
+ *(.bss.*)
+ } :data
+}
diff --git a/src/emit.c b/src/emit.c
@@ -1,6 +1,7 @@
#include <assert.h>
#include <ctype.h>
#include <float.h>
+#include <inttypes.h>
#include <stdlib.h>
#include <stdio.h>
#include "emit.h"
@@ -96,7 +97,7 @@ emit_const(struct qbe_value *val, FILE *out)
fprintf(out, "%u", val->wval);
break;
case Q_LONG:
- fprintf(out, "%lu", val->lval);
+ fprintf(out, "%" PRIu64, val->lval);
break;
case Q_SINGLE:
fprintf(out, "s_%.*g", DECIMAL_DIG, val->sval);
diff --git a/src/gen.c b/src/gen.c
@@ -501,7 +501,7 @@ gen_expr_alloc_init_with(struct gen_context *ctx,
objtype = objtype->pointer.referent;
struct qbe_value sz = constl(objtype->size);
- struct gen_value result = mktemp(ctx, expr->result, ".%d");
+ struct gen_value result = mkgtemp(ctx, expr->result, ".%d");
struct qbe_value qresult = mkqval(ctx, &result);
struct qbe_value rtfunc = mkrtfunc(ctx, "rt.malloc");
pushi(ctx->current, &qresult, Q_CALL, &rtfunc, &sz, NULL);
@@ -539,7 +539,7 @@ gen_expr_alloc_slice_with(struct gen_context *ctx,
gen_alloc_slice_at(ctx, expr, *out, expand);
return gv_void;
}
- struct gen_value temp = mktemp(ctx, expr->result, "object.%d");
+ struct gen_value temp = mkgtemp(ctx, expr->result, "object.%d");
struct qbe_value base = mkqval(ctx, &temp);
struct qbe_value sz = constl(expr->result->size);
enum qbe_instr alloc = alloc_for_align(expr->result->align);
@@ -555,7 +555,7 @@ gen_expr_alloc_copy_with(struct gen_context *ctx,
// alloc(init...) case
struct gen_value ret = gv_void;
if (out == NULL) {
- ret = mktemp(ctx, expr->result, "object.%d");
+ ret = mkgtemp(ctx, expr->result, "object.%d");
out = &ret;
struct qbe_value base = mkqval(ctx, out);
@@ -906,7 +906,7 @@ gen_expr_binarithm(struct gen_context *ctx, const struct expression *expr)
{
const struct type *ltype = type_dealias(expr->binarithm.lvalue->result);
const struct type *rtype = type_dealias(expr->binarithm.rvalue->result);
- struct gen_value result = mktemp(ctx, expr->result, ".%d");
+ struct gen_value result = mkgtemp(ctx, expr->result, ".%d");
struct qbe_value qresult = mkqval(ctx, &result);
if (expr->binarithm.op == BIN_LAND || expr->binarithm.op == BIN_LOR) {
@@ -1070,7 +1070,7 @@ gen_expr_call(struct gen_context *ctx, const struct expression *expr)
};
struct gen_value rval = gv_void;
if (type_dealias(rtype->func.result)->storage != STORAGE_VOID) {
- rval = mktemp(ctx, rtype->func.result, "returns.%d");
+ rval = mkgtemp(ctx, rtype->func.result, "returns.%d");
call.out = xcalloc(1, sizeof(struct qbe_value));
*call.out = mkqval(ctx, &rval);
call.out->type = qtype_lookup(ctx, rtype->func.result, false);
@@ -1238,8 +1238,8 @@ gen_expr_cast_tagged_at(struct gen_context *ctx,
subtype = tagged_subset_compat(to, from) ? from : to;
const struct type *innertype = type_store_tagged_to_union(
ctx->store, type_dealias(subtype));
- struct gen_value iout = mktemp(ctx, innertype, ".%d");
- struct gen_value ival = mktemp(ctx, innertype, ".%d");
+ struct gen_value iout = mkgtemp(ctx, innertype, ".%d");
+ struct gen_value ival = mkgtemp(ctx, innertype, ".%d");
struct qbe_value qiout = mkqval(ctx, &iout);
struct qbe_value qival = mkqval(ctx, &ival);
struct qbe_value offs = constl(to->align);
@@ -1259,7 +1259,7 @@ gen_expr_cast_tagged_at(struct gen_context *ctx,
return;
}
- struct gen_value storage = mktemp(ctx, subtype, ".%d");
+ struct gen_value storage = mkgtemp(ctx, subtype, ".%d");
struct qbe_value qstor = mklval(ctx, &storage);
struct qbe_value offs = constl(to->align);
pushi(ctx->current, &qstor, Q_ADD, &qout, &offs, NULL);
@@ -1323,9 +1323,9 @@ gen_expr_cast_array_at(struct gen_context *ctx,
struct qbe_value base = mkqval(ctx, &out);
struct qbe_value offs = constl((typein->array.length - 1) * membtype->size);
- struct gen_value next = mktemp(ctx, membtype, ".%d");
+ struct gen_value next = mkgtemp(ctx, membtype, ".%d");
struct qbe_value ptr = mklval(ctx, &next);
- struct gen_value item = mktemp(ctx, membtype, "item.%d");
+ struct gen_value item = mkgtemp(ctx, membtype, "item.%d");
struct qbe_value qitem = mklval(ctx, &item);
pushi(ctx->current, &qitem, Q_ADD, &base, &offs, NULL);
@@ -1404,7 +1404,7 @@ gen_expr_cast(struct gen_context *ctx, const struct expression *expr)
}
if (cast_prefers_at(expr)) {
- struct gen_value out = mktemp(ctx, expr->result, "object.%d");
+ struct gen_value out = mkgtemp(ctx, expr->result, "object.%d");
struct qbe_value base = mkqval(ctx, &out);
struct qbe_value sz = constl(expr->result->size);
enum qbe_instr alloc = alloc_for_align(expr->result->align);
@@ -1437,7 +1437,7 @@ gen_expr_cast(struct gen_context *ctx, const struct expression *expr)
struct qbe_value qval = mkqval(ctx, &val);
if (expr->cast.kind == C_TEST) {
struct gen_value out =
- mktemp(ctx, &builtin_type_bool, ".%d");
+ mkgtemp(ctx, &builtin_type_bool, ".%d");
struct qbe_value qout = mkqval(ctx, &out);
struct qbe_value zero = constl(0);
@@ -1507,7 +1507,7 @@ gen_expr_cast(struct gen_context *ctx, const struct expression *expr)
struct gen_value value = gen_expr(ctx, expr->cast.value);
struct qbe_value qvalue = mkqval(ctx, &value);
- struct gen_value result = mktemp(ctx, expr->result, "cast.%d");
+ struct gen_value result = mkgtemp(ctx, expr->result, "cast.%d");
struct qbe_value qresult = mkqval(ctx, &result);
struct gen_value intermediate;
struct qbe_value qintermediate;
@@ -1580,7 +1580,7 @@ gen_expr_cast(struct gen_context *ctx, const struct expression *expr)
switch (from->size) {
case 1:
case 2:
- intermediate = mktemp(ctx,
+ intermediate = mkgtemp(ctx,
&builtin_type_i32, "cast.%d");
qintermediate = mkqval(ctx, &intermediate);
pushi(ctx->current, &qintermediate,
@@ -1600,7 +1600,7 @@ gen_expr_cast(struct gen_context *ctx, const struct expression *expr)
switch (from->size) {
case 1:
case 2:
- intermediate = mktemp(ctx,
+ intermediate = mkgtemp(ctx,
&builtin_type_i32, "cast.%d");
qintermediate = mkqval(ctx, &intermediate);
pushi(ctx->current, &qintermediate,
@@ -1665,7 +1665,7 @@ gen_expr_compound_with(struct gen_context *ctx,
struct gen_value gvout = gv_void;
if (!out) {
- gvout = mktemp(ctx, expr->result, ".%d");
+ gvout = mkgtemp(ctx, expr->result, ".%d");
}
scope->out = out;
scope->result = gvout;
@@ -1692,7 +1692,7 @@ gen_const_array_at(struct gen_context *ctx,
size_t n = 0;
const struct type *atype = type_dealias(expr->result);
- struct gen_value item = mktemp(ctx, atype->array.members, "item.%d");
+ struct gen_value item = mkgtemp(ctx, atype->array.members, "item.%d");
for (const struct array_constant *ac = aexpr; ac; ac = ac->next) {
struct qbe_value offs = constl(n * atype->array.members->size);
struct qbe_value ptr = mklval(ctx, &item);
@@ -1768,7 +1768,7 @@ static struct gen_value
gen_expr_const(struct gen_context *ctx, const struct expression *expr)
{
if (type_is_aggregate(type_dealias(expr->result))) {
- struct gen_value out = mktemp(ctx, expr->result, "object.%d");
+ struct gen_value out = mkgtemp(ctx, expr->result, "object.%d");
struct qbe_value base = mkqval(ctx, &out);
struct qbe_value sz = constl(expr->result->size);
enum qbe_instr alloc = alloc_for_align(expr->result->align);
@@ -1987,7 +1987,7 @@ gen_expr_if_with(struct gen_context *ctx,
{
struct gen_value gvout = gv_void;
if (!out) {
- gvout = mktemp(ctx, expr->result, ".%d");
+ gvout = mkgtemp(ctx, expr->result, ".%d");
}
struct qbe_statement ltrue, lfalse, lend;
@@ -2194,7 +2194,7 @@ gen_nested_match_tests(struct gen_context *ctx, struct gen_value object,
// tag of the foo object for int.
struct qbe_value *subtag = &tag;
struct qbe_value subval = mkcopy(ctx, &object, "subval.%d");
- struct gen_value match = mktemp(ctx, &builtin_type_bool, ".%d");
+ struct gen_value match = mkgtemp(ctx, &builtin_type_bool, ".%d");
struct qbe_value qmatch = mkqval(ctx, &match);
struct qbe_value temp = mkqtmp(ctx, &qbe_word, ".%d");
const struct type *subtype = object.type;
@@ -2244,7 +2244,7 @@ gen_subset_match_tests(struct gen_context *ctx,
//
// In this situation, we test the match object's tag against each type
// ID of the case type.
- struct gen_value match = mktemp(ctx, &builtin_type_bool, ".%d");
+ struct gen_value match = mkgtemp(ctx, &builtin_type_bool, ".%d");
for (const struct type_tagged_union *tu = &type->tagged; tu; tu = tu->next) {
struct qbe_statement lnexttag;
struct qbe_value bnexttag = mklabel(ctx, &lnexttag, ".%d");
@@ -2265,7 +2265,7 @@ gen_match_with_tagged(struct gen_context *ctx,
{
struct gen_value gvout = gv_void;
if (!out) {
- gvout = mktemp(ctx, expr->result, ".%d");
+ gvout = mkgtemp(ctx, expr->result, ".%d");
}
const struct type *objtype = expr->match.value->result;
@@ -2397,7 +2397,7 @@ gen_match_with_nullable(struct gen_context *ctx,
{
struct gen_value gvout = gv_void;
if (!out) {
- gvout = mktemp(ctx, expr->result, ".%d");
+ gvout = mkgtemp(ctx, expr->result, ".%d");
}
struct qbe_statement lout;
@@ -2433,7 +2433,7 @@ gen_match_with_nullable(struct gen_context *ctx,
}
struct gen_binding *gb = xcalloc(1, sizeof(struct gen_binding));
- gb->value = mktemp(ctx, _case->type, "binding.%d");
+ gb->value = mkgtemp(ctx, _case->type, "binding.%d");
gb->object = _case->object;
gb->next = ctx->bindings;
ctx->bindings = gb;
@@ -2509,7 +2509,7 @@ gen_expr_measure(struct gen_context *ctx, const struct expression *expr)
case STORAGE_STRING:
gv = gen_expr(ctx, value);
gv = gen_autoderef(ctx, gv);
- temp = mktemp(ctx, &builtin_type_size, ".%d");
+ temp = mkgtemp(ctx, &builtin_type_size, ".%d");
struct qbe_value qv = mkqval(ctx, &gv),
qtemp = mkqval(ctx, &temp),
offs = constl(builtin_type_size.size);
@@ -2580,7 +2580,7 @@ gen_expr_struct_at(struct gen_context *ctx,
&base, &zero, &size, NULL);
}
- struct gen_value ftemp = mktemp(ctx, &builtin_type_void, "field.%d");
+ struct gen_value ftemp = mkgtemp(ctx, &builtin_type_void, "field.%d");
for (const struct expr_struct_field *field = expr->_struct.fields;
field; field = field->next) {
if (!field->value) {
@@ -2603,7 +2603,7 @@ gen_expr_switch_with(struct gen_context *ctx,
{
struct gen_value gvout = gv_void;
if (!out) {
- gvout = mktemp(ctx, expr->result, ".%d");
+ gvout = mkgtemp(ctx, expr->result, ".%d");
}
struct qbe_statement lout;
@@ -2714,7 +2714,7 @@ gen_expr_slice_at(struct gen_context *ctx,
qbase = mkqtmp(ctx, ctx->arch.sz, "base.%d");
enum qbe_instr load = load_for_type(ctx, &builtin_type_size);
pushi(ctx->current, &qbase, load, &qobject, NULL);
- length = mktemp(ctx, &builtin_type_size, "len.%d");
+ length = mkgtemp(ctx, &builtin_type_size, "len.%d");
qlength = mkqval(ctx, &length);
pushi(ctx->current, &qptr, Q_ADD, &qobject, &offset, NULL);
pushi(ctx->current, &qlength, load, &qptr, NULL);
@@ -2795,7 +2795,7 @@ gen_expr_tuple_at(struct gen_context *ctx,
struct qbe_value base = mkqval(ctx, &out);
const struct type *type = type_dealias(expr->result);
- struct gen_value vtemp = mktemp(ctx, &builtin_type_void, "value.%d");
+ struct gen_value vtemp = mkgtemp(ctx, &builtin_type_void, "value.%d");
const struct expression_tuple *value = &expr->tuple;
for (const struct type_tuple *tuple = &type->tuple;
tuple; tuple = tuple->next) {
@@ -2822,7 +2822,7 @@ gen_expr_unarithm(struct gen_context *ctx,
val.type = expr->result;
return val;
}
- struct gen_value val = mktemp(ctx, operand->result, ".%d");
+ struct gen_value val = mkgtemp(ctx, operand->result, ".%d");
struct qbe_value qv = mklval(ctx, &val);
struct qbe_value sz = constl(val.type->size);
enum qbe_instr alloc = alloc_for_align(val.type->align);
@@ -2837,21 +2837,21 @@ gen_expr_unarithm(struct gen_context *ctx,
return gen_load(ctx, val);
case UN_BNOT:
val = gen_expr(ctx, operand);
- temp = mktemp(ctx, operand->result, ".%d");
+ temp = mkgtemp(ctx, operand->result, ".%d");
qval = mkqval(ctx, &val), qtmp = mkqval(ctx, &temp);
struct qbe_value ones = constl((uint64_t)-1);
pushi(ctx->current, &qtmp, Q_XOR, &qval, &ones, NULL);
return temp;
case UN_LNOT:
val = gen_expr(ctx, operand);
- temp = mktemp(ctx, operand->result, ".%d");
+ temp = mkgtemp(ctx, operand->result, ".%d");
qval = mkqval(ctx, &val), qtmp = mkqval(ctx, &temp);
struct qbe_value zerow = constw(0);
pushi(ctx->current, &qtmp, Q_CEQW, &qval, &zerow, NULL);
return temp;
case UN_MINUS:
val = gen_expr(ctx, operand);
- temp = mktemp(ctx, operand->result, ".%d");
+ temp = mkgtemp(ctx, operand->result, ".%d");
qval = mkqval(ctx, &val), qtmp = mkqval(ctx, &temp);
pushi(ctx->current, &qtmp, Q_NEG, &qval, NULL);
return temp;
@@ -2866,7 +2866,7 @@ gen_expr_vaarg(struct gen_context *ctx,
const struct expression *expr)
{
// XXX: qbe only supports variadic base types, should check for this
- struct gen_value result = mktemp(ctx, expr->result, ".%d");
+ struct gen_value result = mkgtemp(ctx, expr->result, ".%d");
struct qbe_value qresult = mkqval(ctx, &result);
struct gen_value ap = gen_expr(ctx, expr->vaarg.ap);
struct qbe_value qap = mkqval(ctx, &ap);
@@ -2951,7 +2951,7 @@ gen_expr(struct gen_context *ctx, const struct expression *expr)
return *(struct gen_value *)expr->user;
}
- struct gen_value out = mktemp(ctx, expr->result, "object.%d");
+ struct gen_value out = mkgtemp(ctx, expr->result, "object.%d");
struct qbe_value base = mkqval(ctx, &out);
struct qbe_value sz = constl(expr->result->size);
enum qbe_instr alloc = alloc_for_align(expr->result->align);
diff --git a/src/genutil.c b/src/genutil.c
@@ -66,7 +66,7 @@ mkqtmp(struct gen_context *ctx, const struct qbe_type *qtype, const char *fmt)
}
struct gen_value
-mktemp(struct gen_context *ctx, const struct type *type, const char *fmt)
+mkgtemp(struct gen_context *ctx, const struct type *type, const char *fmt)
{
return (struct gen_value){
.kind = GV_TEMP,
diff --git a/src/qtype.c b/src/qtype.c
@@ -1,4 +1,5 @@
#include <assert.h>
+#include <inttypes.h>
#include <stdlib.h>
#include <stdio.h>
#include "gen.h"
@@ -18,9 +19,9 @@ sf_compar(const void *_a, const void *_b)
static const struct qbe_type *
tagged_qtype(struct gen_context *ctx, const struct type *type)
{
- int n = snprintf(NULL, 0, "tags.%zd", ctx->id);
+ int n = snprintf(NULL, 0, "tags.%" PRIu64, ctx->id);
char *name = xcalloc(1, n + 1);
- snprintf(name, n + 1, "tags.%zd", ctx->id);
+ snprintf(name, n + 1, "tags.%" PRIu64, ctx->id);
++ctx->id;
struct qbe_def *def = xcalloc(1, sizeof(struct qbe_def));
@@ -65,9 +66,9 @@ aggregate_lookup(struct gen_context *ctx, const struct type *type)
}
}
- int n = snprintf(NULL, 0, "type.%zd", ctx->id);
+ int n = snprintf(NULL, 0, "type.%" PRIu64, ctx->id);
char *name = xcalloc(1, n + 1);
- snprintf(name, n + 1, "type.%zd", ctx->id);
+ snprintf(name, n + 1, "type.%" PRIu64, ctx->id);
++ctx->id;
struct qbe_def *def = xcalloc(1, sizeof(struct qbe_def));
diff --git a/src/typedef.c b/src/typedef.c
@@ -86,7 +86,7 @@ emit_const(const struct expression *expr, FILE *out)
case STORAGE_I8:
case STORAGE_ICONST:
case STORAGE_INT:
- fprintf(out, "%ld%s", val->ival,
+ fprintf(out, "%" PRIiMAX "%s", val->ival,
storage_to_suffix(type_dealias(expr->result)->storage));
break;
case STORAGE_NULL:
@@ -99,7 +99,7 @@ emit_const(const struct expression *expr, FILE *out)
case STORAGE_U8:
case STORAGE_UINT:
case STORAGE_UINTPTR:
- fprintf(out, "%lu%s", val->uval,
+ fprintf(out, "%" PRIuMAX "%s", val->uval,
storage_to_suffix(type_dealias(expr->result)->storage));
break;
case STORAGE_VOID:
@@ -301,10 +301,10 @@ emit_type(const struct type *type, FILE *out)
ev; ev = ev->next) {
fprintf(out, "%s = ", ev->name);
if (type_is_signed(type)) {
- fprintf(out, "%zd%s", ev->ival,
+ fprintf(out, "%" PRIi64 "%s", ev->ival,
storage_to_suffix(type->_enum.storage));
} else {
- fprintf(out, "%zu%s", ev->uval,
+ fprintf(out, "%" PRIu64 "%s", ev->uval,
storage_to_suffix(type->_enum.storage));
}
if (ev->next) {
diff --git a/tests/configure b/tests/configure
@@ -1,6 +1,13 @@
#!/bin/sh
all="$all tests"
+rtscript="rt/hare.sc"
+
+if [ `uname -s` = "OpenBSD" ]
+then
+ rtscript="rt/hare+openbsd.sc"
+fi
+
tests() {
# harec tests
for t in \
@@ -46,7 +53,7 @@ tests/$t: libhart.a tests/$t.ha
@HARECACHE=\$(HARECACHE) ./harec -o tests/$t.ssa tests/$t.ha
@\$(QBE) -o tests/$t.s tests/$t.ssa
@\$(AS) -g -o tests/$t.o tests/$t.s
- @\$(LD) --gc-sections -T rt/hare.sc -o tests/$t $rtstart tests/$t.o libhart.a
+ @\$(LD) --gc-sections -T $rtscript -o tests/$t $rtstart tests/$t.o libhart.a
@rm tests/$t.s tests/$t.ssa tests/$t.o
check: tests/$t