diff --git a/Makefile b/Makefile index 4ead08582..d59f1fcd7 100644 --- a/Makefile +++ b/Makefile @@ -66,7 +66,7 @@ MAKEFLAGS += --no-builtin-rules .SUFFIXES: .DELETE_ON_ERROR: .FEATURES: output-sync -.PHONY: all o bins check test depend tags +.PHONY: all o bins check test depend tags aarch64 ifneq ($(m),) ifeq ($(MODE),) @@ -267,7 +267,7 @@ CHECKS = $(foreach x,$(PKGS),$($(x)_CHECKS)) bins: $(BINS) check: $(CHECKS) -test: $(TESTS) +test: $(TESTS) aarch64 depend: o/$(MODE)/depend tags: TAGS HTAGS @@ -424,6 +424,10 @@ toolchain: o/cosmopolitan.h \ o/$(MODE)/cosmopolitan.a \ o/$(MODE)/third_party/libcxx/libcxx.a +aarch64: private .UNSANDBOXED = true +aarch64: + $(MAKE) m=aarch64 + # UNSPECIFIED PREREQUISITES TUTORIAL # # A build rule must exist for all files that make needs to consider in diff --git a/ape/aarch64.lds b/ape/aarch64.lds index 48dcecb32..5501184cb 100644 --- a/ape/aarch64.lds +++ b/ape/aarch64.lds @@ -1,56 +1,42 @@ /*-*- mode: ld-script; indent-tabs-mode: nil; tab-width: 2; coding: utf-8 -*-│ │vi: set et sts=2 tw=2 fenc=utf-8 :vi│ -╞══════════════════════════════════════════════════════════════════════════════╡ -│ Copyright 2023 Justine Alexandra Roberts Tunney │ -│ │ -│ Permission to use, copy, modify, and/or distribute this software for │ -│ any purpose with or without fee is hereby granted, provided that the │ -│ above copyright notice and this permission notice appear in all copies. │ -│ │ -│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ -│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ -│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ -│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ -│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ -│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ -│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ -│ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/thread/tls.h" #include "libc/zip.h" ENTRY(_start) OUTPUT_ARCH(aarch64) OUTPUT_FORMAT("elf64-littleaarch64", - "elf64-bigaarch64", - "elf64-littleaarch64") + "elf64-bigaarch64", + "elf64-littleaarch64") SECTIONS { PROVIDE(__executable_start = SEGMENT_START("text-segment", IMAGE_BASE_VIRTUAL)); . = SEGMENT_START("text-segment", IMAGE_BASE_VIRTUAL) + SIZEOF_HEADERS; - .interp : { *(.interp) } - .note.gnu.build-id : { *(.note.gnu.build-id) } - .hash : { *(.hash) } - .gnu.hash : { *(.gnu.hash) } - .dynsym : { *(.dynsym) } - .dynstr : { *(.dynstr) } - .gnu.version : { *(.gnu.version) } - .gnu.version_d : { *(.gnu.version_d) } - .gnu.version_r : { *(.gnu.version_r) } - .rela.init : { *(.rela.init) } - .rela.text : { *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*) } - .rela.fini : { *(.rela.fini) } - .rela.rodata : { *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*) } - .rela.data.rel.ro : { *(.rela.data.rel.ro .rela.data.rel.ro.* .rela.gnu.linkonce.d.rel.ro.*) } - .rela.data : { *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*) } - .rela.tdata : { *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*) } - .rela.tbss : { *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*) } - .rela.ctors : { *(.rela.ctors) } - .rela.dtors : { *(.rela.dtors) } - .rela.got : { *(.rela.got) } - .rela.bss : { *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*) } - .rela.ifunc : { *(.rela.ifunc) } + .interp : { *(.interp) } + .note.gnu.build-id : { *(.note.gnu.build-id) } + .hash : { *(.hash) } + .gnu.hash : { *(.gnu.hash) } + .dynsym : { *(.dynsym) } + .dynstr : { *(.dynstr) } + .gnu.version : { *(.gnu.version) } + .gnu.version_d : { *(.gnu.version_d) } + .gnu.version_r : { *(.gnu.version_r) } + .rela.init : { *(.rela.init) } + .rela.text : { *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*) } + .rela.fini : { *(.rela.fini) } + .rela.rodata : { *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*) } + .rela.data.rel.ro : { *(.rela.data.rel.ro .rela.data.rel.ro.* .rela.gnu.linkonce.d.rel.ro.*) } + .rela.data : { *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*) } + .rela.tdata : { *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*) } + .rela.tbss : { *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*) } + .rela.ctors : { *(.rela.ctors) } + .rela.dtors : { *(.rela.dtors) } + .rela.got : { *(.rela.got) } + .rela.bss : { *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*) } + .rela.ifunc : { *(.rela.ifunc) } .rela.plt : { *(.rela.plt) @@ -102,9 +88,9 @@ SECTIONS { } .comment : { - KEEP(*(.commentprologue)) + PROVIDE_HIDDEN(kLegalNotices = .); KEEP(*(.comment)) - KEEP(*(.commentepilogue)) + BYTE(0); } .eh_frame_hdr : { @@ -153,7 +139,7 @@ SECTIONS { *(.exception_ranges*) } - .tdata : ONLY_IF_RW { + .tdata : { PROVIDE_HIDDEN(_tdata_start = .); PROVIDE_HIDDEN(__tdata_start = .); *(.tdata .tdata.* .gnu.linkonce.td.*) @@ -184,6 +170,8 @@ SECTIONS { .data.rel.ro : { *(.data.rel.ro.local* .gnu.linkonce.d.rel.ro.local.*) *(.data.rel.ro .data.rel.ro.* .gnu.linkonce.d.rel.ro.*) + . = ALIGN(__SIZEOF_POINTER__); + KEEP(*(SORT_BY_NAME(.piro.relo.sort.*))) } .dynamic : { @@ -204,6 +192,8 @@ SECTIONS { .data : { PROVIDE(__data_start = .); + . = ALIGN(__SIZEOF_POINTER__); + KEEP(*(SORT_BY_NAME(.piro.data.sort.*))) *(.data .data.* .gnu.linkonce.d.*) KEEP(*(SORT_BY_NAME(.sort.data.*))) SORT(CONSTRUCTORS) @@ -212,7 +202,7 @@ SECTIONS { _edata = .; PROVIDE(edata = .); - .data : { + .zip : { KEEP(*(SORT_BY_NAME(.zip.*))) HIDDEN(_ezip = .); } @@ -239,36 +229,36 @@ SECTIONS { . = DATA_SEGMENT_END(.); - .stab 0 : { *(.stab) } - .stabstr 0 : { *(.stabstr) } - .stab.excl 0 : { *(.stab.excl) } - .stab.exclstr 0 : { *(.stab.exclstr) } - .stab.index 0 : { *(.stab.index) } - .stab.indexstr 0 : { *(.stab.indexstr) } + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } .gnu.build.attributes : { *(.gnu.build.attributes .gnu.build.attributes.*) } - .debug 0 : { *(.debug) } - .line 0 : { *(.line) } - .debug_srcinfo 0 : { *(.debug_srcinfo) } - .debug_sfnames 0 : { *(.debug_sfnames) } - .debug_aranges 0 : { *(.debug_aranges) } - .debug_pubnames 0 : { *(.debug_pubnames) } - .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } - .debug_abbrev 0 : { *(.debug_abbrev) } - .debug_line 0 : { *(.debug_line .debug_line.* .debug_line_end) } - .debug_frame 0 : { *(.debug_frame) } - .debug_str 0 : { *(.debug_str) } - .debug_loc 0 : { *(.debug_loc) } - .debug_macinfo 0 : { *(.debug_macinfo) } - .debug_weaknames 0 : { *(.debug_weaknames) } - .debug_funcnames 0 : { *(.debug_funcnames) } - .debug_typenames 0 : { *(.debug_typenames) } - .debug_varnames 0 : { *(.debug_varnames) } - .debug_pubtypes 0 : { *(.debug_pubtypes) } - .debug_ranges 0 : { *(.debug_ranges) } - .debug_macro 0 : { *(.debug_macro) } - .debug_addr 0 : { *(.debug_addr) } - .ARM.attributes 0 : { KEEP(*(.ARM.attributes)) KEEP(*(.gnu.attributes)) } - .note.gnu.arm.ident 0 : { KEEP(*(.note.gnu.arm.ident)) } + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line .debug_line.* .debug_line_end) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } + .debug_pubtypes 0 : { *(.debug_pubtypes) } + .debug_ranges 0 : { *(.debug_ranges) } + .debug_macro 0 : { *(.debug_macro) } + .debug_addr 0 : { *(.debug_addr) } + .ARM.attributes 0 : { KEEP(*(.ARM.attributes)) KEEP(*(.gnu.attributes)) } + .note.gnu.arm.ident 0 : { KEEP(*(.note.gnu.arm.ident)) } /DISCARD/ : { *(.GCC.command.line) @@ -287,6 +277,7 @@ PROVIDE_HIDDEN(_tdata_size = _tdata_end - _tdata_start); PROVIDE_HIDDEN(_tbss_size = _tbss_end - _tbss_start); PROVIDE_HIDDEN(_tbss_offset = _tbss_start - _tdata_start); PROVIDE_HIDDEN(_tls_content = (_tdata_end - _tdata_start) + (_tbss_end - _tbss_start)); +PROVIDE_HIDDEN(_tls_align = MAX(ALIGNOF(.tdata), ALIGNOF(.tbss))); PROVIDE_HIDDEN(__zip_start_rva = DEFINED(__zip_start) ? __zip_start - __executable_start : 0); /* ZIP End of Central Directory header */ @@ -296,3 +287,6 @@ ZIPCONST(v_zip_cdirsize, __zip_end - __zip_start); ASSERT(v_zip_cdirsize % kZipCdirHdrLinkableSize == 0, "bad zip cdir"); ZIPCONST(v_zip_records, v_zip_cdirsize / kZipCdirHdrLinkableSize); ZIPCONST(v_zip_commentsize, _ezip - __zip_end - kZipCdirHdrMinSize); + +ASSERT(ALIGNOF(.tdata) <= TLS_ALIGNMENT && ALIGNOF(.tbss) <= TLS_ALIGNMENT, + "_Thread_local _Alignof can't exceed TLS_ALIGNMENT"); diff --git a/ape/ape.lds b/ape/ape.lds index dc2b5c58e..11b1e0cea 100644 --- a/ape/ape.lds +++ b/ape/ape.lds @@ -416,7 +416,6 @@ SECTIONS { /*BEGIN: Post-Initialization Read-Only */ . = ALIGN(__SIZEOF_POINTER__); KEEP(*(SORT_BY_NAME(.piro.relo.sort.*))) - PROVIDE_HIDDEN(__relo_end = .); . = ALIGN(__SIZEOF_POINTER__); KEEP(*(SORT_BY_NAME(.piro.data.sort.*))) KEEP(*(.piro.pad.data)) @@ -518,6 +517,7 @@ HIDDEN(_tdata_size = _tdata_end - _tdata_start); HIDDEN(_tbss_size = _tbss_end - _tbss_start); HIDDEN(_tbss_offset = _tbss_start - _tdata_start); HIDDEN(_tls_content = (_tdata_end - _tdata_start) + (_tbss_end - _tbss_start)); +HIDDEN(_tls_align = 1); HIDDEN(__privileged_addr = ROUNDDOWN(__privileged_start, PAGESIZE)); HIDDEN(__privileged_size = (ROUNDUP(__privileged_end, PAGESIZE) - diff --git a/ape/ape.mk b/ape/ape.mk index 09d586fcb..02c210bbf 100644 --- a/ape/ape.mk +++ b/ape/ape.mk @@ -42,6 +42,7 @@ o/$(MODE)/ape/aarch64.lds: \ ape/aarch64.lds \ libc/zip.h \ libc/intrin/bits.h \ + libc/thread/tls.h \ libc/calls/struct/timespec.h \ libc/macros.internal.h \ libc/str/str.h diff --git a/ape/sections.internal.h b/ape/sections.internal.h index 7e72a3553..ab0bb9b97 100644 --- a/ape/sections.internal.h +++ b/ape/sections.internal.h @@ -14,14 +14,13 @@ extern unsigned char _tdata_start[] __attribute__((__weak__)); extern unsigned char _tdata_end[] __attribute__((__weak__)); extern unsigned char _tbss_start[] __attribute__((__weak__)); extern unsigned char _tbss_end[] __attribute__((__weak__)); +extern unsigned char _tls_align[] __attribute__((__weak__)); extern unsigned char __privileged_start[] __attribute__((__weak__)); extern unsigned char __privileged_addr[] __attribute__((__weak__)); extern unsigned char __privileged_size[] __attribute__((__weak__)); extern unsigned char __privileged_end[] __attribute__((__weak__)); extern unsigned char __test_start[] __attribute__((__weak__)); extern unsigned char __ro[] __attribute__((__weak__)); -extern unsigned char *__relo_start[] __attribute__((__weak__)); -extern unsigned char *__relo_end[] __attribute__((__weak__)); extern uint8_t __zip_start[] __attribute__((__weak__)); extern uint8_t __zip_end[] __attribute__((__weak__)); extern uint8_t __data_start[] __attribute__((__weak__)); diff --git a/build/objdump b/build/objdump index 7e400c3b4..2e032aa04 100755 --- a/build/objdump +++ b/build/objdump @@ -1,6 +1,5 @@ #!/bin/sh -for last; do true; done -if printf '%s\n' "$last" | grep aarch64 >/dev/null 2>&1; then +if printf '%s\n' "$*" | grep aarch64 >/dev/null 2>&1; then exec o/third_party/gcc/bin/aarch64-linux-musl-objdump "$@" else exec o/third_party/gcc/bin/x86_64-linux-musl-objdump "$@" diff --git a/build/run b/build/run index 0fcdaf848..d1ada17a1 100755 --- a/build/run +++ b/build/run @@ -1,6 +1,5 @@ #!/bin/sh -for last; do true; done -if printf '%s\n' "$last" | grep aarch64 >/dev/null 2>&1; then +if printf '%s\n' "$*" | grep aarch64 >/dev/null 2>&1; then if [ ! -f o/third_party/qemu/qemu-aarch64 ]; then make -j8 o/third_party/qemu/qemu-aarch64 fi diff --git a/examples/examples.mk b/examples/examples.mk index 421016275..6eba67034 100644 --- a/examples/examples.mk +++ b/examples/examples.mk @@ -162,7 +162,8 @@ o/$(MODE)/examples/nesemu1.com.dbg: \ o/$(MODE)/examples/symtab.com: \ o/$(MODE)/examples/symtab.com.dbg \ o/$(MODE)/third_party/zip/zip.com \ - o/$(MODE)/tool/build/symtab.com + o/$(MODE)/tool/build/symtab.com \ + $(VM) @$(MAKE_OBJCOPY) @$(MAKE_SYMTAB_CREATE) @$(MAKE_SYMTAB_ZIP) diff --git a/libc/calls/calls.h b/libc/calls/calls.h index f2c9f8439..18a34fe29 100644 --- a/libc/calls/calls.h +++ b/libc/calls/calls.h @@ -50,11 +50,11 @@ #define MAP_HUGE_2MB (21 << MAP_HUGE_SHIFT) #define MAP_HUGE_1GB (30 << MAP_HUGE_SHIFT) -#define WCOREDUMP(s) (0x80 & (s)) +#define WCOREDUMP(s) (128 & (s)) #define WEXITSTATUS(s) ((0xff00 & (s)) >> 8) #define WIFCONTINUED(s) ((s) == 0xffff) #define WIFEXITED(s) (!WTERMSIG(s)) -#define WIFSIGNALED(s) ((0xffff & (s)) - 1u < 0xffu) +#define WIFSIGNALED(s) (((signed char)((127 & (s)) + 1) >> 1) > 0) #define WIFSTOPPED(s) ((255 & (s)) == 127) #define WSTOPSIG(s) WEXITSTATUS(s) #define WTERMSIG(s) (127 & (s)) diff --git a/libc/calls/dtime.c b/libc/calls/dtime.c index 7ccc41afa..ac8465c84 100644 --- a/libc/calls/dtime.c +++ b/libc/calls/dtime.c @@ -18,6 +18,8 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/struct/timespec.h" +// TODO(jart): DELETE + /** * Returns seconds since epoch w/ high-precision. * @param clockid can be CLOCK_{REALTIME,MONOTONIC}, etc. @@ -27,7 +29,7 @@ long double dtime(int clockid) { struct timespec tv; clock_gettime(clockid, &tv); secs = tv.tv_nsec; - secs *= 1 / 1e9; + secs *= 1e-9; secs += tv.tv_sec; return secs; } diff --git a/libc/calls/execve-sysv.c b/libc/calls/execve-sysv.c index fe5137af7..b99b976a2 100644 --- a/libc/calls/execve-sysv.c +++ b/libc/calls/execve-sysv.c @@ -49,7 +49,7 @@ static bool IsApeBinary(const char *path) { bool res = false; // TODO(jart): Should we block signals too? BLOCK_CANCELLATIONS; - if ((fd = sys_open(path, O_RDONLY, 0)) != -1) { + if ((fd = sys_openat(AT_FDCWD, path, O_RDONLY, 0)) != -1) { res = sys_read(fd, buf, 8) == 8 && IsAPEMagic(buf); sys_close(fd); } diff --git a/libc/calls/oldbench.c b/libc/calls/oldbench.c index f2e9cee07..834e190f0 100644 --- a/libc/calls/oldbench.c +++ b/libc/calls/oldbench.c @@ -76,7 +76,7 @@ static void Refresh(void) { memcpy(&g_now, &now, sizeof(now)); } -long double ConvertTicksToNanos(uint64_t ticks) { +long double ConvertTicksToNanos(double ticks) { if (!g_now.once) Refresh(); return ticks * g_now.cpn; /* pico scale */ } diff --git a/libc/calls/openpty.c b/libc/calls/openpty.c index 13bedb0dd..f2c68367b 100644 --- a/libc/calls/openpty.c +++ b/libc/calls/openpty.c @@ -32,6 +32,7 @@ #include "libc/intrin/kprintf.h" #include "libc/log/rop.h" #include "libc/str/str.h" +#include "libc/sysv/consts/at.h" #include "libc/sysv/consts/o.h" #include "libc/sysv/consts/pty.h" #include "libc/sysv/consts/termios.h" @@ -55,7 +56,7 @@ static int openpty_impl(int *mfd, int *sfd, char *name, RETURN_ON_ERROR(grantpt(m)); RETURN_ON_ERROR(unlockpt(m)); RETURN_ON_ERROR(_ptsname(m, t.sname, sizeof(t.sname))); - RETURN_ON_ERROR((s = sys_open(t.sname, O_RDWR, 0))); + RETURN_ON_ERROR((s = sys_openat(AT_FDCWD, t.sname, O_RDWR, 0))); } else { RETURN_ON_ERROR(sys_ioctl(m, PTMGET, &t)); close(m); diff --git a/libc/calls/pledge-linux.c b/libc/calls/pledge-linux.c index 18313c084..1c143ea75 100644 --- a/libc/calls/pledge-linux.c +++ b/libc/calls/pledge-linux.c @@ -19,6 +19,7 @@ #include "ape/sections.internal.h" #include "libc/calls/calls.h" #include "libc/calls/pledge.internal.h" +#include "libc/calls/prctl.internal.h" #include "libc/calls/struct/bpf.h" #include "libc/calls/struct/filter.h" #include "libc/calls/struct/seccomp.h" @@ -1100,33 +1101,6 @@ static privileged void Log(const char *s, ...) { va_end(va); } -static privileged int Prctl(int op, long a, void *b, long c, long d) { - int rc; -#ifdef __x86_64__ - asm volatile("mov\t%5,%%r10\n\t" - "mov\t%6,%%r8\n\t" - "syscall" - : "=a"(rc) - : "0"(__NR_linux_prctl), "D"(op), "S"(a), "d"(b), "g"(c), "g"(d) - : "rcx", "r8", "r10", "r11", "memory"); -#elif defined(__aarch64__) - register long r0 asm("x0") = (long)op; - register long r1 asm("x1") = (long)a; - register long r2 asm("x2") = (long)b; - register long r3 asm("x3") = (long)c; - register long r4 asm("x4") = (long)d; - register long res_x0 asm("x0"); - asm volatile("mov\tx8,%1\n\t" - "svc\t0" - : "=r"(res_x0) - : "i"(__NR_linux_prctl), "r"(r0), "r"(r1), "r"(r2), "r"(r3), - "r"(r4) - : "x8", "memory"); - rc = res_x0; -#endif - return rc; -} - static privileged int SigAction(int sig, struct sigaction *act, struct sigaction *old) { int res; @@ -2353,18 +2327,18 @@ privileged int sys_pledge_linux(unsigned long ipromises, int mode) { // PR_SET_SECCOMP (Linux 2.6.23+) will refuse to work if // PR_SET_NO_NEW_PRIVS (Linux 3.5+) wasn't called so we punt the error // detection to the seccomp system call below. - Prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0); + sys_prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0); // register our seccomp filter with the kernel struct sock_fprog sandbox = {.len = f.n, .filter = f.p}; - rc = Prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &sandbox, 0, 0); + rc = sys_prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, (long)&sandbox, 0, 0); // the EINVAL error could mean a lot of things. it could mean the bpf // code is broken. it could also mean we're running on RHEL5 which // doesn't have SECCOMP support. since we don't consider lack of // system support for security to be an error, we distinguish these // two cases by running a simpler SECCOMP operation. - if (rc == -Einval && Prctl(PR_GET_SECCOMP, 0, 0, 0, 0) == -Einval) { + if (rc == -Einval && sys_prctl(PR_GET_SECCOMP, 0, 0, 0, 0) == -Einval) { rc = 0; // -Enosys } diff --git a/libc/calls/pledge.c b/libc/calls/pledge.c index 64b1c2beb..6c24b989d 100644 --- a/libc/calls/pledge.c +++ b/libc/calls/pledge.c @@ -18,6 +18,7 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/calls.h" #include "libc/calls/pledge.internal.h" +#include "libc/calls/prctl.internal.h" #include "libc/calls/state.internal.h" #include "libc/calls/syscall-sysv.internal.h" #include "libc/dce.h" @@ -26,6 +27,7 @@ #include "libc/intrin/strace.internal.h" #include "libc/nexgen32e/vendor.internal.h" #include "libc/runtime/runtime.h" +#include "libc/sysv/consts/pr.h" #include "libc/sysv/errfuns.h" /** @@ -42,8 +44,10 @@ * across execve() if permitted). Root access is not required. Support * is limited to Linux 2.6.23+ (c. RHEL6) and OpenBSD. If your kernel * isn't supported, then pledge() will return 0 and do nothing rather - * than raising ENOSYS. We don't consider lack of system support to be - * an error, because the specified operations will be permitted. + * than raising ENOSYS. This implementation doesn't consider lack of + * system support to be an error by default. To perform a functionality + * check, use `pledge(0,0)` which is a no-op that'll fail appropriately + * when the necessary system support isn't available for restrictions. * * The promises you give pledge() define which system calls are allowed. * Error messages are logged when sandbox violations occur, but how that @@ -234,6 +238,7 @@ * subprocesses can't inherit the `SIGSYS` handler this installs. * * @return 0 on success, or -1 w/ errno + * @raise ENOSYS if `pledge(0, 0)` was used and security is not possible * @raise EINVAL if `execpromises` on Linux isn't a subset of `promises` * @raise EINVAL if `promises` allows exec and `execpromises` is null * @threadsafe @@ -242,8 +247,24 @@ int pledge(const char *promises, const char *execpromises) { int e, rc; unsigned long ipromises, iexecpromises; - if (IsGenuineBlink()) { - rc = 0; // blink doesn't support seccomp + if (!promises) { + // OpenBSD says NULL argument means it doesn't change, i.e. + // pledge(0,0) on OpenBSD does nothing. The Cosmopolitan Libc + // implementation defines pledge(0,0) as a no-op feature check. + // Cosmo pledge() is currently implemented to succeed silently if + // the necessary kernel features aren't supported by the host. Apps + // may use pledge(0,0) to perform a support check, to determine if + // pledge() will be able to impose the restrictions it advertises + // within the host environment. + if (execpromises) return einval(); + if (IsGenuineBlink()) return enosys(); + if (IsOpenbsd()) return sys_pledge(0, 0); + if (!IsLinux()) return enosys(); + if (!(rc = sys_prctl(PR_GET_SECCOMP, 0, 0, 0, 0))) return 0; + errno = -rc; + return -1; + } else if (!IsTiny() && IsGenuineBlink()) { + rc = 0; // blink doesn't support seccomp; avoid noisy log warnings } else if (!ParsePromises(promises, &ipromises) && !ParsePromises(execpromises, &iexecpromises)) { if (IsLinux()) { diff --git a/libc/calls/posix_openpt.c b/libc/calls/posix_openpt.c index 3b5333ef1..eb1906407 100644 --- a/libc/calls/posix_openpt.c +++ b/libc/calls/posix_openpt.c @@ -22,6 +22,7 @@ #include "libc/errno.h" #include "libc/intrin/describeflags.internal.h" #include "libc/intrin/strace.internal.h" +#include "libc/sysv/consts/at.h" #include "libc/sysv/consts/o.h" #include "libc/sysv/errfuns.h" @@ -37,9 +38,9 @@ int posix_openpt(int flags) { if ((flags & O_ACCMODE) != O_RDWR) { rc = einval(); } else if (IsLinux() || IsXnu() || IsNetbsd()) { - rc = sys_open("/dev/ptmx", flags, 0); + rc = sys_openat(AT_FDCWD, "/dev/ptmx", flags, 0); } else if (IsOpenbsd()) { - rc = sys_open("/dev/ptm", flags, 0); + rc = sys_openat(AT_FDCWD, "/dev/ptm", flags, 0); } else if (IsFreebsd()) { rc = sys_posix_openpt(flags); if (rc == -1 && errno == ENOSPC) errno = EAGAIN; diff --git a/libc/calls/prctl.c b/libc/calls/prctl.c index 97f84d64b..d59b0fa43 100644 --- a/libc/calls/prctl.c +++ b/libc/calls/prctl.c @@ -17,6 +17,7 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/calls.h" +#include "libc/calls/prctl.internal.h" #include "libc/calls/syscall-sysv.internal.h" #include "libc/dce.h" #include "libc/errno.h" @@ -43,30 +44,11 @@ privileged int prctl(int operation, ...) { va_end(va); if (IsLinux()) { -#ifdef __x86_64__ - asm volatile("mov\t%5,%%r10\n\t" - "mov\t%6,%%r8\n\t" - "syscall" - : "=a"(rc) - : "0"(157), "D"(operation), "S"(a), "d"(b), "g"(c), "g"(d) - : "rcx", "r8", "r10", "r11", "memory"); - if (rc > -4096u) errno = -rc, rc = -1; -#elif defined(__aarch64__) - register long r0 asm("x0") = (long)operation; - register long r1 asm("x1") = (long)a; - register long r2 asm("x2") = (long)b; - register long r3 asm("x3") = (long)c; - register long r4 asm("x4") = (long)d; - register long res_x0 asm("x0"); - asm volatile("mov\tx8,%1\n\t" - "svc\t0" - : "=r"(res_x0) - : "i"(167), "r"(r0), "r"(r1), "r"(r2), "r"(r3), "r"(r4) - : "x8", "memory"); - rc = _sysret(res_x0); -#else -#error "arch unsupported" -#endif + rc = sys_prctl(operation, a, b, c, d); + if (rc < 0) { + errno = -rc; + rc = -1; + } } else { rc = enosys(); } diff --git a/libc/calls/prctl.internal.h b/libc/calls/prctl.internal.h new file mode 100644 index 000000000..89d9a0308 --- /dev/null +++ b/libc/calls/prctl.internal.h @@ -0,0 +1,38 @@ +#ifndef COSMOPOLITAN_LIBC_CALLS_PRCTL_INTERNAL_H_ +#define COSMOPOLITAN_LIBC_CALLS_PRCTL_INTERNAL_H_ +#include "libc/dce.h" +#include "libc/sysv/consts/nrlinux.h" +#if !(__ASSEMBLER__ + __LINKER__ + 0) +COSMOPOLITAN_C_START_ + +forceinline int sys_prctl(int op, long a, long b, long c, long d) { + int rc; +#ifdef __x86_64__ + register long r10 asm("r10") = c; + register long r8 asm("r8") = d; + asm volatile("syscall" + : "=a"(rc) + : "0"(__NR_linux_prctl), "D"(op), "S"(a), "d"(b), "r"(r10), + "r"(r8) + : "rcx", "r11", "memory"); +#elif defined(__aarch64__) + register long r0 asm("x0") = op; + register long r1 asm("x1") = a; + register long r2 asm("x2") = b; + register long r3 asm("x3") = c; + register long r4 asm("x4") = d; + register long res_x0 asm("x0"); + asm volatile("mov\tx8,%1\n\t" + "svc\t0" + : "=r"(res_x0) + : "i"(__NR_linux_prctl), "r"(r0), "r"(r1), "r"(r2), "r"(r3), + "r"(r4) + : "x8", "memory"); + rc = res_x0; +#endif + return rc; +} + +COSMOPOLITAN_C_END_ +#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ +#endif /* COSMOPOLITAN_LIBC_CALLS_PRCTL_INTERNAL_H_ */ diff --git a/libc/calls/syscall-sysv.internal.h b/libc/calls/syscall-sysv.internal.h index f4e5ea517..3c3bcd609 100644 --- a/libc/calls/syscall-sysv.internal.h +++ b/libc/calls/syscall-sysv.internal.h @@ -75,7 +75,6 @@ i32 sys_mknodat(i32, const char *, u32, u64) _Hide; i32 sys_mprotect(void *, u64, i32) _Hide; i32 sys_msync(void *, u64, i32) _Hide; i32 sys_munmap(void *, u64) _Hide; -i32 sys_open(const char *, i32, u32) _Hide; i32 sys_openat(i32, const char *, i32, u32) _Hide; i32 sys_pause(void) _Hide; i32 sys_pipe(i32[hasatleast 2]) _Hide; diff --git a/libc/calls/unveil.c b/libc/calls/unveil.c index ad16f5864..8f48da9e2 100644 --- a/libc/calls/unveil.c +++ b/libc/calls/unveil.c @@ -27,8 +27,10 @@ #include "libc/calls/struct/stat.internal.h" #include "libc/calls/syscall-sysv.internal.h" #include "libc/calls/syscall_support-sysv.internal.h" +#include "libc/dce.h" #include "libc/errno.h" #include "libc/fmt/conv.h" +#include "libc/intrin/kprintf.h" #include "libc/intrin/strace.internal.h" #include "libc/macros.internal.h" #include "libc/nexgen32e/vendor.internal.h" @@ -99,9 +101,11 @@ static int landlock_abi_version; static int landlock_abi_errno; __attribute__((__constructor__)) void init_landlock_version() { + int e = errno; landlock_abi_version = landlock_create_ruleset(0, 0, LANDLOCK_CREATE_RULESET_VERSION); landlock_abi_errno = errno; + errno = e; } /** @@ -170,7 +174,7 @@ static int unveil_init(void) { const struct landlock_ruleset_attr attr = { .handled_access_fs = State.fs_mask, }; - // [undocumented] landlock_create_ruleset() always returns o_cloexec + // [undocumented] landlock_create_ruleset() always returns O_CLOEXEC // assert(__sys_fcntl(rc, F_GETFD, 0) == FD_CLOEXEC); if ((rc = landlock_create_ruleset(&attr, sizeof(attr), 0)) < 0) return -1; // grant file descriptor a higher number that's less likely to interfere @@ -274,7 +278,7 @@ int sys_unveil_linux(const char *path, const char *permissions) { // now we can open the path BLOCK_CANCELLATIONS; - rc = sys_open(path, O_PATH | O_NOFOLLOW | O_CLOEXEC, 0); + rc = sys_openat(AT_FDCWD, path, O_PATH | O_NOFOLLOW | O_CLOEXEC, 0); ALLOW_CANCELLATIONS; if (rc == -1) return rc; @@ -308,9 +312,16 @@ int sys_unveil_linux(const char *path, const char *permissions) { * should become unhidden. When you're finished, you call `unveil(0,0)` * which commits your policy. * - * This function requires OpenBSD or Linux 5.13+. We don't consider lack - * of system support to be an ENOSYS error, because the files will still - * become unveiled. Therefore we return 0 in such cases. + * This function requires OpenBSD or Linux 5.13+ (2022+). If the kernel + * support isn't available (or we're in an emulator like Qemu or Blink) + * then zero is returned and nothing happens (instead of raising ENOSYS) + * because the files are still unveiled. Use `unveil("", 0)` to feature + * check the host system, which is defined as a no-op that'll fail if + * the host system doesn't have the necessary features that allow + * unveil() impose bona-fide security restrictions. Otherwise, if + * everything is good, a return value `>=0` is returned, where `0` means + * OpenBSD, and `>=1` means Linux with Landlock LSM, in which case the + * return code shall be the maximum supported Landlock ABI version. * * There are some differences between unveil() on Linux versus OpenBSD. * @@ -338,10 +349,10 @@ int sys_unveil_linux(const char *path, const char *permissions) { * possible to use opendir() and go fishing for paths which weren't * previously known. * - * 5. Use ftruncate() rather than truncate() if you wish for portability to - * Linux kernels versions released before February 2022. One issue - * Landlock hadn't addressed as of ABI version 2 was restrictions over - * truncate() and setxattr() which could permit certain kinds of + * 5. Use ftruncate() rather than truncate() if you wish for portability + * to Linux kernels versions released before February 2022. One issue + * Landlock hadn't addressed as of ABI version 2 was restrictions + * over truncate() and setxattr() which could permit certain kinds of * modifications to files outside the sandbox. When your policy is * committed, we install a SECCOMP BPF filter to disable those calls, * however similar trickery may be possible through other unaddressed @@ -349,8 +360,8 @@ int sys_unveil_linux(const char *path, const char *permissions) { * unveil() will solve this, since it installs a strong system call * access policy. Linux 6.2 has improved this situation with Landlock * ABI v3, which added the ability to control truncation operations - - * this means the SECCOMP BPF filter will only disable - * truncate() on Linux 6.1 or older + * this means the SECCOMP BPF filter will only disable truncate() on + * Linux 6.1 or older. * * 6. Set your process-wide policy at startup from the main thread. On * OpenBSD unveil() will apply process-wide even when called from a @@ -385,10 +396,14 @@ int sys_unveil_linux(const char *path, const char *permissions) { * - `c` allows `path` to be created and removed, corresponding to * the pledge promise "cpath". * - * @return 0 on success, or -1 w/ errno + * @return 0 on success, or -1 w/ errno; note: if `unveil("",0)` is used + * to perform a feature check, then on Linux a value greater than 0 + * shall be returned which is the supported Landlock ABI version + * @raise EPERM if unveil() is called after locking * @raise EINVAL if one argument is set and the other is not * @raise EINVAL if an invalid character in `permissions` was found - * @raise EPERM if unveil() is called after locking + * @raise ENOSYS if `unveil("",0)` was used and security isn't possible + * @raise EOPNOTSUPP if `unveil("",0)` was used and Landlock LSM is disabled * @note on Linux this function requires Linux Kernel 5.13+ and version 6.2+ * to properly support truncation operations * @see [1] https://docs.kernel.org/userspace-api/landlock.html @@ -397,8 +412,24 @@ int sys_unveil_linux(const char *path, const char *permissions) { int unveil(const char *path, const char *permissions) { int e, rc; e = errno; - if (IsGenuineBlink()) { - rc = 0; // blink doesn't support landlock + if (path && !*path) { + // OpenBSD will always fail on both unveil("",0) and unveil("",""), + // since an empty `path` is invalid and `permissions` is mandatory. + // Cosmopolitan Libc uses it as a feature check convention, to test + // if the host environment enables unveil() to impose true security + // restrictions because the default behavior is to silently succeed + // so that programs will err on the side of working if distributed. + if (IsOpenbsd()) return 0; + if (landlock_abi_version != -1) { + _unassert(landlock_abi_version >= 1); + return landlock_abi_version; + } else { + _unassert(landlock_abi_errno); + errno = landlock_abi_errno; + return -1; + } + } else if (!IsTiny() && IsGenuineBlink()) { + rc = 0; // blink doesn't support landlock; avoid noisy log warnings } else if (IsLinux()) { rc = sys_unveil_linux(path, permissions); } else { diff --git a/libc/integral/c.inc b/libc/integral/c.inc index 1aca67eae..28619eb49 100644 --- a/libc/integral/c.inc +++ b/libc/integral/c.inc @@ -53,16 +53,18 @@ #endif #ifdef _MSC_VER -#define __builtin_unreachable() __assume(0) +#define __builtin_unreachable() __assume(false) #elif defined(__STRICT_ANSI__) || \ !((__GNUC__ + 0) * 100 + (__GNUC_MINOR__ + 0) >= 405 || \ - defined(__clang__) || defined(__INTEL_COMPILER)) + defined(__clang__) || defined(__INTEL_COMPILER) || \ + __has_builtin(__builtin_unreachable)) #define __builtin_unreachable() \ for (;;) { \ } #endif -#if defined(__STRICT_ANSI__) || (!defined(__llvm__) && !__has_builtin(assume)) +#if defined(__STRICT_ANSI__) || \ + (!defined(__llvm__) && !__has_builtin(__builtin_assume)) #define __builtin_assume(x) \ do { \ if (!(x)) __builtin_unreachable(); \ @@ -248,13 +250,13 @@ typedef struct { #endif #endif -#ifndef noclone +#ifndef dontclone #if !defined(__STRICT_ANSI__) && \ (__has_attribute(__noclone__) || \ (__GNUC__ + 0) * 100 + (__GNUC_MINOR__ + 0) >= 405) -#define noclone __attribute__((__noclone__)) +#define dontclone __attribute__((__noclone__)) #else -#define noclone +#define dontclone #endif #endif @@ -417,16 +419,16 @@ typedef struct { #endif #endif -#ifndef nooptimize +#ifndef dontoptimize #ifndef __STRICT_ANSI__ -#if (__GNUC__ + 0) * 100 + (__GNUC_MINOR__ + 0) >= 407 || \ +#if defined(__llvm__) || __has_attribute(__optnone__) +#define dontoptimize __attribute__((__optnone__)) +#elif (__GNUC__ + 0) * 100 + (__GNUC_MINOR__ + 0) >= 407 || \ __has_attribute(__optimize__) -#define nooptimize __attribute__((__optimize__(1))) -#elif defined(__llvm__) || __has_attribute(__optnone__) -#define nooptimize __attribute__((__optnone__)) +#define dontoptimize __attribute__((__optimize__(0))) #endif #else -#define nooptimize +#define dontoptimize #endif #endif @@ -570,7 +572,7 @@ typedef struct { #if __cplusplus + 0 >= 201103L #define autotype(x) auto -#elif ((__has_builtin(auto_type) || defined(__llvm__) || \ +#elif ((__has_builtin(__auto_type) || defined(__llvm__) || \ (__GNUC__ + 0) * 100 + (__GNUC_MINOR__ + 0) >= 409) && \ !defined(__chibicc__)) #define autotype(x) __auto_type @@ -588,39 +590,42 @@ typedef struct { #define nocallersavedregisters #endif -#if (__GNUC__ + 0) * 100 + (__GNUC_MINOR__ + 0) >= 408 || \ - __has_attribute(__no_sanitize_address__) +#if ((__GNUC__ + 0) * 100 + (__GNUC_MINOR__ + 0) >= 408 || \ + __has_attribute(__no_sanitize_address__)) && \ + !defined(__STRICT_ANSI__) #define noasan __attribute__((__no_sanitize_address__)) #else #define noasan #endif -#if (__GNUC__ + 0) * 100 + (__GNUC_MINOR__ + 0) >= 408 || \ - __has_attribute(__no_sanitize_undefined__) +#if ((__GNUC__ + 0) * 100 + (__GNUC_MINOR__ + 0) >= 408 || \ + __has_attribute(__no_sanitize_undefined__)) && \ + !defined(__STRICT_ANSI__) #define noubsan __attribute__((__no_sanitize_undefined__)) #else #define noubsan #endif #ifndef unreachable -#if defined(__GNUC__) && !defined(__STRICT_ANSI__) #define unreachable __builtin_unreachable() -#else -#define unreachable \ - do { \ - } while (1) -#endif #endif +#ifdef __STRICT_ANSI__ +void abort(void) wontreturn; +#define notpossible abort() +#else #ifdef __x86_64__ -#define notpossible \ - do { \ - asm("nop\n\tud2\n\tnop"); \ - unreachable; \ +#define notpossible \ + do { \ + asm("nop\n\t" \ + "ud2\n\t" \ + "nop"); \ + unreachable; \ } while (0) #else #define notpossible __builtin_trap() #endif +#endif #define donothing \ do { \ diff --git a/libc/intrin/asan.c b/libc/intrin/asan.c index f62f00064..b5e2812d9 100644 --- a/libc/intrin/asan.c +++ b/libc/intrin/asan.c @@ -1400,7 +1400,7 @@ void __asan_map_shadow(uintptr_t p, size_t n) { } } size = (size_t)i << 16; - addr = (void *)(intptr_t)((int64_t)((uint64_t)a << 32) >> 16); + addr = (void *)ADDR_32_TO_48(a); prot = PROT_READ | PROT_WRITE; flag = MAP_PRIVATE | MAP_FIXED | MAP_ANONYMOUS; sm = _weaken(sys_mmap)(addr, size, prot, flag, -1, 0); @@ -1413,8 +1413,7 @@ void __asan_map_shadow(uintptr_t p, size_t n) { __asan_die()(); __asan_unreachable(); } - __repstosb((void *)(intptr_t)((int64_t)((uint64_t)a << 32) >> 16), - kAsanUnmapped, size); + __repstosb(addr, kAsanUnmapped, size); } __asan_unpoison((char *)p, n); } diff --git a/libc/calls/cp.c b/libc/intrin/cp.c similarity index 100% rename from libc/calls/cp.c rename to libc/intrin/cp.c diff --git a/libc/intrin/describeframe.c b/libc/intrin/describeframe.c index 735f58665..217c54922 100644 --- a/libc/intrin/describeframe.c +++ b/libc/intrin/describeframe.c @@ -26,12 +26,11 @@ #include "libc/runtime/runtime.h" #include "libc/runtime/winargs.internal.h" -#define ADDR(x) ((int64_t)((uint64_t)(x) << 32) >> 16) #define UNSHADOW(x) ((int64_t)(MAX(0, (x)-0x7fff8000)) << 3) #define FRAME(x) ((int)((x) >> 16)) forceinline pureconst bool IsBrkFrame(int x) { - unsigned char *p = (unsigned char *)((intptr_t)((uintptr_t)x << 32) >> 16); + unsigned char *p = (unsigned char *)ADDR_32_TO_48(x); return _weaken(__brk) && p >= _end && p < _weaken(__brk)->p; } @@ -78,7 +77,8 @@ const char *(DescribeFrame)(char buf[32], int x) { char *p; if (IsShadowFrame(x)) { ksnprintf(buf, 32, "%s %s %.8x", GetFrameName(x), - GetFrameName(FRAME(UNSHADOW(ADDR(x)))), FRAME(UNSHADOW(ADDR(x)))); + GetFrameName(FRAME(UNSHADOW(ADDR_32_TO_48(x)))), + FRAME(UNSHADOW(ADDR_32_TO_48(x)))); return buf; } else { return GetFrameName(x); diff --git a/libc/intrin/exit.c b/libc/intrin/exit.c index cc4bfa3cb..9c7c0ba8c 100644 --- a/libc/intrin/exit.c +++ b/libc/intrin/exit.c @@ -39,7 +39,6 @@ wontreturn void _Exit(int exitcode) { int i; STRACE("_Exit(%d)", exitcode); -#ifdef __x86_64__ if (!IsWindows() && !IsMetal()) { // On Linux _Exit1 (exit) must be called in pledge("") mode. If we // call _Exit (exit_group) when we haven't used pledge("stdio") then @@ -47,34 +46,48 @@ wontreturn void _Exit(int exitcode) { // _Exit1 (__threxit) because only _Exit (exit) is whitelisted when // operating in pledge("") mode. if (!(IsLinux() && !PLEDGED(STDIO))) { +#ifdef __x86_64__ asm volatile("syscall" : /* no outputs */ : "a"(__NR_exit_group), "D"(exitcode) : "rcx", "r11", "memory"); +#elif defined(__aarch64__) + register long x0 asm("x0") = exitcode; + asm volatile("mov\tx8,%0\n\t" + "mov\tx16,%1\n\t" + "svc\t0" + : /* no outputs */ + : "i"(94), "i"(1), "r"(x0) + : "x8", "x16", "memory"); +#else +#error "unsupported architecture" +#endif } // Inline _Exit1() just in case _Exit() isn't allowed by pledge() +#ifdef __x86_64__ asm volatile("syscall" : /* no outputs */ : "a"(__NR_exit), "D"(exitcode) : "rcx", "r11", "memory"); +#else + register long r0 asm("x0") = exitcode; + asm volatile("mov\tx8,%0\n\t" + "mov\tx16,%1\n\t" + "svc\t0" + : /* no outputs */ + : "i"(93), "i"(0x169), "r"(r0) + : "x8", "memory"); +#endif } else if (IsWindows()) { ExitProcess(exitcode); } +#ifdef __x86_64__ asm("push\t$0\n\t" "push\t$0\n\t" "cli\n\t" "lidt\t(%rsp)"); for (;;) asm("ud2"); -#elif defined(__aarch64__) - register long x0 asm("x0") = exitcode; - asm volatile("mov\tx8,%0\n\t" - "mov\tx16,%1\n\t" - "svc\t0" - : /* no outputs */ - : "i"(94), "i"(1), "r"(x0) - : "x8", "x16", "memory"); - notpossible; #else -#error "arch unsupported" + unreachable; #endif } diff --git a/libc/intrin/feholdexcept.c b/libc/intrin/feholdexcept.c new file mode 100644 index 000000000..dadf6753a --- /dev/null +++ b/libc/intrin/feholdexcept.c @@ -0,0 +1,10 @@ +#include "libc/runtime/fenv.h" + +/** + * Saves floating-point environment and clears current exceptions. + */ +int feholdexcept(fenv_t *envp) { + fegetenv(envp); + feclearexcept(FE_ALL_EXCEPT); + return 0; +} diff --git a/libc/intrin/fenv.S b/libc/intrin/fenv.S index 3c27094ed..5c9dfac9c 100644 --- a/libc/intrin/fenv.S +++ b/libc/intrin/fenv.S @@ -27,6 +27,18 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/macros.internal.h" +// Clears floating point exception status, e.g. +// +// feclearexcept(FE_ALL_EXCEPT); +// +// @param excepts may bitwise-or the following: +// - `FE_INVALID` +// - `FE_DIVBYZERO` +// - `FE_OVERFLOW` +// - `FE_UNDERFLOW` +// - `FE_INEXACT` +// - `FE_ALL_EXCEPT` (all of the above) +// @return 0 on success, or nonzero on error feclearexcept: #ifdef __x86_64__ // maintain exceptions in the sse mxcsr, clear x87 exceptions @@ -53,9 +65,47 @@ feclearexcept: msr fpsr,x1 mov w0,#0 ret +#else +#error "unsupported architecture" #endif .endfn feclearexcept,globl +// Checks for floating point exception. +// +// This function may be used to check the thread-local +// floating-point exception status bits, e.g. +// +// feclearexcept(FE_ALL_EXCEPT); +// volatile double x = 0, y = 1 / x; +// assert(fetestexcept(FE_ALL_EXCEPT) == FE_DIVBYZERO); +// +// @param excepts may bitwise-or the following: +// - `FE_INVALID` +// - `FE_DIVBYZERO` +// - `FE_OVERFLOW` +// - `FE_UNDERFLOW` +// - `FE_INEXACT` +// - `FE_ALL_EXCEPT` (all of the above) +// @return mask of which exception status codes are currently set, +// or zero if there aren't any floating point exceptions +fetestexcept: +#ifdef __x86_64__ + and $0x3f,%edi + push %rax + stmxcsr (%rsp) + pop %rsi + fnstsw %ax + or %esi,%eax + and %edi,%eax + ret +#elif defined(__aarch64__) + and w0,w0,#0x1f + mrs x1,fpsr + and w0,w0,w1 + ret +#endif + .endfn fetestexcept,globl + feraiseexcept: #ifdef __x86_64__ and $0x3f,%edi @@ -159,21 +209,3 @@ fesetenv: ret #endif .endfn fesetenv,globl - -fetestexcept: -#ifdef __x86_64__ - and $0x3f,%edi - push %rax - stmxcsr (%rsp) - pop %rsi - fnstsw %ax - or %esi,%eax - and %edi,%eax - ret -#elif defined(__aarch64__) - and w0,w0,#0x1f - mrs x1,fpsr - and w0,w0,w1 - ret -#endif - .endfn fetestexcept,globl diff --git a/libc/tinymath/llrint.c b/libc/intrin/feupdateenv.c similarity index 84% rename from libc/tinymath/llrint.c rename to libc/intrin/feupdateenv.c index 11772e3f3..2a0b6ee58 100644 --- a/libc/tinymath/llrint.c +++ b/libc/intrin/feupdateenv.c @@ -16,21 +16,14 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/math.h" +#include "libc/runtime/fenv.h" /** - * Rounds to nearest integer. + * Restores floating point environment and raises exceptions. */ -long long llrint(double x) { - long long res; -#ifdef __x86_64__ - asm("cvtsd2si\t%1,%0" : "=r"(res) : "x"(x)); -#elif defined(__aarch64__) - asm("frintx\t%d1,%d1\n\t" - "fcvtzs\t%x0,%d1" - : "=r"(res), "+w"(x)); -#else - res = rint(x); -#endif /* __x86_64__ */ - return res; +int feupdateenv(const fenv_t *envp) { + int ex = fetestexcept(FE_ALL_EXCEPT); + fesetenv(envp); + feraiseexcept(ex); + return 0; } diff --git a/libc/intrin/isdebuggerpresent.c b/libc/intrin/isdebuggerpresent.c index 72096463e..cf43ca0ef 100644 --- a/libc/intrin/isdebuggerpresent.c +++ b/libc/intrin/isdebuggerpresent.c @@ -16,6 +16,7 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/calls/cp.internal.h" #include "libc/calls/syscall-sysv.internal.h" #include "libc/dce.h" #include "libc/errno.h" @@ -50,6 +51,7 @@ int IsDebuggerPresent(bool force) { if (!PLEDGED(RPATH)) return false; res = 0; e = errno; + BEGIN_CANCELLATION_POINT; if ((fd = __sys_openat(AT_FDCWD, "/proc/self/status", O_RDONLY, 0)) >= 0) { if ((got = sys_read(fd, buf, sizeof(buf) - 1)) > 0) { buf[got] = '\0'; @@ -60,6 +62,7 @@ int IsDebuggerPresent(bool force) { } sys_close(fd); } + END_CANCELLATION_POINT; errno = e; return res; } diff --git a/libc/intrin/kprintf.greg.c b/libc/intrin/kprintf.greg.c index 5b2364b0f..c86417db3 100644 --- a/libc/intrin/kprintf.greg.c +++ b/libc/intrin/kprintf.greg.c @@ -37,6 +37,7 @@ #include "libc/intrin/weaken.h" #include "libc/limits.h" #include "libc/log/internal.h" +#include "libc/log/libfatal.internal.h" #include "libc/macros.internal.h" #include "libc/nexgen32e/rdtsc.h" #include "libc/nexgen32e/uart.internal.h" @@ -174,6 +175,7 @@ privileged static bool kismapped(int x) { privileged bool kisdangerous(const void *p) { int frame; + if (IsTiny()) return false; if (kisimagepointer(p)) return false; if (kiskernelpointer(p)) return false; if (IsOldStack(p)) return false; @@ -189,7 +191,7 @@ privileged bool kisdangerous(const void *p) { return true; } -privileged static void klog(const char *b, size_t n) { +privileged dontinline void klog(const char *b, size_t n) { #ifdef __x86_64__ int e; bool cf; diff --git a/libc/intrin/printmemoryintervals.c b/libc/intrin/printmemoryintervals.c index 6dc1caac7..485ea8bd2 100644 --- a/libc/intrin/printmemoryintervals.c +++ b/libc/intrin/printmemoryintervals.c @@ -23,8 +23,6 @@ #include "libc/macros.internal.h" #include "libc/runtime/memtrack.internal.h" -#define ADDR(x) ((intptr_t)((int64_t)((uint64_t)(x) << 32) >> 16)) - static bool IsNoteworthyHole(unsigned i, const struct MemoryIntervals *mm) { // gaps between shadow frames aren't interesting // the chasm from heap to stack ruins statistics diff --git a/libc/log/oncrash_arm64.c b/libc/log/oncrash_arm64.c index 06698f251..6c3473ab4 100644 --- a/libc/log/oncrash_arm64.c +++ b/libc/log/oncrash_arm64.c @@ -217,14 +217,17 @@ relegated void __oncrash_arm64(int sig, struct siginfo *si, void *arg) { for (j = 0; j < 4; ++j) { int r = 8 * j + i; if (j) Append(b, " "); - Append(b, "%s%016lx%s %sr%d", ColorRegister(r), - ctx->uc_mcontext.regs[r], reset, r == 8 || r == 9 ? " " : "", - r); + Append(b, "%s%016lx%s %d%s", ColorRegister(r), + ctx->uc_mcontext.regs[r], reset, r, + r == 8 || r == 9 ? " " : ""); } Append(b, "\n"); } // PRINT CURRENT LOCATION + // + // We can get the address of the currently executing function by + // simply examining the program counter. pc = ctx->uc_mcontext.pc; Append(b, " %016lx sp %lx pc", ctx->uc_mcontext.sp, pc); if (pc && (symbol = __get_symbol(st, pc))) { @@ -239,6 +242,13 @@ relegated void __oncrash_arm64(int sig, struct siginfo *si, void *arg) { Append(b, "\n"); // PRINT LINKED LOCATION + // + // The x30 register can usually tell us the address of the parent + // function. This can help us determine the caller in cases where + // stack frames aren't being generated by the compiler; but if we + // have stack frames, then we need to ensure this won't duplicate + // the first element of the frame pointer backtrace below. + fp = (struct StackFrame *)ctx->uc_mcontext.regs[29]; if (IsCode((pc = ctx->uc_mcontext.regs[30]))) { Append(b, " %016lx sp %lx lr", ctx->uc_mcontext.sp, pc); if (pc && (symbol = __get_symbol(st, pc))) { @@ -251,10 +261,18 @@ relegated void __oncrash_arm64(int sig, struct siginfo *si, void *arg) { } } Append(b, "\n"); + if (fp && !kisdangerous(fp) && pc == fp->addr) { + fp = fp->next; + } } // PRINT FRAME POINTERS - fp = (struct StackFrame *)ctx->uc_mcontext.regs[29]; + // + // The prologues and epilogues of non-leaf functions should save + // the frame pointer (x29) and return address (x30) to the stack + // and then set x29 to sp, which is the address of the new frame + // effectively creating a daisy chain letting us trace back into + // the origin of execution, e.g. _start(), or sys_clone_linux(). for (i = 0; fp; fp = fp->next) { if (kisdangerous(fp)) { Append(b, " %016lx \n", fp); @@ -284,9 +302,10 @@ relegated void __oncrash_arm64(int sig, struct siginfo *si, void *arg) { } } } else { - Append(b, "got %G while crashing!\n"); + Append(b, "got %G while crashing!\n", sig); } sys_write(2, b->p, MIN(b->i, b->n)); + __print_maps(); _Exit(128 + sig); } diff --git a/libc/log/showcrashreports.c b/libc/log/showcrashreports.c index fd6bed95b..44965d08a 100644 --- a/libc/log/showcrashreports.c +++ b/libc/log/showcrashreports.c @@ -26,6 +26,7 @@ #include "libc/log/log.h" #include "libc/macros.internal.h" #include "libc/mem/mem.h" +#include "libc/runtime/internal.h" #include "libc/runtime/runtime.h" #include "libc/runtime/stack.h" #include "libc/runtime/symbols.internal.h" @@ -158,4 +159,6 @@ void ShowCrashReports(void) { InstallCrashHandler(SIGBUS, __got_sigbus, ef); // misalign, mmap i/o failed InstallCrashHandler(SIGURG, __got_sigurg, ef); // placeholder GetSymbolTable(); + void __wipe(uintptr_t); + return __wipe(0); } diff --git a/libc/macros.internal.h b/libc/macros.internal.h index aa58074a7..4ac846f28 100644 --- a/libc/macros.internal.h +++ b/libc/macros.internal.h @@ -170,6 +170,31 @@ .previous .endm +// Begins definition of frameless function that calls no functions. +.macro .leafprologue +#if !(defined(TINY) && !defined(__PG__)) +#ifdef __x86_64__ + push %rbp + mov %rsp,%rbp +#elif defined(__aarch64__) + stp x29,x30,[sp,#-16]! + mov x29,sp +#endif +#endif +.endm + +// Ends definition of frameless function that calls no functions. +.macro .leafepilogue +#if !(defined(TINY) && !defined(__PG__)) +#ifdef __x86_64__ + pop %rbp +#elif defined(__aarch64__) + ldp x29,x30,[sp],#16 +#endif +#endif + ret +.endm + // Documents unreachable assembly code. .macro .unreachable #if !defined(NDEBUG) && defined(__x86_64__) @@ -390,22 +415,6 @@ .byte 0x0f,0x1f,0105,\endfunc-. # nopl disp8(%rbp) .endm -// Begins definition of frameless function that calls no functions. -.macro .leafprologue -#if !(defined(TINY) && !defined(__PG__)) - push %rbp - mov %rsp,%rbp -#endif -.endm - -// Ends definition of frameless function that calls no functions. -.macro .leafepilogue -#if !(defined(TINY) && !defined(__PG__)) - pop %rbp -#endif - ret -.endm - // Good alignment for functions where alignment actually helps. // @note 16-byte .macro .alignfunc diff --git a/libc/nexgen32e/rdtsc.h b/libc/nexgen32e/rdtsc.h index 12a4be0fb..46aef6718 100644 --- a/libc/nexgen32e/rdtsc.h +++ b/libc/nexgen32e/rdtsc.h @@ -46,6 +46,20 @@ COSMOPOLITAN_C_START_ asm volatile("mrs\t%0,cntvct_el0" : "=r"(_Ts)); \ _Ts * 48; /* the fudge factor */ \ }) +#elif defined(__powerpc64__) +#define __RDTSC(ASM) \ + ({ \ + uint64_t _Ts; \ + asm volatile("mfspr\t%0,268" : "=r"(_Ts)); \ + _Ts; \ + }) +#elif defined(__riscv) +#define __RDTSC(ASM) \ + ({ \ + uint64_t _Ts; \ + asm volatile("rdcycle\t%0" : "=r"(_Ts)); \ + _Ts; \ + }) #endif COSMOPOLITAN_C_END_ diff --git a/libc/runtime/clone-linux.S b/libc/runtime/clone-linux.S index e2478e73e..46856e95a 100644 --- a/libc/runtime/clone-linux.S +++ b/libc/runtime/clone-linux.S @@ -56,14 +56,19 @@ sys_clone_linux: syscall 1: hlt // ctid was corrupted by program! #elif defined(__aarch64__) + stp x29,x30,[sp,#-16]! + mov x29,sp mov x8,x3 // swap x3 and x4 mov x3,x4 // swap x3 and x4 mov x4,x8 // swap x3 and x4 mov x8,#220 // __NR_clone svc #0 cbz x0,2f + ldp x29,x30,[sp],#16 ret -2: mov x0,x6 // child thread +2: mov x29,#0 // wipe backtrace + mov x28,x3 // set cosmo tls + mov x0,x6 // child thread ldr w1,[x4] // arg2 = *ctid blr x5 mov x8,#93 // __NR_exit diff --git a/libc/runtime/cosmo2.c b/libc/runtime/cosmo2.c index 173d1df01..7915a978b 100644 --- a/libc/runtime/cosmo2.c +++ b/libc/runtime/cosmo2.c @@ -24,11 +24,14 @@ #include "libc/runtime/internal.h" #include "libc/runtime/memtrack.internal.h" #include "libc/runtime/runtime.h" +#include "libc/runtime/stack.h" #include "libc/runtime/syslib.internal.h" +#include "libc/sysv/consts/prot.h" #include "libc/thread/thread.h" #include "libc/thread/tls.h" #ifndef __x86_64__ +void __wipe(uintptr_t); int main(int, char **, char **) __attribute__((__weak__)); typedef int init_f(int argc, char **argv, char **envp, unsigned long *auxv); @@ -46,6 +49,9 @@ extern init_f *__preinit_array_start[] __attribute__((__weak__)); extern init_f *__preinit_array_end[] __attribute__((__weak__)); extern init_f *__init_array_start[] __attribute__((__weak__)); extern init_f *__init_array_end[] __attribute__((__weak__)); +extern char ape_stack_vaddr[] __attribute__((__weak__)); +extern char ape_stack_memsz[] __attribute__((__weak__)); +extern char ape_stack_prot[] __attribute__((__weak__)); extern pthread_mutex_t __mmi_lock_obj; extern int hostos asm("__hostos"); @@ -86,11 +92,21 @@ textstartup void cosmo(long *sp, struct Syslib *m1) { __oldstack = (intptr_t)sp; __pid = sys_getpid().ax; - // initialize mmap() manager extremely early + // initialize memory manager _mmi.n = ARRAYLEN(_mmi.s); _mmi.p = _mmi.s; __mmi_lock_obj._type = PTHREAD_MUTEX_RECURSIVE; + if (!IsTiny()) { + // record system-provided stack to memory manager + _mmi.i = 1; + _mmi.p->x = (uintptr_t)GetStackAddr() >> 16; + _mmi.p->y = + (uintptr_t)(GetStackAddr() + (GetStackSize() - FRAMESIZE)) >> 16; + _mmi.p->size = GetStackSize(); + _mmi.p->prot = PROT_READ | PROT_WRITE; + } + #if 0 #if IsAsan() __asan_init(argc, argv, envp, auxv); @@ -118,6 +134,7 @@ textstartup void cosmo(long *sp, struct Syslib *m1) { } // run program + if (!IsTiny()) __wipe(0); exit(main(argc, argv, envp)); } diff --git a/libc/runtime/enable_tls.c b/libc/runtime/enable_tls.c index 36b719455..42629d1fd 100644 --- a/libc/runtime/enable_tls.c +++ b/libc/runtime/enable_tls.c @@ -16,6 +16,7 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ +#include "ape/sections.internal.h" #include "libc/assert.h" #include "libc/calls/syscall-sysv.internal.h" #include "libc/errno.h" @@ -93,7 +94,7 @@ _Alignas(TLS_ALIGNMENT) static char __static_tls[6016]; */ textstartup void __enable_tls(void) { int tid; - size_t siz; + size_t hiz, siz; char *mem, *tls; struct CosmoTib *tib; @@ -146,8 +147,8 @@ textstartup void __enable_tls(void) { #elif defined(__aarch64__) - siz = ROUNDUP(sizeof(*tib) + 2 * sizeof(void *) + I(_tls_size), - _Alignof(__static_tls)); + hiz = ROUNDUP(sizeof(*tib) + 2 * sizeof(void *), I(_tls_align)); + siz = hiz + I(_tls_size); if (siz <= sizeof(__static_tls)) { mem = __static_tls; } else { @@ -160,12 +161,12 @@ textstartup void __enable_tls(void) { if (IsAsan()) { // there's a roundup(pagesize) gap between .tdata and .tbss // poison that empty space - __asan_poison(mem + sizeof(*tib) + 2 * sizeof(void *) + I(_tdata_size), - I(_tbss_offset) - I(_tdata_size), kAsanProtected); + __asan_poison(mem + hiz + I(_tdata_size), I(_tbss_offset) - I(_tdata_size), + kAsanProtected); } tib = (struct CosmoTib *)mem; - tls = mem + sizeof(*tib) + 2 * sizeof(void *); + tls = mem + hiz; // Set the DTV. // diff --git a/libc/runtime/memtrack.internal.h b/libc/runtime/memtrack.internal.h index fdff38aeb..ecfb3f85c 100644 --- a/libc/runtime/memtrack.internal.h +++ b/libc/runtime/memtrack.internal.h @@ -70,11 +70,45 @@ size_t GetMemtrackSize(struct MemoryIntervals *); #define __mmi_unlock() (__threaded ? __mmi_unlock() : 0) #endif +#ifdef __x86_64__ +/* + * AMD64 has 48-bit signed pointers (PML4T) + * AMD64 is trying to go bigger, i.e. 57-bit (PML5T) + * LINUX forbids userspace from leveraging negative pointers + * Q-EMU may impose smaller vaspaces emulating AMD on non-AMD + * + * Having "signed pointers" means these top sixteen bits + * + * 0x0000000000000000 + * ^^^^ + * + * must be + * + * - 0000 for positive pointers + * - FFFF for negative pointers + * + * otherwise the instruction using the faulty pointer will fault. + */ #define IsLegalPointer(p) \ (-0x800000000000 <= (intptr_t)(p) && (intptr_t)(p) <= 0x7fffffffffff) +#define ADDR_32_TO_48(x) (intptr_t)((uint64_t)(int)(x) << 16) +#elif defined(__aarch64__) +/* + * ARM64 has 48-bit unsigned pointers (Armv8.0-A) + * ARM64 can possibly go bigger, i.e. 52-bit (Armv8.2-A) + * ARM64 can impose arbitrarily smaller vaspaces, e.g. 40/44-bit + * APPLE in their limitless authoritarianism forbids 32-bit pointers + */ +#define IsLegalPointer(p) ((uintptr_t)(p) <= 0xffffffffffff) +#define ADDR_32_TO_48(x) (uintptr_t)((uint64_t)(uint32_t)(x) << 16) +#else +/* RISC-V Sipeed Nezha has 39-bit vaspace */ +#error "unsupported architecture" +#endif -forceinline pureconst bool IsLegalSize(size_t n) { - return n <= 0x7fffffffffff; +forceinline pureconst bool IsLegalSize(uint64_t n) { + /* subtract frame size so roundup is safe */ + return n <= 0x800000000000 - FRAMESIZE; } forceinline pureconst bool IsAutoFrame(int x) { diff --git a/libc/runtime/mmap.c b/libc/runtime/mmap.c index b887410ba..60315a988 100644 --- a/libc/runtime/mmap.c +++ b/libc/runtime/mmap.c @@ -61,11 +61,10 @@ #define IP(X) (intptr_t)(X) #define VIP(X) (void *)IP(X) #define ALIGNED(p) (!(IP(p) & (FRAMESIZE - 1))) -#define ADDR(x) ((int64_t)((uint64_t)(x) << 32) >> 16) #define SHADE(x) (((intptr_t)(x) >> 3) + 0x7fff8000) #define FRAME(x) ((int)((intptr_t)(x) >> 16)) -static unsigned long RoundDownTwoPow(unsigned long x) { +static pureconst unsigned long RoundDownTwoPow(unsigned long x) { return x ? 1ul << _bsrl(x) : 0; } @@ -247,62 +246,49 @@ noasan inline void *_Mmap(void *addr, size_t size, int prot, int flags, int fd, size_t virtualused, virtualneed; if (VERY_UNLIKELY(!size)) { - STRACE("size=0"); - return VIP(einval()); - } - - if (VERY_UNLIKELY(!IsLegalPointer(p))) { - STRACE("p isn't 48-bit"); + STRACE("can't mmap zero bytes"); return VIP(einval()); } if (VERY_UNLIKELY(!ALIGNED(p))) { - STRACE("p isn't 64kb aligned"); - return VIP(einval()); - } - - if (VERY_UNLIKELY(fd < -1)) { - STRACE("mmap(%.12p, %'zu, fd=%d) EBADF", p, size, fd); - return VIP(ebadf()); - } - - if (VERY_UNLIKELY(!((fd != -1) ^ !!(flags & MAP_ANONYMOUS)))) { - STRACE("fd anonymous mismatch"); - return VIP(einval()); - } - - if (VERY_UNLIKELY(!(!!(flags & MAP_PRIVATE) ^ !!(flags & MAP_SHARED)))) { - STRACE("MAP_SHARED ^ MAP_PRIVATE"); - return VIP(einval()); - } - - if (VERY_UNLIKELY(off < 0)) { - STRACE("neg off"); - return VIP(einval()); - } - - if (VERY_UNLIKELY(!ALIGNED(off))) { - STRACE("p isn't 64kb aligned"); - return VIP(einval()); - } - - if (fd == -1) { - size = ROUNDUP(size, FRAMESIZE); - if (IsWindows()) { - prot |= PROT_WRITE; /* kludge */ - } - } else if (__isfdkind(fd, kFdZip)) { - STRACE("fd is zipos handle"); + STRACE("cosmo mmap is 64kb aligned"); return VIP(einval()); } if (VERY_UNLIKELY(!IsLegalSize(size))) { - STRACE("size isn't 48-bit"); + STRACE("mmap size isn't legal"); return VIP(einval()); } - if (VERY_UNLIKELY(INT64_MAX - size < off)) { - STRACE("too large"); + if (VERY_UNLIKELY(!IsLegalPointer(p))) { + STRACE("mmap addr isn't 48-bit"); + return VIP(einval()); + } + + if ((flags & (MAP_SHARED | MAP_PRIVATE)) == (MAP_SHARED | MAP_PRIVATE)) { + flags = MAP_SHARED; // cf. MAP_SHARED_VALIDATE + } + + if (flags & MAP_ANONYMOUS) { + fd = -1; + off = 0; + size = ROUNDUP(size, FRAMESIZE); + if (IsWindows()) prot |= PROT_WRITE; // kludge + if ((flags & MAP_TYPE) == MAP_FILE) { + STRACE("need MAP_PRIVATE or MAP_SHARED"); + return VIP(einval()); + } + } else if (__isfdkind(fd, kFdZip)) { + STRACE("mmap fd is zipos handle"); + return VIP(einval()); + } else if (VERY_UNLIKELY(off < 0)) { + STRACE("mmap negative offset"); + return VIP(einval()); + } else if (VERY_UNLIKELY(!ALIGNED(off))) { + STRACE("mmap off isn't 64kb aligned"); + return VIP(einval()); + } else if (VERY_UNLIKELY(INT64_MAX - size < off)) { + STRACE("mmap too large"); return VIP(einval()); } @@ -310,26 +296,25 @@ noasan inline void *_Mmap(void *addr, size_t size, int prot, int flags, int fd, (__builtin_add_overflow((virtualused = GetMemtrackSize(&_mmi)), size, &virtualneed) || virtualneed > __virtualmax)) { - STRACE("%'zu size + %'zu inuse exceeds virtual memory limit %'zu", size, - virtualused, __virtualmax); + STRACE("mmap %'zu size + %'zu inuse exceeds virtual memory limit %'zu", + size, virtualused, __virtualmax); return VIP(enomem()); } clashes = OverlapsImageSpace(p, size) || OverlapsExistingMapping(p, size); if ((flags & MAP_FIXED_NOREPLACE) == MAP_FIXED_NOREPLACE && clashes) { - STRACE("noreplace overlaps existing"); + STRACE("mmap noreplace overlaps existing"); return VIP(eexist()); } if (__builtin_add_overflow((int)(size >> 16), (int)!!(size & (FRAMESIZE - 1)), &n)) { - STRACE("memory range overflows"); + STRACE("mmap range overflows"); return VIP(einval()); } - a = max(1, RoundDownTwoPow(size) >> 16); - + a = MAX(1, RoundDownTwoPow(size) >> 16); f = (flags & ~MAP_FIXED_NOREPLACE) | MAP_FIXED; if (flags & MAP_FIXED) { x = FRAME(p); @@ -347,7 +332,7 @@ noasan inline void *_Mmap(void *addr, size_t size, int prot, int flags, int fd, } needguard = false; - p = (char *)ADDR(x); + p = (char *)ADDR_32_TO_48(x); if ((f & MAP_TYPE) == MAP_STACK) { if (~f & MAP_ANONYMOUS) { STRACE("MAP_STACK must be anonymous"); @@ -446,7 +431,7 @@ noasan inline void *_Mmap(void *addr, size_t size, int prot, int flags, int fd, * is specified * @param prot can have PROT_READ/PROT_WRITE/PROT_EXEC/PROT_NONE/etc. * @param flags should have one of the following masked by `MAP_TYPE` - * - `MAP_FILE` in which case `fd != -1` should be the case + * - `MAP_FILE` in which case `MAP_ANONYMOUS` shouldn't be used * - `MAP_PRIVATE` for copy-on-write behavior of writeable pages * - `MAP_SHARED` to create shared memory between processes * - `MAP_STACK` to create a grows-down alloc, where a guard page @@ -460,7 +445,7 @@ noasan inline void *_Mmap(void *addr, size_t size, int prot, int flags, int fd, * compile-time checks to ensure some char[8192] vars will not * create an undetectable overflow into another thread's stack * Your `flags` may optionally bitwise or any of the following: - * - `MAP_ANONYMOUS` in which case `fd == -1` should be the case + * - `MAP_ANONYMOUS` in which case `fd` and `off` are ignored * - `MAP_FIXED` in which case `addr` becomes more than a hint * - `MAP_FIXED_NOREPLACE` to protect existing mappings; this is * always polyfilled by mmap() which tracks its own memory and @@ -476,8 +461,7 @@ noasan inline void *_Mmap(void *addr, size_t size, int prot, int flags, int fd, * - `MAP_INHERIT` is NetBSD-only * - `MAP_LOCKED` is Linux-only * @param fd is an open()'d file descriptor, whose contents shall be - * made available w/ automatic reading at the chosen address and - * must be -1 if MAP_ANONYMOUS is specified + * made available w/ automatic reading at the chosen address * @param off specifies absolute byte index of fd's file for mapping, * should be zero if MAP_ANONYMOUS is specified, and sadly needs * to be 64kb aligned too diff --git a/libc/runtime/mprotect-nt.greg.c b/libc/runtime/mprotect-nt.greg.c index 485dca8c3..18acb25b0 100644 --- a/libc/runtime/mprotect-nt.greg.c +++ b/libc/runtime/mprotect-nt.greg.c @@ -21,8 +21,6 @@ #include "libc/runtime/internal.h" #include "libc/runtime/memtrack.internal.h" -#define ADDR(x) ((char *)((int64_t)((uint64_t)(x) << 32) >> 16)) - textwindows int sys_mprotect_nt(void *addr, size_t size, int prot) { int rc = 0; unsigned i; @@ -31,7 +29,7 @@ textwindows int sys_mprotect_nt(void *addr, size_t size, int prot) { __mmi_lock(); p = addr; i = FindMemoryInterval(&_mmi, (intptr_t)p >> 16); - if (i == _mmi.i || (!i && p + size <= ADDR(_mmi.p[0].x))) { + if (i == _mmi.i || (!i && p + size <= (char *)ADDR_32_TO_48(_mmi.p[0].x))) { // memory isn't in memtrack // let's just trust the user then // it's probably part of the executable @@ -42,7 +40,7 @@ textwindows int sys_mprotect_nt(void *addr, size_t size, int prot) { // memory is in memtrack, so use memtrack, to do dimensioning // we unfortunately must do something similar to this for cow for (; i < _mmi.i; ++i) { - x = ADDR(_mmi.p[i].x); + x = (char *)ADDR_32_TO_48(_mmi.p[i].x); y = x + _mmi.p[i].size; if ((x <= p && p < y) || (x < p + size && p + size <= y) || (p < x && y < p + size)) { diff --git a/libc/runtime/mremap.c b/libc/runtime/mremap.c index ec479d8ff..768b9a61f 100644 --- a/libc/runtime/mremap.c +++ b/libc/runtime/mremap.c @@ -36,7 +36,6 @@ #define IP(X) (intptr_t)(X) #define VIP(X) (void *)IP(X) #define ALIGNED(p) (!(IP(p) & (FRAMESIZE - 1))) -#define ADDR(x) ((int64_t)((uint64_t)(x) << 32) >> 16) #define SHADE(x) (((intptr_t)(x) >> 3) + 0x7fff8000) #define FRAME(x) ((int)((intptr_t)(x) >> 16)) @@ -53,8 +52,8 @@ static size_t GetMapSize(size_t i, size_t *j) { } static bool MustMoveMap(intptr_t y, size_t j) { - return ADDR(_mmi.p[j].y) + FRAMESIZE > y || - (j + 1 < _mmi.i && ADDR(_mmi.p[j + 1].x) < y); + return ADDR_32_TO_48(_mmi.p[j].y) + FRAMESIZE > y || + (j + 1 < _mmi.i && ADDR_32_TO_48(_mmi.p[j + 1].x) < y); } /** @@ -178,9 +177,9 @@ void *mremap(void *p, size_t n, size_t m, int f, ... /* void *q */) { return VIP(enomem()); } q = sys_mremap((void *)p, n, m, MREMAP_MAYMOVE | MREMAP_FIXED, - (void *)ADDR(a)); + (void *)ADDR_32_TO_48(a)); KERNTRACE("sys_mremap(%p, %'zu, %'zu, %#b, %p) → %p", p, n, m, - MREMAP_MAYMOVE | MREMAP_FIXED, ADDR(a), q); + MREMAP_MAYMOVE | MREMAP_FIXED, ADDR_32_TO_48(a), q); if (q == MAP_FAILED) return 0; if (ReleaseMemoryIntervals(&_mmi, (uintptr_t)p >> 16, ((uintptr_t)p + n - FRAMESIZE) >> 16, 0) != -1 && @@ -194,7 +193,7 @@ void *mremap(void *p, size_t n, size_t m, int f, ... /* void *q */) { _weaken(__asan_map_shadow)((intptr_t)q, m); } } - return (void *)ADDR(a); + return (void *)ADDR_32_TO_48(a); } else { abort(); } diff --git a/libc/runtime/msync-nt.c b/libc/runtime/msync-nt.c index 519764531..2ff616586 100644 --- a/libc/runtime/msync-nt.c +++ b/libc/runtime/msync-nt.c @@ -25,14 +25,12 @@ #include "libc/sysv/consts/o.h" #include "libc/sysv/consts/prot.h" -#define ADDR(x) ((char *)((int64_t)((uint64_t)(x) << 32) >> 16)) - noasan textwindows int sys_msync_nt(char *addr, size_t size, int flags) { int i, rc = 0; char *a, *b, *x, *y; __mmi_lock(); for (i = FindMemoryInterval(&_mmi, (intptr_t)addr >> 16); i < _mmi.i; ++i) { - x = ADDR(_mmi.p[i].x); + x = (char *)ADDR_32_TO_48(_mmi.p[i].x); y = x + _mmi.p[i].size; if ((x <= addr && addr < y) || (x < addr + size && addr + size <= y) || (addr < x && y < addr + size)) { diff --git a/libc/runtime/munmap.c b/libc/runtime/munmap.c index e4781bdbb..ce9e30b79 100644 --- a/libc/runtime/munmap.c +++ b/libc/runtime/munmap.c @@ -37,7 +37,6 @@ #define IP(X) (intptr_t)(X) #define ALIGNED(p) (!(IP(p) & (FRAMESIZE - 1))) -#define ADDR(x) ((int64_t)((uint64_t)(x) << 32) >> 16) #define FRAME(x) ((int)((intptr_t)(x) >> 16)) static noasan void MunmapShadow(char *p, size_t n) { @@ -97,9 +96,9 @@ static noasan void MunmapImpl(char *p, size_t n) { } // openbsd even requires that if we mapped, for instance a 5 byte // file, that we be sure to call munmap(file, 5). let's abstract! - a = ADDR(beg); - b = ADDR(end) + FRAMESIZE; - c = ADDR(_mmi.p[i].x) + _mmi.p[i].size; + a = ADDR_32_TO_48(beg); + b = ADDR_32_TO_48(end) + FRAMESIZE; + c = ADDR_32_TO_48(_mmi.p[i].x) + _mmi.p[i].size; q = (char *)a; m = MIN(b, c) - a; if (!IsWindows()) { @@ -119,23 +118,23 @@ noasan int _Munmap(char *p, size_t n) { intptr_t a, b, x, y; _unassert(!__vforked); if (UNLIKELY(!n)) { - STRACE("n=0"); + STRACE("munmap n is 0"); return einval(); } if (UNLIKELY(!IsLegalSize(n))) { - STRACE("n isn't 48-bit"); + STRACE("munmap n isn't 48-bit"); return einval(); } if (UNLIKELY(!IsLegalPointer(p))) { - STRACE("p isn't 48-bit"); + STRACE("munmap p isn't 48-bit"); return einval(); } if (UNLIKELY(!IsLegalPointer(p + (n - 1)))) { - STRACE("p+(n-1) isn't 48-bit"); + STRACE("munmap p+(n-1) isn't 48-bit"); return einval(); } if (UNLIKELY(!ALIGNED(p))) { - STRACE("p isn't 64kb aligned"); + STRACE("munmap(%p) isn't 64kb aligned", p); return einval(); } MunmapImpl(p, n); diff --git a/libc/runtime/openexecutable.S b/libc/runtime/openexecutable.S index cc15a70ae..4a970ece7 100644 --- a/libc/runtime/openexecutable.S +++ b/libc/runtime/openexecutable.S @@ -33,50 +33,50 @@ _OpenExecutable: push %rbp mov %rsp,%rbp - pushq __NR_open(%rip) # -0x08(%rbp) - pushq __NR_mmap(%rip) # -0x10(%rbp) - pushq __NR_munmap(%rip) # -0x18(%rbp) - pushq O_RDWR(%rip) # -0x20(%rbp) - pushq MAP_ANONYMOUS(%rip) # -0x28(%rbp) - pushq MAP_PRIVATE(%rip) # -0x30(%rbp) - pushq MAP_FIXED(%rip) # -0x38(%rbp) - pushq __NR_mprotect(%rip) # -0x40(%rbp) - pushq O_RDONLY(%rip) # -0x48(%rbp) - push %rbx # code buffer - push %r12 # data buffer - push %r14 # filename - push %r15 # fd + pushq __NR_open(%rip) // -0x08(%rbp) + pushq __NR_mmap(%rip) // -0x10(%rbp) + pushq __NR_munmap(%rip) // -0x18(%rbp) + pushq O_RDWR(%rip) // -0x20(%rbp) + pushq MAP_ANONYMOUS(%rip) // -0x28(%rbp) + pushq MAP_PRIVATE(%rip) // -0x30(%rbp) + pushq MAP_FIXED(%rip) // -0x38(%rbp) + pushq __NR_mprotect(%rip) // -0x40(%rbp) + pushq O_RDONLY(%rip) // -0x48(%rbp) + push %rbx // code buffer + push %r12 // data buffer + push %r14 // filename + push %r15 // fd // Get filename. lea program_executable_name(%rip),%r14 // Allocate code buffer. - mov -0x10(%rbp),%eax # __NR_mmap + mov -0x10(%rbp),%eax // __NR_mmap xor %edi,%edi mov $PAGESIZE,%esi mov $PROT_READ|PROT_WRITE,%edx - mov -0x28(%rbp),%r10d # MAP_ANONYMOUS - or -0x30(%rbp),%r10d # MAP_PRIVATE + mov -0x28(%rbp),%r10d // MAP_ANONYMOUS + or -0x30(%rbp),%r10d // MAP_PRIVATE mov $-1,%r8 mov $0,%r9 - push %r9 # openbsd:pad - push %r9 # openbsd:align + push %r9 // openbsd:pad + push %r9 // openbsd:align syscall pop %r9 pop %r9 mov %rax,%rbx // Allocate data buffer. - mov -0x10(%rbp),%eax # __NR_mmap + mov -0x10(%rbp),%eax // __NR_mmap xor %edi,%edi mov $ape_ram_filesz,%esi mov $PROT_READ|PROT_WRITE,%edx - mov -0x28(%rbp),%r10d # MAP_ANONYMOUS - or -0x30(%rbp),%r10d # MAP_PRIVATE + mov -0x28(%rbp),%r10d // MAP_ANONYMOUS + or -0x30(%rbp),%r10d // MAP_PRIVATE mov $-1,%r8 mov $0,%r9 - push %r9 # openbsd:pad - push %r9 # openbsd:align + push %r9 // openbsd:pad + push %r9 // openbsd:align syscall pop %r9 pop %r9 @@ -95,7 +95,7 @@ _OpenExecutable: rep movsb // Change protection. - mov -0x40(%rbp),%eax # __NR_mprotect + mov -0x40(%rbp),%eax // __NR_mprotect mov %rbx,%rdi mov $PAGESIZE,%esi mov $PROT_READ|PROT_EXEC,%edx @@ -106,63 +106,63 @@ _OpenExecutable: // // Unmap code segment. -8: mov -0x18(%rbp),%eax # __NR_munmap +8: mov -0x18(%rbp),%eax // __NR_munmap mov $ape_rom_vaddr,%edi mov $ape_rom_filesz,%esi syscall // Unmap data segment. - mov -0x18(%rbp),%eax # __NR_munmap + mov -0x18(%rbp),%eax // __NR_munmap mov $ape_ram_vaddr,%edi mov $ape_ram_filesz,%esi syscall // Open executable in read-write mode. - mov -0x08(%rbp),%eax # __NR_open + mov -0x08(%rbp),%eax // __NR_open mov %r14,%rdi - mov -0x20(%rbp),%esi # O_RDWR - clc # clear carry flag + mov -0x20(%rbp),%esi // O_RDWR + clc // clear carry flag syscall - jc .Lohno # bsd error + jc .Lohno // bsd error cmp $-4095,%eax - jae .Lohno # linux error + jae .Lohno // linux error jmp .Lok // Open executable in read-only mode. -.Lohno: mov -0x08(%rbp),%eax # __NR_open +.Lohno: mov -0x08(%rbp),%eax // __NR_open mov %r14,%rdi - mov -0x48(%rbp),%esi # O_RDONLY + mov -0x48(%rbp),%esi // O_RDONLY syscall .Lok: mov %eax,%r15d // Map code segment. - mov -0x10(%rbp),%eax # __NR_mmap + mov -0x10(%rbp),%eax // __NR_mmap mov $ape_rom_vaddr,%edi mov $ape_rom_filesz,%esi mov $PROT_READ|PROT_EXEC,%edx - mov -0x38(%rbp),%r10d # MAP_FIXED - or -0x30(%rbp),%r10d # MAP_PRIVATE + mov -0x38(%rbp),%r10d // MAP_FIXED + or -0x30(%rbp),%r10d // MAP_PRIVATE mov %r15d,%r8d mov $ape_rom_offset,%r9d - push %r9 # openbsd:pad - push %r9 # openbsd:align + push %r9 // openbsd:pad + push %r9 // openbsd:align syscall pop %r9 pop %r9 // Allocate data segment. - mov -0x10(%rbp),%eax # __NR_mmap + mov -0x10(%rbp),%eax // __NR_mmap mov $ape_ram_vaddr,%edi mov $ape_ram_filesz,%esi mov $PROT_READ|PROT_WRITE,%edx - mov -0x38(%rbp),%r10d # MAP_FIXED - or -0x30(%rbp),%r10d # MAP_PRIVATE - or -0x28(%rbp),%r10d # MAP_ANONYMOUS + mov -0x38(%rbp),%r10d // MAP_FIXED + or -0x30(%rbp),%r10d // MAP_PRIVATE + or -0x28(%rbp),%r10d // MAP_ANONYMOUS mov $-1,%r8 mov $0,%r9 - push %r9 # openbsd:pad - push %r9 # openbsd:align + push %r9 // openbsd:pad + push %r9 // openbsd:align syscall pop %r9 pop %r9 diff --git a/libc/runtime/runtime.mk b/libc/runtime/runtime.mk index 5581cb04a..8f0f7d034 100644 --- a/libc/runtime/runtime.mk +++ b/libc/runtime/runtime.mk @@ -127,6 +127,8 @@ endif # these assembly files are safe to build on aarch64 o/$(MODE)/libc/runtime/init.o: libc/runtime/init.S @$(COMPILE) -AOBJECTIFY.S $(OBJECTIFY.S) $(OUTPUT_OPTION) -c $< +o/$(MODE)/libc/runtime/wipe.o: libc/runtime/wipe.S + @$(COMPILE) -AOBJECTIFY.S $(OBJECTIFY.S) $(OUTPUT_OPTION) -c $< o/$(MODE)/libc/runtime/vfork.o: libc/runtime/vfork.S @$(COMPILE) -AOBJECTIFY.S $(OBJECTIFY.S) $(OUTPUT_OPTION) -c $< o/$(MODE)/libc/runtime/clone-linux.o: libc/runtime/clone-linux.S diff --git a/libc/tinymath/llrintf.c b/libc/runtime/wipe.S similarity index 57% rename from libc/tinymath/llrintf.c rename to libc/runtime/wipe.S index 67b26af20..1ceae8414 100644 --- a/libc/tinymath/llrintf.c +++ b/libc/runtime/wipe.S @@ -1,5 +1,5 @@ -/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ -│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│ +/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│ +│vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi│ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2023 Justine Alexandra Roberts Tunney │ │ │ @@ -16,21 +16,69 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/math.h" +#include "libc/nexgen32e/x86feature.h" +#include "libc/macros.internal.h" -/** - * Rounds to nearest integer. - */ -long long llrintf(float x) { - long long res; +// Zeroes as many registers as possible. +// +// Each caller should declare an appropriate prototype. +// +// @param is return value +// @return is copied from parameter +__wipe: #ifdef __x86_64__ - asm("cvtss2si\t%1,%0" : "=res"(res) : "x"(x)); + mov %rdi,%rax + xor %edi,%edi + xor %esi,%esi + xor %edx,%edx + xor %ecx,%ecx + xor %r8d,%r8d + xor %r9d,%r9d + xor %r10d,%r10d + xor %r11d,%r11d + testb X86_HAVE(AVX)+kCpuids(%rip) + jz .Lsse + vpxor %xmm0,%xmm0,%xmm0 + vpxor %xmm1,%xmm1,%xmm1 + vpxor %xmm2,%xmm2,%xmm2 + vpxor %xmm3,%xmm3,%xmm3 + vpxor %xmm4,%xmm4,%xmm4 + vpxor %xmm5,%xmm5,%xmm5 + vpxor %xmm6,%xmm6,%xmm6 + vpxor %xmm7,%xmm7,%xmm7 + ret +.Lsse: xorps %xmm0,%xmm0 + xorps %xmm1,%xmm1 + xorps %xmm2,%xmm2 + xorps %xmm3,%xmm3 + xorps %xmm4,%xmm4 + xorps %xmm5,%xmm5 + xorps %xmm6,%xmm6 + xorps %xmm7,%xmm7 + ret #elif defined(__aarch64__) - asm("frintx\t%s1,%s1\n\t" - "fcvtzs\t%x0,%s1" - : "=r"(res), "+w"(x)); -#else - res = rintf(x); -#endif /* __x86_64__ */ - return res; -} + mov x1,#0 + mov x2,#0 + mov x3,#0 + mov x4,#0 + mov x5,#0 + mov x6,#0 + mov x7,#0 + mov x9,#0 + mov x10,#0 + mov x11,#0 + mov x12,#0 + mov x13,#0 + mov x14,#0 + mov x15,#0 + movi v0.16b,#0 + movi v1.16b,#0 + movi v2.16b,#0 + movi v3.16b,#0 + movi v4.16b,#0 + movi v5.16b,#0 + movi v6.16b,#0 + movi v7.16b,#0 + ret +#endif + .endfn __wipe,globl,hidden diff --git a/libc/stdio/dtoa.c b/libc/stdio/dtoa.c index 5919745fa..1525c9a8a 100644 --- a/libc/stdio/dtoa.c +++ b/libc/stdio/dtoa.c @@ -29,6 +29,7 @@ #include "libc/fmt/internal.h" #include "libc/intrin/bsr.h" #include "libc/macros.internal.h" +#include "libc/math.h" #include "libc/str/str.h" #include "third_party/gdtoa/gdtoa.h" @@ -53,22 +54,22 @@ union U { double d; uint64_t q; long double ld; - unsigned int ui[4]; - unsigned short us[5]; + uint32_t ui[4]; + uint16_t us[5]; }; static const FPI kFpiDbl = { - .nbits = 53, - .emin = 1 - 1023 - 53 + 1, - .emax = 2046 - 1023 - 53 + 1, + .nbits = DBL_MANT_DIG, + .emin = 3 - DBL_MAX_EXP - DBL_MANT_DIG, + .emax = DBL_MAX_EXP - DBL_MANT_DIG, .rounding = FPI_Round_near, .sudden_underflow = 0, }; static const FPI kFpiLdbl = { - .nbits = 64, - .emin = 1 - 16383 - 64 + 1, - .emax = 32766 - 16383 - 64 + 1, + .nbits = LDBL_MANT_DIG, + .emin = 3 - LDBL_MAX_EXP - LDBL_MANT_DIG, + .emax = LDBL_MAX_EXP - LDBL_MANT_DIG, .rounding = FPI_Round_near, .sudden_underflow = 0, }; @@ -80,21 +81,20 @@ static const char kSpecialFloats[2][2][4] = { static void dfpbits(union U *u, struct FPBits *b) { int ex, i; - uint32_t *bits; b->fpi = &kFpiDbl; b->sign = u->ui[1] & 0x80000000L; - bits = b->bits; - bits[1] = u->ui[1] & 0xfffff; - bits[0] = u->ui[0]; + b->bits[1] = u->ui[1] & 0xfffff; + b->bits[0] = u->ui[0]; if ((ex = (u->ui[1] & 0x7ff00000L) >> 20) != 0) { - if (ex == 0x7ff) { - // Infinity or NaN - i = bits[0] | bits[1] ? STRTOG_NaN : STRTOG_Infinite; - } else { + if (ex != 0x7ff) { i = STRTOG_Normal; - bits[1] |= 0x100000; + b->bits[1] |= 1 << (52 - 32); // set lowest exponent bit + } else if (b->bits[0] | b->bits[1]) { + i = STRTOG_NaN; + } else { + i = STRTOG_Infinite; } - } else if (bits[0] | bits[1]) { + } else if (b->bits[0] | b->bits[1]) { i = STRTOG_Denormal; ex = 1; } else { @@ -104,26 +104,49 @@ static void dfpbits(union U *u, struct FPBits *b) { b->ex = ex - (0x3ff + 52); } -static void xfpbits(union U *u, struct FPBits *b) { - uint32_t *bits; +static void ldfpbits(union U *u, struct FPBits *b) { +#if LDBL_MANT_DIG == 53 + dfpbits(u, b); +#else int ex, i; + uint16_t sex; +#if LDBL_MANT_DIG == 64 + b->bits[3] = 0; + b->bits[2] = 0; + b->bits[1] = ((unsigned)u->us[3] << 16) | u->us[2]; + b->bits[0] = ((unsigned)u->us[1] << 16) | u->us[0]; + sex = u->us[4]; +#elif LDBL_MANT_DIG == 113 + b->bits[3] = u->ui[3] & 0xffff; + b->bits[2] = u->ui[2]; + b->bits[1] = u->ui[1]; + b->bits[0] = u->ui[0]; + sex = u->ui[3] >> 16; +#else +#error "unsupported architecture" +#endif b->fpi = &kFpiLdbl; - b->sign = u->us[4] & 0x8000; - bits = b->bits; - bits[1] = ((unsigned)u->us[3] << 16) | u->us[2]; - bits[0] = ((unsigned)u->us[1] << 16) | u->us[0]; - if ((ex = u->us[4] & 0x7fff) != 0) { - i = STRTOG_Normal; - if (ex == 0x7fff) // Infinity or NaN - i = bits[0] | bits[1] ? STRTOG_NaN : STRTOG_Infinite; - } else if (bits[0] | bits[1]) { + b->sign = sex & 0x8000; + if ((ex = sex & 0x7fff) != 0) { + if (ex != 0x7fff) { + i = STRTOG_Normal; +#if LDBL_MANT_DIG == 113 + b->bits[3] |= 1 << (112 - 32 * 3); // set lowest exponent bit +#endif + } else if (b->bits[0] | b->bits[1] | b->bits[2] | b->bits[3]) { + i = STRTOG_NaN; + } else { + i = STRTOG_Infinite; + } + } else if (b->bits[0] | b->bits[1] | b->bits[2] | b->bits[3]) { i = STRTOG_Denormal; ex = 1; } else { i = STRTOG_Zero; } b->kind = i; - b->ex = ex - (0x3fff + 63); + b->ex = ex - (0x3fff + (LDBL_MANT_DIG - 1)); +#endif } // returns number of hex digits minus 1, or 0 for zero @@ -257,7 +280,7 @@ int __fmt_dtoa(int (*out)(const char *, void *, size_t), void *arg, int d, } else { u.ld = va_arg(va, long double); consumed = __FMT_CONSUMED_LONG_DOUBLE; - xfpbits(&u, &fpb); + ldfpbits(&u, &fpb); s = s0 = gdtoa(fpb.fpi, fpb.ex, fpb.bits, &fpb.kind, 3, prec, &decpt, &se); } @@ -354,7 +377,7 @@ int __fmt_dtoa(int (*out)(const char *, void *, size_t), void *arg, int d, } else { u.ld = va_arg(va, long double); consumed = __FMT_CONSUMED_LONG_DOUBLE; - xfpbits(&u, &fpb); + ldfpbits(&u, &fpb); s = s0 = gdtoa(fpb.fpi, fpb.ex, fpb.bits, &fpb.kind, prec ? 2 : 0, prec, &decpt, &se); } @@ -397,7 +420,7 @@ int __fmt_dtoa(int (*out)(const char *, void *, size_t), void *arg, int d, } else { u.ld = va_arg(va, long double); consumed = __FMT_CONSUMED_LONG_DOUBLE; - xfpbits(&u, &fpb); + ldfpbits(&u, &fpb); s = s0 = gdtoa(fpb.fpi, fpb.ex, fpb.bits, &fpb.kind, prec ? 2 : 0, prec, &decpt, &se); } @@ -460,7 +483,7 @@ int __fmt_dtoa(int (*out)(const char *, void *, size_t), void *arg, int d, if (longdouble) { u.ld = va_arg(va, long double); consumed = __FMT_CONSUMED_LONG_DOUBLE; - xfpbits(&u, &fpb); + ldfpbits(&u, &fpb); } else { u.d = va_arg(va, double); consumed = __FMT_CONSUMED_DOUBLE; diff --git a/libc/sysv/calls/sys_bogus.S b/libc/sysv/calls/sys_bogus.S index 128f7a786..2dcb451a9 100644 --- a/libc/sysv/calls/sys_bogus.S +++ b/libc/sysv/calls/sys_bogus.S @@ -1,2 +1,2 @@ #include "libc/sysv/macros.internal.h" -.scall sys_bogus,0x00b5005002500500,4095,1280,globl +.scall sys_bogus,0x00b5005002500500,1280,1280,globl diff --git a/libc/sysv/calls/sys_open.S b/libc/sysv/calls/sys_open.S deleted file mode 100644 index 3a436c36e..000000000 --- a/libc/sysv/calls/sys_open.S +++ /dev/null @@ -1,2 +0,0 @@ -#include "libc/sysv/macros.internal.h" -.scall sys_open,0x8058058052805802,180,5,globl,hidden diff --git a/libc/sysv/macros.internal.h b/libc/sysv/macros.internal.h index 7b06b4228..20052cf20 100644 --- a/libc/sysv/macros.internal.h +++ b/libc/sysv/macros.internal.h @@ -68,7 +68,8 @@ .else \name: mov x16,#\arm_xnu // apple ordinal mov x8,#\arm_linux // systemd ordinal - eor x9,x9,x9 // clear carry flag + mov x9,#0 // clear carry flag + adds x9,x9,#0 // clear carry flag svc #0 // issue system call bcs 1f b _sysret diff --git a/libc/sysv/syscalls.sh b/libc/sysv/syscalls.sh index 11853697e..d97e26a71 100755 --- a/libc/sysv/syscalls.sh +++ b/libc/sysv/syscalls.sh @@ -36,7 +36,6 @@ dir=libc/sysv/calls scall sys_exit 0x00100100120010e7 0x05e globl hidden # a.k.a. exit_group scall sys_read 0x8038038032803800 0x03f globl hidden scall sys_write 0x8048048042804801 0x040 globl hidden -scall sys_open 0x8058058052805802 0x0b4 globl hidden scall sys_close 0x0060060062006003 0x039 globl hidden scall __sys_stat 0x1b7026fff2152004 0x04f globl hidden # FreeBSD 11→12 fumble; use sys_fstatat(); blocked on Android scall __sys_fstat 0x1b80352272153005 0x050 globl hidden # needs __stat2linux() @@ -363,7 +362,7 @@ scall sys_io_uring_register 0xfffffffffffff1ab 0x1ab globl #────────────────────────RHEL CLOUD────────────────────────────────── # ←──────┬─ red hat terminates community release of enterprise linux circa 2020 scall sys_pledge 0xfff06cffffffffff 0xfff globl hidden # └─ online linux services ban the president of united states of america scall sys_msyscall 0xfff025ffffffffff 0xfff globl # no wrapper -scall sys_bogus 0x00b5005002500500 0xfff globl +scall sys_bogus 0x00b5005002500500 0x500 globl scall sys_open_tree 0xfffffffffffff1ac 0x1ac globl # no wrapper scall sys_move_mount 0xfffffffffffff1ad 0x1ad globl # no wrapper scall sys_fsopen 0xfffffffffffff1ae 0x1ae globl # no wrapper diff --git a/libc/sysv/systemfive.S b/libc/sysv/systemfive.S index 8def555b4..5219a3e6f 100644 --- a/libc/sysv/systemfive.S +++ b/libc/sysv/systemfive.S @@ -107,52 +107,52 @@ __pid: .quad 0 systemfive_cp: push %rbp - mov %rsp,%rbp # so backtraces work -systemfive_cancellable: # our pthread_cancel() miracle code - cmpb $0,__tls_enabled(%rip) # inspired by the musl libc design! - je 1f # we handle linux and bsd together! - mov %fs:0,%r10 # CosmoTib::tib_self - mov 0x28(%r10),%r10 # CosmoTib::tib_pthread - test %r10,%r10 # is it a posix thread? - jz 1f # it's spawn() probably - testb $PT_NOCANCEL,0x00(%r10) # PosixThread::flags - jnz 1f # canceler no cancelling + mov %rsp,%rbp // so backtraces work +systemfive_cancellable: // our pthread_cancel() miracle code + cmpb $0,__tls_enabled(%rip) // inspired by the musl libc design! + je 1f // we handle linux and bsd together! + mov %fs:0,%r10 // CosmoTib::tib_self + mov 0x28(%r10),%r10 // CosmoTib::tib_pthread + test %r10,%r10 // is it a posix thread? + jz 1f // it's spawn() probably + testb $PT_NOCANCEL,0x00(%r10) // PosixThread::flags + jnz 1f // canceler no cancelling #if IsModeDbg() testb $PT_INCANCEL,0x00(%r10) jz 5f #endif - cmp $0,0x04(%r10) # PosixThread::cancelled - jne systemfive_cancel # we will tail call below -1: mov %rcx,%r10 # move the fourth argument - clc # no cancellable system calls exist - syscall # that have 7+ args on the bsd OSes -systemfive_cancellable_end: # i/o calls park here for long time + cmp $0,0x04(%r10) // PosixThread::cancelled + jne systemfive_cancel // we will tail call below +1: mov %rcx,%r10 // move the fourth argument + clc // no cancellable system calls exist + syscall // that have 7+ args on the bsd OSes +systemfive_cancellable_end: // i/o calls park here for long time pop %rbp jnc 2f - neg %rax # turns bsd errno to system v errno -2: cmp $-4095,%rax # but we still check again on eintr - jae 3f # branch because system call failed - ret # done if the system call succeeded -3: neg %eax # now examine the nature of failure - cmp EINTR(%rip),%eax # did the SIGTHR cancel our IO call - jne systemfive_errno # werent interrupted by OnSigCancel - cmpb $0,__tls_enabled(%rip) # make sure it's safe to grab %fs:0 - je systemfive_errno # tls is disabled we can't continue - mov %fs:0,%rcx # CosmoTib::tib_self - mov 0x28(%rcx),%rcx # CosmoTib::tib_pthread - test %rcx,%rcx # is it a posix thread? - jz systemfive_errno # it's spawn() probably - testb $PT_NOCANCEL,0x00(%rcx) # PosixThread::flags - jnz systemfive_errno # cancellation is disabled - cmp $0,0x04(%rcx) # PosixThread::cancelled - je systemfive_errno # we aren't actually cancelled - jmp 4f # now we are in fact cancelled -systemfive_cancel: # SIGTHR will jump here too + neg %rax // turns bsd errno to system v errno +2: cmp $-4095,%rax // but we still check again on eintr + jae 3f // branch because system call failed + ret // done if the system call succeeded +3: neg %eax // now examine the nature of failure + cmp EINTR(%rip),%eax // did the SIGTHR cancel our IO call + jne systemfive_errno // werent interrupted by OnSigCancel + cmpb $0,__tls_enabled(%rip) // make sure it's safe to grab %fs:0 + je systemfive_errno // tls is disabled we can't continue + mov %fs:0,%rcx // CosmoTib::tib_self + mov 0x28(%rcx),%rcx // CosmoTib::tib_pthread + test %rcx,%rcx // is it a posix thread? + jz systemfive_errno // it's spawn() probably + testb $PT_NOCANCEL,0x00(%rcx) // PosixThread::flags + jnz systemfive_errno // cancellation is disabled + cmp $0,0x04(%rcx) // PosixThread::cancelled + je systemfive_errno // we aren't actually cancelled + jmp 4f // now we are in fact cancelled +systemfive_cancel: // SIGTHR will jump here too pop %rbp -4: jmp _pthread_cancel_sys # tail call - .weak _pthread_cancel_sys # must be linked if we're cancelled +4: jmp _pthread_cancel_sys // tail call + .weak _pthread_cancel_sys // must be linked if we're cancelled #if IsModeDbg() -not_a_cancellation_point: # need BEGIN/END_CANCELLATION_POINT +not_a_cancellation_point: // need BEGIN/END_CANCELLATION_POINT nop .weak report_cancellation_point 5: ezlea report_cancellation_point,cx @@ -170,18 +170,18 @@ not_a_cancellation_point: # need BEGIN/END_CANCELLATION_POINT .Lanchorpoint: #if SupportsLinux() || SupportsMetal() systemfive_linux: - and $0xfff,%eax # remove nonlinux bits from ordinal - cmp $0xfff,%eax # checks if unsupported by platform - je systemfive_enosys # never taken branches cost nothing - btr $11,%eax # 0x800 means a call is cancellable - jc systemfive_cp # it is handled by the holiest code - mov %rcx,%r10 # syscall instruction clobbers %rcx - push %rbp # linux never reads args from stack - mov %rsp,%rbp # having frame will help backtraces - syscall # this is known as a context switch - pop %rbp # next we check to see if it failed - cmp $-4095,%rax # system five nexgen32e abi § a.2.1 - jae systemfive_error # encodes errno as neg return value + and $0xfff,%eax // remove nonlinux bits from ordinal + cmp $0xfff,%eax // checks if unsupported by platform + je systemfive_enosys // never taken branches cost nothing + btr $11,%eax // 0x800 means a call is cancellable + jc systemfive_cp // it is handled by the holiest code + mov %rcx,%r10 // syscall instruction clobbers %rcx + push %rbp // linux never reads args from stack + mov %rsp,%rbp // having frame will help backtraces + syscall // this is known as a context switch + pop %rbp // next we check to see if it failed + cmp $-4095,%rax // system five nexgen32e abi § a.2.1 + jae systemfive_error // encodes errno as neg return value ret .endfn systemfive_linux,globl,hidden systemfive_error: @@ -192,9 +192,9 @@ systemfive_error: systemfive_errno: xchg %eax,%ecx .errno - mov %ecx,(%rax) # normalize to c library convention - push $-1 # negative one is only error result - pop %rax # the push pop is to save code size + mov %ecx,(%rax) // normalize to c library convention + push $-1 // negative one is only error result + pop %rax // the push pop is to save code size ret .endfn systemfive_errno,globl,hidden systemfive_enosys: @@ -228,20 +228,20 @@ systemfive_bsdscrub: systemfive_bsd: cmp $0xfff,%ax je systemfive_enosys - btr $11,%eax # checks/reset the 800 cancellable bit + btr $11,%eax // checks/reset the 800 cancellable bit jc systemfive_cp mov %rcx,%r10 - syscall # bsd will need arg on stack sometimes - jc systemfive_errno # bsd sets carry flag if %rax is errno + syscall // bsd will need arg on stack sometimes + jc systemfive_errno // bsd sets carry flag if %rax is errno ret .endfn systemfive_bsd #endif #if SupportsXnu() systemfive_xnu: -// 0x?????????2153??? # how syscalls.sh encodes xnu ordinals +// 0x?????????2153??? // how syscalls.sh encodes xnu ordinals // │└┴┴┐ // │ ├┬┐ -// 0x0000000002000153 # how xnu wants ordinals to be encoded +// 0x0000000002000153 // how xnu wants ordinals to be encoded mov %eax,%r11d and $0x0f000000,%r11d shl $8,%eax @@ -271,10 +271,10 @@ systemfive_xnu: // set by libc/crt/crt.S for XNU/FreeBSD // set by libc/nt/winmain.greg.c for New Technology test %eax,%eax - jnz _init_systemfive_detected # os is already known + jnz _init_systemfive_detected // os is already known #endif #if SupportsOpenbsd() - cmpq $0,(%r15) # OpenBSD has no auxv + cmpq $0,(%r15) // OpenBSD has no auxv jnz 0f mov $_HOSTOPENBSD,%al jmp _init_systemfive_detected @@ -282,7 +282,7 @@ systemfive_xnu: #endif #if SupportsNetbsd() xor %ecx,%ecx -0: cmpq $2014,(%r15,%rcx,8) # NetBSD's AT_EXECFN +0: cmpq $2014,(%r15,%rcx,8) // NetBSD's AT_EXECFN jne 1f mov $_HOSTNETBSD,%al jmp _init_systemfive_detected @@ -371,7 +371,7 @@ _init_systemfive_magnums: xor %ebx,%ebx xor %ecx,%ecx xor %edx,%edx -3: lodsb # decodes uleb128 +3: lodsb // decodes uleb128 movzbl %al,%edx and $127,%dl shl %cl,%rdx @@ -422,23 +422,23 @@ _init_systemfive_pid: #endif #if SupportsBsd() && !defined(TINY) _init_systemfive_sigsys: - testb IsBsd() # BSDs will trap SIGSYS! - jz 1f # We want ENOSYS instead - push %rdi # XNU removed some calls - push %rsi # in past, so this makes - xor %eax,%eax # troubleshooting easier - push %rax # but it's non-essential + testb IsBsd() // BSDs will trap SIGSYS! + jz 1f // We want ENOSYS instead + push %rdi // XNU removed some calls + push %rsi // in past, so this makes + xor %eax,%eax // troubleshooting easier + push %rax // but it's non-essential push %rax push %rax push %rax push %rax - push $SIG_IGN # sigaction_meta size 48 - mov __NR_sigaction,%eax # mag - mov SIGSYS,%edi # sig - mov %rsp,%rsi # new - xor %edx,%edx # old - mov $8,%r10d # for linux - xor %r8d,%r8d # for netbsd + push $SIG_IGN // sigaction_meta size 48 + mov __NR_sigaction,%eax // mag + mov SIGSYS,%edi // sig + mov %rsp,%rsi // new + xor %edx,%edx // old + mov $8,%r10d // for linux + xor %r8d,%r8d // for netbsd syscall add $6*8,%rsp pop %rsi diff --git a/libc/testlib/bench.h b/libc/testlib/bench.h index 5298fe707..8caec1de2 100644 --- a/libc/testlib/bench.h +++ b/libc/testlib/bench.h @@ -1,6 +1,5 @@ #ifndef COSMOPOLITAN_LIBC_BENCH_H_ #define COSMOPOLITAN_LIBC_BENCH_H_ -#include "libc/intrin/safemacros.internal.h" #include "libc/nexgen32e/bench.h" #if !(__ASSEMBLER__ + __LINKER__ + 0) COSMOPOLITAN_C_START_ @@ -9,22 +8,39 @@ COSMOPOLITAN_C_START_ * @fileoverview Microbenchmarking Toolz. */ +#define BENCHLOOPER(START, STOP, N, EXPR) \ + ({ \ + long Iter = 1; \ + long Toto = (N); \ + uint64_t Time1 = START(); \ + asm volatile("" ::: "memory"); \ + for (; Iter < Toto; ++Iter) { \ + asm volatile("" ::: "memory"); \ + EXPR; \ + asm volatile("" ::: "memory"); \ + } \ + asm volatile("" ::: "memory"); \ + uint64_t Time2 = STOP(); \ + (double)(long)(Time2 - Time1) / Iter; \ + }) + #ifndef BENCHLOOP -#define BENCHLOOP(START, STOP, N, INIT, EXPR) \ - ({ \ - unsigned long Iter, Count; \ - uint64_t Time1, Time2; \ - double Average; \ - for (Average = 1, Iter = 1, Count = (N); Iter < Count; ++Iter) { \ - INIT; \ - Time1 = START(); \ - asm volatile("" ::: "memory"); \ - EXPR; \ - asm volatile("" ::: "memory"); \ - Time2 = STOP(); \ - Average += 1. / Iter * ((int)unsignedsubtract(Time2, Time1) - Average); \ - } \ - Average; \ +/* TODO(jart): DELETE */ +#define BENCHLOOP(START, STOP, N, INIT, EXPR) \ + ({ \ + double Average; \ + uint64_t Time1, Time2; \ + unsigned long Iter, Count; \ + for (Average = 1, Iter = 1, Count = (N); Iter < Count; ++Iter) { \ + INIT; \ + Time1 = START(); \ + asm volatile("" ::: "memory"); \ + EXPR; \ + asm volatile("" ::: "memory"); \ + Time2 = STOP(); \ + Average += 1. / Iter * ((int)(Time2 - Time1) - Average); \ + } \ + Average; \ }) #endif /* BENCHLOOP */ diff --git a/libc/testlib/ezbench.h b/libc/testlib/ezbench.h index 531320f1b..9b444a752 100644 --- a/libc/testlib/ezbench.h +++ b/libc/testlib/ezbench.h @@ -1,5 +1,7 @@ #ifndef COSMOPOLITAN_LIBC_TESTLIB_EZBENCH_H_ #define COSMOPOLITAN_LIBC_TESTLIB_EZBENCH_H_ +#include "libc/macros.internal.h" +#include "libc/math.h" #include "libc/nexgen32e/bench.h" #include "libc/nexgen32e/x86feature.h" #include "libc/testlib/bench.h" @@ -18,7 +20,7 @@ COSMOPOLITAN_C_START_ #define EZBENCH2(NAME, INIT, EXPR) \ do { \ int Core, Tries, Interrupts; \ - int64_t Speculative, MemoryStrict; \ + double Speculative, MemoryStrict; \ Tries = 0; \ do { \ __testlib_yield(); \ @@ -53,14 +55,14 @@ COSMOPOLITAN_C_START_ __testlib_getinterrupts() > Interrupts)); \ if (Tries == EZBENCH_TRIES) __testlib_ezbenchwarn(" memory strict"); \ __testlib_ezbenchreport( \ - NAME, MAX(0, Speculative - __testlib_ezbenchcontrol()), \ - MAX(0, MemoryStrict - __testlib_ezbenchcontrol())); \ + NAME, MAX(.001, Speculative - __testlib_ezbenchcontrol()), \ + MAX(.001, MemoryStrict - __testlib_ezbenchcontrol())); \ } while (0) #define EZBENCH3(NAME, NUM, INIT, EXPR) \ do { \ int Core, Tries, Interrupts; \ - int64_t Speculative, MemoryStrict; \ + double Speculative, MemoryStrict; \ Tries = 0; \ do { \ __testlib_yield(); \ @@ -95,14 +97,14 @@ COSMOPOLITAN_C_START_ __testlib_getinterrupts() > Interrupts)); \ if (Tries == EZBENCH_TRIES) __testlib_ezbenchwarn(" memory strict"); \ __testlib_ezbenchreport( \ - NAME, MAX(0, Speculative - __testlib_ezbenchcontrol()), \ - MAX(0, MemoryStrict - __testlib_ezbenchcontrol())); \ + NAME, MAX(.001, Speculative - __testlib_ezbenchcontrol()), \ + MAX(.001, MemoryStrict - __testlib_ezbenchcontrol())); \ } while (0) #define EZBENCH_C(NAME, CONTROL, EXPR) \ do { \ int Core, Tries, Interrupts; \ - int64_t Control, Speculative, MemoryStrict; \ + double Control, Speculative, MemoryStrict; \ Tries = 0; \ do { \ __testlib_yield(); \ @@ -144,53 +146,48 @@ COSMOPOLITAN_C_START_ (__testlib_getcore() != Core && \ __testlib_getinterrupts() > Interrupts)); \ if (Tries == EZBENCH_TRIES) __testlib_ezbenchwarn(" memory strict"); \ - __testlib_ezbenchreport(NAME, MAX(0, Speculative - Control), \ - MAX(0, MemoryStrict - Control)); \ + __testlib_ezbenchreport(NAME, MAX(.001, Speculative - Control), \ + MAX(.001, MemoryStrict - Control)); \ } while (0) -#define EZBENCH_N(NAME, N, EXPR) \ - do { \ - int64_t Speculative, Toto; \ - int Core, Tries, Interrupts; \ - Tries = 0; \ - do { \ - __testlib_yield(); \ - Core = __testlib_getcore(); \ - Interrupts = __testlib_getinterrupts(); \ - EXPR; \ - Speculative = BENCHLOOP(__startbench, __endbench, 32, \ - __polluteregisters(), (EXPR)); \ - } while (++Tries < EZBENCH_TRIES && \ - (__testlib_getcore() != Core && \ - __testlib_getinterrupts() > Interrupts)); \ - if (Tries == EZBENCH_TRIES) __testlib_ezbenchwarn(""); \ - __testlib_ezbenchreport_n( \ - NAME, 'n', N, MAX(0, Speculative - __testlib_ezbenchcontrol())); \ +#define EZBENCH_N(NAME, N, EXPR) \ + do { \ + double Speculative, Toto; \ + int Core, Tries, Interrupts; \ + Tries = 0; \ + do { \ + __testlib_yield(); \ + Core = __testlib_getcore(); \ + Interrupts = __testlib_getinterrupts(); \ + EXPR; \ + Speculative = BENCHLOOPER(__startbench, __endbench, 32, (EXPR)); \ + } while (++Tries < EZBENCH_TRIES && !Speculative); \ + if (Tries == EZBENCH_TRIES) __testlib_ezbenchwarn(""); \ + __testlib_ezbenchreport_n(NAME, 'n', N, Speculative); \ } while (0) -#define EZBENCH_K(NAME, K, EXPR) \ - do { \ - int Core; \ - int64_t Speculative; \ - do { \ - __testlib_yield(); \ - Core = __testlib_getcore(); \ - EXPR; \ - Speculative = BENCHLOOP(__startbench, __endbench, EZBENCH_COUNT, \ - donothing, (EXPR)); \ - } while (Core != __testlib_getcore()); \ - __testlib_ezbenchreport_n( \ - NAME, 'k', K, MAX(0, Speculative - __testlib_ezbenchcontrol())); \ +#define EZBENCH_K(NAME, K, EXPR) \ + do { \ + int Core; \ + double Speculative; \ + do { \ + __testlib_yield(); \ + Core = __testlib_getcore(); \ + EXPR; \ + Speculative = \ + BENCHLOOPER(__startbench, __endbench, EZBENCH_COUNT, (EXPR)); \ + } while (Core != __testlib_getcore()); \ + __testlib_ezbenchreport_n(NAME, 'k', K, Speculative); \ } while (0) void __polluteregisters(void); void __testlib_yield(void); int __testlib_getcore(void); int64_t __testlib_getinterrupts(void); -int64_t __testlib_ezbenchcontrol(void); +double __testlib_ezbenchcontrol(void); void __testlib_ezbenchwarn(const char *); -void __testlib_ezbenchreport(const char *, uint64_t, uint64_t); -void __testlib_ezbenchreport_n(const char *, char, size_t, uint64_t); +void __testlib_ezbenchreport(const char *, double, double); +void __testlib_ezbenchreport_n(const char *, char, size_t, double); #ifdef __STRICT_ANSI__ #undef EZBENCH2 diff --git a/libc/testlib/ezbenchcontrol.c b/libc/testlib/ezbenchcontrol.c index 353a8b89e..792244b1c 100644 --- a/libc/testlib/ezbenchcontrol.c +++ b/libc/testlib/ezbenchcontrol.c @@ -21,9 +21,9 @@ #include "libc/testlib/testlib.h" static bool once; -static int64_t g_ezbenchcontrol; +static double g_ezbenchcontrol; -int64_t __testlib_ezbenchcontrol(void) { +double __testlib_ezbenchcontrol(void) { if (!once) { int Core, Tries, Interrupts; Tries = 0; @@ -38,7 +38,7 @@ int64_t __testlib_ezbenchcontrol(void) { if (Tries == 10) { fputs("warning: failed to accurately benchmark control\n", stderr); } - fprintf(stderr, "will subtract benchmark overhead of %ld cycles\n\n", + fprintf(stderr, "will subtract benchmark overhead of %g cycles\n\n", g_ezbenchcontrol); once = true; } diff --git a/libc/testlib/ezbenchreport.c b/libc/testlib/ezbenchreport.c index b0d2a28f4..53b6cfaaa 100644 --- a/libc/testlib/ezbenchreport.c +++ b/libc/testlib/ezbenchreport.c @@ -26,17 +26,17 @@ STATIC_YOINK("strnwidth"); -void __testlib_ezbenchreport(const char *form, uint64_t c1, uint64_t c2) { - uint64_t ns1, ns2; +void __testlib_ezbenchreport(const char *form, double c1, double c2) { + long ns1, ns2; __warn_if_powersave(); - ns1 = rintl(ConvertTicksToNanos(c1)); - ns2 = rintl(ConvertTicksToNanos(c2)); + ns1 = lrintl(ConvertTicksToNanos(c1)); + ns2 = lrintl(ConvertTicksToNanos(c2)); (fprintf)(stderr, VEIL("r", " * %-19s l: %,9luc %,9luns m: %,9luc %,9luns\n"), - form, c1, ns1, c2, ns2); + form, lrint(c1), ns1, lrint(c2), ns2); } -void __testlib_ezbenchreport_n(const char *form, char z, size_t n, uint64_t c) { +void __testlib_ezbenchreport_n(const char *form, char z, size_t n, double c) { char msg[128]; uint64_t bps; long double cn, lat; diff --git a/libc/testlib/polluteregisters.S b/libc/testlib/polluteregisters.S index df7d75def..314746119 100644 --- a/libc/testlib/polluteregisters.S +++ b/libc/testlib/polluteregisters.S @@ -25,6 +25,8 @@ __polluteregisters: xor %eax,%eax xor %ecx,%ecx xor %edx,%edx + xor %edi,%edi + xor %esi,%esi xor %r8d,%r8d xor %r9d,%r9d xor %r10d,%r10d @@ -49,6 +51,31 @@ __polluteregisters: xorps %xmm6,%xmm6 xorps %xmm7,%xmm7 .leafepilogue +#elif defined(__aarch64__) + mov x0,#0 + mov x1,#0 + mov x2,#0 + mov x3,#0 + mov x4,#0 + mov x5,#0 + mov x6,#0 + mov x7,#0 + mov x9,#0 + mov x10,#0 + mov x11,#0 + mov x12,#0 + mov x13,#0 + mov x14,#0 + mov x15,#0 + movi v0.16b,#0 + movi v1.16b,#0 + movi v2.16b,#0 + movi v3.16b,#0 + movi v4.16b,#0 + movi v5.16b,#0 + movi v6.16b,#0 + movi v7.16b,#0 + ret #else ret #endif @@ -58,7 +85,7 @@ __polluteregisters: // Fill registers with junk data to create false dependencies. // Which shall create the problem that happens w/o vzeroupper. // Or the Core Architecture errata regarding BSR/BSF w/ 64bit. -__polluteregisters: +__polluteregisters_old: .leafprologue mov $-1,%rax mov %rax,%rcx @@ -96,4 +123,4 @@ __polluteregisters: punpcklqdq %xmm0,%xmm6 punpcklqdq %xmm0,%xmm7 .leafepilogue - .endfn __polluteregisters,globl + .endfn __polluteregisters_old,globl diff --git a/libc/testlib/thrashcodecache.S b/libc/testlib/thrashcodecache.S index c932064f8..5fa61cc6f 100644 --- a/libc/testlib/thrashcodecache.S +++ b/libc/testlib/thrashcodecache.S @@ -32,9 +32,9 @@ thrashcodecache: i = 0xdeadbeef 0: .rept 32768/(3+7) rex.wrb - .byte 0001|(i&030) # ADD/OR/... Evqp Gvqp - .byte 0300|(i&033) # %r8-%r11 to %r8-%r11 - .byte 0x49,0x81,0360|(i&003) # XOR immed32,%r8-%r11 + .byte 0001|(i&030) // ADD/OR/... Evqp Gvqp + .byte 0300|(i&033) // %r8-%r11 to %r8-%r11 + .byte 0x49,0x81,0360|(i&003) // XOR immed32,%r8-%r11 .long i i = ((i * 1103515245 + 12345) >> 16) & 0xffffffff .endr diff --git a/libc/thread/mktls.c b/libc/thread/mktls.c index 67a58f478..3b1eb03cb 100644 --- a/libc/thread/mktls.c +++ b/libc/thread/mktls.c @@ -16,6 +16,7 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ +#include "ape/sections.internal.h" #include "libc/dce.h" #include "libc/intrin/asan.internal.h" #include "libc/intrin/asancodes.h" @@ -76,26 +77,25 @@ static char *_mktls_below(struct CosmoTib **out_tib) { } static char *_mktls_above(struct CosmoTib **out_tib) { - size_t siz; + size_t hiz, siz; char *mem, *dtv, *tls; struct CosmoTib *tib, *old; // allocate memory for tdata, tbss, and tib - siz = ROUNDUP(sizeof(struct CosmoTib) + 2 * sizeof(void *) + I(_tls_size), - TLS_ALIGNMENT); + hiz = ROUNDUP(sizeof(*tib) + 2 * sizeof(void *), I(_tls_align)); + siz = hiz + I(_tls_size); mem = memalign(TLS_ALIGNMENT, siz); if (!mem) return 0; // poison memory between tdata and tbss if (IsAsan()) { - __asan_poison( - mem + sizeof(struct CosmoTib) + 2 * sizeof(void *) + I(_tdata_size), - I(_tbss_offset) - I(_tdata_size), kAsanProtected); + __asan_poison(mem + hiz + I(_tdata_size), I(_tbss_offset) - I(_tdata_size), + kAsanProtected); } tib = (struct CosmoTib *)mem; dtv = mem + sizeof(*tib); - tls = dtv + 2 * sizeof(void *); + tls = mem + hiz; // set dtv ((uintptr_t *)dtv)[0] = 1; diff --git a/libc/thread/pthread_getname_np.c b/libc/thread/pthread_getname_np.c index 4170d7c3f..0bd568264 100644 --- a/libc/thread/pthread_getname_np.c +++ b/libc/thread/pthread_getname_np.c @@ -26,6 +26,7 @@ #include "libc/intrin/atomic.h" #include "libc/macros.internal.h" #include "libc/str/str.h" +#include "libc/sysv/consts/at.h" #include "libc/sysv/consts/o.h" #include "libc/sysv/consts/pr.h" #include "libc/thread/posixthread.internal.h" @@ -52,7 +53,7 @@ static errno_t pthread_getname_impl(pthread_t thread, char *name, size_t size) { p = stpcpy(p, "/proc/self/task/"); p = FormatUint32(p, tid); p = stpcpy(p, "/comm"); - if ((fd = sys_open(path, O_RDONLY | O_CLOEXEC, 0)) == -1) { + if ((fd = sys_openat(AT_FDCWD, path, O_RDONLY | O_CLOEXEC, 0)) == -1) { rc = errno; errno = e; return rc; diff --git a/libc/thread/pthread_setname_np.c b/libc/thread/pthread_setname_np.c index 1effca9a7..603d6c1d4 100644 --- a/libc/thread/pthread_setname_np.c +++ b/libc/thread/pthread_setname_np.c @@ -26,6 +26,7 @@ #include "libc/intrin/asmflag.h" #include "libc/intrin/atomic.h" #include "libc/str/str.h" +#include "libc/sysv/consts/at.h" #include "libc/sysv/consts/o.h" #include "libc/sysv/consts/pr.h" #include "libc/thread/posixthread.internal.h" @@ -50,7 +51,7 @@ static errno_t pthread_setname_impl(pthread_t thread, const char *name) { p = stpcpy(p, "/proc/self/task/"); p = FormatUint32(p, tid); p = stpcpy(p, "/comm"); - if ((fd = sys_open(path, O_WRONLY | O_CLOEXEC, 0)) == -1) { + if ((fd = sys_openat(AT_FDCWD, path, O_WRONLY | O_CLOEXEC, 0)) == -1) { rc = errno; errno = e; return rc; diff --git a/libc/thread/tls.h b/libc/thread/tls.h index d101194af..cfa40e197 100644 --- a/libc/thread/tls.h +++ b/libc/thread/tls.h @@ -66,7 +66,11 @@ void __set_tls(struct CosmoTib *); }) #define __adj_tls(tib) (tib) #elif defined(__aarch64__) -#define __get_tls() ((struct CosmoTib *)__builtin_thread_pointer() - 1) +#define __get_tls() \ + ({ \ + register struct CosmoTib *_t asm("x28"); \ + _t - 1; \ + }) #define __adj_tls(tib) ((struct CosmoTib *)(tib) + 1) #endif diff --git a/libc/time/time.h b/libc/time/time.h index b2784f207..e21d116b6 100644 --- a/libc/time/time.h +++ b/libc/time/time.h @@ -26,7 +26,7 @@ int64_t clock(void); int64_t posix2time(int64_t) pureconst; int64_t time(int64_t *); int64_t time2posix(int64_t) pureconst; -long double ConvertTicksToNanos(uint64_t); +long double ConvertTicksToNanos(double); long double dsleep(long double); long double dtime(int); unsigned alarm(unsigned); diff --git a/libc/tinymath/logb.c b/libc/tinymath/logb.c index e5ea47ebd..5f09b9cf0 100644 --- a/libc/tinymath/logb.c +++ b/libc/tinymath/logb.c @@ -20,6 +20,6 @@ double logb(double x) { if (!isfinite(x)) return x * x; - if (x == 0) return -1 / (x * x); + if (!x) return -1 / (x * x); return ilogb(x); } diff --git a/libc/tinymath/logbf.c b/libc/tinymath/logbf.c index 005b942f6..24d42ec32 100644 --- a/libc/tinymath/logbf.c +++ b/libc/tinymath/logbf.c @@ -20,6 +20,6 @@ float logbf(float x) { if (!isfinite(x)) return x * x; - if (x == 0) return -1 / (x * x); + if (!x) return -1 / (x * x); return ilogbf(x); } diff --git a/libc/tinymath/lrint.c b/libc/tinymath/lrint.c index a1443269a..d3f137ec3 100644 --- a/libc/tinymath/lrint.c +++ b/libc/tinymath/lrint.c @@ -1,119 +1,52 @@ -/*-*- mode:c;indent-tabs-mode:t;c-basic-offset:8;tab-width:8;coding:utf-8 -*-│ -│vi: set et ft=c ts=8 tw=8 fenc=utf-8 :vi│ -╚──────────────────────────────────────────────────────────────────────────────╝ +/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ +│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│ +╞══════════════════════════════════════════════════════════════════════════════╡ +│ Copyright 2023 Justine Alexandra Roberts Tunney │ │ │ -│ Musl Libc │ -│ Copyright © 2005-2014 Rich Felker, et al. │ -│ │ -│ Permission is hereby granted, free of charge, to any person obtaining │ -│ a copy of this software and associated documentation files (the │ -│ "Software"), to deal in the Software without restriction, including │ -│ without limitation the rights to use, copy, modify, merge, publish, │ -│ distribute, sublicense, and/or sell copies of the Software, and to │ -│ permit persons to whom the Software is furnished to do so, subject to │ -│ the following conditions: │ -│ │ -│ The above copyright notice and this permission notice shall be │ -│ included in all copies or substantial portions of the Software. │ -│ │ -│ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, │ -│ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF │ -│ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. │ -│ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY │ -│ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, │ -│ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE │ -│ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. │ +│ Permission to use, copy, modify, and/or distribute this software for │ +│ any purpose with or without fee is hereby granted, provided that the │ +│ above copyright notice and this permission notice appear in all copies. │ │ │ +│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ +│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ +│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ +│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ +│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ +│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ +│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ +│ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/limits.h" #include "libc/math.h" -#include "libc/runtime/fenv.h" -#include "libc/tinymath/expo.internal.h" -#include "libc/tinymath/feval.internal.h" - -asm(".ident\t\"\\n\\n\ -Musl libc (MIT License)\\n\ -Copyright 2005-2014 Rich Felker, et. al.\""); -asm(".include \"libc/disclaimer.inc\""); -// clang-format off - -/* -If the result cannot be represented (overflow, nan), then -lrint raises the invalid exception. - -Otherwise if the input was not an integer then the inexact -exception is raised. - -C99 is a bit vague about whether inexact exception is -allowed to be raised when invalid is raised. -(F.9 explicitly allows spurious inexact exceptions, F.9.6.5 -does not make it clear if that rule applies to lrint, but -IEEE 754r 7.8 seems to forbid spurious inexact exception in -the ineger conversion functions) - -So we try to make sure that no spurious inexact exception is -raised in case of an overflow. - -If the bit size of long > precision of double, then there -cannot be inexact rounding in case the result overflows, -otherwise LONG_MAX and LONG_MIN can be represented exactly -as a double. -*/ - -#if LONG_MAX < 1U<<53 && defined(FE_INEXACT) -#if FLT_EVAL_METHOD==0 || FLT_EVAL_METHOD==1 -#define EPS DBL_EPSILON -#elif FLT_EVAL_METHOD==2 -#define EPS LDBL_EPSILON -#endif -static dontinline long lrint_slow(double x) { -// #pragma STDC FENV_ACCESS ON - int e; - e = fetestexcept(FE_INEXACT); - x = rint(x); - if (!e && (x > LONG_MAX || x < LONG_MIN)) - feclearexcept(FE_INEXACT); - /* conversion */ - return x; -} -#else -#define JUST_CALL_RINT -#endif /** - * Rounds to nearest integer. + * Rounds to integer in current rounding mode. + * + * The floating-point exception `FE_INEXACT` is raised if the result is + * different from the input. */ -long lrint(double x) -{ +long lrint(double x) { + long i; #ifdef __x86_64__ - long res; - asm("cvtsd2si\t%1,%0" : "=r"(res) : "x"(x)); - return res; + asm("cvtsd2si\t%1,%0" : "=r"(i) : "x"(x)); #elif defined(__aarch64__) - long res; - asm("frintx\t%d1,%d1\n\t" - "fcvtzs\t%x0,%d1" - : "=r"(res), "+w"(x)); - return res; + asm("frintx\t%d1,%d1\n\t" + "fcvtzs\t%x0,%d1" + : "=r"(i), "+w"(x)); #elif defined(__powerpc64__) && defined(_ARCH_PWR5X) - long res; - asm("fctid\t%0,%1" : "=d"(res) : "d"(x)); - return res; -#elif defined(JUST_CALL_RINT) - return rint(x); + asm("fctid\t%0,%1" : "=d"(i) : "d"(x)); #else - uint32_t abstop = asuint64(x)>>32 & 0x7fffffff; - uint64_t sign = asuint64(x) & (1ULL << 63); - if (abstop < 0x41dfffff) { - /* |x| < 0x7ffffc00, no overflow */ - double_t toint = asdouble(asuint64(1/EPS) | sign); - double_t y = x + toint - toint; - return (long)y; - } - return lrint_slow(x); + i = rint(x); #endif /* __x86_64__ */ + return i; } +#if __SIZEOF_LONG__ == __SIZEOF_LONG_LONG__ +__weak_reference(lrint, llrint); +#endif + #if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 __strong_reference(lrint, lrintl); +#if __SIZEOF_LONG__ == __SIZEOF_LONG_LONG__ +__strong_reference(lrint, llrintl); +#endif #endif diff --git a/libc/tinymath/lrintf.c b/libc/tinymath/lrintf.c index 64b0f5c40..c661d273b 100644 --- a/libc/tinymath/lrintf.c +++ b/libc/tinymath/lrintf.c @@ -19,20 +19,27 @@ #include "libc/math.h" /** - * Rounds to nearest integer. + * Rounds to integer in current rounding mode. + * + * The floating-point exception `FE_INEXACT` is raised if the result is + * different from the input. */ long lrintf(float x) { - long res; + long i; #ifdef __x86_64__ - asm("cvtss2si\t%1,%0" : "=res"(res) : "x"(x)); + asm("cvtss2si\t%1,%0" : "=r"(i) : "x"(x)); #elif defined(__aarch64__) asm("frintx\t%s1,%s1\n\t" "fcvtzs\t%x0,%s1" - : "=r"(res), "+w"(x)); + : "=r"(i), "+w"(x)); #elif defined(__powerpc64__) - asm("fctid\t%0,%1" : "=d"(res) : "f"(x)); + asm("fctid\t%0,%1" : "=d"(i) : "f"(x)); #else - res = rintf(x); + i = rintf(x); #endif /* __x86_64__ */ - return res; + return i; } + +#if __SIZEOF_LONG__ == __SIZEOF_LONG_LONG__ +__weak_reference(lrintf, llrintf); +#endif diff --git a/libc/tinymath/lrintl.c b/libc/tinymath/lrintl.c index d5d052e9e..fea6b8515 100644 --- a/libc/tinymath/lrintl.c +++ b/libc/tinymath/lrintl.c @@ -1,68 +1,41 @@ -/*-*- mode:c;indent-tabs-mode:t;c-basic-offset:8;tab-width:8;coding:utf-8 -*-│ -│vi: set et ft=c ts=8 tw=8 fenc=utf-8 :vi│ -╚──────────────────────────────────────────────────────────────────────────────╝ +/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ +│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│ +╞══════════════════════════════════════════════════════════════════════════════╡ +│ Copyright 2023 Justine Alexandra Roberts Tunney │ │ │ -│ Musl Libc │ -│ Copyright © 2005-2014 Rich Felker, et al. │ -│ │ -│ Permission is hereby granted, free of charge, to any person obtaining │ -│ a copy of this software and associated documentation files (the │ -│ "Software"), to deal in the Software without restriction, including │ -│ without limitation the rights to use, copy, modify, merge, publish, │ -│ distribute, sublicense, and/or sell copies of the Software, and to │ -│ permit persons to whom the Software is furnished to do so, subject to │ -│ the following conditions: │ -│ │ -│ The above copyright notice and this permission notice shall be │ -│ included in all copies or substantial portions of the Software. │ -│ │ -│ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, │ -│ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF │ -│ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. │ -│ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY │ -│ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, │ -│ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE │ -│ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. │ +│ Permission to use, copy, modify, and/or distribute this software for │ +│ any purpose with or without fee is hereby granted, provided that the │ +│ above copyright notice and this permission notice appear in all copies. │ │ │ +│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ +│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ +│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ +│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ +│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ +│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ +│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ +│ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/limits.h" #include "libc/math.h" #include "libc/runtime/fenv.h" -#include "libc/tinymath/expo.internal.h" -#include "libc/tinymath/feval.internal.h" #if !(LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024) -asm(".ident\t\"\\n\\n\ -Musl libc (MIT License)\\n\ -Copyright 2005-2014 Rich Felker, et. al.\""); -asm(".include \"libc/disclaimer.inc\""); -// clang-format off - /** - * Rounds to nearest integer. + * Rounds to integer in current rounding mode. + * + * The floating-point exception `FE_INEXACT` is raised if the result is + * different from the input. */ -long lrintl(long double x) -{ -#ifdef FE_INEXACT -/* -see comments in lrint.c - -Note that if LONG_MAX == 0x7fffffffffffffff && LDBL_MANT_DIG == 64 -then x == 2**63 - 0.5 is the only input that overflows and -raises inexact (with tonearest or upward rounding mode) -*/ -// #pragma STDC FENV_ACCESS ON - int e; - - e = fetestexcept(FE_INEXACT); - x = rintl(x); - if (!e && (x > LONG_MAX || x < LONG_MIN)) - feclearexcept(FE_INEXACT); - /* conversion */ - return x; -#else - return rintl(x); -#endif +long lrintl(long double x) { + fenv_t env; + long double y; + feholdexcept(&env); + y = rintl(x); + if (fetestexcept(FE_INVALID)) { + feclearexcept(FE_INEXACT); + } + feupdateenv(&env); + return y; } #endif /* long double is long */ diff --git a/libc/tinymath/rint.c b/libc/tinymath/rint.c index f2deb3a21..01d0a0b1a 100644 --- a/libc/tinymath/rint.c +++ b/libc/tinymath/rint.c @@ -41,6 +41,12 @@ asm(".include \"libc/disclaimer.inc\""); #endif static const double_t toint = 1/EPS; +/** + * Rounds to integer in current rounding mode. + * + * The floating-point exception `FE_INEXACT` is raised if the result is + * different from the input. + */ double rint(double x) { union {double f; uint64_t i;} u = {x}; diff --git a/libc/tinymath/rintf.c b/libc/tinymath/rintf.c index 9a9ba7ac7..e286c3f6c 100644 --- a/libc/tinymath/rintf.c +++ b/libc/tinymath/rintf.c @@ -43,6 +43,12 @@ asm(".include \"libc/disclaimer.inc\""); #endif static const float_t toint = 1/EPS; +/** + * Rounds to integer in current rounding mode. + * + * The floating-point exception `FE_INEXACT` is raised if the result is + * different from the input. + */ float rintf(float x) { union {float f; uint32_t i;} u = {x}; diff --git a/libc/tinymath/rintl.c b/libc/tinymath/rintl.c index b8d3450f1..da161085c 100644 --- a/libc/tinymath/rintl.c +++ b/libc/tinymath/rintl.c @@ -35,6 +35,12 @@ Copyright 2005-2014 Rich Felker, et. al.\""); asm(".include \"libc/disclaimer.inc\""); // clang-format off +/** + * Rounds to integer in current rounding mode. + * + * The floating-point exception `FE_INEXACT` is raised if the result is + * different from the input. + */ long double rintl(long double x) { static const long double toint = 1/LDBL_EPSILON; diff --git a/net/turfwar/turfwar.mk b/net/turfwar/turfwar.mk index c200b74a2..d3c2e58de 100644 --- a/net/turfwar/turfwar.mk +++ b/net/turfwar/turfwar.mk @@ -71,7 +71,8 @@ o/$(MODE)/net/turfwar/turfbean.com.dbg: \ o/$(MODE)/net/turfwar/turfbean.com: \ o/$(MODE)/net/turfwar/turfbean.com.dbg \ o/$(MODE)/third_party/zip/zip.com \ - o/$(MODE)/tool/build/symtab.com + o/$(MODE)/tool/build/symtab.com \ + $(VM) @$(MAKE_OBJCOPY) @$(MAKE_SYMTAB_CREATE) @$(MAKE_SYMTAB_ZIP) diff --git a/test/libc/calls/pledge2_test.c b/test/libc/calls/pledge2_test.c index c70772678..f3d18c651 100644 --- a/test/libc/calls/pledge2_test.c +++ b/test/libc/calls/pledge2_test.c @@ -25,6 +25,7 @@ #include "libc/intrin/promises.internal.h" #include "libc/runtime/runtime.h" #include "libc/sock/sock.h" +#include "libc/stdio/stdio.h" #include "libc/sysv/consts/af.h" #include "libc/sysv/consts/ipproto.h" #include "libc/sysv/consts/sig.h" @@ -32,10 +33,11 @@ #include "libc/testlib/subprocess.h" #include "libc/testlib/testlib.h" -#ifdef __x86_64__ - void SetUp(void) { - if (!__is_linux_2_6_23() && !IsOpenbsd()) exit(0); + if (pledge(0, 0) == -1) { + fprintf(stderr, "warning: pledge() not supported on this system\n"); + exit(0); + } } TEST(pledge, testSoftError) { @@ -116,5 +118,3 @@ TEST(pledge, testEmptyPledge_doesntUseTrapping) { socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); TERMS(IsOpenbsd() ? SIGABRT : SIGSYS); } - -#endif /* __x86_64__ */ diff --git a/test/libc/calls/pledge_test.c b/test/libc/calls/pledge_test.c index 34d4d29b4..aa9516459 100644 --- a/test/libc/calls/pledge_test.c +++ b/test/libc/calls/pledge_test.c @@ -62,9 +62,6 @@ #include "libc/time/time.h" #include "libc/x/x.h" -// TODO(jart): Get pledge truly working on AARCH64 -#ifdef __x86_64__ - char testlib_enable_tmp_setup_teardown; void OnSig(int sig) { @@ -75,7 +72,10 @@ int sys_memfd_secret(unsigned int); // our ENOSYS threshold void SetUp(void) { __enable_threads(); - if (!__is_linux_2_6_23() && !IsOpenbsd()) exit(0); + if (pledge(0, 0) == -1) { + fprintf(stderr, "warning: pledge() not supported on this system\n"); + exit(0); + } testlib_extract("/zip/life.elf", "life.elf", 0755); testlib_extract("/zip/sock.elf", "sock.elf", 0755); __pledge_mode = PLEDGE_PENALTY_RETURN_EPERM; @@ -659,5 +659,3 @@ BENCH(pledge, bench) { } wait(0); } - -#endif /* __x86_64__ */ diff --git a/test/libc/calls/read_test.c b/test/libc/calls/read_test.c index fd965a9c0..997d5e719 100644 --- a/test/libc/calls/read_test.c +++ b/test/libc/calls/read_test.c @@ -45,28 +45,6 @@ TEST(read, eof) { //////////////////////////////////////////////////////////////////////////////// -static long Read(long fd, void *buf, unsigned long size) { -#ifdef __x86_64__ - long ax, di, si, dx; - asm volatile("syscall" - : "=a"(ax), "=D"(di), "=S"(si), "=d"(dx) - : "0"(__NR_read), "1"(fd), "2"(buf), "3"(size) - : "rcx", "r8", "r9", "r10", "r11", "memory", "cc"); - return ax; -#elif defined(__aarch64__) - register long r0 asm("x0") = (long)fd; - register long r1 asm("x1") = (long)buf; - register long r2 asm("x2") = (long)size; - register long r8 asm("x8") = (long)__NR_read; - register long res_x0 asm("x0"); - asm volatile("svc\t0" - : "=r"(res_x0) - : "r"(r0), "r"(r1), "r"(r2), "r"(r8) - : "memory"); - return res_x0; -#endif -} - BENCH(read, bench) { char buf[16]; ASSERT_SYS(0, 3, open("/dev/zero", O_RDONLY)); @@ -80,7 +58,5 @@ BENCH(read, bench) { preadv(3, (struct iovec[]){{buf, 1}, {buf + 1, 4}}, 2, 0)); EZBENCH2("sys_read", donothing, sys_read(3, buf, 5)); EZBENCH2("sys_readv", donothing, sys_readv(3, &(struct iovec){buf, 5}, 1)); - EZBENCH2("Read", donothing, Read(3, buf, 5)); - EZBENCH2("Read", donothing, Read(3, buf, 5)); ASSERT_SYS(0, 0, close(3)); } diff --git a/test/libc/calls/test.mk b/test/libc/calls/test.mk index e9f52bbb3..d422f566a 100644 --- a/test/libc/calls/test.mk +++ b/test/libc/calls/test.mk @@ -118,25 +118,20 @@ o/$(MODE)/test/libc/calls/ioctl_siocgifconf_test.com.runs: \ o/$(MODE)/test/libc/calls/poll_test.com.runs: \ private .PLEDGE = stdio rpath wpath cpath fattr proc inet -o/$(MODE)/test/libc/calls/fcntl_test.com.runs: \ - private .PLEDGE = stdio rpath wpath cpath fattr proc flock - -o/$(MODE)/test/libc/calls/lock_test.com.runs: \ - private .PLEDGE = stdio rpath wpath cpath fattr proc flock - -o/$(MODE)/test/libc/calls/lock2_test.com.runs: \ - private .PLEDGE = stdio rpath wpath cpath fattr proc flock - +o/$(MODE)/test/libc/calls/fcntl_test.com.runs \ +o/$(MODE)/test/libc/calls/lock_test.com.runs \ +o/$(MODE)/test/libc/calls/lock2_test.com.runs \ o/$(MODE)/test/libc/calls/lock_ofd_test.com.runs: \ private .PLEDGE = stdio rpath wpath cpath fattr proc flock +o/$(MODE)/test/libc/calls/unveil_test.com.runs \ o/$(MODE)/test/libc/calls/openbsd_test.com.runs: \ private .PLEDGE = stdio rpath wpath cpath fattr proc unveil o/$(MODE)/test/libc/calls/fexecve_test.com.runs: \ private .UNSANDBOXED = 1 # for memfd_create() -o/$(MODE)/test/libc/calls/execve_test.com.runs: \ +o/$(MODE)/test/libc/calls/execve_test.com.runs: \ private .UNSANDBOXED = 1 # for memfd_create() o/$(MODE)/test/libc/calls/read_test.com.runs: \ diff --git a/test/libc/calls/unveil_test.c b/test/libc/calls/unveil_test.c index cd6d19a60..4501ec0be 100644 --- a/test/libc/calls/unveil_test.c +++ b/test/libc/calls/unveil_test.c @@ -51,16 +51,21 @@ char testlib_enable_tmp_setup_teardown; struct stat st; -static bool SupportsLandlock(void) { - int e = errno; - bool r = landlock_create_ruleset(0, 0, LANDLOCK_CREATE_RULESET_VERSION) >= 0; - errno = e; - return r; +bool HasUnveilSupport(void) { + return unveil("", 0) >= 0; +} + +bool UnveilCanSecureTruncate(void) { + int abi = unveil("", 0); + return abi == 0 || abi >= 3; } void SetUpOnce(void) { __enable_threads(); - if (!(IsLinux() && SupportsLandlock()) && !IsOpenbsd()) exit(0); + if (!HasUnveilSupport()) { + fprintf(stderr, "warning: unveil() not supported on this system: %m\n"); + exit(0); + } } void SetUp(void) { @@ -68,10 +73,6 @@ void SetUp(void) { ASSERT_SYS(0, 0, stat("/zip/life.elf", &st)); } -bool HasTruncateSupport(void) { - return IsOpenbsd() || landlock_create_ruleset(0, 0, LANDLOCK_CREATE_RULESET_VERSION) >= 3; -} - TEST(unveil, api_differences) { SPAWN(fork); ASSERT_SYS(0, 0, mkdir("foo", 0755)); @@ -249,7 +250,7 @@ TEST(unveil, truncate_isForbiddenBySeccomp) { ASSERT_SYS(0, 0, xbarf("garden/secret.txt", "hello", 5)); ASSERT_SYS(0, 0, unveil("jail", "rw")); ASSERT_SYS(0, 0, unveil(0, 0)); - ASSERT_SYS(!HasTruncateSupport() ? EPERM : EACCES_OR_ENOENT, -1, + ASSERT_SYS(!UnveilCanSecureTruncate() ? EPERM : EACCES_OR_ENOENT, -1, truncate("garden/secret.txt", 0)); if (IsLinux()) { ASSERT_SYS(0, 0, stat("garden/secret.txt", &st)); diff --git a/test/libc/calls/write_test.c b/test/libc/calls/write_test.c index ad6b9fca7..aaad1fb68 100644 --- a/test/libc/calls/write_test.c +++ b/test/libc/calls/write_test.c @@ -96,30 +96,6 @@ TEST(write, rlimitFsizeExceeded_raisesEfbig) { EXITS(0); } -static long Write(long fd, const void *data, unsigned long size) { -#ifdef __x86_64__ - long ax, di, si, dx; - asm volatile("syscall" - : "=a"(ax), "=D"(di), "=S"(si), "=d"(dx) - : "0"(__NR_write), "1"(fd), "2"(data), "3"(size) - : "rcx", "r8", "r9", "r10", "r11", "memory", "cc"); - return ax; -#elif defined(__aarch64__) - register long r0 asm("x0") = (long)fd; - register long r1 asm("x1") = (long)data; - register long r2 asm("x2") = (long)size; - register long r8 asm("x8") = (long)__NR_write; - register long res_x0 asm("x0"); - asm volatile("svc\t0" - : "=r"(res_x0) - : "r"(r0), "r"(r1), "r"(r2), "r"(r8) - : "memory"); - return res_x0; -#else -#error "unsupported architecture" -#endif -} - BENCH(write, bench) { ASSERT_SYS(0, 3, open("/dev/null", O_WRONLY)); EZBENCH2("write", donothing, write(3, "hello", 5)); @@ -127,7 +103,5 @@ BENCH(write, bench) { EZBENCH2("sys_write", donothing, sys_write(3, "hello", 5)); EZBENCH2("sys_writev", donothing, sys_writev(3, &(struct iovec){"hello", 5}, 1)); - EZBENCH2("Write", donothing, Write(3, "hello", 5)); - EZBENCH2("Write", donothing, Write(3, "hello", 5)); ASSERT_SYS(0, 0, close(3)); } diff --git a/test/libc/intrin/dos2errno_test.c b/test/libc/intrin/dos2errno_test.c index 1438bfffb..39e675711 100644 --- a/test/libc/intrin/dos2errno_test.c +++ b/test/libc/intrin/dos2errno_test.c @@ -26,6 +26,7 @@ #include "libc/testlib/testlib.h" TEST(__dos2errno, test) { +#ifdef __x86__ EXPECT_EQ(0, __dos2errno(0)); EXPECT_EQ(EACCES, __dos2errno(kNtErrorSectorNotFound)); EXPECT_EQ(EADDRNOTAVAIL, __dos2errno(kNtErrorInvalidNetname)); @@ -33,4 +34,5 @@ TEST(__dos2errno, test) { if (IsWindows()) { EXPECT_EQ(ENOLCK, __dos2errno(kNtErrorNotLocked)); } +#endif } diff --git a/test/libc/intrin/kprintf_test.c b/test/libc/intrin/kprintf_test.c index ba082ab51..26aa2b0f7 100644 --- a/test/libc/intrin/kprintf_test.c +++ b/test/libc/intrin/kprintf_test.c @@ -221,14 +221,13 @@ TEST(ksnprintf, testSymbols) { } } -#ifdef __x86_64__ TEST(ksnprintf, fuzzTheUnbreakable) { int e; size_t i; uint64_t x; char *f, b[32]; _Alignas(FRAMESIZE) static const char weasel[FRAMESIZE]; - asm("mov\t%1,%0" : "=r"(f) : "g"(weasel)); + f = VEIL("r", weasel); EXPECT_SYS(0, 0, mprotect(f, FRAMESIZE, PROT_READ | PROT_WRITE)); strcpy(f, "hello %s\n"); EXPECT_EQ(12, ksnprintf(b, sizeof(b), f, "world")); @@ -243,7 +242,6 @@ TEST(ksnprintf, fuzzTheUnbreakable) { } EXPECT_SYS(0, 0, mprotect(f, FRAMESIZE, PROT_READ)); } -#endif /* __x86_64__ */ TEST(kprintf, testFailure_wontClobberErrnoAndBypassesSystemCallSupport) { int n; diff --git a/test/libc/intrin/lock_test.c b/test/libc/intrin/lock_test.c index 3c2fad4e0..2bd4cd9a9 100644 --- a/test/libc/intrin/lock_test.c +++ b/test/libc/intrin/lock_test.c @@ -220,7 +220,7 @@ int main(int argc, char *argv[]) { TestContendedLock("PTHREAD_MUTEX_ERRORCHECK RAW TLS", PTHREAD_MUTEX_ERRORCHECK); - __tls_enabled = 0; + __tls_enabled_set(false); TestUncontendedLock("PTHREAD_MUTEX_NORMAL RAW", PTHREAD_MUTEX_NORMAL); TestUncontendedLock("PTHREAD_MUTEX_RECURSIVE RAW", PTHREAD_MUTEX_RECURSIVE); diff --git a/test/libc/intrin/memmove_test.c b/test/libc/intrin/memmove_test.c index 8c99c9d2f..ddaffb2c5 100644 --- a/test/libc/intrin/memmove_test.c +++ b/test/libc/intrin/memmove_test.c @@ -17,10 +17,10 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/macros.internal.h" +#include "libc/mem/gc.internal.h" #include "libc/mem/mem.h" #include "libc/nexgen32e/nexgen32e.h" #include "libc/stdio/rand.h" -#include "libc/mem/gc.internal.h" #include "libc/stdio/stdio.h" #include "libc/str/str.h" #include "libc/testlib/ezbench.h" @@ -83,7 +83,7 @@ TEST(memmove, bighug) { BENCH(memmove, bench) { volatile char *r; - int n, max = 8 * 1024 * 1024; + int n, max = 128 * 1024 * 1024; char *volatile p = gc(calloc(max, 1)); char *volatile q = gc(calloc(max, 1)); EZBENCH_N("memmove", 0, memmove(p, q, 0)); diff --git a/test/libc/intrin/strcmp_test.c b/test/libc/intrin/strcmp_test.c index 10c47cc7a..b47f97950 100644 --- a/test/libc/intrin/strcmp_test.c +++ b/test/libc/intrin/strcmp_test.c @@ -108,8 +108,8 @@ TEST(strncmp, testInequality) { char *s1 = strcpy(malloc(2), "1"); char *s2 = strcpy(malloc(1), ""); ASSERT_EQ(0, strncmp(s1, s2, 0)); - ASSERT_EQ('1', strncmp(s1, s2, 1)); - ASSERT_EQ(-'1', strncmp(s2, s1, 1)); + ASSERT_GT(strncmp(s1, s2, 1), 0); + ASSERT_LT(strncmp(s2, s1, 1), 0); free(s2); free(s1); } diff --git a/test/libc/runtime/arch_prctl_test.c b/test/libc/runtime/arch_prctl_test.c index 44a406815..df8644e75 100644 --- a/test/libc/runtime/arch_prctl_test.c +++ b/test/libc/runtime/arch_prctl_test.c @@ -32,7 +32,7 @@ #ifdef __x86_64__ void SetUpOnce(void) { - __tls_enabled = false; + __tls_enabled_set(false); ASSERT_SYS(0, 0, pledge("stdio rpath", 0)); } diff --git a/test/libc/runtime/brk_test.c b/test/libc/runtime/brk_test.c deleted file mode 100644 index 10a6f28f6..000000000 --- a/test/libc/runtime/brk_test.c +++ /dev/null @@ -1,96 +0,0 @@ -/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ -│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│ -╞══════════════════════════════════════════════════════════════════════════════╡ -│ Copyright 2022 Justine Alexandra Roberts Tunney │ -│ │ -│ Permission to use, copy, modify, and/or distribute this software for │ -│ any purpose with or without fee is hereby granted, provided that the │ -│ above copyright notice and this permission notice appear in all copies. │ -│ │ -│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ -│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ -│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ -│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ -│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ -│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ -│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ -│ PERFORMANCE OF THIS SOFTWARE. │ -╚─────────────────────────────────────────────────────────────────────────────*/ -#include "ape/sections.internal.h" -#include "libc/calls/struct/rlimit.h" -#include "libc/dce.h" -#include "libc/errno.h" -#include "libc/limits.h" -#include "libc/runtime/runtime.h" -#include "libc/sysv/consts/map.h" -#include "libc/sysv/consts/prot.h" -#include "libc/sysv/consts/rlimit.h" -#include "libc/testlib/subprocess.h" -#include "libc/testlib/testlib.h" - -void SetUp(void) { - if (IsWindows()) { - ASSERT_SYS(ENOSYS, -1, brk(0)); - ASSERT_SYS(ENOSYS, MAP_FAILED, sbrk(0)); - exit(0); - } -} - -TEST(sbrk, testReportCurrentBreak) { - ASSERT_SYS(0, _end, sbrk(0)); -} - -TEST(sbrk, hugeDelta_returnsEoverflow) { - ASSERT_SYS(EOVERFLOW, MAP_FAILED, sbrk(INTPTR_MAX)); -} - -TEST(brk, underflowsEnd_returnsEinval) { - ASSERT_SYS(EINVAL, -1, brk(0)); -} - -TEST(sbrk, underflowsEnd_returnsEinval) { - ASSERT_SYS(EINVAL, MAP_FAILED, sbrk(-GUARDSIZE)); -} - -#ifndef __aarch64__ -// not sure if qemu-aarch64 supports this -TEST(sbrk, giantDelta_returnsEnomem) { - if (IsXnu()) return; // mmap polyfills this but brk doesn't right now - if (IsWsl1()) return; // WSL1 setrlimit() is busted - SPAWN(fork); - struct rlimit rl = {1024 * 1024, 1024 * 1024}; - ASSERT_SYS(0, 0, setrlimit(RLIMIT_AS, &rl)); - ASSERT_SYS(ENOMEM, MAP_FAILED, sbrk(1024 * 1024 * 4)); - EXITS(0); -} -#endif - -TEST(sbrk, overlapsExistingMapping_failsWithEexist) { - char *p = (char *)ROUNDUP((intptr_t)_end, FRAMESIZE); - ASSERT_EQ(p, mmap(p, FRAMESIZE, PROT_READ | PROT_WRITE, - MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED, -1, 0)); - ASSERT_SYS(EEXIST, MAP_FAILED, sbrk(FRAMESIZE)); - ASSERT_SYS(0, 0, munmap(p, FRAMESIZE)); -} - -TEST(sbrk, testGrowAndShrink) { - SPAWN(fork); - ASSERT_FALSE(testlib_memoryexists(_end)); - ASSERT_SYS(0, _end, sbrk(GUARDSIZE)); - ASSERT_SYS(0, _end + GUARDSIZE, sbrk(0)); - ASSERT_TRUE(testlib_memoryexists(_end)); - ASSERT_FALSE(testlib_memoryexists(_end + GUARDSIZE)); - ASSERT_SYS(0, _end + GUARDSIZE, sbrk(-GUARDSIZE)); - ASSERT_FALSE(testlib_memoryexists(_end)); - EXITS(0); -} - -TEST(brk, testGrowAndShrink) { - SPAWN(fork); - ASSERT_FALSE(testlib_memoryexists(_end)); - ASSERT_EQ(0, brk(_end + GUARDSIZE)); - ASSERT_TRUE(testlib_memoryexists(_end)); - ASSERT_FALSE(testlib_memoryexists(_end + GUARDSIZE)); - ASSERT_EQ(0, brk(_end)); - EXITS(0); -} diff --git a/test/libc/stdio/dtoa_test.c b/test/libc/stdio/dtoa_test.c index 3f7eca933..6d6c34328 100644 --- a/test/libc/stdio/dtoa_test.c +++ b/test/libc/stdio/dtoa_test.c @@ -101,6 +101,8 @@ TEST(printf, double) { } } +#if LDBL_MANT_DIG == 64 + static const struct { const char *s; const char *f; @@ -155,3 +157,5 @@ TEST(printf, longdouble) { } } } + +#endif // LDBL_MANT_DIG == 64 diff --git a/test/libc/str/highwayhash64_test.c b/test/libc/str/highwayhash64_test.c index 3d16d5ff8..201bbbe8d 100644 --- a/test/libc/str/highwayhash64_test.c +++ b/test/libc/str/highwayhash64_test.c @@ -18,6 +18,7 @@ #include "libc/str/highwayhash64.h" #include "libc/inttypes.h" #include "libc/nexgen32e/crc32.h" +#include "libc/runtime/runtime.h" #include "libc/stdio/rand.h" #include "libc/stdio/stdio.h" #include "libc/str/str.h" diff --git a/test/libc/tinymath/logb_test.c b/test/libc/tinymath/logb_test.c index 73abda775..f5516bdac 100644 --- a/test/libc/tinymath/logb_test.c +++ b/test/libc/tinymath/logb_test.c @@ -18,6 +18,8 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/limits.h" #include "libc/math.h" +#include "libc/stdio/rand.h" +#include "libc/stdio/stdio.h" #include "libc/testlib/testlib.h" TEST(ilogb, yolo) { diff --git a/test/tool/build/lib/alu_test.c b/test/tool/build/lib/alu_test.c index f1184cac9..d92033680 100644 --- a/test/tool/build/lib/alu_test.c +++ b/test/tool/build/lib/alu_test.c @@ -16,6 +16,7 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ +#include "tool/build/lib/alu.h" #include "libc/assert.h" #include "libc/limits.h" #include "libc/runtime/runtime.h" @@ -23,9 +24,9 @@ #include "libc/testlib/ezbench.h" #include "libc/testlib/testlib.h" #include "test/tool/build/lib/optest.h" -#include "tool/build/lib/alu.h" #include "tool/build/lib/case.h" #include "tool/build/lib/flags.h" +#ifdef __x86_64__ #define ALU_TEST 8 @@ -134,3 +135,5 @@ int64_t RunOpTest(char w, int h, uint64_t x, uint64_t y, uint32_t *f) { TEST(alu, test) { RunOpTests(kAluOps, ARRAYLEN(kAluOps), kAluNames); } + +#endif /* __x86_64__ */ diff --git a/test/tool/build/lib/bitscan_test.c b/test/tool/build/lib/bitscan_test.c index d2e8a19b6..9e718f34e 100644 --- a/test/tool/build/lib/bitscan_test.c +++ b/test/tool/build/lib/bitscan_test.c @@ -16,11 +16,12 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ +#include "tool/build/lib/bitscan.h" #include "libc/macros.internal.h" #include "libc/testlib/testlib.h" #include "test/tool/build/lib/numbers.h" -#include "tool/build/lib/bitscan.h" #include "tool/build/lib/flags.h" +#ifdef __x86_64__ #define OSZ 00000000040 #define REXW 00000000100 @@ -103,3 +104,5 @@ TEST(bsf16, test) { if (!zf) ASSERT_EQ(a, b, "%#lx", x); } } + +#endif /* __x86_64__ */ diff --git a/test/tool/build/lib/bsu_test.c b/test/tool/build/lib/bsu_test.c index 1e4053527..290b5dfac 100644 --- a/test/tool/build/lib/bsu_test.c +++ b/test/tool/build/lib/bsu_test.c @@ -25,6 +25,7 @@ #include "tool/build/lib/alu.h" #include "tool/build/lib/flags.h" #include "tool/build/lib/machine.h" +#ifdef __x86_64__ #define NATIVE_ALU2(MODE, INSTRUCTION) \ asm("pushf\n\t" \ @@ -324,3 +325,5 @@ TEST(shld64, smoke) { } } } + +#endif /* __x86_64__ */ diff --git a/test/tool/build/lib/divmul_test.c b/test/tool/build/lib/divmul_test.c index ea0a96639..aaef0059e 100644 --- a/test/tool/build/lib/divmul_test.c +++ b/test/tool/build/lib/divmul_test.c @@ -16,6 +16,7 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ +#include "tool/build/lib/divmul.h" #include "libc/calls/struct/sigaction.h" #include "libc/macros.internal.h" #include "libc/runtime/runtime.h" @@ -25,10 +26,10 @@ #include "libc/testlib/testlib.h" #include "libc/x/xsigaction.h" #include "third_party/xed/x86.h" -#include "tool/build/lib/divmul.h" #include "tool/build/lib/endian.h" #include "tool/build/lib/flags.h" #include "tool/build/lib/machine.h" +#ifdef __x86_64__ #define CX 1 #define OSZ 00000000040 @@ -551,3 +552,5 @@ TEST(div64, test) { } } } + +#endif /* __x86_64__ */ diff --git a/test/tool/build/lib/optest.c b/test/tool/build/lib/optest.c index e7647cbe5..1be12f7a1 100644 --- a/test/tool/build/lib/optest.c +++ b/test/tool/build/lib/optest.c @@ -16,13 +16,14 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ +#include "test/tool/build/lib/optest.h" #include "libc/intrin/weaken.h" #include "libc/macros.internal.h" #include "libc/runtime/runtime.h" #include "libc/stdio/stdio.h" #include "test/tool/build/lib/numbers.h" -#include "test/tool/build/lib/optest.h" #include "tool/build/lib/flags.h" +#ifdef __x86_64__ const char kOpSuffix[] = {'b', 'w', 'l', 'q'}; @@ -91,3 +92,5 @@ void(RunOpTests)(const uint8_t *ops, size_t n, const char *const *opnames, exit(1); } } + +#endif /* __x86_64__ */ diff --git a/test/tool/net/lunix_test.lua b/test/tool/net/lunix_test.lua index 4bb8bd688..67525cca4 100644 --- a/test/tool/net/lunix_test.lua +++ b/test/tool/net/lunix_test.lua @@ -70,28 +70,20 @@ function UnixTest() -- 1. fork off a process -- 2. sandbox the process -- 3. then violate its security - if GetHostOs() == "LINUX" then - reader, writer = assert(unix.pipe()) - if assert(unix.fork()) == 0 then - assert(unix.dup(writer, 2)) - assert(unix.pledge("stdio")) - unix.socket() - unix.exit(0) - end - unix.close(writer) - unix.close(reader) - pid, ws = assert(unix.wait()) - assert(unix.WIFSIGNALED(ws)) - assert(unix.WTERMSIG(ws) == unix.SIGSYS) - elseif GetHostOs() == "OPENBSD" then - if assert(unix.fork()) == 0 then - assert(unix.pledge("stdio")) - unix.socket() - unix.exit(1) - end - pid, ws = assert(unix.wait()) - assert(unix.WIFSIGNALED(ws)) - assert(unix.WTERMSIG(ws) == unix.SIGABRT) + if unix.pledge(nil, nil) then + reader, writer = assert(unix.pipe()) + if assert(unix.fork()) == 0 then + assert(unix.dup(writer, 2)) + assert(unix.pledge("stdio")) + unix.socket() + unix.exit(0) + end + unix.close(writer) + unix.close(reader) + pid, ws = assert(unix.wait()) + assert(unix.WIFSIGNALED(ws)) + assert(unix.WTERMSIG(ws) == unix.SIGSYS or -- Linux + unix.WTERMSIG(ws) == unix.SIGABRT) -- OpenBSD end -- sigaction diff --git a/test/tool/net/redbean_test.c b/test/tool/net/redbean_test.c index 157eb20c8..a977e31b6 100644 --- a/test/tool/net/redbean_test.c +++ b/test/tool/net/redbean_test.c @@ -39,6 +39,7 @@ #include "libc/testlib/testlib.h" #include "libc/x/x.h" #include "third_party/regex/regex.h" +#ifdef __x86_64__ STATIC_YOINK("zip_uri_support"); STATIC_YOINK("o/" MODE "/test/tool/net/redbean-tester.com"); @@ -285,3 +286,5 @@ Z\n", EXPECT_NE(-1, wait(0)); EXPECT_NE(-1, sigprocmask(SIG_SETMASK, &savemask, 0)); } + +#endif /* __x86_64__ */ diff --git a/test/tool/net/test.mk b/test/tool/net/test.mk index c4ebc5cfe..68c2b980d 100644 --- a/test/tool/net/test.mk +++ b/test/tool/net/test.mk @@ -85,7 +85,8 @@ o/$(MODE)/test/tool/net/redbean-tester.com: \ o/$(MODE)/test/tool/net/redbean-tester.com.dbg \ o/$(MODE)/third_party/zip/zip.com \ o/$(MODE)/tool/build/symtab.com \ - $(TOOL_NET_REDBEAN_STANDARD_ASSETS) + $(TOOL_NET_REDBEAN_STANDARD_ASSETS) \ + $(VM) @$(MAKE_OBJCOPY) @$(MAKE_SYMTAB_CREATE) @$(MAKE_SYMTAB_ZIP) diff --git a/test/tool/plinko/test.mk b/test/tool/plinko/test.mk index 0c6b1ca50..7f1f53c76 100644 --- a/test/tool/plinko/test.mk +++ b/test/tool/plinko/test.mk @@ -1,6 +1,8 @@ #-*-mode:makefile-gmake;indent-tabs-mode:t;tab-width:8;coding:utf-8-*-┐ #───vi: set et ft=make ts=8 tw=8 fenc=utf-8 :vi───────────────────────┘ +ifeq ($(ARCH), x86_64) + PKGS += TEST_TOOL_PLINKO TEST_TOOL_PLINKO = $(TOOL_PLINKO_A_DEPS) $(TOOL_PLINKO_A) @@ -86,3 +88,8 @@ o/$(MODE)/test/tool/plinko/library_test.lisp.zip.o: private ZIPOBJ_FLAGS += -B o/$(MODE)/test/tool/plinko: \ $(TEST_TOOL_PLINKO_BINS) \ $(TEST_TOOL_PLINKO_CHECKS) + +else +.PHONY: o/$(MODE)/test/tool/plinko +o/$(MODE)/test/tool/plinko: +endif diff --git a/third_party/awk/awk.mk b/third_party/awk/awk.mk index e2f1538bf..b5f531a4d 100644 --- a/third_party/awk/awk.mk +++ b/third_party/awk/awk.mk @@ -52,7 +52,7 @@ o/$(MODE)/third_party/awk/awk.com.dbg: \ @$(APELINK) o/$(MODE)/third_party/awk/README.zip.o: \ - ZIPOBJ_FLAGS = \ + ZIPOBJ_FLAGS += \ -B THIRD_PARTY_AWK_BINS = $(THIRD_PARTY_AWK_COMS) $(THIRD_PARTY_AWK_COMS:%=%.dbg) diff --git a/third_party/chibicc/parse.c b/third_party/chibicc/parse.c index cb3fea28b..8d5f1eb8a 100644 --- a/third_party/chibicc/parse.c +++ b/third_party/chibicc/parse.c @@ -555,7 +555,7 @@ static Token *thing_attributes(Token *tok, void *arg) { if (consume_attribute(&tok, tok, "noinline") || consume_attribute(&tok, tok, "const") || consume_attribute(&tok, tok, "pure") || - consume_attribute(&tok, tok, "noclone") || + consume_attribute(&tok, tok, "dontclone") || consume_attribute(&tok, tok, "may_alias") || consume_attribute(&tok, tok, "warn_unused_result") || consume_attribute(&tok, tok, "flatten") || diff --git a/third_party/gcc/libexec/gcc/aarch64-linux-musl/9.2.0/ld.sym b/third_party/gcc/libexec/gcc/aarch64-linux-musl/9.2.0/ld.sym new file mode 100644 index 000000000..bee146f79 --- /dev/null +++ b/third_party/gcc/libexec/gcc/aarch64-linux-musl/9.2.0/ld.sym @@ -0,0 +1 @@ +../../../../bin/aarch64-linux-musl-ld.bfd \ No newline at end of file diff --git a/third_party/lua/lunix.c b/third_party/lua/lunix.c index af3e54cb7..41687a47f 100644 --- a/third_party/lua/lunix.c +++ b/third_party/lua/lunix.c @@ -16,6 +16,7 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ +#include "third_party/lua/lunix.h" #include "libc/assert.h" #include "libc/atomic.h" #include "libc/calls/calls.h" @@ -112,7 +113,6 @@ #include "third_party/lua/lgc.h" #include "third_party/lua/lua.h" #include "third_party/lua/luaconf.h" -#include "third_party/lua/lunix.h" #include "third_party/nsync/futex.internal.h" #include "tool/net/luacheck.h" @@ -1488,7 +1488,7 @@ static int LuaUnixPledge(lua_State *L) { int olderr = errno; __pledge_mode = luaL_optinteger(L, 3, 0); return SysretBool(L, "pledge", olderr, - pledge(luaL_checkstring(L, 1), luaL_optstring(L, 2, 0))); + pledge(luaL_optstring(L, 1, 0), luaL_optstring(L, 2, 0))); } // sandbox.unveil([path:str[, permissions:str]]) diff --git a/third_party/make/job.c b/third_party/make/job.c index fda914ef0..e0bf03a19 100644 --- a/third_party/make/job.c +++ b/third_party/make/job.c @@ -2118,6 +2118,7 @@ child_execute_job (struct childbase *child, else if (!(~ipromises & (1ul << PROMISE_INET)) && !(~ipromises & (1ul << PROMISE_DNS))) DB (DB_JOBS, (_("Internet access will be blocked by pledge\n"))); +#ifdef __x86_64__ else { e = errno; @@ -2143,6 +2144,7 @@ child_execute_job (struct childbase *child, } } } +#endif /* [jart] Resolve command into executable path. */ if (!strict || !sandboxed) diff --git a/third_party/make/make.mk b/third_party/make/make.mk index b154db5db..f9bab762e 100644 --- a/third_party/make/make.mk +++ b/third_party/make/make.mk @@ -153,7 +153,8 @@ o/$(MODE)/third_party/make/make.com.dbg: \ o/$(MODE)/third_party/make/make.com: \ o/$(MODE)/third_party/make/make.com.dbg \ o/$(MODE)/third_party/zip/zip.com \ - o/$(MODE)/tool/build/symtab.com + o/$(MODE)/tool/build/symtab.com \ + $(VM) @$(MAKE_OBJCOPY) @$(MAKE_SYMTAB_CREATE) @$(MAKE_SYMTAB_ZIP) diff --git a/third_party/python/freeze.c b/third_party/python/freeze.c index 08c2c9b07..ed6cb16b6 100644 --- a/third_party/python/freeze.c +++ b/third_party/python/freeze.c @@ -5,6 +5,7 @@ │ https://docs.python.org/3/license.html │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/assert.h" +#include "libc/log/log.h" #include "libc/mem/mem.h" #include "third_party/python/Include/bytesobject.h" #include "third_party/python/Include/compile.h" diff --git a/third_party/python/python.mk b/third_party/python/python.mk index a3bdb5c28..af5f9aafe 100644 --- a/third_party/python/python.mk +++ b/third_party/python/python.mk @@ -28,11 +28,16 @@ THIRD_PARTY_PYTHON_CHECKS = \ $(THIRD_PARTY_PYTHON_STAGE1_A).pkg \ $(THIRD_PARTY_PYTHON_STAGE2_A).pkg \ $(THIRD_PARTY_PYTHON_PYTEST_A).pkg \ - $(THIRD_PARTY_PYTHON_PYTEST_PYMAINS:%=o/$(MODE)/%.runs) \ $(THIRD_PARTY_PYTHON_HDRS:%=o/$(MODE)/%.ok) \ o/$(MODE)/third_party/python/python.pkg \ o/$(MODE)/third_party/python/freeze.pkg +# TODO: Deal with aarch64 under qemu not making execve() easy. +ifeq ($(ARCH), x86_64) +THIRD_PARTY_PYTHON_CHECKS += \ + $(THIRD_PARTY_PYTHON_PYTEST_PYMAINS:%=o/$(MODE)/%.runs) +endif + ################################################################################ # STAGE ONE - BOOTSTRAPPING PYTHON @@ -4187,7 +4192,7 @@ $(THIRD_PARTY_PYTHON_HELLO_OBJS): private PYFLAGS += -C2 -m # this directory entry is at the tip of the tree # therefore building it requires special care o/$(MODE)/third_party/python/Lib/.zip.o: third_party/python/.python - @$(COMPILE) -wAZIPOBJ $(ZIPOBJ) -C2 $(OUTPUT_OPTION) third_party/python/.python + @$(COMPILE) -wAZIPOBJ $(ZIPOBJ) -b$(IMAGE_BASE_VIRTUAL) -C2 $(OUTPUT_OPTION) third_party/python/.python # these need to be explictly defined because landlock make won't sandbox # prerequisites with a trailing slash. diff --git a/tool/build/emubin/spiral.c b/tool/build/emubin/spiral.c index 5c77618b4..b7ce27dac 100644 --- a/tool/build/emubin/spiral.c +++ b/tool/build/emubin/spiral.c @@ -57,36 +57,36 @@ forceinline long double tau(void) { return pi() * 2; } -forceinline void sincosl(long double x, long double *sin, long double *cos) { +forceinline void sincosl_(long double x, long double *sin, long double *cos) { asm("fsincos" : "=t"(*sin), "=u"(*cos) : "0"(x)); } -forceinline long double atan2l(long double x, long double y) { +forceinline long double atan2l_(long double x, long double y) { asm("fpatan" : "+t"(x) : "u"(y) : "st(1)"); return x; } -forceinline long lrintl(long double x) { +forceinline long lrintl_(long double x) { long i; asm("fistp%z0\t%0" : "=m"(i) : "t"(x) : "st"); return i; } -forceinline long double truncl(long double x) { +forceinline long double truncl_(long double x) { asm("frndint" : "+t"(x)); return x; } -forceinline long double fabsl(long double x) { +forceinline long double fabsl_(long double x) { asm("fabs" : "+t"(x)); return x; } -forceinline long lroundl(long double x) { +forceinline long lroundl_(long double x) { int s = signbit(x); - x = truncl(fabsl(x) + .5); + x = truncl_(fabsl_(x) + .5); if (s) x = -x; - return lrintl(x); + return lrintl_(x); } static unsigned short GetFpuControlWord(void) { @@ -111,13 +111,13 @@ static void spiral(unsigned char p[25][80][2], unsigned char B[25][80], int g) { int i, x, y; long double a, b, u, v, h; for (a = b = i = 0; i < 1000; ++i) { - sincosl(a, &u, &v); - h = atan2l(u, v) - .333L * g; - x = lroundl(80 + u * b); - y = lroundl(25 + v * b * (1. / ((266 / 64.) * (900 / 1600.)))); + sincosl_(a, &u, &v); + h = atan2l_(u, v) - .333L * g; + x = lroundl_(80 + u * b); + y = lroundl_(25 + v * b * (1. / ((266 / 64.) * (900 / 1600.)))); B[y >> 1][x >> 1] |= 1 << ((y & 1) << 1 | (x & 1)); POKE(p[y >> 1][x >> 1][0], kBlocks[B[y >> 1][x >> 1]]); - POKE(p[y >> 1][x >> 1][1], (lrintl((h + tau()) * (8 / tau())) & 7) + 8); + POKE(p[y >> 1][x >> 1][1], (lrintl_((h + tau()) * (8 / tau())) & 7) + 8); a += .05; b += .05; } diff --git a/tool/emacs/c.lang b/tool/emacs/c.lang index a4c3e4bd5..ceae3bb10 100644 --- a/tool/emacs/c.lang +++ b/tool/emacs/c.lang @@ -88,7 +88,7 @@ Keywords={ "textexit", "externinline", "dontinline", -"noclone", +"dontclone", "donothing", "printfesque", "flattenout", @@ -102,7 +102,7 @@ Keywords={ "forceinline", "nocallersavedregisters", "dontthrow", -"nooptimize", +"dontoptimize", "optimizesize", "optimizespeed", "alignof", diff --git a/tool/emacs/cosmo-c-keywords.el b/tool/emacs/cosmo-c-keywords.el index acd02e23b..38dbda135 100644 --- a/tool/emacs/cosmo-c-keywords.el +++ b/tool/emacs/cosmo-c-keywords.el @@ -51,7 +51,7 @@ "forceinline" "nocallersavedregisters" "dontthrow" - "nooptimize" + "dontoptimize" "optimizesize" "optimizespeed" "alignof" diff --git a/tool/emacs/cosmo-stuff.el b/tool/emacs/cosmo-stuff.el index 26c1c5265..3c40f17c4 100644 --- a/tool/emacs/cosmo-stuff.el +++ b/tool/emacs/cosmo-stuff.el @@ -614,9 +614,8 @@ ((eq major-mode 'sh-mode) (compile (format "sh -c %s" file))) ((eq major-mode 'lua-mode) - (let* ((mode (cosmo--make-mode arg)) - (redbean )) - (compile (format "make -j16 MODE=%s o/%s/tool/net/redbean.com && o/%s/tool/net/redbean.com -i %s" mode mode mode file)))) + (let* ((mode (cosmo--make-mode arg))) + (compile (format "make -j16 MODE=%s o/%s/tool/net/redbean.com && build/run o/%s/tool/net/redbean.com -i %s" mode mode mode file)))) ((and (eq major-mode 'python-mode) (cosmo-startswith "third_party/python/Lib/test/" file)) (let ((mode (cosmo--make-mode arg))) diff --git a/tool/emacs/key.py b/tool/emacs/key.py index 27b8081b7..5ba8c66f0 100644 --- a/tool/emacs/key.py +++ b/tool/emacs/key.py @@ -349,7 +349,7 @@ cosmo_kws = frozenset([ "dontinline", "noinstrument", "nointerpose", - "nooptimize", + "dontoptimize", "noprune", "wontreturn", "nosideeffect", @@ -411,7 +411,7 @@ cosmo_kws = frozenset([ "dontinline", "noinstrument", "nointerpose", - "nooptimize", + "dontoptimize", "noprune", "wontreturn", "nosideeffect", diff --git a/tool/net/definitions.lua b/tool/net/definitions.lua index b020068d3..885a3962a 100644 --- a/tool/net/definitions.lua +++ b/tool/net/definitions.lua @@ -1196,6 +1196,10 @@ function GetHost() end ---@nodiscard function GetHostOs() end +---@return "X86_64"|"AARCH64"|"POWERPC64"|"S390X" isaname string that describes the host instruction set architecture +---@nodiscard +function GetHostIsa() end + ---@param str string|integer monospace display width of string. --- This is useful for fixed-width formatting. For example, CJK characters --- typically take up two cells. This function takes into consideration combining diff --git a/tool/net/help.txt b/tool/net/help.txt index 6d6a776da..b577410fd 100644 --- a/tool/net/help.txt +++ b/tool/net/help.txt @@ -1202,6 +1202,15 @@ FUNCTIONS - `"FREEBSD"` - `"OPENBSD"` + GetHostIsa() → str + Returns string describing host instruction set architecture. + + This can return: + + - `"X86_64"` for Intel and AMD systems + - `"AARCH64"` for ARM64, M1, and Raspberry Pi systems + - `"POWERPC64"` for OpenPOWER Raptor Computing Systems + GetMonospaceWidth(str|char) → int Returns monospace display width of string. This is useful for fixed-width formatting. For example, CJK characters typically take @@ -4296,6 +4305,16 @@ UNIX MODULE OpenBSD should ignore the chown functions without crashing. Linux will just EPERM. + Root access isn't required. Support is limited to OpenBSD and Linux + 2.6.23+ (i.e. RHEL6 c. 2012) so long as Redbean is running directly + on the host system, i.e. not running in a userspace emulator like + Blink or Qemu. If your environment isn't supported, then pledge() + will return 0 and do nothing, rather than raising ENOSYS, so the + apps you share with others will err on the side of not breaking. If + a functionality check is needed, please use `unix.pledge(nil, nil)` + which is a no-op that will fail appropriately when the necessary + system support isn't available to impose security restrictions. + `promises` is a string that may include any of the following groups delimited by spaces. This list has been curated to focus on the system calls for which this module provides wrappers. See the @@ -4502,6 +4521,18 @@ UNIX MODULE This system call is supported natively on OpenBSD and polyfilled on Linux using the Landlock LSM[1]. + This function requires OpenBSD or Linux 5.13+ (2022+). If the kernel + support isn't available (or we're in an emulator like Qemu or Blink) + then zero is returned and nothing happens (instead of raising + ENOSYS) because the files are still unveiled. Use `unix.unveil("", + nil)` to feature check the host system, which is defined as a no-op + that'll fail if the host system doesn't have the necessary features + that allow unix.unveil() impose bona-fide security restrictions. + Otherwise, if everything is good, a return value `>=0` is returned, + where `0` means OpenBSD, and `>=1` means Linux with Landlock LSM, in + which case the return code shall be the maximum supported Landlock + ABI version. + `path` is the file or directory to unveil `permissions` is a string consisting of zero or more of the diff --git a/tool/net/lfuncs.c b/tool/net/lfuncs.c index 91d406a7e..e04176e26 100644 --- a/tool/net/lfuncs.c +++ b/tool/net/lfuncs.c @@ -213,6 +213,23 @@ int LuaGetHostOs(lua_State *L) { return 1; } +int LuaGetHostIsa(lua_State *L) { + const char *s; +#ifdef __x86_64__ + s = "X86_64"; +#elif defined(__aarch64__) + s = "AARCH64"; +#elif defined(__powerpc64__) + s = "POWERPC64"; +#elif defined(__s390x__) + s = "S390X"; +#else +#error "unsupported architecture" +#endif + lua_pushstring(L, s); + return 1; +} + int LuaFormatIp(lua_State *L) { char b[16]; uint32_t ip; diff --git a/tool/net/lfuncs.h b/tool/net/lfuncs.h index e44cce1e9..0f19dcf3d 100644 --- a/tool/net/lfuncs.h +++ b/tool/net/lfuncs.h @@ -41,6 +41,7 @@ int LuaGetCpuCore(lua_State *); int LuaGetCpuCount(lua_State *); int LuaGetCpuNode(lua_State *); int LuaGetCryptoHash(lua_State *); +int LuaGetHostIsa(lua_State *); int LuaGetHostOs(lua_State *); int LuaGetHttpReason(lua_State *); int LuaGetLogLevel(lua_State *); diff --git a/tool/net/redbean.c b/tool/net/redbean.c index 23aab74f6..7df38b32a 100644 --- a/tool/net/redbean.c +++ b/tool/net/redbean.c @@ -1091,7 +1091,6 @@ static void UpdateLuaPath(const char *s) { #endif } - static void ProgramDirectory(const char *path) { char *s; size_t n; @@ -5163,6 +5162,7 @@ static const luaL_Reg kLuaFuncs[] = { {"GetHeader", LuaGetHeader}, // {"GetHeaders", LuaGetHeaders}, // {"GetHost", LuaGetHost}, // + {"GetHostIsa", LuaGetHostIsa}, // {"GetHostOs", LuaGetHostOs}, // {"GetHttpReason", LuaGetHttpReason}, // {"GetHttpVersion", LuaGetHttpVersion}, // @@ -6905,6 +6905,7 @@ static int HandleConnection(size_t i) { } static void MakeExecutableModifiable(void) { +#ifdef __x86_64__ int ft; size_t n; extern char ape_rom_vaddr[] __attribute__((__weak__)); @@ -6923,6 +6924,9 @@ static void MakeExecutableModifiable(void) { ftrace_install(); ftrace_enabled(ft); } +#else + // TODO +#endif } static int HandleReadline(void) {