diff --git a/Makefile b/Makefile index 37ac7ec62..03ed5172d 100644 --- a/Makefile +++ b/Makefile @@ -199,6 +199,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 +216,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) @@ -351,6 +352,7 @@ o/cosmopolitan.html: \ ~/.cosmo.mk: $(SRCS): $(HDRS): +$(INCS): .DEFAULT: @echo >&2 @echo NOTE: deleting o/$(MODE)/depend because of an unspecified prerequisite: $@ >&2 diff --git a/ape/ape.mk b/ape/ape.mk index 529c0d1e9..a9589aafb 100644 --- a/ape/ape.mk +++ b/ape/ape.mk @@ -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) diff --git a/build/compile b/build/compile index bfef27189..96b311e32 100755 --- a/build/compile +++ b/build/compile @@ -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 diff --git a/build/mkdeps b/build/mkdeps index e1d83bf15..b6919ca4b 100755 --- a/build/mkdeps +++ b/build/mkdeps @@ -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 diff --git a/dsp/core/core.mk b/dsp/core/core.mk index d4e130f36..66bba02f2 100644 --- a/dsp/core/core.mk +++ b/dsp/core/core.mk @@ -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 diff --git a/dsp/scale/scale.mk b/dsp/scale/scale.mk index 09403c741..ead96d43a 100644 --- a/dsp/scale/scale.mk +++ b/dsp/scale/scale.mk @@ -30,6 +30,7 @@ DSP_SCALE_A_DIRECTDEPS = \ LIBC_MEM \ LIBC_NEXGEN32E \ LIBC_RUNTIME \ + LIBC_STR \ LIBC_STUBS \ LIBC_STUBS \ LIBC_TIME \ diff --git a/libc/alg/alg.mk b/libc/alg/alg.mk index a0ad35482..df07ceb29 100644 --- a/libc/alg/alg.mk +++ b/libc/alg/alg.mk @@ -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 diff --git a/libc/calls/calls.mk b/libc/calls/calls.mk index 7511494d3..c7f103d63 100644 --- a/libc/calls/calls.mk +++ b/libc/calls/calls.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)) @@ -86,6 +87,7 @@ 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)) diff --git a/libc/calls/dup3-sysv.c b/libc/calls/dup3-sysv.c index 142484110..f231daf3b 100644 --- a/libc/calls/dup3-sysv.c +++ b/libc/calls/dup3-sysv.c @@ -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) { diff --git a/libc/calls/madvise-nt.c b/libc/calls/madvise-nt.c index 9d8005d1e..780e57b8c 100644 --- a/libc/calls/madvise-nt.c +++ b/libc/calls/madvise-nt.c @@ -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_; } diff --git a/libc/calls/now.c b/libc/calls/now.c index 4cdef2ebe..2e4cf360d 100644 --- a/libc/calls/now.c +++ b/libc/calls/now.c @@ -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); } diff --git a/libc/fmt/fmt.mk b/libc/fmt/fmt.mk index ccffc3d4e..e906da317 100644 --- a/libc/fmt/fmt.mk +++ b/libc/fmt/fmt.mk @@ -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 diff --git a/libc/integral/c.inc b/libc/integral/c.inc index 56aa255f2..56cc7d496 100644 --- a/libc/integral/c.inc +++ b/libc/integral/c.inc @@ -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) diff --git a/libc/intrin/asan.c b/libc/intrin/asan.c index 950d39c08..3d934be3b 100644 --- a/libc/intrin/asan.c +++ b/libc/intrin/asan.c @@ -154,6 +154,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 +271,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 +291,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; @@ -455,8 +456,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"); @@ -709,7 +708,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); diff --git a/libc/intrin/intrin.mk b/libc/intrin/intrin.mk index cd9a91927..4506a7ab8 100644 --- a/libc/intrin/intrin.mk +++ b/libc/intrin/intrin.mk @@ -46,7 +46,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)) diff --git a/libc/intrin/psrldq.c b/libc/intrin/psrldq.c index 2c88aea42..505d870e1 100644 --- a/libc/intrin/psrldq.c +++ b/libc/intrin/psrldq.c @@ -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); } diff --git a/libc/libc.mk b/libc/libc.mk index 7bbaec715..91a0d9be0 100644 --- a/libc/libc.mk +++ b/libc/libc.mk @@ -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) diff --git a/libc/nexgen32e/khalfcache3.S b/libc/nexgen32e/khalfcache3.S index 11fc2b572..d807f0251 100644 --- a/libc/nexgen32e/khalfcache3.S +++ b/libc/nexgen32e/khalfcache3.S @@ -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 diff --git a/libc/nexgen32e/nexgen32e.h b/libc/nexgen32e/nexgen32e.h index 7ac2ea8eb..90aa608a6 100644 --- a/libc/nexgen32e/nexgen32e.h +++ b/libc/nexgen32e/nexgen32e.h @@ -3,6 +3,8 @@ #if !(__ASSEMBLER__ + __LINKER__ + 0) COSMOPOLITAN_C_START_ +extern long kHalfCache3; + void imapxlatab(void *); void insertionsort(int32_t *, size_t); diff --git a/libc/nexgen32e/nexgen32e.mk b/libc/nexgen32e/nexgen32e.mk index 620d53e11..5a9571f73 100644 --- a/libc/nexgen32e/nexgen32e.mk +++ b/libc/nexgen32e/nexgen32e.mk @@ -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 diff --git a/libc/nexgen32e/strsak.S b/libc/nexgen32e/strsak.S index acdf5c9a1..05d030470 100644 --- a/libc/nexgen32e/strsak.S +++ b/libc/nexgen32e/strsak.S @@ -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 diff --git a/libc/nt/nt.mk b/libc/nt/nt.mk index 8c157b5f8..26918848e 100644 --- a/libc/nt/nt.mk +++ b/libc/nt/nt.mk @@ -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))) #─────────────────────────────────────────────────────────────────────────────── diff --git a/libc/sock/sock.mk b/libc/sock/sock.mk index 98e5b1466..217c2c88a 100644 --- a/libc/sock/sock.mk +++ b/libc/sock/sock.mk @@ -8,6 +8,7 @@ LIBC_SOCK = $(LIBC_SOCK_A_DEPS) $(LIBC_SOCK_A) LIBC_SOCK_A = o/$(MODE)/libc/sock/sock.a LIBC_SOCK_A_FILES := $(wildcard libc/sock/*) LIBC_SOCK_A_HDRS = $(filter %.h,$(LIBC_SOCK_A_FILES)) +LIBC_SOCK_A_INCS = $(filter %.inc,$(LIBC_SOCK_A_FILES)) LIBC_SOCK_A_SRCS = $(filter %.c,$(LIBC_SOCK_A_FILES)) LIBC_SOCK_A_OBJS = \ @@ -31,6 +32,7 @@ LIBC_SOCK_A_DIRECTDEPS = \ LIBC_NT_WS2_32 \ LIBC_RUNTIME \ LIBC_STDIO \ + LIBC_STR \ LIBC_STUBS \ LIBC_SYSV_CALLS \ LIBC_SYSV @@ -49,6 +51,7 @@ $(LIBC_SOCK_A).pkg: \ LIBC_SOCK_LIBS = $(foreach x,$(LIBC_SOCK_ARTIFACTS),$($(x))) LIBC_SOCK_SRCS = $(foreach x,$(LIBC_SOCK_ARTIFACTS),$($(x)_SRCS)) LIBC_SOCK_HDRS = $(foreach x,$(LIBC_SOCK_ARTIFACTS),$($(x)_HDRS)) +LIBC_SOCK_INCS = $(foreach x,$(LIBC_SOCK_ARTIFACTS),$($(x)_INCS)) LIBC_SOCK_CHECKS = $(foreach x,$(LIBC_SOCK_ARTIFACTS),$($(x)_CHECKS)) LIBC_SOCK_OBJS = $(foreach x,$(LIBC_SOCK_ARTIFACTS),$($(x)_OBJS)) $(LIBC_SOCK_OBJS): $(BUILD_FILES) libc/sock/sock.mk diff --git a/libc/stdio/g_stderr.c b/libc/stdio/g_stderr.c index 6db70e02e..6b1de57ad 100644 --- a/libc/stdio/g_stderr.c +++ b/libc/stdio/g_stderr.c @@ -27,7 +27,7 @@ STATIC_YOINK("_init_g_stderr"); FILE *stderr; hidden FILE g_stderr; -hidden unsigned char g_stderr_buf[BUFSIZ] forcealign(PAGESIZE); +hidden unsigned char g_stderr_buf[BUFSIZ]; static textstartup void _init_g_stderr2() { _fflushregister(stderr); diff --git a/libc/stdio/g_stdin.c b/libc/stdio/g_stdin.c index 82a38cb5a..ae5329940 100644 --- a/libc/stdio/g_stdin.c +++ b/libc/stdio/g_stdin.c @@ -27,7 +27,7 @@ STATIC_YOINK("_init_g_stdin"); FILE *stdin; hidden FILE g_stdin; -hidden unsigned char g_stdin_buf[BUFSIZ] forcealign(PAGESIZE); +hidden unsigned char g_stdin_buf[BUFSIZ]; static textstartup void g_stdin_init() { _fflushregister(stdin); diff --git a/libc/stdio/g_stdout.c b/libc/stdio/g_stdout.c index a2d6fc61b..761fd2f42 100644 --- a/libc/stdio/g_stdout.c +++ b/libc/stdio/g_stdout.c @@ -30,7 +30,7 @@ STATIC_YOINK("_init_g_stdout"); FILE *stdout; hidden FILE g_stdout; -hidden unsigned char g_stdout_buf[BUFSIZ] forcealign(PAGESIZE); +hidden unsigned char g_stdout_buf[BUFSIZ]; static textstartup void _init_g_stdout2() { struct FILE *sf; diff --git a/libc/str/tinymemccpy.c b/libc/str/index.c similarity index 81% rename from libc/str/tinymemccpy.c rename to libc/str/index.c index 328cf6a3a..6e1decccf 100644 --- a/libc/str/tinymemccpy.c +++ b/libc/str/index.c @@ -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 │ @@ -18,12 +18,14 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/str/str.h" -void *tinymemccpy(void *dst, const void *src, int termchar, size_t limit) { - size_t i; - unsigned char *d; - const unsigned char *s; - for (termchar &= 0xff, d = dst, s = src, i = 0; i < limit; ++i) { - if ((d[i] = s[i]) == termchar) return d + i + 1; - } - return NULL; +/** + * Returns pointer to first instance of character, the BSD way. + * + * @param s is a NUL-terminated string + * @param is masked with 255 as byte to search for + * @return is pointer to first instance of c or NULL if not found, + * noting that c being NUL will return a pointer to terminator + */ +char *index(const char *s, int c) { + return strchr(s, c); } diff --git a/libc/str/memccpy.c b/libc/str/memccpy.c index 1276d6348..c982372a4 100644 --- a/libc/str/memccpy.c +++ b/libc/str/memccpy.c @@ -18,8 +18,14 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/str/str.h" +static noasan uint64_t UncheckedAlignedRead64(unsigned char *p) { + return (uint64_t)p[7] << 070 | (uint64_t)p[6] << 060 | (uint64_t)p[5] << 050 | + (uint64_t)p[4] << 040 | (uint64_t)p[3] << 030 | (uint64_t)p[2] << 020 | + (uint64_t)p[1] << 010 | (uint64_t)p[0] << 000; +} + /** - * Copies at most 𝑛 bytes from 𝑠 to 𝑑 until 𝑐 is encountered. + * Copies at most N bytes from SRC to DST until 𝑐 is encountered. * * This is little-known C Standard Library approach, dating back to the * Fourth Edition of System Five, for copying a C strings to fixed-width @@ -39,17 +45,46 @@ * char cstrbuf[16]; * snprintf(cstrbuf, sizeof(cstrbuf), "%s", CSTR); * - * @return 𝑑 + idx(𝑐) + 1, or NULL if 𝑐 ∉ 𝑠₀․․ₙ₋₁ - * @note 𝑑 and 𝑠 can't overlap + * @param c is search character and is masked with 255 + * @return DST + idx(c) + 1, or NULL if 𝑐 ∉ 𝑠₀․․ₙ₋₁ + * @note DST and SRC can't overlap * @asyncsignalsafe */ -void *memccpy(void *d, const void *s, int c, size_t n) { - const char *p, *pe; - p = s; - if ((pe = memchr(p, c, n))) { - return mempcpy(d, s, pe - p + 1); - } else { - memcpy(d, s, n); - return NULL; +void *memccpy(void *dst, const void *src, int c, size_t n) { + size_t i; + uint64_t v, w; + unsigned char *d; + unsigned char *pd; + const unsigned char *s; + i = 0; + d = dst; + s = src; + c &= 255; + v = 0x0101010101010101 * c; + for (; (uintptr_t)(s + i) & 7; ++i) { + if (i == n) return NULL; + if ((d[i] = s[i]) == c) return d + i + 1; } + for (; i + 8 <= n; i += 8) { + w = UncheckedAlignedRead64(s + i); + if (~(w ^ v) & ((w ^ v) - 0x0101010101010101) & 0x8080808080808080) { + break; + } else { + pd = d + i; + pd[0] = (w >> 000) & 255; + pd[1] = (w >> 010) & 255; + pd[2] = (w >> 020) & 255; + pd[3] = (w >> 030) & 255; + pd[4] = (w >> 040) & 255; + pd[5] = (w >> 050) & 255; + pd[6] = (w >> 060) & 255; + pd[7] = (w >> 070) & 255; + } + } + for (; i < n; ++i) { + if ((d[i] = s[i]) == c) { + return d + i + 1; + } + } + return NULL; } diff --git a/libc/str/memchr.c b/libc/str/memchr.c new file mode 100644 index 000000000..1c917fb70 --- /dev/null +++ b/libc/str/memchr.c @@ -0,0 +1,47 @@ +/*-*- 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/str/str.h" + +/** + * Returns pointer to first instance of character. + * + * @param m is memory to search + * @param c is search byte which is masked with 255 + * @param n is byte length of p + * @return is pointer to first instance of c or NULL if not found + * @asyncsignalsafe + */ +void *memchr(const void *m, int c, size_t n) { + uint64_t v, w; + const unsigned char *p, *pe; + c &= 255; + v = 0x0101010101010101 * c; + for (p = (const unsigned char *)m, pe = p + n; p + 8 <= pe; p += 8) { + w = (uint64_t)p[7] << 070 | (uint64_t)p[6] << 060 | (uint64_t)p[5] << 050 | + (uint64_t)p[4] << 040 | (uint64_t)p[3] << 030 | (uint64_t)p[2] << 020 | + (uint64_t)p[1] << 010 | (uint64_t)p[0] << 000; + if ((w = ~(w ^ v) & ((w ^ v) - 0x0101010101010101) & 0x8080808080808080)) { + return p + ((unsigned)__builtin_ctzll(w) >> 3); + } + } + for (; p < pe; ++p) { + if (*p == c) return p; + } + return NULL; +} diff --git a/libc/str/memmove-pure.c b/libc/str/memmove-pure.c new file mode 100644 index 000000000..2f0bbddfc --- /dev/null +++ b/libc/str/memmove-pure.c @@ -0,0 +1,160 @@ +/*-*- 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/str/str.h" + +typedef long long xmm_t __attribute__((__vector_size__(16), __aligned__(1))); + +/** + * Copies memory. + * + * DST and SRC may overlap. + * + * @param dst is destination + * @param src is memory to copy + * @param n is number of bytes to copy + * @return dst + * @asyncsignalsafe + */ +void *memmove$pure(void *dst, const void *src, size_t n) { + size_t i; + xmm_t v, w; + char *d, *r; + const char *s; + uint64_t a, b; + d = dst; + s = src; + switch (n) { + case 9 ... 15: + __builtin_memcpy(&a, s, 8); + __builtin_memcpy(&b, s + n - 8, 8); + __builtin_memcpy(d, &a, 8); + __builtin_memcpy(d + n - 8, &b, 8); + return d; + case 5 ... 7: + __builtin_memcpy(&a, s, 4); + __builtin_memcpy(&b, s + n - 4, 4); + __builtin_memcpy(d, &a, 4); + __builtin_memcpy(d + n - 4, &b, 4); + return d; + case 17 ... 32: + __builtin_memcpy(&v, s, 16); + __builtin_memcpy(&w, s + n - 16, 16); + __builtin_memcpy(d, &v, 16); + __builtin_memcpy(d + n - 16, &w, 16); + return d; + case 16: + __builtin_memcpy(&v, s, 16); + __builtin_memcpy(d, &v, 16); + return d; + case 0: + return d; + case 1: + *d = *s; + return d; + case 8: + __builtin_memcpy(&a, s, 8); + __builtin_memcpy(d, &a, 8); + return d; + case 4: + __builtin_memcpy(&a, s, 4); + __builtin_memcpy(d, &a, 4); + return d; + case 2: + __builtin_memcpy(&a, s, 2); + __builtin_memcpy(d, &a, 2); + return d; + case 3: + __builtin_memcpy(&a, s, 2); + __builtin_memcpy(&b, s + 1, 2); + __builtin_memcpy(d, &a, 2); + __builtin_memcpy(d + 1, &b, 2); + return d; + default: + r = d; + if (d > s) { + do { + n -= 32; + __builtin_memcpy(&v, s + n, 16); + __builtin_memcpy(&w, s + n + 16, 16); + __builtin_memcpy(d + n, &v, 16); + __builtin_memcpy(d + n + 16, &w, 16); + } while (n >= 32); + } else { + i = 0; + do { + __builtin_memcpy(&v, s + i, 16); + __builtin_memcpy(&w, s + i + 16, 16); + __builtin_memcpy(d + i, &v, 16); + __builtin_memcpy(d + i + 16, &w, 16); + } while ((i += 32) + 32 <= n); + d += i; + s += i; + n -= i; + } + switch (n) { + case 0: + return r; + case 17 ... 31: + __builtin_memcpy(&v, s, 16); + __builtin_memcpy(&w, s + n - 16, 16); + __builtin_memcpy(d, &v, 16); + __builtin_memcpy(d + n - 16, &w, 16); + return r; + case 9 ... 15: + __builtin_memcpy(&a, s, 8); + __builtin_memcpy(&b, s + n - 8, 8); + __builtin_memcpy(d, &a, 8); + __builtin_memcpy(d + n - 8, &b, 8); + return r; + case 5 ... 7: + __builtin_memcpy(&a, s, 4); + __builtin_memcpy(&b, s + n - 4, 4); + __builtin_memcpy(d, &a, 4); + __builtin_memcpy(d + n - 4, &b, 4); + return r; + case 16: + __builtin_memcpy(&v, s, 16); + __builtin_memcpy(d, &v, 16); + return r; + case 8: + __builtin_memcpy(&a, s, 8); + __builtin_memcpy(d, &a, 8); + return r; + case 4: + __builtin_memcpy(&a, s, 4); + __builtin_memcpy(d, &a, 4); + return r; + case 1: + *d = *s; + return r; + case 2: + __builtin_memcpy(&a, s, 2); + __builtin_memcpy(d, &a, 2); + return r; + case 3: + __builtin_memcpy(&a, s, 2); + __builtin_memcpy(&b, s + 1, 2); + __builtin_memcpy(d, &a, 2); + __builtin_memcpy(d + 1, &b, 2); + return r; + default: + unreachable; + } + } +} diff --git a/libc/str/memset-pure.c b/libc/str/memset-pure.c new file mode 100644 index 000000000..60a132eb2 --- /dev/null +++ b/libc/str/memset-pure.c @@ -0,0 +1,100 @@ +/*-*- 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/str/str.h" + +/** + * Sets memory. + * + * @param p is memory address + * @param c is masked with 255 and used as repeated byte + * @param n is byte length + * @return p + * @asyncsignalsafe + */ +void *memset$pure(void *p, int c, size_t n) { + char *b; + uint64_t x; + b = p; + x = 0x0101010101010101 * (c & 0xff); + switch (n) { + case 0: + return p; + case 1: + __builtin_memcpy(b, &x, 1); + return p; + case 2: + __builtin_memcpy(b, &x, 2); + return p; + case 3: + __builtin_memcpy(b, &x, 2); + __builtin_memcpy(b + 1, &x, 2); + return p; + case 4: + __builtin_memcpy(b, &x, 4); + return p; + case 5 ... 7: + __builtin_memcpy(b, &x, 4); + __builtin_memcpy(b + n - 4, &x, 4); + return p; + case 8: + __builtin_memcpy(b, &x, 8); + return p; + case 9 ... 16: + __builtin_memcpy(b, &x, 8); + __builtin_memcpy(b + n - 8, &x, 8); + return p; + default: + do { + n -= 16; + __builtin_memcpy(b + n, &x, 8); + asm volatile("" ::: "memory"); + __builtin_memcpy(b + n + 8, &x, 8); + } while (n >= 16); + switch (n) { + case 0: + return p; + case 1: + __builtin_memcpy(b, &x, 1); + return p; + case 2: + __builtin_memcpy(b, &x, 2); + return p; + case 3: + __builtin_memcpy(b, &x, 2); + __builtin_memcpy(b + 1, &x, 2); + return p; + case 4: + __builtin_memcpy(b, &x, 4); + return p; + case 5 ... 7: + __builtin_memcpy(b, &x, 4); + __builtin_memcpy(b + n - 4, &x, 4); + return p; + case 8: + __builtin_memcpy(b, &x, 8); + return p; + case 9 ... 15: + __builtin_memcpy(b, &x, 8); + __builtin_memcpy(b + n - 8, &x, 8); + return p; + default: + unreachable; + } + } +} diff --git a/libc/str/rawmemchr.c b/libc/str/rawmemchr.c new file mode 100644 index 000000000..dab660dc2 --- /dev/null +++ b/libc/str/rawmemchr.c @@ -0,0 +1,53 @@ +/*-*- 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/assert.h" +#include "libc/str/str.h" + +static noasan uint64_t UncheckedAlignedRead64(unsigned char *p) { + return (uint64_t)p[7] << 070 | (uint64_t)p[6] << 060 | (uint64_t)p[5] << 050 | + (uint64_t)p[4] << 040 | (uint64_t)p[3] << 030 | (uint64_t)p[2] << 020 | + (uint64_t)p[1] << 010 | (uint64_t)p[0] << 000; +} + +/** + * Returns pointer to first instance of character. + * + * @param m is memory to search + * @param c is search byte which is masked with 255 + * @return is pointer to first instance of c + */ +void *rawmemchr(const void *m, int c) { + uint64_t v, w; + const unsigned char *s; + s = m; + c &= 255; + v = 0x0101010101010101 * c; + for (; (uintptr_t)s & 7; ++s) { + if (*s == c) return s; + } + for (;; s += 8) { + w = UncheckedAlignedRead64(s); + if ((w = ~(w ^ v) & ((w ^ v) - 0x0101010101010101) & 0x8080808080808080)) { + s += (unsigned)__builtin_ctzll(w) >> 3; + break; + } + } + assert(*s == c); + return s; +} diff --git a/libc/str/str.h b/libc/str/str.h index b26931069..740227ec2 100644 --- a/libc/str/str.h +++ b/libc/str/str.h @@ -90,7 +90,6 @@ void *memeqmask(void *, const void *, const void *, size_t) memcpyesque; size_t strlen(const char *) strlenesque; size_t strnlen(const char *, size_t) strlenesque; size_t strnlen_s(const char *, size_t); -size_t strlen$pure(const char *) strlenesque; char *strchr(const char *, int) strlenesque; char *index(const char *, int) strlenesque; void *memchr(const void *, int, size_t) strlenesque; @@ -246,8 +245,8 @@ char *strsignal(int) returnsnonnull libcesque; │ cosmopolitan § strings » optimizations ─╬─│┼ ╚────────────────────────────────────────────────────────────────────────────│*/ -#define __memcpy_isgoodsize(SIZE) \ - (__builtin_constant_p(SIZE) && ((SIZE) <= __BIGGEST_ALIGNMENT__ * 2 && \ +#define __memcpy_isgoodsize(SIZE) \ + (__builtin_constant_p(SIZE) && ((SIZE) <= __BIGGEST_ALIGNMENT__ && \ __builtin_popcountl((unsigned)(SIZE)) == 1)) #define __memset_isgoodsize(SIZE) \ @@ -361,15 +360,44 @@ char *strsignal(int) returnsnonnull libcesque; }) #endif /* hosted/sse2/unbloat */ -#ifdef __FSANITIZE_ADDRESS__ /*───────────────────────────────────────────────────────────────────────────│─╗ │ cosmopolitan § strings » address sanitizer ─╬─│┼ ╚────────────────────────────────────────────────────────────────────────────│*/ +void *memset$pure(void *, int, size_t) memcpyesque; +void *memmove$pure(void *, const void *, size_t) memcpyesque; +size_t strlen$pure(const char *) strlenesque; +size_t strcspn$pure(const char *, const char *) strlenesque; +#if defined(__FSANITIZE_ADDRESS__) + +#define strcspn(STR, REJECT) strcspn$pure(STR, REJECT) -#ifdef strlen #undef strlen -#endif -#define strlen(s) strlen$pure(s) +#define strlen(STR) \ + (__builtin_constant_p(STR) ? __builtin_strlen(STR) : strlen$pure(STR)) + +#undef memset +#define memset(DST, CHAR, SIZE) \ + (__memcpy_isgoodsize(SIZE) ? __builtin_memset(DST, CHAR, SIZE) \ + : memset$pure(DST, CHAR, SIZE)) + +#undef memmove +#define memmove(DST, SRC, SIZE) \ + (__memcpy_isgoodsize(SIZE) ? __builtin_memmove(DST, SRC, SIZE) \ + : memmove$pure(DST, SRC, SIZE)) + +#undef memcpy +#define memcpy(DST, SRC, SIZE) \ + (__memcpy_isgoodsize(SIZE) ? __builtin_memcpy(DST, SRC, SIZE) \ + : memmove$pure(DST, SRC, SIZE)) + +#undef mempcpy +#define mempcpy(DST, SRC, SIZE) \ + (__memcpy_isgoodsize(SIZE) ? __builtin_mempcpy(DST, SRC, SIZE) : ({ \ + void *DsT = (DST); \ + size_t SiZe = (SIZE); \ + memmove$pure(DsT, SRC, SiZe); \ + (void *)((char *)DsT + SiZe); \ + })) #endif /* __FSANITIZE_ADDRESS__ */ #endif /* __GNUC__ && !__STRICT_ANSI__ */ diff --git a/libc/str/str.mk b/libc/str/str.mk index 6f9927c6a..d634a3a80 100644 --- a/libc/str/str.mk +++ b/libc/str/str.mk @@ -8,6 +8,7 @@ LIBC_STR = $(LIBC_STR_A_DEPS) $(LIBC_STR_A) LIBC_STR_A = o/$(MODE)/libc/str/str.a LIBC_STR_A_FILES := $(wildcard libc/str/*) LIBC_STR_A_HDRS = $(filter %.h,$(LIBC_STR_A_FILES)) +LIBC_STR_A_INCS = $(filter %.inc,$(LIBC_STR_A_FILES)) LIBC_STR_A_SRCS_A = $(filter %.s,$(LIBC_STR_A_FILES)) LIBC_STR_A_SRCS_S = $(filter %.S,$(LIBC_STR_A_FILES)) LIBC_STR_A_SRCS_C = $(filter %.c,$(LIBC_STR_A_FILES)) @@ -49,6 +50,7 @@ o/$(MODE)/libc/str/memmem.o: \ LIBC_STR_LIBS = $(foreach x,$(LIBC_STR_ARTIFACTS),$($(x))) LIBC_STR_SRCS = $(foreach x,$(LIBC_STR_ARTIFACTS),$($(x)_SRCS)) LIBC_STR_HDRS = $(foreach x,$(LIBC_STR_ARTIFACTS),$($(x)_HDRS)) +LIBC_STR_INCS = $(foreach x,$(LIBC_STR_ARTIFACTS),$($(x)_INCS)) LIBC_STR_BINS = $(foreach x,$(LIBC_STR_ARTIFACTS),$($(x)_BINS)) LIBC_STR_CHECKS = $(foreach x,$(LIBC_STR_ARTIFACTS),$($(x)_CHECKS)) LIBC_STR_OBJS = $(foreach x,$(LIBC_STR_ARTIFACTS),$($(x)_OBJS)) diff --git a/libc/str/strchr.c b/libc/str/strchr.c new file mode 100644 index 000000000..6d7ea516c --- /dev/null +++ b/libc/str/strchr.c @@ -0,0 +1,69 @@ +/*-*- 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/assert.h" +#include "libc/str/str.h" + +noasan static const unsigned char *strchr$x64(const unsigned char *p, + uint64_t c) { + unsigned a, b; + uint64_t w, x, y; + for (c *= 0x0101010101010101;; p += 8) { + w = (uint64_t)p[7] << 070 | (uint64_t)p[6] << 060 | (uint64_t)p[5] << 050 | + (uint64_t)p[4] << 040 | (uint64_t)p[3] << 030 | (uint64_t)p[2] << 020 | + (uint64_t)p[1] << 010 | (uint64_t)p[0] << 000; + if ((x = ~(w ^ c) & ((w ^ c) - 0x0101010101010101) & 0x8080808080808080) | + (y = ~w & (w - 0x0101010101010101) & 0x8080808080808080)) { + if (x) { + a = __builtin_ctzll(x); + if (y) { + b = __builtin_ctzll(y); + if (a <= b) { + return p + (a >> 3); + } else { + return NULL; + } + } else { + return p + (a >> 3); + } + } else { + return NULL; + } + } + } +} + +/** + * Returns pointer to first instance of character. + * + * @param s is a NUL-terminated string + * @param c is masked with 255 as byte to search for + * @return pointer to first instance of c or NULL if not found + * noting that if c is NUL we return pointer to terminator + * @asyncsignalsafe + */ +char *strchr(const char *s, int c) { + char *r; + for (c &= 0xff; (uintptr_t)s & 7; ++s) { + if ((*s & 0xff) == c) return s; + if (!*s) return NULL; + } + r = (char *)strchr$x64((const unsigned char *)s, c); + assert(!r || *r || !c); + return r; +} diff --git a/libc/str/strchrnul.c b/libc/str/strchrnul.c new file mode 100644 index 000000000..8efc95274 --- /dev/null +++ b/libc/str/strchrnul.c @@ -0,0 +1,69 @@ +/*-*- 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/assert.h" +#include "libc/str/str.h" + +noasan static const unsigned char *strchrnul$x64(const unsigned char *p, + uint64_t c) { + unsigned a, b; + uint64_t w, x, y; + for (c *= 0x0101010101010101;; p += 8) { + w = (uint64_t)p[7] << 070 | (uint64_t)p[6] << 060 | (uint64_t)p[5] << 050 | + (uint64_t)p[4] << 040 | (uint64_t)p[3] << 030 | (uint64_t)p[2] << 020 | + (uint64_t)p[1] << 010 | (uint64_t)p[0] << 000; + if ((x = ~(w ^ c) & ((w ^ c) - 0x0101010101010101) & 0x8080808080808080) | + (y = ~w & (w - 0x0101010101010101) & 0x8080808080808080)) { + if (x) { + a = __builtin_ctzll(x); + if (y) { + b = __builtin_ctzll(y); + if (a <= b) { + return p + (a >> 3); + } else { + return p + (b >> 3); + } + } else { + return p + (a >> 3); + } + } else { + b = __builtin_ctzll(y); + return p + (b >> 3); + } + } + } +} + +/** + * Returns pointer to first instance of character. + * + * @param s is a NUL-terminated string + * @param c is masked with 255 as byte to search for + * @return pointer to first instance of c, or pointer to + * NUL terminator if c is not found + */ +char *strchrnul(const char *s, int c) { + char *r; + for (c &= 0xff; (uintptr_t)s & 7; ++s) { + if ((*s & 0xff) == c) return s; + if (!*s) return s; + } + r = (char *)strchrnul$x64((const unsigned char *)s, c); + assert((*r & 0xff) == c || !*r); + return r; +} diff --git a/libc/str/strcmp.c b/libc/str/strcmp.c index cf6760aef..53cc44cf5 100644 --- a/libc/str/strcmp.c +++ b/libc/str/strcmp.c @@ -18,6 +18,12 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/str/str.h" +static inline noasan uint64_t UncheckedAlignedRead64(unsigned char *p) { + return (uint64_t)p[7] << 070 | (uint64_t)p[6] << 060 | (uint64_t)p[5] << 050 | + (uint64_t)p[4] << 040 | (uint64_t)p[3] << 030 | (uint64_t)p[2] << 020 | + (uint64_t)p[1] << 010 | (uint64_t)p[0] << 000; +} + /** * Compares NUL-terminated strings. * @@ -28,7 +34,25 @@ */ int strcmp(const char *a, const char *b) { size_t i = 0; + uint64_t v, w, d; if (a == b) return 0; - while (a[i] == b[i] && b[i]) ++i; - return (a[i] & 0xff) - (b[i] & 0xff); + if (((uintptr_t)a & 7) == ((uintptr_t)b & 7)) { + for (; (uintptr_t)a & 7; ++i) { + if (a[i] != b[i] || !b[i]) { + return (a[i] & 0xff) - (b[i] & 0xff); + } + } + for (;; i += 8) { + v = UncheckedAlignedRead64(a + i); + w = UncheckedAlignedRead64(b + i); + w = (v ^ w) | (~v & (v - 0x0101010101010101) & 0x8080808080808080); + if (w) { + i += (unsigned)__builtin_ctzll(w) >> 3; + return (a[i] & 0xff) - (b[i] & 0xff); + } + } + } else { + while (a[i] == b[i] && b[i]) ++i; + return (a[i] & 0xff) - (b[i] & 0xff); + } } diff --git a/libc/str/strcspn-pure.c b/libc/str/strcspn-pure.c new file mode 100644 index 000000000..0acecb89a --- /dev/null +++ b/libc/str/strcspn-pure.c @@ -0,0 +1,62 @@ +/*-*- 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 │ +│ │ +│ 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/intrin/pcmpeqb.h" +#include "libc/intrin/pmovmskb.h" +#include "libc/intrin/pshufd.h" +#include "libc/intrin/punpcklbw.h" +#include "libc/intrin/punpcklwd.h" +#include "libc/nexgen32e/hascharacter.internal.h" +#include "libc/str/str.h" + +#define V(p) (void *)(p) + +/** + * Returns prefix length, consisting of chars not in reject. + * a.k.a. Return index of first byte that's in charset. + * + * @param reject is nul-terminated character set + * @see strspn(), strtok_r() + * @asyncsignalsafe + */ +size_t strcspn$pure(const char *s, const char *reject) { + size_t i, n; + unsigned m; + char cv[16], sv[16]; + if ((n = strlen(reject)) < 16) { + memset(sv, 0, 16); + memcpy(sv, reject, n); + for (i = 0;; ++i) { + cv[0] = s[i]; + punpcklbw(V(cv), V(cv), V(cv)); + punpcklwd(V(cv), V(cv), V(cv)); + pshufd(V(cv), V(cv), 0); + pcmpeqb(V(cv), V(cv), V(sv)); + if ((m = pmovmskb(V(cv)))) { + break; + } + } + return i; + } + for (i = 0; s[i]; ++i) { + if (HasCharacter(s[i], reject)) { + break; + } + } + return i; +} diff --git a/libc/str/strlen-pure.c b/libc/str/strlen-pure.c index cf6d698c2..8c3ba391c 100644 --- a/libc/str/strlen-pure.c +++ b/libc/str/strlen-pure.c @@ -16,35 +16,35 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/assert.h" #include "libc/str/str.h" -noasan static const char *strlen$pure$x64(const char *p) { +static noasan size_t strlen$pure$x64(const char *s, size_t i) { uint64_t w; + const unsigned char *p; for (;;) { - w = *(uint64_t *)p; - if (~w & (w - 0x0101010101010101) & 0x8080808080808080) { - break; + p = (const unsigned char *)s + i; + w = (uint64_t)p[7] << 070 | (uint64_t)p[6] << 060 | (uint64_t)p[5] << 050 | + (uint64_t)p[4] << 040 | (uint64_t)p[3] << 030 | (uint64_t)p[2] << 020 | + (uint64_t)p[1] << 010 | (uint64_t)p[0] << 000; + if ((w = ~w & (w - 0x0101010101010101) & 0x8080808080808080)) { + return i + ((unsigned)__builtin_ctzll(w) >> 3); } else { - p += 8; + i += 8; } } - return p; } /** * Returns length of NUL-terminated string. */ size_t strlen$pure(const char *s) { - const char *p; - p = s; - while ((uintptr_t)p & 7) { - if (*p) { - ++p; - } else { - return p - s; - } + size_t i; + for (i = 0; (uintptr_t)(s + i) & 7; ++i) { + if (!s[i]) return i; } - p = strlen$pure$x64(p); - while (*p) ++p; - return p - s; + i = strlen$pure$x64(s, i); + assert(!i || s[0]); + assert(!s[i]); + return i; } diff --git a/libc/str/strnlen.c b/libc/str/strnlen.c new file mode 100644 index 000000000..8fa348e62 --- /dev/null +++ b/libc/str/strnlen.c @@ -0,0 +1,57 @@ +/*-*- 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/assert.h" +#include "libc/str/str.h" + +static noasan size_t strnlen$x64(const char *s, size_t n, size_t i) { + uint64_t w; + const unsigned char *p; + for (; i + 8 < n; i += 8) { + p = (const unsigned char *)s + i; + w = (uint64_t)p[7] << 070 | (uint64_t)p[6] << 060 | (uint64_t)p[5] << 050 | + (uint64_t)p[4] << 040 | (uint64_t)p[3] << 030 | (uint64_t)p[2] << 020 | + (uint64_t)p[1] << 010 | (uint64_t)p[0] << 000; + if ((w = ~w & (w - 0x0101010101010101) & 0x8080808080808080)) { + i += (unsigned)__builtin_ctzll(w) >> 3; + break; + } + } + return i; +} + +/** + * Returns length of NUL-terminated string w/ limit. + * + * @param s is string + * @param n is max length + * @return byte length + * @asyncsignalsafe + */ +size_t strnlen(const char *s, size_t n) { + size_t i; + for (i = 0; (uintptr_t)(s + i) & 7; ++i) { + if (i == n || !s[i]) return i; + } + i = strnlen$x64(s, n, i); + for (;; ++i) { + if (i == n || !s[i]) break; + } + assert(i == n || (i < n && !s[i])); + return i; +} diff --git a/libc/sysv/sysv.mk b/libc/sysv/sysv.mk index 72ac457fe..189fd55d1 100644 --- a/libc/sysv/sysv.mk +++ b/libc/sysv/sysv.mk @@ -5,6 +5,7 @@ PKGS += LIBC_SYSV LIBC_SYSV_LIBS = $(foreach x,$(LIBC_SYSV_ARTIFACTS),$($(x)_A)) LIBC_SYSV_ARCHIVES = $(foreach x,$(LIBC_SYSV_ARTIFACTS),$($(x)_A)) LIBC_SYSV_HDRS = $(foreach x,$(LIBC_SYSV_ARTIFACTS),$($(x)_HDRS)) +LIBC_SYSV_INCS = $(foreach x,$(LIBC_SYSV_ARTIFACTS),$($(x)_INCS)) LIBC_SYSV_BINS = $(foreach x,$(LIBC_SYSV_ARTIFACTS),$($(x)_BINS)) LIBC_SYSV_CHECKS = $(foreach x,$(LIBC_SYSV_ARTIFACTS),$($(x)_CHECKS)) LIBC_SYSV_OBJS = $(foreach x,$(LIBC_SYSV_ARTIFACTS),$($(x)_OBJS)) @@ -20,6 +21,7 @@ LIBC_SYSV = \ LIBC_SYSV_ARTIFACTS += LIBC_SYSV_A LIBC_SYSV_A = o/$(MODE)/libc/sysv/sysv.a LIBC_SYSV_A_HDRS = $(filter %.h,$(LIBC_SYSV_A_FILES)) +LIBC_SYSV_A_INCS = $(filter %.inc,$(LIBC_SYSV_A_FILES)) LIBC_SYSV_A_SRCS_A = $(filter %.s,$(LIBC_SYSV_A_FILES)) LIBC_SYSV_A_SRCS_S = $(filter %.S,$(LIBC_SYSV_A_FILES)) LIBC_SYSV_A_CHECKS = $(LIBC_SYSV_A).pkg diff --git a/libc/testlib/ezbenchreport.c b/libc/testlib/ezbenchreport.c index 704933ffa..1f27b9acd 100644 --- a/libc/testlib/ezbenchreport.c +++ b/libc/testlib/ezbenchreport.c @@ -27,8 +27,8 @@ STATIC_YOINK("strnwidth"); void __testlib_ezbenchreport(const char *form, uint64_t c1, uint64_t c2) { uint64_t ns1, ns2; - ns1 = rintl(converttickstonanos(c1)); - ns2 = rintl(converttickstonanos(c2)); + ns1 = rintl(ConvertTicksToNanos(c1)); + ns2 = rintl(ConvertTicksToNanos(c2)); (fprintf)(stderr, VEIL("r", "%-30s l: %,10lu𝑐 %,10lu𝑛𝑠 m: %,10lu𝑐 %,10lu𝑛𝑠\n"), form, c1, ns1, c2, ns2); diff --git a/libc/time/time.h b/libc/time/time.h index a33985d3e..f56b98cb4 100644 --- a/libc/time/time.h +++ b/libc/time/time.h @@ -60,8 +60,7 @@ int futimesat(int, const char *, const struct timeval[2]); long double dtime(int); long double dsleep(long double); extern long double (*nowl)(void); -long double converttickstonanos(uint64_t); -long double converttickstoseconds(uint64_t); +long double ConvertTicksToNanos(uint64_t); double difftime(int64_t, int64_t) nothrow pureconst; diff --git a/test/dsp/scale/scale_test.c b/test/dsp/scale/scale_test.c index f6f89315a..0ba91e37d 100644 --- a/test/dsp/scale/scale_test.c +++ b/test/dsp/scale/scale_test.c @@ -80,11 +80,12 @@ prpppppppppppppoooooooonnnnnnnnnnnnnnnooooooooppppppppppppptp\ pppppppppppppppppppoooooooooooooooooooooooppppppppppppppppppp"; TEST(gyarados, testIdentityDifference) { - static unsigned char A[1][32][62]; - static unsigned char B[1][32][62]; + static unsigned char A[1][32][61]; + static unsigned char B[1][32][61]; + ASSERT_EQ(sizeof(A), strlen(kDieWelle)); memcpy(A, kDieWelle, sizeof(A)); EzGyarados(1, 32, 61, B, 1, 32, 61, A, 0, 1, 32, 61, 32, 61, 1, 1, 0, 0); - AbsoluteDifference(32, 62, B[0], 32, 62, B[0], 32, 62, A[0]); + AbsoluteDifference(32, 61, B[0], 32, 61, B[0], 32, 61, A[0]); EXPECT_STREQ(u"\n\                                                              \n\                                                              \n\ diff --git a/test/libc/crypto/test.mk b/test/libc/crypto/test.mk index 3b2ec1427..5b7d429bc 100644 --- a/test/libc/crypto/test.mk +++ b/test/libc/crypto/test.mk @@ -26,6 +26,7 @@ TEST_LIBC_CRYPTO_DIRECTDEPS = \ LIBC_INTRIN \ LIBC_NEXGEN32E \ LIBC_RUNTIME \ + LIBC_STR \ LIBC_STUBS \ LIBC_TESTLIB diff --git a/test/libc/mem/test.mk b/test/libc/mem/test.mk index 0ddfb6ac3..dd1120293 100644 --- a/test/libc/mem/test.mk +++ b/test/libc/mem/test.mk @@ -30,6 +30,7 @@ TEST_LIBC_MEM_DIRECTDEPS = \ LIBC_RAND \ LIBC_RUNTIME \ LIBC_STDIO \ + LIBC_STR \ LIBC_STUBS \ LIBC_SYSV \ LIBC_TESTLIB diff --git a/test/libc/nexgen32e/memmove_test.c b/test/libc/nexgen32e/memmove_test.c index 460b9e6f9..d69ceb422 100644 --- a/test/libc/nexgen32e/memmove_test.c +++ b/test/libc/nexgen32e/memmove_test.c @@ -17,77 +17,117 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/bits/bits.h" -#include "libc/bits/safemacros.h" +#include "libc/macros.h" #include "libc/mem/mem.h" +#include "libc/rand/rand.h" #include "libc/str/str.h" #include "libc/testlib/testlib.h" -#define N 256 -#define S 7 +#define N 65 +#define S 1 long i, j, n; -char *b1, *b2; +char *b0, *b1, *b2; + +noinline char *PosixMemmove(char *dst, const char *src, size_t n) { + char *tmp; + tmp = malloc(n); + memcpy(tmp, src, n); + memcpy(dst, tmp, n); + free(tmp); + return dst; +} TEST(memmove, overlapping) { for (i = 0; i < N; i += S) { - for (j = 10; j < N; j += S) { - b1 = malloc(N); - b2 = malloc(N); - n = min(N - i, N - j); - memcpy(b2, b1 + i, n); - ASSERT_EQ(b1 + j, memmove(b1 + j, b1 + i, n)); - ASSERT_EQ(0, memcmp(b1 + j, b2, n)); - free(b2); - free(b1); + for (j = 0; j < N; j += S) { + for (n = MIN(N - i, N - j) + 1; n--;) { + b0 = rngset(malloc(N), N, rand64, -1); + b1 = memcpy(malloc(N), b0, N); + b2 = memcpy(malloc(N), b0, N); + ASSERT_EQ(b1 + j, memmove(b1 + j, b1 + i, n)); + ASSERT_EQ(b2 + j, PosixMemmove(b2 + j, b2 + i, n)); + ASSERT_EQ(0, memcmp(b1, b2, N), + "j=%ld i=%ld n=%ld\n" + "\t%#.*s data\n" + "\t%#.*s memmove\n" + "\t%#.*s posix", + j, i, n, n, b0, n, b1, n, b2); + free(b2); + free(b1); + free(b0); + } + } + } +} + +TEST(memmove$pure, overlapping) { + for (i = 0; i < N; i += S) { + for (j = 0; j < N; j += S) { + for (n = MIN(N - i, N - j) + 1; n--;) { + b0 = rngset(malloc(N), N, rand64, -1); + b1 = memcpy(malloc(N), b0, N); + b2 = memcpy(malloc(N), b0, N); + ASSERT_EQ(b1 + j, memmove$pure(b1 + j, b1 + i, n)); + ASSERT_EQ(b2 + j, PosixMemmove(b2 + j, b2 + i, n)); + ASSERT_EQ(0, memcmp(b1, b2, N), + "j=%ld i=%ld n=%ld\n" + "\t%#.*s data\n" + "\t%#.*s memmove\n" + "\t%#.*s posix", + j, i, n, n, b0, n, b1, n, b2); + free(b2); + free(b1); + free(b0); + } + } + } +} + +TEST(memcpy, overlapping) { + for (i = 0; i < N; i += S) { + for (j = 0; j < N; j += S) { + for (n = MIN(N - i, N - j) + 1; n--;) { + if (j <= i) { + b0 = rngset(malloc(N), N, rand64, -1); + b1 = memcpy(malloc(N), b0, N); + b2 = memcpy(malloc(N), b0, N); + ASSERT_EQ(b1 + j, memcpy(b1 + j, b1 + i, n)); + ASSERT_EQ(b2 + j, PosixMemmove(b2 + j, b2 + i, n)); + ASSERT_EQ(0, memcmp(b1, b2, N), + "j=%ld i=%ld n=%ld\n" + "\t%#.*s data\n" + "\t%#.*s memmove\n" + "\t%#.*s posix", + j, i, n, n, b0, n, b1, n, b2); + free(b2); + free(b1); + free(b0); + } + } } } } TEST(memmove, overlappingDirect) { for (i = 0; i < N; i += S) { - for (j = 10; j < N; j += S) { - b1 = malloc(N); - b2 = malloc(N); - n = min(N - i, N - j); - memcpy(b2, b1 + i, n); - ASSERT_EQ(b1 + j, (memmove)(b1 + j, b1 + i, n)); - ASSERT_EQ(0, memcmp(b1 + j, b2, n)); - free(b2); - free(b1); + for (j = 0; j < N; j += S) { + for (n = MIN(N - i, N - j) + 1; n--;) { + b0 = rngset(malloc(N), N, rand64, -1); + b1 = memcpy(malloc(N), b0, N); + b2 = memcpy(malloc(N), b0, N); + ASSERT_EQ(b1 + j, (memmove)(b1 + j, b1 + i, n)); + ASSERT_EQ(b2 + j, PosixMemmove(b2 + j, b2 + i, n)); + ASSERT_EQ(0, memcmp(b1, b2, N), + "j=%ld i=%ld n=%ld\n" + "\t%#.*s data\n" + "\t%#.*s memmove\n" + "\t%#.*s posix", + j, i, n, n, b0, n, b1, n, b2); + free(b2); + free(b1); + free(b0); + } } } } - -char *MoveMemory(char *dst, const char *src, size_t n) { - size_t i; - for (i = 0; i < n; ++i) { - dst[i] = src[i]; - } - return dst; -} - -TEST(memmove, overlappingBackwards_isGenerallySafe) { - char buf[32]; - strcpy(buf, "abcdefghijklmnopqrstuvwxyz"); - ASSERT_STREQ("cdefghijklmnopqrstuvwxyzyz", MoveMemory(buf, buf + 2, 24)); - strcpy(buf, "abcdefghijklmnopqrstuvwxyz"); - ASSERT_STREQ("cdefghijklmnopqrstuvwxyzyz", memmove(buf, buf + 2, 24)); - strcpy(buf, "abcdefghijklmnopqrstuvwxyz"); - ASSERT_STREQ("cdefghijklmnopqrstuvwxyzyz", memcpy(buf, buf + 2, 24)); -} - -TEST(memmove, overlappingForwards_avoidsRunLengthDecodeBehavior) { - volatile char buf[32]; - strcpy(buf, "abc"); - MoveMemory(buf + 1, buf, 2); - ASSERT_STREQ("aaa", buf); - strcpy(buf, "abc"); - (memmove)(buf + 1, buf, 2); - ASSERT_STREQ("aab", buf); - strcpy(buf, "abcdefghijklmnopqrstuvwxyz"); - MoveMemory(buf + 2, buf, 24); - ASSERT_STREQ("ababababababababababababab", buf); - strcpy(buf, "abcdefghijklmnopqrstuvwxyz"); - memmove(buf + 2, buf, 24); - ASSERT_STREQ("ababcdefghijklmnopqrstuvwx", buf); -} diff --git a/test/libc/sock/test.mk b/test/libc/sock/test.mk index aa47dc97a..961a53c4a 100644 --- a/test/libc/sock/test.mk +++ b/test/libc/sock/test.mk @@ -31,6 +31,7 @@ TEST_LIBC_SOCK_DIRECTDEPS = \ LIBC_RUNTIME \ LIBC_SOCK \ LIBC_STDIO \ + LIBC_STR \ LIBC_STUBS \ LIBC_SYSV \ LIBC_TESTLIB \ diff --git a/test/libc/str/memccpy_test.c b/test/libc/str/memccpy_test.c index 3051bffea..fc6cc6357 100644 --- a/test/libc/str/memccpy_test.c +++ b/test/libc/str/memccpy_test.c @@ -23,7 +23,15 @@ #include "libc/testlib/ezbench.h" #include "libc/testlib/testlib.h" -void *memccpy2(void *, const void *, int, size_t); +void *memccpy$pure(void *d, const void *s, int c, size_t n) { + size_t i; + unsigned char *x; + const unsigned char *y; + for (c &= 0xff, x = d, y = s, i = 0; i < n; ++i) { + if ((x[i] = y[i]) == c) return x + i + 1; + } + return NULL; +} TEST(memccpy, testStringCopy) { char buf[16]; @@ -49,7 +57,7 @@ TEST(memccpy, memcpy) { b2 = calloc(1, n); b3 = calloc(1, n); rngset(b1, n, rand64, -1); - e1 = tinymemccpy(b2, b1, 31337, n); + e1 = memccpy$pure(b2, b1, 31337, n); e2 = memccpy(b3, b1, 31337, n); n1 = e1 ? e1 - b2 : n; n2 = e2 ? e2 - b3 : n; diff --git a/test/libc/str/memcpy_test.c b/test/libc/str/memcpy_test.c index 2181c428a..ec1be0696 100644 --- a/test/libc/str/memcpy_test.c +++ b/test/libc/str/memcpy_test.c @@ -18,38 +18,54 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/bits/bits.h" #include "libc/mem/mem.h" +#include "libc/nexgen32e/nexgen32e.h" +#include "libc/rand/rand.h" +#include "libc/stdio/stdio.h" #include "libc/str/str.h" +#include "libc/testlib/ezbench.h" #include "libc/testlib/testlib.h" -TEST(memcpy, memcpy) { +TEST(memcpy, test) { char *b1, *b2; for (unsigned n = 0; n < 1026; ++n) { b1 = malloc(n); b2 = malloc(n); - ASSERT_EQ(b1, memcpy(b1, b2, n)); + rngset(b1, n, rand64, -1); + rngset(b2, n, rand64, -1); + ASSERT_EQ(b1, memcpy(b1, b2, n), "%ld\n\t%#.*s\n\t%#.*s", n, n, b1, n, b2); + ASSERT_EQ(0, memcmp(b1, b2, n)); + free(b2); + free(b1); + } + for (unsigned n = kHalfCache3 - 1; n < kHalfCache3 + 2; ++n) { + b1 = malloc(n); + b2 = malloc(n); + rngset(b1, n, rand64, -1); + rngset(b2, n, rand64, -1); + ASSERT_EQ(b1, memcpy(b1, b2, n), "%ld\n\t%#.*s\n\t%#.*s", n, n, b1, n, b2); ASSERT_EQ(0, memcmp(b1, b2, n)); free(b2); free(b1); } } -TEST(memcpy, memcpyDirect) { +TEST(mempcpy, test) { char *b1, *b2; for (unsigned n = 0; n < 1026; ++n) { b1 = malloc(n); b2 = malloc(n); - ASSERT_EQ(b1, (memcpy)(b1, b2, n)); + rngset(b1, n, rand64, -1); + rngset(b2, n, rand64, -1); + ASSERT_EQ(b1 + n, mempcpy(b1, b2, n)); ASSERT_EQ(0, memcmp(b1, b2, n)); free(b2); free(b1); } -} - -TEST(memcpy, mempcpy) { - char *b1, *b2; - for (unsigned n = 0; n < 1026; ++n) { + for (unsigned n = kHalfCache3 - 1; n < kHalfCache3 + 2; ++n) { b1 = malloc(n); b2 = malloc(n); + rngset(b1, n, rand64, -1); + rngset(b2, n, rand64, -1); ASSERT_EQ(b1 + n, mempcpy(b1, b2, n)); ASSERT_EQ(0, memcmp(b1, b2, n)); free(b2); @@ -57,11 +73,49 @@ TEST(memcpy, mempcpy) { } } -TEST(memcpy, mempcpyDirect) { +TEST(memcpy, direct) { char *b1, *b2; for (unsigned n = 0; n < 1026; ++n) { b1 = malloc(n); b2 = malloc(n); + rngset(b1, n, rand64, -1); + rngset(b2, n, rand64, -1); + ASSERT_EQ(b1, (memcpy)(b1, b2, n), "%ld\n\t%#.*s\n\t%#.*s", n, n, b1, n, + b2); + ASSERT_EQ(0, memcmp(b1, b2, n)); + free(b2); + free(b1); + } + for (unsigned n = kHalfCache3 - 1; n < kHalfCache3 + 2; ++n) { + b1 = malloc(n); + b2 = malloc(n); + rngset(b1, n, rand64, -1); + rngset(b2, n, rand64, -1); + ASSERT_EQ(b1, (memcpy)(b1, b2, n), "%ld\n\t%#.*s\n\t%#.*s", n, n, b1, n, + b2); + ASSERT_EQ(0, memcmp(b1, b2, n)); + free(b2); + free(b1); + } +} + +TEST(mempcpy, direct) { + char *b1, *b2; + for (unsigned n = 0; n < 1026; ++n) { + b1 = malloc(n); + b2 = malloc(n); + rngset(b1, n, rand64, -1); + rngset(b2, n, rand64, -1); + ASSERT_EQ(b1 + n, (mempcpy)(b1, b2, n)); + ASSERT_EQ(0, memcmp(b1, b2, n)); + free(b2); + free(b1); + } + for (unsigned n = kHalfCache3 - 1; n < kHalfCache3 + 2; ++n) { + b1 = malloc(n); + b2 = malloc(n); + rngset(b1, n, rand64, -1); + rngset(b2, n, rand64, -1); ASSERT_EQ(b1 + n, (mempcpy)(b1, b2, n)); ASSERT_EQ(0, memcmp(b1, b2, n)); free(b2); @@ -105,3 +159,44 @@ TEST(memcpy, testBackwardsOverlap3) { EXPECT_EQ('C', c[1]); free(c); } + +void *MemCpy(void *, const void *, size_t); + +#define B(F, N) \ + do { \ + char *d = rngset(malloc(N), N, rand64, -1); \ + char *s = rngset(malloc(N), N, rand64, -1); \ + EZBENCH2(#F " " #N, donothing, \ + EXPROPRIATE(F(VEIL("r", d), VEIL("r", s), N))); \ + free(d); \ + free(s); \ + } while (0) + +#define BB(N) \ + do { \ + B(memmove$pure, N); \ + B(memcpy, N); \ + B(MemCpy, N); \ + fprintf(stderr, "\n"); \ + } while (0) + +BENCH(memcpy, bench) { + BB(0); + BB(1); + BB(2); + BB(3); + BB(7); + BB(8); + BB(15); + BB(16); + BB(31); + BB(32); + BB(63); + BB(64); + BB(255); + BB(256); + BB(1023); + BB(1024); + BB(PAGESIZE); + BB(FRAMESIZE); +} diff --git a/test/libc/str/strchr_test.c b/test/libc/str/strchr_test.c index 7b34a8100..bdb1c6215 100644 --- a/test/libc/str/strchr_test.c +++ b/test/libc/str/strchr_test.c @@ -17,7 +17,10 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/bits/bits.h" +#include "libc/mem/mem.h" +#include "libc/rand/rand.h" #include "libc/str/str.h" +#include "libc/testlib/ezbench.h" #include "libc/testlib/testlib.h" TEST(strchr, blank) { @@ -66,3 +69,99 @@ TEST(strchrnul, notFound_returnsPointerToNulByte) { EXPECT_STREQ("", strchrnul(buf, 'z')); EXPECT_EQ(&buf[2], strchrnul(buf, 'z')); } + +char *strchr$pure(const char *s, int c) { + char *r; + for (c &= 0xff;; ++s) { + if ((*s & 0xff) == c) return (char *)s; + if (!*s) return NULL; + } +} + +TEST(strchr, fuzz) { + char *p; + int i, j; + p = calloc(1, 64); + for (i = -2; i < 257; ++i) { + for (j = 0; j < 17; ++j) { + rngset(p, 63, rand64, -1); + ASSERT_EQ(strchr(p + j, i), strchr$pure(p + j, i)); + } + } + free(p); +} + +BENCH(strchr, bench) { + EZBENCH2("strchr 0", donothing, EXPROPRIATE(strchr(VEIL("r", ""), 0))); + EZBENCH2("strchr 5", donothing, EXPROPRIATE(strchr(VEIL("r", "hello"), 'o'))); + EZBENCH2("strchr 8", donothing, + EXPROPRIATE(strchr(VEIL("r", "hellzzzo"), 'o'))); + EZBENCH2("strchr 17", donothing, + EXPROPRIATE(strchr(VEIL("r", "hellzzzhellzzzeeo"), 'o'))); + EZBENCH2("strchr 34", donothing, + EXPROPRIATE( + strchr(VEIL("r", "hellzzzhellzzzeeAhellzzzhellzzzeeo"), 'o'))); +} + +char *memchr$pure(const char *m, int c, size_t n) { + const unsigned char *p, *pe; + for (c &= 0xff, p = (const unsigned char *)m, pe = p + n; p < pe; ++p) { + if (*p == c) return p; + } + return NULL; +} + +TEST(memchr, fuzz) { + char *p; + int i, j; + p = malloc(64); + for (i = -2; i < 257; ++i) { + for (j = 0; j < 17; ++j) { + rngset(p, 64, rand64, -1); + ASSERT_EQ(memchr(p + j, i, 64 - j), memchr$pure(p + j, i, 64 - j)); + } + } + free(p); +} + +char *strchrnul$pure(const char *s, int c) { + char *r; + for (c &= 0xff;; ++s) { + if ((*s & 0xff) == c) return (char *)s; + if (!*s) return s; + } +} + +TEST(strchrnul, fuzz) { + char *p; + int i, j; + p = calloc(1, 64); + for (i = -2; i < 257; ++i) { + for (j = 0; j < 17; ++j) { + rngset(p, 63, rand64, -1); + ASSERT_EQ(strchrnul(p + j, i), strchrnul$pure(p + j, i)); + } + } + free(p); +} + +void *rawmemchr$pure(const void *m, int c) { + const unsigned char *s; + for (c &= 255, s = m;; ++s) { + if (*s == c) return s; + } +} + +TEST(rawmemchr, fuzz) { + char *p; + int i, j; + p = malloc(64); + for (i = -2; i < 257; ++i) { + for (j = 0; j < 17; ++j) { + rngset(p, 63, rand64, -1); + p[63] = i; + ASSERT_EQ(rawmemchr(p + j, i), rawmemchr$pure(p + j, i)); + } + } + free(p); +} diff --git a/test/libc/str/strlen_test.c b/test/libc/str/strlen_test.c index b874bd6ed..8c1cb1078 100644 --- a/test/libc/str/strlen_test.c +++ b/test/libc/str/strlen_test.c @@ -19,8 +19,10 @@ #include "libc/bits/bits.h" #include "libc/macros.h" #include "libc/mem/mem.h" +#include "libc/nexgen32e/bsr.h" #include "libc/nexgen32e/tinystrlen.internal.h" #include "libc/rand/rand.h" +#include "libc/stdio/stdio.h" #include "libc/str/str.h" #include "libc/testlib/ezbench.h" #include "libc/testlib/testlib.h" @@ -30,6 +32,8 @@ char16_t u16[] = u"utf16 ☻"; wchar_t u32[] = L"utf32 ☻"; TEST(strlen, usageExample_c11) { + _Alignas(16) char ugh[] = "eeeeeeeeeeeeeee\017"; + EXPECT_EQ(1, strlen$pure(ugh + 15)); EXPECT_EQ(6 + 3, strlen(u8)); EXPECT_EQ(7, strlen16(u16)); EXPECT_EQ(7, wcslen(u32)); @@ -143,7 +147,7 @@ TEST(strlen, fuzz) { b = rngset(calloc(1, n), n - 1, rand64, -1); n1 = strlen(b); n2 = strlen$pure(b); - ASSERT_EQ(n1, n2); + ASSERT_EQ(n1, n2, "%#.*s", n, b); n1 = strlen(b + 1); n2 = strlen$pure(b + 1); ASSERT_EQ(n1, n2); @@ -166,8 +170,14 @@ BENCH(strlen, bench) { EZBENCH2("strlen$pure 8", donothing, strlen$pure_("1234567")); EZBENCH2("strlen 9", donothing, strlen_("12345678")); EZBENCH2("strlen$pure 9", donothing, strlen$pure_("12345678")); + EZBENCH2("strlen 11", donothing, strlen_("12345678aa")); + EZBENCH2("strlen$pure 11", donothing, strlen$pure_("12345678aa")); + EZBENCH2("strlen 13", donothing, strlen_("12345678aabb")); + EZBENCH2("strlen$pure 13", donothing, strlen$pure_("12345678aabb")); EZBENCH2("strlen 16", donothing, strlen_("123456781234567")); EZBENCH2("strlen$pure 16", donothing, strlen$pure_("123456781234567")); + EZBENCH2("strlen 17", donothing, strlen_("123456781234567e")); + EZBENCH2("strlen$pure 17", donothing, strlen$pure_("123456781234567e")); EZBENCH2("strlen 1023", donothing, strlen_(b)); EZBENCH2("strlen$pure 1023", donothing, strlen$pure_(b)); } diff --git a/test/libc/tinymath/test.mk b/test/libc/tinymath/test.mk index fbe434b1a..e02150f8d 100644 --- a/test/libc/tinymath/test.mk +++ b/test/libc/tinymath/test.mk @@ -28,6 +28,7 @@ TEST_LIBC_TINYMATH_DIRECTDEPS = \ LIBC_MEM \ LIBC_NEXGEN32E \ LIBC_RUNTIME \ + LIBC_STR \ LIBC_STUBS \ LIBC_TESTLIB \ LIBC_TINYMATH \ diff --git a/third_party/compiler_rt/compiler_rt.mk b/third_party/compiler_rt/compiler_rt.mk index e888d5742..575d5e9d7 100644 --- a/third_party/compiler_rt/compiler_rt.mk +++ b/third_party/compiler_rt/compiler_rt.mk @@ -10,6 +10,7 @@ THIRD_PARTY_COMPILER_RT_A_FILES := \ $(wildcard third_party/compiler_rt/*) \ $(wildcard third_party/compiler_rt/nexgen32e/*) THIRD_PARTY_COMPILER_RT_A_HDRS = $(filter %.h,$(THIRD_PARTY_COMPILER_RT_A_FILES)) +THIRD_PARTY_COMPILER_RT_A_INCS = $(filter %.inc,$(THIRD_PARTY_COMPILER_RT_A_FILES)) THIRD_PARTY_COMPILER_RT_A_SRCS_S = $(filter %.S,$(THIRD_PARTY_COMPILER_RT_A_FILES)) THIRD_PARTY_COMPILER_RT_A_SRCS_C = $(filter %.c,$(THIRD_PARTY_COMPILER_RT_A_FILES)) @@ -51,6 +52,7 @@ $(THIRD_PARTY_COMPILER_RT_A_OBJS): \ THIRD_PARTY_COMPILER_RT_LIBS = $(foreach x,$(THIRD_PARTY_COMPILER_RT_ARTIFACTS),$($(x))) THIRD_PARTY_COMPILER_RT_SRCS = $(foreach x,$(THIRD_PARTY_COMPILER_RT_ARTIFACTS),$($(x)_SRCS)) THIRD_PARTY_COMPILER_RT_HDRS = $(foreach x,$(THIRD_PARTY_COMPILER_RT_ARTIFACTS),$($(x)_HDRS)) +THIRD_PARTY_COMPILER_RT_INCS = $(foreach x,$(THIRD_PARTY_COMPILER_RT_ARTIFACTS),$($(x)_INCS)) THIRD_PARTY_COMPILER_RT_CHECKS = $(foreach x,$(THIRD_PARTY_COMPILER_RT_ARTIFACTS),$($(x)_CHECKS)) THIRD_PARTY_COMPILER_RT_OBJS = $(foreach x,$(THIRD_PARTY_COMPILER_RT_ARTIFACTS),$($(x)_OBJS)) diff --git a/third_party/duktape/duktape.mk b/third_party/duktape/duktape.mk index 49f800c19..81ae7f206 100644 --- a/third_party/duktape/duktape.mk +++ b/third_party/duktape/duktape.mk @@ -8,6 +8,7 @@ THIRD_PARTY_DUKTAPE = $(THIRD_PARTY_DUKTAPE_A_DEPS) $(THIRD_PARTY_DUKTAPE_A) THIRD_PARTY_DUKTAPE_A = o/$(MODE)/third_party/duktape/duktape.a THIRD_PARTY_DUKTAPE_A_FILES := $(wildcard third_party/duktape/*) THIRD_PARTY_DUKTAPE_A_HDRS = $(filter %.h,$(THIRD_PARTY_DUKTAPE_A_FILES)) +THIRD_PARTY_DUKTAPE_A_INCS = $(filter %.inc,$(THIRD_PARTY_DUKTAPE_A_FILES)) THIRD_PARTY_DUKTAPE_A_SRCS_A = $(filter %.s,$(THIRD_PARTY_DUKTAPE_A_FILES)) THIRD_PARTY_DUKTAPE_A_SRCS_S = $(filter %.S,$(THIRD_PARTY_DUKTAPE_A_FILES)) THIRD_PARTY_DUKTAPE_A_SRCS_C = $(filter %.c,$(THIRD_PARTY_DUKTAPE_A_FILES)) @@ -60,6 +61,7 @@ o/dbg/third_party/duktape/duk_js_executor.o: \ THIRD_PARTY_DUKTAPE_LIBS = $(foreach x,$(THIRD_PARTY_DUKTAPE_ARTIFACTS),$($(x))) THIRD_PARTY_DUKTAPE_SRCS = $(foreach x,$(THIRD_PARTY_DUKTAPE_ARTIFACTS),$($(x)_SRCS)) THIRD_PARTY_DUKTAPE_HDRS = $(foreach x,$(THIRD_PARTY_DUKTAPE_ARTIFACTS),$($(x)_HDRS)) +THIRD_PARTY_DUKTAPE_INCS = $(foreach x,$(THIRD_PARTY_DUKTAPE_ARTIFACTS),$($(x)_INCS)) THIRD_PARTY_DUKTAPE_BINS = $(foreach x,$(THIRD_PARTY_DUKTAPE_ARTIFACTS),$($(x)_BINS)) THIRD_PARTY_DUKTAPE_CHECKS = $(foreach x,$(THIRD_PARTY_DUKTAPE_ARTIFACTS),$($(x)_CHECKS)) THIRD_PARTY_DUKTAPE_OBJS = $(foreach x,$(THIRD_PARTY_DUKTAPE_ARTIFACTS),$($(x)_OBJS)) diff --git a/third_party/gdtoa/gdtoa.mk b/third_party/gdtoa/gdtoa.mk index deff0ad14..ef587ed15 100644 --- a/third_party/gdtoa/gdtoa.mk +++ b/third_party/gdtoa/gdtoa.mk @@ -8,6 +8,7 @@ THIRD_PARTY_GDTOA = $(THIRD_PARTY_GDTOA_A_DEPS) $(THIRD_PARTY_GDTOA_A) THIRD_PARTY_GDTOA_A = o/$(MODE)/third_party/gdtoa/gdtoa.a THIRD_PARTY_GDTOA_A_FILES := $(wildcard third_party/gdtoa/*) THIRD_PARTY_GDTOA_A_HDRS = $(filter %.h,$(THIRD_PARTY_GDTOA_A_FILES)) +THIRD_PARTY_GDTOA_A_INCS = $(filter %.inc,$(THIRD_PARTY_GDTOA_A_FILES)) THIRD_PARTY_GDTOA_A_SRCS_S = $(filter %.S,$(THIRD_PARTY_GDTOA_A_FILES)) THIRD_PARTY_GDTOA_A_SRCS_C = $(filter %.c,$(THIRD_PARTY_GDTOA_A_FILES)) @@ -54,6 +55,7 @@ $(THIRD_PARTY_GDTOA_A_OBJS): \ THIRD_PARTY_GDTOA_LIBS = $(foreach x,$(THIRD_PARTY_GDTOA_ARTIFACTS),$($(x))) THIRD_PARTY_GDTOA_SRCS = $(foreach x,$(THIRD_PARTY_GDTOA_ARTIFACTS),$($(x)_SRCS)) THIRD_PARTY_GDTOA_HDRS = $(foreach x,$(THIRD_PARTY_GDTOA_ARTIFACTS),$($(x)_HDRS)) +THIRD_PARTY_GDTOA_INCS = $(foreach x,$(THIRD_PARTY_GDTOA_ARTIFACTS),$($(x)_INCS)) THIRD_PARTY_GDTOA_CHECKS = $(foreach x,$(THIRD_PARTY_GDTOA_ARTIFACTS),$($(x)_CHECKS)) THIRD_PARTY_GDTOA_OBJS = $(foreach x,$(THIRD_PARTY_GDTOA_ARTIFACTS),$($(x)_OBJS)) $(THIRD_PARTY_GDTOA_OBJS): $(BUILD_FILES) third_party/gdtoa/gdtoa.mk diff --git a/third_party/lemon/lemon.mk b/third_party/lemon/lemon.mk index c055b2ada..3de296d05 100644 --- a/third_party/lemon/lemon.mk +++ b/third_party/lemon/lemon.mk @@ -1,6 +1,12 @@ #-*-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───────────────────────┘ +PKGS += THIRD_PARTY_LEMON +THIRD_PARTY_LEMON_FILES := $(wildcard third_party/lemon/*) +THIRD_PARTY_LEMON_HDRS = $(filter %.h,$(THIRD_PARTY_LEMON_FILES)) +THIRD_PARTY_LEMON_INCS = $(filter %.inc,$(THIRD_PARTY_LEMON_FILES)) +THIRD_PARTY_LEMON_SRCS = $(filter %.c,$(THIRD_PARTY_LEMON_FILES)) + LEMON = $(MKDIR) $(@D) && ACTION="LEMON $@" build/do $(THIRD_PARTY_LEMON) THIRD_PARTY_LEMON = o/$(MODE)/third_party/lemon/lemon.com.dbg diff --git a/third_party/lz4cli/bench.c b/third_party/lz4cli/bench.c index 9906cbb3e..a924bf9bb 100644 --- a/third_party/lz4cli/bench.c +++ b/third_party/lz4cli/bench.c @@ -36,8 +36,8 @@ /* ************************************* * Includes ***************************************/ -#include "platform.h" /* Compiler options */ -#include "util.h" /* UTIL_GetFileSize, UTIL_sleep */ +#include "third_party/lz4cli/platform.h" /* Compiler options */ +#include "third_party/lz4cli/util.h" /* UTIL_GetFileSize, UTIL_sleep */ #include "libc/mem/mem.h" /* malloc, free */ #include "libc/str/str.h" /* memset */ #include "libc/stdio/stdio.h" /* fprintf, fopen, ftello */ @@ -46,17 +46,17 @@ #include "libc/bits/initializer.internal.h" #include "libc/runtime/runtime.h" /* assert */ -#include "datagen.h" /* RDG_genBuffer */ -#include "xxhash.h" +#include "third_party/lz4cli/datagen.h" /* RDG_genBuffer */ +#include "third_party/lz4cli/xxhash.h" -#include "lz4.h" +#include "third_party/lz4cli/lz4.h" #define COMPRESSOR0 LZ4_compress_local static int LZ4_compress_local(const char* src, char* dst, int srcSize, int dstSize, int clevel) { int const acceleration = (clevel < 0) ? -clevel + 1 : 1; return LZ4_compress_fast(src, dst, srcSize, dstSize, acceleration); } -#include "lz4hc.h" +#include "third_party/lz4cli/lz4hc.h" #define COMPRESSOR1 LZ4_compress_HC #define DEFAULTCOMPRESSOR COMPRESSOR0 #define LZ4_isError(errcode) (errcode==0) diff --git a/third_party/lz4cli/datagen.c b/third_party/lz4cli/datagen.c index 3ba944cc5..37326dcd2 100644 --- a/third_party/lz4cli/datagen.c +++ b/third_party/lz4cli/datagen.c @@ -27,8 +27,8 @@ /************************************** * Includes **************************************/ -#include "platform.h" /* Compiler options, SET_BINARY_MODE */ -#include "util.h" /* U32 */ +#include "third_party/lz4cli/platform.h" /* Compiler options, SET_BINARY_MODE */ +#include "third_party/lz4cli/util.h" /* U32 */ #include "libc/mem/mem.h" /* malloc */ #include "libc/stdio/stdio.h" /* FILE, fwrite */ #include "libc/str/str.h" /* memcpy */ diff --git a/third_party/lz4cli/lz4.c b/third_party/lz4cli/lz4.c index 6853188a3..cfaed5688 100644 --- a/third_party/lz4cli/lz4.c +++ b/third_party/lz4cli/lz4.c @@ -94,7 +94,7 @@ **************************************/ #define LZ4_STATIC_LINKING_ONLY #define LZ4_DISABLE_DEPRECATE_WARNINGS /* due to LZ4_decompress_safe_withPrefix64k */ -#include "lz4.h" +#include "third_party/lz4cli/lz4.h" /* see also "memory routines" below */ diff --git a/third_party/lz4cli/lz4cli.c b/third_party/lz4cli/lz4cli.c index f4e181fe3..1ce02243e 100644 --- a/third_party/lz4cli/lz4cli.c +++ b/third_party/lz4cli/lz4cli.c @@ -36,17 +36,17 @@ asm(".include \"third_party/lz4cli/COPYING\""); /**************************** * Includes *****************************/ -#include "platform.h" /* Compiler options, IS_CONSOLE */ -#include "util.h" /* UTIL_HAS_CREATEFILELIST, UTIL_createFileList */ +#include "third_party/lz4cli/platform.h" /* Compiler options, IS_CONSOLE */ +#include "third_party/lz4cli/util.h" /* UTIL_HAS_CREATEFILELIST, UTIL_createFileList */ #include "libc/stdio/stdio.h" /* fprintf, getchar */ #include "libc/mem/mem.h" /* exit, calloc, free */ #include "libc/str/str.h" /* strcmp, strlen */ -#include "bench.h" /* BMK_benchFile, BMK_SetNbIterations, BMK_SetBlocksize, BMK_SetPause */ -#include "lz4io.h" /* LZ4IO_compressFilename, LZ4IO_decompressFilename, LZ4IO_compressMultipleFilenames */ -#include "lz4hc.h" /* LZ4HC_CLEVEL_MAX */ +#include "third_party/lz4cli/bench.h" /* BMK_benchFile, BMK_SetNbIterations, BMK_SetBlocksize, BMK_SetPause */ +#include "third_party/lz4cli/lz4io.h" /* LZ4IO_compressFilename, LZ4IO_decompressFilename, LZ4IO_compressMultipleFilenames */ +#include "third_party/lz4cli/lz4hc.h" /* LZ4HC_CLEVEL_MAX */ #include "libc/runtime/runtime.h" #include "libc/log/log.h" -#include "lz4.h" /* LZ4_VERSION_STRING */ +#include "third_party/lz4cli/lz4.h" /* LZ4_VERSION_STRING */ /***************************** diff --git a/third_party/lz4cli/lz4cli.mk b/third_party/lz4cli/lz4cli.mk index c46dae862..48116f25e 100644 --- a/third_party/lz4cli/lz4cli.mk +++ b/third_party/lz4cli/lz4cli.mk @@ -13,6 +13,10 @@ PKGS += THIRD_PARTY_LZ4CLI +THIRD_PARTY_LZ4CLI_FILES := $(wildcard third_party/lz4cli/*) +THIRD_PARTY_LZ4CLI_SRCS = $(filter %.c,$(THIRD_PARTY_LZ4CLI_FILES)) +THIRD_PARTY_LZ4CLI_HDRS = $(filter %.h,$(THIRD_PARTY_LZ4CLI_FILES)) + THIRD_PARTY_LZ4CLI = \ o/$(MODE)/third_party/lz4cli/lz4cli.com diff --git a/third_party/lz4cli/lz4hc.c b/third_party/lz4cli/lz4hc.c index 68ea9d32d..fa8cc4025 100644 --- a/third_party/lz4cli/lz4hc.c +++ b/third_party/lz4cli/lz4hc.c @@ -51,7 +51,7 @@ /*=== Dependency ===*/ #define LZ4_HC_STATIC_LINKING_ONLY -#include "lz4hc.h" +#include "third_party/lz4cli/lz4hc.h" /*=== Common LZ4 definitions ===*/ @@ -63,7 +63,7 @@ #endif #define LZ4_COMMONDEFS_ONLY -#include "lz4.c" /* LZ4_count, constants, mem */ +#include "third_party/lz4cli/lz4.c" /* LZ4_count, constants, mem */ /*=== Constants ===*/ diff --git a/third_party/lz4cli/lz4hc.h b/third_party/lz4cli/lz4hc.h index e18bd1cd5..f412c5da0 100644 --- a/third_party/lz4cli/lz4hc.h +++ b/third_party/lz4cli/lz4hc.h @@ -41,7 +41,7 @@ extern "C" { /* --- Dependency --- */ /* note : lz4hc requires lz4.h/lz4.c for compilation */ -#include "lz4.h" /* stddef, LZ4LIB_API, LZ4_DEPRECATED */ +#include "third_party/lz4cli/lz4.h" /* stddef, LZ4LIB_API, LZ4_DEPRECATED */ /* --- Useful constants --- */ diff --git a/third_party/lz4cli/xxhash.c b/third_party/lz4cli/xxhash.c index cdac03e12..2e157f83a 100644 --- a/third_party/lz4cli/xxhash.c +++ b/third_party/lz4cli/xxhash.c @@ -106,7 +106,7 @@ static void XXH_free (void* p) { free(p); } static void* XXH_memcpy(void* dest, const void* src, size_t size) { return memcpy(dest,src,size); } #define XXH_STATIC_LINKING_ONLY -#include "xxhash.h" +#include "third_party/lz4cli/xxhash.h" /* ************************************* diff --git a/third_party/lz4cli/xxhash.h b/third_party/lz4cli/xxhash.h index 0be20cc8f..0048760f5 100644 --- a/third_party/lz4cli/xxhash.h +++ b/third_party/lz4cli/xxhash.h @@ -280,7 +280,7 @@ XXH_PUBLIC_API XXH64_hash_t XXH64_hashFromCanonical(const XXH64_canonical_t* src #endif # ifdef XXH_PRIVATE_API -# include "xxhash.c" /* include xxhash function bodies as `static`, for inlining */ +# include "third_party/lz4cli/xxhash.c" /* include xxhash function bodies as `static`, for inlining */ # endif #endif /* XXH_STATIC_LINKING_ONLY */ diff --git a/third_party/regex/regex.mk b/third_party/regex/regex.mk index ecb602015..a052c695e 100644 --- a/third_party/regex/regex.mk +++ b/third_party/regex/regex.mk @@ -8,6 +8,7 @@ THIRD_PARTY_REGEX = $(THIRD_PARTY_REGEX_A_DEPS) $(THIRD_PARTY_REGEX_A) THIRD_PARTY_REGEX_A = o/$(MODE)/third_party/regex/regex.a THIRD_PARTY_REGEX_A_FILES := $(wildcard third_party/regex/*) THIRD_PARTY_REGEX_A_HDRS = $(filter %.h,$(THIRD_PARTY_REGEX_A_FILES)) +THIRD_PARTY_REGEX_A_INCS = $(filter %.inc,$(THIRD_PARTY_REGEX_A_FILES)) THIRD_PARTY_REGEX_A_SRCS = $(filter %.c,$(THIRD_PARTY_REGEX_A_FILES)) THIRD_PARTY_REGEX_A_OBJS = \ diff --git a/tool/build/blinkenlights.c b/tool/build/blinkenlights.c index 0d47a85c0..0e14cd992 100644 --- a/tool/build/blinkenlights.c +++ b/tool/build/blinkenlights.c @@ -245,6 +245,10 @@ static long rombase; static long codesize; static int64_t opstart; static int64_t mapsstart; +static uint64_t readaddr; +static uint64_t readsize; +static uint64_t writeaddr; +static uint64_t writesize; static int64_t framesstart; static int64_t breakpointsstart; static uint64_t last_opcount; @@ -424,6 +428,10 @@ static void OnSigBusted(void) { longjmp(onbusted, 1); } +static bool IsShadow(int64_t v) { + return 0x7fff8000 <= v && v < 0x100080000000; +} + static int VirtualBing(int64_t v) { int rc; uint8_t *p; @@ -446,7 +454,7 @@ static int VirtualShadow(int64_t v) { int rc; char *p; jmp_buf busted; - if (0x7fff8000 <= v && v < 0x100080000000) return -2; + if (IsShadow(v)) return -2; onbusted = busted; if ((p = FindReal(m, (v >> 3) + 0x7fff8000))) { if (!setjmp(busted)) { @@ -1171,11 +1179,12 @@ static void DrawSse(struct Panel *p) { } static void ScrollMemoryView(struct Panel *p, struct MemoryView *v, int64_t a) { - long i, n; + long i, n, w; + w = DUMPWIDTH * (1ull << v->zoom); n = p->bottom - p->top; - i = a / (DUMPWIDTH * (1ull << v->zoom)); + i = a / w; if (!(v->start <= i && i < v->start + n)) { - v->start = i; + v->start = i - n / 4; } } @@ -1194,8 +1203,8 @@ static void ZoomMemoryView(struct MemoryView *v, long y, long x, int dy) { static void ScrollMemoryViews(void) { ScrollMemoryView(&pan.code, &codeview, GetIp()); - ScrollMemoryView(&pan.readdata, &readview, m->readaddr); - ScrollMemoryView(&pan.writedata, &writeview, m->writeaddr); + ScrollMemoryView(&pan.readdata, &readview, readaddr); + ScrollMemoryView(&pan.writedata, &writeview, writeaddr); ScrollMemoryView(&pan.stack, &stackview, GetSp()); } @@ -1299,9 +1308,9 @@ static void DrawMemoryUnzoomed(struct Panel *p, struct MemoryView *view, if (sc > 7) { x = 129; /* PURPLE: shadow corruption */ } else if (sc == kAsanHeapFree) { - x = 17; /* NAVYBLUE: heap freed */ + x = 20; /* BLUE: heap freed */ } else if (sc == kAsanRelocated) { - x = 18; /* DARKBLUE: heap relocated */ + x = 16; /* BLACK: heap relocated */ } else if (sc == kAsanHeapUnderrun || sc == kAsanAllocaUnderrun) { x = 53; /* RED+PURPLETINGE: heap underrun */ } else if (sc == kAsanHeapOverrun || sc == kAsanAllocaOverrun) { @@ -1309,7 +1318,7 @@ static void DrawMemoryUnzoomed(struct Panel *p, struct MemoryView *view, } else if (sc < 0) { x = 52; /* RED: uncategorized invalid */ } else if (sc > 0 && (k & 7) >= sc) { - x = 54; /* REDPURP: invalid address (skew) */ + x = 88; /* BRIGHTRED: invalid address (skew) */ } else if (!sc || (sc > 0 && (k & 7) < sc)) { x = 22; /* GREEN: valid address */ } else { @@ -1529,6 +1538,14 @@ static void PreventBufferbloat(void) { static void Redraw(void) { int i, j; + if (!IsShadow(m->readaddr) && !IsShadow(m->readaddr + m->readsize)) { + readaddr = m->readaddr; + readsize = m->readsize; + } + if (!IsShadow(m->writeaddr) && !IsShadow(m->writeaddr + m->writesize)) { + writeaddr = m->writeaddr; + writesize = m->writesize; + } ScrollOp(&pan.disassembly, GetDisIndex()); if (last_opcount) { ips = unsignedsubtract(opcount, last_opcount) / (nowl() - last_seconds); @@ -1555,9 +1572,8 @@ static void Redraw(void) { DrawFrames(&pan.frames); DrawBreakpoints(&pan.breakpoints); DrawMemory(&pan.code, &codeview, GetIp(), GetIp() + m->xedd->length); - DrawMemory(&pan.readdata, &readview, m->readaddr, m->readaddr + m->readsize); - DrawMemory(&pan.writedata, &writeview, m->writeaddr, - m->writeaddr + m->writesize); + DrawMemory(&pan.readdata, &readview, readaddr, readaddr + readsize); + DrawMemory(&pan.writedata, &writeview, writeaddr, writeaddr + writesize); DrawMemory(&pan.stack, &stackview, GetSp(), GetSp() + GetPointerWidth()); DrawStatus(&pan.status); PreventBufferbloat(); diff --git a/tool/build/lib/syscall.c b/tool/build/lib/syscall.c index d78880fa0..b2ac15305 100644 --- a/tool/build/lib/syscall.c +++ b/tool/build/lib/syscall.c @@ -1011,6 +1011,10 @@ static int OpMkdir(struct Machine *m, int64_t path, int mode) { return mkdir(LoadStr(m, path), mode); } +static int OpMkdirat(struct Machine *m, int dirfd, int64_t path, int mode) { + return mkdirat(XlatAfd(m, dirfd), LoadStr(m, path), mode); +} + static int OpMknod(struct Machine *m, int64_t path, uint32_t mode, uint64_t dev) { return mknod(LoadStr(m, path), mode, dev); @@ -1024,10 +1028,20 @@ static int OpUnlink(struct Machine *m, int64_t path) { return unlink(LoadStr(m, path)); } +static int OpUnlinkat(struct Machine *m, int dirfd, int64_t path, int flags) { + return unlinkat(XlatAfd(m, dirfd), LoadStr(m, path), XlatAtf(flags)); +} + static int OpRename(struct Machine *m, int64_t src, int64_t dst) { return rename(LoadStr(m, src), LoadStr(m, dst)); } +static int OpRenameat(struct Machine *m, int srcdirfd, int64_t src, + int dstdirfd, int64_t dst) { + return renameat(XlatAfd(m, srcdirfd), LoadStr(m, src), XlatAfd(m, dstdirfd), + LoadStr(m, dst)); +} + static int OpTruncate(struct Machine *m, int64_t path, uint64_t length) { return truncate(LoadStr(m, path), length); } @@ -1384,12 +1398,12 @@ void OpSyscall(struct Machine *m, uint32_t rde) { SYSCALL(0x0DD, OpFadvise(m, di, si, dx, r0)); SYSCALL(0x0E4, OpClockGettime(m, di, si)); SYSCALL(0x101, OpOpenat(m, di, si, dx, r0)); - SYSCALL(0x102, mkdirat(XlatAfd(m, di), P(si), dx)); + SYSCALL(0x102, OpMkdirat(m, di, si, dx)); SYSCALL(0x104, fchownat(XlatAfd(m, di), P(si), dx, r0, XlatAtf(r8))); SYSCALL(0x105, futimesat(XlatAfd(m, di), P(si), P(dx))); SYSCALL(0x106, OpFstatat(m, di, si, dx, r0)); - SYSCALL(0x107, unlinkat(XlatAfd(m, di), P(si), XlatAtf(dx))); - SYSCALL(0x108, renameat(XlatAfd(m, di), P(si), XlatAfd(m, dx), P(r0))); + SYSCALL(0x107, OpUnlinkat(m, di, si, dx)); + SYSCALL(0x108, OpRenameat(m, di, si, dx, r0)); SYSCALL(0x10D, OpFaccessat(m, di, si, dx, r0)); SYSCALL(0x113, splice(di, P(si), dx, P(r0), r8, XlatAtf(r9))); SYSCALL(0x115, sync_file_range(di, si, dx, XlatAtf(r0))); diff --git a/tool/emacs/cosmo-c-builtins.el b/tool/emacs/cosmo-c-builtins.el index cb068a29c..355de558c 100644 --- a/tool/emacs/cosmo-c-builtins.el +++ b/tool/emacs/cosmo-c-builtins.el @@ -259,6 +259,8 @@ "__builtin_lrintf" "__builtin_lrintl" "__builtin_memcpy" + "__builtin_mempcpy" + "__builtin_memmove" "__builtin_memcmp" "__builtin_memset" "__builtin_strlen"))