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