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: .SUFFIXES:
.DELETE_ON_ERROR: .DELETE_ON_ERROR:
.FEATURES: output-sync .FEATURES: output-sync
.PHONY: all o bins check test depend tags .PHONY: all o bins check test depend tags aarch64
ifneq ($(m),) ifneq ($(m),)
ifeq ($(MODE),) ifeq ($(MODE),)
@ -267,7 +267,7 @@ CHECKS = $(foreach x,$(PKGS),$($(x)_CHECKS))
bins: $(BINS) bins: $(BINS)
check: $(CHECKS) check: $(CHECKS)
test: $(TESTS) test: $(TESTS) aarch64
depend: o/$(MODE)/depend depend: o/$(MODE)/depend
tags: TAGS HTAGS tags: TAGS HTAGS
@ -424,6 +424,10 @@ toolchain: o/cosmopolitan.h \
o/$(MODE)/cosmopolitan.a \ o/$(MODE)/cosmopolitan.a \
o/$(MODE)/third_party/libcxx/libcxx.a o/$(MODE)/third_party/libcxx/libcxx.a
aarch64: private .UNSANDBOXED = true
aarch64:
$(MAKE) m=aarch64
# UNSPECIFIED PREREQUISITES TUTORIAL # UNSPECIFIED PREREQUISITES TUTORIAL
# #
# A build rule must exist for all files that make needs to consider in # 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 -*-│ /*-*- mode: ld-script; indent-tabs-mode: nil; tab-width: 2; coding: utf-8 -*-│
│vi: set et sts=2 tw=2 fenc=utf-8 :vi│ │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" #include "libc/zip.h"
ENTRY(_start) ENTRY(_start)
OUTPUT_ARCH(aarch64) OUTPUT_ARCH(aarch64)
OUTPUT_FORMAT("elf64-littleaarch64", OUTPUT_FORMAT("elf64-littleaarch64",
"elf64-bigaarch64", "elf64-bigaarch64",
"elf64-littleaarch64") "elf64-littleaarch64")
SECTIONS { SECTIONS {
PROVIDE(__executable_start = SEGMENT_START("text-segment", IMAGE_BASE_VIRTUAL)); PROVIDE(__executable_start = SEGMENT_START("text-segment", IMAGE_BASE_VIRTUAL));
. = SEGMENT_START("text-segment", IMAGE_BASE_VIRTUAL) + SIZEOF_HEADERS; . = SEGMENT_START("text-segment", IMAGE_BASE_VIRTUAL) + SIZEOF_HEADERS;
.interp : { *(.interp) } .interp : { *(.interp) }
.note.gnu.build-id : { *(.note.gnu.build-id) } .note.gnu.build-id : { *(.note.gnu.build-id) }
.hash : { *(.hash) } .hash : { *(.hash) }
.gnu.hash : { *(.gnu.hash) } .gnu.hash : { *(.gnu.hash) }
.dynsym : { *(.dynsym) } .dynsym : { *(.dynsym) }
.dynstr : { *(.dynstr) } .dynstr : { *(.dynstr) }
.gnu.version : { *(.gnu.version) } .gnu.version : { *(.gnu.version) }
.gnu.version_d : { *(.gnu.version_d) } .gnu.version_d : { *(.gnu.version_d) }
.gnu.version_r : { *(.gnu.version_r) } .gnu.version_r : { *(.gnu.version_r) }
.rela.init : { *(.rela.init) } .rela.init : { *(.rela.init) }
.rela.text : { *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*) } .rela.text : { *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*) }
.rela.fini : { *(.rela.fini) } .rela.fini : { *(.rela.fini) }
.rela.rodata : { *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*) } .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.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.data : { *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*) }
.rela.tdata : { *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*) } .rela.tdata : { *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*) }
.rela.tbss : { *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*) } .rela.tbss : { *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*) }
.rela.ctors : { *(.rela.ctors) } .rela.ctors : { *(.rela.ctors) }
.rela.dtors : { *(.rela.dtors) } .rela.dtors : { *(.rela.dtors) }
.rela.got : { *(.rela.got) } .rela.got : { *(.rela.got) }
.rela.bss : { *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*) } .rela.bss : { *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*) }
.rela.ifunc : { *(.rela.ifunc) } .rela.ifunc : { *(.rela.ifunc) }
.rela.plt : { .rela.plt : {
*(.rela.plt) *(.rela.plt)
@ -102,9 +88,9 @@ SECTIONS {
} }
.comment : { .comment : {
KEEP(*(.commentprologue)) PROVIDE_HIDDEN(kLegalNotices = .);
KEEP(*(.comment)) KEEP(*(.comment))
KEEP(*(.commentepilogue)) BYTE(0);
} }
.eh_frame_hdr : { .eh_frame_hdr : {
@ -153,7 +139,7 @@ SECTIONS {
*(.exception_ranges*) *(.exception_ranges*)
} }
.tdata : ONLY_IF_RW { .tdata : {
PROVIDE_HIDDEN(_tdata_start = .); PROVIDE_HIDDEN(_tdata_start = .);
PROVIDE_HIDDEN(__tdata_start = .); PROVIDE_HIDDEN(__tdata_start = .);
*(.tdata .tdata.* .gnu.linkonce.td.*) *(.tdata .tdata.* .gnu.linkonce.td.*)
@ -184,6 +170,8 @@ SECTIONS {
.data.rel.ro : { .data.rel.ro : {
*(.data.rel.ro.local* .gnu.linkonce.d.rel.ro.local.*) *(.data.rel.ro.local* .gnu.linkonce.d.rel.ro.local.*)
*(.data.rel.ro .data.rel.ro.* .gnu.linkonce.d.rel.ro.*) *(.data.rel.ro .data.rel.ro.* .gnu.linkonce.d.rel.ro.*)
. = ALIGN(__SIZEOF_POINTER__);
KEEP(*(SORT_BY_NAME(.piro.relo.sort.*)))
} }
.dynamic : { .dynamic : {
@ -204,6 +192,8 @@ SECTIONS {
.data : { .data : {
PROVIDE(__data_start = .); PROVIDE(__data_start = .);
. = ALIGN(__SIZEOF_POINTER__);
KEEP(*(SORT_BY_NAME(.piro.data.sort.*)))
*(.data .data.* .gnu.linkonce.d.*) *(.data .data.* .gnu.linkonce.d.*)
KEEP(*(SORT_BY_NAME(.sort.data.*))) KEEP(*(SORT_BY_NAME(.sort.data.*)))
SORT(CONSTRUCTORS) SORT(CONSTRUCTORS)
@ -212,7 +202,7 @@ SECTIONS {
_edata = .; _edata = .;
PROVIDE(edata = .); PROVIDE(edata = .);
.data : { .zip : {
KEEP(*(SORT_BY_NAME(.zip.*))) KEEP(*(SORT_BY_NAME(.zip.*)))
HIDDEN(_ezip = .); HIDDEN(_ezip = .);
} }
@ -239,36 +229,36 @@ SECTIONS {
. = DATA_SEGMENT_END(.); . = DATA_SEGMENT_END(.);
.stab 0 : { *(.stab) } .stab 0 : { *(.stab) }
.stabstr 0 : { *(.stabstr) } .stabstr 0 : { *(.stabstr) }
.stab.excl 0 : { *(.stab.excl) } .stab.excl 0 : { *(.stab.excl) }
.stab.exclstr 0 : { *(.stab.exclstr) } .stab.exclstr 0 : { *(.stab.exclstr) }
.stab.index 0 : { *(.stab.index) } .stab.index 0 : { *(.stab.index) }
.stab.indexstr 0 : { *(.stab.indexstr) } .stab.indexstr 0 : { *(.stab.indexstr) }
.gnu.build.attributes : { *(.gnu.build.attributes .gnu.build.attributes.*) } .gnu.build.attributes : { *(.gnu.build.attributes .gnu.build.attributes.*) }
.debug 0 : { *(.debug) } .debug 0 : { *(.debug) }
.line 0 : { *(.line) } .line 0 : { *(.line) }
.debug_srcinfo 0 : { *(.debug_srcinfo) } .debug_srcinfo 0 : { *(.debug_srcinfo) }
.debug_sfnames 0 : { *(.debug_sfnames) } .debug_sfnames 0 : { *(.debug_sfnames) }
.debug_aranges 0 : { *(.debug_aranges) } .debug_aranges 0 : { *(.debug_aranges) }
.debug_pubnames 0 : { *(.debug_pubnames) } .debug_pubnames 0 : { *(.debug_pubnames) }
.debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) }
.debug_abbrev 0 : { *(.debug_abbrev) } .debug_abbrev 0 : { *(.debug_abbrev) }
.debug_line 0 : { *(.debug_line .debug_line.* .debug_line_end) } .debug_line 0 : { *(.debug_line .debug_line.* .debug_line_end) }
.debug_frame 0 : { *(.debug_frame) } .debug_frame 0 : { *(.debug_frame) }
.debug_str 0 : { *(.debug_str) } .debug_str 0 : { *(.debug_str) }
.debug_loc 0 : { *(.debug_loc) } .debug_loc 0 : { *(.debug_loc) }
.debug_macinfo 0 : { *(.debug_macinfo) } .debug_macinfo 0 : { *(.debug_macinfo) }
.debug_weaknames 0 : { *(.debug_weaknames) } .debug_weaknames 0 : { *(.debug_weaknames) }
.debug_funcnames 0 : { *(.debug_funcnames) } .debug_funcnames 0 : { *(.debug_funcnames) }
.debug_typenames 0 : { *(.debug_typenames) } .debug_typenames 0 : { *(.debug_typenames) }
.debug_varnames 0 : { *(.debug_varnames) } .debug_varnames 0 : { *(.debug_varnames) }
.debug_pubtypes 0 : { *(.debug_pubtypes) } .debug_pubtypes 0 : { *(.debug_pubtypes) }
.debug_ranges 0 : { *(.debug_ranges) } .debug_ranges 0 : { *(.debug_ranges) }
.debug_macro 0 : { *(.debug_macro) } .debug_macro 0 : { *(.debug_macro) }
.debug_addr 0 : { *(.debug_addr) } .debug_addr 0 : { *(.debug_addr) }
.ARM.attributes 0 : { KEEP(*(.ARM.attributes)) KEEP(*(.gnu.attributes)) } .ARM.attributes 0 : { KEEP(*(.ARM.attributes)) KEEP(*(.gnu.attributes)) }
.note.gnu.arm.ident 0 : { KEEP(*(.note.gnu.arm.ident)) } .note.gnu.arm.ident 0 : { KEEP(*(.note.gnu.arm.ident)) }
/DISCARD/ : { /DISCARD/ : {
*(.GCC.command.line) *(.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_size = _tbss_end - _tbss_start);
PROVIDE_HIDDEN(_tbss_offset = _tbss_start - _tdata_start); PROVIDE_HIDDEN(_tbss_offset = _tbss_start - _tdata_start);
PROVIDE_HIDDEN(_tls_content = (_tdata_end - _tdata_start) + (_tbss_end - _tbss_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); PROVIDE_HIDDEN(__zip_start_rva = DEFINED(__zip_start) ? __zip_start - __executable_start : 0);
/* ZIP End of Central Directory header */ /* 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"); ASSERT(v_zip_cdirsize % kZipCdirHdrLinkableSize == 0, "bad zip cdir");
ZIPCONST(v_zip_records, v_zip_cdirsize / kZipCdirHdrLinkableSize); ZIPCONST(v_zip_records, v_zip_cdirsize / kZipCdirHdrLinkableSize);
ZIPCONST(v_zip_commentsize, _ezip - __zip_end - kZipCdirHdrMinSize); 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 */ /*BEGIN: Post-Initialization Read-Only */
. = ALIGN(__SIZEOF_POINTER__); . = ALIGN(__SIZEOF_POINTER__);
KEEP(*(SORT_BY_NAME(.piro.relo.sort.*))) KEEP(*(SORT_BY_NAME(.piro.relo.sort.*)))
PROVIDE_HIDDEN(__relo_end = .);
. = ALIGN(__SIZEOF_POINTER__); . = ALIGN(__SIZEOF_POINTER__);
KEEP(*(SORT_BY_NAME(.piro.data.sort.*))) KEEP(*(SORT_BY_NAME(.piro.data.sort.*)))
KEEP(*(.piro.pad.data)) KEEP(*(.piro.pad.data))
@ -518,6 +517,7 @@ HIDDEN(_tdata_size = _tdata_end - _tdata_start);
HIDDEN(_tbss_size = _tbss_end - _tbss_start); HIDDEN(_tbss_size = _tbss_end - _tbss_start);
HIDDEN(_tbss_offset = _tbss_start - _tdata_start); HIDDEN(_tbss_offset = _tbss_start - _tdata_start);
HIDDEN(_tls_content = (_tdata_end - _tdata_start) + (_tbss_end - _tbss_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_addr = ROUNDDOWN(__privileged_start, PAGESIZE));
HIDDEN(__privileged_size = (ROUNDUP(__privileged_end, PAGESIZE) - HIDDEN(__privileged_size = (ROUNDUP(__privileged_end, PAGESIZE) -

View file

@ -42,6 +42,7 @@ o/$(MODE)/ape/aarch64.lds: \
ape/aarch64.lds \ ape/aarch64.lds \
libc/zip.h \ libc/zip.h \
libc/intrin/bits.h \ libc/intrin/bits.h \
libc/thread/tls.h \
libc/calls/struct/timespec.h \ libc/calls/struct/timespec.h \
libc/macros.internal.h \ libc/macros.internal.h \
libc/str/str.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 _tdata_end[] __attribute__((__weak__));
extern unsigned char _tbss_start[] __attribute__((__weak__)); extern unsigned char _tbss_start[] __attribute__((__weak__));
extern unsigned char _tbss_end[] __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_start[] __attribute__((__weak__));
extern unsigned char __privileged_addr[] __attribute__((__weak__)); extern unsigned char __privileged_addr[] __attribute__((__weak__));
extern unsigned char __privileged_size[] __attribute__((__weak__)); extern unsigned char __privileged_size[] __attribute__((__weak__));
extern unsigned char __privileged_end[] __attribute__((__weak__)); extern unsigned char __privileged_end[] __attribute__((__weak__));
extern unsigned char __test_start[] __attribute__((__weak__)); extern unsigned char __test_start[] __attribute__((__weak__));
extern unsigned char __ro[] __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_start[] __attribute__((__weak__));
extern uint8_t __zip_end[] __attribute__((__weak__)); extern uint8_t __zip_end[] __attribute__((__weak__));
extern uint8_t __data_start[] __attribute__((__weak__)); extern uint8_t __data_start[] __attribute__((__weak__));

View file

@ -1,6 +1,5 @@
#!/bin/sh #!/bin/sh
for last; do true; done if printf '%s\n' "$*" | grep aarch64 >/dev/null 2>&1; then
if printf '%s\n' "$last" | grep aarch64 >/dev/null 2>&1; then
exec o/third_party/gcc/bin/aarch64-linux-musl-objdump "$@" exec o/third_party/gcc/bin/aarch64-linux-musl-objdump "$@"
else else
exec o/third_party/gcc/bin/x86_64-linux-musl-objdump "$@" exec o/third_party/gcc/bin/x86_64-linux-musl-objdump "$@"

View file

@ -1,6 +1,5 @@
#!/bin/sh #!/bin/sh
for last; do true; done if printf '%s\n' "$*" | grep aarch64 >/dev/null 2>&1; then
if printf '%s\n' "$last" | grep aarch64 >/dev/null 2>&1; then
if [ ! -f o/third_party/qemu/qemu-aarch64 ]; then if [ ! -f o/third_party/qemu/qemu-aarch64 ]; then
make -j8 o/third_party/qemu/qemu-aarch64 make -j8 o/third_party/qemu/qemu-aarch64
fi fi

View file

@ -162,7 +162,8 @@ o/$(MODE)/examples/nesemu1.com.dbg: \
o/$(MODE)/examples/symtab.com: \ o/$(MODE)/examples/symtab.com: \
o/$(MODE)/examples/symtab.com.dbg \ o/$(MODE)/examples/symtab.com.dbg \
o/$(MODE)/third_party/zip/zip.com \ o/$(MODE)/third_party/zip/zip.com \
o/$(MODE)/tool/build/symtab.com o/$(MODE)/tool/build/symtab.com \
$(VM)
@$(MAKE_OBJCOPY) @$(MAKE_OBJCOPY)
@$(MAKE_SYMTAB_CREATE) @$(MAKE_SYMTAB_CREATE)
@$(MAKE_SYMTAB_ZIP) @$(MAKE_SYMTAB_ZIP)

View file

@ -50,11 +50,11 @@
#define MAP_HUGE_2MB (21 << MAP_HUGE_SHIFT) #define MAP_HUGE_2MB (21 << MAP_HUGE_SHIFT)
#define MAP_HUGE_1GB (30 << 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 WEXITSTATUS(s) ((0xff00 & (s)) >> 8)
#define WIFCONTINUED(s) ((s) == 0xffff) #define WIFCONTINUED(s) ((s) == 0xffff)
#define WIFEXITED(s) (!WTERMSIG(s)) #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 WIFSTOPPED(s) ((255 & (s)) == 127)
#define WSTOPSIG(s) WEXITSTATUS(s) #define WSTOPSIG(s) WEXITSTATUS(s)
#define WTERMSIG(s) (127 & (s)) #define WTERMSIG(s) (127 & (s))

View file

@ -18,6 +18,8 @@
*/ */
#include "libc/calls/struct/timespec.h" #include "libc/calls/struct/timespec.h"
// TODO(jart): DELETE
/** /**
* Returns seconds since epoch w/ high-precision. * Returns seconds since epoch w/ high-precision.
* @param clockid can be CLOCK_{REALTIME,MONOTONIC}, etc. * @param clockid can be CLOCK_{REALTIME,MONOTONIC}, etc.
@ -27,7 +29,7 @@ long double dtime(int clockid) {
struct timespec tv; struct timespec tv;
clock_gettime(clockid, &tv); clock_gettime(clockid, &tv);
secs = tv.tv_nsec; secs = tv.tv_nsec;
secs *= 1 / 1e9; secs *= 1e-9;
secs += tv.tv_sec; secs += tv.tv_sec;
return secs; return secs;
} }

View file

@ -49,7 +49,7 @@ static bool IsApeBinary(const char *path) {
bool res = false; bool res = false;
// TODO(jart): Should we block signals too? // TODO(jart): Should we block signals too?
BLOCK_CANCELLATIONS; 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); res = sys_read(fd, buf, 8) == 8 && IsAPEMagic(buf);
sys_close(fd); sys_close(fd);
} }

View file

@ -76,7 +76,7 @@ static void Refresh(void) {
memcpy(&g_now, &now, sizeof(now)); memcpy(&g_now, &now, sizeof(now));
} }
long double ConvertTicksToNanos(uint64_t ticks) { long double ConvertTicksToNanos(double ticks) {
if (!g_now.once) Refresh(); if (!g_now.once) Refresh();
return ticks * g_now.cpn; /* pico scale */ return ticks * g_now.cpn; /* pico scale */
} }

View file

@ -32,6 +32,7 @@
#include "libc/intrin/kprintf.h" #include "libc/intrin/kprintf.h"
#include "libc/log/rop.h" #include "libc/log/rop.h"
#include "libc/str/str.h" #include "libc/str/str.h"
#include "libc/sysv/consts/at.h"
#include "libc/sysv/consts/o.h" #include "libc/sysv/consts/o.h"
#include "libc/sysv/consts/pty.h" #include "libc/sysv/consts/pty.h"
#include "libc/sysv/consts/termios.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(grantpt(m));
RETURN_ON_ERROR(unlockpt(m)); RETURN_ON_ERROR(unlockpt(m));
RETURN_ON_ERROR(_ptsname(m, t.sname, sizeof(t.sname))); 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 { } else {
RETURN_ON_ERROR(sys_ioctl(m, PTMGET, &t)); RETURN_ON_ERROR(sys_ioctl(m, PTMGET, &t));
close(m); close(m);

View file

@ -19,6 +19,7 @@
#include "ape/sections.internal.h" #include "ape/sections.internal.h"
#include "libc/calls/calls.h" #include "libc/calls/calls.h"
#include "libc/calls/pledge.internal.h" #include "libc/calls/pledge.internal.h"
#include "libc/calls/prctl.internal.h"
#include "libc/calls/struct/bpf.h" #include "libc/calls/struct/bpf.h"
#include "libc/calls/struct/filter.h" #include "libc/calls/struct/filter.h"
#include "libc/calls/struct/seccomp.h" #include "libc/calls/struct/seccomp.h"
@ -1100,33 +1101,6 @@ static privileged void Log(const char *s, ...) {
va_end(va); 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, static privileged int SigAction(int sig, struct sigaction *act,
struct sigaction *old) { struct sigaction *old) {
int res; 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_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 // PR_SET_NO_NEW_PRIVS (Linux 3.5+) wasn't called so we punt the error
// detection to the seccomp system call below. // 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 // register our seccomp filter with the kernel
struct sock_fprog sandbox = {.len = f.n, .filter = f.p}; 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 // 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 // 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 // doesn't have SECCOMP support. since we don't consider lack of
// system support for security to be an error, we distinguish these // system support for security to be an error, we distinguish these
// two cases by running a simpler SECCOMP operation. // 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 rc = 0; // -Enosys
} }

View file

@ -18,6 +18,7 @@
*/ */
#include "libc/calls/calls.h" #include "libc/calls/calls.h"
#include "libc/calls/pledge.internal.h" #include "libc/calls/pledge.internal.h"
#include "libc/calls/prctl.internal.h"
#include "libc/calls/state.internal.h" #include "libc/calls/state.internal.h"
#include "libc/calls/syscall-sysv.internal.h" #include "libc/calls/syscall-sysv.internal.h"
#include "libc/dce.h" #include "libc/dce.h"
@ -26,6 +27,7 @@
#include "libc/intrin/strace.internal.h" #include "libc/intrin/strace.internal.h"
#include "libc/nexgen32e/vendor.internal.h" #include "libc/nexgen32e/vendor.internal.h"
#include "libc/runtime/runtime.h" #include "libc/runtime/runtime.h"
#include "libc/sysv/consts/pr.h"
#include "libc/sysv/errfuns.h" #include "libc/sysv/errfuns.h"
/** /**
@ -42,8 +44,10 @@
* across execve() if permitted). Root access is not required. Support * across execve() if permitted). Root access is not required. Support
* is limited to Linux 2.6.23+ (c. RHEL6) and OpenBSD. If your kernel * 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 * 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 * than raising ENOSYS. This implementation doesn't consider lack of
* an error, because the specified operations will be permitted. * 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. * The promises you give pledge() define which system calls are allowed.
* Error messages are logged when sandbox violations occur, but how that * Error messages are logged when sandbox violations occur, but how that
@ -234,6 +238,7 @@
* subprocesses can't inherit the `SIGSYS` handler this installs. * subprocesses can't inherit the `SIGSYS` handler this installs.
* *
* @return 0 on success, or -1 w/ errno * @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 `execpromises` on Linux isn't a subset of `promises`
* @raise EINVAL if `promises` allows exec and `execpromises` is null * @raise EINVAL if `promises` allows exec and `execpromises` is null
* @threadsafe * @threadsafe
@ -242,8 +247,24 @@
int pledge(const char *promises, const char *execpromises) { int pledge(const char *promises, const char *execpromises) {
int e, rc; int e, rc;
unsigned long ipromises, iexecpromises; unsigned long ipromises, iexecpromises;
if (IsGenuineBlink()) { if (!promises) {
rc = 0; // blink doesn't support seccomp // 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) && } else if (!ParsePromises(promises, &ipromises) &&
!ParsePromises(execpromises, &iexecpromises)) { !ParsePromises(execpromises, &iexecpromises)) {
if (IsLinux()) { if (IsLinux()) {

View file

@ -22,6 +22,7 @@
#include "libc/errno.h" #include "libc/errno.h"
#include "libc/intrin/describeflags.internal.h" #include "libc/intrin/describeflags.internal.h"
#include "libc/intrin/strace.internal.h" #include "libc/intrin/strace.internal.h"
#include "libc/sysv/consts/at.h"
#include "libc/sysv/consts/o.h" #include "libc/sysv/consts/o.h"
#include "libc/sysv/errfuns.h" #include "libc/sysv/errfuns.h"
@ -37,9 +38,9 @@ int posix_openpt(int flags) {
if ((flags & O_ACCMODE) != O_RDWR) { if ((flags & O_ACCMODE) != O_RDWR) {
rc = einval(); rc = einval();
} else if (IsLinux() || IsXnu() || IsNetbsd()) { } else if (IsLinux() || IsXnu() || IsNetbsd()) {
rc = sys_open("/dev/ptmx", flags, 0); rc = sys_openat(AT_FDCWD, "/dev/ptmx", flags, 0);
} else if (IsOpenbsd()) { } else if (IsOpenbsd()) {
rc = sys_open("/dev/ptm", flags, 0); rc = sys_openat(AT_FDCWD, "/dev/ptm", flags, 0);
} else if (IsFreebsd()) { } else if (IsFreebsd()) {
rc = sys_posix_openpt(flags); rc = sys_posix_openpt(flags);
if (rc == -1 && errno == ENOSPC) errno = EAGAIN; if (rc == -1 && errno == ENOSPC) errno = EAGAIN;

View file

@ -17,6 +17,7 @@
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "libc/calls/calls.h" #include "libc/calls/calls.h"
#include "libc/calls/prctl.internal.h"
#include "libc/calls/syscall-sysv.internal.h" #include "libc/calls/syscall-sysv.internal.h"
#include "libc/dce.h" #include "libc/dce.h"
#include "libc/errno.h" #include "libc/errno.h"
@ -43,30 +44,11 @@ privileged int prctl(int operation, ...) {
va_end(va); va_end(va);
if (IsLinux()) { if (IsLinux()) {
#ifdef __x86_64__ rc = sys_prctl(operation, a, b, c, d);
asm volatile("mov\t%5,%%r10\n\t" if (rc < 0) {
"mov\t%6,%%r8\n\t" errno = -rc;
"syscall" rc = -1;
: "=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
} else { } else {
rc = enosys(); 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_mprotect(void *, u64, i32) _Hide;
i32 sys_msync(void *, u64, i32) _Hide; i32 sys_msync(void *, u64, i32) _Hide;
i32 sys_munmap(void *, u64) _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_openat(i32, const char *, i32, u32) _Hide;
i32 sys_pause(void) _Hide; i32 sys_pause(void) _Hide;
i32 sys_pipe(i32[hasatleast 2]) _Hide; i32 sys_pipe(i32[hasatleast 2]) _Hide;

View file

@ -27,8 +27,10 @@
#include "libc/calls/struct/stat.internal.h" #include "libc/calls/struct/stat.internal.h"
#include "libc/calls/syscall-sysv.internal.h" #include "libc/calls/syscall-sysv.internal.h"
#include "libc/calls/syscall_support-sysv.internal.h" #include "libc/calls/syscall_support-sysv.internal.h"
#include "libc/dce.h"
#include "libc/errno.h" #include "libc/errno.h"
#include "libc/fmt/conv.h" #include "libc/fmt/conv.h"
#include "libc/intrin/kprintf.h"
#include "libc/intrin/strace.internal.h" #include "libc/intrin/strace.internal.h"
#include "libc/macros.internal.h" #include "libc/macros.internal.h"
#include "libc/nexgen32e/vendor.internal.h" #include "libc/nexgen32e/vendor.internal.h"
@ -99,9 +101,11 @@ static int landlock_abi_version;
static int landlock_abi_errno; static int landlock_abi_errno;
__attribute__((__constructor__)) void init_landlock_version() { __attribute__((__constructor__)) void init_landlock_version() {
int e = errno;
landlock_abi_version = landlock_abi_version =
landlock_create_ruleset(0, 0, LANDLOCK_CREATE_RULESET_VERSION); landlock_create_ruleset(0, 0, LANDLOCK_CREATE_RULESET_VERSION);
landlock_abi_errno = errno; landlock_abi_errno = errno;
errno = e;
} }
/** /**
@ -170,7 +174,7 @@ static int unveil_init(void) {
const struct landlock_ruleset_attr attr = { const struct landlock_ruleset_attr attr = {
.handled_access_fs = State.fs_mask, .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); // assert(__sys_fcntl(rc, F_GETFD, 0) == FD_CLOEXEC);
if ((rc = landlock_create_ruleset(&attr, sizeof(attr), 0)) < 0) return -1; if ((rc = landlock_create_ruleset(&attr, sizeof(attr), 0)) < 0) return -1;
// grant file descriptor a higher number that's less likely to interfere // 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 // now we can open the path
BLOCK_CANCELLATIONS; 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; ALLOW_CANCELLATIONS;
if (rc == -1) return rc; 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)` * should become unhidden. When you're finished, you call `unveil(0,0)`
* which commits your policy. * which commits your policy.
* *
* This function requires OpenBSD or Linux 5.13+. We don't consider lack * This function requires OpenBSD or Linux 5.13+ (2022+). If the kernel
* of system support to be an ENOSYS error, because the files will still * support isn't available (or we're in an emulator like Qemu or Blink)
* become unveiled. Therefore we return 0 in such cases. * 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. * 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 * possible to use opendir() and go fishing for paths which weren't
* previously known. * previously known.
* *
* 5. Use ftruncate() rather than truncate() if you wish for portability to * 5. Use ftruncate() rather than truncate() if you wish for portability
* Linux kernels versions released before February 2022. One issue * to Linux kernels versions released before February 2022. One issue
* Landlock hadn't addressed as of ABI version 2 was restrictions over * Landlock hadn't addressed as of ABI version 2 was restrictions
* truncate() and setxattr() which could permit certain kinds of * over truncate() and setxattr() which could permit certain kinds of
* modifications to files outside the sandbox. When your policy is * modifications to files outside the sandbox. When your policy is
* committed, we install a SECCOMP BPF filter to disable those calls, * committed, we install a SECCOMP BPF filter to disable those calls,
* however similar trickery may be possible through other unaddressed * 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 * unveil() will solve this, since it installs a strong system call
* access policy. Linux 6.2 has improved this situation with Landlock * access policy. Linux 6.2 has improved this situation with Landlock
* ABI v3, which added the ability to control truncation operations - * ABI v3, which added the ability to control truncation operations -
* this means the SECCOMP BPF filter will only disable * this means the SECCOMP BPF filter will only disable truncate() on
* truncate() on Linux 6.1 or older * Linux 6.1 or older.
* *
* 6. Set your process-wide policy at startup from the main thread. On * 6. Set your process-wide policy at startup from the main thread. On
* OpenBSD unveil() will apply process-wide even when called from a * 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 * - `c` allows `path` to be created and removed, corresponding to
* the pledge promise "cpath". * 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 one argument is set and the other is not
* @raise EINVAL if an invalid character in `permissions` was found * @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+ * @note on Linux this function requires Linux Kernel 5.13+ and version 6.2+
* to properly support truncation operations * to properly support truncation operations
* @see [1] https://docs.kernel.org/userspace-api/landlock.html * @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 unveil(const char *path, const char *permissions) {
int e, rc; int e, rc;
e = errno; e = errno;
if (IsGenuineBlink()) { if (path && !*path) {
rc = 0; // blink doesn't support landlock // 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()) { } else if (IsLinux()) {
rc = sys_unveil_linux(path, permissions); rc = sys_unveil_linux(path, permissions);
} else { } else {

View file

@ -53,16 +53,18 @@
#endif #endif
#ifdef _MSC_VER #ifdef _MSC_VER
#define __builtin_unreachable() __assume(0) #define __builtin_unreachable() __assume(false)
#elif defined(__STRICT_ANSI__) || \ #elif defined(__STRICT_ANSI__) || \
!((__GNUC__ + 0) * 100 + (__GNUC_MINOR__ + 0) >= 405 || \ !((__GNUC__ + 0) * 100 + (__GNUC_MINOR__ + 0) >= 405 || \
defined(__clang__) || defined(__INTEL_COMPILER)) defined(__clang__) || defined(__INTEL_COMPILER) || \
__has_builtin(__builtin_unreachable))
#define __builtin_unreachable() \ #define __builtin_unreachable() \
for (;;) { \ for (;;) { \
} }
#endif #endif
#if defined(__STRICT_ANSI__) || (!defined(__llvm__) && !__has_builtin(assume)) #if defined(__STRICT_ANSI__) || \
(!defined(__llvm__) && !__has_builtin(__builtin_assume))
#define __builtin_assume(x) \ #define __builtin_assume(x) \
do { \ do { \
if (!(x)) __builtin_unreachable(); \ if (!(x)) __builtin_unreachable(); \
@ -248,13 +250,13 @@ typedef struct {
#endif #endif
#endif #endif
#ifndef noclone #ifndef dontclone
#if !defined(__STRICT_ANSI__) && \ #if !defined(__STRICT_ANSI__) && \
(__has_attribute(__noclone__) || \ (__has_attribute(__noclone__) || \
(__GNUC__ + 0) * 100 + (__GNUC_MINOR__ + 0) >= 405) (__GNUC__ + 0) * 100 + (__GNUC_MINOR__ + 0) >= 405)
#define noclone __attribute__((__noclone__)) #define dontclone __attribute__((__noclone__))
#else #else
#define noclone #define dontclone
#endif #endif
#endif #endif
@ -417,16 +419,16 @@ typedef struct {
#endif #endif
#endif #endif
#ifndef nooptimize #ifndef dontoptimize
#ifndef __STRICT_ANSI__ #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__) __has_attribute(__optimize__)
#define nooptimize __attribute__((__optimize__(1))) #define dontoptimize __attribute__((__optimize__(0)))
#elif defined(__llvm__) || __has_attribute(__optnone__)
#define nooptimize __attribute__((__optnone__))
#endif #endif
#else #else
#define nooptimize #define dontoptimize
#endif #endif
#endif #endif
@ -570,7 +572,7 @@ typedef struct {
#if __cplusplus + 0 >= 201103L #if __cplusplus + 0 >= 201103L
#define autotype(x) auto #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) && \ (__GNUC__ + 0) * 100 + (__GNUC_MINOR__ + 0) >= 409) && \
!defined(__chibicc__)) !defined(__chibicc__))
#define autotype(x) __auto_type #define autotype(x) __auto_type
@ -588,39 +590,42 @@ typedef struct {
#define nocallersavedregisters #define nocallersavedregisters
#endif #endif
#if (__GNUC__ + 0) * 100 + (__GNUC_MINOR__ + 0) >= 408 || \ #if ((__GNUC__ + 0) * 100 + (__GNUC_MINOR__ + 0) >= 408 || \
__has_attribute(__no_sanitize_address__) __has_attribute(__no_sanitize_address__)) && \
!defined(__STRICT_ANSI__)
#define noasan __attribute__((__no_sanitize_address__)) #define noasan __attribute__((__no_sanitize_address__))
#else #else
#define noasan #define noasan
#endif #endif
#if (__GNUC__ + 0) * 100 + (__GNUC_MINOR__ + 0) >= 408 || \ #if ((__GNUC__ + 0) * 100 + (__GNUC_MINOR__ + 0) >= 408 || \
__has_attribute(__no_sanitize_undefined__) __has_attribute(__no_sanitize_undefined__)) && \
!defined(__STRICT_ANSI__)
#define noubsan __attribute__((__no_sanitize_undefined__)) #define noubsan __attribute__((__no_sanitize_undefined__))
#else #else
#define noubsan #define noubsan
#endif #endif
#ifndef unreachable #ifndef unreachable
#if defined(__GNUC__) && !defined(__STRICT_ANSI__)
#define unreachable __builtin_unreachable() #define unreachable __builtin_unreachable()
#else
#define unreachable \
do { \
} while (1)
#endif
#endif #endif
#ifdef __STRICT_ANSI__
void abort(void) wontreturn;
#define notpossible abort()
#else
#ifdef __x86_64__ #ifdef __x86_64__
#define notpossible \ #define notpossible \
do { \ do { \
asm("nop\n\tud2\n\tnop"); \ asm("nop\n\t" \
unreachable; \ "ud2\n\t" \
"nop"); \
unreachable; \
} while (0) } while (0)
#else #else
#define notpossible __builtin_trap() #define notpossible __builtin_trap()
#endif #endif
#endif
#define donothing \ #define donothing \
do { \ do { \

View file

@ -1400,7 +1400,7 @@ void __asan_map_shadow(uintptr_t p, size_t n) {
} }
} }
size = (size_t)i << 16; 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; prot = PROT_READ | PROT_WRITE;
flag = MAP_PRIVATE | MAP_FIXED | MAP_ANONYMOUS; flag = MAP_PRIVATE | MAP_FIXED | MAP_ANONYMOUS;
sm = _weaken(sys_mmap)(addr, size, prot, flag, -1, 0); 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_die()();
__asan_unreachable(); __asan_unreachable();
} }
__repstosb((void *)(intptr_t)((int64_t)((uint64_t)a << 32) >> 16), __repstosb(addr, kAsanUnmapped, size);
kAsanUnmapped, size);
} }
__asan_unpoison((char *)p, n); __asan_unpoison((char *)p, n);
} }

View file

@ -26,12 +26,11 @@
#include "libc/runtime/runtime.h" #include "libc/runtime/runtime.h"
#include "libc/runtime/winargs.internal.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 UNSHADOW(x) ((int64_t)(MAX(0, (x)-0x7fff8000)) << 3)
#define FRAME(x) ((int)((x) >> 16)) #define FRAME(x) ((int)((x) >> 16))
forceinline pureconst bool IsBrkFrame(int x) { 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; return _weaken(__brk) && p >= _end && p < _weaken(__brk)->p;
} }
@ -78,7 +77,8 @@ const char *(DescribeFrame)(char buf[32], int x) {
char *p; char *p;
if (IsShadowFrame(x)) { if (IsShadowFrame(x)) {
ksnprintf(buf, 32, "%s %s %.8x", GetFrameName(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; return buf;
} else { } else {
return GetFrameName(x); return GetFrameName(x);

View file

@ -39,7 +39,6 @@
wontreturn void _Exit(int exitcode) { wontreturn void _Exit(int exitcode) {
int i; int i;
STRACE("_Exit(%d)", exitcode); STRACE("_Exit(%d)", exitcode);
#ifdef __x86_64__
if (!IsWindows() && !IsMetal()) { if (!IsWindows() && !IsMetal()) {
// On Linux _Exit1 (exit) must be called in pledge("") mode. If we // On Linux _Exit1 (exit) must be called in pledge("") mode. If we
// call _Exit (exit_group) when we haven't used pledge("stdio") then // 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 // _Exit1 (__threxit) because only _Exit (exit) is whitelisted when
// operating in pledge("") mode. // operating in pledge("") mode.
if (!(IsLinux() && !PLEDGED(STDIO))) { if (!(IsLinux() && !PLEDGED(STDIO))) {
#ifdef __x86_64__
asm volatile("syscall" asm volatile("syscall"
: /* no outputs */ : /* no outputs */
: "a"(__NR_exit_group), "D"(exitcode) : "a"(__NR_exit_group), "D"(exitcode)
: "rcx", "r11", "memory"); : "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() // Inline _Exit1() just in case _Exit() isn't allowed by pledge()
#ifdef __x86_64__
asm volatile("syscall" asm volatile("syscall"
: /* no outputs */ : /* no outputs */
: "a"(__NR_exit), "D"(exitcode) : "a"(__NR_exit), "D"(exitcode)
: "rcx", "r11", "memory"); : "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()) { } else if (IsWindows()) {
ExitProcess(exitcode); ExitProcess(exitcode);
} }
#ifdef __x86_64__
asm("push\t$0\n\t" asm("push\t$0\n\t"
"push\t$0\n\t" "push\t$0\n\t"
"cli\n\t" "cli\n\t"
"lidt\t(%rsp)"); "lidt\t(%rsp)");
for (;;) asm("ud2"); 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 #else
#error "arch unsupported" unreachable;
#endif #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" #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: feclearexcept:
#ifdef __x86_64__ #ifdef __x86_64__
// maintain exceptions in the sse mxcsr, clear x87 exceptions // maintain exceptions in the sse mxcsr, clear x87 exceptions
@ -53,9 +65,47 @@ feclearexcept:
msr fpsr,x1 msr fpsr,x1
mov w0,#0 mov w0,#0
ret ret
#else
#error "unsupported architecture"
#endif #endif
.endfn feclearexcept,globl .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: feraiseexcept:
#ifdef __x86_64__ #ifdef __x86_64__
and $0x3f,%edi and $0x3f,%edi
@ -159,21 +209,3 @@ fesetenv:
ret ret
#endif #endif
.endfn fesetenv,globl .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 TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE. 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) { int feupdateenv(const fenv_t *envp) {
long long res; int ex = fetestexcept(FE_ALL_EXCEPT);
#ifdef __x86_64__ fesetenv(envp);
asm("cvtsd2si\t%1,%0" : "=r"(res) : "x"(x)); feraiseexcept(ex);
#elif defined(__aarch64__) return 0;
asm("frintx\t%d1,%d1\n\t"
"fcvtzs\t%x0,%d1"
: "=r"(res), "+w"(x));
#else
res = rint(x);
#endif /* __x86_64__ */
return res;
} }

View file

@ -16,6 +16,7 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "libc/calls/cp.internal.h"
#include "libc/calls/syscall-sysv.internal.h" #include "libc/calls/syscall-sysv.internal.h"
#include "libc/dce.h" #include "libc/dce.h"
#include "libc/errno.h" #include "libc/errno.h"
@ -50,6 +51,7 @@ int IsDebuggerPresent(bool force) {
if (!PLEDGED(RPATH)) return false; if (!PLEDGED(RPATH)) return false;
res = 0; res = 0;
e = errno; e = errno;
BEGIN_CANCELLATION_POINT;
if ((fd = __sys_openat(AT_FDCWD, "/proc/self/status", O_RDONLY, 0)) >= 0) { if ((fd = __sys_openat(AT_FDCWD, "/proc/self/status", O_RDONLY, 0)) >= 0) {
if ((got = sys_read(fd, buf, sizeof(buf) - 1)) > 0) { if ((got = sys_read(fd, buf, sizeof(buf) - 1)) > 0) {
buf[got] = '\0'; buf[got] = '\0';
@ -60,6 +62,7 @@ int IsDebuggerPresent(bool force) {
} }
sys_close(fd); sys_close(fd);
} }
END_CANCELLATION_POINT;
errno = e; errno = e;
return res; return res;
} }

View file

@ -37,6 +37,7 @@
#include "libc/intrin/weaken.h" #include "libc/intrin/weaken.h"
#include "libc/limits.h" #include "libc/limits.h"
#include "libc/log/internal.h" #include "libc/log/internal.h"
#include "libc/log/libfatal.internal.h"
#include "libc/macros.internal.h" #include "libc/macros.internal.h"
#include "libc/nexgen32e/rdtsc.h" #include "libc/nexgen32e/rdtsc.h"
#include "libc/nexgen32e/uart.internal.h" #include "libc/nexgen32e/uart.internal.h"
@ -174,6 +175,7 @@ privileged static bool kismapped(int x) {
privileged bool kisdangerous(const void *p) { privileged bool kisdangerous(const void *p) {
int frame; int frame;
if (IsTiny()) return false;
if (kisimagepointer(p)) return false; if (kisimagepointer(p)) return false;
if (kiskernelpointer(p)) return false; if (kiskernelpointer(p)) return false;
if (IsOldStack(p)) return false; if (IsOldStack(p)) return false;
@ -189,7 +191,7 @@ privileged bool kisdangerous(const void *p) {
return true; 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__ #ifdef __x86_64__
int e; int e;
bool cf; bool cf;

View file

@ -23,8 +23,6 @@
#include "libc/macros.internal.h" #include "libc/macros.internal.h"
#include "libc/runtime/memtrack.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) { static bool IsNoteworthyHole(unsigned i, const struct MemoryIntervals *mm) {
// gaps between shadow frames aren't interesting // gaps between shadow frames aren't interesting
// the chasm from heap to stack ruins statistics // 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) { for (j = 0; j < 4; ++j) {
int r = 8 * j + i; int r = 8 * j + i;
if (j) Append(b, " "); if (j) Append(b, " ");
Append(b, "%s%016lx%s %sr%d", ColorRegister(r), Append(b, "%s%016lx%s %d%s", ColorRegister(r),
ctx->uc_mcontext.regs[r], reset, r == 8 || r == 9 ? " " : "", ctx->uc_mcontext.regs[r], reset, r,
r); r == 8 || r == 9 ? " " : "");
} }
Append(b, "\n"); Append(b, "\n");
} }
// PRINT CURRENT LOCATION // PRINT CURRENT LOCATION
//
// We can get the address of the currently executing function by
// simply examining the program counter.
pc = ctx->uc_mcontext.pc; pc = ctx->uc_mcontext.pc;
Append(b, " %016lx sp %lx pc", ctx->uc_mcontext.sp, pc); Append(b, " %016lx sp %lx pc", ctx->uc_mcontext.sp, pc);
if (pc && (symbol = __get_symbol(st, 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"); Append(b, "\n");
// PRINT LINKED LOCATION // 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]))) { if (IsCode((pc = ctx->uc_mcontext.regs[30]))) {
Append(b, " %016lx sp %lx lr", ctx->uc_mcontext.sp, pc); Append(b, " %016lx sp %lx lr", ctx->uc_mcontext.sp, pc);
if (pc && (symbol = __get_symbol(st, 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"); Append(b, "\n");
if (fp && !kisdangerous(fp) && pc == fp->addr) {
fp = fp->next;
}
} }
// PRINT FRAME POINTERS // 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) { for (i = 0; fp; fp = fp->next) {
if (kisdangerous(fp)) { if (kisdangerous(fp)) {
Append(b, " %016lx <dangerous fp>\n", fp); Append(b, " %016lx <dangerous fp>\n", fp);
@ -284,9 +302,10 @@ relegated void __oncrash_arm64(int sig, struct siginfo *si, void *arg) {
} }
} }
} else { } 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)); sys_write(2, b->p, MIN(b->i, b->n));
__print_maps();
_Exit(128 + sig); _Exit(128 + sig);
} }

View file

@ -26,6 +26,7 @@
#include "libc/log/log.h" #include "libc/log/log.h"
#include "libc/macros.internal.h" #include "libc/macros.internal.h"
#include "libc/mem/mem.h" #include "libc/mem/mem.h"
#include "libc/runtime/internal.h"
#include "libc/runtime/runtime.h" #include "libc/runtime/runtime.h"
#include "libc/runtime/stack.h" #include "libc/runtime/stack.h"
#include "libc/runtime/symbols.internal.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(SIGBUS, __got_sigbus, ef); // misalign, mmap i/o failed
InstallCrashHandler(SIGURG, __got_sigurg, ef); // placeholder InstallCrashHandler(SIGURG, __got_sigurg, ef); // placeholder
GetSymbolTable(); GetSymbolTable();
void __wipe(uintptr_t);
return __wipe(0);
} }

View file

@ -170,6 +170,31 @@
.previous .previous
.endm .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. // Documents unreachable assembly code.
.macro .unreachable .macro .unreachable
#if !defined(NDEBUG) && defined(__x86_64__) #if !defined(NDEBUG) && defined(__x86_64__)
@ -390,22 +415,6 @@
.byte 0x0f,0x1f,0105,\endfunc-. # nopl disp8(%rbp) .byte 0x0f,0x1f,0105,\endfunc-. # nopl disp8(%rbp)
.endm .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. // Good alignment for functions where alignment actually helps.
// @note 16-byte // @note 16-byte
.macro .alignfunc .macro .alignfunc

View file

@ -46,6 +46,20 @@ COSMOPOLITAN_C_START_
asm volatile("mrs\t%0,cntvct_el0" : "=r"(_Ts)); \ asm volatile("mrs\t%0,cntvct_el0" : "=r"(_Ts)); \
_Ts * 48; /* the fudge factor */ \ _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 #endif
COSMOPOLITAN_C_END_ COSMOPOLITAN_C_END_

View file

@ -56,14 +56,19 @@ sys_clone_linux:
syscall syscall
1: hlt // ctid was corrupted by program! 1: hlt // ctid was corrupted by program!
#elif defined(__aarch64__) #elif defined(__aarch64__)
stp x29,x30,[sp,#-16]!
mov x29,sp
mov x8,x3 // swap x3 and x4 mov x8,x3 // swap x3 and x4
mov x3,x4 // swap x3 and x4 mov x3,x4 // swap x3 and x4
mov x4,x8 // swap x3 and x4 mov x4,x8 // swap x3 and x4
mov x8,#220 // __NR_clone mov x8,#220 // __NR_clone
svc #0 svc #0
cbz x0,2f cbz x0,2f
ldp x29,x30,[sp],#16
ret 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 ldr w1,[x4] // arg2 = *ctid
blr x5 blr x5
mov x8,#93 // __NR_exit mov x8,#93 // __NR_exit

View file

@ -24,11 +24,14 @@
#include "libc/runtime/internal.h" #include "libc/runtime/internal.h"
#include "libc/runtime/memtrack.internal.h" #include "libc/runtime/memtrack.internal.h"
#include "libc/runtime/runtime.h" #include "libc/runtime/runtime.h"
#include "libc/runtime/stack.h"
#include "libc/runtime/syslib.internal.h" #include "libc/runtime/syslib.internal.h"
#include "libc/sysv/consts/prot.h"
#include "libc/thread/thread.h" #include "libc/thread/thread.h"
#include "libc/thread/tls.h" #include "libc/thread/tls.h"
#ifndef __x86_64__ #ifndef __x86_64__
void __wipe(uintptr_t);
int main(int, char **, char **) __attribute__((__weak__)); int main(int, char **, char **) __attribute__((__weak__));
typedef int init_f(int argc, char **argv, char **envp, unsigned long *auxv); 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 *__preinit_array_end[] __attribute__((__weak__));
extern init_f *__init_array_start[] __attribute__((__weak__)); extern init_f *__init_array_start[] __attribute__((__weak__));
extern init_f *__init_array_end[] __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 pthread_mutex_t __mmi_lock_obj;
extern int hostos asm("__hostos"); extern int hostos asm("__hostos");
@ -86,11 +92,21 @@ textstartup void cosmo(long *sp, struct Syslib *m1) {
__oldstack = (intptr_t)sp; __oldstack = (intptr_t)sp;
__pid = sys_getpid().ax; __pid = sys_getpid().ax;
// initialize mmap() manager extremely early // initialize memory manager
_mmi.n = ARRAYLEN(_mmi.s); _mmi.n = ARRAYLEN(_mmi.s);
_mmi.p = _mmi.s; _mmi.p = _mmi.s;
__mmi_lock_obj._type = PTHREAD_MUTEX_RECURSIVE; __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 0
#if IsAsan() #if IsAsan()
__asan_init(argc, argv, envp, auxv); __asan_init(argc, argv, envp, auxv);
@ -118,6 +134,7 @@ textstartup void cosmo(long *sp, struct Syslib *m1) {
} }
// run program // run program
if (!IsTiny()) __wipe(0);
exit(main(argc, argv, envp)); exit(main(argc, argv, envp));
} }

View file

@ -16,6 +16,7 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "ape/sections.internal.h"
#include "libc/assert.h" #include "libc/assert.h"
#include "libc/calls/syscall-sysv.internal.h" #include "libc/calls/syscall-sysv.internal.h"
#include "libc/errno.h" #include "libc/errno.h"
@ -93,7 +94,7 @@ _Alignas(TLS_ALIGNMENT) static char __static_tls[6016];
*/ */
textstartup void __enable_tls(void) { textstartup void __enable_tls(void) {
int tid; int tid;
size_t siz; size_t hiz, siz;
char *mem, *tls; char *mem, *tls;
struct CosmoTib *tib; struct CosmoTib *tib;
@ -146,8 +147,8 @@ textstartup void __enable_tls(void) {
#elif defined(__aarch64__) #elif defined(__aarch64__)
siz = ROUNDUP(sizeof(*tib) + 2 * sizeof(void *) + I(_tls_size), hiz = ROUNDUP(sizeof(*tib) + 2 * sizeof(void *), I(_tls_align));
_Alignof(__static_tls)); siz = hiz + I(_tls_size);
if (siz <= sizeof(__static_tls)) { if (siz <= sizeof(__static_tls)) {
mem = __static_tls; mem = __static_tls;
} else { } else {
@ -160,12 +161,12 @@ textstartup void __enable_tls(void) {
if (IsAsan()) { if (IsAsan()) {
// there's a roundup(pagesize) gap between .tdata and .tbss // there's a roundup(pagesize) gap between .tdata and .tbss
// poison that empty space // poison that empty space
__asan_poison(mem + sizeof(*tib) + 2 * sizeof(void *) + I(_tdata_size), __asan_poison(mem + hiz + I(_tdata_size), I(_tbss_offset) - I(_tdata_size),
I(_tbss_offset) - I(_tdata_size), kAsanProtected); kAsanProtected);
} }
tib = (struct CosmoTib *)mem; tib = (struct CosmoTib *)mem;
tls = mem + sizeof(*tib) + 2 * sizeof(void *); tls = mem + hiz;
// Set the DTV. // Set the DTV.
// //

View file

@ -70,11 +70,45 @@ size_t GetMemtrackSize(struct MemoryIntervals *);
#define __mmi_unlock() (__threaded ? __mmi_unlock() : 0) #define __mmi_unlock() (__threaded ? __mmi_unlock() : 0)
#endif #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) \ #define IsLegalPointer(p) \
(-0x800000000000 <= (intptr_t)(p) && (intptr_t)(p) <= 0x7fffffffffff) (-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) { forceinline pureconst bool IsLegalSize(uint64_t n) {
return n <= 0x7fffffffffff; /* subtract frame size so roundup is safe */
return n <= 0x800000000000 - FRAMESIZE;
} }
forceinline pureconst bool IsAutoFrame(int x) { forceinline pureconst bool IsAutoFrame(int x) {

View file

@ -61,11 +61,10 @@
#define IP(X) (intptr_t)(X) #define IP(X) (intptr_t)(X)
#define VIP(X) (void *)IP(X) #define VIP(X) (void *)IP(X)
#define ALIGNED(p) (!(IP(p) & (FRAMESIZE - 1))) #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 SHADE(x) (((intptr_t)(x) >> 3) + 0x7fff8000)
#define FRAME(x) ((int)((intptr_t)(x) >> 16)) #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; 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; size_t virtualused, virtualneed;
if (VERY_UNLIKELY(!size)) { if (VERY_UNLIKELY(!size)) {
STRACE("size=0"); STRACE("can't mmap zero bytes");
return VIP(einval());
}
if (VERY_UNLIKELY(!IsLegalPointer(p))) {
STRACE("p isn't 48-bit");
return VIP(einval()); return VIP(einval());
} }
if (VERY_UNLIKELY(!ALIGNED(p))) { if (VERY_UNLIKELY(!ALIGNED(p))) {
STRACE("p isn't 64kb aligned"); STRACE("cosmo mmap is 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");
return VIP(einval()); return VIP(einval());
} }
if (VERY_UNLIKELY(!IsLegalSize(size))) { if (VERY_UNLIKELY(!IsLegalSize(size))) {
STRACE("size isn't 48-bit"); STRACE("mmap size isn't legal");
return VIP(einval()); return VIP(einval());
} }
if (VERY_UNLIKELY(INT64_MAX - size < off)) { if (VERY_UNLIKELY(!IsLegalPointer(p))) {
STRACE("too large"); 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()); 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, (__builtin_add_overflow((virtualused = GetMemtrackSize(&_mmi)), size,
&virtualneed) || &virtualneed) ||
virtualneed > __virtualmax)) { virtualneed > __virtualmax)) {
STRACE("%'zu size + %'zu inuse exceeds virtual memory limit %'zu", size, STRACE("mmap %'zu size + %'zu inuse exceeds virtual memory limit %'zu",
virtualused, __virtualmax); size, virtualused, __virtualmax);
return VIP(enomem()); return VIP(enomem());
} }
clashes = OverlapsImageSpace(p, size) || OverlapsExistingMapping(p, size); clashes = OverlapsImageSpace(p, size) || OverlapsExistingMapping(p, size);
if ((flags & MAP_FIXED_NOREPLACE) == MAP_FIXED_NOREPLACE && clashes) { if ((flags & MAP_FIXED_NOREPLACE) == MAP_FIXED_NOREPLACE && clashes) {
STRACE("noreplace overlaps existing"); STRACE("mmap noreplace overlaps existing");
return VIP(eexist()); return VIP(eexist());
} }
if (__builtin_add_overflow((int)(size >> 16), (int)!!(size & (FRAMESIZE - 1)), if (__builtin_add_overflow((int)(size >> 16), (int)!!(size & (FRAMESIZE - 1)),
&n)) { &n)) {
STRACE("memory range overflows"); STRACE("mmap range overflows");
return VIP(einval()); return VIP(einval());
} }
a = max(1, RoundDownTwoPow(size) >> 16); a = MAX(1, RoundDownTwoPow(size) >> 16);
f = (flags & ~MAP_FIXED_NOREPLACE) | MAP_FIXED; f = (flags & ~MAP_FIXED_NOREPLACE) | MAP_FIXED;
if (flags & MAP_FIXED) { if (flags & MAP_FIXED) {
x = FRAME(p); x = FRAME(p);
@ -347,7 +332,7 @@ noasan inline void *_Mmap(void *addr, size_t size, int prot, int flags, int fd,
} }
needguard = false; needguard = false;
p = (char *)ADDR(x); p = (char *)ADDR_32_TO_48(x);
if ((f & MAP_TYPE) == MAP_STACK) { if ((f & MAP_TYPE) == MAP_STACK) {
if (~f & MAP_ANONYMOUS) { if (~f & MAP_ANONYMOUS) {
STRACE("MAP_STACK must be 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 * is specified
* @param prot can have PROT_READ/PROT_WRITE/PROT_EXEC/PROT_NONE/etc. * @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` * @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_PRIVATE` for copy-on-write behavior of writeable pages
* - `MAP_SHARED` to create shared memory between processes * - `MAP_SHARED` to create shared memory between processes
* - `MAP_STACK` to create a grows-down alloc, where a guard page * - `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 * compile-time checks to ensure some char[8192] vars will not
* create an undetectable overflow into another thread's stack * create an undetectable overflow into another thread's stack
* Your `flags` may optionally bitwise or any of the following: * 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` in which case `addr` becomes more than a hint
* - `MAP_FIXED_NOREPLACE` to protect existing mappings; this is * - `MAP_FIXED_NOREPLACE` to protect existing mappings; this is
* always polyfilled by mmap() which tracks its own memory and * 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_INHERIT` is NetBSD-only
* - `MAP_LOCKED` is Linux-only * - `MAP_LOCKED` is Linux-only
* @param fd is an open()'d file descriptor, whose contents shall be * @param fd is an open()'d file descriptor, whose contents shall be
* made available w/ automatic reading at the chosen address and * made available w/ automatic reading at the chosen address
* must be -1 if MAP_ANONYMOUS is specified
* @param off specifies absolute byte index of fd's file for mapping, * @param off specifies absolute byte index of fd's file for mapping,
* should be zero if MAP_ANONYMOUS is specified, and sadly needs * should be zero if MAP_ANONYMOUS is specified, and sadly needs
* to be 64kb aligned too * to be 64kb aligned too

View file

@ -21,8 +21,6 @@
#include "libc/runtime/internal.h" #include "libc/runtime/internal.h"
#include "libc/runtime/memtrack.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) { textwindows int sys_mprotect_nt(void *addr, size_t size, int prot) {
int rc = 0; int rc = 0;
unsigned i; unsigned i;
@ -31,7 +29,7 @@ textwindows int sys_mprotect_nt(void *addr, size_t size, int prot) {
__mmi_lock(); __mmi_lock();
p = addr; p = addr;
i = FindMemoryInterval(&_mmi, (intptr_t)p >> 16); 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 // memory isn't in memtrack
// let's just trust the user then // let's just trust the user then
// it's probably part of the executable // 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 // memory is in memtrack, so use memtrack, to do dimensioning
// we unfortunately must do something similar to this for cow // we unfortunately must do something similar to this for cow
for (; i < _mmi.i; ++i) { 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; y = x + _mmi.p[i].size;
if ((x <= p && p < y) || (x < p + size && p + size <= y) || if ((x <= p && p < y) || (x < p + size && p + size <= y) ||
(p < x && y < p + size)) { (p < x && y < p + size)) {

View file

@ -36,7 +36,6 @@
#define IP(X) (intptr_t)(X) #define IP(X) (intptr_t)(X)
#define VIP(X) (void *)IP(X) #define VIP(X) (void *)IP(X)
#define ALIGNED(p) (!(IP(p) & (FRAMESIZE - 1))) #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 SHADE(x) (((intptr_t)(x) >> 3) + 0x7fff8000)
#define FRAME(x) ((int)((intptr_t)(x) >> 16)) #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) { static bool MustMoveMap(intptr_t y, size_t j) {
return ADDR(_mmi.p[j].y) + FRAMESIZE > y || return ADDR_32_TO_48(_mmi.p[j].y) + FRAMESIZE > y ||
(j + 1 < _mmi.i && ADDR(_mmi.p[j + 1].x) < 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()); return VIP(enomem());
} }
q = sys_mremap((void *)p, n, m, MREMAP_MAYMOVE | MREMAP_FIXED, 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, 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 (q == MAP_FAILED) return 0;
if (ReleaseMemoryIntervals(&_mmi, (uintptr_t)p >> 16, if (ReleaseMemoryIntervals(&_mmi, (uintptr_t)p >> 16,
((uintptr_t)p + n - FRAMESIZE) >> 16, 0) != -1 && ((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); _weaken(__asan_map_shadow)((intptr_t)q, m);
} }
} }
return (void *)ADDR(a); return (void *)ADDR_32_TO_48(a);
} else { } else {
abort(); abort();
} }

View file

@ -25,14 +25,12 @@
#include "libc/sysv/consts/o.h" #include "libc/sysv/consts/o.h"
#include "libc/sysv/consts/prot.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) { noasan textwindows int sys_msync_nt(char *addr, size_t size, int flags) {
int i, rc = 0; int i, rc = 0;
char *a, *b, *x, *y; char *a, *b, *x, *y;
__mmi_lock(); __mmi_lock();
for (i = FindMemoryInterval(&_mmi, (intptr_t)addr >> 16); i < _mmi.i; ++i) { 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; y = x + _mmi.p[i].size;
if ((x <= addr && addr < y) || (x < addr + size && addr + size <= y) || if ((x <= addr && addr < y) || (x < addr + size && addr + size <= y) ||
(addr < x && y < addr + size)) { (addr < x && y < addr + size)) {

View file

@ -37,7 +37,6 @@
#define IP(X) (intptr_t)(X) #define IP(X) (intptr_t)(X)
#define ALIGNED(p) (!(IP(p) & (FRAMESIZE - 1))) #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)) #define FRAME(x) ((int)((intptr_t)(x) >> 16))
static noasan void MunmapShadow(char *p, size_t n) { 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 // 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! // file, that we be sure to call munmap(file, 5). let's abstract!
a = ADDR(beg); a = ADDR_32_TO_48(beg);
b = ADDR(end) + FRAMESIZE; b = ADDR_32_TO_48(end) + FRAMESIZE;
c = ADDR(_mmi.p[i].x) + _mmi.p[i].size; c = ADDR_32_TO_48(_mmi.p[i].x) + _mmi.p[i].size;
q = (char *)a; q = (char *)a;
m = MIN(b, c) - a; m = MIN(b, c) - a;
if (!IsWindows()) { if (!IsWindows()) {
@ -119,23 +118,23 @@ noasan int _Munmap(char *p, size_t n) {
intptr_t a, b, x, y; intptr_t a, b, x, y;
_unassert(!__vforked); _unassert(!__vforked);
if (UNLIKELY(!n)) { if (UNLIKELY(!n)) {
STRACE("n=0"); STRACE("munmap n is 0");
return einval(); return einval();
} }
if (UNLIKELY(!IsLegalSize(n))) { if (UNLIKELY(!IsLegalSize(n))) {
STRACE("n isn't 48-bit"); STRACE("munmap n isn't 48-bit");
return einval(); return einval();
} }
if (UNLIKELY(!IsLegalPointer(p))) { if (UNLIKELY(!IsLegalPointer(p))) {
STRACE("p isn't 48-bit"); STRACE("munmap p isn't 48-bit");
return einval(); return einval();
} }
if (UNLIKELY(!IsLegalPointer(p + (n - 1)))) { 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(); return einval();
} }
if (UNLIKELY(!ALIGNED(p))) { if (UNLIKELY(!ALIGNED(p))) {
STRACE("p isn't 64kb aligned"); STRACE("munmap(%p) isn't 64kb aligned", p);
return einval(); return einval();
} }
MunmapImpl(p, n); MunmapImpl(p, n);

View file

@ -33,50 +33,50 @@
_OpenExecutable: _OpenExecutable:
push %rbp push %rbp
mov %rsp,%rbp mov %rsp,%rbp
pushq __NR_open(%rip) # -0x08(%rbp) pushq __NR_open(%rip) // -0x08(%rbp)
pushq __NR_mmap(%rip) # -0x10(%rbp) pushq __NR_mmap(%rip) // -0x10(%rbp)
pushq __NR_munmap(%rip) # -0x18(%rbp) pushq __NR_munmap(%rip) // -0x18(%rbp)
pushq O_RDWR(%rip) # -0x20(%rbp) pushq O_RDWR(%rip) // -0x20(%rbp)
pushq MAP_ANONYMOUS(%rip) # -0x28(%rbp) pushq MAP_ANONYMOUS(%rip) // -0x28(%rbp)
pushq MAP_PRIVATE(%rip) # -0x30(%rbp) pushq MAP_PRIVATE(%rip) // -0x30(%rbp)
pushq MAP_FIXED(%rip) # -0x38(%rbp) pushq MAP_FIXED(%rip) // -0x38(%rbp)
pushq __NR_mprotect(%rip) # -0x40(%rbp) pushq __NR_mprotect(%rip) // -0x40(%rbp)
pushq O_RDONLY(%rip) # -0x48(%rbp) pushq O_RDONLY(%rip) // -0x48(%rbp)
push %rbx # code buffer push %rbx // code buffer
push %r12 # data buffer push %r12 // data buffer
push %r14 # filename push %r14 // filename
push %r15 # fd push %r15 // fd
// Get filename. // Get filename.
lea program_executable_name(%rip),%r14 lea program_executable_name(%rip),%r14
// Allocate code buffer. // Allocate code buffer.
mov -0x10(%rbp),%eax # __NR_mmap mov -0x10(%rbp),%eax // __NR_mmap
xor %edi,%edi xor %edi,%edi
mov $PAGESIZE,%esi mov $PAGESIZE,%esi
mov $PROT_READ|PROT_WRITE,%edx mov $PROT_READ|PROT_WRITE,%edx
mov -0x28(%rbp),%r10d # MAP_ANONYMOUS mov -0x28(%rbp),%r10d // MAP_ANONYMOUS
or -0x30(%rbp),%r10d # MAP_PRIVATE or -0x30(%rbp),%r10d // MAP_PRIVATE
mov $-1,%r8 mov $-1,%r8
mov $0,%r9 mov $0,%r9
push %r9 # openbsd:pad push %r9 // openbsd:pad
push %r9 # openbsd:align push %r9 // openbsd:align
syscall syscall
pop %r9 pop %r9
pop %r9 pop %r9
mov %rax,%rbx mov %rax,%rbx
// Allocate data buffer. // Allocate data buffer.
mov -0x10(%rbp),%eax # __NR_mmap mov -0x10(%rbp),%eax // __NR_mmap
xor %edi,%edi xor %edi,%edi
mov $ape_ram_filesz,%esi mov $ape_ram_filesz,%esi
mov $PROT_READ|PROT_WRITE,%edx mov $PROT_READ|PROT_WRITE,%edx
mov -0x28(%rbp),%r10d # MAP_ANONYMOUS mov -0x28(%rbp),%r10d // MAP_ANONYMOUS
or -0x30(%rbp),%r10d # MAP_PRIVATE or -0x30(%rbp),%r10d // MAP_PRIVATE
mov $-1,%r8 mov $-1,%r8
mov $0,%r9 mov $0,%r9
push %r9 # openbsd:pad push %r9 // openbsd:pad
push %r9 # openbsd:align push %r9 // openbsd:align
syscall syscall
pop %r9 pop %r9
pop %r9 pop %r9
@ -95,7 +95,7 @@ _OpenExecutable:
rep movsb rep movsb
// Change protection. // Change protection.
mov -0x40(%rbp),%eax # __NR_mprotect mov -0x40(%rbp),%eax // __NR_mprotect
mov %rbx,%rdi mov %rbx,%rdi
mov $PAGESIZE,%esi mov $PAGESIZE,%esi
mov $PROT_READ|PROT_EXEC,%edx mov $PROT_READ|PROT_EXEC,%edx
@ -106,63 +106,63 @@ _OpenExecutable:
// <LIMBO> // <LIMBO>
// Unmap code segment. // 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_vaddr,%edi
mov $ape_rom_filesz,%esi mov $ape_rom_filesz,%esi
syscall syscall
// Unmap data segment. // Unmap data segment.
mov -0x18(%rbp),%eax # __NR_munmap mov -0x18(%rbp),%eax // __NR_munmap
mov $ape_ram_vaddr,%edi mov $ape_ram_vaddr,%edi
mov $ape_ram_filesz,%esi mov $ape_ram_filesz,%esi
syscall syscall
// Open executable in read-write mode. // Open executable in read-write mode.
mov -0x08(%rbp),%eax # __NR_open mov -0x08(%rbp),%eax // __NR_open
mov %r14,%rdi mov %r14,%rdi
mov -0x20(%rbp),%esi # O_RDWR mov -0x20(%rbp),%esi // O_RDWR
clc # clear carry flag clc // clear carry flag
syscall syscall
jc .Lohno # bsd error jc .Lohno // bsd error
cmp $-4095,%eax cmp $-4095,%eax
jae .Lohno # linux error jae .Lohno // linux error
jmp .Lok jmp .Lok
// Open executable in read-only mode. // Open executable in read-only mode.
.Lohno: mov -0x08(%rbp),%eax # __NR_open .Lohno: mov -0x08(%rbp),%eax // __NR_open
mov %r14,%rdi mov %r14,%rdi
mov -0x48(%rbp),%esi # O_RDONLY mov -0x48(%rbp),%esi // O_RDONLY
syscall syscall
.Lok: mov %eax,%r15d .Lok: mov %eax,%r15d
// Map code segment. // Map code segment.
mov -0x10(%rbp),%eax # __NR_mmap mov -0x10(%rbp),%eax // __NR_mmap
mov $ape_rom_vaddr,%edi mov $ape_rom_vaddr,%edi
mov $ape_rom_filesz,%esi mov $ape_rom_filesz,%esi
mov $PROT_READ|PROT_EXEC,%edx mov $PROT_READ|PROT_EXEC,%edx
mov -0x38(%rbp),%r10d # MAP_FIXED mov -0x38(%rbp),%r10d // MAP_FIXED
or -0x30(%rbp),%r10d # MAP_PRIVATE or -0x30(%rbp),%r10d // MAP_PRIVATE
mov %r15d,%r8d mov %r15d,%r8d
mov $ape_rom_offset,%r9d mov $ape_rom_offset,%r9d
push %r9 # openbsd:pad push %r9 // openbsd:pad
push %r9 # openbsd:align push %r9 // openbsd:align
syscall syscall
pop %r9 pop %r9
pop %r9 pop %r9
// Allocate data segment. // Allocate data segment.
mov -0x10(%rbp),%eax # __NR_mmap mov -0x10(%rbp),%eax // __NR_mmap
mov $ape_ram_vaddr,%edi mov $ape_ram_vaddr,%edi
mov $ape_ram_filesz,%esi mov $ape_ram_filesz,%esi
mov $PROT_READ|PROT_WRITE,%edx mov $PROT_READ|PROT_WRITE,%edx
mov -0x38(%rbp),%r10d # MAP_FIXED mov -0x38(%rbp),%r10d // MAP_FIXED
or -0x30(%rbp),%r10d # MAP_PRIVATE or -0x30(%rbp),%r10d // MAP_PRIVATE
or -0x28(%rbp),%r10d # MAP_ANONYMOUS or -0x28(%rbp),%r10d // MAP_ANONYMOUS
mov $-1,%r8 mov $-1,%r8
mov $0,%r9 mov $0,%r9
push %r9 # openbsd:pad push %r9 // openbsd:pad
push %r9 # openbsd:align push %r9 // openbsd:align
syscall syscall
pop %r9 pop %r9
pop %r9 pop %r9

View file

@ -127,6 +127,8 @@ endif
# these assembly files are safe to build on aarch64 # these assembly files are safe to build on aarch64
o/$(MODE)/libc/runtime/init.o: libc/runtime/init.S o/$(MODE)/libc/runtime/init.o: libc/runtime/init.S
@$(COMPILE) -AOBJECTIFY.S $(OBJECTIFY.S) $(OUTPUT_OPTION) -c $< @$(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 o/$(MODE)/libc/runtime/vfork.o: libc/runtime/vfork.S
@$(COMPILE) -AOBJECTIFY.S $(OBJECTIFY.S) $(OUTPUT_OPTION) -c $< @$(COMPILE) -AOBJECTIFY.S $(OBJECTIFY.S) $(OUTPUT_OPTION) -c $<
o/$(MODE)/libc/runtime/clone-linux.o: libc/runtime/clone-linux.S 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 -*-│ /*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi
Copyright 2023 Justine Alexandra Roberts Tunney Copyright 2023 Justine Alexandra Roberts Tunney
@ -16,21 +16,69 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "libc/math.h" #include "libc/nexgen32e/x86feature.h"
#include "libc/macros.internal.h"
/** // Zeroes as many registers as possible.
* Rounds to nearest integer. //
*/ // Each caller should declare an appropriate prototype.
long long llrintf(float x) { //
long long res; // @param is return value
// @return is copied from parameter
__wipe:
#ifdef __x86_64__ #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__) #elif defined(__aarch64__)
asm("frintx\t%s1,%s1\n\t" mov x1,#0
"fcvtzs\t%x0,%s1" mov x2,#0
: "=r"(res), "+w"(x)); mov x3,#0
#else mov x4,#0
res = rintf(x); mov x5,#0
#endif /* __x86_64__ */ mov x6,#0
return res; 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/fmt/internal.h"
#include "libc/intrin/bsr.h" #include "libc/intrin/bsr.h"
#include "libc/macros.internal.h" #include "libc/macros.internal.h"
#include "libc/math.h"
#include "libc/str/str.h" #include "libc/str/str.h"
#include "third_party/gdtoa/gdtoa.h" #include "third_party/gdtoa/gdtoa.h"
@ -53,22 +54,22 @@ union U {
double d; double d;
uint64_t q; uint64_t q;
long double ld; long double ld;
unsigned int ui[4]; uint32_t ui[4];
unsigned short us[5]; uint16_t us[5];
}; };
static const FPI kFpiDbl = { static const FPI kFpiDbl = {
.nbits = 53, .nbits = DBL_MANT_DIG,
.emin = 1 - 1023 - 53 + 1, .emin = 3 - DBL_MAX_EXP - DBL_MANT_DIG,
.emax = 2046 - 1023 - 53 + 1, .emax = DBL_MAX_EXP - DBL_MANT_DIG,
.rounding = FPI_Round_near, .rounding = FPI_Round_near,
.sudden_underflow = 0, .sudden_underflow = 0,
}; };
static const FPI kFpiLdbl = { static const FPI kFpiLdbl = {
.nbits = 64, .nbits = LDBL_MANT_DIG,
.emin = 1 - 16383 - 64 + 1, .emin = 3 - LDBL_MAX_EXP - LDBL_MANT_DIG,
.emax = 32766 - 16383 - 64 + 1, .emax = LDBL_MAX_EXP - LDBL_MANT_DIG,
.rounding = FPI_Round_near, .rounding = FPI_Round_near,
.sudden_underflow = 0, .sudden_underflow = 0,
}; };
@ -80,21 +81,20 @@ static const char kSpecialFloats[2][2][4] = {
static void dfpbits(union U *u, struct FPBits *b) { static void dfpbits(union U *u, struct FPBits *b) {
int ex, i; int ex, i;
uint32_t *bits;
b->fpi = &kFpiDbl; b->fpi = &kFpiDbl;
b->sign = u->ui[1] & 0x80000000L; b->sign = u->ui[1] & 0x80000000L;
bits = b->bits; b->bits[1] = u->ui[1] & 0xfffff;
bits[1] = u->ui[1] & 0xfffff; b->bits[0] = u->ui[0];
bits[0] = u->ui[0];
if ((ex = (u->ui[1] & 0x7ff00000L) >> 20) != 0) { if ((ex = (u->ui[1] & 0x7ff00000L) >> 20) != 0) {
if (ex == 0x7ff) { if (ex != 0x7ff) {
// Infinity or NaN
i = bits[0] | bits[1] ? STRTOG_NaN : STRTOG_Infinite;
} else {
i = STRTOG_Normal; 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; i = STRTOG_Denormal;
ex = 1; ex = 1;
} else { } else {
@ -104,26 +104,49 @@ static void dfpbits(union U *u, struct FPBits *b) {
b->ex = ex - (0x3ff + 52); b->ex = ex - (0x3ff + 52);
} }
static void xfpbits(union U *u, struct FPBits *b) { static void ldfpbits(union U *u, struct FPBits *b) {
uint32_t *bits; #if LDBL_MANT_DIG == 53
dfpbits(u, b);
#else
int ex, i; 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->fpi = &kFpiLdbl;
b->sign = u->us[4] & 0x8000; b->sign = sex & 0x8000;
bits = b->bits; if ((ex = sex & 0x7fff) != 0) {
bits[1] = ((unsigned)u->us[3] << 16) | u->us[2]; if (ex != 0x7fff) {
bits[0] = ((unsigned)u->us[1] << 16) | u->us[0]; i = STRTOG_Normal;
if ((ex = u->us[4] & 0x7fff) != 0) { #if LDBL_MANT_DIG == 113
i = STRTOG_Normal; b->bits[3] |= 1 << (112 - 32 * 3); // set lowest exponent bit
if (ex == 0x7fff) // Infinity or NaN #endif
i = bits[0] | bits[1] ? STRTOG_NaN : STRTOG_Infinite; } else if (b->bits[0] | b->bits[1] | b->bits[2] | b->bits[3]) {
} else if (bits[0] | bits[1]) { i = STRTOG_NaN;
} else {
i = STRTOG_Infinite;
}
} else if (b->bits[0] | b->bits[1] | b->bits[2] | b->bits[3]) {
i = STRTOG_Denormal; i = STRTOG_Denormal;
ex = 1; ex = 1;
} else { } else {
i = STRTOG_Zero; i = STRTOG_Zero;
} }
b->kind = i; 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 // 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 { } else {
u.ld = va_arg(va, long double); u.ld = va_arg(va, long double);
consumed = __FMT_CONSUMED_LONG_DOUBLE; consumed = __FMT_CONSUMED_LONG_DOUBLE;
xfpbits(&u, &fpb); ldfpbits(&u, &fpb);
s = s0 = s = s0 =
gdtoa(fpb.fpi, fpb.ex, fpb.bits, &fpb.kind, 3, prec, &decpt, &se); 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 { } else {
u.ld = va_arg(va, long double); u.ld = va_arg(va, long double);
consumed = __FMT_CONSUMED_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, s = s0 = gdtoa(fpb.fpi, fpb.ex, fpb.bits, &fpb.kind, prec ? 2 : 0, prec,
&decpt, &se); &decpt, &se);
} }
@ -397,7 +420,7 @@ int __fmt_dtoa(int (*out)(const char *, void *, size_t), void *arg, int d,
} else { } else {
u.ld = va_arg(va, long double); u.ld = va_arg(va, long double);
consumed = __FMT_CONSUMED_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, s = s0 = gdtoa(fpb.fpi, fpb.ex, fpb.bits, &fpb.kind, prec ? 2 : 0, prec,
&decpt, &se); &decpt, &se);
} }
@ -460,7 +483,7 @@ int __fmt_dtoa(int (*out)(const char *, void *, size_t), void *arg, int d,
if (longdouble) { if (longdouble) {
u.ld = va_arg(va, long double); u.ld = va_arg(va, long double);
consumed = __FMT_CONSUMED_LONG_DOUBLE; consumed = __FMT_CONSUMED_LONG_DOUBLE;
xfpbits(&u, &fpb); ldfpbits(&u, &fpb);
} else { } else {
u.d = va_arg(va, double); u.d = va_arg(va, double);
consumed = __FMT_CONSUMED_DOUBLE; consumed = __FMT_CONSUMED_DOUBLE;

View file

@ -1,2 +1,2 @@
#include "libc/sysv/macros.internal.h" #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 .else
\name: mov x16,#\arm_xnu // apple ordinal \name: mov x16,#\arm_xnu // apple ordinal
mov x8,#\arm_linux // systemd 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 svc #0 // issue system call
bcs 1f bcs 1f
b _sysret 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_exit 0x00100100120010e7 0x05e globl hidden # a.k.a. exit_group
scall sys_read 0x8038038032803800 0x03f globl hidden scall sys_read 0x8038038032803800 0x03f globl hidden
scall sys_write 0x8048048042804801 0x040 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_close 0x0060060062006003 0x039 globl hidden
scall __sys_stat 0x1b7026fff2152004 0x04f globl hidden # FreeBSD 11→12 fumble; use sys_fstatat(); blocked on Android 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() 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 #────────────────────────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_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_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_open_tree 0xfffffffffffff1ac 0x1ac globl # no wrapper
scall sys_move_mount 0xfffffffffffff1ad 0x1ad globl # no wrapper scall sys_move_mount 0xfffffffffffff1ad 0x1ad globl # no wrapper
scall sys_fsopen 0xfffffffffffff1ae 0x1ae globl # no wrapper scall sys_fsopen 0xfffffffffffff1ae 0x1ae globl # no wrapper

View file

@ -107,52 +107,52 @@ __pid: .quad 0
systemfive_cp: systemfive_cp:
push %rbp push %rbp
mov %rsp,%rbp # so backtraces work mov %rsp,%rbp // so backtraces work
systemfive_cancellable: # our pthread_cancel() miracle code systemfive_cancellable: // our pthread_cancel() miracle code
cmpb $0,__tls_enabled(%rip) # inspired by the musl libc design! cmpb $0,__tls_enabled(%rip) // inspired by the musl libc design!
je 1f # we handle linux and bsd together! je 1f // we handle linux and bsd together!
mov %fs:0,%r10 # CosmoTib::tib_self mov %fs:0,%r10 // CosmoTib::tib_self
mov 0x28(%r10),%r10 # CosmoTib::tib_pthread mov 0x28(%r10),%r10 // CosmoTib::tib_pthread
test %r10,%r10 # is it a posix thread? test %r10,%r10 // is it a posix thread?
jz 1f # it's spawn() probably jz 1f // it's spawn() probably
testb $PT_NOCANCEL,0x00(%r10) # PosixThread::flags testb $PT_NOCANCEL,0x00(%r10) // PosixThread::flags
jnz 1f # canceler no cancelling jnz 1f // canceler no cancelling
#if IsModeDbg() #if IsModeDbg()
testb $PT_INCANCEL,0x00(%r10) testb $PT_INCANCEL,0x00(%r10)
jz 5f jz 5f
#endif #endif
cmp $0,0x04(%r10) # PosixThread::cancelled cmp $0,0x04(%r10) // PosixThread::cancelled
jne systemfive_cancel # we will tail call below jne systemfive_cancel // we will tail call below
1: mov %rcx,%r10 # move the fourth argument 1: mov %rcx,%r10 // move the fourth argument
clc # no cancellable system calls exist clc // no cancellable system calls exist
syscall # that have 7+ args on the bsd OSes syscall // that have 7+ args on the bsd OSes
systemfive_cancellable_end: # i/o calls park here for long time systemfive_cancellable_end: // i/o calls park here for long time
pop %rbp pop %rbp
jnc 2f jnc 2f
neg %rax # turns bsd errno to system v errno neg %rax // turns bsd errno to system v errno
2: cmp $-4095,%rax # but we still check again on eintr 2: cmp $-4095,%rax // but we still check again on eintr
jae 3f # branch because system call failed jae 3f // branch because system call failed
ret # done if the system call succeeded ret // done if the system call succeeded
3: neg %eax # now examine the nature of failure 3: neg %eax // now examine the nature of failure
cmp EINTR(%rip),%eax # did the SIGTHR cancel our IO call cmp EINTR(%rip),%eax // did the SIGTHR cancel our IO call
jne systemfive_errno # werent interrupted by OnSigCancel jne systemfive_errno // werent interrupted by OnSigCancel
cmpb $0,__tls_enabled(%rip) # make sure it's safe to grab %fs:0 cmpb $0,__tls_enabled(%rip) // make sure it's safe to grab %fs:0
je systemfive_errno # tls is disabled we can't continue je systemfive_errno // tls is disabled we can't continue
mov %fs:0,%rcx # CosmoTib::tib_self mov %fs:0,%rcx // CosmoTib::tib_self
mov 0x28(%rcx),%rcx # CosmoTib::tib_pthread mov 0x28(%rcx),%rcx // CosmoTib::tib_pthread
test %rcx,%rcx # is it a posix thread? test %rcx,%rcx // is it a posix thread?
jz systemfive_errno # it's spawn() probably jz systemfive_errno // it's spawn() probably
testb $PT_NOCANCEL,0x00(%rcx) # PosixThread::flags testb $PT_NOCANCEL,0x00(%rcx) // PosixThread::flags
jnz systemfive_errno # cancellation is disabled jnz systemfive_errno // cancellation is disabled
cmp $0,0x04(%rcx) # PosixThread::cancelled cmp $0,0x04(%rcx) // PosixThread::cancelled
je systemfive_errno # we aren't actually cancelled je systemfive_errno // we aren't actually cancelled
jmp 4f # now we are in fact cancelled jmp 4f // now we are in fact cancelled
systemfive_cancel: # SIGTHR will jump here too systemfive_cancel: // SIGTHR will jump here too
pop %rbp pop %rbp
4: jmp _pthread_cancel_sys # tail call 4: jmp _pthread_cancel_sys // tail call
.weak _pthread_cancel_sys # must be linked if we're cancelled .weak _pthread_cancel_sys // must be linked if we're cancelled
#if IsModeDbg() #if IsModeDbg()
not_a_cancellation_point: # need BEGIN/END_CANCELLATION_POINT not_a_cancellation_point: // need BEGIN/END_CANCELLATION_POINT
nop nop
.weak report_cancellation_point .weak report_cancellation_point
5: ezlea report_cancellation_point,cx 5: ezlea report_cancellation_point,cx
@ -170,18 +170,18 @@ not_a_cancellation_point: # need BEGIN/END_CANCELLATION_POINT
.Lanchorpoint: .Lanchorpoint:
#if SupportsLinux() || SupportsMetal() #if SupportsLinux() || SupportsMetal()
systemfive_linux: systemfive_linux:
and $0xfff,%eax # remove nonlinux bits from ordinal and $0xfff,%eax // remove nonlinux bits from ordinal
cmp $0xfff,%eax # checks if unsupported by platform cmp $0xfff,%eax // checks if unsupported by platform
je systemfive_enosys # never taken branches cost nothing je systemfive_enosys // never taken branches cost nothing
btr $11,%eax # 0x800 means a call is cancellable btr $11,%eax // 0x800 means a call is cancellable
jc systemfive_cp # it is handled by the holiest code jc systemfive_cp // it is handled by the holiest code
mov %rcx,%r10 # syscall instruction clobbers %rcx mov %rcx,%r10 // syscall instruction clobbers %rcx
push %rbp # linux never reads args from stack push %rbp // linux never reads args from stack
mov %rsp,%rbp # having frame will help backtraces mov %rsp,%rbp // having frame will help backtraces
syscall # this is known as a context switch syscall // this is known as a context switch
pop %rbp # next we check to see if it failed pop %rbp // next we check to see if it failed
cmp $-4095,%rax # system five nexgen32e abi § a.2.1 cmp $-4095,%rax // system five nexgen32e abi § a.2.1
jae systemfive_error # encodes errno as neg return value jae systemfive_error // encodes errno as neg return value
ret ret
.endfn systemfive_linux,globl,hidden .endfn systemfive_linux,globl,hidden
systemfive_error: systemfive_error:
@ -192,9 +192,9 @@ systemfive_error:
systemfive_errno: systemfive_errno:
xchg %eax,%ecx xchg %eax,%ecx
.errno .errno
mov %ecx,(%rax) # normalize to c library convention mov %ecx,(%rax) // normalize to c library convention
push $-1 # negative one is only error result push $-1 // negative one is only error result
pop %rax # the push pop is to save code size pop %rax // the push pop is to save code size
ret ret
.endfn systemfive_errno,globl,hidden .endfn systemfive_errno,globl,hidden
systemfive_enosys: systemfive_enosys:
@ -228,20 +228,20 @@ systemfive_bsdscrub:
systemfive_bsd: systemfive_bsd:
cmp $0xfff,%ax cmp $0xfff,%ax
je systemfive_enosys je systemfive_enosys
btr $11,%eax # checks/reset the 800 cancellable bit btr $11,%eax // checks/reset the 800 cancellable bit
jc systemfive_cp jc systemfive_cp
mov %rcx,%r10 mov %rcx,%r10
syscall # bsd will need arg on stack sometimes syscall // bsd will need arg on stack sometimes
jc systemfive_errno # bsd sets carry flag if %rax is errno jc systemfive_errno // bsd sets carry flag if %rax is errno
ret ret
.endfn systemfive_bsd .endfn systemfive_bsd
#endif #endif
#if SupportsXnu() #if SupportsXnu()
systemfive_xnu: 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 mov %eax,%r11d
and $0x0f000000,%r11d and $0x0f000000,%r11d
shl $8,%eax shl $8,%eax
@ -271,10 +271,10 @@ systemfive_xnu:
// set by libc/crt/crt.S for XNU/FreeBSD // set by libc/crt/crt.S for XNU/FreeBSD
// set by libc/nt/winmain.greg.c for New Technology // set by libc/nt/winmain.greg.c for New Technology
test %eax,%eax test %eax,%eax
jnz _init_systemfive_detected # os is already known jnz _init_systemfive_detected // os is already known
#endif #endif
#if SupportsOpenbsd() #if SupportsOpenbsd()
cmpq $0,(%r15) # OpenBSD has no auxv cmpq $0,(%r15) // OpenBSD has no auxv
jnz 0f jnz 0f
mov $_HOSTOPENBSD,%al mov $_HOSTOPENBSD,%al
jmp _init_systemfive_detected jmp _init_systemfive_detected
@ -282,7 +282,7 @@ systemfive_xnu:
#endif #endif
#if SupportsNetbsd() #if SupportsNetbsd()
xor %ecx,%ecx 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 jne 1f
mov $_HOSTNETBSD,%al mov $_HOSTNETBSD,%al
jmp _init_systemfive_detected jmp _init_systemfive_detected
@ -371,7 +371,7 @@ _init_systemfive_magnums:
xor %ebx,%ebx xor %ebx,%ebx
xor %ecx,%ecx xor %ecx,%ecx
xor %edx,%edx xor %edx,%edx
3: lodsb # decodes uleb128 3: lodsb // decodes uleb128
movzbl %al,%edx movzbl %al,%edx
and $127,%dl and $127,%dl
shl %cl,%rdx shl %cl,%rdx
@ -422,23 +422,23 @@ _init_systemfive_pid:
#endif #endif
#if SupportsBsd() && !defined(TINY) #if SupportsBsd() && !defined(TINY)
_init_systemfive_sigsys: _init_systemfive_sigsys:
testb IsBsd() # BSDs will trap SIGSYS! testb IsBsd() // BSDs will trap SIGSYS!
jz 1f # We want ENOSYS instead jz 1f // We want ENOSYS instead
push %rdi # XNU removed some calls push %rdi // XNU removed some calls
push %rsi # in past, so this makes push %rsi // in past, so this makes
xor %eax,%eax # troubleshooting easier xor %eax,%eax // troubleshooting easier
push %rax # but it's non-essential push %rax // but it's non-essential
push %rax push %rax
push %rax push %rax
push %rax push %rax
push %rax push %rax
push $SIG_IGN # sigaction_meta size 48 push $SIG_IGN // sigaction_meta size 48
mov __NR_sigaction,%eax # mag mov __NR_sigaction,%eax // mag
mov SIGSYS,%edi # sig mov SIGSYS,%edi // sig
mov %rsp,%rsi # new mov %rsp,%rsi // new
xor %edx,%edx # old xor %edx,%edx // old
mov $8,%r10d # for linux mov $8,%r10d // for linux
xor %r8d,%r8d # for netbsd xor %r8d,%r8d // for netbsd
syscall syscall
add $6*8,%rsp add $6*8,%rsp
pop %rsi pop %rsi

View file

@ -1,6 +1,5 @@
#ifndef COSMOPOLITAN_LIBC_BENCH_H_ #ifndef COSMOPOLITAN_LIBC_BENCH_H_
#define COSMOPOLITAN_LIBC_BENCH_H_ #define COSMOPOLITAN_LIBC_BENCH_H_
#include "libc/intrin/safemacros.internal.h"
#include "libc/nexgen32e/bench.h" #include "libc/nexgen32e/bench.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0) #if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_ COSMOPOLITAN_C_START_
@ -9,22 +8,39 @@ COSMOPOLITAN_C_START_
* @fileoverview Microbenchmarking Toolz. * @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 #ifndef BENCHLOOP
#define BENCHLOOP(START, STOP, N, INIT, EXPR) \ /* TODO(jart): DELETE */
({ \ #define BENCHLOOP(START, STOP, N, INIT, EXPR) \
unsigned long Iter, Count; \ ({ \
uint64_t Time1, Time2; \ double Average; \
double Average; \ uint64_t Time1, Time2; \
for (Average = 1, Iter = 1, Count = (N); Iter < Count; ++Iter) { \ unsigned long Iter, Count; \
INIT; \ for (Average = 1, Iter = 1, Count = (N); Iter < Count; ++Iter) { \
Time1 = START(); \ INIT; \
asm volatile("" ::: "memory"); \ Time1 = START(); \
EXPR; \ asm volatile("" ::: "memory"); \
asm volatile("" ::: "memory"); \ EXPR; \
Time2 = STOP(); \ asm volatile("" ::: "memory"); \
Average += 1. / Iter * ((int)unsignedsubtract(Time2, Time1) - Average); \ Time2 = STOP(); \
} \ Average += 1. / Iter * ((int)(Time2 - Time1) - Average); \
Average; \ } \
Average; \
}) })
#endif /* BENCHLOOP */ #endif /* BENCHLOOP */

View file

@ -1,5 +1,7 @@
#ifndef COSMOPOLITAN_LIBC_TESTLIB_EZBENCH_H_ #ifndef COSMOPOLITAN_LIBC_TESTLIB_EZBENCH_H_
#define 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/bench.h"
#include "libc/nexgen32e/x86feature.h" #include "libc/nexgen32e/x86feature.h"
#include "libc/testlib/bench.h" #include "libc/testlib/bench.h"
@ -18,7 +20,7 @@ COSMOPOLITAN_C_START_
#define EZBENCH2(NAME, INIT, EXPR) \ #define EZBENCH2(NAME, INIT, EXPR) \
do { \ do { \
int Core, Tries, Interrupts; \ int Core, Tries, Interrupts; \
int64_t Speculative, MemoryStrict; \ double Speculative, MemoryStrict; \
Tries = 0; \ Tries = 0; \
do { \ do { \
__testlib_yield(); \ __testlib_yield(); \
@ -53,14 +55,14 @@ COSMOPOLITAN_C_START_
__testlib_getinterrupts() > Interrupts)); \ __testlib_getinterrupts() > Interrupts)); \
if (Tries == EZBENCH_TRIES) __testlib_ezbenchwarn(" memory strict"); \ if (Tries == EZBENCH_TRIES) __testlib_ezbenchwarn(" memory strict"); \
__testlib_ezbenchreport( \ __testlib_ezbenchreport( \
NAME, MAX(0, Speculative - __testlib_ezbenchcontrol()), \ NAME, MAX(.001, Speculative - __testlib_ezbenchcontrol()), \
MAX(0, MemoryStrict - __testlib_ezbenchcontrol())); \ MAX(.001, MemoryStrict - __testlib_ezbenchcontrol())); \
} while (0) } while (0)
#define EZBENCH3(NAME, NUM, INIT, EXPR) \ #define EZBENCH3(NAME, NUM, INIT, EXPR) \
do { \ do { \
int Core, Tries, Interrupts; \ int Core, Tries, Interrupts; \
int64_t Speculative, MemoryStrict; \ double Speculative, MemoryStrict; \
Tries = 0; \ Tries = 0; \
do { \ do { \
__testlib_yield(); \ __testlib_yield(); \
@ -95,14 +97,14 @@ COSMOPOLITAN_C_START_
__testlib_getinterrupts() > Interrupts)); \ __testlib_getinterrupts() > Interrupts)); \
if (Tries == EZBENCH_TRIES) __testlib_ezbenchwarn(" memory strict"); \ if (Tries == EZBENCH_TRIES) __testlib_ezbenchwarn(" memory strict"); \
__testlib_ezbenchreport( \ __testlib_ezbenchreport( \
NAME, MAX(0, Speculative - __testlib_ezbenchcontrol()), \ NAME, MAX(.001, Speculative - __testlib_ezbenchcontrol()), \
MAX(0, MemoryStrict - __testlib_ezbenchcontrol())); \ MAX(.001, MemoryStrict - __testlib_ezbenchcontrol())); \
} while (0) } while (0)
#define EZBENCH_C(NAME, CONTROL, EXPR) \ #define EZBENCH_C(NAME, CONTROL, EXPR) \
do { \ do { \
int Core, Tries, Interrupts; \ int Core, Tries, Interrupts; \
int64_t Control, Speculative, MemoryStrict; \ double Control, Speculative, MemoryStrict; \
Tries = 0; \ Tries = 0; \
do { \ do { \
__testlib_yield(); \ __testlib_yield(); \
@ -144,53 +146,48 @@ COSMOPOLITAN_C_START_
(__testlib_getcore() != Core && \ (__testlib_getcore() != Core && \
__testlib_getinterrupts() > Interrupts)); \ __testlib_getinterrupts() > Interrupts)); \
if (Tries == EZBENCH_TRIES) __testlib_ezbenchwarn(" memory strict"); \ if (Tries == EZBENCH_TRIES) __testlib_ezbenchwarn(" memory strict"); \
__testlib_ezbenchreport(NAME, MAX(0, Speculative - Control), \ __testlib_ezbenchreport(NAME, MAX(.001, Speculative - Control), \
MAX(0, MemoryStrict - Control)); \ MAX(.001, MemoryStrict - Control)); \
} while (0) } while (0)
#define EZBENCH_N(NAME, N, EXPR) \ #define EZBENCH_N(NAME, N, EXPR) \
do { \ do { \
int64_t Speculative, Toto; \ double Speculative, Toto; \
int Core, Tries, Interrupts; \ int Core, Tries, Interrupts; \
Tries = 0; \ Tries = 0; \
do { \ do { \
__testlib_yield(); \ __testlib_yield(); \
Core = __testlib_getcore(); \ Core = __testlib_getcore(); \
Interrupts = __testlib_getinterrupts(); \ Interrupts = __testlib_getinterrupts(); \
EXPR; \ EXPR; \
Speculative = BENCHLOOP(__startbench, __endbench, 32, \ Speculative = BENCHLOOPER(__startbench, __endbench, 32, (EXPR)); \
__polluteregisters(), (EXPR)); \ } while (++Tries < EZBENCH_TRIES && !Speculative); \
} while (++Tries < EZBENCH_TRIES && \ if (Tries == EZBENCH_TRIES) __testlib_ezbenchwarn(""); \
(__testlib_getcore() != Core && \ __testlib_ezbenchreport_n(NAME, 'n', N, Speculative); \
__testlib_getinterrupts() > Interrupts)); \
if (Tries == EZBENCH_TRIES) __testlib_ezbenchwarn(""); \
__testlib_ezbenchreport_n( \
NAME, 'n', N, MAX(0, Speculative - __testlib_ezbenchcontrol())); \
} while (0) } while (0)
#define EZBENCH_K(NAME, K, EXPR) \ #define EZBENCH_K(NAME, K, EXPR) \
do { \ do { \
int Core; \ int Core; \
int64_t Speculative; \ double Speculative; \
do { \ do { \
__testlib_yield(); \ __testlib_yield(); \
Core = __testlib_getcore(); \ Core = __testlib_getcore(); \
EXPR; \ EXPR; \
Speculative = BENCHLOOP(__startbench, __endbench, EZBENCH_COUNT, \ Speculative = \
donothing, (EXPR)); \ BENCHLOOPER(__startbench, __endbench, EZBENCH_COUNT, (EXPR)); \
} while (Core != __testlib_getcore()); \ } while (Core != __testlib_getcore()); \
__testlib_ezbenchreport_n( \ __testlib_ezbenchreport_n(NAME, 'k', K, Speculative); \
NAME, 'k', K, MAX(0, Speculative - __testlib_ezbenchcontrol())); \
} while (0) } while (0)
void __polluteregisters(void); void __polluteregisters(void);
void __testlib_yield(void); void __testlib_yield(void);
int __testlib_getcore(void); int __testlib_getcore(void);
int64_t __testlib_getinterrupts(void); int64_t __testlib_getinterrupts(void);
int64_t __testlib_ezbenchcontrol(void); double __testlib_ezbenchcontrol(void);
void __testlib_ezbenchwarn(const char *); void __testlib_ezbenchwarn(const char *);
void __testlib_ezbenchreport(const char *, uint64_t, uint64_t); void __testlib_ezbenchreport(const char *, double, double);
void __testlib_ezbenchreport_n(const char *, char, size_t, uint64_t); void __testlib_ezbenchreport_n(const char *, char, size_t, double);
#ifdef __STRICT_ANSI__ #ifdef __STRICT_ANSI__
#undef EZBENCH2 #undef EZBENCH2

View file

@ -21,9 +21,9 @@
#include "libc/testlib/testlib.h" #include "libc/testlib/testlib.h"
static bool once; static bool once;
static int64_t g_ezbenchcontrol; static double g_ezbenchcontrol;
int64_t __testlib_ezbenchcontrol(void) { double __testlib_ezbenchcontrol(void) {
if (!once) { if (!once) {
int Core, Tries, Interrupts; int Core, Tries, Interrupts;
Tries = 0; Tries = 0;
@ -38,7 +38,7 @@ int64_t __testlib_ezbenchcontrol(void) {
if (Tries == 10) { if (Tries == 10) {
fputs("warning: failed to accurately benchmark control\n", stderr); 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); g_ezbenchcontrol);
once = true; once = true;
} }

View file

@ -26,17 +26,17 @@
STATIC_YOINK("strnwidth"); STATIC_YOINK("strnwidth");
void __testlib_ezbenchreport(const char *form, uint64_t c1, uint64_t c2) { void __testlib_ezbenchreport(const char *form, double c1, double c2) {
uint64_t ns1, ns2; long ns1, ns2;
__warn_if_powersave(); __warn_if_powersave();
ns1 = rintl(ConvertTicksToNanos(c1)); ns1 = lrintl(ConvertTicksToNanos(c1));
ns2 = rintl(ConvertTicksToNanos(c2)); ns2 = lrintl(ConvertTicksToNanos(c2));
(fprintf)(stderr, (fprintf)(stderr,
VEIL("r", " * %-19s l: %,9luc %,9luns m: %,9luc %,9luns\n"), 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]; char msg[128];
uint64_t bps; uint64_t bps;
long double cn, lat; long double cn, lat;

View file

@ -25,6 +25,8 @@ __polluteregisters:
xor %eax,%eax xor %eax,%eax
xor %ecx,%ecx xor %ecx,%ecx
xor %edx,%edx xor %edx,%edx
xor %edi,%edi
xor %esi,%esi
xor %r8d,%r8d xor %r8d,%r8d
xor %r9d,%r9d xor %r9d,%r9d
xor %r10d,%r10d xor %r10d,%r10d
@ -49,6 +51,31 @@ __polluteregisters:
xorps %xmm6,%xmm6 xorps %xmm6,%xmm6
xorps %xmm7,%xmm7 xorps %xmm7,%xmm7
.leafepilogue .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 #else
ret ret
#endif #endif
@ -58,7 +85,7 @@ __polluteregisters:
// Fill registers with junk data to create false dependencies. // Fill registers with junk data to create false dependencies.
// Which shall create the problem that happens w/o vzeroupper. // Which shall create the problem that happens w/o vzeroupper.
// Or the Core Architecture errata regarding BSR/BSF w/ 64bit. // Or the Core Architecture errata regarding BSR/BSF w/ 64bit.
__polluteregisters: __polluteregisters_old:
.leafprologue .leafprologue
mov $-1,%rax mov $-1,%rax
mov %rax,%rcx mov %rax,%rcx
@ -96,4 +123,4 @@ __polluteregisters:
punpcklqdq %xmm0,%xmm6 punpcklqdq %xmm0,%xmm6
punpcklqdq %xmm0,%xmm7 punpcklqdq %xmm0,%xmm7
.leafepilogue .leafepilogue
.endfn __polluteregisters,globl .endfn __polluteregisters_old,globl

View file

@ -32,9 +32,9 @@ thrashcodecache:
i = 0xdeadbeef i = 0xdeadbeef
0: .rept 32768/(3+7) 0: .rept 32768/(3+7)
rex.wrb rex.wrb
.byte 0001|(i&030) # ADD/OR/... Evqp Gvqp .byte 0001|(i&030) // ADD/OR/... Evqp Gvqp
.byte 0300|(i&033) # %r8-%r11 to %r8-%r11 .byte 0300|(i&033) // %r8-%r11 to %r8-%r11
.byte 0x49,0x81,0360|(i&003) # XOR immed32,%r8-%r11 .byte 0x49,0x81,0360|(i&003) // XOR immed32,%r8-%r11
.long i .long i
i = ((i * 1103515245 + 12345) >> 16) & 0xffffffff i = ((i * 1103515245 + 12345) >> 16) & 0xffffffff
.endr .endr

View file

@ -16,6 +16,7 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "ape/sections.internal.h"
#include "libc/dce.h" #include "libc/dce.h"
#include "libc/intrin/asan.internal.h" #include "libc/intrin/asan.internal.h"
#include "libc/intrin/asancodes.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) { static char *_mktls_above(struct CosmoTib **out_tib) {
size_t siz; size_t hiz, siz;
char *mem, *dtv, *tls; char *mem, *dtv, *tls;
struct CosmoTib *tib, *old; struct CosmoTib *tib, *old;
// allocate memory for tdata, tbss, and tib // allocate memory for tdata, tbss, and tib
siz = ROUNDUP(sizeof(struct CosmoTib) + 2 * sizeof(void *) + I(_tls_size), hiz = ROUNDUP(sizeof(*tib) + 2 * sizeof(void *), I(_tls_align));
TLS_ALIGNMENT); siz = hiz + I(_tls_size);
mem = memalign(TLS_ALIGNMENT, siz); mem = memalign(TLS_ALIGNMENT, siz);
if (!mem) return 0; if (!mem) return 0;
// poison memory between tdata and tbss // poison memory between tdata and tbss
if (IsAsan()) { if (IsAsan()) {
__asan_poison( __asan_poison(mem + hiz + I(_tdata_size), I(_tbss_offset) - I(_tdata_size),
mem + sizeof(struct CosmoTib) + 2 * sizeof(void *) + I(_tdata_size), kAsanProtected);
I(_tbss_offset) - I(_tdata_size), kAsanProtected);
} }
tib = (struct CosmoTib *)mem; tib = (struct CosmoTib *)mem;
dtv = mem + sizeof(*tib); dtv = mem + sizeof(*tib);
tls = dtv + 2 * sizeof(void *); tls = mem + hiz;
// set dtv // set dtv
((uintptr_t *)dtv)[0] = 1; ((uintptr_t *)dtv)[0] = 1;

View file

@ -26,6 +26,7 @@
#include "libc/intrin/atomic.h" #include "libc/intrin/atomic.h"
#include "libc/macros.internal.h" #include "libc/macros.internal.h"
#include "libc/str/str.h" #include "libc/str/str.h"
#include "libc/sysv/consts/at.h"
#include "libc/sysv/consts/o.h" #include "libc/sysv/consts/o.h"
#include "libc/sysv/consts/pr.h" #include "libc/sysv/consts/pr.h"
#include "libc/thread/posixthread.internal.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 = stpcpy(p, "/proc/self/task/");
p = FormatUint32(p, tid); p = FormatUint32(p, tid);
p = stpcpy(p, "/comm"); 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; rc = errno;
errno = e; errno = e;
return rc; return rc;

View file

@ -26,6 +26,7 @@
#include "libc/intrin/asmflag.h" #include "libc/intrin/asmflag.h"
#include "libc/intrin/atomic.h" #include "libc/intrin/atomic.h"
#include "libc/str/str.h" #include "libc/str/str.h"
#include "libc/sysv/consts/at.h"
#include "libc/sysv/consts/o.h" #include "libc/sysv/consts/o.h"
#include "libc/sysv/consts/pr.h" #include "libc/sysv/consts/pr.h"
#include "libc/thread/posixthread.internal.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 = stpcpy(p, "/proc/self/task/");
p = FormatUint32(p, tid); p = FormatUint32(p, tid);
p = stpcpy(p, "/comm"); 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; rc = errno;
errno = e; errno = e;
return rc; return rc;

View file

@ -66,7 +66,11 @@ void __set_tls(struct CosmoTib *);
}) })
#define __adj_tls(tib) (tib) #define __adj_tls(tib) (tib)
#elif defined(__aarch64__) #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) #define __adj_tls(tib) ((struct CosmoTib *)(tib) + 1)
#endif #endif

View file

@ -26,7 +26,7 @@ int64_t clock(void);
int64_t posix2time(int64_t) pureconst; int64_t posix2time(int64_t) pureconst;
int64_t time(int64_t *); int64_t time(int64_t *);
int64_t time2posix(int64_t) pureconst; int64_t time2posix(int64_t) pureconst;
long double ConvertTicksToNanos(uint64_t); long double ConvertTicksToNanos(double);
long double dsleep(long double); long double dsleep(long double);
long double dtime(int); long double dtime(int);
unsigned alarm(unsigned); unsigned alarm(unsigned);

View file

@ -20,6 +20,6 @@
double logb(double x) { double logb(double x) {
if (!isfinite(x)) return x * x; if (!isfinite(x)) return x * x;
if (x == 0) return -1 / (x * x); if (!x) return -1 / (x * x);
return ilogb(x); return ilogb(x);
} }

View file

@ -20,6 +20,6 @@
float logbf(float x) { float logbf(float x) {
if (!isfinite(x)) return x * x; if (!isfinite(x)) return x * x;
if (x == 0) return -1 / (x * x); if (!x) return -1 / (x * x);
return ilogbf(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 -*-│ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set et ft=c ts=8 tw=8 fenc=utf-8 :vi vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2023 Justine Alexandra Roberts Tunney
Musl Libc Permission to use, copy, modify, and/or distribute this software for
Copyright © 2005-2014 Rich Felker, et al. any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
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.
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/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__ #ifdef __x86_64__
long res; asm("cvtsd2si\t%1,%0" : "=r"(i) : "x"(x));
asm("cvtsd2si\t%1,%0" : "=r"(res) : "x"(x));
return res;
#elif defined(__aarch64__) #elif defined(__aarch64__)
long res; asm("frintx\t%d1,%d1\n\t"
asm("frintx\t%d1,%d1\n\t" "fcvtzs\t%x0,%d1"
"fcvtzs\t%x0,%d1" : "=r"(i), "+w"(x));
: "=r"(res), "+w"(x));
return res;
#elif defined(__powerpc64__) && defined(_ARCH_PWR5X) #elif defined(__powerpc64__) && defined(_ARCH_PWR5X)
long res; asm("fctid\t%0,%1" : "=d"(i) : "d"(x));
asm("fctid\t%0,%1" : "=d"(res) : "d"(x));
return res;
#elif defined(JUST_CALL_RINT)
return rint(x);
#else #else
uint32_t abstop = asuint64(x)>>32 & 0x7fffffff; i = rint(x);
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);
#endif /* __x86_64__ */ #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 #if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024
__strong_reference(lrint, lrintl); __strong_reference(lrint, lrintl);
#if __SIZEOF_LONG__ == __SIZEOF_LONG_LONG__
__strong_reference(lrint, llrintl);
#endif
#endif #endif

View file

@ -19,20 +19,27 @@
#include "libc/math.h" #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 lrintf(float x) {
long res; long i;
#ifdef __x86_64__ #ifdef __x86_64__
asm("cvtss2si\t%1,%0" : "=res"(res) : "x"(x)); asm("cvtss2si\t%1,%0" : "=r"(i) : "x"(x));
#elif defined(__aarch64__) #elif defined(__aarch64__)
asm("frintx\t%s1,%s1\n\t" asm("frintx\t%s1,%s1\n\t"
"fcvtzs\t%x0,%s1" "fcvtzs\t%x0,%s1"
: "=r"(res), "+w"(x)); : "=r"(i), "+w"(x));
#elif defined(__powerpc64__) #elif defined(__powerpc64__)
asm("fctid\t%0,%1" : "=d"(res) : "f"(x)); asm("fctid\t%0,%1" : "=d"(i) : "f"(x));
#else #else
res = rintf(x); i = rintf(x);
#endif /* __x86_64__ */ #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 -*-│ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set et ft=c ts=8 tw=8 fenc=utf-8 :vi vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2023 Justine Alexandra Roberts Tunney
Musl Libc Permission to use, copy, modify, and/or distribute this software for
Copyright © 2005-2014 Rich Felker, et al. any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
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.
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/math.h"
#include "libc/runtime/fenv.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) #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) long lrintl(long double x) {
{ fenv_t env;
#ifdef FE_INEXACT long double y;
/* feholdexcept(&env);
see comments in lrint.c y = rintl(x);
if (fetestexcept(FE_INVALID)) {
Note that if LONG_MAX == 0x7fffffffffffffff && LDBL_MANT_DIG == 64 feclearexcept(FE_INEXACT);
then x == 2**63 - 0.5 is the only input that overflows and }
raises inexact (with tonearest or upward rounding mode) feupdateenv(&env);
*/ return y;
// #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
} }
#endif /* long double is long */ #endif /* long double is long */

View file

@ -41,6 +41,12 @@ asm(".include \"libc/disclaimer.inc\"");
#endif #endif
static const double_t toint = 1/EPS; 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) double rint(double x)
{ {
union {double f; uint64_t i;} u = {x}; union {double f; uint64_t i;} u = {x};

View file

@ -43,6 +43,12 @@ asm(".include \"libc/disclaimer.inc\"");
#endif #endif
static const float_t toint = 1/EPS; 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) float rintf(float x)
{ {
union {float f; uint32_t i;} u = {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\""); asm(".include \"libc/disclaimer.inc\"");
// clang-format off // 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) long double rintl(long double x)
{ {
static const long double toint = 1/LDBL_EPSILON; 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: \
o/$(MODE)/net/turfwar/turfbean.com.dbg \ o/$(MODE)/net/turfwar/turfbean.com.dbg \
o/$(MODE)/third_party/zip/zip.com \ o/$(MODE)/third_party/zip/zip.com \
o/$(MODE)/tool/build/symtab.com o/$(MODE)/tool/build/symtab.com \
$(VM)
@$(MAKE_OBJCOPY) @$(MAKE_OBJCOPY)
@$(MAKE_SYMTAB_CREATE) @$(MAKE_SYMTAB_CREATE)
@$(MAKE_SYMTAB_ZIP) @$(MAKE_SYMTAB_ZIP)

View file

@ -25,6 +25,7 @@
#include "libc/intrin/promises.internal.h" #include "libc/intrin/promises.internal.h"
#include "libc/runtime/runtime.h" #include "libc/runtime/runtime.h"
#include "libc/sock/sock.h" #include "libc/sock/sock.h"
#include "libc/stdio/stdio.h"
#include "libc/sysv/consts/af.h" #include "libc/sysv/consts/af.h"
#include "libc/sysv/consts/ipproto.h" #include "libc/sysv/consts/ipproto.h"
#include "libc/sysv/consts/sig.h" #include "libc/sysv/consts/sig.h"
@ -32,10 +33,11 @@
#include "libc/testlib/subprocess.h" #include "libc/testlib/subprocess.h"
#include "libc/testlib/testlib.h" #include "libc/testlib/testlib.h"
#ifdef __x86_64__
void SetUp(void) { 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) { TEST(pledge, testSoftError) {
@ -116,5 +118,3 @@ TEST(pledge, testEmptyPledge_doesntUseTrapping) {
socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
TERMS(IsOpenbsd() ? SIGABRT : SIGSYS); TERMS(IsOpenbsd() ? SIGABRT : SIGSYS);
} }
#endif /* __x86_64__ */

View file

@ -62,9 +62,6 @@
#include "libc/time/time.h" #include "libc/time/time.h"
#include "libc/x/x.h" #include "libc/x/x.h"
// TODO(jart): Get pledge truly working on AARCH64
#ifdef __x86_64__
char testlib_enable_tmp_setup_teardown; char testlib_enable_tmp_setup_teardown;
void OnSig(int sig) { void OnSig(int sig) {
@ -75,7 +72,10 @@ int sys_memfd_secret(unsigned int); // our ENOSYS threshold
void SetUp(void) { void SetUp(void) {
__enable_threads(); __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/life.elf", "life.elf", 0755);
testlib_extract("/zip/sock.elf", "sock.elf", 0755); testlib_extract("/zip/sock.elf", "sock.elf", 0755);
__pledge_mode = PLEDGE_PENALTY_RETURN_EPERM; __pledge_mode = PLEDGE_PENALTY_RETURN_EPERM;
@ -659,5 +659,3 @@ BENCH(pledge, bench) {
} }
wait(0); 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) { BENCH(read, bench) {
char buf[16]; char buf[16];
ASSERT_SYS(0, 3, open("/dev/zero", O_RDONLY)); 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)); preadv(3, (struct iovec[]){{buf, 1}, {buf + 1, 4}}, 2, 0));
EZBENCH2("sys_read", donothing, sys_read(3, buf, 5)); EZBENCH2("sys_read", donothing, sys_read(3, buf, 5));
EZBENCH2("sys_readv", donothing, sys_readv(3, &(struct iovec){buf, 5}, 1)); 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)); 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: \ o/$(MODE)/test/libc/calls/poll_test.com.runs: \
private .PLEDGE = stdio rpath wpath cpath fattr proc inet private .PLEDGE = stdio rpath wpath cpath fattr proc inet
o/$(MODE)/test/libc/calls/fcntl_test.com.runs: \ 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 \
o/$(MODE)/test/libc/calls/lock2_test.com.runs \
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/lock_ofd_test.com.runs: \ o/$(MODE)/test/libc/calls/lock_ofd_test.com.runs: \
private .PLEDGE = stdio rpath wpath cpath fattr proc flock 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: \ o/$(MODE)/test/libc/calls/openbsd_test.com.runs: \
private .PLEDGE = stdio rpath wpath cpath fattr proc unveil private .PLEDGE = stdio rpath wpath cpath fattr proc unveil
o/$(MODE)/test/libc/calls/fexecve_test.com.runs: \ o/$(MODE)/test/libc/calls/fexecve_test.com.runs: \
private .UNSANDBOXED = 1 # for memfd_create() 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() private .UNSANDBOXED = 1 # for memfd_create()
o/$(MODE)/test/libc/calls/read_test.com.runs: \ o/$(MODE)/test/libc/calls/read_test.com.runs: \

View file

@ -51,16 +51,21 @@ char testlib_enable_tmp_setup_teardown;
struct stat st; struct stat st;
static bool SupportsLandlock(void) { bool HasUnveilSupport(void) {
int e = errno; return unveil("", 0) >= 0;
bool r = landlock_create_ruleset(0, 0, LANDLOCK_CREATE_RULESET_VERSION) >= 0; }
errno = e;
return r; bool UnveilCanSecureTruncate(void) {
int abi = unveil("", 0);
return abi == 0 || abi >= 3;
} }
void SetUpOnce(void) { void SetUpOnce(void) {
__enable_threads(); __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) { void SetUp(void) {
@ -68,10 +73,6 @@ void SetUp(void) {
ASSERT_SYS(0, 0, stat("/zip/life.elf", &st)); 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) { TEST(unveil, api_differences) {
SPAWN(fork); SPAWN(fork);
ASSERT_SYS(0, 0, mkdir("foo", 0755)); 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, xbarf("garden/secret.txt", "hello", 5));
ASSERT_SYS(0, 0, unveil("jail", "rw")); ASSERT_SYS(0, 0, unveil("jail", "rw"));
ASSERT_SYS(0, 0, unveil(0, 0)); 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)); truncate("garden/secret.txt", 0));
if (IsLinux()) { if (IsLinux()) {
ASSERT_SYS(0, 0, stat("garden/secret.txt", &st)); ASSERT_SYS(0, 0, stat("garden/secret.txt", &st));

View file

@ -96,30 +96,6 @@ TEST(write, rlimitFsizeExceeded_raisesEfbig) {
EXITS(0); 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) { BENCH(write, bench) {
ASSERT_SYS(0, 3, open("/dev/null", O_WRONLY)); ASSERT_SYS(0, 3, open("/dev/null", O_WRONLY));
EZBENCH2("write", donothing, write(3, "hello", 5)); 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_write", donothing, sys_write(3, "hello", 5));
EZBENCH2("sys_writev", donothing, EZBENCH2("sys_writev", donothing,
sys_writev(3, &(struct iovec){"hello", 5}, 1)); 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)); ASSERT_SYS(0, 0, close(3));
} }

View file

@ -26,6 +26,7 @@
#include "libc/testlib/testlib.h" #include "libc/testlib/testlib.h"
TEST(__dos2errno, test) { TEST(__dos2errno, test) {
#ifdef __x86__
EXPECT_EQ(0, __dos2errno(0)); EXPECT_EQ(0, __dos2errno(0));
EXPECT_EQ(EACCES, __dos2errno(kNtErrorSectorNotFound)); EXPECT_EQ(EACCES, __dos2errno(kNtErrorSectorNotFound));
EXPECT_EQ(EADDRNOTAVAIL, __dos2errno(kNtErrorInvalidNetname)); EXPECT_EQ(EADDRNOTAVAIL, __dos2errno(kNtErrorInvalidNetname));
@ -33,4 +34,5 @@ TEST(__dos2errno, test) {
if (IsWindows()) { if (IsWindows()) {
EXPECT_EQ(ENOLCK, __dos2errno(kNtErrorNotLocked)); EXPECT_EQ(ENOLCK, __dos2errno(kNtErrorNotLocked));
} }
#endif
} }

View file

@ -221,14 +221,13 @@ TEST(ksnprintf, testSymbols) {
} }
} }
#ifdef __x86_64__
TEST(ksnprintf, fuzzTheUnbreakable) { TEST(ksnprintf, fuzzTheUnbreakable) {
int e; int e;
size_t i; size_t i;
uint64_t x; uint64_t x;
char *f, b[32]; char *f, b[32];
_Alignas(FRAMESIZE) static const char weasel[FRAMESIZE]; _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)); EXPECT_SYS(0, 0, mprotect(f, FRAMESIZE, PROT_READ | PROT_WRITE));
strcpy(f, "hello %s\n"); strcpy(f, "hello %s\n");
EXPECT_EQ(12, ksnprintf(b, sizeof(b), f, "world")); 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)); EXPECT_SYS(0, 0, mprotect(f, FRAMESIZE, PROT_READ));
} }
#endif /* __x86_64__ */
TEST(kprintf, testFailure_wontClobberErrnoAndBypassesSystemCallSupport) { TEST(kprintf, testFailure_wontClobberErrnoAndBypassesSystemCallSupport) {
int n; int n;

View file

@ -220,7 +220,7 @@ int main(int argc, char *argv[]) {
TestContendedLock("PTHREAD_MUTEX_ERRORCHECK RAW TLS", TestContendedLock("PTHREAD_MUTEX_ERRORCHECK RAW TLS",
PTHREAD_MUTEX_ERRORCHECK); PTHREAD_MUTEX_ERRORCHECK);
__tls_enabled = 0; __tls_enabled_set(false);
TestUncontendedLock("PTHREAD_MUTEX_NORMAL RAW", PTHREAD_MUTEX_NORMAL); TestUncontendedLock("PTHREAD_MUTEX_NORMAL RAW", PTHREAD_MUTEX_NORMAL);
TestUncontendedLock("PTHREAD_MUTEX_RECURSIVE RAW", PTHREAD_MUTEX_RECURSIVE); TestUncontendedLock("PTHREAD_MUTEX_RECURSIVE RAW", PTHREAD_MUTEX_RECURSIVE);

View file

@ -17,10 +17,10 @@
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "libc/macros.internal.h" #include "libc/macros.internal.h"
#include "libc/mem/gc.internal.h"
#include "libc/mem/mem.h" #include "libc/mem/mem.h"
#include "libc/nexgen32e/nexgen32e.h" #include "libc/nexgen32e/nexgen32e.h"
#include "libc/stdio/rand.h" #include "libc/stdio/rand.h"
#include "libc/mem/gc.internal.h"
#include "libc/stdio/stdio.h" #include "libc/stdio/stdio.h"
#include "libc/str/str.h" #include "libc/str/str.h"
#include "libc/testlib/ezbench.h" #include "libc/testlib/ezbench.h"
@ -83,7 +83,7 @@ TEST(memmove, bighug) {
BENCH(memmove, bench) { BENCH(memmove, bench) {
volatile char *r; volatile char *r;
int n, max = 8 * 1024 * 1024; int n, max = 128 * 1024 * 1024;
char *volatile p = gc(calloc(max, 1)); char *volatile p = gc(calloc(max, 1));
char *volatile q = gc(calloc(max, 1)); char *volatile q = gc(calloc(max, 1));
EZBENCH_N("memmove", 0, memmove(p, q, 0)); EZBENCH_N("memmove", 0, memmove(p, q, 0));

View file

@ -108,8 +108,8 @@ TEST(strncmp, testInequality) {
char *s1 = strcpy(malloc(2), "1"); char *s1 = strcpy(malloc(2), "1");
char *s2 = strcpy(malloc(1), ""); char *s2 = strcpy(malloc(1), "");
ASSERT_EQ(0, strncmp(s1, s2, 0)); ASSERT_EQ(0, strncmp(s1, s2, 0));
ASSERT_EQ('1', strncmp(s1, s2, 1)); ASSERT_GT(strncmp(s1, s2, 1), 0);
ASSERT_EQ(-'1', strncmp(s2, s1, 1)); ASSERT_LT(strncmp(s2, s1, 1), 0);
free(s2); free(s2);
free(s1); free(s1);
} }

View file

@ -32,7 +32,7 @@
#ifdef __x86_64__ #ifdef __x86_64__
void SetUpOnce(void) { void SetUpOnce(void) {
__tls_enabled = false; __tls_enabled_set(false);
ASSERT_SYS(0, 0, pledge("stdio rpath", 0)); 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 { static const struct {
const char *s; const char *s;
const char *f; 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/str/highwayhash64.h"
#include "libc/inttypes.h" #include "libc/inttypes.h"
#include "libc/nexgen32e/crc32.h" #include "libc/nexgen32e/crc32.h"
#include "libc/runtime/runtime.h"
#include "libc/stdio/rand.h" #include "libc/stdio/rand.h"
#include "libc/stdio/stdio.h" #include "libc/stdio/stdio.h"
#include "libc/str/str.h" #include "libc/str/str.h"

View file

@ -18,6 +18,8 @@
*/ */
#include "libc/limits.h" #include "libc/limits.h"
#include "libc/math.h" #include "libc/math.h"
#include "libc/stdio/rand.h"
#include "libc/stdio/stdio.h"
#include "libc/testlib/testlib.h" #include "libc/testlib/testlib.h"
TEST(ilogb, yolo) { TEST(ilogb, yolo) {

View file

@ -16,6 +16,7 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "tool/build/lib/alu.h"
#include "libc/assert.h" #include "libc/assert.h"
#include "libc/limits.h" #include "libc/limits.h"
#include "libc/runtime/runtime.h" #include "libc/runtime/runtime.h"
@ -23,9 +24,9 @@
#include "libc/testlib/ezbench.h" #include "libc/testlib/ezbench.h"
#include "libc/testlib/testlib.h" #include "libc/testlib/testlib.h"
#include "test/tool/build/lib/optest.h" #include "test/tool/build/lib/optest.h"
#include "tool/build/lib/alu.h"
#include "tool/build/lib/case.h" #include "tool/build/lib/case.h"
#include "tool/build/lib/flags.h" #include "tool/build/lib/flags.h"
#ifdef __x86_64__
#define ALU_TEST 8 #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) { TEST(alu, test) {
RunOpTests(kAluOps, ARRAYLEN(kAluOps), kAluNames); 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 TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "tool/build/lib/bitscan.h"
#include "libc/macros.internal.h" #include "libc/macros.internal.h"
#include "libc/testlib/testlib.h" #include "libc/testlib/testlib.h"
#include "test/tool/build/lib/numbers.h" #include "test/tool/build/lib/numbers.h"
#include "tool/build/lib/bitscan.h"
#include "tool/build/lib/flags.h" #include "tool/build/lib/flags.h"
#ifdef __x86_64__
#define OSZ 00000000040 #define OSZ 00000000040
#define REXW 00000000100 #define REXW 00000000100
@ -103,3 +104,5 @@ TEST(bsf16, test) {
if (!zf) ASSERT_EQ(a, b, "%#lx", x); 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/alu.h"
#include "tool/build/lib/flags.h" #include "tool/build/lib/flags.h"
#include "tool/build/lib/machine.h" #include "tool/build/lib/machine.h"
#ifdef __x86_64__
#define NATIVE_ALU2(MODE, INSTRUCTION) \ #define NATIVE_ALU2(MODE, INSTRUCTION) \
asm("pushf\n\t" \ 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 TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "tool/build/lib/divmul.h"
#include "libc/calls/struct/sigaction.h" #include "libc/calls/struct/sigaction.h"
#include "libc/macros.internal.h" #include "libc/macros.internal.h"
#include "libc/runtime/runtime.h" #include "libc/runtime/runtime.h"
@ -25,10 +26,10 @@
#include "libc/testlib/testlib.h" #include "libc/testlib/testlib.h"
#include "libc/x/xsigaction.h" #include "libc/x/xsigaction.h"
#include "third_party/xed/x86.h" #include "third_party/xed/x86.h"
#include "tool/build/lib/divmul.h"
#include "tool/build/lib/endian.h" #include "tool/build/lib/endian.h"
#include "tool/build/lib/flags.h" #include "tool/build/lib/flags.h"
#include "tool/build/lib/machine.h" #include "tool/build/lib/machine.h"
#ifdef __x86_64__
#define CX 1 #define CX 1
#define OSZ 00000000040 #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 TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "test/tool/build/lib/optest.h"
#include "libc/intrin/weaken.h" #include "libc/intrin/weaken.h"
#include "libc/macros.internal.h" #include "libc/macros.internal.h"
#include "libc/runtime/runtime.h" #include "libc/runtime/runtime.h"
#include "libc/stdio/stdio.h" #include "libc/stdio/stdio.h"
#include "test/tool/build/lib/numbers.h" #include "test/tool/build/lib/numbers.h"
#include "test/tool/build/lib/optest.h"
#include "tool/build/lib/flags.h" #include "tool/build/lib/flags.h"
#ifdef __x86_64__
const char kOpSuffix[] = {'b', 'w', 'l', 'q'}; 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); exit(1);
} }
} }
#endif /* __x86_64__ */

View file

@ -70,28 +70,20 @@ function UnixTest()
-- 1. fork off a process -- 1. fork off a process
-- 2. sandbox the process -- 2. sandbox the process
-- 3. then violate its security -- 3. then violate its security
if GetHostOs() == "LINUX" then if unix.pledge(nil, nil) then
reader, writer = assert(unix.pipe()) reader, writer = assert(unix.pipe())
if assert(unix.fork()) == 0 then if assert(unix.fork()) == 0 then
assert(unix.dup(writer, 2)) assert(unix.dup(writer, 2))
assert(unix.pledge("stdio")) assert(unix.pledge("stdio"))
unix.socket() unix.socket()
unix.exit(0) unix.exit(0)
end end
unix.close(writer) unix.close(writer)
unix.close(reader) unix.close(reader)
pid, ws = assert(unix.wait()) pid, ws = assert(unix.wait())
assert(unix.WIFSIGNALED(ws)) assert(unix.WIFSIGNALED(ws))
assert(unix.WTERMSIG(ws) == unix.SIGSYS) assert(unix.WTERMSIG(ws) == unix.SIGSYS or -- Linux
elseif GetHostOs() == "OPENBSD" then unix.WTERMSIG(ws) == unix.SIGABRT) -- OpenBSD
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)
end end
-- sigaction -- sigaction

View file

@ -39,6 +39,7 @@
#include "libc/testlib/testlib.h" #include "libc/testlib/testlib.h"
#include "libc/x/x.h" #include "libc/x/x.h"
#include "third_party/regex/regex.h" #include "third_party/regex/regex.h"
#ifdef __x86_64__
STATIC_YOINK("zip_uri_support"); STATIC_YOINK("zip_uri_support");
STATIC_YOINK("o/" MODE "/test/tool/net/redbean-tester.com"); STATIC_YOINK("o/" MODE "/test/tool/net/redbean-tester.com");
@ -285,3 +286,5 @@ Z\n",
EXPECT_NE(-1, wait(0)); EXPECT_NE(-1, wait(0));
EXPECT_NE(-1, sigprocmask(SIG_SETMASK, &savemask, 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)/test/tool/net/redbean-tester.com.dbg \
o/$(MODE)/third_party/zip/zip.com \ o/$(MODE)/third_party/zip/zip.com \
o/$(MODE)/tool/build/symtab.com \ o/$(MODE)/tool/build/symtab.com \
$(TOOL_NET_REDBEAN_STANDARD_ASSETS) $(TOOL_NET_REDBEAN_STANDARD_ASSETS) \
$(VM)
@$(MAKE_OBJCOPY) @$(MAKE_OBJCOPY)
@$(MAKE_SYMTAB_CREATE) @$(MAKE_SYMTAB_CREATE)
@$(MAKE_SYMTAB_ZIP) @$(MAKE_SYMTAB_ZIP)

View file

@ -1,6 +1,8 @@
#-*-mode:makefile-gmake;indent-tabs-mode:t;tab-width:8;coding:utf-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───────────────────────┘ #───vi: set et ft=make ts=8 tw=8 fenc=utf-8 :vi───────────────────────┘
ifeq ($(ARCH), x86_64)
PKGS += TEST_TOOL_PLINKO PKGS += TEST_TOOL_PLINKO
TEST_TOOL_PLINKO = $(TOOL_PLINKO_A_DEPS) $(TOOL_PLINKO_A) 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: \ o/$(MODE)/test/tool/plinko: \
$(TEST_TOOL_PLINKO_BINS) \ $(TEST_TOOL_PLINKO_BINS) \
$(TEST_TOOL_PLINKO_CHECKS) $(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) @$(APELINK)
o/$(MODE)/third_party/awk/README.zip.o: \ o/$(MODE)/third_party/awk/README.zip.o: \
ZIPOBJ_FLAGS = \ ZIPOBJ_FLAGS += \
-B -B
THIRD_PARTY_AWK_BINS = $(THIRD_PARTY_AWK_COMS) $(THIRD_PARTY_AWK_COMS:%=%.dbg) 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") || if (consume_attribute(&tok, tok, "noinline") ||
consume_attribute(&tok, tok, "const") || consume_attribute(&tok, tok, "const") ||
consume_attribute(&tok, tok, "pure") || 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, "may_alias") ||
consume_attribute(&tok, tok, "warn_unused_result") || consume_attribute(&tok, tok, "warn_unused_result") ||
consume_attribute(&tok, tok, "flatten") || consume_attribute(&tok, tok, "flatten") ||

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