mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-05-23 05:42:29 +00:00
Make more functions friendly to Address Sanitizer
This commit is contained in:
parent
3ab76b2312
commit
cbfd4ccd1e
70 changed files with 1267 additions and 291 deletions
|
@ -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))
|
||||
|
||||
|
@ -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))
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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_;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)))
|
||||
|
||||
#───────────────────────────────────────────────────────────────────────────────
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
|
47
libc/str/memchr.c
Normal file
47
libc/str/memchr.c
Normal file
|
@ -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;
|
||||
}
|
160
libc/str/memmove-pure.c
Normal file
160
libc/str/memmove-pure.c
Normal file
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
100
libc/str/memset-pure.c
Normal file
100
libc/str/memset-pure.c
Normal file
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
53
libc/str/rawmemchr.c
Normal file
53
libc/str/rawmemchr.c
Normal file
|
@ -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;
|
||||
}
|
|
@ -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__ */
|
||||
|
|
|
@ -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))
|
||||
|
|
69
libc/str/strchr.c
Normal file
69
libc/str/strchr.c
Normal file
|
@ -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;
|
||||
}
|
69
libc/str/strchrnul.c
Normal file
69
libc/str/strchrnul.c
Normal file
|
@ -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;
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
62
libc/str/strcspn-pure.c
Normal file
62
libc/str/strcspn-pure.c
Normal file
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
|
57
libc/str/strnlen.c
Normal file
57
libc/str/strnlen.c
Normal file
|
@ -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;
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue