mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-02-07 06:53:33 +00:00
finish intellisense support and sync with upstream
This commit is contained in:
commit
ec9bfd8c56
221 changed files with 2360 additions and 1439 deletions
4
.vscode/vscode.h
vendored
4
.vscode/vscode.h
vendored
|
@ -121,6 +121,7 @@ typedef struct { int ax, dx; } axdx_t;
|
|||
|
||||
#define _Vector_size(x) __attribute__(( vector_size( x ) ))
|
||||
|
||||
#define IMAGE_BASE_VIRTUAL 0x400000
|
||||
#define __SIGACTION(...) (0)
|
||||
#define VEIL(x, y) (y)
|
||||
#define STATIC_YOINK(x)
|
||||
|
@ -133,9 +134,12 @@ typedef struct { int ax, dx; } axdx_t;
|
|||
#define reverse(x, y) 0
|
||||
#define atomic_load(...) 0
|
||||
#define atomic_store(...) 0
|
||||
#define autotype(x) int
|
||||
|
||||
#define _Generic_(...) (void*)(0)
|
||||
#define _Generic(...) _Generic_
|
||||
#define _Alignas(...)
|
||||
#define _Section(...)
|
||||
|
||||
#define offsetof(x, y) 0
|
||||
#define cmpxchg(...) 0
|
||||
|
|
52
Makefile
52
Makefile
|
@ -82,17 +82,19 @@ o: o/$(MODE)/ape \
|
|||
|
||||
PKGS =
|
||||
|
||||
-include ~/.cosmo.mk #──No.1
|
||||
-include ~/.cosmo.mk
|
||||
include build/functions.mk #─┐
|
||||
include build/definitions.mk # ├──meta
|
||||
include build/config.mk # │
|
||||
include build/rules.mk # │
|
||||
include build/definitions.mk # ├──META
|
||||
include build/config.mk # │ You can build
|
||||
include build/rules.mk # │ You can topologically order
|
||||
include build/online.mk # │
|
||||
include libc/stubs/stubs.mk #─┘
|
||||
include libc/nexgen32e/nexgen32e.mk #─┐
|
||||
include libc/intrin/intrin.mk # │
|
||||
include libc/linux/linux.mk # │
|
||||
include libc/tinymath/tinymath.mk # ├──metal
|
||||
include libc/sysv/sysv.mk # ├──SYSTEM SUPPORT
|
||||
include libc/nt/nt.mk # │ You can do math
|
||||
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 libc/bits/bits.mk # │
|
||||
include libc/str/str.mk # │
|
||||
|
@ -100,23 +102,20 @@ include third_party/xed/xed.mk # │
|
|||
include third_party/zlib/zlib.mk # │
|
||||
include libc/elf/elf.mk # │
|
||||
include ape/lib/apelib.mk # │
|
||||
include ape/ape.mk #─┘
|
||||
include libc/sysv/sysv.mk #─┐
|
||||
include libc/nt/nt.mk # ├──system
|
||||
include libc/fmt/fmt.mk # │
|
||||
include libc/rand/rand.mk #─┘
|
||||
include ape/ape.mk # │
|
||||
include libc/fmt/fmt.mk #─┘
|
||||
include libc/calls/calls.mk #─┐
|
||||
include libc/runtime/runtime.mk # ├──systems
|
||||
include libc/crt/crt.mk # │
|
||||
include libc/runtime/runtime.mk # ├──SYSTEMS RUNTIME
|
||||
include libc/crt/crt.mk # │ You can issue system calls
|
||||
include libc/rand/rand.mk # │
|
||||
include libc/unicode/unicode.mk # │
|
||||
include third_party/dlmalloc/dlmalloc.mk # │
|
||||
include libc/mem/mem.mk # │
|
||||
include libc/ohmyplus/ohmyplus.mk # │
|
||||
include libc/zipos/zipos.mk # │
|
||||
include third_party/gdtoa/gdtoa.mk # │
|
||||
include third_party/dlmalloc/dlmalloc.mk #─┘
|
||||
include libc/mem/mem.mk #─┐
|
||||
include libc/ohmyplus/ohmyplus.mk # ├──DYNAMIC RUNTIME
|
||||
include libc/zipos/zipos.mk # │ You can now use stdio
|
||||
include third_party/gdtoa/gdtoa.mk # │ You can finally call malloc()
|
||||
include libc/time/time.mk # │
|
||||
include libc/alg/alg.mk # │
|
||||
include libc/calls/hefty/hefty.mk # │
|
||||
include libc/stdio/stdio.mk # │
|
||||
include third_party/f2c/f2c.mk # │
|
||||
include third_party/blas/blas.mk # │
|
||||
|
@ -132,8 +131,8 @@ include third_party/musl/musl.mk # │
|
|||
include third_party/getopt/getopt.mk # │
|
||||
include libc/libc.mk #─┘
|
||||
include libc/sock/sock.mk #─┐
|
||||
include dsp/tty/tty.mk # ├──online
|
||||
include libc/dns/dns.mk # │
|
||||
include dsp/tty/tty.mk # ├──ONLINE RUNTIME
|
||||
include libc/dns/dns.mk # │ You can communicate with the network
|
||||
include libc/crypto/crypto.mk # │
|
||||
include net/http/http.mk #─┘
|
||||
include third_party/lemon/lemon.mk
|
||||
|
@ -199,6 +198,7 @@ include test/test.mk
|
|||
OBJS = $(foreach x,$(PKGS),$($(x)_OBJS))
|
||||
SRCS = $(foreach x,$(PKGS),$($(x)_SRCS))
|
||||
HDRS = $(foreach x,$(PKGS),$($(x)_HDRS))
|
||||
INCS = $(foreach x,$(PKGS),$($(x)_INCS))
|
||||
BINS = $(foreach x,$(PKGS),$($(x)_BINS))
|
||||
TESTS = $(foreach x,$(PKGS),$($(x)_TESTS))
|
||||
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))))
|
||||
$(file >$@) $(foreach x,$(SRCS),$(file >>$@,$(x)))
|
||||
|
||||
o/$(MODE)/hdrs.txt: o/$(MODE)/.x $(MAKEFILES) $(call uniq,$(foreach x,$(HDRS),$(dir $(x))))
|
||||
$(file >$@) $(foreach x,$(HDRS),$(file >>$@,$(x)))
|
||||
o/$(MODE)/hdrs.txt: o/$(MODE)/.x $(MAKEFILES) $(call uniq,$(foreach x,$(HDRS) $(INCS),$(dir $(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
|
||||
|
||||
TAGS: o/$(MODE)/srcs.txt $(SRCS)
|
||||
|
@ -251,7 +251,6 @@ COSMOPOLITAN_OBJECTS = \
|
|||
APE_LIB \
|
||||
THIRD_PARTY_MUSL \
|
||||
LIBC_STDIO \
|
||||
LIBC_CALLS_HEFTY \
|
||||
THIRD_PARTY_REGEX \
|
||||
LIBC_ALG \
|
||||
LIBC_MEM \
|
||||
|
@ -351,6 +350,7 @@ o/cosmopolitan.html: \
|
|||
~/.cosmo.mk:
|
||||
$(SRCS):
|
||||
$(HDRS):
|
||||
$(INCS):
|
||||
.DEFAULT:
|
||||
@echo >&2
|
||||
@echo NOTE: deleting o/$(MODE)/depend because of an unspecified prerequisite: $@ >&2
|
||||
|
|
|
@ -282,6 +282,9 @@ SECTIONS {
|
|||
KEEP(*(.textwindowsepilogue))
|
||||
*(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.*))
|
||||
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);
|
||||
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.shnum = (.Lape.pe.sections_end - .Lape.pe.sections) / 40);
|
||||
HIDDEN(.Lidata.idtsize = idata.idtend - idata.idt);
|
||||
|
|
|
@ -33,6 +33,7 @@ APELINK = \
|
|||
|
||||
APE_FILES := $(wildcard ape/*.*)
|
||||
APE_HDRS = $(filter %.h,$(APE_FILES))
|
||||
APE_INCS = $(filter %.inc,$(APE_FILES))
|
||||
APE_SRCS = $(filter %.S,$(APE_FILES))
|
||||
APE_OBJS = $(APE_SRCS:%.S=o/$(MODE)/%.o)
|
||||
APE_DEPS = $(APE_LIB)
|
||||
|
|
|
@ -37,6 +37,8 @@ export LC_ALL=C
|
|||
MKDIR=${MKDIR:-$(command -v mkdir) -p} || exit
|
||||
|
||||
GZME=
|
||||
ASAN=
|
||||
UBSAN=
|
||||
PLAT="${1%% *}"
|
||||
FDIAGNOSTIC_COLOR=
|
||||
CCNAME=${CCNAME:-gcc}
|
||||
|
@ -87,11 +89,21 @@ for x; do
|
|||
set -- "$@" "$x" -Wa,-msse2avx -D__MNO_VZEROUPPER__
|
||||
;;
|
||||
-fsanitize=address)
|
||||
set -- "$@" "$x" -D__FSANITIZE_ADDRESS__
|
||||
ASAN="$x -D__FSANITIZE_ADDRESS__"
|
||||
;;
|
||||
-fsanitize=undefined)
|
||||
set -- "$@" "$x" -D__FSANITIZE_UNDEFINED__
|
||||
COUNTERMAND="$COUNTERMAND -fno-data-sections" # sqlite.o
|
||||
# UBSAN w/ -fdata-sections exceeds ELF's 65,280 section limit
|
||||
UBSAN="$x -fno-data-sections"
|
||||
;;
|
||||
-fno-sanitize=address)
|
||||
ASAN=
|
||||
;;
|
||||
-fno-sanitize=ubsan)
|
||||
UBSAN=
|
||||
;;
|
||||
-fno-sanitize=all)
|
||||
ASAN=
|
||||
UBSAN=
|
||||
;;
|
||||
-mnop-mcount)
|
||||
if [ "$CCNAME" = "gcc" ] && [ "$CCVERSION" -ge 6 ]; then
|
||||
|
@ -256,7 +268,7 @@ else
|
|||
done
|
||||
fi
|
||||
|
||||
set -- "$@" -no-canonical-prefixes $FDIAGNOSTIC_COLOR $COUNTERMAND
|
||||
set -- "$@" -no-canonical-prefixes $FDIAGNOSTIC_COLOR $ASAN $UBSAN $COUNTERMAND
|
||||
|
||||
if [ "$SILENT" = "0" ]; then
|
||||
printf "%s\n" "$*" >&2
|
||||
|
|
|
@ -94,8 +94,7 @@ CONFIG_CPPFLAGS += \
|
|||
CONFIG_CCFLAGS += \
|
||||
$(BACKTRACES) \
|
||||
$(FTRACE) \
|
||||
-O1 \
|
||||
-fno-inline
|
||||
-O2
|
||||
|
||||
CONFIG_COPTS += \
|
||||
$(SECURITY_BLANKETS) \
|
||||
|
|
|
@ -2,16 +2,16 @@
|
|||
#-*-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─────────────┘
|
||||
|
||||
#if [ -x "o/$MODE/tool/build/mkdeps.com" ]; then
|
||||
# set -- "o/$MODE/tool/build/mkdeps.com" "$@"
|
||||
#else
|
||||
if [ -x "o/$MODE/tool/build/mkdeps.com" ]; then
|
||||
set -- "o/$MODE/tool/build/mkdeps.com" "$@"
|
||||
else
|
||||
if [ ! -x o/build/bootstrap/mkdeps.com ]; then
|
||||
mkdir -p o/build/bootstrap &&
|
||||
cp -a build/bootstrap/mkdeps.com \
|
||||
o/build/bootstrap/mkdeps.com || exit
|
||||
fi
|
||||
set -- o/build/bootstrap/mkdeps.com "$@"
|
||||
#fi
|
||||
fi
|
||||
|
||||
if [ "$SILENT" = "0" ]; then
|
||||
printf "%s\n" "$*" >&2
|
||||
|
|
|
@ -24,9 +24,10 @@ DSP_CORE_A_CHECKS = \
|
|||
$(DSP_CORE_A_HDRS:%=o/$(MODE)/%.ok)
|
||||
|
||||
DSP_CORE_A_DIRECTDEPS = \
|
||||
LIBC_NEXGEN32E \
|
||||
LIBC_MEM \
|
||||
LIBC_INTRIN \
|
||||
LIBC_MEM \
|
||||
LIBC_NEXGEN32E \
|
||||
LIBC_STR \
|
||||
LIBC_TINYMATH \
|
||||
LIBC_STUBS
|
||||
|
||||
|
|
|
@ -30,6 +30,7 @@ DSP_SCALE_A_DIRECTDEPS = \
|
|||
LIBC_MEM \
|
||||
LIBC_NEXGEN32E \
|
||||
LIBC_RUNTIME \
|
||||
LIBC_STR \
|
||||
LIBC_STUBS \
|
||||
LIBC_STUBS \
|
||||
LIBC_TIME \
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
╚─────────────────────────────────────────────────────────────────*/
|
||||
#endif
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/hefty/copyfile.h"
|
||||
#include "libc/calls/copyfile.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/fmt/conv.h"
|
||||
#include "libc/fmt/fmt.h"
|
||||
|
|
|
@ -44,7 +44,6 @@ EXAMPLES_DIRECTDEPS = \
|
|||
LIBC_ALG \
|
||||
LIBC_BITS \
|
||||
LIBC_CALLS \
|
||||
LIBC_CALLS_HEFTY \
|
||||
LIBC_FMT \
|
||||
LIBC_INTRIN \
|
||||
LIBC_LOG \
|
||||
|
|
|
@ -154,7 +154,6 @@ static bool resized_;
|
|||
static size_t vtsize_;
|
||||
static bool artifacts_;
|
||||
static long tyn_, txn_;
|
||||
static const char* ffplay_;
|
||||
static struct Frame vf_[2];
|
||||
static struct Audio audio_;
|
||||
static const char* inputfn_;
|
||||
|
@ -1685,6 +1684,7 @@ int PlayGame(const char* romfile, const char* opt_tasfile) {
|
|||
FILE* fp;
|
||||
int devnull;
|
||||
int pipefds[2];
|
||||
const char* ffplay;
|
||||
inputfn_ = opt_tasfile;
|
||||
|
||||
if (!(fp = fopen(romfile, "rb"))) {
|
||||
|
@ -1701,7 +1701,7 @@ int PlayGame(const char* romfile, const char* opt_tasfile) {
|
|||
|
||||
// open speaker
|
||||
// todo: this needs plenty of work
|
||||
if ((ffplay_ = commandvenv("FFPLAY", "ffplay"))) {
|
||||
if ((ffplay = commandvenv("FFPLAY", "ffplay"))) {
|
||||
devnull = open("/dev/null", O_WRONLY | O_CLOEXEC);
|
||||
pipe2(pipefds, O_CLOEXEC);
|
||||
if (!(playpid_ = vfork())) {
|
||||
|
@ -1713,7 +1713,7 @@ int PlayGame(const char* romfile, const char* opt_tasfile) {
|
|||
dup2(pipefds[0], 0);
|
||||
dup2(devnull, 1);
|
||||
dup2(devnull, 2);
|
||||
execv(ffplay_, (char* const*)args);
|
||||
execv(ffplay, (char* const*)args);
|
||||
abort();
|
||||
}
|
||||
close(pipefds[0]);
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/macros.h"
|
||||
.text.syscall
|
||||
|
||||
/ Tiny Raw Linux Binary Tutorial
|
||||
/
|
||||
|
|
|
@ -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_FILES := $(wildcard libc/alg/*)
|
||||
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_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_SRCS = $(foreach x,$(LIBC_ALG_ARTIFACTS),$($(x)_SRCS))
|
||||
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_OBJS = $(foreach x,$(LIBC_ALG_ARTIFACTS),$($(x)_OBJS))
|
||||
$(LIBC_ALG_OBJS): $(BUILD_FILES) libc/alg/alg.mk
|
||||
|
|
|
@ -21,6 +21,7 @@ LIBC_CALLS_A_FILES := \
|
|||
$(wildcard libc/calls/struct/*) \
|
||||
$(wildcard libc/calls/*)
|
||||
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_C = $(filter %.c,$(LIBC_CALLS_A_FILES))
|
||||
|
||||
|
@ -43,7 +44,6 @@ LIBC_CALLS_A_DIRECTDEPS = \
|
|||
LIBC_NT_ADVAPI32 \
|
||||
LIBC_NT_KERNEL32 \
|
||||
LIBC_NT_NTDLL \
|
||||
LIBC_RAND \
|
||||
LIBC_STR \
|
||||
LIBC_STUBS \
|
||||
LIBC_SYSV_CALLS \
|
||||
|
@ -86,12 +86,11 @@ o/$(MODE)/libc/calls/mkntenvblock.o: \
|
|||
LIBC_CALLS_LIBS = $(foreach x,$(LIBC_CALLS_ARTIFACTS),$($(x)))
|
||||
LIBC_CALLS_SRCS = $(foreach x,$(LIBC_CALLS_ARTIFACTS),$($(x)_SRCS))
|
||||
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_CHECKS = $(foreach x,$(LIBC_CALLS_ARTIFACTS),$($(x)_CHECKS))
|
||||
LIBC_CALLS_OBJS = $(foreach x,$(LIBC_CALLS_ARTIFACTS),$($(x)_OBJS))
|
||||
LIBC_CALLS_TESTS = $(foreach x,$(LIBC_CALLS_ARTIFACTS),$($(x)_TESTS))
|
||||
|
||||
.PHONY: o/$(MODE)/libc/calls
|
||||
o/$(MODE)/libc/calls: \
|
||||
o/$(MODE)/libc/calls/hefty \
|
||||
$(LIBC_CALLS_CHECKS)
|
||||
o/$(MODE)/libc/calls: $(LIBC_CALLS_CHECKS)
|
||||
|
|
|
@ -42,7 +42,6 @@
|
|||
* @errors ENOENT, ENOTDIR, ENOSYS
|
||||
* @asyncsignalsafe
|
||||
* @see fchmod()
|
||||
* @syscall
|
||||
*/
|
||||
int chmod(const char *pathname, uint32_t mode) {
|
||||
if (!pathname) return efault();
|
||||
|
|
|
@ -50,7 +50,6 @@
|
|||
* errno isn't restored to its original value, to detect prec. loss
|
||||
* @see strftime(), gettimeofday()
|
||||
* @asyncsignalsafe
|
||||
* @syscall
|
||||
*/
|
||||
int clock_gettime(int clockid, struct timespec *out_ts) {
|
||||
/* TODO(jart): Just ignore O/S for MONOTONIC and measure RDTSC on start */
|
||||
|
|
|
@ -17,13 +17,15 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/nt/enum/filetype.h"
|
||||
#include "libc/nt/files.h"
|
||||
#include "libc/nt/runtime.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
textwindows int close$nt(int fd) {
|
||||
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
|
||||
* 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);
|
||||
}
|
||||
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();
|
||||
}
|
||||
|
|
|
@ -53,8 +53,7 @@ int close(int fd) {
|
|||
rc = ebadf();
|
||||
}
|
||||
if (!__vforked && fd < g_fds.n) {
|
||||
g_fds.p[fd].kind = kFdEmpty;
|
||||
g_fds.f = MIN(g_fds.f, fd);
|
||||
__releasefd(fd);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/hefty/copyfile.h"
|
||||
#include "libc/calls/copyfile.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/struct/stat.h"
|
||||
#include "libc/dce.h"
|
|
@ -1,5 +1,5 @@
|
|||
#ifndef COSMOPOLITAN_LIBC_CALLS_HEFTY_COPYFILE_H_
|
||||
#define COSMOPOLITAN_LIBC_CALLS_HEFTY_COPYFILE_H_
|
||||
#ifndef COSMOPOLITAN_LIBC_CALLS_COPYFILE_H_
|
||||
#define COSMOPOLITAN_LIBC_CALLS_COPYFILE_H_
|
||||
|
||||
#define COPYFILE_NOCLOBBER 1
|
||||
#define COPYFILE_PRESERVE_OWNER 2
|
||||
|
@ -12,4 +12,4 @@ int copyfile(const char *, const char *, int) paramsnonnull();
|
|||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_LIBC_CALLS_HEFTY_COPYFILE_H_ */
|
||||
#endif /* COSMOPOLITAN_LIBC_CALLS_COPYFILE_H_ */
|
|
@ -30,17 +30,18 @@
|
|||
*/
|
||||
textwindows int dup$nt(int oldfd, int newfd, int flags) {
|
||||
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 = __getemptyfd()) == -1) {
|
||||
return -1;
|
||||
}
|
||||
} else if (__ensurefds(newfd) != -1) {
|
||||
if (g_fds.p[newfd].kind != kFdEmpty) {
|
||||
close(newfd);
|
||||
}
|
||||
if ((newfd = __reservefd()) == -1) return -1;
|
||||
} 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();
|
||||
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;
|
||||
return newfd;
|
||||
} else {
|
||||
__releasefd(newfd);
|
||||
return __winerr();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,13 +25,14 @@ int32_t dup3$sysv(int32_t oldfd, int32_t newfd, int flags) {
|
|||
static bool once, demodernize;
|
||||
int olderr, fd;
|
||||
if (!once) {
|
||||
once = true;
|
||||
olderr = errno;
|
||||
fd = __dup3$sysv(oldfd, newfd, flags);
|
||||
if ((fd == -1 && errno == ENOSYS) || fd == __NR_dup3_linux) {
|
||||
demodernize = true;
|
||||
once = true;
|
||||
errno = olderr;
|
||||
} else {
|
||||
once = true;
|
||||
return fd;
|
||||
}
|
||||
} else if (!demodernize) {
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/assert.h"
|
||||
#include "libc/bits/bits.h"
|
||||
#include "libc/bits/weaken.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/mem/mem.h"
|
||||
|
@ -24,24 +25,29 @@
|
|||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
int __ensurefds(int fd) {
|
||||
size_t n;
|
||||
struct Fd *p;
|
||||
if (fd < g_fds.n) return fd;
|
||||
if (weaken(malloc)) {
|
||||
n = MAX(fd + 1, g_fds.n + (g_fds.n << 1));
|
||||
if ((p = weaken(malloc)(n * sizeof(*p)))) {
|
||||
memcpy(p, g_fds.p, g_fds.n * sizeof(*p));
|
||||
memset(p + g_fds.n, 0, (n - g_fds.n) * sizeof(*p));
|
||||
if (g_fds.p != g_fds.__init_p && weaken(free)) {
|
||||
weaken(free)(g_fds.p);
|
||||
size_t n1, n2;
|
||||
struct Fd *p1, *p2;
|
||||
for (;;) {
|
||||
p1 = g_fds.p;
|
||||
n1 = g_fds.n;
|
||||
if (fd < n1) return fd;
|
||||
if (weaken(malloc)) {
|
||||
n2 = MAX(fd + 1, n1 + (n1 << 1));
|
||||
if ((p2 = weaken(malloc)(n2 * sizeof(*p1)))) {
|
||||
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 {
|
||||
return enomem();
|
||||
return emfile();
|
||||
}
|
||||
} else {
|
||||
return emfile();
|
||||
}
|
||||
}
|
|
@ -47,7 +47,7 @@ textwindows int execve$nt(const char *program, char *const argv[],
|
|||
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);
|
||||
if (rc == -1) return -1;
|
||||
CloseHandle(procinfo.hThread);
|
||||
|
|
|
@ -29,7 +29,6 @@
|
|||
* @param len 0 means ‘til end of file
|
||||
* @param advice can be MADV_SEQUENTIAL, MADV_RANDOM, etc.
|
||||
* @return -1 on error
|
||||
* @syscall
|
||||
*/
|
||||
int fadvise(int fd, uint64_t offset, uint64_t len, int advice) {
|
||||
if (!IsWindows()) {
|
||||
|
|
|
@ -38,7 +38,6 @@
|
|||
* @return 0 on success, or -1 w/ errno
|
||||
* @note limited availability on rhel5 and openbsd
|
||||
* @see ftruncate()
|
||||
* @syscall
|
||||
*/
|
||||
int fallocate(int fd, int32_t mode, int64_t offset, int64_t length) {
|
||||
int rc;
|
||||
|
|
|
@ -40,7 +40,6 @@
|
|||
* @errors ENOSYS
|
||||
* @asyncsignalsafe
|
||||
* @see chmod()
|
||||
* @syscall
|
||||
*/
|
||||
int fchmod(int fd, uint32_t mode) {
|
||||
/* TODO(jart): Windows */
|
||||
|
|
|
@ -28,7 +28,6 @@
|
|||
* @return 0 on success, or -1 w/ errno
|
||||
* @see /etc/passwd for user ids
|
||||
* @see /etc/group for group ids
|
||||
* @syscall
|
||||
*/
|
||||
int fchown(int fd, uint32_t uid, uint32_t gid) {
|
||||
/* TODO(jart): Windows? */
|
||||
|
|
|
@ -29,7 +29,6 @@
|
|||
* @param arg can be FD_CLOEXEC, etc. depending
|
||||
* @return 0 on success, or -1 w/ errno
|
||||
* @asyncsignalsafe
|
||||
* @syscall
|
||||
*/
|
||||
int fcntl(int fd, int cmd, ...) {
|
||||
va_list va;
|
||||
|
|
|
@ -26,7 +26,6 @@
|
|||
* @return 0 on success, or -1 w/ errno
|
||||
* @see fsync(), sync_file_range()
|
||||
* @asyncsignalsafe
|
||||
* @syscall
|
||||
*/
|
||||
int fdatasync(int fd) {
|
||||
if (!IsWindows()) {
|
||||
|
|
|
@ -16,10 +16,7 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/bits/bits.h"
|
||||
#include "libc/bits/safemacros.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/str/str.h"
|
||||
|
||||
/**
|
||||
* Returns value of environment variable, or NULL if not found.
|
||||
|
|
|
@ -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)
|
|
@ -36,6 +36,7 @@ struct IoctlPtmGet {
|
|||
char theduxname[16];
|
||||
char workername[16];
|
||||
};
|
||||
|
||||
enum FdKind {
|
||||
kFdEmpty,
|
||||
kFdFile,
|
||||
|
@ -45,6 +46,7 @@ enum FdKind {
|
|||
kFdSerial,
|
||||
kFdZip,
|
||||
kFdEpoll,
|
||||
kFdReserved
|
||||
};
|
||||
|
||||
struct Fd {
|
||||
|
@ -71,7 +73,8 @@ hidden extern struct NtSystemInfo g_ntsysteminfo;
|
|||
hidden extern struct NtStartupInfo g_ntstartupinfo;
|
||||
hidden extern const struct NtSecurityAttributes kNtIsInheritable;
|
||||
|
||||
ssize_t __getemptyfd(void) hidden;
|
||||
int __reservefd(void) hidden;
|
||||
void __releasefd(int) hidden;
|
||||
int __ensurefds(int) hidden;
|
||||
void __removefd(int) hidden;
|
||||
|
||||
|
|
|
@ -22,7 +22,6 @@
|
|||
#include "libc/nt/console.h"
|
||||
#include "libc/nt/enum/consolemodeflags.h"
|
||||
#include "libc/nt/enum/version.h"
|
||||
#include "libc/nt/struct/teb.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
#include "libc/sysv/consts/termios.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
|
||||
/**
|
||||
* Controls settings on device.
|
||||
* @vforksafe
|
||||
*/
|
||||
int(ioctl)(int fd, uint64_t request, void *memory) {
|
||||
__IOCTL_DISPATCH(EQUAL, fd, request, memory);
|
||||
|
|
|
@ -32,7 +32,11 @@
|
|||
|
||||
#define kBufSize 1024
|
||||
#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.
|
||||
|
@ -42,19 +46,18 @@ int IsDebuggerPresent(bool force) {
|
|||
int fd, res;
|
||||
ssize_t got;
|
||||
char buf[1024];
|
||||
res = 0;
|
||||
res = false;
|
||||
if (!force) {
|
||||
if (getenv("HEISENDEBUG")) return false;
|
||||
if (IsGenuineCosmo()) return false;
|
||||
}
|
||||
if (IsWindows()) {
|
||||
res = NtGetPeb()->BeingDebugged;
|
||||
res = NtBeingDebugged();
|
||||
} else if (IsLinux()) {
|
||||
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';
|
||||
res =
|
||||
atoi(firstnonnull(strstr(buf, kGdbPid), kGdbPid) + strlen(kGdbPid));
|
||||
res = atoi(firstnonnull(strstr(buf, kPid), kPid) + strlen(kPid));
|
||||
}
|
||||
close$sysv(fd);
|
||||
}
|
||||
|
|
|
@ -29,9 +29,9 @@ forceinline typeof(PrefetchVirtualMemory) *GetPrefetchVirtualMemory(void) {
|
|||
static bool once;
|
||||
static typeof(PrefetchVirtualMemory) *PrefetchVirtualMemory_;
|
||||
if (!once) {
|
||||
once = true;
|
||||
PrefetchVirtualMemory_ = /* win8.1+ */
|
||||
GetProcAddressModule("Kernel32.dll", "PrefetchVirtualMemory");
|
||||
once = true;
|
||||
}
|
||||
return PrefetchVirtualMemory_;
|
||||
}
|
||||
|
@ -40,9 +40,9 @@ forceinline typeof(OfferVirtualMemory) *GetOfferVirtualMemory(void) {
|
|||
static bool once;
|
||||
static typeof(OfferVirtualMemory) *OfferVirtualMemory_;
|
||||
if (!once) {
|
||||
once = true;
|
||||
OfferVirtualMemory_ = /* win8.1+ */
|
||||
GetProcAddressModule("Kernel32.dll", "OfferVirtualMemory");
|
||||
once = true;
|
||||
}
|
||||
return OfferVirtualMemory_;
|
||||
}
|
||||
|
|
|
@ -37,8 +37,8 @@
|
|||
* @kudos Daniel Colascione for teaching how to quote
|
||||
* @see libc/runtime/dosargv.c
|
||||
*/
|
||||
textwindows int mkntcmdline(char16_t cmdline[ARG_MAX], const char *prog,
|
||||
char *const argv[]) {
|
||||
textwindows noasan int mkntcmdline(char16_t cmdline[ARG_MAX], const char *prog,
|
||||
char *const argv[]) {
|
||||
char *arg;
|
||||
uint64_t w;
|
||||
wint_t x, y;
|
||||
|
|
|
@ -29,21 +29,18 @@
|
|||
#include "libc/str/utf16.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;
|
||||
while (l[i] == r[i] && r[i]) ++i;
|
||||
return (l[i] & 0xff) - (r[i] & 0xff);
|
||||
}
|
||||
|
||||
static void SortStrings(char **a, size_t n) {
|
||||
char *t;
|
||||
size_t i, j;
|
||||
for (i = 1; i < n; ++i) {
|
||||
for (t = a[i], j = i; j > 0 && CompareStrings(t, a[j - 1]) < 0; --j) {
|
||||
a[j] = a[j - 1];
|
||||
}
|
||||
a[j] = t;
|
||||
static noasan void InsertString(char **a, size_t i, char *s) {
|
||||
size_t j;
|
||||
for (j = i; j > 0 && CompareStrings(s, a[j - 1]) < 0; --j) {
|
||||
a[j] = a[j - 1];
|
||||
}
|
||||
a[j] = s;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -51,19 +48,24 @@ static void SortStrings(char **a, size_t n) {
|
|||
*
|
||||
* 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
|
||||
* @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;
|
||||
uint64_t w;
|
||||
char **vars;
|
||||
wint_t x, y;
|
||||
size_t i, j, k, n, m;
|
||||
for (n = 0; envp[n];) n++;
|
||||
vars = alloca(n * sizeof(char *));
|
||||
memcpy(vars, envp, n * sizeof(char *));
|
||||
SortStrings(vars, n);
|
||||
vars = alloca((n + 1) * sizeof(char *));
|
||||
for (i = 0; i < n; ++i) InsertString(vars, i, envp[i]);
|
||||
if (extravar) InsertString(vars, n++, extravar);
|
||||
for (k = i = 0; i < n; ++i) {
|
||||
j = 0;
|
||||
do {
|
||||
|
|
|
@ -34,7 +34,7 @@ extern __msabi typeof(VirtualProtect) *const __imp_VirtualProtect;
|
|||
* @return 0 on success, or -1 w/ errno
|
||||
* @see mmap()
|
||||
*/
|
||||
int mprotect(void *addr, uint64_t len, int prot) {
|
||||
textsyscall int mprotect(void *addr, uint64_t len, int prot) {
|
||||
bool cf;
|
||||
int64_t rc;
|
||||
uint32_t oldprot;
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#include "libc/dce.h"
|
||||
#include "libc/nexgen32e/rdtsc.h"
|
||||
#include "libc/nexgen32e/x86feature.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/clock.h"
|
||||
#include "libc/time/time.h"
|
||||
|
||||
|
@ -55,19 +56,21 @@ static long double MeasureNanosPerCycle(void) {
|
|||
}
|
||||
|
||||
static void InitTime(void) {
|
||||
g_now.cpn = MeasureNanosPerCycle();
|
||||
g_now.r0 = dtime(CLOCK_REALTIME);
|
||||
g_now.k0 = rdtsc();
|
||||
g_now.once = true;
|
||||
struct Now now;
|
||||
now.cpn = MeasureNanosPerCycle();
|
||||
now.r0 = dtime(CLOCK_REALTIME);
|
||||
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();
|
||||
return ticks * g_now.cpn; /* pico scale */
|
||||
}
|
||||
|
||||
long double converttickstoseconds(uint64_t ticks) {
|
||||
return 1 / 1e9 * converttickstonanos(ticks);
|
||||
static long double ConvertTicksToSeconds(uint64_t ticks) {
|
||||
return 1 / 1e9 * ConvertTicksToNanos(ticks);
|
||||
}
|
||||
|
||||
long double nowl$sys(void) {
|
||||
|
@ -78,5 +81,5 @@ long double nowl$art(void) {
|
|||
uint64_t ticks;
|
||||
if (!g_now.once) InitTime();
|
||||
ticks = unsignedsubtract(rdtsc(), g_now.k0);
|
||||
return g_now.r0 + converttickstoseconds(ticks);
|
||||
return g_now.r0 + ConvertTicksToSeconds(ticks);
|
||||
}
|
||||
|
|
|
@ -48,6 +48,7 @@ struct SpawnBlock {
|
|||
* don't need to be passed in sorted order; however, this function
|
||||
* goes faster the closer they are to sorted
|
||||
* @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
|
||||
* be inherited; which, assuming the System V wrapper functions are
|
||||
* being used, should mean (1) all files and sockets that weren't
|
||||
|
@ -59,7 +60,7 @@ struct SpawnBlock {
|
|||
*/
|
||||
textwindows int ntspawn(
|
||||
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,
|
||||
uint32_t dwCreationFlags, const char16_t *opt_lpCurrentDirectory,
|
||||
const struct NtStartupInfo *lpStartupInfo,
|
||||
|
@ -81,7 +82,7 @@ textwindows int ntspawn(
|
|||
MapViewOfFileExNuma(handle, kNtFileMapRead | kNtFileMapWrite, 0, 0,
|
||||
blocksize, NULL, kNtNumaNoPreferredNode))) {
|
||||
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,
|
||||
opt_lpThreadAttributes, bInheritHandles,
|
||||
dwCreationFlags | kNtCreateUnicodeEnvironment,
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#ifndef COSMOPOLITAN_LIBC_CALLS_HEFTY_NTSPAWN_H_
|
||||
#define COSMOPOLITAN_LIBC_CALLS_HEFTY_NTSPAWN_H_
|
||||
#ifndef COSMOPOLITAN_LIBC_CALLS_NTSPAWN_H_
|
||||
#define COSMOPOLITAN_LIBC_CALLS_NTSPAWN_H_
|
||||
#include "libc/nt/struct/processinformation.h"
|
||||
#include "libc/nt/struct/securityattributes.h"
|
||||
#include "libc/nt/struct/startupinfo.h"
|
||||
|
@ -7,12 +7,12 @@
|
|||
COSMOPOLITAN_C_START_
|
||||
|
||||
int mkntcmdline(char16_t[ARG_MAX], const char *, char *const[]) hidden;
|
||||
int mkntenvblock(char16_t[ARG_MAX], char *const[]) hidden;
|
||||
int ntspawn(const char *, char *const[], char *const[],
|
||||
int mkntenvblock(char16_t[ARG_MAX], char *const[], const char *) hidden;
|
||||
int ntspawn(const char *, char *const[], char *const[], const char *,
|
||||
struct NtSecurityAttributes *, struct NtSecurityAttributes *,
|
||||
bool32, uint32_t, const char16_t *, const struct NtStartupInfo *,
|
||||
struct NtProcessInformation *) hidden;
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_LIBC_CALLS_HEFTY_NTSPAWN_H_ */
|
||||
#endif /* COSMOPOLITAN_LIBC_CALLS_NTSPAWN_H_ */
|
||||
|
|
|
@ -42,16 +42,7 @@ static textwindows int64_t open$nt$impl(int dirfd, const char *path,
|
|||
char16_t path16[PATH_MAX];
|
||||
if (__mkntpathat(dirfd, path, flags, path16) == -1) return -1;
|
||||
if ((handle = CreateFile(
|
||||
path16,
|
||||
(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),
|
||||
path16, flags & 0xf000000f, /* see consts.sh */
|
||||
(flags & O_EXCL)
|
||||
? kNtFileShareExclusive
|
||||
: kNtFileShareRead | kNtFileShareWrite | kNtFileShareDelete,
|
||||
|
@ -75,14 +66,6 @@ static textwindows int64_t open$nt$impl(int dirfd, const char *path,
|
|||
kNtFileFlagBackupSemantics | kNtFileFlagPosixSemantics |
|
||||
kNtFileAttributeTemporary)))),
|
||||
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;
|
||||
} else if (GetLastError() == kNtErrorFileExists &&
|
||||
((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,
|
||||
int32_t mode) {
|
||||
size_t fd;
|
||||
if ((fd = __getemptyfd()) == -1) return -1;
|
||||
int fd;
|
||||
ssize_t rc;
|
||||
if ((fd = __reservefd()) == -1) return -1;
|
||||
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 {
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -31,7 +31,7 @@
|
|||
* @asyncsignalsafe
|
||||
* @vforksafe
|
||||
*/
|
||||
nodiscard int open(const char *file, int flags, ...) {
|
||||
int open(const char *file, int flags, ...) {
|
||||
va_list va;
|
||||
unsigned mode;
|
||||
va_start(va, flags);
|
||||
|
|
|
@ -67,8 +67,8 @@ static int openanon$impl(const char *name, unsigned flags,
|
|||
}
|
||||
return fd;
|
||||
} else {
|
||||
if ((fd = __getemptyfd()) != -1 &&
|
||||
(g_fds.p[fd].handle = CreateFileA(
|
||||
if ((fd = __reservefd()) == -1) return -1;
|
||||
if ((g_fds.p[fd].handle = CreateFileA(
|
||||
pathbuf, kNtGenericRead | kNtGenericWrite, kNtFileShareExclusive,
|
||||
&kNtIsInheritable, kNtCreateAlways,
|
||||
(kNtFileAttributeNotContentIndexed | kNtFileAttributeNormal |
|
||||
|
@ -78,6 +78,7 @@ static int openanon$impl(const char *name, unsigned flags,
|
|||
g_fds.p[fd].flags = flags;
|
||||
return fd;
|
||||
} else {
|
||||
__releasefd(fd);
|
||||
return __winerr();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -37,6 +37,7 @@
|
|||
* ignored if O_CREAT or O_TMPFILE weren't passed
|
||||
* @return number needing close(), or -1 w/ errno
|
||||
* @asyncsignalsafe
|
||||
* @vforksafe
|
||||
*/
|
||||
nodiscard int openat(int dirfd, const char *file, int flags, ...) {
|
||||
va_list va;
|
||||
|
@ -47,11 +48,9 @@ nodiscard int openat(int dirfd, const char *file, int flags, ...) {
|
|||
va_end(va);
|
||||
if (!file) return efault();
|
||||
if (weaken(__zipos_open) && weaken(__zipos_parseuri)(file, &zipname) != -1) {
|
||||
if (dirfd == AT_FDCWD) {
|
||||
return weaken(__zipos_open)(&zipname, flags, mode);
|
||||
} else {
|
||||
return eopnotsupp(); /* TODO */
|
||||
}
|
||||
if (__vforked) return einval();
|
||||
if (dirfd != AT_FDCWD) return einval();
|
||||
return weaken(__zipos_open)(&zipname, flags, mode);
|
||||
} else if (!IsWindows()) {
|
||||
return openat$sysv(dirfd, file, flags, mode);
|
||||
} else {
|
||||
|
|
|
@ -58,16 +58,19 @@ textwindows int pipe$nt(int pipefd[2], unsigned flags) {
|
|||
int reader, writer;
|
||||
char16_t pipename[64];
|
||||
CreatePipeName(pipename);
|
||||
if ((reader = __reservefd()) == -1) return -1;
|
||||
if ((writer = __reservefd()) == -1) {
|
||||
__releasefd(reader);
|
||||
return -1;
|
||||
}
|
||||
if ((hin = CreateNamedPipe(pipename, kNtPipeAccessInbound,
|
||||
kNtPipeWait | kNtPipeReadmodeByte, 1, 65536, 65536,
|
||||
0, &kNtIsInheritable)) != -1) {
|
||||
if ((hout = CreateFile(pipename, kNtGenericWrite, kNtFileShareWrite,
|
||||
&kNtIsInheritable, kNtOpenExisting, 0, 0)) != -1) {
|
||||
reader = __getemptyfd();
|
||||
g_fds.p[reader].kind = kFdFile;
|
||||
g_fds.p[reader].flags = flags;
|
||||
g_fds.p[reader].handle = hin;
|
||||
writer = __getemptyfd();
|
||||
g_fds.p[writer].kind = kFdFile;
|
||||
g_fds.p[writer].flags = flags;
|
||||
g_fds.p[writer].handle = hout;
|
||||
|
@ -78,5 +81,6 @@ textwindows int pipe$nt(int pipefd[2], unsigned flags) {
|
|||
CloseHandle(hin);
|
||||
}
|
||||
}
|
||||
__releasefd(reader);
|
||||
return __winerr();
|
||||
}
|
||||
|
|
29
libc/calls/releasefd.c
Normal file
29
libc/calls/releasefd.c
Normal 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));
|
||||
}
|
|
@ -24,11 +24,16 @@
|
|||
/**
|
||||
* Finds open file descriptor slot.
|
||||
*/
|
||||
ssize_t __getemptyfd(void) {
|
||||
for (; g_fds.f < g_fds.n; ++g_fds.f) {
|
||||
if (g_fds.p[g_fds.f].kind == kFdEmpty) {
|
||||
return g_fds.f;
|
||||
int __reservefd(void) {
|
||||
int fd;
|
||||
for (;;) {
|
||||
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);
|
||||
}
|
|
@ -19,6 +19,7 @@
|
|||
#include "libc/bits/bits.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/sigbits.h"
|
||||
#include "libc/calls/struct/sigaction-freebsd.internal.h"
|
||||
#include "libc/calls/struct/sigaction-linux.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
|
||||
* @asyncsignalsafe
|
||||
* @vforksafe
|
||||
*/
|
||||
int(sigaction)(int sig, const struct sigaction *act, struct sigaction *oldact) {
|
||||
_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));
|
||||
int rc, rva, oldrva;
|
||||
struct sigaction *ap, copy;
|
||||
if (!(0 < sig && sig < NSIG) || sig == SIGKILL || sig == SIGSTOP) {
|
||||
return einval();
|
||||
}
|
||||
if (!(0 < sig && sig < NSIG)) return einval();
|
||||
if (sig == SIGKILL || sig == SIGSTOP) return einval();
|
||||
if (!act) {
|
||||
rva = (int32_t)(intptr_t)SIG_DFL;
|
||||
} else if ((intptr_t)act->sa_handler < kSigactionMinRva) {
|
||||
|
@ -142,6 +143,9 @@ int(sigaction)(int sig, const struct sigaction *act, struct sigaction *oldact) {
|
|||
} else {
|
||||
return efault();
|
||||
}
|
||||
if (__vforked && rva != (intptr_t)SIG_DFL && rva != (intptr_t)SIG_IGN) {
|
||||
return einval();
|
||||
}
|
||||
if (!IsWindows()) {
|
||||
if (!IsMetal()) {
|
||||
if (act) {
|
||||
|
@ -150,16 +154,13 @@ int(sigaction)(int sig, const struct sigaction *act, struct sigaction *oldact) {
|
|||
if (IsXnu()) {
|
||||
ap->sa_restorer = (void *)&xnutrampoline;
|
||||
ap->sa_handler = (void *)&xnutrampoline;
|
||||
} else {
|
||||
if (IsLinux()) {
|
||||
if (!(ap->sa_flags & SA_RESTORER)) {
|
||||
ap->sa_flags |= SA_RESTORER;
|
||||
ap->sa_restorer = &__restore_rt;
|
||||
}
|
||||
}
|
||||
if (rva >= kSigactionMinRva) {
|
||||
ap->sa_sigaction = (sigaction_f)__sigenter;
|
||||
} else if (IsLinux()) {
|
||||
if (!(ap->sa_flags & SA_RESTORER)) {
|
||||
ap->sa_flags |= SA_RESTORER;
|
||||
ap->sa_restorer = &__restore_rt;
|
||||
}
|
||||
} else if (rva >= kSigactionMinRva) {
|
||||
ap->sa_sigaction = (sigaction_f)__sigenter;
|
||||
}
|
||||
sigaction$cosmo2native((union metasigaction *)ap);
|
||||
} else {
|
||||
|
@ -179,7 +180,7 @@ int(sigaction)(int sig, const struct sigaction *act, struct sigaction *oldact) {
|
|||
}
|
||||
rc = 0;
|
||||
}
|
||||
if (rc != -1) {
|
||||
if (rc != -1 && !__vforked) {
|
||||
if (oldact) {
|
||||
oldrva = __sighandrvas[sig];
|
||||
oldact->sa_sigaction = (sigaction_f)(
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
#include "libc/macros.h"
|
||||
.source __FILE__
|
||||
|
||||
/ System Five signal handler.
|
||||
/ BSD signal handler.
|
||||
/
|
||||
/ This is needed because (1) a signal is allowed to trigger at
|
||||
/ just about any time, and leaf functions (e.g. memcpy) aren't
|
||||
|
|
|
@ -28,7 +28,7 @@
|
|||
* @return -1 w/ few exceptions
|
||||
* @note this is a code-size saving device
|
||||
*/
|
||||
privileged int64_t __winerr(void) {
|
||||
privileged noasan int64_t __winerr(void) {
|
||||
if (IsWindows()) {
|
||||
errno = GetLastError();
|
||||
return -1;
|
||||
|
|
|
@ -42,7 +42,6 @@ textwindows ssize_t write$nt(struct Fd *fd, const struct iovec *iov,
|
|||
iovlen ? clampio(iov[0].iov_len) : 0, &wrote,
|
||||
offset2overlap(opt_offset, &overlap))) {
|
||||
if (!wrote) assert(!SumIovecLen(iov, iovlen));
|
||||
FlushFileBuffers(fd->handle);
|
||||
return wrote;
|
||||
} else {
|
||||
return __winerr();
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "ape/relocations.h"
|
||||
#include "libc/macros.h"
|
||||
|
||||
/**
|
||||
* @fileoverview Cosmopolitan ELF-Normative Linker Script.
|
||||
|
@ -66,6 +67,9 @@ SECTIONS {
|
|||
.text : {
|
||||
*(SORT_BY_ALIGNMENT(.text.hot))
|
||||
KEEP(*(.keep.text))
|
||||
HIDDEN(__text_syscall_start = .);
|
||||
*(.text.syscall .text.syscall.*)
|
||||
HIDDEN(__text_syscall_end = .);
|
||||
*(.text .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)));
|
||||
|
|
|
@ -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_FILES := $(wildcard libc/fmt/*)
|
||||
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_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_SRCS = $(foreach x,$(LIBC_FMT_ARTIFACTS),$($(x)_SRCS))
|
||||
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_OBJS = $(foreach x,$(LIBC_FMT_ARTIFACTS),$($(x)_OBJS))
|
||||
$(LIBC_FMT_OBJS): $(BUILD_FILES) libc/fmt/fmt.mk
|
||||
|
|
|
@ -331,7 +331,7 @@ typedef uint64_t uintmax_t;
|
|||
|
||||
#ifndef nullterminated
|
||||
#if !defined(__STRICT_ANSI__) && \
|
||||
(__has_attribute(__sentinel__) || __GNUC__ >= 4)
|
||||
(__has_attribute(__sentinel__) || __GNUC__ + 0 >= 4)
|
||||
#define nullterminated(x) __attribute__((__sentinel__ x))
|
||||
#else
|
||||
#define nullterminated(x)
|
||||
|
@ -618,6 +618,7 @@ typedef uint64_t uintmax_t;
|
|||
#define textexit _Section(".text.exit") noinstrument
|
||||
#define textreal _Section(".text.real")
|
||||
#define textwindows _Section(".text.windows")
|
||||
#define textsyscall _Section(".text.syscall") noinline
|
||||
#define antiquity _Section(".text.antiquity")
|
||||
#else
|
||||
#define testonly
|
||||
|
|
|
@ -20,17 +20,19 @@
|
|||
#include "libc/bits/bits.h"
|
||||
#include "libc/bits/weaken.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/intrin/asan.internal.h"
|
||||
#include "libc/linux/exit.h"
|
||||
#include "libc/linux/write.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/macros.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/memtrack.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/sysv/consts/auxv.h"
|
||||
#include "libc/sysv/consts/map.h"
|
||||
#include "libc/sysv/consts/nr.h"
|
||||
#include "libc/sysv/consts/prot.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;
|
||||
}
|
||||
|
||||
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) {
|
||||
char *b;
|
||||
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);
|
||||
return d + n;
|
||||
default:
|
||||
i = 0;
|
||||
do {
|
||||
__builtin_memcpy(&a, s + i, 8);
|
||||
asm volatile("" ::: "memory");
|
||||
__builtin_memcpy(d + i, &a, 8);
|
||||
} while ((i += 8) + 8 <= n);
|
||||
for (; i < n; ++i) d[i] = s[i];
|
||||
return d + i;
|
||||
if (n <= 64) {
|
||||
i = 0;
|
||||
do {
|
||||
__builtin_memcpy(&a, s + i, 8);
|
||||
asm volatile("" ::: "memory");
|
||||
__builtin_memcpy(d + i, &a, 8);
|
||||
} while ((i += 8) + 8 <= n);
|
||||
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;
|
||||
}
|
||||
|
||||
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) {
|
||||
int i;
|
||||
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) {
|
||||
case kAsanHeapFree:
|
||||
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;
|
||||
if (weaken(write)) {
|
||||
if ((rc = weaken(write)(2, data, size)) != -1) {
|
||||
return 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;
|
||||
}
|
||||
}
|
||||
return LinuxWrite(2, data, size);
|
||||
}
|
||||
|
||||
static ssize_t __asan_write_string(const char *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) {
|
||||
if (weaken(__die)) weaken(__die)();
|
||||
if (weaken(abort)) weaken(abort)();
|
||||
__asan_exit(134);
|
||||
}
|
||||
|
@ -455,8 +472,6 @@ static wontreturn void __asan_report_heap_fault(void *addr, long c) {
|
|||
char *p, ibuf[21], buf[256];
|
||||
p = __asan_report_start(buf);
|
||||
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_mempcpy(p, ibuf, __asan_int2hex((intptr_t)addr, ibuf, 48));
|
||||
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) {
|
||||
char *p, ibuf[21], buf[256];
|
||||
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_mempcpy(p, ibuf, __asan_int2str(size, ibuf));
|
||||
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_poison((uintptr_t)p - 16, 16, underrun); /* see dlmalloc design */
|
||||
__asan_poison((uintptr_t)p + n, c - n, overrun);
|
||||
__asan_memset(p, 0xF9, n);
|
||||
WRITE64BE(p + c - sizeof(n), n);
|
||||
}
|
||||
return p;
|
||||
|
@ -637,7 +653,9 @@ void __asan_stack_free(char *p, size_t size, int classid) {
|
|||
__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);
|
||||
}
|
||||
|
||||
|
@ -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");
|
||||
}
|
||||
|
||||
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");
|
||||
}
|
||||
|
||||
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) {
|
||||
/* TODO(jart): Make sense of this function. */
|
||||
/* __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;
|
||||
struct DirectMap sm;
|
||||
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");
|
||||
}
|
||||
m = weaken(_mmi);
|
||||
|
@ -777,6 +805,10 @@ textstartup void __asan_init(int argc, char **argv, char **envp,
|
|||
intptr_t *auxv) {
|
||||
static bool once;
|
||||
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(__mmap);
|
||||
REQUIRE(MAP_ANONYMOUS);
|
||||
|
|
|
@ -25,7 +25,9 @@ LIBC_INTRIN_A_CHECKS = \
|
|||
|
||||
LIBC_INTRIN_A_DIRECTDEPS = \
|
||||
LIBC_STUBS \
|
||||
LIBC_NEXGEN32E
|
||||
LIBC_SYSV \
|
||||
LIBC_NEXGEN32E \
|
||||
LIBC_NT_KERNEL32
|
||||
|
||||
LIBC_INTRIN_A_DEPS := \
|
||||
$(call uniq,$(foreach x,$(LIBC_INTRIN_A_DIRECTDEPS),$($(x))))
|
||||
|
@ -46,7 +48,8 @@ $(LIBC_INTRIN_A_OBJS): \
|
|||
|
||||
o/$(MODE)/libc/intrin/asan.o: \
|
||||
OVERRIDE_CFLAGS += \
|
||||
-mgeneral-regs-only
|
||||
-mgeneral-regs-only \
|
||||
-O2
|
||||
|
||||
LIBC_INTRIN_LIBS = $(foreach x,$(LIBC_INTRIN_ARTIFACTS),$($(x)))
|
||||
LIBC_INTRIN_HDRS = $(foreach x,$(LIBC_INTRIN_ARTIFACTS),$($(x)_HDRS))
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*-*- 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 2020 Justine Alexandra Roberts Tunney │
|
||||
│ 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 │
|
||||
|
@ -16,9 +16,9 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/math.h"
|
||||
#include "libc/nexgen32e/nexgen32e.h"
|
||||
#include "libc/nt/struct/teb.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
|
||||
bool ctz(double x, double y) {
|
||||
return __builtin_islessgreater(x, y);
|
||||
textwindows noasan int NtGetVersion(void) {
|
||||
return (NtGetPeb()->OSMajorVersion & 0xff) << 8 | NtGetPeb()->OSMinorVersion;
|
||||
}
|
|
@ -29,6 +29,6 @@
|
|||
void(psrldq)(uint8_t b[16], const uint8_t a[16], unsigned long n) {
|
||||
unsigned i;
|
||||
if (n > 16) n = 16;
|
||||
memcpy(b, a + n, 16 - n);
|
||||
memset(b + (16 - n), 0, n);
|
||||
__builtin_memcpy(b, a + n, 16 - n);
|
||||
__builtin_memset(b + (16 - n), 0, n);
|
||||
}
|
||||
|
|
|
@ -25,6 +25,18 @@
|
|||
/ since ASAN has the same stylistic hugeness as UBSAN.
|
||||
/ 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:
|
||||
push $1
|
||||
jmp OnReportLoad
|
||||
|
@ -43,14 +55,18 @@ __asan_report_load8:
|
|||
.endfn __asan_report_load8,globl
|
||||
__asan_report_load16:
|
||||
push $16
|
||||
/ 𝑠𝑙𝑖𝑑𝑒
|
||||
jmp OnReportLoad
|
||||
.endfn __asan_report_load16,globl
|
||||
__asan_report_load32:
|
||||
push $32
|
||||
/ 𝑠𝑙𝑖𝑑𝑒
|
||||
.endfn __asan_report_load32,globl
|
||||
OnReportLoad:
|
||||
pop %rsi
|
||||
/ 𝑠𝑙𝑖𝑑𝑒
|
||||
.endfn OnReportLoad
|
||||
__asan_report_load_n:
|
||||
lea __asan_report_load_impl(%rip),%r11
|
||||
lea __asan_report_load(%rip),%r11
|
||||
jmp __asan_report_noreentry
|
||||
.endfn __asan_report_load_n,globl
|
||||
|
||||
|
@ -83,7 +99,7 @@ ReportStore:
|
|||
/ 𝑠𝑙𝑖𝑑𝑒
|
||||
.endfn ReportStore
|
||||
__asan_report_store_n:
|
||||
lea __asan_report_store_impl(%rip),%r11
|
||||
lea __asan_report_store(%rip),%r11
|
||||
/ 𝑠𝑙𝑖𝑑𝑒
|
||||
.endfn __asan_report_store_n,globl
|
||||
|
||||
|
@ -198,31 +214,6 @@ OnStackMalloc:
|
|||
jmp __asan_stack_malloc
|
||||
.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:
|
||||
ret
|
||||
.endfn __asan_version_mismatch_check_v8,globl
|
||||
|
@ -240,14 +231,76 @@ __asan_version_mismatch_check_v8:
|
|||
pop %rdi
|
||||
.init.end 301,_init_asan
|
||||
|
||||
.rodata.cst4
|
||||
__asan_option_detect_stack_use_after_return:
|
||||
.long 0
|
||||
.endobj __asan_option_detect_stack_use_after_return,globl
|
||||
.previous
|
||||
__asan_before_dynamic_init:
|
||||
push %rbp
|
||||
mov %rsp,%rbp
|
||||
ud2
|
||||
.endfn __asan_before_dynamic_init,globl
|
||||
|
||||
.bss
|
||||
__asan_noreentry:
|
||||
.byte 0
|
||||
.endobj __asan_noreentry
|
||||
.previous
|
||||
__asan_after_dynamic_init:
|
||||
push %rbp
|
||||
mov %rsp,%rbp
|
||||
ud2
|
||||
.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
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
PKGS += LIBC
|
||||
|
||||
LIBC_HDRS = $(filter %.h,$(LIBC_FILES))
|
||||
LIBC_INCS = $(filter %.inc,$(LIBC_FILES))
|
||||
LIBC_FILES := $(wildcard libc/*)
|
||||
LIBC_CHECKS = $(LIBC_HDRS:%=o/$(MODE)/%.ok)
|
||||
|
||||
|
|
|
@ -48,7 +48,6 @@ static int PrintBacktraceUsingAddr2line(int fd, const struct StackFrame *bp) {
|
|||
struct Garbages *garbage;
|
||||
sigset_t chldmask, savemask;
|
||||
const struct StackFrame *frame;
|
||||
struct sigaction ignore, saveint, savequit;
|
||||
const char *debugbin, *p1, *p2, *p3, *addr2line;
|
||||
char buf[kBacktraceBufSize], *argv[kBacktraceMaxFrames];
|
||||
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;
|
||||
}
|
||||
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);
|
||||
sigaddset(&chldmask, SIGCHLD);
|
||||
sigprocmask(SIG_BLOCK, &chldmask, &savemask);
|
||||
pipe(pipefds);
|
||||
if (!(pid = vfork())) {
|
||||
sigaction(SIGINT, &saveint, NULL);
|
||||
sigaction(SIGQUIT, &savequit, NULL);
|
||||
sigprocmask(SIG_SETMASK, &savemask, NULL);
|
||||
dup2(pipefds[1], 1);
|
||||
close(pipefds[0]);
|
||||
|
@ -124,8 +116,6 @@ static int PrintBacktraceUsingAddr2line(int fd, const struct StackFrame *bp) {
|
|||
if (errno == EINTR) continue;
|
||||
return -1;
|
||||
}
|
||||
sigaction(SIGINT, &saveint, NULL);
|
||||
sigaction(SIGQUIT, &savequit, NULL);
|
||||
sigprocmask(SIG_SETMASK, &savemask, NULL);
|
||||
if (WIFEXITED(ws) && !WEXITSTATUS(ws)) {
|
||||
return 0;
|
||||
|
|
|
@ -25,19 +25,30 @@
|
|||
|
||||
/**
|
||||
* 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;
|
||||
char pathbuf[PATH_MAX];
|
||||
static char pathbuf[PATH_MAX];
|
||||
if (*cmd == '/' || *cmd == '\\') return cmd;
|
||||
if ((exepath = getenv(var))) {
|
||||
if (!isempty(exepath) && access(exepath, X_OK) != -1) {
|
||||
return strdup(exepath);
|
||||
if (isempty(exepath)) return NULL;
|
||||
if (access(exepath, X_OK) != -1) {
|
||||
return exepath;
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
} else if ((exepath = commandv(cmd, pathbuf))) {
|
||||
return strdup(exepath);
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
return commandv(cmd, pathbuf);
|
||||
}
|
||||
|
|
|
@ -40,7 +40,7 @@ void memsummary(int); /* light version of same thing */
|
|||
uint16_t getttycols(uint16_t);
|
||||
int getttysize(int, struct winsize *) paramsnonnull();
|
||||
bool IsTerminalInarticulate(void) nosideeffect;
|
||||
char *commandvenv(const char *, const char *) nodiscard;
|
||||
const char *commandvenv(const char *, const char *);
|
||||
const char *GetAddr2linePath(void);
|
||||
const char *GetGdbPath(void);
|
||||
|
||||
|
|
|
@ -28,7 +28,6 @@ LIBC_LOG_A_CHECKS = \
|
|||
LIBC_LOG_A_DIRECTDEPS = \
|
||||
LIBC_ALG \
|
||||
LIBC_CALLS \
|
||||
LIBC_CALLS_HEFTY \
|
||||
LIBC_ELF \
|
||||
LIBC_FMT \
|
||||
LIBC_INTRIN \
|
||||
|
|
|
@ -17,9 +17,11 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/fmt/itoa.h"
|
||||
#include "libc/log/color.internal.h"
|
||||
#include "libc/log/internal.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/fileno.h"
|
||||
|
||||
/**
|
||||
|
@ -29,6 +31,18 @@
|
|||
* @see __start_fatal_ndebug()
|
||||
*/
|
||||
relegated void __start_fatal(const char *file, int line) {
|
||||
dprintf(STDERR_FILENO, "%s%s%s%s:%s:%d:%s%s: ", CLS, RED, "error", BLUE1,
|
||||
file, line, program_invocation_short_name, RESET);
|
||||
char s[16 + 16 + 16 + 16 + PATH_MAX + 16 + NAME_MAX + 16], *p;
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -33,6 +33,9 @@
|
|||
.macro .text.exit
|
||||
.section .text.exit,"ax",@progbits
|
||||
.endm
|
||||
.macro .text.syscall
|
||||
.section .text.syscall,"ax",@progbits
|
||||
.endm
|
||||
.macro .firstclass
|
||||
.section .text.hot,"ax",@progbits
|
||||
.endm
|
||||
|
|
|
@ -18,8 +18,8 @@
|
|||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/macros.h"
|
||||
|
||||
/ Half size of level 3 cache in bytes.
|
||||
.initbss 202,_init_kHalfCache3
|
||||
/ Half size of level 3 cache in bytes.
|
||||
kHalfCache3:
|
||||
.quad 0
|
||||
.endobj kHalfCache3,globl
|
||||
|
|
|
@ -3,6 +3,8 @@
|
|||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
extern long kHalfCache3;
|
||||
|
||||
void imapxlatab(void *);
|
||||
void insertionsort(int32_t *, size_t);
|
||||
|
||||
|
|
|
@ -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_FILES := $(wildcard libc/nexgen32e/*)
|
||||
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_S = $(filter %.S,$(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_SRCS = $(foreach x,$(LIBC_NEXGEN32E_ARTIFACTS),$($(x)_SRCS))
|
||||
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_OBJS = $(foreach x,$(LIBC_NEXGEN32E_ARTIFACTS),$($(x)_OBJS))
|
||||
$(LIBC_NEXGEN32E_OBJS): $(BUILD_FILES) libc/nexgen32e/nexgen32e.mk
|
||||
|
|
|
@ -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 (1’s 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__
|
|
@ -21,71 +21,6 @@
|
|||
#include "libc/macros.h"
|
||||
.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.
|
||||
/
|
||||
/ This is like strnlen() except it'll return 0 if (1) RDI is NULL
|
||||
|
@ -102,24 +37,13 @@ strnlen_s:
|
|||
test %rdi,%rdi
|
||||
jnz 0f
|
||||
.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
|
||||
mov %rdi,%r8
|
||||
/ 𝑠𝑙𝑖𝑑𝑒
|
||||
.endfn strnlen,globl
|
||||
.endfn strnlen_s,globl
|
||||
|
||||
/ 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 rsi is max number of bytes to consider
|
||||
|
|
|
@ -5,6 +5,7 @@ PKGS += LIBC_NT
|
|||
|
||||
LIBC_NT_LIBS = $(foreach x,$(LIBC_NT_ARTIFACTS),$($(x)))
|
||||
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_OBJS = $(foreach x,$(LIBC_NT_ARTIFACTS),$($(x)_OBJS))
|
||||
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/*)
|
||||
|
||||
LIBC_NT_A_HDRS = \
|
||||
$(filter %.h,$(LIBC_NT_A_FILES))
|
||||
|
||||
LIBC_NT_A_HDRS = $(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)))
|
||||
|
||||
#───────────────────────────────────────────────────────────────────────────────
|
||||
|
|
|
@ -4,14 +4,15 @@
|
|||
#include "libc/nt/struct/peb.h"
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
|
||||
/* These macros address directly into NT's TEB a.k.a. TIB */
|
||||
#define NtGetPeb() gs((struct NtPeb **)(0x60ULL))
|
||||
#define NtGetTeb() gs((void **)(0x30)) /* %gs:0 linear address */
|
||||
#define NtGetPid() gs((uint32_t *)(0x40)) /* GetCurrentProcessId() */
|
||||
#define NtGetTid() gs((uint32_t *)(0x48)) /* GetCurrentThreadId() */
|
||||
#define NtGetErr() gs((int *)(0x68))
|
||||
#define NtGetVersion() \
|
||||
((NtGetPeb()->OSMajorVersion & 0xff) << 8 | NtGetPeb()->OSMinorVersion)
|
||||
/*
|
||||
* These macros address directly into NT's TEB a.k.a. TIB
|
||||
* Any function that does this needs the `noasan` keyword
|
||||
*/
|
||||
#define NtGetPeb() gs((struct NtPeb **)(0x60ULL))
|
||||
#define NtGetTeb() gs((void **)(0x30)) /* %gs:0 linear address */
|
||||
#define NtGetPid() gs((uint32_t *)(0x40)) /* GetCurrentProcessId() */
|
||||
#define NtGetTid() gs((uint32_t *)(0x48)) /* GetCurrentThreadId() */
|
||||
#define NtGetErr() gs((int *)(0x68))
|
||||
#define _NtGetSeh() gs((void **)(0x00))
|
||||
#define _NtGetStackHigh() gs((void **)(0x08))
|
||||
#define _NtGetStackLow() gs((void **)(0x10))
|
||||
|
|
|
@ -24,14 +24,14 @@ LIBC_RAND_A_CHECKS = \
|
|||
$(LIBC_RAND_A_HDRS:%=o/$(MODE)/%.ok)
|
||||
|
||||
LIBC_RAND_A_DIRECTDEPS = \
|
||||
LIBC_STUBS \
|
||||
LIBC_INTRIN \
|
||||
LIBC_TINYMATH \
|
||||
LIBC_CALLS \
|
||||
LIBC_NEXGEN32E \
|
||||
LIBC_NT_KERNEL32 \
|
||||
LIBC_STR \
|
||||
LIBC_STUBS \
|
||||
LIBC_SYSV \
|
||||
LIBC_SYSV_CALLS \
|
||||
LIBC_SYSV
|
||||
LIBC_TINYMATH
|
||||
|
||||
LIBC_RAND_A_DEPS := \
|
||||
$(call uniq,$(foreach x,$(LIBC_RAND_A_DIRECTDEPS),$($(x))))
|
||||
|
|
|
@ -33,7 +33,7 @@ hidden extern uint64_t g_rando64;
|
|||
*
|
||||
* @see rngset()
|
||||
*/
|
||||
nodebuginfo uint64_t(rand64)(void) {
|
||||
nodebuginfo uint64_t rand64(void) {
|
||||
uint64_t res;
|
||||
if (X86_HAVE(RDRND)) {
|
||||
res = rdrand();
|
||||
|
|
|
@ -16,11 +16,11 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/nexgen32e/rdtsc.h"
|
||||
#include "libc/nt/dll.h"
|
||||
#include "libc/nt/events.h"
|
||||
#include "libc/nt/struct/point.h"
|
||||
#include "libc/nt/struct/teb.h"
|
||||
#include "libc/rand/rand.h"
|
||||
|
||||
/**
|
||||
|
@ -29,7 +29,7 @@
|
|||
textwindows int64_t winrandish(void) {
|
||||
int64_t res;
|
||||
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
|
||||
* let's avoid having our CUI apps yoink USER32.DLL until we're
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
#include "libc/sysv/consts/sig.h"
|
||||
#include "libc/sysv/consts/nr.h"
|
||||
#include "libc/macros.h"
|
||||
.real
|
||||
.text.syscall
|
||||
.source __FILE__
|
||||
|
||||
/ Terminates program abnormally.
|
||||
|
|
|
@ -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;
|
||||
switch (code) {
|
||||
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;
|
||||
switch (code) {
|
||||
case ARCH_GET_FS:
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
#include "libc/runtime/memtrack.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
|
||||
bool AreMemoryIntervalsOk(const struct MemoryIntervals *mm) {
|
||||
noasan bool AreMemoryIntervalsOk(const struct MemoryIntervals *mm) {
|
||||
int i;
|
||||
for (i = 0; i < mm->i; ++i) {
|
||||
if (mm->p[i].y < mm->p[i].x) return false;
|
||||
|
|
|
@ -17,38 +17,83 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/assert.h"
|
||||
#include "libc/bits/bits.h"
|
||||
#include "libc/bits/weaken.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/macros.h"
|
||||
#include "libc/mem/alloca.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/fileno.h"
|
||||
#include "libc/nt/runtime.h"
|
||||
#include "libc/sysv/consts/nr.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.
|
||||
*/
|
||||
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;
|
||||
char *msg, *p, linebuf[16];
|
||||
unsigned i, exprlen, filelen;
|
||||
if (!once) {
|
||||
once = true;
|
||||
exprlen = expr ? strlen(expr) : 0;
|
||||
filelen = file ? strlen(file) : 0;
|
||||
if (cmpxchg(&once, false, true)) {
|
||||
exprlen = expr ? __assert_strlen(expr) : 0;
|
||||
filelen = file ? __assert_strlen(file) : 0;
|
||||
p = msg = alloca(MIN(512, exprlen + filelen + 64));
|
||||
p = mempcpy(p, file, filelen);
|
||||
p = stpcpy(p, ":");
|
||||
p = __assert_stpcpy(p, file);
|
||||
p = __assert_stpcpy(p, ":");
|
||||
if (line < 1) line = 1;
|
||||
for (i = 0; line; line /= 10) linebuf[i++] = '0' + line % 10;
|
||||
while (i) *p++ = linebuf[--i];
|
||||
p = stpcpy(p, ":");
|
||||
p = mempcpy(p, expr, exprlen);
|
||||
p = stpcpy(p, "\r\n");
|
||||
write(STDERR_FILENO, msg, p - msg);
|
||||
p = __assert_stpcpy(p, ":");
|
||||
p = __assert_stpcpy(p, expr);
|
||||
p = __assert_stpcpy(p, "\r\n");
|
||||
__assert_write(msg, p - msg);
|
||||
if (weaken(__die)) weaken(__die)();
|
||||
}
|
||||
abort();
|
||||
unreachable;
|
||||
__assert_exit(23);
|
||||
}
|
||||
|
|
|
@ -51,7 +51,7 @@ static struct CxaAtexitBlocks {
|
|||
* @return 0 on success or nonzero w/ errno
|
||||
* @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;
|
||||
struct CxaAtexitBlock *b, *b2;
|
||||
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
|
||||
*/
|
||||
void __cxa_finalize(void *pred) {
|
||||
noasan void __cxa_finalize(void *pred) {
|
||||
unsigned i;
|
||||
unsigned long mask;
|
||||
struct CxaAtexitBlock *b, *b2;
|
||||
|
|
|
@ -28,8 +28,8 @@
|
|||
* bypassed by calling this function. However the caller is responsible
|
||||
* for passing the magic memory handle on Windows NT to CloseHandle().
|
||||
*/
|
||||
struct DirectMap __mmap(void *addr, size_t size, unsigned prot, unsigned flags,
|
||||
int fd, int64_t off) {
|
||||
noasan struct DirectMap __mmap(void *addr, size_t size, unsigned prot,
|
||||
unsigned flags, int fd, int64_t off) {
|
||||
if (!IsWindows()) {
|
||||
return (struct DirectMap){mmap$sysv(addr, size, prot, flags, fd, off),
|
||||
kNtInvalidHandleValue};
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/nt/enum/filemapflags.h"
|
||||
#include "libc/nt/enum/pageflags.h"
|
||||
|
@ -24,13 +25,15 @@
|
|||
#include "libc/runtime/directmap.h"
|
||||
#include "libc/sysv/consts/prot.h"
|
||||
|
||||
textwindows struct DirectMap __mmap$nt(void *addr, size_t size, unsigned prot,
|
||||
int64_t handle, int64_t off) {
|
||||
textwindows noasan struct DirectMap __mmap$nt(void *addr, size_t size,
|
||||
unsigned prot, int64_t handle,
|
||||
int64_t off) {
|
||||
struct DirectMap dm;
|
||||
if ((dm.maphandle = CreateFileMappingNuma(
|
||||
handle, &kNtIsInheritable,
|
||||
(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(
|
||||
dm.maphandle,
|
||||
(prot & PROT_WRITE)
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
#include "libc/dce.h"
|
||||
#include "libc/runtime/internal.h"
|
||||
#include "libc/macros.h"
|
||||
.privileged
|
||||
.text.syscall
|
||||
.source __FILE__
|
||||
|
||||
/ Terminates process, ignoring destructors and atexit() handlers.
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#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;
|
||||
l = 0;
|
||||
r = mm->i;
|
||||
|
|
|
@ -46,17 +46,18 @@
|
|||
#include "libc/sysv/consts/sig.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
static textwindows int64_t ParseInt(char16_t **p) {
|
||||
uint64_t x = 0;
|
||||
while ('0' <= **p && **p <= '9') {
|
||||
x *= 10;
|
||||
x += *(*p)++ - '0';
|
||||
static textwindows noasan char16_t *ParseInt(char16_t *p, int64_t *x) {
|
||||
*x = 0;
|
||||
while (*p == ' ') p++;
|
||||
while ('0' <= *p && *p <= '9') {
|
||||
*x *= 10;
|
||||
*x += *p++ - '0';
|
||||
}
|
||||
return x;
|
||||
return p;
|
||||
}
|
||||
|
||||
static noinline textwindows void ForkIo(int64_t h, void *buf, size_t n,
|
||||
bool32 (*f)()) {
|
||||
static noinline textwindows noasan void ForkIo(int64_t h, void *buf, size_t n,
|
||||
bool32 (*f)()) {
|
||||
char *p;
|
||||
size_t i;
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
textwindows void WinMainForked(void) {
|
||||
int64_t h;
|
||||
textwindows noasan void WinMainForked(void) {
|
||||
void *addr;
|
||||
jmp_buf jb;
|
||||
char16_t *p;
|
||||
uint64_t size;
|
||||
uint32_t i, varlen;
|
||||
struct DirectMap dm;
|
||||
int64_t reader, writer;
|
||||
char16_t var[21 + 1 + 21 + 1];
|
||||
varlen = GetEnvironmentVariable(u"_FORK", var, ARRAYLEN(var));
|
||||
if (!varlen) return;
|
||||
if (varlen >= ARRAYLEN(var)) ExitProcess(123);
|
||||
SetEnvironmentVariable(u"_FORK", NULL);
|
||||
if (!varlen || varlen >= ARRAYLEN(var)) return;
|
||||
p = var;
|
||||
h = ParseInt(&p);
|
||||
if (*p++ == ' ') CloseHandle(ParseInt(&p));
|
||||
ReadAll(h, jb, sizeof(jb));
|
||||
ReadAll(h, &_mmi.i, sizeof(_mmi.i));
|
||||
ParseInt(ParseInt(var, &reader), &writer);
|
||||
ReadAll(reader, jb, sizeof(jb));
|
||||
ReadAll(reader, &_mmi.i, sizeof(_mmi.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);
|
||||
size = ((uint64_t)(_mmi.p[i].y - _mmi.p[i].x) << 16) + FRAMESIZE;
|
||||
if (_mmi.p[i].flags & MAP_PRIVATE) {
|
||||
CloseHandle(_mmi.p[i].h);
|
||||
_mmi.p[i].h =
|
||||
__mmap$nt(addr, size, PROT_READ | PROT_WRITE | PROT_EXEC, -1, 0)
|
||||
.maphandle;
|
||||
ReadAll(h, addr, size);
|
||||
_mmi.p[i].h = __mmap$nt(addr, size, _mmi.p[i].prot, -1, 0).maphandle;
|
||||
ReadAll(reader, addr, size);
|
||||
} else {
|
||||
MapViewOfFileExNuma(
|
||||
_mmi.p[i].h,
|
||||
|
@ -109,9 +108,9 @@ textwindows void WinMainForked(void) {
|
|||
0, 0, size, addr, kNtNumaNoPreferredNode);
|
||||
}
|
||||
}
|
||||
ReadAll(h, _edata, _end - _edata);
|
||||
CloseHandle(h);
|
||||
unsetenv("_FORK");
|
||||
ReadAll(reader, _edata, _end - _edata);
|
||||
CloseHandle(reader);
|
||||
CloseHandle(writer);
|
||||
if (weaken(__wincrash$nt)) {
|
||||
AddVectoredExceptionHandler(1, (void *)weaken(__wincrash$nt));
|
||||
}
|
||||
|
@ -120,20 +119,19 @@ textwindows void WinMainForked(void) {
|
|||
|
||||
textwindows int fork$nt(void) {
|
||||
jmp_buf jb;
|
||||
int i, rc, pid;
|
||||
char exe[PATH_MAX];
|
||||
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 NtProcessInformation procinfo;
|
||||
if ((pid = __getemptyfd()) == -1) return -1;
|
||||
if ((pid = releaseme = __reservefd()) == -1) return -1;
|
||||
if (!setjmp(jb)) {
|
||||
if (CreatePipe(&reader, &writer, &kNtIsInheritable, 0)) {
|
||||
p = buf;
|
||||
p = stpcpy(forkvar, "_FORK=");
|
||||
p += uint64toarray_radix10(reader, p);
|
||||
*p++ = ' ';
|
||||
p += uint64toarray_radix10(writer, p);
|
||||
setenv("_FORK", buf, true);
|
||||
memset(&startinfo, 0, sizeof(startinfo));
|
||||
startinfo.cb = sizeof(struct NtStartupInfo);
|
||||
startinfo.dwFlags = kNtStartfUsestdhandles;
|
||||
|
@ -141,8 +139,8 @@ textwindows int fork$nt(void) {
|
|||
startinfo.hStdOutput = g_fds.p[1].handle;
|
||||
startinfo.hStdError = g_fds.p[2].handle;
|
||||
GetModuleFileNameA(0, exe, ARRAYLEN(exe));
|
||||
if (ntspawn(exe, g_argv, environ, &kNtIsInheritable, NULL, true, 0, NULL,
|
||||
&startinfo, &procinfo) != -1) {
|
||||
if (ntspawn(exe, g_argv, environ, forkvar, &kNtIsInheritable, NULL, true,
|
||||
0, NULL, &startinfo, &procinfo) != -1) {
|
||||
CloseHandle(reader);
|
||||
CloseHandle(procinfo.hThread);
|
||||
if (weaken(__sighandrvas) &&
|
||||
|
@ -152,6 +150,7 @@ textwindows int fork$nt(void) {
|
|||
g_fds.p[pid].kind = kFdProcess;
|
||||
g_fds.p[pid].handle = procinfo.hProcess;
|
||||
g_fds.p[pid].flags = O_CLOEXEC;
|
||||
releaseme = -1;
|
||||
}
|
||||
WriteAll(writer, jb, sizeof(jb));
|
||||
WriteAll(writer, &_mmi.i, sizeof(_mmi.i));
|
||||
|
@ -167,7 +166,6 @@ textwindows int fork$nt(void) {
|
|||
} else {
|
||||
rc = -1;
|
||||
}
|
||||
unsetenv("_FORK");
|
||||
rc = pid;
|
||||
} else {
|
||||
rc = __winerr();
|
||||
|
@ -175,5 +173,8 @@ textwindows int fork$nt(void) {
|
|||
} else {
|
||||
rc = 0;
|
||||
}
|
||||
if (releaseme != -1) {
|
||||
__releasefd(releaseme);
|
||||
}
|
||||
return rc;
|
||||
}
|
|
@ -32,7 +32,7 @@ struct DosArgv {
|
|||
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;
|
||||
for (;;) {
|
||||
if (!(x = *(*s)++)) break;
|
||||
|
@ -50,7 +50,7 @@ static textwindows wint_t DecodeDosArgv(const char16_t **s) {
|
|||
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;
|
||||
w = tpenc(wc);
|
||||
do {
|
||||
|
@ -78,8 +78,8 @@ static textwindows void AppendDosArgv(struct DosArgv *st, wint_t wc) {
|
|||
* @see libc/runtime/ntspawn.c
|
||||
* @note kudos to Simon Tatham for figuring out quoting behavior
|
||||
*/
|
||||
textwindows int GetDosArgv(const char16_t *cmdline, char *buf, size_t size,
|
||||
char **argv, size_t max) {
|
||||
textwindows noasan int GetDosArgv(const char16_t *cmdline, char *buf,
|
||||
size_t size, char **argv, size_t max) {
|
||||
bool inquote;
|
||||
size_t i, argc, slashes, quotes;
|
||||
struct DosArgv st;
|
||||
|
|
|
@ -18,6 +18,30 @@
|
|||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/runtime/runtime.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.
|
||||
|
@ -29,8 +53,8 @@
|
|||
* @param max is the pointer count capacity of envp
|
||||
* @return number of variables decoded, excluding NULL-terminator
|
||||
*/
|
||||
textwindows int GetDosEnviron(const char16_t *env, char *buf, size_t size,
|
||||
char **envp, size_t max) {
|
||||
textwindows noasan int GetDosEnviron(const char16_t *env, char *buf,
|
||||
size_t size, char **envp, size_t max) {
|
||||
int i;
|
||||
axdx_t r;
|
||||
i = 0;
|
||||
|
@ -38,7 +62,7 @@ textwindows int GetDosEnviron(const char16_t *env, char *buf, size_t size,
|
|||
--size;
|
||||
while (*env) {
|
||||
if (i + 1 < max) envp[i++] = buf;
|
||||
r = tprecode16to8(buf, size, env);
|
||||
r = Recode16to8(buf, size, env);
|
||||
size -= r.ax + 1;
|
||||
buf += r.ax + 1;
|
||||
env += r.dx;
|
||||
|
|
|
@ -24,7 +24,8 @@
|
|||
#include "libc/str/str.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 + n <= mm->i);
|
||||
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;
|
||||
}
|
||||
|
||||
static void CreateMemoryInterval(struct MemoryIntervals *mm, int i) {
|
||||
static noasan void CreateMemoryInterval(struct MemoryIntervals *mm, int i) {
|
||||
assert(i >= 0);
|
||||
assert(i <= mm->i);
|
||||
assert(mm->i < ARRAYLEN(mm->p));
|
||||
|
@ -41,7 +42,7 @@ static void CreateMemoryInterval(struct MemoryIntervals *mm, int 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();
|
||||
CreateMemoryInterval(mm, i);
|
||||
mm->p[i].y = x - 1;
|
||||
|
@ -49,8 +50,8 @@ static int PunchHole(struct MemoryIntervals *mm, int x, int y, int i) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
int ReleaseMemoryIntervals(struct MemoryIntervals *mm, int x, int y,
|
||||
void wincb(struct MemoryIntervals *, int, int)) {
|
||||
noasan int ReleaseMemoryIntervals(struct MemoryIntervals *mm, int x, int y,
|
||||
void wf(struct MemoryIntervals *, int, int)) {
|
||||
unsigned l, r;
|
||||
assert(y >= x);
|
||||
assert(AreMemoryIntervalsOk(mm));
|
||||
|
@ -81,16 +82,16 @@ int ReleaseMemoryIntervals(struct MemoryIntervals *mm, int x, int y,
|
|||
--r;
|
||||
}
|
||||
if (l <= r) {
|
||||
if (IsWindows() && wincb) {
|
||||
wincb(mm, l, r);
|
||||
if (IsWindows() && wf) {
|
||||
wf(mm, l, r);
|
||||
}
|
||||
RemoveMemoryIntervals(mm, l, r - l + 1);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int TrackMemoryInterval(struct MemoryIntervals *mm, int x, int y, long h,
|
||||
int prot, int flags) {
|
||||
noasan int TrackMemoryInterval(struct MemoryIntervals *mm, int x, int y, long h,
|
||||
int prot, int flags) {
|
||||
unsigned i;
|
||||
assert(y >= x);
|
||||
assert(AreMemoryIntervalsOk(mm));
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
#include "libc/dce.h"
|
||||
#include "libc/macros.h"
|
||||
#include "libc/nt/enum/version.h"
|
||||
#include "libc/nt/struct/teb.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
|
|
@ -22,14 +22,14 @@
|
|||
#include "libc/runtime/memtrack.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
|
||||
static void *GetFrameAddr(int f) {
|
||||
static noasan void *GetFrameAddr(int f) {
|
||||
intptr_t a;
|
||||
a = f;
|
||||
a *= FRAMESIZE;
|
||||
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;
|
||||
for (i = l; i <= r; ++i) {
|
||||
ok = UnmapViewOfFile(GetFrameAddr(mm->p[i].x));
|
||||
|
|
|
@ -52,13 +52,14 @@
|
|||
* @param flags can have MAP_ANONYMOUS, MAP_SHARED, MAP_PRIVATE, etc.
|
||||
* @param fd is an open()'d file descriptor whose contents shall be
|
||||
* mapped, and is ignored if MAP_ANONYMOUS is specified
|
||||
* @param offset specifies absolute byte index of fd's file for mapping,
|
||||
* and should be zero if MAP_ANONYMOUS is specified
|
||||
* @param off specifies absolute byte index of fd's file for mapping,
|
||||
* should be zero if MAP_ANONYMOUS is specified, and sadly needs
|
||||
* to be 64kb aligned too
|
||||
* @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) {
|
||||
int i, x, n, a, b;
|
||||
struct DirectMap dm;
|
||||
int i, x, n, a, b, f;
|
||||
if (!size) return VIP(einval());
|
||||
if (!ALIGNED(off)) 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);
|
||||
}
|
||||
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) {
|
||||
return MAP_FAILED;
|
||||
}
|
||||
|
|
|
@ -28,14 +28,13 @@
|
|||
#define WasImported(SLOT) \
|
||||
((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;
|
||||
char xmm[256];
|
||||
uint32_t wrote;
|
||||
savexmm(xmm + 128);
|
||||
hand = __imp_GetStdHandle(kNtStdErrorHandle);
|
||||
__imp_WriteFile(hand, data, len, &wrote, NULL);
|
||||
__imp_FlushFileBuffers(hand);
|
||||
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()
|
||||
* @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;
|
||||
if (WasImported(__imp_WriteFile)) {
|
||||
__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;
|
||||
while (s[n]) ++n;
|
||||
__print(s, n);
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue