Make improvements

This change progresses our AARCH64 support:

- The AARCH64 build and tests are now passing
- Add 128-bit floating-point support to printf()
- Fix clone() so it initializes cosmo's x28 TLS register
- Fix TLS memory layout issue with aarch64 _Alignas vars
- Revamp microbenchmarking tools so they work on aarch64
- Make some subtle improvements to aarch64 crash reporting
- Make kisdangerous() memory checks more accurate on aarch64
- Remove sys_open() since it's not available on Linux AARCH64

This change makes general improvements to Cosmo and Redbean:

- Introduce GetHostIsa() function in Redbean
- You can now feature check using pledge(0, 0)
- You can now feature check using unveil("",0)
- Refactor some more x86-specific asm comments
- Refactor and write docs for some libm functions
- Make the mmap() API behave more similar to Linux
- Fix WIFSIGNALED() which wrongly returned true for zero
- Rename some obscure cosmo keywords from noFOO to dontFOO
This commit is contained in:
Justine Tunney 2023-06-03 08:12:13 -07:00
parent 5655c9a4e7
commit 8f522cb702
No known key found for this signature in database
GPG key ID: BE714B4575D6E328
116 changed files with 1194 additions and 1025 deletions

View file

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

View file

@ -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");

View file

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

View file

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

View file

@ -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__));

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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);
}

View file

@ -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 */
}

View file

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

View file

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

View file

@ -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()) {

View file

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

View file

@ -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();
}

View file

@ -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_ */

View file

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

View file

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

View file

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

View file

@ -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);
}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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 <dangerous fp>\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);
}

View file

@ -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);
}

View file

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

View file

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

View file

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

View file

@ -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));
}

View file

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

View file

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

View file

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

View file

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

View file

@ -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();
}

View file

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

View file

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

View file

@ -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:
// <LIMBO>
// 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

View file

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

View file

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

View file

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

View file

@ -1,2 +1,2 @@
#include "libc/sysv/macros.internal.h"
.scall sys_bogus,0x00b5005002500500,4095,1280,globl
.scall sys_bogus,0x00b5005002500500,1280,1280,globl

View file

@ -1,2 +0,0 @@
#include "libc/sysv/macros.internal.h"
.scall sys_open,0x8058058052805802,180,5,globl,hidden

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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);
}

View file

@ -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);
}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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__ */

View file

@ -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__ */

View file

@ -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));
}

View file

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

View file

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

View file

@ -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));
}

View file

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

View file

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

View file

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

View file

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

View file

@ -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);
}

View file

@ -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));
}

View file

@ -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);
}

View file

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

View file

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

View file

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

View file

@ -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__ */

View file

@ -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__ */

View file

@ -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__ */

View file

@ -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__ */

View file

@ -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__ */

View file

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

View file

@ -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__ */

View file

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

View file

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

View file

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

View file

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

Some files were not shown because too many files have changed in this diff Show more