finish intellisense support and sync with upstream

This commit is contained in:
Alexander Nicholi 2021-02-03 13:50:08 -05:00
commit ec9bfd8c56
No known key found for this signature in database
GPG key ID: B75B2EB05540F74C
221 changed files with 2360 additions and 1439 deletions

4
.vscode/vscode.h vendored
View file

@ -121,6 +121,7 @@ typedef struct { int ax, dx; } axdx_t;
#define _Vector_size(x) __attribute__(( vector_size( x ) )) #define _Vector_size(x) __attribute__(( vector_size( x ) ))
#define IMAGE_BASE_VIRTUAL 0x400000
#define __SIGACTION(...) (0) #define __SIGACTION(...) (0)
#define VEIL(x, y) (y) #define VEIL(x, y) (y)
#define STATIC_YOINK(x) #define STATIC_YOINK(x)
@ -133,9 +134,12 @@ typedef struct { int ax, dx; } axdx_t;
#define reverse(x, y) 0 #define reverse(x, y) 0
#define atomic_load(...) 0 #define atomic_load(...) 0
#define atomic_store(...) 0 #define atomic_store(...) 0
#define autotype(x) int
#define _Generic_(...) (void*)(0) #define _Generic_(...) (void*)(0)
#define _Generic(...) _Generic_ #define _Generic(...) _Generic_
#define _Alignas(...)
#define _Section(...)
#define offsetof(x, y) 0 #define offsetof(x, y) 0
#define cmpxchg(...) 0 #define cmpxchg(...) 0

View file

@ -82,17 +82,19 @@ o: o/$(MODE)/ape \
PKGS = PKGS =
-include ~/.cosmo.mk #──No.1 -include ~/.cosmo.mk
include build/functions.mk #─┐ include build/functions.mk #─┐
include build/definitions.mk # ├──meta include build/definitions.mk # ├──META
include build/config.mk # │ include build/config.mk # │ You can build
include build/rules.mk # │ include build/rules.mk # │ You can topologically order
include build/online.mk # │ include build/online.mk # │
include libc/stubs/stubs.mk #─┘ include libc/stubs/stubs.mk #─┘
include libc/nexgen32e/nexgen32e.mk #─┐ include libc/nexgen32e/nexgen32e.mk #─┐
include libc/intrin/intrin.mk # │ include libc/sysv/sysv.mk # ├──SYSTEM SUPPORT
include libc/linux/linux.mk # │ include libc/nt/nt.mk # │ You can do math
include libc/tinymath/tinymath.mk # ├──metal include libc/intrin/intrin.mk # │ You can use the stack
include libc/linux/linux.mk # │ You can manipulate arrays
include libc/tinymath/tinymath.mk # │ You can issue raw system calls
include third_party/compiler_rt/compiler_rt.mk # │ include third_party/compiler_rt/compiler_rt.mk # │
include libc/bits/bits.mk # │ include libc/bits/bits.mk # │
include libc/str/str.mk # │ include libc/str/str.mk # │
@ -100,23 +102,20 @@ include third_party/xed/xed.mk # │
include third_party/zlib/zlib.mk # │ include third_party/zlib/zlib.mk # │
include libc/elf/elf.mk # │ include libc/elf/elf.mk # │
include ape/lib/apelib.mk # │ include ape/lib/apelib.mk # │
include ape/ape.mk #─┘ include ape/ape.mk # │
include libc/sysv/sysv.mk #─┐ include libc/fmt/fmt.mk #─┘
include libc/nt/nt.mk # ├──system
include libc/fmt/fmt.mk # │
include libc/rand/rand.mk #─┘
include libc/calls/calls.mk #─┐ include libc/calls/calls.mk #─┐
include libc/runtime/runtime.mk # ├──systems include libc/runtime/runtime.mk # ├──SYSTEMS RUNTIME
include libc/crt/crt.mk # │ include libc/crt/crt.mk # │ You can issue system calls
include libc/rand/rand.mk # │
include libc/unicode/unicode.mk # │ include libc/unicode/unicode.mk # │
include third_party/dlmalloc/dlmalloc.mk # include third_party/dlmalloc/dlmalloc.mk #─┘
include libc/mem/mem.mk # include libc/mem/mem.mk #─┐
include libc/ohmyplus/ohmyplus.mk # include libc/ohmyplus/ohmyplus.mk # ├──DYNAMIC RUNTIME
include libc/zipos/zipos.mk # │ include libc/zipos/zipos.mk # │ You can now use stdio
include third_party/gdtoa/gdtoa.mk # │ include third_party/gdtoa/gdtoa.mk # │ You can finally call malloc()
include libc/time/time.mk # │ include libc/time/time.mk # │
include libc/alg/alg.mk # │ include libc/alg/alg.mk # │
include libc/calls/hefty/hefty.mk # │
include libc/stdio/stdio.mk # │ include libc/stdio/stdio.mk # │
include third_party/f2c/f2c.mk # │ include third_party/f2c/f2c.mk # │
include third_party/blas/blas.mk # │ include third_party/blas/blas.mk # │
@ -132,8 +131,8 @@ include third_party/musl/musl.mk # │
include third_party/getopt/getopt.mk # │ include third_party/getopt/getopt.mk # │
include libc/libc.mk #─┘ include libc/libc.mk #─┘
include libc/sock/sock.mk #─┐ include libc/sock/sock.mk #─┐
include dsp/tty/tty.mk # ├──online include dsp/tty/tty.mk # ├──ONLINE RUNTIME
include libc/dns/dns.mk # │ include libc/dns/dns.mk # │ You can communicate with the network
include libc/crypto/crypto.mk # │ include libc/crypto/crypto.mk # │
include net/http/http.mk #─┘ include net/http/http.mk #─┘
include third_party/lemon/lemon.mk include third_party/lemon/lemon.mk
@ -199,6 +198,7 @@ include test/test.mk
OBJS = $(foreach x,$(PKGS),$($(x)_OBJS)) OBJS = $(foreach x,$(PKGS),$($(x)_OBJS))
SRCS = $(foreach x,$(PKGS),$($(x)_SRCS)) SRCS = $(foreach x,$(PKGS),$($(x)_SRCS))
HDRS = $(foreach x,$(PKGS),$($(x)_HDRS)) HDRS = $(foreach x,$(PKGS),$($(x)_HDRS))
INCS = $(foreach x,$(PKGS),$($(x)_INCS))
BINS = $(foreach x,$(PKGS),$($(x)_BINS)) BINS = $(foreach x,$(PKGS),$($(x)_BINS))
TESTS = $(foreach x,$(PKGS),$($(x)_TESTS)) TESTS = $(foreach x,$(PKGS),$($(x)_TESTS))
CHECKS = $(foreach x,$(PKGS),$($(x)_CHECKS)) CHECKS = $(foreach x,$(PKGS),$($(x)_CHECKS))
@ -215,10 +215,10 @@ o/$(MODE)/.x:
o/$(MODE)/srcs.txt: o/$(MODE)/.x $(MAKEFILES) $(call uniq,$(foreach x,$(SRCS),$(dir $(x)))) o/$(MODE)/srcs.txt: o/$(MODE)/.x $(MAKEFILES) $(call uniq,$(foreach x,$(SRCS),$(dir $(x))))
$(file >$@) $(foreach x,$(SRCS),$(file >>$@,$(x))) $(file >$@) $(foreach x,$(SRCS),$(file >>$@,$(x)))
o/$(MODE)/hdrs.txt: o/$(MODE)/.x $(MAKEFILES) $(call uniq,$(foreach x,$(HDRS),$(dir $(x)))) o/$(MODE)/hdrs.txt: o/$(MODE)/.x $(MAKEFILES) $(call uniq,$(foreach x,$(HDRS) $(INCS),$(dir $(x))))
$(file >$@) $(foreach x,$(HDRS),$(file >>$@,$(x))) $(file >$@) $(foreach x,$(HDRS) $(INCS),$(file >>$@,$(x)))
o/$(MODE)/depend: o/$(MODE)/.x o/$(MODE)/srcs.txt o/$(MODE)/hdrs.txt $(SRCS) $(HDRS) o/$(MODE)/depend: o/$(MODE)/.x o/$(MODE)/srcs.txt o/$(MODE)/hdrs.txt $(SRCS) $(HDRS) $(INCS)
@build/mkdeps -o $@ -r o/$(MODE)/ o/$(MODE)/srcs.txt o/$(MODE)/hdrs.txt @build/mkdeps -o $@ -r o/$(MODE)/ o/$(MODE)/srcs.txt o/$(MODE)/hdrs.txt
TAGS: o/$(MODE)/srcs.txt $(SRCS) TAGS: o/$(MODE)/srcs.txt $(SRCS)
@ -251,7 +251,6 @@ COSMOPOLITAN_OBJECTS = \
APE_LIB \ APE_LIB \
THIRD_PARTY_MUSL \ THIRD_PARTY_MUSL \
LIBC_STDIO \ LIBC_STDIO \
LIBC_CALLS_HEFTY \
THIRD_PARTY_REGEX \ THIRD_PARTY_REGEX \
LIBC_ALG \ LIBC_ALG \
LIBC_MEM \ LIBC_MEM \
@ -351,6 +350,7 @@ o/cosmopolitan.html: \
~/.cosmo.mk: ~/.cosmo.mk:
$(SRCS): $(SRCS):
$(HDRS): $(HDRS):
$(INCS):
.DEFAULT: .DEFAULT:
@echo >&2 @echo >&2
@echo NOTE: deleting o/$(MODE)/depend because of an unspecified prerequisite: $@ >&2 @echo NOTE: deleting o/$(MODE)/depend because of an unspecified prerequisite: $@ >&2

View file

