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