@ -282,6 +282,9 @@ SECTIONS {
KEEP(*(.textwindowsepilogue)) KEEP(*(.textwindowsepilogue))
*(SORT_BY_ALIGNMENT(.text.modernity)) *(SORT_BY_ALIGNMENT(.text.modernity))
*(SORT_BY_ALIGNMENT(.text.modernity.*)) *(SORT_BY_ALIGNMENT(.text.modernity.*))
HIDDEN(__text_syscall_start = .);
*(.text.syscall .text.syscall.*)
HIDDEN(__text_syscall_end = .);
*(SORT_BY_ALIGNMENT(.text.hot)) *(SORT_BY_ALIGNMENT(.text.hot))
*(SORT_BY_ALIGNMENT(.text.hot.*)) *(SORT_BY_ALIGNMENT(.text.hot.*))
KEEP(*(.keep.text)) KEEP(*(.keep.text))
@ -483,6 +486,10 @@ SHSTUB2(.Lape.macho.dd.skip, RVA(ape.macho) / 8);
SHSTUB2(.Lape.macho.dd.count, (.Lape.macho.end - ape.macho) / 8); SHSTUB2(.Lape.macho.dd.count, (.Lape.macho.end - ape.macho) / 8);
PFSTUB4(.Lape.pe.offset, ape.pe - ape.mz); PFSTUB4(.Lape.pe.offset, ape.pe - ape.mz);
HIDDEN(__text_syscall_addr = ROUNDDOWN(__text_syscall_start, PAGESIZE));
HIDDEN(__text_syscall_size = (ROUNDUP(__text_syscall_end, PAGESIZE) -
ROUNDDOWN(__text_syscall_start, PAGESIZE)));
HIDDEN(.Lape.pe.optsz = .Lape.pe.sections - (ape.pe + 24)); HIDDEN(.Lape.pe.optsz = .Lape.pe.sections - (ape.pe + 24));
HIDDEN(.Lape.pe.shnum = (.Lape.pe.sections_end - .Lape.pe.sections) / 40); HIDDEN(.Lape.pe.shnum = (.Lape.pe.sections_end - .Lape.pe.sections) / 40);
HIDDEN(.Lidata.idtsize = idata.idtend - idata.idt); HIDDEN(.Lidata.idtsize = idata.idtend - idata.idt);

View file

@ -33,6 +33,7 @@ APELINK = \
APE_FILES := $(wildcard ape/*.*) APE_FILES := $(wildcard ape/*.*)
APE_HDRS = $(filter %.h,$(APE_FILES)) APE_HDRS = $(filter %.h,$(APE_FILES))
APE_INCS = $(filter %.inc,$(APE_FILES))
APE_SRCS = $(filter %.S,$(APE_FILES)) APE_SRCS = $(filter %.S,$(APE_FILES))
APE_OBJS = $(APE_SRCS:%.S=o/$(MODE)/%.o) APE_OBJS = $(APE_SRCS:%.S=o/$(MODE)/%.o)
APE_DEPS = $(APE_LIB) APE_DEPS = $(APE_LIB)

View file

@ -37,6 +37,8 @@ export LC_ALL=C
MKDIR=${MKDIR:-$(command -v mkdir) -p} || exit MKDIR=${MKDIR:-$(command -v mkdir) -p} || exit
GZME= GZME=
ASAN=
UBSAN=
PLAT="${1%% *}" PLAT="${1%% *}"
FDIAGNOSTIC_COLOR= FDIAGNOSTIC_COLOR=
CCNAME=${CCNAME:-gcc} CCNAME=${CCNAME:-gcc}
@ -87,11 +89,21 @@ for x; do
set -- "$@" "$x" -Wa,-msse2avx -D__MNO_VZEROUPPER__ set -- "$@" "$x" -Wa,-msse2avx -D__MNO_VZEROUPPER__
;; ;;
-fsanitize=address) -fsanitize=address)
set -- "$@" "$x" -D__FSANITIZE_ADDRESS__ ASAN="$x -D__FSANITIZE_ADDRESS__"
;; ;;
-fsanitize=undefined) -fsanitize=undefined)
set -- "$@" "$x" -D__FSANITIZE_UNDEFINED__ # UBSAN w/ -fdata-sections exceeds ELF's 65,280 section limit
COUNTERMAND="$COUNTERMAND -fno-data-sections" # sqlite.o UBSAN="$x -fno-data-sections"
;;
-fno-sanitize=address)
ASAN=
;;
-fno-sanitize=ubsan)
UBSAN=
;;
-fno-sanitize=all)
ASAN=
UBSAN=
;; ;;
-mnop-mcount) -mnop-mcount)
if [ "$CCNAME" = "gcc" ] && [ "$CCVERSION" -ge 6 ]; then if [ "$CCNAME" = "gcc" ] && [ "$CCVERSION" -ge 6 ]; then
@ -256,7 +268,7 @@ else
done done
fi fi
set -- "$@" -no-canonical-prefixes $FDIAGNOSTIC_COLOR $COUNTERMAND set -- "$@" -no-canonical-prefixes $FDIAGNOSTIC_COLOR $ASAN $UBSAN $COUNTERMAND
if [ "$SILENT" = "0" ]; then if [ "$SILENT" = "0" ]; then
printf "%s\n" "$*" >&2 printf "%s\n" "$*" >&2

View file

@ -94,8 +94,7 @@ CONFIG_CPPFLAGS += \
CONFIG_CCFLAGS += \ CONFIG_CCFLAGS += \
$(BACKTRACES) \ $(BACKTRACES) \
$(FTRACE) \ $(FTRACE) \
-O1 \ -O2
-fno-inline
CONFIG_COPTS += \ CONFIG_COPTS += \
$(SECURITY_BLANKETS) \ $(SECURITY_BLANKETS) \

View file

@ -2,16 +2,16 @@
#-*-mode:sh;indent-tabs-mode:nil;tab-width:2;coding:utf-8-*-┐ #-*-mode:sh;indent-tabs-mode:nil;tab-width:2;coding:utf-8-*-┐
#───vi: set net ft=sh ts=2 sts=2 fenc=utf-8 :vi─────────────┘ #───vi: set net ft=sh ts=2 sts=2 fenc=utf-8 :vi─────────────┘
#if [ -x "o/$MODE/tool/build/mkdeps.com" ]; then if [ -x "o/$MODE/tool/build/mkdeps.com" ]; then
# set -- "o/$MODE/tool/build/mkdeps.com" "$@" set -- "o/$MODE/tool/build/mkdeps.com" "$@"
#else else
if [ ! -x o/build/bootstrap/mkdeps.com ]; then if [ ! -x o/build/bootstrap/mkdeps.com ]; then
mkdir -p o/build/bootstrap && mkdir -p o/build/bootstrap &&
cp -a build/bootstrap/mkdeps.com \ cp -a build/bootstrap/mkdeps.com \
o/build/bootstrap/mkdeps.com || exit o/build/bootstrap/mkdeps.com || exit
fi fi
set -- o/build/bootstrap/mkdeps.com "$@" set -- o/build/bootstrap/mkdeps.com "$@"
#fi fi
if [ "$SILENT" = "0" ]; then if [ "$SILENT" = "0" ]; then
printf "%s\n" "$*" >&2 printf "%s\n" "$*" >&2

View file

@ -24,9 +24,10 @@ DSP_CORE_A_CHECKS = \
$(DSP_CORE_A_HDRS:%=o/$(MODE)/%.ok) $(DSP_CORE_A_HDRS:%=o/$(MODE)/%.ok)
DSP_CORE_A_DIRECTDEPS = \ DSP_CORE_A_DIRECTDEPS = \
LIBC_NEXGEN32E \
LIBC_MEM \
LIBC_INTRIN \ LIBC_INTRIN \
LIBC_MEM \
LIBC_NEXGEN32E \
LIBC_STR \
LIBC_TINYMATH \ LIBC_TINYMATH \
LIBC_STUBS LIBC_STUBS

View file

@ -30,6 +30,7 @@ DSP_SCALE_A_DIRECTDEPS = \
LIBC_MEM \ LIBC_MEM \
LIBC_NEXGEN32E \ LIBC_NEXGEN32E \
LIBC_RUNTIME \ LIBC_RUNTIME \
LIBC_STR \
LIBC_STUBS \ LIBC_STUBS \
LIBC_STUBS \ LIBC_STUBS \
LIBC_TIME \ LIBC_TIME \

View file

@ -8,7 +8,7 @@
*/ */
#endif #endif
#include "libc/calls/calls.h" #include "libc/calls/calls.h"
#include "libc/calls/hefty/copyfile.h" #include "libc/calls/copyfile.h"
#include "libc/errno.h" #include "libc/errno.h"
#include "libc/fmt/conv.h" #include "libc/fmt/conv.h"
#include "libc/fmt/fmt.h" #include "libc/fmt/fmt.h"

View file

@ -44,7 +44,6 @@ EXAMPLES_DIRECTDEPS = \
LIBC_ALG \ LIBC_ALG \
LIBC_BITS \ LIBC_BITS \
LIBC_CALLS \ LIBC_CALLS \
LIBC_CALLS_HEFTY \
LIBC_FMT \ LIBC_FMT \
LIBC_INTRIN \ LIBC_INTRIN \
LIBC_LOG \ LIBC_LOG \

View file

@ -154,7 +154,6 @@ static bool resized_;
static size_t vtsize_; static size_t vtsize_;
static bool artifacts_; static bool artifacts_;
static long tyn_, txn_; static long tyn_, txn_;
static const char* ffplay_;
static struct Frame vf_[2]; static struct Frame vf_[2];
static struct Audio audio_; static struct Audio audio_;
static const char* inputfn_; static const char* inputfn_;
@ -1685,6 +1684,7 @@ int PlayGame(const char* romfile, const char* opt_tasfile) {
FILE* fp; FILE* fp;
int devnull; int devnull;
int pipefds[2]; int pipefds[2];
const char* ffplay;
inputfn_ = opt_tasfile; inputfn_ = opt_tasfile;
if (!(fp = fopen(romfile, "rb"))) { if (!(fp = fopen(romfile, "rb"))) {
@ -1701,7 +1701,7 @@ int PlayGame(const char* romfile, const char* opt_tasfile) {
// open speaker // open speaker
// todo: this needs plenty of work // todo: this needs plenty of work
if ((ffplay_ = commandvenv("FFPLAY", "ffplay"))) { if ((ffplay = commandvenv("FFPLAY", "ffplay"))) {
devnull = open("/dev/null", O_WRONLY | O_CLOEXEC); devnull = open("/dev/null", O_WRONLY | O_CLOEXEC);
pipe2(pipefds, O_CLOEXEC); pipe2(pipefds, O_CLOEXEC);
if (!(playpid_ = vfork())) { if (!(playpid_ = vfork())) {
@ -1713,7 +1713,7 @@ int PlayGame(const char* romfile, const char* opt_tasfile) {
dup2(pipefds[0], 0); dup2(pipefds[0], 0);
dup2(devnull, 1); dup2(devnull, 1);
dup2(devnull, 2); dup2(devnull, 2);
execv(ffplay_, (char* const*)args); execv(ffplay, (char* const*)args);
abort(); abort();
} }
close(pipefds[0]); close(pipefds[0]);

View file

@ -17,6 +17,7 @@
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "libc/macros.h" #include "libc/macros.h"
.text.syscall
/ Tiny Raw Linux Binary Tutorial / Tiny Raw Linux Binary Tutorial
/ /

View file

@ -8,6 +8,7 @@ LIBC_ALG = $(LIBC_ALG_A_DEPS) $(LIBC_ALG_A)
LIBC_ALG_A = o/$(MODE)/libc/alg/alg.a LIBC_ALG_A = o/$(MODE)/libc/alg/alg.a
LIBC_ALG_A_FILES := $(wildcard libc/alg/*) LIBC_ALG_A_FILES := $(wildcard libc/alg/*)
LIBC_ALG_A_HDRS = $(filter %.h,$(LIBC_ALG_A_FILES)) LIBC_ALG_A_HDRS = $(filter %.h,$(LIBC_ALG_A_FILES))
LIBC_ALG_A_INCS = $(filter %.inc,$(LIBC_ALG_A_FILES))
LIBC_ALG_A_SRCS_S = $(filter %.S,$(LIBC_ALG_A_FILES)) LIBC_ALG_A_SRCS_S = $(filter %.S,$(LIBC_ALG_A_FILES))
LIBC_ALG_A_SRCS_C = $(filter %.c,$(LIBC_ALG_A_FILES)) LIBC_ALG_A_SRCS_C = $(filter %.c,$(LIBC_ALG_A_FILES))
@ -51,6 +52,7 @@ o/$(MODE)/libc/alg/critbit0.o: \
LIBC_ALG_LIBS = $(foreach x,$(LIBC_ALG_ARTIFACTS),$($(x))) LIBC_ALG_LIBS = $(foreach x,$(LIBC_ALG_ARTIFACTS),$($(x)))
LIBC_ALG_SRCS = $(foreach x,$(LIBC_ALG_ARTIFACTS),$($(x)_SRCS)) LIBC_ALG_SRCS = $(foreach x,$(LIBC_ALG_ARTIFACTS),$($(x)_SRCS))
LIBC_ALG_HDRS = $(foreach x,$(LIBC_ALG_ARTIFACTS),$($(x)_HDRS)) LIBC_ALG_HDRS = $(foreach x,$(LIBC_ALG_ARTIFACTS),$($(x)_HDRS))
LIBC_ALG_INCS = $(foreach x,$(LIBC_ALG_ARTIFACTS),$($(x)_INCS))
LIBC_ALG_CHECKS = $(foreach x,$(LIBC_ALG_ARTIFACTS),$($(x)_CHECKS)) LIBC_ALG_CHECKS = $(foreach x,$(LIBC_ALG_ARTIFACTS),$($(x)_CHECKS))
LIBC_ALG_OBJS = $(foreach x,$(LIBC_ALG_ARTIFACTS),$($(x)_OBJS)) LIBC_ALG_OBJS = $(foreach x,$(LIBC_ALG_ARTIFACTS),$($(x)_OBJS))
$(LIBC_ALG_OBJS): $(BUILD_FILES) libc/alg/alg.mk $(LIBC_ALG_OBJS): $(BUILD_FILES) libc/alg/alg.mk

View file

@ -21,6 +21,7 @@ LIBC_CALLS_A_FILES := \
$(wildcard libc/calls/struct/*) \ $(wildcard libc/calls/struct/*) \
$(wildcard libc/calls/*) $(wildcard libc/calls/*)
LIBC_CALLS_A_HDRS = $(filter %.h,$(LIBC_CALLS_A_FILES)) LIBC_CALLS_A_HDRS = $(filter %.h,$(LIBC_CALLS_A_FILES))
LIBC_CALLS_A_INCS = $(filter %.inc,$(LIBC_CALLS_A_FILES))
LIBC_CALLS_A_SRCS_S = $(filter %.S,$(LIBC_CALLS_A_FILES)) LIBC_CALLS_A_SRCS_S = $(filter %.S,$(LIBC_CALLS_A_FILES))
LIBC_CALLS_A_SRCS_C = $(filter %.c,$(LIBC_CALLS_A_FILES)) LIBC_CALLS_A_SRCS_C = $(filter %.c,$(LIBC_CALLS_A_FILES))
@ -43,7 +44,6 @@ LIBC_CALLS_A_DIRECTDEPS = \
LIBC_NT_ADVAPI32 \ LIBC_NT_ADVAPI32 \
LIBC_NT_KERNEL32 \ LIBC_NT_KERNEL32 \
LIBC_NT_NTDLL \ LIBC_NT_NTDLL \
LIBC_RAND \
LIBC_STR \ LIBC_STR \
LIBC_STUBS \ LIBC_STUBS \
LIBC_SYSV_CALLS \ LIBC_SYSV_CALLS \
@ -86,12 +86,11 @@ o/$(MODE)/libc/calls/mkntenvblock.o: \
LIBC_CALLS_LIBS = $(foreach x,$(LIBC_CALLS_ARTIFACTS),$($(x))) LIBC_CALLS_LIBS = $(foreach x,$(LIBC_CALLS_ARTIFACTS),$($(x)))
LIBC_CALLS_SRCS = $(foreach x,$(LIBC_CALLS_ARTIFACTS),$($(x)_SRCS)) LIBC_CALLS_SRCS = $(foreach x,$(LIBC_CALLS_ARTIFACTS),$($(x)_SRCS))
LIBC_CALLS_HDRS = $(foreach x,$(LIBC_CALLS_ARTIFACTS),$($(x)_HDRS)) LIBC_CALLS_HDRS = $(foreach x,$(LIBC_CALLS_ARTIFACTS),$($(x)_HDRS))
LIBC_CALLS_INCS = $(foreach x,$(LIBC_CALLS_ARTIFACTS),$($(x)_INCS))
LIBC_CALLS_BINS = $(foreach x,$(LIBC_CALLS_ARTIFACTS),$($(x)_BINS)) LIBC_CALLS_BINS = $(foreach x,$(LIBC_CALLS_ARTIFACTS),$($(x)_BINS))
LIBC_CALLS_CHECKS = $(foreach x,$(LIBC_CALLS_ARTIFACTS),$($(x)_CHECKS)) LIBC_CALLS_CHECKS = $(foreach x,$(LIBC_CALLS_ARTIFACTS),$($(x)_CHECKS))
LIBC_CALLS_OBJS = $(foreach x,$(LIBC_CALLS_ARTIFACTS),$($(x)_OBJS)) LIBC_CALLS_OBJS = $(foreach x,$(LIBC_CALLS_ARTIFACTS),$($(x)_OBJS))
LIBC_CALLS_TESTS = $(foreach x,$(LIBC_CALLS_ARTIFACTS),$($(x)_TESTS)) LIBC_CALLS_TESTS = $(foreach x,$(LIBC_CALLS_ARTIFACTS),$($(x)_TESTS))
.PHONY: o/$(MODE)/libc/calls .PHONY: o/$(MODE)/libc/calls
o/$(MODE)/libc/calls: \ o/$(MODE)/libc/calls: $(LIBC_CALLS_CHECKS)
o/$(MODE)/libc/calls/hefty \
$(LIBC_CALLS_CHECKS)

View file

@ -42,7 +42,6 @@
* @errors ENOENT, ENOTDIR, ENOSYS * @errors ENOENT, ENOTDIR, ENOSYS
* @asyncsignalsafe * @asyncsignalsafe
* @see fchmod() * @see fchmod()
* @syscall
*/ */
int chmod(const char *pathname, uint32_t mode) { int chmod(const char *pathname, uint32_t mode) {
if (!pathname) return efault(); if (!pathname) return efault();

View file

@ -50,7 +50,6 @@
* errno isn't restored to its original value, to detect prec. loss * errno isn't restored to its original value, to detect prec. loss
* @see strftime(), gettimeofday() * @see strftime(), gettimeofday()
* @asyncsignalsafe * @asyncsignalsafe
* @syscall
*/ */
int clock_gettime(int clockid, struct timespec *out_ts) { int clock_gettime(int clockid, struct timespec *out_ts) {
/* TODO(jart): Just ignore O/S for MONOTONIC and measure RDTSC on start */ /* TODO(jart): Just ignore O/S for MONOTONIC and measure RDTSC on start */

View file

@ -17,13 +17,15 @@
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "libc/calls/internal.h" #include "libc/calls/internal.h"
#include "libc/nt/enum/filetype.h"
#include "libc/nt/files.h" #include "libc/nt/files.h"
#include "libc/nt/runtime.h" #include "libc/nt/runtime.h"
#include "libc/sysv/errfuns.h" #include "libc/sysv/errfuns.h"
textwindows int close$nt(int fd) { textwindows int close$nt(int fd) {
bool32 ok; bool32 ok;
if (g_fds.p[fd].kind == kFdFile) { if (g_fds.p[fd].kind == kFdFile &&
GetFileType(g_fds.p[fd].handle) == kNtFileTypeDisk) {
/* /*
* Like Linux, closing a file on Windows doesn't guarantee it's * Like Linux, closing a file on Windows doesn't guarantee it's
* immediately synced to disk. But unlike Linux, this could cause * immediately synced to disk. But unlike Linux, this could cause
@ -32,6 +34,8 @@ textwindows int close$nt(int fd) {
FlushFileBuffers(g_fds.p[fd].handle); FlushFileBuffers(g_fds.p[fd].handle);
} }
ok = CloseHandle(g_fds.p[fd].handle); ok = CloseHandle(g_fds.p[fd].handle);
if (g_fds.p[fd].kind == kFdConsole) ok &= CloseHandle(g_fds.p[fd].extra); if (g_fds.p[fd].kind == kFdConsole) {
ok &= CloseHandle(g_fds.p[fd].extra);
}
return ok ? 0 : __winerr(); return ok ? 0 : __winerr();
} }

View file

@ -53,8 +53,7 @@ int close(int fd) {
rc = ebadf(); rc = ebadf();
} }
if (!__vforked && fd < g_fds.n) { if (!__vforked && fd < g_fds.n) {
g_fds.p[fd].kind = kFdEmpty; __releasefd(fd);
g_fds.f = MIN(g_fds.f, fd);
} }
return rc; return rc;
} }

View file

@ -16,7 +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/hefty/copyfile.h" #include "libc/calls/copyfile.h"
#include "libc/calls/internal.h" #include "libc/calls/internal.h"
#include "libc/calls/struct/stat.h" #include "libc/calls/struct/stat.h"
#include "libc/dce.h" #include "libc/dce.h"

View file

@ -1,5 +1,5 @@
#ifndef COSMOPOLITAN_LIBC_CALLS_HEFTY_COPYFILE_H_ #ifndef COSMOPOLITAN_LIBC_CALLS_COPYFILE_H_
#define COSMOPOLITAN_LIBC_CALLS_HEFTY_COPYFILE_H_ #define COSMOPOLITAN_LIBC_CALLS_COPYFILE_H_
#define COPYFILE_NOCLOBBER 1 #define COPYFILE_NOCLOBBER 1
#define COPYFILE_PRESERVE_OWNER 2 #define COPYFILE_PRESERVE_OWNER 2
@ -12,4 +12,4 @@ int copyfile(const char *, const char *, int) paramsnonnull();
COSMOPOLITAN_C_END_ COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_CALLS_HEFTY_COPYFILE_H_ */ #endif /* COSMOPOLITAN_LIBC_CALLS_COPYFILE_H_ */

View file

@ -30,17 +30,18 @@
*/ */
textwindows int dup$nt(int oldfd, int newfd, int flags) { textwindows int dup$nt(int oldfd, int newfd, int flags) {
int64_t proc; int64_t proc;
if (!__isfdkind(oldfd, kFdFile)) return ebadf(); if (oldfd < 0) return einval();
if (oldfd >= g_fds.n ||
(g_fds.p[oldfd].kind != kFdFile && g_fds.p[oldfd].kind != kFdSocket &&
g_fds.p[oldfd].kind != kFdConsole)) {
return ebadf();
}
if (newfd == -1) { if (newfd == -1) {
if ((newfd = __getemptyfd()) == -1) { if ((newfd = __reservefd()) == -1) return -1;
return -1;
}
} else if (__ensurefds(newfd) != -1) {
if (g_fds.p[newfd].kind != kFdEmpty) {
close(newfd);
}
} else { } else {
return -1; if (__ensurefds(newfd) == -1) return -1;
if (g_fds.p[newfd].kind) close(newfd);
g_fds.p[newfd].kind = kFdReserved;
} }
proc = GetCurrentProcess(); proc = GetCurrentProcess();
if (DuplicateHandle(proc, g_fds.p[oldfd].handle, proc, &g_fds.p[newfd].handle, if (DuplicateHandle(proc, g_fds.p[oldfd].handle, proc, &g_fds.p[newfd].handle,
@ -49,6 +50,7 @@ textwindows int dup$nt(int oldfd, int newfd, int flags) {
g_fds.p[newfd].flags = flags; g_fds.p[newfd].flags = flags;
return newfd; return newfd;
} else { } else {
__releasefd(newfd);
return __winerr(); return __winerr();
} }
} }

View file

@ -25,13 +25,14 @@ int32_t dup3$sysv(int32_t oldfd, int32_t newfd, int flags) {
static bool once, demodernize; static bool once, demodernize;
int olderr, fd; int olderr, fd;
if (!once) { if (!once) {
once = true;
olderr = errno; olderr = errno;
fd = __dup3$sysv(oldfd, newfd, flags); fd = __dup3$sysv(oldfd, newfd, flags);
if ((fd == -1 && errno == ENOSYS) || fd == __NR_dup3_linux) { if ((fd == -1 && errno == ENOSYS) || fd == __NR_dup3_linux) {
demodernize = true; demodernize = true;
once = true;
errno = olderr; errno = olderr;
} else { } else {
once = true;
return fd; return fd;
} }
} else if (!demodernize) { } else if (!demodernize) {

View file

@ -17,6 +17,7 @@
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "libc/assert.h" #include "libc/assert.h"
#include "libc/bits/bits.h"
#include "libc/bits/weaken.h" #include "libc/bits/weaken.h"
#include "libc/calls/internal.h" #include "libc/calls/internal.h"
#include "libc/mem/mem.h" #include "libc/mem/mem.h"
@ -24,24 +25,29 @@
#include "libc/sysv/errfuns.h" #include "libc/sysv/errfuns.h"
int __ensurefds(int fd) { int __ensurefds(int fd) {
size_t n; size_t n1, n2;
struct Fd *p; struct Fd *p1, *p2;
if (fd < g_fds.n) return fd; for (;;) {
if (weaken(malloc)) { p1 = g_fds.p;
n = MAX(fd + 1, g_fds.n + (g_fds.n << 1)); n1 = g_fds.n;
if ((p = weaken(malloc)(n * sizeof(*p)))) { if (fd < n1) return fd;
memcpy(p, g_fds.p, g_fds.n * sizeof(*p)); if (weaken(malloc)) {
memset(p + g_fds.n, 0, (n - g_fds.n) * sizeof(*p)); n2 = MAX(fd + 1, n1 + (n1 << 1));
if (g_fds.p != g_fds.__init_p && weaken(free)) { if ((p2 = weaken(malloc)(n2 * sizeof(*p1)))) {
weaken(free)(g_fds.p); memcpy(p2, p1, n1 * sizeof(*p1));
memset(p2 + n1, 0, (n2 - n1) * sizeof(*p1));
if (p1 != g_fds.__init_p && weaken(free)) weaken(free)(p1);
if (cmpxchg(&g_fds.p, p1, p2)) {
g_fds.n = n2;
return fd;
} else if (weaken(free)) {
weaken(free)(p2);
}
} else {
return enomem();
} }
g_fds.p = p;
g_fds.n = n;
return fd;
} else { } else {
return enomem(); return emfile();
} }
} else {
return emfile();
} }
} }

View file

@ -47,7 +47,7 @@ textwindows int execve$nt(const char *program, char *const argv[],
close(i); close(i);
} }
} }
rc = ntspawn(program, argv, envp, NULL, NULL, true, 0, NULL, &startinfo, rc = ntspawn(program, argv, envp, NULL, NULL, NULL, true, 0, NULL, &startinfo,
&procinfo); &procinfo);
if (rc == -1) return -1; if (rc == -1) return -1;
CloseHandle(procinfo.hThread); CloseHandle(procinfo.hThread);

View file

@ -29,7 +29,6 @@
* @param len 0 means til end of file * @param len 0 means til end of file
* @param advice can be MADV_SEQUENTIAL, MADV_RANDOM, etc. * @param advice can be MADV_SEQUENTIAL, MADV_RANDOM, etc.
* @return -1 on error * @return -1 on error
* @syscall
*/ */
int fadvise(int fd, uint64_t offset, uint64_t len, int advice) { int fadvise(int fd, uint64_t offset, uint64_t len, int advice) {
if (!IsWindows()) { if (!IsWindows()) {

View file

@ -38,7 +38,6 @@
* @return 0 on success, or -1 w/ errno * @return 0 on success, or -1 w/ errno
* @note limited availability on rhel5 and openbsd * @note limited availability on rhel5 and openbsd
* @see ftruncate() * @see ftruncate()
* @syscall
*/ */
int fallocate(int fd, int32_t mode, int64_t offset, int64_t length) { int fallocate(int fd, int32_t mode, int64_t offset, int64_t length) {
int rc; int rc;

View file

@ -40,7 +40,6 @@
* @errors ENOSYS * @errors ENOSYS
* @asyncsignalsafe * @asyncsignalsafe
* @see chmod() * @see chmod()
* @syscall
*/ */
int fchmod(int fd, uint32_t mode) { int fchmod(int fd, uint32_t mode) {
/* TODO(jart): Windows */ /* TODO(jart): Windows */

View file

@ -28,7 +28,6 @@
* @return 0 on success, or -1 w/ errno * @return 0 on success, or -1 w/ errno
* @see /etc/passwd for user ids * @see /etc/passwd for user ids
* @see /etc/group for group ids * @see /etc/group for group ids
* @syscall
*/ */
int fchown(int fd, uint32_t uid, uint32_t gid) { int fchown(int fd, uint32_t uid, uint32_t gid) {
/* TODO(jart): Windows? */ /* TODO(jart): Windows? */

View file

@ -29,7 +29,6 @@
* @param arg can be FD_CLOEXEC, etc. depending * @param arg can be FD_CLOEXEC, etc. depending
* @return 0 on success, or -1 w/ errno * @return 0 on success, or -1 w/ errno
* @asyncsignalsafe * @asyncsignalsafe
* @syscall
*/ */
int fcntl(int fd, int cmd, ...) { int fcntl(int fd, int cmd, ...) {
va_list va; va_list va;

View file

@ -26,7 +26,6 @@
* @return 0 on success, or -1 w/ errno * @return 0 on success, or -1 w/ errno
* @see fsync(), sync_file_range() * @see fsync(), sync_file_range()
* @asyncsignalsafe * @asyncsignalsafe
* @syscall
*/ */
int fdatasync(int fd) { int fdatasync(int fd) {
if (!IsWindows()) { if (!IsWindows()) {

View file

@ -16,10 +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/bits/bits.h"
#include "libc/bits/safemacros.h"
#include "libc/runtime/runtime.h" #include "libc/runtime/runtime.h"
#include "libc/str/str.h"
/** /**
* Returns value of environment variable, or NULL if not found. * Returns value of environment variable, or NULL if not found.

View file

@ -1,72 +0,0 @@
#-*-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───────────────────────┘
#
# SYNOPSIS
#
# Cosmopolitan System Call Compatibility Layer
#
# DESCRIPTION
#
# This subpackage exports functions traditionally understood as system
# calls that Cosmopolitan needs to wrap in a nontrivial way, requiring
# things like dynamic memory allocation.
PKGS += LIBC_CALLS_HEFTY
LIBC_CALLS_HEFTY_ARTIFACTS += LIBC_CALLS_HEFTY_A
LIBC_CALLS_HEFTY = $(LIBC_CALLS_HEFTY_A_DEPS) $(LIBC_CALLS_HEFTY_A)
LIBC_CALLS_HEFTY_A = o/$(MODE)/libc/calls/hefty/hefty.a
LIBC_CALLS_HEFTY_A_FILES := $(wildcard libc/calls/hefty/*)
LIBC_CALLS_HEFTY_A_HDRS = $(filter %.h,$(LIBC_CALLS_HEFTY_A_FILES))
LIBC_CALLS_HEFTY_A_SRCS_S = $(filter %.S,$(LIBC_CALLS_HEFTY_A_FILES))
LIBC_CALLS_HEFTY_A_SRCS_C = $(filter %.c,$(LIBC_CALLS_HEFTY_A_FILES))
LIBC_CALLS_HEFTY_A_SRCS = \
$(LIBC_CALLS_HEFTY_A_SRCS_S) \
$(LIBC_CALLS_HEFTY_A_SRCS_C)
LIBC_CALLS_HEFTY_A_OBJS = \
$(LIBC_CALLS_HEFTY_A_SRCS_S:%.S=o/$(MODE)/%.o) \
$(LIBC_CALLS_HEFTY_A_SRCS_C:%.c=o/$(MODE)/%.o)
LIBC_CALLS_HEFTY_A_CHECKS = \
$(LIBC_CALLS_HEFTY_A).pkg \
$(LIBC_CALLS_HEFTY_A_HDRS:%=o/$(MODE)/%.ok)
LIBC_CALLS_HEFTY_A_DIRECTDEPS = \
LIBC_ALG \
LIBC_CALLS \
LIBC_FMT \
LIBC_INTRIN \
LIBC_MEM \
LIBC_NEXGEN32E \
LIBC_NT_KERNEL32 \
LIBC_RUNTIME \
LIBC_STR \
LIBC_STUBS \
LIBC_SYSV \
LIBC_SYSV_CALLS
LIBC_CALLS_HEFTY_A_DEPS := \
$(call uniq,$(foreach x,$(LIBC_CALLS_HEFTY_A_DIRECTDEPS),$($(x))))
$(LIBC_CALLS_HEFTY_A): \
libc/calls/hefty/ \
$(LIBC_CALLS_HEFTY_A).pkg \
$(LIBC_CALLS_HEFTY_A_OBJS)
$(LIBC_CALLS_HEFTY_A).pkg: \
$(LIBC_CALLS_HEFTY_A_OBJS) \
$(foreach x,$(LIBC_CALLS_HEFTY_A_DIRECTDEPS),$($(x)_A).pkg)
LIBC_CALLS_HEFTY_LIBS = $(foreach x,$(LIBC_CALLS_HEFTY_ARTIFACTS),$($(x)))
LIBC_CALLS_HEFTY_SRCS = $(foreach x,$(LIBC_CALLS_HEFTY_ARTIFACTS),$($(x)_SRCS))
LIBC_CALLS_HEFTY_HDRS = $(foreach x,$(LIBC_CALLS_HEFTY_ARTIFACTS),$($(x)_HDRS))
LIBC_CALLS_HEFTY_BINS = $(foreach x,$(LIBC_CALLS_HEFTY_ARTIFACTS),$($(x)_BINS))
LIBC_CALLS_HEFTY_CHECKS = $(foreach x,$(LIBC_CALLS_HEFTY_ARTIFACTS),$($(x)_CHECKS))
LIBC_CALLS_HEFTY_OBJS = $(foreach x,$(LIBC_CALLS_HEFTY_ARTIFACTS),$($(x)_OBJS))
LIBC_CALLS_HEFTY_TESTS = $(foreach x,$(LIBC_CALLS_HEFTY_ARTIFACTS),$($(x)_TESTS))
$(LIBC_CALLS_HEFTY_OBJS): $(BUILD_FILES) libc/calls/hefty/hefty.mk
.PHONY: o/$(MODE)/libc/calls/hefty
o/$(MODE)/libc/calls/hefty: $(LIBC_CALLS_HEFTY_CHECKS)

View file

@ -36,6 +36,7 @@ struct IoctlPtmGet {
char theduxname[16]; char theduxname[16];
char workername[16]; char workername[16];
}; };
enum FdKind { enum FdKind {
kFdEmpty, kFdEmpty,
kFdFile, kFdFile,
@ -45,6 +46,7 @@ enum FdKind {
kFdSerial, kFdSerial,
kFdZip, kFdZip,
kFdEpoll, kFdEpoll,
kFdReserved
}; };
struct Fd { struct Fd {
@ -71,7 +73,8 @@ hidden extern struct NtSystemInfo g_ntsysteminfo;
hidden extern struct NtStartupInfo g_ntstartupinfo; hidden extern struct NtStartupInfo g_ntstartupinfo;
hidden extern const struct NtSecurityAttributes kNtIsInheritable; hidden extern const struct NtSecurityAttributes kNtIsInheritable;
ssize_t __getemptyfd(void) hidden; int __reservefd(void) hidden;
void __releasefd(int) hidden;
int __ensurefds(int) hidden; int __ensurefds(int) hidden;
void __removefd(int) hidden; void __removefd(int) hidden;

View file

@ -22,7 +22,6 @@
#include "libc/nt/console.h" #include "libc/nt/console.h"
#include "libc/nt/enum/consolemodeflags.h" #include "libc/nt/enum/consolemodeflags.h"
#include "libc/nt/enum/version.h" #include "libc/nt/enum/version.h"
#include "libc/nt/struct/teb.h"
#include "libc/sysv/consts/o.h" #include "libc/sysv/consts/o.h"
#include "libc/sysv/consts/termios.h" #include "libc/sysv/consts/termios.h"
#include "libc/sysv/errfuns.h" #include "libc/sysv/errfuns.h"

View file

@ -25,6 +25,7 @@
/** /**
* Controls settings on device. * Controls settings on device.
* @vforksafe
*/ */
int(ioctl)(int fd, uint64_t request, void *memory) { int(ioctl)(int fd, uint64_t request, void *memory) {
__IOCTL_DISPATCH(EQUAL, fd, request, memory); __IOCTL_DISPATCH(EQUAL, fd, request, memory);

View file

@ -32,7 +32,11 @@
#define kBufSize 1024 #define kBufSize 1024
#define kProcStatus "/proc/self/status" #define kProcStatus "/proc/self/status"
_Alignas(16) static const char kGdbPid[] = "TracerPid:\t"; #define kPid "TracerPid:\t"
static noasan int NtBeingDebugged(void) {
return NtGetPeb()->BeingDebugged;
}
/** /**
* Determines if gdb, strace, windbg, etc. is controlling process. * Determines if gdb, strace, windbg, etc. is controlling process.
@ -42,19 +46,18 @@ int IsDebuggerPresent(bool force) {
int fd, res; int fd, res;
ssize_t got; ssize_t got;
char buf[1024]; char buf[1024];
res = 0; res = false;
if (!force) { if (!force) {
if (getenv("HEISENDEBUG")) return false; if (getenv("HEISENDEBUG")) return false;
if (IsGenuineCosmo()) return false; if (IsGenuineCosmo()) return false;
} }
if (IsWindows()) { if (IsWindows()) {
res = NtGetPeb()->BeingDebugged; res = NtBeingDebugged();
} else if (IsLinux()) { } else if (IsLinux()) {
if ((fd = openat$sysv(AT_FDCWD, kProcStatus, O_RDONLY, 0)) != -1) { if ((fd = openat$sysv(AT_FDCWD, kProcStatus, O_RDONLY, 0)) != -1) {
if ((got = read$sysv(fd, buf, sizeof(buf) - sizeof(kGdbPid))) != -1) { if ((got = read$sysv(fd, buf, sizeof(buf) - sizeof(kPid))) != -1) {
buf[got] = '\0'; buf[got] = '\0';
res = res = atoi(firstnonnull(strstr(buf, kPid), kPid) + strlen(kPid));
atoi(firstnonnull(strstr(buf, kGdbPid), kGdbPid) + strlen(kGdbPid));
} }
close$sysv(fd); close$sysv(fd);
} }

View file

@ -29,9 +29,9 @@ forceinline typeof(PrefetchVirtualMemory) *GetPrefetchVirtualMemory(void) {
static bool once; static bool once;
static typeof(PrefetchVirtualMemory) *PrefetchVirtualMemory_; static typeof(PrefetchVirtualMemory) *PrefetchVirtualMemory_;
if (!once) { if (!once) {
once = true;
PrefetchVirtualMemory_ = /* win8.1+ */ PrefetchVirtualMemory_ = /* win8.1+ */
GetProcAddressModule("Kernel32.dll", "PrefetchVirtualMemory"); GetProcAddressModule("Kernel32.dll", "PrefetchVirtualMemory");
once = true;
} }
return PrefetchVirtualMemory_; return PrefetchVirtualMemory_;
} }
@ -40,9 +40,9 @@ forceinline typeof(OfferVirtualMemory) *GetOfferVirtualMemory(void) {
static bool once; static bool once;
static typeof(OfferVirtualMemory) *OfferVirtualMemory_; static typeof(OfferVirtualMemory) *OfferVirtualMemory_;
if (!once) { if (!once) {
once = true;
OfferVirtualMemory_ = /* win8.1+ */ OfferVirtualMemory_ = /* win8.1+ */
GetProcAddressModule("Kernel32.dll", "OfferVirtualMemory"); GetProcAddressModule("Kernel32.dll", "OfferVirtualMemory");
once = true;
} }
return OfferVirtualMemory_; return OfferVirtualMemory_;
} }

View file

@ -37,8 +37,8 @@
* @kudos Daniel Colascione for teaching how to quote * @kudos Daniel Colascione for teaching how to quote
* @see libc/runtime/dosargv.c * @see libc/runtime/dosargv.c
*/ */
textwindows int mkntcmdline(char16_t cmdline[ARG_MAX], const char *prog, textwindows noasan int mkntcmdline(char16_t cmdline[ARG_MAX], const char *prog,
char *const argv[]) { char *const argv[]) {
char *arg; char *arg;
uint64_t w; uint64_t w;
wint_t x, y; wint_t x, y;

View file

@ -29,21 +29,18 @@
#include "libc/str/utf16.h" #include "libc/str/utf16.h"
#include "libc/sysv/errfuns.h" #include "libc/sysv/errfuns.h"
static int CompareStrings(const char *l, const char *r) { static noasan int CompareStrings(const char *l, const char *r) {
size_t i = 0; size_t i = 0;
while (l[i] == r[i] && r[i]) ++i; while (l[i] == r[i] && r[i]) ++i;
return (l[i] & 0xff) - (r[i] & 0xff); return (l[i] & 0xff) - (r[i] & 0xff);
} }
static void SortStrings(char **a, size_t n) { static noasan void InsertString(char **a, size_t i, char *s) {
char *t; size_t j;
size_t i, j; for (j = i; j > 0 && CompareStrings(s, a[j - 1]) < 0; --j) {
for (i = 1; i < n; ++i) { a[j] = a[j - 1];
for (t = a[i], j = i; j > 0 && CompareStrings(t, a[j - 1]) < 0; --j) {
a[j] = a[j - 1];
}
a[j] = t;
} }
a[j] = s;
} }
/** /**
@ -51,19 +48,24 @@ static void SortStrings(char **a, size_t n) {
* *
* This is designed to meet the requirements of CreateProcess(). * This is designed to meet the requirements of CreateProcess().
* *
* @param envvars receives sorted double-NUL terminated string list
* @param envp is an a NULL-terminated array of UTF-8 strings * @param envp is an a NULL-terminated array of UTF-8 strings
* @return freshly allocated lpEnvironment or NULL w/ errno * @param extravar is a VAR=val string we consider part of envp or NULL
* @return 0 on success, or -1 w/ errno
* @error E2BIG if total number of shorts exceeded ARG_MAX (0x8000)
*/ */
textwindows int mkntenvblock(char16_t envvars[ARG_MAX], char *const envp[]) { textwindows noasan int mkntenvblock(char16_t envvars[ARG_MAX],
char *const envp[], const char *extravar) {
char *t;
axdx_t rc; axdx_t rc;
uint64_t w; uint64_t w;
char **vars; char **vars;
wint_t x, y; wint_t x, y;
size_t i, j, k, n, m; size_t i, j, k, n, m;
for (n = 0; envp[n];) n++; for (n = 0; envp[n];) n++;
vars = alloca(n * sizeof(char *)); vars = alloca((n + 1) * sizeof(char *));
memcpy(vars, envp, n * sizeof(char *)); for (i = 0; i < n; ++i) InsertString(vars, i, envp[i]);
SortStrings(vars, n); if (extravar) InsertString(vars, n++, extravar);
for (k = i = 0; i < n; ++i) { for (k = i = 0; i < n; ++i) {
j = 0; j = 0;
do { do {

View file

@ -34,7 +34,7 @@ extern __msabi typeof(VirtualProtect) *const __imp_VirtualProtect;
* @return 0 on success, or -1 w/ errno * @return 0 on success, or -1 w/ errno
* @see mmap() * @see mmap()
*/ */
int mprotect(void *addr, uint64_t len, int prot) { textsyscall int mprotect(void *addr, uint64_t len, int prot) {
bool cf; bool cf;
int64_t rc; int64_t rc;
uint32_t oldprot; uint32_t oldprot;

View file

@ -23,6 +23,7 @@
#include "libc/dce.h" #include "libc/dce.h"
#include "libc/nexgen32e/rdtsc.h" #include "libc/nexgen32e/rdtsc.h"
#include "libc/nexgen32e/x86feature.h" #include "libc/nexgen32e/x86feature.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/clock.h" #include "libc/sysv/consts/clock.h"
#include "libc/time/time.h" #include "libc/time/time.h"
@ -55,19 +56,21 @@ static long double MeasureNanosPerCycle(void) {
} }
static void InitTime(void) { static void InitTime(void) {
g_now.cpn = MeasureNanosPerCycle(); struct Now now;
g_now.r0 = dtime(CLOCK_REALTIME); now.cpn = MeasureNanosPerCycle();
g_now.k0 = rdtsc(); now.r0 = dtime(CLOCK_REALTIME);
g_now.once = true; now.k0 = rdtsc();
now.once = true;
memcpy(&g_now, &now, sizeof(now));
} }
long double converttickstonanos(uint64_t ticks) { long double ConvertTicksToNanos(uint64_t ticks) {
if (!g_now.once) InitTime(); if (!g_now.once) InitTime();
return ticks * g_now.cpn; /* pico scale */ return ticks * g_now.cpn; /* pico scale */
} }
long double converttickstoseconds(uint64_t ticks) { static long double ConvertTicksToSeconds(uint64_t ticks) {
return 1 / 1e9 * converttickstonanos(ticks); return 1 / 1e9 * ConvertTicksToNanos(ticks);
} }
long double nowl$sys(void) { long double nowl$sys(void) {
@ -78,5 +81,5 @@ long double nowl$art(void) {
uint64_t ticks; uint64_t ticks;
if (!g_now.once) InitTime(); if (!g_now.once) InitTime();
ticks = unsignedsubtract(rdtsc(), g_now.k0); ticks = unsignedsubtract(rdtsc(), g_now.k0);
return g_now.r0 + converttickstoseconds(ticks); return g_now.r0 + ConvertTicksToSeconds(ticks);
} }

View file

@ -48,6 +48,7 @@ struct SpawnBlock {
* don't need to be passed in sorted order; however, this function * don't need to be passed in sorted order; however, this function
* goes faster the closer they are to sorted * goes faster the closer they are to sorted
* @param envp[m-1] is NULL * @param envp[m-1] is NULL
* @param extravar is added to envp to avoid setenv() in caller
* @param bInheritHandles means handles already marked inheritable will * @param bInheritHandles means handles already marked inheritable will
* be inherited; which, assuming the System V wrapper functions are * be inherited; which, assuming the System V wrapper functions are
* being used, should mean (1) all files and sockets that weren't * being used, should mean (1) all files and sockets that weren't
@ -59,7 +60,7 @@ struct SpawnBlock {
*/ */
textwindows int ntspawn( textwindows int ntspawn(
const char *prog, char *const argv[], char *const envp[], const char *prog, char *const argv[], char *const envp[],
struct NtSecurityAttributes *opt_lpProcessAttributes, const char *extravar, struct NtSecurityAttributes *opt_lpProcessAttributes,
struct NtSecurityAttributes *opt_lpThreadAttributes, bool32 bInheritHandles, struct NtSecurityAttributes *opt_lpThreadAttributes, bool32 bInheritHandles,
uint32_t dwCreationFlags, const char16_t *opt_lpCurrentDirectory, uint32_t dwCreationFlags, const char16_t *opt_lpCurrentDirectory,
const struct NtStartupInfo *lpStartupInfo, const struct NtStartupInfo *lpStartupInfo,
@ -81,7 +82,7 @@ textwindows int ntspawn(
MapViewOfFileExNuma(handle, kNtFileMapRead | kNtFileMapWrite, 0, 0, MapViewOfFileExNuma(handle, kNtFileMapRead | kNtFileMapWrite, 0, 0,
blocksize, NULL, kNtNumaNoPreferredNode))) { blocksize, NULL, kNtNumaNoPreferredNode))) {
if (mkntcmdline(block->cmdline, prog, argv) != -1 && if (mkntcmdline(block->cmdline, prog, argv) != -1 &&
mkntenvblock(block->envvars, envp) != -1) { mkntenvblock(block->envvars, envp, extravar) != -1) {
if (CreateProcess(NULL, block->cmdline, opt_lpProcessAttributes, if (CreateProcess(NULL, block->cmdline, opt_lpProcessAttributes,
opt_lpThreadAttributes, bInheritHandles, opt_lpThreadAttributes, bInheritHandles,
dwCreationFlags | kNtCreateUnicodeEnvironment, dwCreationFlags | kNtCreateUnicodeEnvironment,

View file

@ -1,5 +1,5 @@
#ifndef COSMOPOLITAN_LIBC_CALLS_HEFTY_NTSPAWN_H_ #ifndef COSMOPOLITAN_LIBC_CALLS_NTSPAWN_H_
#define COSMOPOLITAN_LIBC_CALLS_HEFTY_NTSPAWN_H_ #define COSMOPOLITAN_LIBC_CALLS_NTSPAWN_H_
#include "libc/nt/struct/processinformation.h" #include "libc/nt/struct/processinformation.h"
#include "libc/nt/struct/securityattributes.h" #include "libc/nt/struct/securityattributes.h"
#include "libc/nt/struct/startupinfo.h" #include "libc/nt/struct/startupinfo.h"
@ -7,12 +7,12 @@
COSMOPOLITAN_C_START_ COSMOPOLITAN_C_START_
int mkntcmdline(char16_t[ARG_MAX], const char *, char *const[]) hidden; int mkntcmdline(char16_t[ARG_MAX], const char *, char *const[]) hidden;
int mkntenvblock(char16_t[ARG_MAX], char *const[]) hidden; int mkntenvblock(char16_t[ARG_MAX], char *const[], const char *) hidden;
int ntspawn(const char *, char *const[], char *const[], int ntspawn(const char *, char *const[], char *const[], const char *,
struct NtSecurityAttributes *, struct NtSecurityAttributes *, struct NtSecurityAttributes *, struct NtSecurityAttributes *,
bool32, uint32_t, const char16_t *, const struct NtStartupInfo *, bool32, uint32_t, const char16_t *, const struct NtStartupInfo *,
struct NtProcessInformation *) hidden; struct NtProcessInformation *) hidden;
COSMOPOLITAN_C_END_ COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_CALLS_HEFTY_NTSPAWN_H_ */ #endif /* COSMOPOLITAN_LIBC_CALLS_NTSPAWN_H_ */

View file

@ -42,16 +42,7 @@ static textwindows int64_t open$nt$impl(int dirfd, const char *path,
char16_t path16[PATH_MAX]; char16_t path16[PATH_MAX];
if (__mkntpathat(dirfd, path, flags, path16) == -1) return -1; if (__mkntpathat(dirfd, path, flags, path16) == -1) return -1;
if ((handle = CreateFile( if ((handle = CreateFile(
path16, path16, flags & 0xf000000f, /* see consts.sh */
(flags & 0xf000000f) |
(/* this is needed if we mmap(rwx+cow)
nt is choosy about open() access */
(flags & O_APPEND)
? kNtFileAppendData
: (flags & O_ACCMODE) == O_RDONLY
? kNtGenericExecute | kNtFileGenericRead
: kNtGenericExecute | kNtFileGenericRead |
kNtFileGenericWrite),
(flags & O_EXCL) (flags & O_EXCL)
? kNtFileShareExclusive ? kNtFileShareExclusive
: kNtFileShareRead | kNtFileShareWrite | kNtFileShareDelete, : kNtFileShareRead | kNtFileShareWrite | kNtFileShareDelete,
@ -75,14 +66,6 @@ static textwindows int64_t open$nt$impl(int dirfd, const char *path,
kNtFileFlagBackupSemantics | kNtFileFlagPosixSemantics | kNtFileFlagBackupSemantics | kNtFileFlagPosixSemantics |
kNtFileAttributeTemporary)))), kNtFileAttributeTemporary)))),
0)) != -1) { 0)) != -1) {
if (flags & O_SPARSE) {
/*
* TODO(jart): Can all files be sparse files? That seems to be the
* way Linux behaves out of the box.
* TODO(jart): Wow why does sparse wreak havoc?
*/
DeviceIoControl(handle, kNtFsctlSetSparse, NULL, 0, NULL, 0, &br, NULL);
}
return handle; return handle;
} else if (GetLastError() == kNtErrorFileExists && } else if (GetLastError() == kNtErrorFileExists &&
((flags & O_CREAT) && ((flags & O_CREAT) &&
@ -129,11 +112,16 @@ static textwindows ssize_t open$nt$file(int dirfd, const char *file,
textwindows ssize_t open$nt(int dirfd, const char *file, uint32_t flags, textwindows ssize_t open$nt(int dirfd, const char *file, uint32_t flags,
int32_t mode) { int32_t mode) {
size_t fd; int fd;
if ((fd = __getemptyfd()) == -1) return -1; ssize_t rc;
if ((fd = __reservefd()) == -1) return -1;
if ((flags & O_ACCMODE) == O_RDWR && !strcmp(file, kNtMagicPaths.devtty)) { if ((flags & O_ACCMODE) == O_RDWR && !strcmp(file, kNtMagicPaths.devtty)) {
return open$nt$console(dirfd, &kNtMagicPaths, flags, mode, fd); rc = open$nt$console(dirfd, &kNtMagicPaths, flags, mode, fd);
} else { } else {
return open$nt$file(dirfd, file, flags, mode, fd); rc = open$nt$file(dirfd, file, flags, mode, fd);
} }
if (rc == -1) {
__releasefd(fd);
}
return rc;
} }

View file

@ -31,7 +31,7 @@
* @asyncsignalsafe * @asyncsignalsafe
* @vforksafe * @vforksafe
*/ */
nodiscard int open(const char *file, int flags, ...) { int open(const char *file, int flags, ...) {
va_list va; va_list va;
unsigned mode; unsigned mode;
va_start(va, flags); va_start(va, flags);

View file

@ -67,8 +67,8 @@ static int openanon$impl(const char *name, unsigned flags,
} }
return fd; return fd;
} else { } else {
if ((fd = __getemptyfd()) != -1 && if ((fd = __reservefd()) == -1) return -1;
(g_fds.p[fd].handle = CreateFileA( if ((g_fds.p[fd].handle = CreateFileA(
pathbuf, kNtGenericRead | kNtGenericWrite, kNtFileShareExclusive, pathbuf, kNtGenericRead | kNtGenericWrite, kNtFileShareExclusive,
&kNtIsInheritable, kNtCreateAlways, &kNtIsInheritable, kNtCreateAlways,
(kNtFileAttributeNotContentIndexed | kNtFileAttributeNormal | (kNtFileAttributeNotContentIndexed | kNtFileAttributeNormal |
@ -78,6 +78,7 @@ static int openanon$impl(const char *name, unsigned flags,
g_fds.p[fd].flags = flags; g_fds.p[fd].flags = flags;
return fd; return fd;
} else { } else {
__releasefd(fd);
return __winerr(); return __winerr();
} }
} }

View file

@ -37,6 +37,7 @@
* ignored if O_CREAT or O_TMPFILE weren't passed * ignored if O_CREAT or O_TMPFILE weren't passed
* @return number needing close(), or -1 w/ errno * @return number needing close(), or -1 w/ errno
* @asyncsignalsafe * @asyncsignalsafe
* @vforksafe
*/ */
nodiscard int openat(int dirfd, const char *file, int flags, ...) { nodiscard int openat(int dirfd, const char *file, int flags, ...) {
va_list va; va_list va;
@ -47,11 +48,9 @@ nodiscard int openat(int dirfd, const char *file, int flags, ...) {
va_end(va); va_end(va);
if (!file) return efault(); if (!file) return efault();
if (weaken(__zipos_open) && weaken(__zipos_parseuri)(file, &zipname) != -1) { if (weaken(__zipos_open) && weaken(__zipos_parseuri)(file, &zipname) != -1) {
if (dirfd == AT_FDCWD) { if (__vforked) return einval();
return weaken(__zipos_open)(&zipname, flags, mode); if (dirfd != AT_FDCWD) return einval();
} else { return weaken(__zipos_open)(&zipname, flags, mode);
return eopnotsupp(); /* TODO */
}
} else if (!IsWindows()) { } else if (!IsWindows()) {
return openat$sysv(dirfd, file, flags, mode); return openat$sysv(dirfd, file, flags, mode);
} else { } else {

View file

@ -58,16 +58,19 @@ textwindows int pipe$nt(int pipefd[2], unsigned flags) {
int reader, writer; int reader, writer;
char16_t pipename[64]; char16_t pipename[64];
CreatePipeName(pipename); CreatePipeName(pipename);
if ((reader = __reservefd()) == -1) return -1;
if ((writer = __reservefd()) == -1) {
__releasefd(reader);
return -1;
}
if ((hin = CreateNamedPipe(pipename, kNtPipeAccessInbound, if ((hin = CreateNamedPipe(pipename, kNtPipeAccessInbound,
kNtPipeWait | kNtPipeReadmodeByte, 1, 65536, 65536, kNtPipeWait | kNtPipeReadmodeByte, 1, 65536, 65536,
0, &kNtIsInheritable)) != -1) { 0, &kNtIsInheritable)) != -1) {
if ((hout = CreateFile(pipename, kNtGenericWrite, kNtFileShareWrite, if ((hout = CreateFile(pipename, kNtGenericWrite, kNtFileShareWrite,
&kNtIsInheritable, kNtOpenExisting, 0, 0)) != -1) { &kNtIsInheritable, kNtOpenExisting, 0, 0)) != -1) {
reader = __getemptyfd();
g_fds.p[reader].kind = kFdFile; g_fds.p[reader].kind = kFdFile;
g_fds.p[reader].flags = flags; g_fds.p[reader].flags = flags;
g_fds.p[reader].handle = hin; g_fds.p[reader].handle = hin;
writer = __getemptyfd();
g_fds.p[writer].kind = kFdFile; g_fds.p[writer].kind = kFdFile;
g_fds.p[writer].flags = flags; g_fds.p[writer].flags = flags;
g_fds.p[writer].handle = hout; g_fds.p[writer].handle = hout;
@ -78,5 +81,6 @@ textwindows int pipe$nt(int pipefd[2], unsigned flags) {
CloseHandle(hin); CloseHandle(hin);
} }
} }
__releasefd(reader);
return __winerr(); return __winerr();
} }

29
libc/calls/releasefd.c Normal file
View file

@ -0,0 +1,29 @@
/*-*- 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 2021 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/bits/bits.h"
#include "libc/calls/internal.h"
void __releasefd(int fd) {
int x;
g_fds.p[fd].kind = kFdEmpty;
do {
x = g_fds.f;
if (fd >= x) break;
} while (!cmpxchg(&g_fds.f, x, fd));
}

View file

@ -24,11 +24,16 @@
/** /**
* Finds open file descriptor slot. * Finds open file descriptor slot.
*/ */
ssize_t __getemptyfd(void) { int __reservefd(void) {
for (; g_fds.f < g_fds.n; ++g_fds.f) { int fd;
if (g_fds.p[g_fds.f].kind == kFdEmpty) { for (;;) {
return g_fds.f; fd = g_fds.f;
if (fd >= g_fds.n) {
if (__ensurefds(fd) == -1) return -1;
}
cmpxchg(&g_fds.f, fd, fd + 1);
if (cmpxchg(&g_fds.p[fd].kind, kFdEmpty, kFdReserved)) {
return fd;
} }
} }
return __ensurefds(g_fds.f);
} }

View file

@ -19,6 +19,7 @@
#include "libc/bits/bits.h" #include "libc/bits/bits.h"
#include "libc/calls/calls.h" #include "libc/calls/calls.h"
#include "libc/calls/internal.h" #include "libc/calls/internal.h"
#include "libc/calls/sigbits.h"
#include "libc/calls/struct/sigaction-freebsd.internal.h" #include "libc/calls/struct/sigaction-freebsd.internal.h"
#include "libc/calls/struct/sigaction-linux.internal.h" #include "libc/calls/struct/sigaction-linux.internal.h"
#include "libc/calls/struct/sigaction-openbsd.internal.h" #include "libc/calls/struct/sigaction-openbsd.internal.h"
@ -120,6 +121,7 @@ static void sigaction$native2cosmo(union metasigaction *sa) {
* *
* @see xsigaction() for a much better api * @see xsigaction() for a much better api
* @asyncsignalsafe * @asyncsignalsafe
* @vforksafe
*/ */
int(sigaction)(int sig, const struct sigaction *act, struct sigaction *oldact) { int(sigaction)(int sig, const struct sigaction *act, struct sigaction *oldact) {
_Static_assert(sizeof(struct sigaction) > sizeof(struct sigaction$linux) && _Static_assert(sizeof(struct sigaction) > sizeof(struct sigaction$linux) &&
@ -129,9 +131,8 @@ int(sigaction)(int sig, const struct sigaction *act, struct sigaction *oldact) {
sizeof(struct sigaction) > sizeof(struct sigaction$openbsd)); sizeof(struct sigaction) > sizeof(struct sigaction$openbsd));
int rc, rva, oldrva; int rc, rva, oldrva;
struct sigaction *ap, copy; struct sigaction *ap, copy;
if (!(0 < sig && sig < NSIG) || sig == SIGKILL || sig == SIGSTOP) { if (!(0 < sig && sig < NSIG)) return einval();
return einval(); if (sig == SIGKILL || sig == SIGSTOP) return einval();
}
if (!act) { if (!act) {
rva = (int32_t)(intptr_t)SIG_DFL; rva = (int32_t)(intptr_t)SIG_DFL;
} else if ((intptr_t)act->sa_handler < kSigactionMinRva) { } else if ((intptr_t)act->sa_handler < kSigactionMinRva) {
@ -142,6 +143,9 @@ int(sigaction)(int sig, const struct sigaction *act, struct sigaction *oldact) {
} else { } else {
return efault(); return efault();
} }
if (__vforked && rva != (intptr_t)SIG_DFL && rva != (intptr_t)SIG_IGN) {
return einval();
}
if (!IsWindows()) { if (!IsWindows()) {
if (!IsMetal()) { if (!IsMetal()) {
if (act) { if (act) {
@ -150,16 +154,13 @@ int(sigaction)(int sig, const struct sigaction *act, struct sigaction *oldact) {
if (IsXnu()) { if (IsXnu()) {
ap->sa_restorer = (void *)&xnutrampoline; ap->sa_restorer = (void *)&xnutrampoline;
ap->sa_handler = (void *)&xnutrampoline; ap->sa_handler = (void *)&xnutrampoline;
} else { } else if (IsLinux()) {
if (IsLinux()) { if (!(ap->sa_flags & SA_RESTORER)) {
if (!(ap->sa_flags & SA_RESTORER)) { ap->sa_flags |= SA_RESTORER;
ap->sa_flags |= SA_RESTORER; ap->sa_restorer = &__restore_rt;
ap->sa_restorer = &__restore_rt;
}
}
if (rva >= kSigactionMinRva) {
ap->sa_sigaction = (sigaction_f)__sigenter;
} }
} else if (rva >= kSigactionMinRva) {
ap->sa_sigaction = (sigaction_f)__sigenter;
} }
sigaction$cosmo2native((union metasigaction *)ap); sigaction$cosmo2native((union metasigaction *)ap);
} else { } else {
@ -179,7 +180,7 @@ int(sigaction)(int sig, const struct sigaction *act, struct sigaction *oldact) {
} }
rc = 0; rc = 0;
} }
if (rc != -1) { if (rc != -1 && !__vforked) {
if (oldact) { if (oldact) {
oldrva = __sighandrvas[sig]; oldrva = __sighandrvas[sig];
oldact->sa_sigaction = (sigaction_f)( oldact->sa_sigaction = (sigaction_f)(

View file

@ -20,7 +20,7 @@
#include "libc/macros.h" #include "libc/macros.h"
.source __FILE__ .source __FILE__
/ System Five signal handler. / BSD signal handler.
/ /
/ This is needed because (1) a signal is allowed to trigger at / This is needed because (1) a signal is allowed to trigger at
/ just about any time, and leaf functions (e.g. memcpy) aren't / just about any time, and leaf functions (e.g. memcpy) aren't

View file

@ -28,7 +28,7 @@
* @return -1 w/ few exceptions * @return -1 w/ few exceptions
* @note this is a code-size saving device * @note this is a code-size saving device
*/ */
privileged int64_t __winerr(void) { privileged noasan int64_t __winerr(void) {
if (IsWindows()) { if (IsWindows()) {
errno = GetLastError(); errno = GetLastError();
return -1; return -1;

View file

@ -42,7 +42,6 @@ textwindows ssize_t write$nt(struct Fd *fd, const struct iovec *iov,
iovlen ? clampio(iov[0].iov_len) : 0, &wrote, iovlen ? clampio(iov[0].iov_len) : 0, &wrote,
offset2overlap(opt_offset, &overlap))) { offset2overlap(opt_offset, &overlap))) {
if (!wrote) assert(!SumIovecLen(iov, iovlen)); if (!wrote) assert(!SumIovecLen(iov, iovlen));
FlushFileBuffers(fd->handle);
return wrote; return wrote;
} else { } else {
return __winerr(); return __winerr();

View file

@ -17,6 +17,7 @@
│ PERFORMANCE OF THIS SOFTWARE. │ │ PERFORMANCE OF THIS SOFTWARE. │
╚─────────────────────────────────────────────────────────────────────────────*/ ╚─────────────────────────────────────────────────────────────────────────────*/
#include "ape/relocations.h" #include "ape/relocations.h"
#include "libc/macros.h"
/** /**
* @fileoverview Cosmopolitan ELF-Normative Linker Script. * @fileoverview Cosmopolitan ELF-Normative Linker Script.
@ -66,6 +67,9 @@ SECTIONS {
.text : { .text : {
*(SORT_BY_ALIGNMENT(.text.hot)) *(SORT_BY_ALIGNMENT(.text.hot))
KEEP(*(.keep.text)) KEEP(*(.keep.text))
HIDDEN(__text_syscall_start = .);
*(.text.syscall .text.syscall.*)
HIDDEN(__text_syscall_end = .);
*(.text .text.*) *(.text .text.*)
KEEP(*(SORT_BY_NAME(.sort.text.*))) KEEP(*(SORT_BY_NAME(.sort.text.*)))
} }
@ -207,3 +211,7 @@ SECTIONS {
*(.*) *(.*)
} }
} }
HIDDEN(__text_syscall_addr = ROUNDDOWN(__text_syscall_start, PAGESIZE));
HIDDEN(__text_syscall_size = (ROUNDUP(__text_syscall_end, PAGESIZE) -
ROUNDDOWN(__text_syscall_start, PAGESIZE)));

View file

@ -17,6 +17,7 @@ LIBC_FMT = $(LIBC_FMT_A_DEPS) $(LIBC_FMT_A)
LIBC_FMT_A = o/$(MODE)/libc/fmt/fmt.a LIBC_FMT_A = o/$(MODE)/libc/fmt/fmt.a
LIBC_FMT_A_FILES := $(wildcard libc/fmt/*) LIBC_FMT_A_FILES := $(wildcard libc/fmt/*)
LIBC_FMT_A_HDRS = $(filter %.h,$(LIBC_FMT_A_FILES)) LIBC_FMT_A_HDRS = $(filter %.h,$(LIBC_FMT_A_FILES))
LIBC_FMT_A_INCS = $(filter %.inc,$(LIBC_FMT_A_FILES))
LIBC_FMT_A_SRCS_S = $(filter %.S,$(LIBC_FMT_A_FILES)) LIBC_FMT_A_SRCS_S = $(filter %.S,$(LIBC_FMT_A_FILES))
LIBC_FMT_A_SRCS_C = $(filter %.c,$(LIBC_FMT_A_FILES)) LIBC_FMT_A_SRCS_C = $(filter %.c,$(LIBC_FMT_A_FILES))
@ -75,6 +76,7 @@ o/$(MODE)/libc/fmt/itoa128radix10.greg.o: \
LIBC_FMT_LIBS = $(foreach x,$(LIBC_FMT_ARTIFACTS),$($(x))) LIBC_FMT_LIBS = $(foreach x,$(LIBC_FMT_ARTIFACTS),$($(x)))
LIBC_FMT_SRCS = $(foreach x,$(LIBC_FMT_ARTIFACTS),$($(x)_SRCS)) LIBC_FMT_SRCS = $(foreach x,$(LIBC_FMT_ARTIFACTS),$($(x)_SRCS))
LIBC_FMT_HDRS = $(foreach x,$(LIBC_FMT_ARTIFACTS),$($(x)_HDRS)) LIBC_FMT_HDRS = $(foreach x,$(LIBC_FMT_ARTIFACTS),$($(x)_HDRS))
LIBC_FMT_INCS = $(foreach x,$(LIBC_FMT_ARTIFACTS),$($(x)_INCS))
LIBC_FMT_CHECKS = $(foreach x,$(LIBC_FMT_ARTIFACTS),$($(x)_CHECKS)) LIBC_FMT_CHECKS = $(foreach x,$(LIBC_FMT_ARTIFACTS),$($(x)_CHECKS))
LIBC_FMT_OBJS = $(foreach x,$(LIBC_FMT_ARTIFACTS),$($(x)_OBJS)) LIBC_FMT_OBJS = $(foreach x,$(LIBC_FMT_ARTIFACTS),$($(x)_OBJS))
$(LIBC_FMT_OBJS): $(BUILD_FILES) libc/fmt/fmt.mk $(LIBC_FMT_OBJS): $(BUILD_FILES) libc/fmt/fmt.mk

View file

@ -331,7 +331,7 @@ typedef uint64_t uintmax_t;
#ifndef nullterminated #ifndef nullterminated
#if !defined(__STRICT_ANSI__) && \ #if !defined(__STRICT_ANSI__) && \
(__has_attribute(__sentinel__) || __GNUC__ >= 4) (__has_attribute(__sentinel__) || __GNUC__ + 0 >= 4)
#define nullterminated(x) __attribute__((__sentinel__ x)) #define nullterminated(x) __attribute__((__sentinel__ x))
#else #else
#define nullterminated(x) #define nullterminated(x)
@ -618,6 +618,7 @@ typedef uint64_t uintmax_t;
#define textexit _Section(".text.exit") noinstrument #define textexit _Section(".text.exit") noinstrument
#define textreal _Section(".text.real") #define textreal _Section(".text.real")
#define textwindows _Section(".text.windows") #define textwindows _Section(".text.windows")
#define textsyscall _Section(".text.syscall") noinline
#define antiquity _Section(".text.antiquity") #define antiquity _Section(".text.antiquity")
#else #else
#define testonly #define testonly

View file

@ -20,17 +20,19 @@
#include "libc/bits/bits.h" #include "libc/bits/bits.h"
#include "libc/bits/weaken.h" #include "libc/bits/weaken.h"
#include "libc/calls/calls.h" #include "libc/calls/calls.h"
#include "libc/dce.h"
#include "libc/intrin/asan.internal.h" #include "libc/intrin/asan.internal.h"
#include "libc/linux/exit.h"
#include "libc/linux/write.h"
#include "libc/log/log.h" #include "libc/log/log.h"
#include "libc/macros.h" #include "libc/macros.h"
#include "libc/mem/hook/hook.h" #include "libc/mem/hook/hook.h"
#include "libc/nt/enum/version.h"
#include "libc/nt/runtime.h"
#include "libc/runtime/directmap.h" #include "libc/runtime/directmap.h"
#include "libc/runtime/memtrack.h" #include "libc/runtime/memtrack.h"
#include "libc/runtime/runtime.h" #include "libc/runtime/runtime.h"
#include "libc/sysv/consts/auxv.h" #include "libc/sysv/consts/auxv.h"
#include "libc/sysv/consts/map.h" #include "libc/sysv/consts/map.h"
#include "libc/sysv/consts/nr.h"
#include "libc/sysv/consts/prot.h" #include "libc/sysv/consts/prot.h"
#include "third_party/dlmalloc/dlmalloc.internal.h" #include "third_party/dlmalloc/dlmalloc.internal.h"
@ -154,6 +156,13 @@ static void *__asan_repstosb(void *di, int al, size_t cx) {
return di; return di;
} }
static void *__asan_repmovsb(void *di, void *si, size_t cx) {
asm("rep movsb"
: "=D"(di), "=S"(si), "=c"(cx), "=m"(*(char(*)[cx])di)
: "0"(di), "1"(si), "2"(cx), "m"(*(char(*)[cx])si));
return di;
}
static void *__asan_memset(void *p, int c, size_t n) { static void *__asan_memset(void *p, int c, size_t n) {
char *b; char *b;
size_t i; size_t i;
@ -264,14 +273,18 @@ static void *__asan_mempcpy(void *dst, const void *src, size_t n) {
__builtin_memcpy(d + n - 8, &b, 8); __builtin_memcpy(d + n - 8, &b, 8);
return d + n; return d + n;
default: default:
i = 0; if (n <= 64) {
do { i = 0;
__builtin_memcpy(&a, s + i, 8); do {
asm volatile("" ::: "memory"); __builtin_memcpy(&a, s + i, 8);
__builtin_memcpy(d + i, &a, 8); asm volatile("" ::: "memory");
} while ((i += 8) + 8 <= n); __builtin_memcpy(d + i, &a, 8);
for (; i < n; ++i) d[i] = s[i]; } while ((i += 8) + 8 <= n);
return d + i; for (; i < n; ++i) d[i] = s[i];
return d + i;
} else {
return __asan_repmovsb(d, s, n);
}
} }
} }
@ -280,16 +293,6 @@ static void *__asan_memcpy(void *dst, const void *src, size_t n) {
return dst; return dst;
} }
static void *__asan_memrchr(void *p, int c, size_t n) {
uint8_t *b;
for (c &= 0xff, b = p; n--;) {
if (b[n] == c) {
return b + n;
}
}
return NULL;
}
static size_t __asan_int2hex(uint64_t x, char b[17], uint8_t k) { static size_t __asan_int2hex(uint64_t x, char b[17], uint8_t k) {
int i; int i;
char *p; char *p;
@ -373,7 +376,9 @@ static const char *__asan_dscribe_heap_poison(long c) {
} }
} }
static const char *__asan_describe_access_poison(int c) { static const char *__asan_describe_access_poison(char *p) {
int c = p[0];
if (1 <= c && c <= 7) c = p[1];
switch (c) { switch (c) {
case kAsanHeapFree: case kAsanHeapFree:
return "heap use after free"; return "heap use after free";
@ -406,30 +411,42 @@ static const char *__asan_describe_access_poison(int c) {
} }
} }
static ssize_t __asan_write(const void *data, size_t size) { static textsyscall wontreturn void __asan_exit(int rc) {
if (!IsWindows()) {
asm volatile("syscall"
: /* no outputs */
: "a"(__NR_exit_group), "D"(rc)
: "memory");
unreachable;
} else {
ExitProcess(rc);
}
}
static textsyscall ssize_t __asan_write(const void *data, size_t size) {
ssize_t rc; ssize_t rc;
if (weaken(write)) { uint32_t wrote;
if ((rc = weaken(write)(2, data, size)) != -1) { if (!IsWindows()) {
return rc; asm volatile("syscall"
: "=a"(rc)
: "0"(__NR_write), "D"(2), "S"(data), "d"(size)
: "rcx", "r11", "memory");
return rc;
} else {
if (WriteFile(GetStdHandle(kNtStdErrorHandle), data, size, &wrote, 0)) {
return wrote;
} else {
return -1;
} }
} }
return LinuxWrite(2, data, size);
} }
static ssize_t __asan_write_string(const char *s) { static ssize_t __asan_write_string(const char *s) {
return __asan_write(s, __asan_strlen(s)); return __asan_write(s, __asan_strlen(s));
} }
static wontreturn void __asan_exit(int rc) {
if (weaken(_Exit)) {
weaken(_Exit)(rc);
} else {
LinuxExit(rc);
}
for (;;) asm("hlt");
}
static wontreturn void __asan_abort(void) { static wontreturn void __asan_abort(void) {
if (weaken(__die)) weaken(__die)();
if (weaken(abort)) weaken(abort)(); if (weaken(abort)) weaken(abort)();
__asan_exit(134); __asan_exit(134);
} }
@ -455,8 +472,6 @@ static wontreturn void __asan_report_heap_fault(void *addr, long c) {
char *p, ibuf[21], buf[256]; char *p, ibuf[21], buf[256];
p = __asan_report_start(buf); p = __asan_report_start(buf);
p = __asan_stpcpy(p, __asan_dscribe_heap_poison(c)); p = __asan_stpcpy(p, __asan_dscribe_heap_poison(c));
p = __asan_stpcpy(p, " ");
p = __asan_mempcpy(p, ibuf, __asan_int2str(c, ibuf));
p = __asan_stpcpy(p, " at 0x"); p = __asan_stpcpy(p, " at 0x");
p = __asan_mempcpy(p, ibuf, __asan_int2hex((intptr_t)addr, ibuf, 48)); p = __asan_mempcpy(p, ibuf, __asan_int2hex((intptr_t)addr, ibuf, 48));
p = __asan_stpcpy(p, " shadow 0x"); p = __asan_stpcpy(p, " shadow 0x");
@ -469,7 +484,7 @@ static wontreturn void __asan_report_memory_fault(uint8_t *addr, int size,
const char *kind) { const char *kind) {
char *p, ibuf[21], buf[256]; char *p, ibuf[21], buf[256];
p = __asan_report_start(buf); p = __asan_report_start(buf);
p = __asan_stpcpy(p, __asan_describe_access_poison(*SHADOW(addr))); p = __asan_stpcpy(p, __asan_describe_access_poison(SHADOW(addr)));
p = __asan_stpcpy(p, " "); p = __asan_stpcpy(p, " ");
p = __asan_mempcpy(p, ibuf, __asan_int2str(size, ibuf)); p = __asan_mempcpy(p, ibuf, __asan_int2str(size, ibuf));
p = __asan_stpcpy(p, "-byte "); p = __asan_stpcpy(p, "-byte ");
@ -525,6 +540,7 @@ static void *__asan_allocate(size_t a, size_t n, int underrun, int overrun) {
__asan_unpoison((uintptr_t)p, n); __asan_unpoison((uintptr_t)p, n);
__asan_poison((uintptr_t)p - 16, 16, underrun); /* see dlmalloc design */ __asan_poison((uintptr_t)p - 16, 16, underrun); /* see dlmalloc design */
__asan_poison((uintptr_t)p + n, c - n, overrun); __asan_poison((uintptr_t)p + n, c - n, overrun);
__asan_memset(p, 0xF9, n);
WRITE64BE(p + c - sizeof(n), n); WRITE64BE(p + c - sizeof(n), n);
} }
return p; return p;
@ -637,7 +653,9 @@ void __asan_stack_free(char *p, size_t size, int classid) {
__asan_deallocate(p, kAsanStackFree); __asan_deallocate(p, kAsanStackFree);
} }
void __asan_handle_no_return_impl(uintptr_t rsp) { void __asan_handle_no_return(void) {
uintptr_t rsp;
rsp = (uintptr_t)__builtin_frame_address(0);
__asan_unpoison(rsp, ROUNDUP(rsp, STACKSIZE) - rsp); __asan_unpoison(rsp, ROUNDUP(rsp, STACKSIZE) - rsp);
} }
@ -657,14 +675,22 @@ void __asan_unregister_globals(struct AsanGlobal g[], int n) {
} }
} }
void __asan_report_load_impl(uint8_t *addr, int size) { void __asan_report_load(uint8_t *addr, int size) {
__asan_report_memory_fault(addr, size, "load"); __asan_report_memory_fault(addr, size, "load");
} }
void __asan_report_store_impl(uint8_t *addr, int size) { void __asan_report_store(uint8_t *addr, int size) {
__asan_report_memory_fault(addr, size, "store"); __asan_report_memory_fault(addr, size, "store");
} }
void __asan_poison_stack_memory(uintptr_t addr, size_t size) {
__asan_poison(addr, size, kAsanStackFree);
}
void __asan_unpoison_stack_memory(uintptr_t addr, size_t size) {
__asan_unpoison(addr, size);
}
void __asan_alloca_poison(uintptr_t addr, size_t size) { void __asan_alloca_poison(uintptr_t addr, size_t size) {
/* TODO(jart): Make sense of this function. */ /* TODO(jart): Make sense of this function. */
/* __asan_poison(addr - 32, 32, kAsanAllocaUnderrun); */ /* __asan_poison(addr - 32, 32, kAsanAllocaUnderrun); */
@ -709,7 +735,9 @@ void __asan_map_shadow(uintptr_t p, size_t n) {
int i, x, a, b; int i, x, a, b;
struct DirectMap sm; struct DirectMap sm;
struct MemoryIntervals *m; struct MemoryIntervals *m;
if (0x7fff8000 <= p && p < 0x100080000000) { if ((0x7fff8000 <= p && p < 0x100080000000) ||
(0x7fff8000 <= p + n && p + n < 0x100080000000) ||
(p < 0x7fff8000 && 0x100080000000 <= p + n)) {
__asan_die("asan error: mmap can't shadow a shadow\r\n"); __asan_die("asan error: mmap can't shadow a shadow\r\n");
} }
m = weaken(_mmi); m = weaken(_mmi);
@ -777,6 +805,10 @@ textstartup void __asan_init(int argc, char **argv, char **envp,
intptr_t *auxv) { intptr_t *auxv) {
static bool once; static bool once;
if (!cmpxchg(&once, false, true)) return; if (!cmpxchg(&once, false, true)) return;
if (IsWindows() && NtGetVersion() < kNtVersionWindows10) {
__asan_write_string("error: asan binaries require windows10\n");
__asan_exit(0); /* So `make MODE=dbg test` passes w/ Windows7 */
}
REQUIRE(_mmi); REQUIRE(_mmi);
REQUIRE(__mmap); REQUIRE(__mmap);
REQUIRE(MAP_ANONYMOUS); REQUIRE(MAP_ANONYMOUS);

View file

@ -25,7 +25,9 @@ LIBC_INTRIN_A_CHECKS = \
LIBC_INTRIN_A_DIRECTDEPS = \ LIBC_INTRIN_A_DIRECTDEPS = \
LIBC_STUBS \ LIBC_STUBS \
LIBC_NEXGEN32E LIBC_SYSV \
LIBC_NEXGEN32E \
LIBC_NT_KERNEL32
LIBC_INTRIN_A_DEPS := \ LIBC_INTRIN_A_DEPS := \
$(call uniq,$(foreach x,$(LIBC_INTRIN_A_DIRECTDEPS),$($(x)))) $(call uniq,$(foreach x,$(LIBC_INTRIN_A_DIRECTDEPS),$($(x))))
@ -46,7 +48,8 @@ $(LIBC_INTRIN_A_OBJS): \
o/$(MODE)/libc/intrin/asan.o: \ o/$(MODE)/libc/intrin/asan.o: \
OVERRIDE_CFLAGS += \ OVERRIDE_CFLAGS += \
-mgeneral-regs-only -mgeneral-regs-only \
-O2
LIBC_INTRIN_LIBS = $(foreach x,$(LIBC_INTRIN_ARTIFACTS),$($(x))) LIBC_INTRIN_LIBS = $(foreach x,$(LIBC_INTRIN_ARTIFACTS),$($(x)))
LIBC_INTRIN_HDRS = $(foreach x,$(LIBC_INTRIN_ARTIFACTS),$($(x)_HDRS)) LIBC_INTRIN_HDRS = $(foreach x,$(LIBC_INTRIN_ARTIFACTS),$($(x)_HDRS))

View file

@ -1,7 +1,7 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ /*-*- 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 vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney Copyright 2021 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the any purpose with or without fee is hereby granted, provided that the
@ -16,9 +16,9 @@
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/nt/struct/teb.h"
#include "libc/nexgen32e/nexgen32e.h" #include "libc/runtime/runtime.h"
bool ctz(double x, double y) { textwindows noasan int NtGetVersion(void) {
return __builtin_islessgreater(x, y); return (NtGetPeb()->OSMajorVersion & 0xff) << 8 | NtGetPeb()->OSMinorVersion;
} }

View file

@ -29,6 +29,6 @@
void(psrldq)(uint8_t b[16], const uint8_t a[16], unsigned long n) { void(psrldq)(uint8_t b[16], const uint8_t a[16], unsigned long n) {
unsigned i; unsigned i;
if (n > 16) n = 16; if (n > 16) n = 16;
memcpy(b, a + n, 16 - n); __builtin_memcpy(b, a + n, 16 - n);
memset(b + (16 - n), 0, n); __builtin_memset(b + (16 - n), 0, n);
} }

View file

@ -25,6 +25,18 @@
/ since ASAN has the same stylistic hugeness as UBSAN. / since ASAN has the same stylistic hugeness as UBSAN.
/ We also guard all the functions, against reentrancy. / We also guard all the functions, against reentrancy.
.rodata.cst4
__asan_option_detect_stack_use_after_return:
.long 0
.endobj __asan_option_detect_stack_use_after_return,globl
.previous
.bss
__asan_noreentry:
.byte 0
.endobj __asan_noreentry
.previous
__asan_report_load1: __asan_report_load1:
push $1 push $1
jmp OnReportLoad jmp OnReportLoad
@ -43,14 +55,18 @@ __asan_report_load8:
.endfn __asan_report_load8,globl .endfn __asan_report_load8,globl
__asan_report_load16: __asan_report_load16:
push $16 push $16
/ 𝑠𝑙𝑖𝑑𝑒 jmp OnReportLoad
.endfn __asan_report_load16,globl .endfn __asan_report_load16,globl
__asan_report_load32:
push $32
/ 𝑠𝑙𝑖𝑑𝑒
.endfn __asan_report_load32,globl
OnReportLoad: OnReportLoad:
pop %rsi pop %rsi
/ 𝑠𝑙𝑖𝑑𝑒 / 𝑠𝑙𝑖𝑑𝑒
.endfn OnReportLoad .endfn OnReportLoad
__asan_report_load_n: __asan_report_load_n:
lea __asan_report_load_impl(%rip),%r11 lea __asan_report_load(%rip),%r11
jmp __asan_report_noreentry jmp __asan_report_noreentry
.endfn __asan_report_load_n,globl .endfn __asan_report_load_n,globl
@ -83,7 +99,7 @@ ReportStore:
/ 𝑠𝑙𝑖𝑑𝑒 / 𝑠𝑙𝑖𝑑𝑒
.endfn ReportStore .endfn ReportStore
__asan_report_store_n: __asan_report_store_n:
lea __asan_report_store_impl(%rip),%r11 lea __asan_report_store(%rip),%r11
/ 𝑠𝑙𝑖𝑑𝑒 / 𝑠𝑙𝑖𝑑𝑒
.endfn __asan_report_store_n,globl .endfn __asan_report_store_n,globl
@ -198,31 +214,6 @@ OnStackMalloc:
jmp __asan_stack_malloc jmp __asan_stack_malloc
.endfn OnStackMalloc .endfn OnStackMalloc
__asan_handle_no_return:
push %rbp
mov %rsp,%rbp
lea 8(%rsp),%rdi
call __asan_handle_no_return_impl
pop %rbp
ret
.endfn __asan_handle_no_return,globl
__asan_before_dynamic_init:
push %rbp
mov %rsp,%rbp
ud2
pop %rbp
ret
.endfn __asan_before_dynamic_init,globl
__asan_after_dynamic_init:
push %rbp
mov %rsp,%rbp
ud2
pop %rbp
ret
.endfn __asan_after_dynamic_init,globl
__asan_version_mismatch_check_v8: __asan_version_mismatch_check_v8:
ret ret
.endfn __asan_version_mismatch_check_v8,globl .endfn __asan_version_mismatch_check_v8,globl
@ -240,14 +231,76 @@ __asan_version_mismatch_check_v8:
pop %rdi pop %rdi
.init.end 301,_init_asan .init.end 301,_init_asan
.rodata.cst4 __asan_before_dynamic_init:
__asan_option_detect_stack_use_after_return: push %rbp
.long 0 mov %rsp,%rbp
.endobj __asan_option_detect_stack_use_after_return,globl ud2
.previous .endfn __asan_before_dynamic_init,globl
.bss __asan_after_dynamic_init:
__asan_noreentry: push %rbp
.byte 0 mov %rsp,%rbp
.endobj __asan_noreentry ud2
.previous .endfn __asan_after_dynamic_init,globl
__asan_load1:
push %rbp
mov %rsp,%rbp
ud2
.endfn __asan_load1,globl
__asan_load2:
push %rbp
mov %rsp,%rbp
ud2
.endfn __asan_load2,globl
__asan_load4:
push %rbp
mov %rsp,%rbp
ud2
.endfn __asan_load4,globl
__asan_load8:
push %rbp
mov %rsp,%rbp
ud2
.endfn __asan_load8,globl
__asan_load16:
push %rbp
mov %rsp,%rbp
ud2
.endfn __asan_load16,globl
__asan_load32:
push %rbp
mov %rsp,%rbp
ud2
.endfn __asan_load32,globl
__asan_store1:
push %rbp
mov %rsp,%rbp
ud2
.endfn __asan_store1,globl
__asan_store2:
push %rbp
mov %rsp,%rbp
ud2
.endfn __asan_store2,globl
__asan_store4:
push %rbp
mov %rsp,%rbp
ud2
.endfn __asan_store4,globl
__asan_store8:
push %rbp
mov %rsp,%rbp
ud2
.endfn __asan_store8,globl
__asan_store16:
push %rbp
mov %rsp,%rbp
ud2
.endfn __asan_store16,globl
__asan_store32:
push %rbp
mov %rsp,%rbp
ud2
.endfn __asan_store32,globl

View file

@ -4,6 +4,7 @@
PKGS += LIBC PKGS += LIBC
LIBC_HDRS = $(filter %.h,$(LIBC_FILES)) LIBC_HDRS = $(filter %.h,$(LIBC_FILES))
LIBC_INCS = $(filter %.inc,$(LIBC_FILES))
LIBC_FILES := $(wildcard libc/*) LIBC_FILES := $(wildcard libc/*)
LIBC_CHECKS = $(LIBC_HDRS:%=o/$(MODE)/%.ok) LIBC_CHECKS = $(LIBC_HDRS:%=o/$(MODE)/%.ok)

View file

@ -48,7 +48,6 @@ static int PrintBacktraceUsingAddr2line(int fd, const struct StackFrame *bp) {
struct Garbages *garbage; struct Garbages *garbage;
sigset_t chldmask, savemask; sigset_t chldmask, savemask;
const struct StackFrame *frame; const struct StackFrame *frame;
struct sigaction ignore, saveint, savequit;
const char *debugbin, *p1, *p2, *p3, *addr2line; const char *debugbin, *p1, *p2, *p3, *addr2line;
char buf[kBacktraceBufSize], *argv[kBacktraceMaxFrames]; char buf[kBacktraceBufSize], *argv[kBacktraceMaxFrames];
if (IsOpenbsd()) return -1; if (IsOpenbsd()) return -1;
@ -77,18 +76,11 @@ static int PrintBacktraceUsingAddr2line(int fd, const struct StackFrame *bp) {
j += uint64toarray_radix16(addr - 1, buf + j) + 1; j += uint64toarray_radix16(addr - 1, buf + j) + 1;
} }
argv[i++] = NULL; argv[i++] = NULL;
ignore.sa_flags = 0;
ignore.sa_handler = SIG_IGN;
sigemptyset(&ignore.sa_mask);
sigaction(SIGINT, &ignore, &saveint);
sigaction(SIGQUIT, &ignore, &savequit);
sigemptyset(&chldmask); sigemptyset(&chldmask);
sigaddset(&chldmask, SIGCHLD); sigaddset(&chldmask, SIGCHLD);
sigprocmask(SIG_BLOCK, &chldmask, &savemask); sigprocmask(SIG_BLOCK, &chldmask, &savemask);
pipe(pipefds); pipe(pipefds);
if (!(pid = vfork())) { if (!(pid = vfork())) {
sigaction(SIGINT, &saveint, NULL);
sigaction(SIGQUIT, &savequit, NULL);
sigprocmask(SIG_SETMASK, &savemask, NULL); sigprocmask(SIG_SETMASK, &savemask, NULL);
dup2(pipefds[1], 1); dup2(pipefds[1], 1);
close(pipefds[0]); close(pipefds[0]);
@ -124,8 +116,6 @@ static int PrintBacktraceUsingAddr2line(int fd, const struct StackFrame *bp) {
if (errno == EINTR) continue; if (errno == EINTR) continue;
return -1; return -1;
} }
sigaction(SIGINT, &saveint, NULL);
sigaction(SIGQUIT, &savequit, NULL);
sigprocmask(SIG_SETMASK, &savemask, NULL); sigprocmask(SIG_SETMASK, &savemask, NULL);
if (WIFEXITED(ws) && !WEXITSTATUS(ws)) { if (WIFEXITED(ws) && !WEXITSTATUS(ws)) {
return 0; return 0;

View file

@ -25,19 +25,30 @@
/** /**
* Finds full executable path in overridable way. * Finds full executable path in overridable way.
*
* This is a higher level version of the commandv() function. Programs
* that spawn subprocesses can use this function to determine the path
* at startup.
*
* @param var is environment variable which may be used to override
* PATH search, and it can force a NULL result if it's empty
* @param cmd is name of program, which is returned asap if it's an
* absolute path
* @return pointer to exe path string, or NULL if it couldn't be found
* or the environment variable was empty; noting that the caller
* should copy this string before saving it
*/ */
nodiscard char *commandvenv(const char *var, const char *cmd) { const char *commandvenv(const char *var, const char *cmd) {
const char *exepath; const char *exepath;
char pathbuf[PATH_MAX]; static char pathbuf[PATH_MAX];
if (*cmd == '/' || *cmd == '\\') return cmd;
if ((exepath = getenv(var))) { if ((exepath = getenv(var))) {
if (!isempty(exepath) && access(exepath, X_OK) != -1) { if (isempty(exepath)) return NULL;
return strdup(exepath); if (access(exepath, X_OK) != -1) {
return exepath;
} else { } else {
return NULL; return NULL;
} }
} else if ((exepath = commandv(cmd, pathbuf))) {
return strdup(exepath);
} else {
return NULL;
} }
return commandv(cmd, pathbuf);
} }

View file

@ -40,7 +40,7 @@ void memsummary(int); /* light version of same thing */
uint16_t getttycols(uint16_t); uint16_t getttycols(uint16_t);
int getttysize(int, struct winsize *) paramsnonnull(); int getttysize(int, struct winsize *) paramsnonnull();
bool IsTerminalInarticulate(void) nosideeffect; bool IsTerminalInarticulate(void) nosideeffect;
char *commandvenv(const char *, const char *) nodiscard; const char *commandvenv(const char *, const char *);
const char *GetAddr2linePath(void); const char *GetAddr2linePath(void);
const char *GetGdbPath(void); const char *GetGdbPath(void);

View file

@ -28,7 +28,6 @@ LIBC_LOG_A_CHECKS = \
LIBC_LOG_A_DIRECTDEPS = \ LIBC_LOG_A_DIRECTDEPS = \
LIBC_ALG \ LIBC_ALG \
LIBC_CALLS \ LIBC_CALLS \
LIBC_CALLS_HEFTY \
LIBC_ELF \ LIBC_ELF \
LIBC_FMT \ LIBC_FMT \
LIBC_INTRIN \ LIBC_INTRIN \

View file

@ -17,9 +17,11 @@
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "libc/calls/calls.h" #include "libc/calls/calls.h"
#include "libc/fmt/itoa.h"
#include "libc/log/color.internal.h" #include "libc/log/color.internal.h"
#include "libc/log/internal.h" #include "libc/log/internal.h"
#include "libc/runtime/runtime.h" #include "libc/runtime/runtime.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/fileno.h" #include "libc/sysv/consts/fileno.h"
/** /**
@ -29,6 +31,18 @@
* @see __start_fatal_ndebug() * @see __start_fatal_ndebug()
*/ */
relegated void __start_fatal(const char *file, int line) { relegated void __start_fatal(const char *file, int line) {
dprintf(STDERR_FILENO, "%s%s%s%s:%s:%d:%s%s: ", CLS, RED, "error", BLUE1, char s[16 + 16 + 16 + 16 + PATH_MAX + 16 + NAME_MAX + 16], *p;
file, line, program_invocation_short_name, RESET); p = stpcpy(s, CLS);
p = stpcpy(p, RED);
p = stpcpy(p, "error");
p = stpcpy(p, BLUE1);
p = stpcpy(p, ":");
p = stpcpy(p, file);
p = stpcpy(p, ":");
p += int64toarray_radix10(line, p);
p = stpcpy(p, ":");
p = stpcpy(p, program_invocation_short_name);
p = stpcpy(p, RESET);
p = stpcpy(p, ": ");
write(2, s, p - s);
} }

View file

@ -33,6 +33,9 @@
.macro .text.exit .macro .text.exit
.section .text.exit,"ax",@progbits .section .text.exit,"ax",@progbits
.endm .endm
.macro .text.syscall
.section .text.syscall,"ax",@progbits
.endm
.macro .firstclass .macro .firstclass
.section .text.hot,"ax",@progbits .section .text.hot,"ax",@progbits
.endm .endm

View file

@ -18,8 +18,8 @@
*/ */
#include "libc/macros.h" #include "libc/macros.h"
/ Half size of level 3 cache in bytes.
.initbss 202,_init_kHalfCache3 .initbss 202,_init_kHalfCache3
/ Half size of level 3 cache in bytes.
kHalfCache3: kHalfCache3:
.quad 0 .quad 0
.endobj kHalfCache3,globl .endobj kHalfCache3,globl

View file

@ -3,6 +3,8 @@
#if !(__ASSEMBLER__ + __LINKER__ + 0) #if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_ COSMOPOLITAN_C_START_
extern long kHalfCache3;
void imapxlatab(void *); void imapxlatab(void *);
void insertionsort(int32_t *, size_t); void insertionsort(int32_t *, size_t);

View file

@ -8,6 +8,7 @@ LIBC_NEXGEN32E = $(LIBC_NEXGEN32E_A_DEPS) $(LIBC_NEXGEN32E_A)
LIBC_NEXGEN32E_A = o/$(MODE)/libc/nexgen32e/nexgen32e.a LIBC_NEXGEN32E_A = o/$(MODE)/libc/nexgen32e/nexgen32e.a
LIBC_NEXGEN32E_A_FILES := $(wildcard libc/nexgen32e/*) LIBC_NEXGEN32E_A_FILES := $(wildcard libc/nexgen32e/*)
LIBC_NEXGEN32E_A_HDRS = $(filter %.h,$(LIBC_NEXGEN32E_A_FILES)) LIBC_NEXGEN32E_A_HDRS = $(filter %.h,$(LIBC_NEXGEN32E_A_FILES))
LIBC_NEXGEN32E_A_INCS = $(filter %.inc,$(LIBC_NEXGEN32E_A_FILES))
LIBC_NEXGEN32E_A_SRCS_A = $(filter %.s,$(LIBC_NEXGEN32E_A_FILES)) LIBC_NEXGEN32E_A_SRCS_A = $(filter %.s,$(LIBC_NEXGEN32E_A_FILES))
LIBC_NEXGEN32E_A_SRCS_S = $(filter %.S,$(LIBC_NEXGEN32E_A_FILES)) LIBC_NEXGEN32E_A_SRCS_S = $(filter %.S,$(LIBC_NEXGEN32E_A_FILES))
LIBC_NEXGEN32E_A_SRCS_C = $(filter %.c,$(LIBC_NEXGEN32E_A_FILES)) LIBC_NEXGEN32E_A_SRCS_C = $(filter %.c,$(LIBC_NEXGEN32E_A_FILES))
@ -49,6 +50,7 @@ o/$(MODE)/libc/nexgen32e/tinystrncmp.ncabi.o: \
LIBC_NEXGEN32E_LIBS = $(foreach x,$(LIBC_NEXGEN32E_ARTIFACTS),$($(x))) LIBC_NEXGEN32E_LIBS = $(foreach x,$(LIBC_NEXGEN32E_ARTIFACTS),$($(x)))
LIBC_NEXGEN32E_SRCS = $(foreach x,$(LIBC_NEXGEN32E_ARTIFACTS),$($(x)_SRCS)) LIBC_NEXGEN32E_SRCS = $(foreach x,$(LIBC_NEXGEN32E_ARTIFACTS),$($(x)_SRCS))
LIBC_NEXGEN32E_HDRS = $(foreach x,$(LIBC_NEXGEN32E_ARTIFACTS),$($(x)_HDRS)) LIBC_NEXGEN32E_HDRS = $(foreach x,$(LIBC_NEXGEN32E_ARTIFACTS),$($(x)_HDRS))
LIBC_NEXGEN32E_INCS = $(foreach x,$(LIBC_NEXGEN32E_ARTIFACTS),$($(x)_INCS))
LIBC_NEXGEN32E_CHECKS = $(foreach x,$(LIBC_NEXGEN32E_ARTIFACTS),$($(x)_CHECKS)) LIBC_NEXGEN32E_CHECKS = $(foreach x,$(LIBC_NEXGEN32E_ARTIFACTS),$($(x)_CHECKS))
LIBC_NEXGEN32E_OBJS = $(foreach x,$(LIBC_NEXGEN32E_ARTIFACTS),$($(x)_OBJS)) LIBC_NEXGEN32E_OBJS = $(foreach x,$(LIBC_NEXGEN32E_ARTIFACTS),$($(x)_OBJS))
$(LIBC_NEXGEN32E_OBJS): $(BUILD_FILES) libc/nexgen32e/nexgen32e.mk $(LIBC_NEXGEN32E_OBJS): $(BUILD_FILES) libc/nexgen32e/nexgen32e.mk

View file

@ -1,100 +0,0 @@
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi
Copyright 2020 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/nexgen32e/macros.h"
#include "libc/nexgen32e/x86feature.h"
#include "libc/macros.h"
/ Mutates string to uppercase roman characters.
/
/ @param RDI points to non-const NUL-terminated string
/ @return RAX will be original RDI
/ @note 10x faster than C
strtoupper:
mov $'A-'a,%edx # adding this uppers
mov $'a|'z<<8,%ecx # uint8_t range a..z
jmp strcaseconv
.endfn strtoupper,globl
/ Mutates string to lowercase roman characters.
/
/ @param RDI points to non-const NUL-terminated string
/ @return RAX will be original RDI
/ @note 10x faster than C
strtolower:
mov $'a-'A,%edx # adding this lowers
mov $'A|'Z<<8,%ecx # uint8_t range A..Z
/ 𝑠𝑙𝑖𝑑𝑒
.endfn strtolower,globl
/ Support code for strtolower() and strtoupper().
/
/ @param RDI points to non-const NUL-terminated string
/ @param CL defines start of character range to mutate
/ @param CH defines end of character range to mutate
/ @param DL is added to each DIL ∈ [CL,CH]
/ @return RAX will be original RDI
strcaseconv:
.leafprologue
.profilable
mov %rdi,%rsi
0: testb $15,%sil # is it aligned?
#if X86_NEED(SSE4_2)
jz .Lsse4
#else
jnz 1f
testb X86_HAVE(SSE4_2)+kCpuids(%rip)
jnz .Lsse4 # is it nehalem?
#endif
1: lodsb # AL = *RSI++
test %al,%al # is it NUL?
jz 3f
cmp %cl,%al # is it in range?
jb 0b
cmp %ch,%al
ja 0b
add %dl,-1(%rsi)
jmp 0b
.Lsse4: movd %ecx,%xmm1 # XMM1 = ['A,'Z,0,0,...]
movd %edx,%xmm2 # XMM2 = ['a-'A,'a-'A,...]
pbroadcastb %xmm2
xor %ecx,%ecx
2: movdqa (%rsi,%rcx),%xmm3
/ 0:index of the LEAST significant, set, bit is used
/ regardless of corresponding input element validity
/ intres2 is returned in least significant bits of xmm0
/ 1:index of the MOST significant, set, bit is used
/ regardless of corresponding input element validity
/ each bit of intres2 is expanded to byte/word
/ 0:negation of intres1 is for all 16 (8) bits
/ 1:negation of intres1 is masked by reg/mem validity
/ intres1 is negated (1s complement)
/ mode{equalany,ranges,equaleach,equalordered}
/ issigned
/ is16bit
/ u
pcmpistrm $0b01000100,%xmm3,%xmm1 # XMM0 8-bit byte mask
pand %xmm2,%xmm0 # won't mask after NUL
paddb %xmm0,%xmm3
movdqa %xmm3,(%rsi,%rcx)
lea 16(%rcx),%rcx
jnz 2b # PCMPISTRM found NUL
3: mov %rdi,%rax
.leafepilogue
.endfn strcaseconv
.source __FILE__

View file

@ -21,71 +21,6 @@
#include "libc/macros.h" #include "libc/macros.h"
.source __FILE__ .source __FILE__
/ Returns pointer to first instance of character.
/
/ @param rdi is a non-null NUL-terminated string pointer
/ @param esi is the search byte
/ @return rax points to character, or to NUL byte if not found
/ @note this won't return NULL if search character is NUL
strchrnul:
.leafprologue
.profilable
or $-1,%r9
jmp 0f
.endfn strchrnul,globl
/ Returns pointer to first instance of character, the BSD way.
/
/ @param rdi is a non-null NUL-terminated string pointer
/ @param esi is the search byte
/ @return rax points to first result, or NULL if not found
/ @note this won't return NULL if search character is NUL
index: nop
/ 𝑠𝑙𝑖𝑑𝑒
.endfn index,globl
/ Returns pointer to first instance of character.
/
/ @param rdi is a non-null NUL-terminated string pointer
/ @param esi is the search byte
/ @return rax points to first result, or NULL if not found
/ @note this won't return NULL if search character is NUL
/ @asyncsignalsafe
strchr: .leafprologue
.profilable
xor %r9d,%r9d
0: movzbl %sil,%edx
or $-1,%rsi
xor %r8,%r8
jmp strsak
.endfn strchr,globl
/ Returns pointer to first instance of character in range.
/
/ @param rdi is a non-null pointer to memory
/ @param esi is the search byte
/ @return rax points to byte if found, or else undefined behavior
rawmemchr:
or $-1,%rdx
/ 𝑠𝑙𝑖𝑑𝑒
.endfn rawmemchr,globl
/ Returns pointer to first instance of character in range.
/
/ @param rdi is a non-null pointer to memory
/ @param esi is the search byte
/ @param rdx is length of memory in bytes
/ @return rax points to byte if found or NULL
/ @asyncsignalsafe
memchr: .leafprologue
.profilable
xchg %rsi,%rdx
mov %dl,%dh
xor %r8,%r8
xor %r10,%r10
jmp strsak
.endfn memchr,globl
/ Returns length of NUL-terminated string w/ security blankets. / Returns length of NUL-terminated string w/ security blankets.
/ /
/ This is like strnlen() except it'll return 0 if (1) RDI is NULL / This is like strnlen() except it'll return 0 if (1) RDI is NULL
@ -102,24 +37,13 @@ strnlen_s:
test %rdi,%rdi test %rdi,%rdi
jnz 0f jnz 0f
.leafepilogue .leafepilogue
.endfn strnlen_s,globl
/ Returns length of NUL-terminated memory, with limit.
/
/ @param rdi is non-null memory
/ @param rsi is the maximum number of bytes to consider
/ @return rax is the number of bytes, excluding the NUL
/ @asyncsignalsafe
strnlen:.leafprologue
.profilable
or $-1,%r10
0: xor %edx,%edx 0: xor %edx,%edx
mov %rdi,%r8 mov %rdi,%r8
/ 𝑠𝑙𝑖𝑑𝑒 / 𝑠𝑙𝑖𝑑𝑒
.endfn strnlen,globl .endfn strnlen_s,globl
/ Swiss army knife of string character scanning. / Swiss army knife of string character scanning.
/ Fourteen fast functions in one. / Used to be fourteen fast functions in one.
/ /
/ @param rdi is non-null string memory / @param rdi is non-null string memory
/ @param rsi is max number of bytes to consider / @param rsi is max number of bytes to consider

View file

@ -5,6 +5,7 @@ PKGS += LIBC_NT
LIBC_NT_LIBS = $(foreach x,$(LIBC_NT_ARTIFACTS),$($(x))) LIBC_NT_LIBS = $(foreach x,$(LIBC_NT_ARTIFACTS),$($(x)))
LIBC_NT_HDRS = $(foreach x,$(LIBC_NT_ARTIFACTS),$($(x)_HDRS)) LIBC_NT_HDRS = $(foreach x,$(LIBC_NT_ARTIFACTS),$($(x)_HDRS))
LIBC_NT_INCS = $(foreach x,$(LIBC_NT_ARTIFACTS),$($(x)_INCS))
LIBC_NT_SRCS = $(foreach x,$(LIBC_NT_ARTIFACTS),$($(x)_SRCS)) LIBC_NT_SRCS = $(foreach x,$(LIBC_NT_ARTIFACTS),$($(x)_SRCS))
LIBC_NT_OBJS = $(foreach x,$(LIBC_NT_ARTIFACTS),$($(x)_OBJS)) LIBC_NT_OBJS = $(foreach x,$(LIBC_NT_ARTIFACTS),$($(x)_OBJS))
LIBC_NT_CHECKS = $(foreach x,$(LIBC_NT_ARTIFACTS),$($(x)_CHECKS)) LIBC_NT_CHECKS = $(foreach x,$(LIBC_NT_ARTIFACTS),$($(x)_CHECKS))
@ -22,9 +23,8 @@ LIBC_NT_A_FILES := \
$(wildcard libc/nt/nt/*.*) \ $(wildcard libc/nt/nt/*.*) \
$(wildcard libc/nt/*) $(wildcard libc/nt/*)
LIBC_NT_A_HDRS = \ LIBC_NT_A_HDRS = $(filter %.h,$(LIBC_NT_A_FILES))
$(filter %.h,$(LIBC_NT_A_FILES)) LIBC_NT_A_INCS = $(filter %.inc,$(LIBC_NT_A_FILES))
LIBC_NT_A_CHECKS = $(patsubst %,o/$(MODE)/%.ok,$(filter %.h,$(LIBC_NT_A_HDRS))) LIBC_NT_A_CHECKS = $(patsubst %,o/$(MODE)/%.ok,$(filter %.h,$(LIBC_NT_A_HDRS)))
#─────────────────────────────────────────────────────────────────────────────── #───────────────────────────────────────────────────────────────────────────────

View file

@ -4,14 +4,15 @@
#include "libc/nt/struct/peb.h" #include "libc/nt/struct/peb.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0) #if !(__ASSEMBLER__ + __LINKER__ + 0)
/* These macros address directly into NT's TEB a.k.a. TIB */ /*
#define NtGetPeb() gs((struct NtPeb **)(0x60ULL)) * These macros address directly into NT's TEB a.k.a. TIB
#define NtGetTeb() gs((void **)(0x30)) /* %gs:0 linear address */ * Any function that does this needs the `noasan` keyword
#define NtGetPid() gs((uint32_t *)(0x40)) /* GetCurrentProcessId() */ */
#define NtGetTid() gs((uint32_t *)(0x48)) /* GetCurrentThreadId() */ #define NtGetPeb() gs((struct NtPeb **)(0x60ULL))
#define NtGetErr() gs((int *)(0x68)) #define NtGetTeb() gs((void **)(0x30)) /* %gs:0 linear address */
#define NtGetVersion() \ #define NtGetPid() gs((uint32_t *)(0x40)) /* GetCurrentProcessId() */
((NtGetPeb()->OSMajorVersion & 0xff) << 8 | NtGetPeb()->OSMinorVersion) #define NtGetTid() gs((uint32_t *)(0x48)) /* GetCurrentThreadId() */
#define NtGetErr() gs((int *)(0x68))
#define _NtGetSeh() gs((void **)(0x00)) #define _NtGetSeh() gs((void **)(0x00))
#define _NtGetStackHigh() gs((void **)(0x08)) #define _NtGetStackHigh() gs((void **)(0x08))
#define _NtGetStackLow() gs((void **)(0x10)) #define _NtGetStackLow() gs((void **)(0x10))

View file

@ -24,14 +24,14 @@ LIBC_RAND_A_CHECKS = \
$(LIBC_RAND_A_HDRS:%=o/$(MODE)/%.ok) $(LIBC_RAND_A_HDRS:%=o/$(MODE)/%.ok)
LIBC_RAND_A_DIRECTDEPS = \ LIBC_RAND_A_DIRECTDEPS = \
LIBC_STUBS \ LIBC_CALLS \
LIBC_INTRIN \
LIBC_TINYMATH \
LIBC_NEXGEN32E \ LIBC_NEXGEN32E \
LIBC_NT_KERNEL32 \ LIBC_NT_KERNEL32 \
LIBC_STR \ LIBC_STR \
LIBC_STUBS \
LIBC_SYSV \
LIBC_SYSV_CALLS \ LIBC_SYSV_CALLS \
LIBC_SYSV LIBC_TINYMATH
LIBC_RAND_A_DEPS := \ LIBC_RAND_A_DEPS := \
$(call uniq,$(foreach x,$(LIBC_RAND_A_DIRECTDEPS),$($(x)))) $(call uniq,$(foreach x,$(LIBC_RAND_A_DIRECTDEPS),$($(x))))

View file

@ -33,7 +33,7 @@ hidden extern uint64_t g_rando64;
* *
* @see rngset() * @see rngset()
*/ */
nodebuginfo uint64_t(rand64)(void) { nodebuginfo uint64_t rand64(void) {
uint64_t res; uint64_t res;
if (X86_HAVE(RDRND)) { if (X86_HAVE(RDRND)) {
res = rdrand(); res = rdrand();

View file

@ -16,11 +16,11 @@
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/calls.h"
#include "libc/nexgen32e/rdtsc.h" #include "libc/nexgen32e/rdtsc.h"
#include "libc/nt/dll.h" #include "libc/nt/dll.h"
#include "libc/nt/events.h" #include "libc/nt/events.h"
#include "libc/nt/struct/point.h" #include "libc/nt/struct/point.h"
#include "libc/nt/struct/teb.h"
#include "libc/rand/rand.h" #include "libc/rand/rand.h"
/** /**
@ -29,7 +29,7 @@
textwindows int64_t winrandish(void) { textwindows int64_t winrandish(void) {
int64_t res; int64_t res;
struct NtPoint point; struct NtPoint point;
res = ((int64_t)NtGetPid() << 17) ^ NtGetTid() ^ rdtsc(); res = ((int64_t)getpid() << 17) ^ gettid() ^ rdtsc();
/* /*
* This function is intended for older CPUs built before 2012, so * This function is intended for older CPUs built before 2012, so
* let's avoid having our CUI apps yoink USER32.DLL until we're * let's avoid having our CUI apps yoink USER32.DLL until we're

View file

@ -21,7 +21,7 @@
#include "libc/sysv/consts/sig.h" #include "libc/sysv/consts/sig.h"
#include "libc/sysv/consts/nr.h" #include "libc/sysv/consts/nr.h"
#include "libc/macros.h" #include "libc/macros.h"
.real .text.syscall
.source __FILE__ .source __FILE__
/ Terminates program abnormally. / Terminates program abnormally.

View file

@ -95,7 +95,7 @@ static int arch_prctl$freebsd(int code, int64_t addr) {
} }
} }
static int arch_prctl$xnu(int code, int64_t addr) { static textsyscall int arch_prctl$xnu(int code, int64_t addr) {
int ax; int ax;
switch (code) { switch (code) {
case ARCH_SET_GS: case ARCH_SET_GS:
@ -113,7 +113,7 @@ static int arch_prctl$xnu(int code, int64_t addr) {
} }
} }
static int arch_prctl$openbsd(int code, int64_t addr) { static textsyscall int arch_prctl$openbsd(int code, int64_t addr) {
int64_t rax; int64_t rax;
switch (code) { switch (code) {
case ARCH_GET_FS: case ARCH_GET_FS:

View file

@ -19,7 +19,7 @@
#include "libc/runtime/memtrack.h" #include "libc/runtime/memtrack.h"
#include "libc/runtime/runtime.h" #include "libc/runtime/runtime.h"
bool AreMemoryIntervalsOk(const struct MemoryIntervals *mm) { noasan bool AreMemoryIntervalsOk(const struct MemoryIntervals *mm) {
int i; int i;
for (i = 0; i < mm->i; ++i) { for (i = 0; i < mm->i; ++i) {
if (mm->p[i].y < mm->p[i].x) return false; if (mm->p[i].y < mm->p[i].x) return false;

View file

@ -17,38 +17,83 @@
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "libc/assert.h" #include "libc/assert.h"
#include "libc/bits/bits.h"
#include "libc/bits/weaken.h" #include "libc/bits/weaken.h"
#include "libc/calls/calls.h" #include "libc/dce.h"
#include "libc/log/log.h" #include "libc/log/log.h"
#include "libc/macros.h" #include "libc/macros.h"
#include "libc/mem/alloca.h" #include "libc/mem/alloca.h"
#include "libc/runtime/runtime.h" #include "libc/nt/runtime.h"
#include "libc/str/str.h" #include "libc/sysv/consts/nr.h"
#include "libc/sysv/consts/fileno.h"
static noasan size_t __assert_strlen(const char *s) {
size_t i = 0;
while (s[i]) ++i;
return i;
}
static noasan char *__assert_stpcpy(char *d, const char *s) {
size_t i;
for (i = 0;; ++i) {
if (!(d[i] = s[i])) {
return d + i;
}
}
}
static textsyscall noasan wontreturn void __assert_exit(int rc) {
if (!IsWindows()) {
asm volatile("syscall"
: /* no outputs */
: "a"(__NR_exit_group), "D"(rc)
: "memory");
unreachable;
} else {
ExitProcess(rc);
}
}
static textsyscall noasan ssize_t __assert_write(const void *data,
size_t size) {
ssize_t rc;
uint32_t wrote;
if (!IsWindows()) {
asm volatile("syscall"
: "=a"(rc)
: "0"(__NR_write), "D"(2), "S"(data), "d"(size)
: "rcx", "r11", "memory");
return rc;
} else {
if (WriteFile(GetStdHandle(kNtStdErrorHandle), data, size, &wrote, 0)) {
return wrote;
} else {
return -1;
}
}
}
/** /**
* Handles failure of assert() macro. * Handles failure of assert() macro.
*/ */
relegated void __assert_fail(const char *expr, const char *file, int line) { relegated wontreturn noasan void __assert_fail(const char *expr,
const char *file, int line) {
static bool once; static bool once;
char *msg, *p, linebuf[16]; char *msg, *p, linebuf[16];
unsigned i, exprlen, filelen; unsigned i, exprlen, filelen;
if (!once) { if (cmpxchg(&once, false, true)) {
once = true; exprlen = expr ? __assert_strlen(expr) : 0;
exprlen = expr ? strlen(expr) : 0; filelen = file ? __assert_strlen(file) : 0;
filelen = file ? strlen(file) : 0;
p = msg = alloca(MIN(512, exprlen + filelen + 64)); p = msg = alloca(MIN(512, exprlen + filelen + 64));
p = mempcpy(p, file, filelen); p = __assert_stpcpy(p, file);
p = stpcpy(p, ":"); p = __assert_stpcpy(p, ":");
if (line < 1) line = 1; if (line < 1) line = 1;
for (i = 0; line; line /= 10) linebuf[i++] = '0' + line % 10; for (i = 0; line; line /= 10) linebuf[i++] = '0' + line % 10;
while (i) *p++ = linebuf[--i]; while (i) *p++ = linebuf[--i];
p = stpcpy(p, ":"); p = __assert_stpcpy(p, ":");
p = mempcpy(p, expr, exprlen); p = __assert_stpcpy(p, expr);
p = stpcpy(p, "\r\n"); p = __assert_stpcpy(p, "\r\n");
write(STDERR_FILENO, msg, p - msg); __assert_write(msg, p - msg);
if (weaken(__die)) weaken(__die)(); if (weaken(__die)) weaken(__die)();
} }
abort(); __assert_exit(23);
unreachable;
} }

View file

@ -51,7 +51,7 @@ static struct CxaAtexitBlocks {
* @return 0 on success or nonzero w/ errno * @return 0 on success or nonzero w/ errno
* @note folks have forked libc in past just to unbloat atexit() * @note folks have forked libc in past just to unbloat atexit()
*/ */
int __cxa_atexit(void *fp, void *arg, void *pred) { noasan int __cxa_atexit(void *fp, void *arg, void *pred) {
unsigned i; unsigned i;
struct CxaAtexitBlock *b, *b2; struct CxaAtexitBlock *b, *b2;
b = __cxa_blocks.p; b = __cxa_blocks.p;
@ -83,7 +83,7 @@ int __cxa_atexit(void *fp, void *arg, void *pred) {
* *
* @param pred can be null to match all * @param pred can be null to match all
*/ */
void __cxa_finalize(void *pred) { noasan void __cxa_finalize(void *pred) {
unsigned i; unsigned i;
unsigned long mask; unsigned long mask;
struct CxaAtexitBlock *b, *b2; struct CxaAtexitBlock *b, *b2;

View file

@ -28,8 +28,8 @@
* bypassed by calling this function. However the caller is responsible * bypassed by calling this function. However the caller is responsible
* for passing the magic memory handle on Windows NT to CloseHandle(). * for passing the magic memory handle on Windows NT to CloseHandle().
*/ */
struct DirectMap __mmap(void *addr, size_t size, unsigned prot, unsigned flags, noasan struct DirectMap __mmap(void *addr, size_t size, unsigned prot,
int fd, int64_t off) { unsigned flags, int fd, int64_t off) {
if (!IsWindows()) { if (!IsWindows()) {
return (struct DirectMap){mmap$sysv(addr, size, prot, flags, fd, off), return (struct DirectMap){mmap$sysv(addr, size, prot, flags, fd, off),
kNtInvalidHandleValue}; kNtInvalidHandleValue};

View file

@ -16,6 +16,7 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "libc/calls/calls.h"
#include "libc/calls/internal.h" #include "libc/calls/internal.h"
#include "libc/nt/enum/filemapflags.h" #include "libc/nt/enum/filemapflags.h"
#include "libc/nt/enum/pageflags.h" #include "libc/nt/enum/pageflags.h"
@ -24,13 +25,15 @@
#include "libc/runtime/directmap.h" #include "libc/runtime/directmap.h"
#include "libc/sysv/consts/prot.h" #include "libc/sysv/consts/prot.h"
textwindows struct DirectMap __mmap$nt(void *addr, size_t size, unsigned prot, textwindows noasan struct DirectMap __mmap$nt(void *addr, size_t size,
int64_t handle, int64_t off) { unsigned prot, int64_t handle,
int64_t off) {
struct DirectMap dm; struct DirectMap dm;
if ((dm.maphandle = CreateFileMappingNuma( if ((dm.maphandle = CreateFileMappingNuma(
handle, &kNtIsInheritable, handle, &kNtIsInheritable,
(prot & PROT_WRITE) ? kNtPageExecuteReadwrite : kNtPageExecuteRead, (prot & PROT_WRITE) ? kNtPageExecuteReadwrite : kNtPageExecuteRead,
size >> 32, size, NULL, kNtNumaNoPreferredNode))) { handle != -1 ? 0 : size >> 32, handle != -1 ? 0 : size, NULL,
kNtNumaNoPreferredNode))) {
if (!(dm.addr = MapViewOfFileExNuma( if (!(dm.addr = MapViewOfFileExNuma(
dm.maphandle, dm.maphandle,
(prot & PROT_WRITE) (prot & PROT_WRITE)

View file

@ -19,7 +19,7 @@
#include "libc/dce.h" #include "libc/dce.h"
#include "libc/runtime/internal.h" #include "libc/runtime/internal.h"
#include "libc/macros.h" #include "libc/macros.h"
.privileged .text.syscall
.source __FILE__ .source __FILE__
/ Terminates process, ignoring destructors and atexit() handlers. / Terminates process, ignoring destructors and atexit() handlers.

View file

@ -18,7 +18,7 @@
*/ */
#include "libc/runtime/memtrack.h" #include "libc/runtime/memtrack.h"
unsigned FindMemoryInterval(const struct MemoryIntervals *mm, int x) { noasan unsigned FindMemoryInterval(const struct MemoryIntervals *mm, int x) {
unsigned l, m, r; unsigned l, m, r;
l = 0; l = 0;
r = mm->i; r = mm->i;

View file

@ -46,17 +46,18 @@
#include "libc/sysv/consts/sig.h" #include "libc/sysv/consts/sig.h"
#include "libc/sysv/errfuns.h" #include "libc/sysv/errfuns.h"
static textwindows int64_t ParseInt(char16_t **p) { static textwindows noasan char16_t *ParseInt(char16_t *p, int64_t *x) {
uint64_t x = 0; *x = 0;
while ('0' <= **p && **p <= '9') { while (*p == ' ') p++;
x *= 10; while ('0' <= *p && *p <= '9') {
x += *(*p)++ - '0'; *x *= 10;
*x += *p++ - '0';
} }
return x; return p;
} }
static noinline textwindows void ForkIo(int64_t h, void *buf, size_t n, static noinline textwindows noasan void ForkIo(int64_t h, void *buf, size_t n,
bool32 (*f)()) { bool32 (*f)()) {
char *p; char *p;
size_t i; size_t i;
uint32_t x; uint32_t x;
@ -65,41 +66,39 @@ static noinline textwindows void ForkIo(int64_t h, void *buf, size_t n,
} }
} }
static noinline textwindows void WriteAll(int64_t h, void *buf, size_t n) { static noinline textwindows noasan void WriteAll(int64_t h, void *buf,
size_t n) {
ForkIo(h, buf, n, WriteFile); ForkIo(h, buf, n, WriteFile);
} }
static noinline textwindows void ReadAll(int64_t h, void *buf, size_t n) { static textwindows noinline noasan void ReadAll(int64_t h, void *buf,
size_t n) {
ForkIo(h, buf, n, ReadFile); ForkIo(h, buf, n, ReadFile);
} }
textwindows void WinMainForked(void) { textwindows noasan void WinMainForked(void) {
int64_t h;
void *addr; void *addr;
jmp_buf jb; jmp_buf jb;
char16_t *p;
uint64_t size; uint64_t size;
uint32_t i, varlen; uint32_t i, varlen;
struct DirectMap dm; struct DirectMap dm;
int64_t reader, writer;
char16_t var[21 + 1 + 21 + 1]; char16_t var[21 + 1 + 21 + 1];
varlen = GetEnvironmentVariable(u"_FORK", var, ARRAYLEN(var)); varlen = GetEnvironmentVariable(u"_FORK", var, ARRAYLEN(var));
if (!varlen) return;
if (varlen >= ARRAYLEN(var)) ExitProcess(123);
SetEnvironmentVariable(u"_FORK", NULL); SetEnvironmentVariable(u"_FORK", NULL);
if (!varlen || varlen >= ARRAYLEN(var)) return; ParseInt(ParseInt(var, &reader), &writer);
p = var; ReadAll(reader, jb, sizeof(jb));
h = ParseInt(&p); ReadAll(reader, &_mmi.i, sizeof(_mmi.i));
if (*p++ == ' ') CloseHandle(ParseInt(&p));
ReadAll(h, jb, sizeof(jb));
ReadAll(h, &_mmi.i, sizeof(_mmi.i));
for (i = 0; i < _mmi.i; ++i) { for (i = 0; i < _mmi.i; ++i) {
ReadAll(h, &_mmi.p[i], sizeof(_mmi.p[i])); ReadAll(reader, &_mmi.p[i], sizeof(_mmi.p[i]));
addr = (void *)((uint64_t)_mmi.p[i].x << 16); addr = (void *)((uint64_t)_mmi.p[i].x << 16);
size = ((uint64_t)(_mmi.p[i].y - _mmi.p[i].x) << 16) + FRAMESIZE; size = ((uint64_t)(_mmi.p[i].y - _mmi.p[i].x) << 16) + FRAMESIZE;
if (_mmi.p[i].flags & MAP_PRIVATE) { if (_mmi.p[i].flags & MAP_PRIVATE) {
CloseHandle(_mmi.p[i].h); CloseHandle(_mmi.p[i].h);
_mmi.p[i].h = _mmi.p[i].h = __mmap$nt(addr, size, _mmi.p[i].prot, -1, 0).maphandle;
__mmap$nt(addr, size, PROT_READ | PROT_WRITE | PROT_EXEC, -1, 0) ReadAll(reader, addr, size);
.maphandle;
ReadAll(h, addr, size);
} else { } else {
MapViewOfFileExNuma( MapViewOfFileExNuma(
_mmi.p[i].h, _mmi.p[i].h,
@ -109,9 +108,9 @@ textwindows void WinMainForked(void) {
0, 0, size, addr, kNtNumaNoPreferredNode); 0, 0, size, addr, kNtNumaNoPreferredNode);
} }
} }
ReadAll(h, _edata, _end - _edata); ReadAll(reader, _edata, _end - _edata);
CloseHandle(h); CloseHandle(reader);
unsetenv("_FORK"); CloseHandle(writer);
if (weaken(__wincrash$nt)) { if (weaken(__wincrash$nt)) {
AddVectoredExceptionHandler(1, (void *)weaken(__wincrash$nt)); AddVectoredExceptionHandler(1, (void *)weaken(__wincrash$nt));
} }
@ -120,20 +119,19 @@ textwindows void WinMainForked(void) {
textwindows int fork$nt(void) { textwindows int fork$nt(void) {
jmp_buf jb; jmp_buf jb;
int i, rc, pid;
char exe[PATH_MAX]; char exe[PATH_MAX];
int64_t reader, writer; int64_t reader, writer;
char *p, buf[21 + 1 + 21 + 1]; int i, rc, pid, releaseme;
char *p, forkvar[6 + 21 + 1 + 21 + 1];
struct NtStartupInfo startinfo; struct NtStartupInfo startinfo;
struct NtProcessInformation procinfo; struct NtProcessInformation procinfo;
if ((pid = __getemptyfd()) == -1) return -1; if ((pid = releaseme = __reservefd()) == -1) return -1;
if (!setjmp(jb)) { if (!setjmp(jb)) {
if (CreatePipe(&reader, &writer, &kNtIsInheritable, 0)) { if (CreatePipe(&reader, &writer, &kNtIsInheritable, 0)) {
p = buf; p = stpcpy(forkvar, "_FORK=");
p += uint64toarray_radix10(reader, p); p += uint64toarray_radix10(reader, p);
*p++ = ' '; *p++ = ' ';
p += uint64toarray_radix10(writer, p); p += uint64toarray_radix10(writer, p);
setenv("_FORK", buf, true);
memset(&startinfo, 0, sizeof(startinfo)); memset(&startinfo, 0, sizeof(startinfo));
startinfo.cb = sizeof(struct NtStartupInfo); startinfo.cb = sizeof(struct NtStartupInfo);
startinfo.dwFlags = kNtStartfUsestdhandles; startinfo.dwFlags = kNtStartfUsestdhandles;
@ -141,8 +139,8 @@ textwindows int fork$nt(void) {
startinfo.hStdOutput = g_fds.p[1].handle; startinfo.hStdOutput = g_fds.p[1].handle;
startinfo.hStdError = g_fds.p[2].handle; startinfo.hStdError = g_fds.p[2].handle;
GetModuleFileNameA(0, exe, ARRAYLEN(exe)); GetModuleFileNameA(0, exe, ARRAYLEN(exe));
if (ntspawn(exe, g_argv, environ, &kNtIsInheritable, NULL, true, 0, NULL, if (ntspawn(exe, g_argv, environ, forkvar, &kNtIsInheritable, NULL, true,
&startinfo, &procinfo) != -1) { 0, NULL, &startinfo, &procinfo) != -1) {
CloseHandle(reader); CloseHandle(reader);
CloseHandle(procinfo.hThread); CloseHandle(procinfo.hThread);
if (weaken(__sighandrvas) && if (weaken(__sighandrvas) &&
@ -152,6 +150,7 @@ textwindows int fork$nt(void) {
g_fds.p[pid].kind = kFdProcess; g_fds.p[pid].kind = kFdProcess;
g_fds.p[pid].handle = procinfo.hProcess; g_fds.p[pid].handle = procinfo.hProcess;
g_fds.p[pid].flags = O_CLOEXEC; g_fds.p[pid].flags = O_CLOEXEC;
releaseme = -1;
} }
WriteAll(writer, jb, sizeof(jb)); WriteAll(writer, jb, sizeof(jb));
WriteAll(writer, &_mmi.i, sizeof(_mmi.i)); WriteAll(writer, &_mmi.i, sizeof(_mmi.i));
@ -167,7 +166,6 @@ textwindows int fork$nt(void) {
} else { } else {
rc = -1; rc = -1;
} }
unsetenv("_FORK");
rc = pid; rc = pid;
} else { } else {
rc = __winerr(); rc = __winerr();
@ -175,5 +173,8 @@ textwindows int fork$nt(void) {
} else { } else {
rc = 0; rc = 0;
} }
if (releaseme != -1) {
__releasefd(releaseme);
}
return rc; return rc;
} }

View file

@ -32,7 +32,7 @@ struct DosArgv {
wint_t wc; wint_t wc;
}; };
static textwindows wint_t DecodeDosArgv(const char16_t **s) { static textwindows noasan wint_t DecodeDosArgv(const char16_t **s) {
wint_t x, y; wint_t x, y;
for (;;) { for (;;) {
if (!(x = *(*s)++)) break; if (!(x = *(*s)++)) break;
@ -50,7 +50,7 @@ static textwindows wint_t DecodeDosArgv(const char16_t **s) {
return x; return x;
} }
static textwindows void AppendDosArgv(struct DosArgv *st, wint_t wc) { static textwindows noasan void AppendDosArgv(struct DosArgv *st, wint_t wc) {
uint64_t w; uint64_t w;
w = tpenc(wc); w = tpenc(wc);
do { do {
@ -78,8 +78,8 @@ static textwindows void AppendDosArgv(struct DosArgv *st, wint_t wc) {
* @see libc/runtime/ntspawn.c * @see libc/runtime/ntspawn.c
* @note kudos to Simon Tatham for figuring out quoting behavior * @note kudos to Simon Tatham for figuring out quoting behavior
*/ */
textwindows int GetDosArgv(const char16_t *cmdline, char *buf, size_t size, textwindows noasan int GetDosArgv(const char16_t *cmdline, char *buf,
char **argv, size_t max) { size_t size, char **argv, size_t max) {
bool inquote; bool inquote;
size_t i, argc, slashes, quotes; size_t i, argc, slashes, quotes;
struct DosArgv st; struct DosArgv st;

View file

@ -18,6 +18,30 @@
*/ */
#include "libc/runtime/runtime.h" #include "libc/runtime/runtime.h"
#include "libc/str/str.h" #include "libc/str/str.h"
#include "libc/str/tpenc.h"
#include "libc/str/utf16.h"
static textwindows noasan axdx_t Recode16to8(char *dst, size_t dstsize,
const char16_t *src) {
axdx_t r;
uint64_t w;
wint_t x, y;
for (r.ax = 0, r.dx = 0;;) {
if (!(x = src[r.dx++])) break;
if (IsUtf16Cont(x)) continue;
if (!IsUcs2(x)) {
if (!(y = src[r.dx++])) break;
x = MergeUtf16(x, y);
}
for (w = tpenc(x); w && r.ax + 1 < dstsize; w >>= 8) {
dst[r.ax++] = w & 0xFF;
}
}
if (r.ax < dstsize) {
dst[r.ax] = 0;
}
return r;
}
/** /**
* Transcodes NT environment variable block from UTF-16 to UTF-8. * Transcodes NT environment variable block from UTF-16 to UTF-8.
@ -29,8 +53,8 @@
* @param max is the pointer count capacity of envp * @param max is the pointer count capacity of envp
* @return number of variables decoded, excluding NULL-terminator * @return number of variables decoded, excluding NULL-terminator
*/ */
textwindows int GetDosEnviron(const char16_t *env, char *buf, size_t size, textwindows noasan int GetDosEnviron(const char16_t *env, char *buf,
char **envp, size_t max) { size_t size, char **envp, size_t max) {
int i; int i;
axdx_t r; axdx_t r;
i = 0; i = 0;
@ -38,7 +62,7 @@ textwindows int GetDosEnviron(const char16_t *env, char *buf, size_t size,
--size; --size;
while (*env) { while (*env) {
if (i + 1 < max) envp[i++] = buf; if (i + 1 < max) envp[i++] = buf;
r = tprecode16to8(buf, size, env); r = Recode16to8(buf, size, env);
size -= r.ax + 1; size -= r.ax + 1;
buf += r.ax + 1; buf += r.ax + 1;
env += r.dx; env += r.dx;

View file

@ -24,7 +24,8 @@
#include "libc/str/str.h" #include "libc/str/str.h"
#include "libc/sysv/errfuns.h" #include "libc/sysv/errfuns.h"
static void RemoveMemoryIntervals(struct MemoryIntervals *mm, int i, int n) { static noasan void RemoveMemoryIntervals(struct MemoryIntervals *mm, int i,
int n) {
assert(i >= 0); assert(i >= 0);
assert(i + n <= mm->i); assert(i + n <= mm->i);
memcpy(mm->p + i, mm->p + i + n, memcpy(mm->p + i, mm->p + i + n,
@ -32,7 +33,7 @@ static void RemoveMemoryIntervals(struct MemoryIntervals *mm, int i, int n) {
mm->i -= n; mm->i -= n;
} }
static void CreateMemoryInterval(struct MemoryIntervals *mm, int i) { static noasan void CreateMemoryInterval(struct MemoryIntervals *mm, int i) {
assert(i >= 0); assert(i >= 0);
assert(i <= mm->i); assert(i <= mm->i);
assert(mm->i < ARRAYLEN(mm->p)); assert(mm->i < ARRAYLEN(mm->p));
@ -41,7 +42,7 @@ static void CreateMemoryInterval(struct MemoryIntervals *mm, int i) {
++mm->i; ++mm->i;
} }
static int PunchHole(struct MemoryIntervals *mm, int x, int y, int i) { static noasan int PunchHole(struct MemoryIntervals *mm, int x, int y, int i) {
if (mm->i == ARRAYLEN(mm->p)) return enomem(); if (mm->i == ARRAYLEN(mm->p)) return enomem();
CreateMemoryInterval(mm, i); CreateMemoryInterval(mm, i);
mm->p[i].y = x - 1; mm->p[i].y = x - 1;
@ -49,8 +50,8 @@ static int PunchHole(struct MemoryIntervals *mm, int x, int y, int i) {
return 0; return 0;
} }
int ReleaseMemoryIntervals(struct MemoryIntervals *mm, int x, int y, noasan int ReleaseMemoryIntervals(struct MemoryIntervals *mm, int x, int y,
void wincb(struct MemoryIntervals *, int, int)) { void wf(struct MemoryIntervals *, int, int)) {
unsigned l, r; unsigned l, r;
assert(y >= x); assert(y >= x);
assert(AreMemoryIntervalsOk(mm)); assert(AreMemoryIntervalsOk(mm));
@ -81,16 +82,16 @@ int ReleaseMemoryIntervals(struct MemoryIntervals *mm, int x, int y,
--r; --r;
} }
if (l <= r) { if (l <= r) {
if (IsWindows() && wincb) { if (IsWindows() && wf) {
wincb(mm, l, r); wf(mm, l, r);
} }
RemoveMemoryIntervals(mm, l, r - l + 1); RemoveMemoryIntervals(mm, l, r - l + 1);
} }
return 0; return 0;
} }
int TrackMemoryInterval(struct MemoryIntervals *mm, int x, int y, long h, noasan int TrackMemoryInterval(struct MemoryIntervals *mm, int x, int y, long h,
int prot, int flags) { int prot, int flags) {
unsigned i; unsigned i;
assert(y >= x); assert(y >= x);
assert(AreMemoryIntervalsOk(mm)); assert(AreMemoryIntervalsOk(mm));

View file

@ -3,7 +3,6 @@
#include "libc/dce.h" #include "libc/dce.h"
#include "libc/macros.h" #include "libc/macros.h"
#include "libc/nt/enum/version.h" #include "libc/nt/enum/version.h"
#include "libc/nt/struct/teb.h"
#include "libc/runtime/runtime.h" #include "libc/runtime/runtime.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0) #if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_ COSMOPOLITAN_C_START_

View file

@ -22,14 +22,14 @@
#include "libc/runtime/memtrack.h" #include "libc/runtime/memtrack.h"
#include "libc/runtime/runtime.h" #include "libc/runtime/runtime.h"
static void *GetFrameAddr(int f) { static noasan void *GetFrameAddr(int f) {
intptr_t a; intptr_t a;
a = f; a = f;
a *= FRAMESIZE; a *= FRAMESIZE;
return (void *)a; return (void *)a;
} }
void ReleaseMemoryNt(struct MemoryIntervals *mm, int l, int r) { noasan void ReleaseMemoryNt(struct MemoryIntervals *mm, int l, int r) {
int i, ok; int i, ok;
for (i = l; i <= r; ++i) { for (i = l; i <= r; ++i) {
ok = UnmapViewOfFile(GetFrameAddr(mm->p[i].x)); ok = UnmapViewOfFile(GetFrameAddr(mm->p[i].x));

View file

@ -52,13 +52,14 @@
* @param flags can have MAP_ANONYMOUS, MAP_SHARED, MAP_PRIVATE, etc. * @param flags can have MAP_ANONYMOUS, MAP_SHARED, MAP_PRIVATE, etc.
* @param fd is an open()'d file descriptor whose contents shall be * @param fd is an open()'d file descriptor whose contents shall be
* mapped, and is ignored if MAP_ANONYMOUS is specified * mapped, and is ignored if MAP_ANONYMOUS is specified
* @param offset specifies absolute byte index of fd's file for mapping, * @param off specifies absolute byte index of fd's file for mapping,
* and should be zero if MAP_ANONYMOUS is specified * should be zero if MAP_ANONYMOUS is specified, and sadly needs
* to be 64kb aligned too
* @return virtual base address of new mapping, or MAP_FAILED w/ errno * @return virtual base address of new mapping, or MAP_FAILED w/ errno
*/ */
void *mmap(void *addr, size_t size, int prot, int flags, int fd, int64_t off) { void *mmap(void *addr, size_t size, int prot, int flags, int fd, int64_t off) {
int i, x, n, a, b;
struct DirectMap dm; struct DirectMap dm;
int i, x, n, a, b, f;
if (!size) return VIP(einval()); if (!size) return VIP(einval());
if (!ALIGNED(off)) return VIP(einval()); if (!ALIGNED(off)) return VIP(einval());
if (!ALIGNED(addr)) return VIP(einval()); if (!ALIGNED(addr)) return VIP(einval());
@ -84,7 +85,12 @@ void *mmap(void *addr, size_t size, int prot, int flags, int fd, int64_t off) {
} }
addr = (void *)(intptr_t)((int64_t)x << 16); addr = (void *)(intptr_t)((int64_t)x << 16);
} }
dm = __mmap(addr, size, prot, flags | MAP_FIXED, fd, off); f = flags | MAP_FIXED;
if (IsOpenbsd() && (f & MAP_GROWSDOWN)) { /* openbsd:dubstack */
dm = __mmap(addr, size, prot, f & ~MAP_GROWSDOWN, fd, off);
if (dm.addr == MAP_FAILED) return MAP_FAILED;
}
dm = __mmap(addr, size, prot, f, fd, off);
if (dm.addr == MAP_FAILED || dm.addr != addr) { if (dm.addr == MAP_FAILED || dm.addr != addr) {
return MAP_FAILED; return MAP_FAILED;
} }

View file

@ -28,14 +28,13 @@
#define WasImported(SLOT) \ #define WasImported(SLOT) \
((void *)*SLOT && *SLOT != (void *)&missingno /* see libc/crt/crt.S */) ((void *)*SLOT && *SLOT != (void *)&missingno /* see libc/crt/crt.S */)
static privileged void __print$nt(const void *data, size_t len) { static void __print$nt(const void *data, size_t len) {
int64_t hand; int64_t hand;
char xmm[256]; char xmm[256];
uint32_t wrote; uint32_t wrote;
savexmm(xmm + 128); savexmm(xmm + 128);
hand = __imp_GetStdHandle(kNtStdErrorHandle); hand = __imp_GetStdHandle(kNtStdErrorHandle);
__imp_WriteFile(hand, data, len, &wrote, NULL); __imp_WriteFile(hand, data, len, &wrote, NULL);
__imp_FlushFileBuffers(hand);
loadxmm(xmm + 128); loadxmm(xmm + 128);
} }
@ -49,7 +48,7 @@ static privileged void __print$nt(const void *data, size_t len) {
* @param len can be computed w/ tinystrlen() * @param len can be computed w/ tinystrlen()
* @clob nothing except flags * @clob nothing except flags
*/ */
privileged void __print(const void *data, size_t len) { textsyscall void __print(const void *data, size_t len) {
int64_t ax, ordinal; int64_t ax, ordinal;
if (WasImported(__imp_WriteFile)) { if (WasImported(__imp_WriteFile)) {
__print$nt(data, len); __print$nt(data, len);
@ -68,7 +67,7 @@ privileged void __print(const void *data, size_t len) {
} }
} }
privileged void __print_string(const char *s) { void __print_string(const char *s) {
size_t n = 0; size_t n = 0;
while (s[n]) ++n; while (s[n]) ++n;
__print(s, n); __print(s, n);

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