Merge branch 'master' into feature/sqliteSerialization

This commit is contained in:
Daniel Oltmanns 2022-06-24 11:30:13 +02:00 committed by GitHub
commit de54cee6ef
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
242 changed files with 9015 additions and 2635 deletions

29
.github/workflows/build.yml vendored Normal file
View file

@ -0,0 +1,29 @@
name: build
on:
push:
branches:
- "master"
pull_request:
branches:
- "master"
# run workflow manually from the Actions tab
workflow_dispatch:
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: support ape bins
run: sudo sh -c "echo ':APE:M::MZqFpD::/bin/sh:' >/proc/sys/fs/binfmt_misc/register"
# gh-action runners have 2 cpus with 1 thread each
- name: make everything
run: V=0 make -j2
- name: printargs.com
run: ./o/examples/printargs.com

View file

@ -1,6 +0,0 @@
virt: lxd
os: linux
language: c
script: make -j4 V=0
notifications:
email: false

View file

@ -148,6 +148,7 @@ include third_party/linenoise/linenoise.mk
include third_party/maxmind/maxmind.mk include third_party/maxmind/maxmind.mk
include third_party/lua/lua.mk include third_party/lua/lua.mk
include third_party/make/make.mk include third_party/make/make.mk
include third_party/finger/finger.mk
include third_party/argon2/argon2.mk include third_party/argon2/argon2.mk
include third_party/smallz4/smallz4.mk include third_party/smallz4/smallz4.mk
include third_party/sqlite3/sqlite3.mk include third_party/sqlite3/sqlite3.mk

View file

@ -1,5 +1,6 @@
![Cosmopolitan Honeybadger](usr/share/img/honeybadger.png) ![Cosmopolitan Honeybadger](usr/share/img/honeybadger.png)
[![build](https://github.com/jart/cosmopolitan/actions/workflows/build.yml/badge.svg)](https://github.com/jart/cosmopolitan/actions/workflows/build.yml)
# Cosmopolitan # Cosmopolitan
[Cosmopolitan Libc](https://justine.lol/cosmopolitan/index.html) makes C [Cosmopolitan Libc](https://justine.lol/cosmopolitan/index.html) makes C
@ -226,3 +227,15 @@ gdb foo.com -ex 'add-symbol-file foo.com.dbg 0x401000'
| FreeBSD | 13 | 2020 | | FreeBSD | 13 | 2020 |
| OpenBSD | 6.4 | 2018 | | OpenBSD | 6.4 | 2018 |
| NetBSD | 9.2 | 2021 | | NetBSD | 9.2 | 2021 |
## Special Thanks
Funding for this project is crowdsourced using
[GitHub Sponsors](https://github.com/sponsors/jart) and
[Patreon](https://www.patreon.com/jart). Your support is what makes this
project possible. Thank you! We'd also like to give special thanks to
the following individuals:
- [Joe Drumgoole](https://github.com/jdrumgoole)
For publicly sponsoring our work at the highest tier.

View file

@ -553,32 +553,6 @@ SHSTUB2(ape_loader_dd_count,
? ROUNDUP(ape_loader_end - ape_loader, PAGESIZE) / 64 ? ROUNDUP(ape_loader_end - ape_loader, PAGESIZE) / 64
: 0); : 0);
#if SupportsXnu()
SHSTUB2(ape_macho_dd_skip, RVA(ape_macho) / 8);
SHSTUB2(ape_macho_dd_count, (ape_macho_end - ape_macho) / 8);
#endif
#if SupportsWindows() || SupportsMetal()
#define LINK_WINDOWS (SupportsWindows() && !DEFINED(EfiMain))
PFSTUB4(ape_pe_offset, ape_pe - ape_mz);
HIDDEN(ape_pe_optsz = ape_pe_sections - (ape_pe + 24));
HIDDEN(ape_pe_shnum = (ape_pe_sections_end - ape_pe_sections) / 40);
HIDDEN(ape_pe_base = IMAGE_BASE_VIRTUAL);
HIDDEN(ape_idata = LINK_WINDOWS ? RVA(ape_idata_iat) : 0);
HIDDEN(ape_idata_iatsize = LINK_WINDOWS ? ape_idata_iatend - ape_idata_iat : 0);
HIDDEN(ape_idata = LINK_WINDOWS ? RVA(ape_idata_idt) : 0);
HIDDEN(ape_idata_idtsize = LINK_WINDOWS ? ape_idata_idtend - ape_idata_idt : 0);
HIDDEN(v_ntversion = LINK_WINDOWS ? 6 : 1);
HIDDEN(v_ntdllchar = LINK_WINDOWS ? 288 : 0);
HIDDEN(v_ntsubversion = LINK_WINDOWS ? 6 : 5);
HIDDEN(v_ntsubsystem = (LINK_WINDOWS
? (DEFINED(GetMessage)
? kNtImageSubsystemWindowsGui
: kNtImageSubsystemWindowsCui)
: kNtImageSubsystemEfiApplication));
HIDDEN(ape_pe_entry = LINK_WINDOWS ? WinMain : EfiMain);
#endif
#if SupportsMetal() #if SupportsMetal()
HIDDEN(v_ape_realsectors = HIDDEN(v_ape_realsectors =
MIN(0x70000 - IMAGE_BASE_REAL, MIN(0x70000 - IMAGE_BASE_REAL,
@ -685,6 +659,32 @@ CHURN(WinMain);
#endif /* SupportsWindows() */ #endif /* SupportsWindows() */
#endif /* SupportsXnu() */ #endif /* SupportsXnu() */
#if SupportsWindows() || SupportsMetal()
#define LINK_WINDOWS (SupportsWindows() && !DEFINED(EfiMain))
PFSTUB4(ape_pe_offset, ape_pe - ape_mz);
HIDDEN(ape_pe_optsz = ape_pe_sections - (ape_pe + 24));
HIDDEN(ape_pe_shnum = (ape_pe_sections_end - ape_pe_sections) / 40);
HIDDEN(ape_pe_base = IMAGE_BASE_VIRTUAL);
HIDDEN(ape_idata = LINK_WINDOWS ? RVA(ape_idata_iat) : 0);
HIDDEN(ape_idata_iatsize = LINK_WINDOWS ? ape_idata_iatend - ape_idata_iat : 0);
HIDDEN(ape_idata = LINK_WINDOWS ? RVA(ape_idata_idt) : 0);
HIDDEN(ape_idata_idtsize = LINK_WINDOWS ? ape_idata_idtend - ape_idata_idt : 0);
HIDDEN(v_ntversion = LINK_WINDOWS ? 6 : 1);
HIDDEN(v_ntdllchar = LINK_WINDOWS ? 288 : 0);
HIDDEN(v_ntsubversion = LINK_WINDOWS ? 6 : 5);
HIDDEN(v_ntsubsystem = (LINK_WINDOWS
? (DEFINED(GetMessage)
? kNtImageSubsystemWindowsGui
: kNtImageSubsystemWindowsCui)
: kNtImageSubsystemEfiApplication));
HIDDEN(ape_pe_entry = LINK_WINDOWS ? WinMain : EfiMain);
#endif
#if SupportsXnu()
SHSTUB2(ape_macho_dd_skip, RVA(ape_macho) / 8);
SHSTUB2(ape_macho_dd_count, (ape_macho_end - ape_macho) / 8);
#endif
ASSERT(DEFINED(ape_mz) ? ape_mz == IMAGE_BASE_VIRTUAL : 1, "linker panic"); ASSERT(DEFINED(ape_mz) ? ape_mz == IMAGE_BASE_VIRTUAL : 1, "linker panic");
ASSERT((DEFINED(__init_bss_end) ? __init_bss_end : 0) % __SIZEOF_POINTER__ == 0, ASSERT((DEFINED(__init_bss_end) ? __init_bss_end : 0) % __SIZEOF_POINTER__ == 0,
"__init_bss misalign"); "__init_bss misalign");

Binary file not shown.

View file

@ -71,8 +71,8 @@
* Like redbean, greenbean has superior performance too, with an * Like redbean, greenbean has superior performance too, with an
* advantage on benchmarks biased towards high connection counts * advantage on benchmarks biased towards high connection counts
* *
* $ wrk -c 300 -t 32 --latency http://10.10.10.124:8080/ * $ wrk -c 300 -t 32 --latency http://127.0.0.1:8080/
* Running 10s test @ http://10.10.10.124:8080/ * Running 10s test @ http://127.0.0.1:8080/
* 32 threads and 300 connections * 32 threads and 300 connections
* Thread Stats Avg Stdev Max +/- Stdev * Thread Stats Avg Stdev Max +/- Stdev
* Latency 661.06us 5.11ms 96.22ms 98.85% * Latency 661.06us 5.11ms 96.22ms 98.85%

View file

@ -96,7 +96,7 @@ o/$(MODE)/examples/pyapp/pyapp.com.dbg: \
o/$(MODE)/examples/pyapp/pyapp.o \ o/$(MODE)/examples/pyapp/pyapp.o \
$(CRT) \ $(CRT) \
$(APE_NO_MODIFY_SELF) $(APE_NO_MODIFY_SELF)
$(LINK) $(LINKARGS) -o $@ @$(COMPILE) -ALINK.ape $(LINK) $(LINKARGS) -o $@
# # Unwrap the APE .COM binary, that's embedded within the linked file # # Unwrap the APE .COM binary, that's embedded within the linked file
# # NOTE: This line can be commented out, since it's in build/rules.mk # # NOTE: This line can be commented out, since it's in build/rules.mk

View file

@ -1,15 +1,11 @@
SYNOPSIS # Cosmopolitan Standard Library
Cosmopolitan Standard Library.
OVERVIEW
This directory defines static archives defining functions, like This directory defines static archives defining functions, like
printf(), mmap(), win32, etc. Please note that the Cosmopolitan `printf()`, `mmap()`, win32, etc. Please note that the Cosmopolitan
build configuration doesn't link any C/C++ library dependencies build configuration doesn't link any C/C++ library dependencies
by default, so you still have the flexibility to choose the one by default, so you still have the flexibility to choose the one
provided by your system. If you'd prefer Cosmopolitan, just add provided by your system. If you'd prefer Cosmopolitan, just add
$(LIBC) and $(CRT) to your linker arguments. `$(LIBC)` and `$(CRT)` to your linker arguments.
Your library is compromised of many bite-sized static archives. Your library is compromised of many bite-sized static archives.
We use the checkdeps tool to guarantee that the contents of the We use the checkdeps tool to guarantee that the contents of the
@ -20,8 +16,8 @@ OVERVIEW
The Cosmopolitan Library exports only the most stable canonical The Cosmopolitan Library exports only the most stable canonical
system calls for all supported operating systems, regardless of system calls for all supported operating systems, regardless of
which platform is used for compilation. We polyfill many of the which platform is used for compilation. We polyfill many of the
APIs, e.g. read(), write() so they work consistently everywhere APIs, e.g. `read()`, `write()` so they work consistently everywhere
while other apis, e.g. CreateWindowEx(), might only work on one while other apis, e.g. `CreateWindowEx()`, might only work on one
platform, in which case they become no-op functions on others. platform, in which case they become no-op functions on others.
Cosmopolitan polyfill wrappers will usually use the dollar sign Cosmopolitan polyfill wrappers will usually use the dollar sign
@ -31,11 +27,11 @@ OVERVIEW
allow Cosmopolitan to go fast on both old and newer computers. allow Cosmopolitan to go fast on both old and newer computers.
We take an approach to configuration that relies heavily on the We take an approach to configuration that relies heavily on the
compiler's dead code elimination pass (libc/dce.h). Most of the compiler's dead code elimination pass (`libc/dce.h`). Most of the
code is written so that, for example, folks not wanting support code is written so that, for example, folks not wanting support
for OpenBSD can flip a bit in SUPPORT_VECTOR and that code will for OpenBSD can flip a bit in `SUPPORT_VECTOR` and that code will
be omitted from the build. The same is true for builds that are be omitted from the build. The same is true for builds that are
tuned using -march=native which effectively asks the library to tuned using `-march=native` which effectively asks the library to
not include runtime support hooks for x86 processors older than not include runtime support hooks for x86 processors older than
what you use. what you use.

View file

@ -20,7 +20,7 @@
#include "libc/bits/asmflag.h" #include "libc/bits/asmflag.h"
#include "libc/bits/bits.h" #include "libc/bits/bits.h"
#include "libc/calls/asan.internal.h" #include "libc/calls/asan.internal.h"
#include "libc/calls/clock_gettime.h" #include "libc/calls/clock_gettime.internal.h"
#include "libc/calls/internal.h" #include "libc/calls/internal.h"
#include "libc/calls/state.internal.h" #include "libc/calls/state.internal.h"
#include "libc/calls/strace.internal.h" #include "libc/calls/strace.internal.h"

View file

@ -7,8 +7,8 @@ COSMOPOLITAN_C_START_
typedef int clock_gettime_f(int, struct timespec *); typedef int clock_gettime_f(int, struct timespec *);
extern clock_gettime_f *__clock_gettime; extern clock_gettime_f *__clock_gettime;
hidden clock_gettime_f __clock_gettime_init; clock_gettime_f *__clock_gettime_get(bool *) hidden;
hidden clock_gettime_f *__clock_gettime_get(bool *); int __clock_gettime_init(int, struct timespec *) hidden;
COSMOPOLITAN_C_END_ COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */

79
libc/calls/getcontext.S Normal file
View file

@ -0,0 +1,79 @@
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi
Copyright 2022 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/macros.internal.h"
// Gets machine state.
//
// @note please use longerjmp() and setlongerjmp() for fibers
// @note currently only gets general registers
// @see setcontext()
getcontext:
mov %r8,40(%rdi)
mov %r9,48(%rdi)
mov %r10,56(%rdi)
mov %r11,64(%rdi)
mov %r12,72(%rdi)
mov %r13,80(%rdi)
mov %r14,88(%rdi)
mov %r15,96(%rdi)
mov %rdi,104(%rdi)
mov %rsi,112(%rdi)
mov %rbp,120(%rdi)
mov %rbx,128(%rdi)
mov %rdx,136(%rdi)
mov %rax,144(%rdi)
mov %rcx,152(%rdi)
lea 8(%rsp),%rax
mov %rax,160(%rdi)
mov (%rsp),%rax
mov %rax,168(%rdi)
xor %eax,%eax
ret
.endfn getcontext,globl
.end
////////////////////////////////////////////////////////////////////////////////
noasan noubsan noinstrument int getcontext(ucontext_t *uc) {
asm volatile("mov\t%%r8,%0" : "=m"(uc->uc_mcontext.r8));
asm volatile("mov\t%%r9,%0" : "=m"(uc->uc_mcontext.r9));
asm volatile("mov\t%%r10,%0" : "=m"(uc->uc_mcontext.r10));
asm volatile("mov\t%%r11,%0" : "=m"(uc->uc_mcontext.r11));
asm volatile("mov\t%%r12,%0" : "=m"(uc->uc_mcontext.r12));
asm volatile("mov\t%%r13,%0" : "=m"(uc->uc_mcontext.r13));
asm volatile("mov\t%%r14,%0" : "=m"(uc->uc_mcontext.r14));
asm volatile("mov\t%%r15,%0" : "=m"(uc->uc_mcontext.r15));
asm volatile("mov\t%%rdi,%0" : "=m"(uc->uc_mcontext.rdi));
asm volatile("mov\t%%rsi,%0" : "=m"(uc->uc_mcontext.rsi));
asm volatile("mov\t%%rbp,%0" : "=m"(uc->uc_mcontext.rbp));
asm volatile("mov\t%%rbx,%0" : "=m"(uc->uc_mcontext.rbx));
asm volatile("mov\t%%rdx,%0" : "=m"(uc->uc_mcontext.rdx));
asm volatile("mov\t%%rax,%0" : "=m"(uc->uc_mcontext.rax));
asm volatile("mov\t%%rcx,%0" : "=m"(uc->uc_mcontext.rcx));
asm volatile("lea\t8(%%rsp),%%rax\n\t"
"mov\t%%rax,%0"
: "=m"(uc->uc_mcontext.rsp)
: /* no inputs */
: "rax");
asm volatile("mov\t(%%rsp),%%rax\n\t"
"mov\t%%rax,%0"
: "=m"(uc->uc_mcontext.rip)
: /* no inputs */
: "rax");
return 0;
}

View file

@ -93,12 +93,21 @@ static int ioctl_siocgifconf_sysv(int fd, struct ifconf *ifc) {
return rc; return rc;
} }
forceinline void Sockaddr2linux(void *saddr) {
char *p;
if (saddr) {
p = saddr;
p[0] = p[1];
p[1] = 0;
}
}
/* Used for all the ioctl that returns sockaddr structure that /* Used for all the ioctl that returns sockaddr structure that
* requires adjustment between Linux and XNU * requires adjustment between Linux and XNU
*/ */
static int ioctl_siocgifaddr_sysv(int fd, uint64_t op, struct ifreq *ifr) { static int ioctl_siocgifaddr_sysv(int fd, uint64_t op, struct ifreq *ifr) {
if (sys_ioctl(fd, op, ifr) == -1) return -1; if (sys_ioctl(fd, op, ifr) == -1) return -1;
if (IsBsd()) sockaddr2linux(&ifr->ifr_addr); if (IsBsd()) Sockaddr2linux(&ifr->ifr_addr);
return 0; return 0;
} }

View file

@ -24,7 +24,7 @@
int sys_nanosleep_xnu(const struct timespec *req, struct timespec *rem) { int sys_nanosleep_xnu(const struct timespec *req, struct timespec *rem) {
long millis; long millis;
millis = div1000int64(req->tv_nsec); millis = req->tv_nsec / 1000;
millis = MAX(1, millis); millis = MAX(1, millis);
return sys_select(0, 0, 0, 0, &(struct timeval){req->tv_sec, millis}); return sys_select(0, 0, 0, 0, &(struct timeval){req->tv_sec, millis});
} }

View file

@ -20,7 +20,7 @@
#include "libc/bits/initializer.internal.h" #include "libc/bits/initializer.internal.h"
#include "libc/bits/safemacros.internal.h" #include "libc/bits/safemacros.internal.h"
#include "libc/calls/calls.h" #include "libc/calls/calls.h"
#include "libc/calls/clock_gettime.h" #include "libc/calls/clock_gettime.internal.h"
#include "libc/calls/internal.h" #include "libc/calls/internal.h"
#include "libc/calls/state.internal.h" #include "libc/calls/state.internal.h"
#include "libc/calls/strace.internal.h" #include "libc/calls/strace.internal.h"

73
libc/calls/setcontext.S Normal file
View file

@ -0,0 +1,73 @@
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi
Copyright 2022 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/macros.internal.h"
// Sets machine state.
//
// @note please use longerjmp() and setlongerjmp() for fibers
// @note currently only sets general registers
// @see getcontext()
setcontext:
mov 40(%rdi),%r8
mov 48(%rdi),%r9
mov 56(%rdi),%r10
mov 64(%rdi),%r11
mov 72(%rdi),%r12
mov 80(%rdi),%r13
mov 88(%rdi),%r14
mov 96(%rdi),%r15
mov 112(%rdi),%rsi
mov 120(%rdi),%rbp
mov 128(%rdi),%rbx
mov 136(%rdi),%rdx
mov 144(%rdi),%rax
mov 152(%rdi),%rcx
mov 160(%rdi),%rsp
xor %rax,%rax
push 168(%rdi)
mov 104(%rdi),%rdi
ret
.endfn setcontext,globl
.end
////////////////////////////////////////////////////////////////////////////////
noasan noubsan int setcontext(const ucontext_t *uc) {
asm volatile("mov\t%0,%%r8" : /* no outputs */ : "m"(uc->uc_mcontext.r8));
asm volatile("mov\t%0,%%r9" : /* no outputs */ : "m"(uc->uc_mcontext.r9));
asm volatile("mov\t%0,%%r10" : /* no outputs */ : "m"(uc->uc_mcontext.r10));
asm volatile("mov\t%0,%%r11" : /* no outputs */ : "m"(uc->uc_mcontext.r11));
asm volatile("mov\t%0,%%r12" : /* no outputs */ : "m"(uc->uc_mcontext.r12));
asm volatile("mov\t%0,%%r13" : /* no outputs */ : "m"(uc->uc_mcontext.r13));
asm volatile("mov\t%0,%%r14" : /* no outputs */ : "m"(uc->uc_mcontext.r14));
asm volatile("mov\t%0,%%r15" : /* no outputs */ : "m"(uc->uc_mcontext.r15));
asm volatile("mov\t%0,%%rsi" : /* no outputs */ : "m"(uc->uc_mcontext.rsi));
asm volatile("mov\t%0,%%rbp" : /* no outputs */ : "m"(uc->uc_mcontext.rbp));
asm volatile("mov\t%0,%%rbx" : /* no outputs */ : "m"(uc->uc_mcontext.rbx));
asm volatile("mov\t%0,%%rdx" : /* no outputs */ : "m"(uc->uc_mcontext.rdx));
asm volatile("mov\t%0,%%rax" : /* no outputs */ : "m"(uc->uc_mcontext.rax));
asm volatile("mov\t%0,%%rcx" : /* no outputs */ : "m"(uc->uc_mcontext.rcx));
asm volatile("mov\t%0,%%rsp" : /* no outputs */ : "m"(uc->uc_mcontext.rsp));
asm volatile("xor\t%%rax,%%rax\n\t"
"push\t%0\n\t"
"mov\t%1,%%rdi\n\t"
"ret"
: /* no outputs */
: "m"(uc->uc_mcontext.rip), "m"(uc->uc_mcontext.rdi));
unreachable;
}

View file

@ -12,6 +12,7 @@ int __notziposat(int, const char *);
int gethostname_bsd(char *, size_t) hidden; int gethostname_bsd(char *, size_t) hidden;
int gethostname_linux(char *, size_t) hidden; int gethostname_linux(char *, size_t) hidden;
int gethostname_nt(char *, size_t, int) hidden; int gethostname_nt(char *, size_t, int) hidden;
long sys_bogus(void);
void *__vdsosym(const char *, const char *) hidden; void *__vdsosym(const char *, const char *) hidden;
void __onfork(void) hidden; void __onfork(void) hidden;
void __restore_rt() hidden; void __restore_rt() hidden;

View file

@ -82,6 +82,9 @@ struct ucontext {
typedef struct ucontext ucontext_t; typedef struct ucontext ucontext_t;
int getcontext(ucontext_t *);
int setcontext(const ucontext_t *);
COSMOPOLITAN_C_END_ COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_CALLS_UCONTEXT_H_ */ #endif /* COSMOPOLITAN_LIBC_CALLS_UCONTEXT_H_ */

View file

@ -41,19 +41,19 @@ int sys_utimensat_xnu(int dirfd, const char *path, const struct timespec ts[2],
tv[0] = now; tv[0] = now;
} else if (ts[0].tv_nsec == UTIME_OMIT) { } else if (ts[0].tv_nsec == UTIME_OMIT) {
tv[0].tv_sec = st.st_atim.tv_sec; tv[0].tv_sec = st.st_atim.tv_sec;
tv[0].tv_usec = div1000int64(st.st_atim.tv_nsec); tv[0].tv_usec = st.st_atim.tv_nsec / 1000;
} else { } else {
tv[0].tv_sec = ts[0].tv_sec; tv[0].tv_sec = ts[0].tv_sec;
tv[0].tv_usec = div1000int64(ts[0].tv_nsec); tv[0].tv_usec = ts[0].tv_nsec / 1000;
} }
if (ts[1].tv_nsec == UTIME_NOW) { if (ts[1].tv_nsec == UTIME_NOW) {
tv[1] = now; tv[1] = now;
} else if (ts[1].tv_nsec == UTIME_OMIT) { } else if (ts[1].tv_nsec == UTIME_OMIT) {
tv[1].tv_sec = st.st_mtim.tv_sec; tv[1].tv_sec = st.st_mtim.tv_sec;
tv[1].tv_usec = div1000int64(st.st_mtim.tv_nsec); tv[1].tv_usec = st.st_mtim.tv_nsec / 1000;
} else { } else {
tv[1].tv_sec = ts[1].tv_sec; tv[1].tv_sec = ts[1].tv_sec;
tv[1].tv_usec = div1000int64(ts[1].tv_nsec); tv[1].tv_usec = ts[1].tv_nsec / 1000;
} }
} else { } else {
tv[0] = now; tv[0] = now;

View file

@ -39,7 +39,7 @@
* @param service is the port number as a string * @param service is the port number as a string
* @param hints may be passed to specialize behavior (optional) * @param hints may be passed to specialize behavior (optional)
* @param res receives a pointer that must be freed with freeaddrinfo(), * @param res receives a pointer that must be freed with freeaddrinfo(),
* and won't be modified if -1 is returned * and won't be modified if non-zero is returned
* @return 0 on success or EAI_xxx value * @return 0 on success or EAI_xxx value
* @threadsafe * @threadsafe
*/ */

View file

@ -1,7 +1,7 @@
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set et ft=asm ts=8 sw=8 fenc=utf-8 :vi vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney Copyright 2022 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the any purpose with or without fee is hereby granted, provided that the
@ -16,18 +16,8 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "libc/macros.internal.h" #include "libc/fmt/fmt.h"
// TODO(jart): pmovzxbw and vpunpcklbw int __xpg_strerror_r(int a, char *b, size_t c) {
strcpyzbw: return strerror_r(a, b, c);
.leafprologue }
.profilable
push %rdi
xor %eax,%eax
1: lodsb
stosw
test %al,%al
jnz 1b
pop %rax
.leafepilogue
.endfn strcpyzbw,globl

View file

@ -50,14 +50,18 @@ int64_t TimeValToWindowsTime(struct timeval) libcesque nosideeffect;
struct timeval WindowsDurationToTimeVal(int64_t) libcesque nosideeffect; struct timeval WindowsDurationToTimeVal(int64_t) libcesque nosideeffect;
struct timespec WindowsDurationToTimeSpec(int64_t) libcesque nosideeffect; struct timespec WindowsDurationToTimeSpec(int64_t) libcesque nosideeffect;
static inline struct NtFileTime MakeFileTime(int64_t x) { #define MakeFileTime(x) \
return (struct NtFileTime){(uint32_t)x, (uint32_t)(x >> 32)}; ({ \
} int64_t __x = x; \
(struct NtFileTime){(uint32_t)__x, (uint32_t)(__x >> 32)}; \
})
static inline int64_t ReadFileTime(struct NtFileTime t) { #define ReadFileTime(t) \
uint64_t x = t.dwHighDateTime; ({ \
return x << 32 | t.dwLowDateTime; struct NtFileTime __t = t; \
} uint64_t x = __t.dwHighDateTime; \
(int64_t)(x << 32 | __t.dwLowDateTime); \
})
#define FileTimeToTimeSpec(x) WindowsTimeToTimeSpec(ReadFileTime(x)) #define FileTimeToTimeSpec(x) WindowsTimeToTimeSpec(ReadFileTime(x))
#define FileTimeToTimeVal(x) WindowsTimeToTimeVal(ReadFileTime(x)) #define FileTimeToTimeVal(x) WindowsTimeToTimeVal(ReadFileTime(x))

View file

@ -1,7 +1,7 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney Copyright 2022 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the any purpose with or without fee is hereby granted, provided that the
@ -19,8 +19,10 @@
#include "libc/str/str.h" #include "libc/str/str.h"
/** /**
* Copies memory the legacy way. * Moves memory the BSD way.
*
* Please use memmove() instead. Note the order of arguments.
*/ */
void *bcopy(void *dst, const void *src, size_t n) { void bcopy(const void *src, void *dest, size_t n) {
return memmove(dst, src, n); memmove(dest, src, n);
} }

View file

@ -0,0 +1,12 @@
#ifndef COSMOPOLITAN_LIBC_INTRIN_FUTEX_INTERNAL_H_
#define COSMOPOLITAN_LIBC_INTRIN_FUTEX_INTERNAL_H_
#include "libc/calls/struct/timespec.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
int _futex_wait(void *, int, struct timespec *);
int _futex_wake(void *, int);
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_INTRIN_FUTEX_INTERNAL_H_ */

44
libc/intrin/futex_wait.c Normal file
View file

@ -0,0 +1,44 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2022 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/bits/asmflag.h"
#include "libc/calls/strace.internal.h"
#include "libc/calls/struct/timespec.h"
#include "libc/intrin/describeflags.internal.h"
#include "libc/intrin/futex.internal.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/futex.h"
#include "libc/sysv/consts/nr.h"
privileged int _futex_wait(void *addr, int expect, struct timespec *timeout) {
int ax;
bool cf;
char buf[45];
asm volatile(CFLAG_ASM("mov\t%6,%%r10\n\t"
"clc\n\t"
"syscall")
: CFLAG_CONSTRAINT(cf), "=a"(ax)
: "1"(__NR_futex), "D"(addr), "S"(FUTEX_WAIT), "d"(expect),
"g"(timeout)
: "rcx", "r10", "r11", "memory");
if (cf) ax = -ax;
STRACE("futex(%p, FUTEX_WAIT, %d, %s) → %s", addr, expect,
DescribeTimespec(buf, sizeof(buf), 0, timeout),
ax ? strerrno(-ax) : "0");
return ax;
}

49
libc/intrin/futex_wake.c Normal file
View file

@ -0,0 +1,49 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2022 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/bits/asmflag.h"
#include "libc/calls/strace.internal.h"
#include "libc/fmt/itoa.h"
#include "libc/intrin/futex.internal.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/futex.h"
#include "libc/sysv/consts/nr.h"
static const char *FormatFutexWakeResult(char buf[12], int ax) {
if (ax >= 0) {
FormatInt32(buf, ax);
return buf;
} else {
return strerrno(-ax);
}
}
privileged int _futex_wake(void *addr, int count) {
int ax;
bool cf;
char buf[12];
asm volatile(CFLAG_ASM("clc\n\t"
"syscall")
: CFLAG_CONSTRAINT(cf), "=a"(ax)
: "1"(__NR_futex), "D"(addr), "S"(FUTEX_WAKE), "d"(count)
: "rcx", "r11", "memory");
if (cf) ax = -ax;
STRACE("futex(%p, FUTEX_WAKE, %d) → %s", addr, count,
FormatFutexWakeResult(buf, ax));
return ax;
}

View file

@ -73,6 +73,8 @@ o/$(MODE)/libc/intrin/kprintf.greg.o: \
-fno-stack-protector -fno-stack-protector
# synchronization primitives are intended to be magic free # synchronization primitives are intended to be magic free
o/$(MODE)/libc/intrin/futex_wait.o \
o/$(MODE)/libc/intrin/futex_wake.o \
o/$(MODE)/libc/intrin/gettid.greg.o \ o/$(MODE)/libc/intrin/gettid.greg.o \
o/$(MODE)/libc/intrin/pthread_mutex_lock.o \ o/$(MODE)/libc/intrin/pthread_mutex_lock.o \
o/$(MODE)/libc/intrin/pthread_mutex_unlock.o \ o/$(MODE)/libc/intrin/pthread_mutex_unlock.o \

View file

@ -4,6 +4,8 @@
#include "libc/calls/struct/timespec.h" #include "libc/calls/struct/timespec.h"
#include "libc/dce.h" #include "libc/dce.h"
#define PTHREAD_KEYS_MAX 64
#define PTHREAD_ONCE_INIT 0 #define PTHREAD_ONCE_INIT 0
#define PTHREAD_MUTEX_DEFAULT PTHREAD_MUTEX_NORMAL #define PTHREAD_MUTEX_DEFAULT PTHREAD_MUTEX_NORMAL
@ -24,6 +26,8 @@ COSMOPOLITAN_C_START_
typedef unsigned long *pthread_t; typedef unsigned long *pthread_t;
typedef int pthread_once_t; typedef int pthread_once_t;
typedef unsigned pthread_key_t;
typedef void (*pthread_key_dtor)(void *);
typedef struct { typedef struct {
int attr; int attr;
@ -105,6 +109,10 @@ int pthread_rwlock_wrlock(pthread_rwlock_t *);
int pthread_rwlock_trywrlock(pthread_rwlock_t *); int pthread_rwlock_trywrlock(pthread_rwlock_t *);
int pthread_rwlock_timedwrlock(pthread_rwlock_t *, const struct timespec *); int pthread_rwlock_timedwrlock(pthread_rwlock_t *, const struct timespec *);
int pthread_rwlock_unlock(pthread_rwlock_t *); int pthread_rwlock_unlock(pthread_rwlock_t *);
int pthread_key_create(pthread_key_t *, pthread_key_dtor);
int pthread_key_delete(pthread_key_t);
int pthread_setspecific(pthread_key_t, void *);
void *pthread_getspecific(pthread_key_t);
#define pthread_mutexattr_init(pAttr) ((pAttr)->attr = PTHREAD_MUTEX_DEFAULT, 0) #define pthread_mutexattr_init(pAttr) ((pAttr)->attr = PTHREAD_MUTEX_DEFAULT, 0)
#define pthread_mutexattr_destroy(pAttr) ((pAttr)->attr = 0) #define pthread_mutexattr_destroy(pAttr) ((pAttr)->attr = 0)
@ -118,14 +126,16 @@ int pthread_rwlock_unlock(pthread_rwlock_t *);
!atomic_exchange(&(mutex)->lock, 1)) \ !atomic_exchange(&(mutex)->lock, 1)) \
? 0 \ ? 0 \
: pthread_mutex_lock(mutex)) : pthread_mutex_lock(mutex))
/*
#define pthread_mutex_unlock(mutex) \ #define pthread_mutex_unlock(mutex) \
((mutex)->attr == PTHREAD_MUTEX_NORMAL \ ((mutex)->attr == PTHREAD_MUTEX_NORMAL \
? (atomic_store_explicit(&(mutex)->lock, 0, memory_order_relaxed), \ ? (atomic_store_explicit(&(mutex)->lock, 0, memory_order_relaxed), \
(IsLinux() && \ ((IsLinux() || IsOpenbsd()) && \
atomic_load_explicit(&(mutex)->waits, memory_order_relaxed) && \ atomic_load_explicit(&(mutex)->waits, memory_order_relaxed) && \
_pthread_mutex_wake(mutex)), \ _pthread_mutex_wake(mutex)), \
0) \ 0) \
: pthread_mutex_unlock(mutex)) : pthread_mutex_unlock(mutex))
*/
#endif #endif
int _pthread_mutex_wake(pthread_mutex_t *) hidden; int _pthread_mutex_wake(pthread_mutex_t *) hidden;

View file

@ -16,6 +16,7 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "libc/errno.h"
#include "libc/intrin/pthread.h" #include "libc/intrin/pthread.h"
#include "libc/str/str.h" #include "libc/str/str.h"
@ -24,6 +25,12 @@
* @return 0 on success, or error number on failure * @return 0 on success, or error number on failure
*/ */
int pthread_mutex_destroy(pthread_mutex_t *mutex) { int pthread_mutex_destroy(pthread_mutex_t *mutex) {
int rc;
if (!mutex->lock && !mutex->waits) {
rc = 0;
} else {
rc = EDEADLK;
}
bzero(mutex, sizeof(*mutex)); bzero(mutex, sizeof(*mutex));
return 0; return 0;
} }

View file

@ -16,14 +16,18 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "libc/bits/asmflag.h"
#include "libc/bits/atomic.h" #include "libc/bits/atomic.h"
#include "libc/calls/calls.h" #include "libc/calls/calls.h"
#include "libc/dce.h" #include "libc/dce.h"
#include "libc/errno.h" #include "libc/errno.h"
#include "libc/intrin/futex.internal.h"
#include "libc/intrin/pthread.h" #include "libc/intrin/pthread.h"
#include "libc/intrin/spinlock.h" #include "libc/intrin/spinlock.h"
#include "libc/linux/futex.h" #include "libc/linux/futex.h"
#include "libc/nexgen32e/threaded.h" #include "libc/nexgen32e/threaded.h"
#include "libc/sysv/consts/futex.h"
#include "libc/sysv/consts/nr.h"
static int pthread_mutex_lock_spin(pthread_mutex_t *mutex, int tries) { static int pthread_mutex_lock_spin(pthread_mutex_t *mutex, int tries) {
volatile int i; volatile int i;
@ -31,9 +35,9 @@ static int pthread_mutex_lock_spin(pthread_mutex_t *mutex, int tries) {
for (i = 0; i != 1 << tries; i++) { for (i = 0; i != 1 << tries; i++) {
} }
tries++; tries++;
} else if (IsLinux()) { } else if (IsLinux() || IsOpenbsd()) {
atomic_fetch_add(&mutex->waits, 1); atomic_fetch_add(&mutex->waits, 1);
LinuxFutexWait(&mutex->lock, 1, 0); _futex_wait(&mutex->lock, 1, &(struct timespec){1});
atomic_fetch_sub(&mutex->waits, 1); atomic_fetch_sub(&mutex->waits, 1);
} else { } else {
sched_yield(); sched_yield();

View file

@ -40,8 +40,8 @@ int(pthread_mutex_unlock)(pthread_mutex_t *mutex) {
// fallthrough // fallthrough
case PTHREAD_MUTEX_NORMAL: case PTHREAD_MUTEX_NORMAL:
atomic_store_explicit(&mutex->lock, 0, memory_order_relaxed); atomic_store_explicit(&mutex->lock, 0, memory_order_relaxed);
if (IsLinux() && if ((IsLinux() || IsOpenbsd()) &&
atomic_load_explicit(&mutex->waits, memory_order_relaxed)) { atomic_load_explicit(&mutex->waits, memory_order_relaxed) > 0) {
_pthread_mutex_wake(mutex); _pthread_mutex_wake(mutex);
} }
return 0; return 0;

View file

@ -16,11 +16,9 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "libc/bits/atomic.h" #include "libc/intrin/futex.internal.h"
#include "libc/dce.h"
#include "libc/intrin/pthread.h" #include "libc/intrin/pthread.h"
#include "libc/linux/futex.h"
int _pthread_mutex_wake(pthread_mutex_t *mutex) { int _pthread_mutex_wake(pthread_mutex_t *mutex) {
return LinuxFutexWake(&mutex->lock, 1); return _futex_wake(&mutex->lock, 1);
} }

View file

@ -1,7 +0,0 @@
#ifndef COSMOPOLITAN_LIBC_INTRIN_REFCOUNT_H_
#define COSMOPOLITAN_LIBC_INTRIN_REFCOUNT_H_
#define _incref(x) __atomic_fetch_add(x, 1, __ATOMIC_RELAXED)
#define _decref(x) __atomic_sub_fetch(x, 1, __ATOMIC_SEQ_CST)
#endif /* COSMOPOLITAN_LIBC_INTRIN_REFCOUNT_H_ */

View file

@ -30,6 +30,7 @@ sched_yield:
testb IsXnu() testb IsXnu()
jz 1f jz 1f
pause pause
xor %eax,%eax
ret ret
#endif #endif

View file

@ -1,7 +1,7 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney Copyright 2022 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the any purpose with or without fee is hereby granted, provided that the
@ -16,40 +16,29 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "libc/str/internal.h" #include "libc/bits/atomic.h"
#include "libc/calls/calls.h"
#include "libc/dce.h"
#include "libc/intrin/futex.internal.h"
#include "libc/intrin/wait0.internal.h"
#include "libc/linux/futex.h"
unsigned cescapec(int c) { /**
unsigned char ch = c; * Blocks until memory location becomes zero.
switch (ch) { *
case '\a': * This is intended to be used on the child thread id, which is updated
return '\\' | 'a' << 8; * by the clone() system call when a thread terminates. The purpose of
case '\b': * this operation is to know when it's safe to munmap() a thread stack.
return '\\' | 'b' << 8; */
case '\v': void _wait0(int *ptid) {
return '\\' | 'v' << 8; int x;
case '\f': for (;;) {
return '\\' | 'f' << 8; if (!(x = atomic_load_explicit(ptid, memory_order_relaxed))) {
case '\?': break;
return '\\' | '?' << 8; } else if (IsLinux() || IsOpenbsd()) {
case '\n': _futex_wait(ptid, x, &(struct timespec){2});
return '\\' | 'n' << 8;
case '\r':
return '\\' | 'r' << 8;
case '\t':
return '\\' | 't' << 8;
case '\"':
return '\\' | '"' << 8;
case '\'':
return '\\' | '\'' << 8;
case '\\':
return '\\' | '\\' << 8;
default: {
if (ch >= 0x80 || !isprint(ch)) {
return '\\' | (ch / 64 + '0') << 8 | (ch % 64 / 8 + '0') << 16 |
(ch % 8 + '0') << 24;
} else { } else {
return ch; sched_yield();
}
} }
} }
} }

View file

@ -1,20 +1,10 @@
#ifndef COSMOPOLITAN_LIBC_INTRIN_WAIT0_H_ #ifndef COSMOPOLITAN_LIBC_INTRIN_WAIT0_H_
#define COSMOPOLITAN_LIBC_INTRIN_WAIT0_H_ #define COSMOPOLITAN_LIBC_INTRIN_WAIT0_H_
#include "libc/bits/atomic.h" #if !(__ASSEMBLER__ + __LINKER__ + 0)
#include "libc/calls/calls.h" COSMOPOLITAN_C_START_
#include "libc/dce.h"
#include "libc/linux/futex.h"
#define _wait0(ptid) \ void _wait0(int *) hidden;
do { \
int x; \
if (!(x = atomic_load_explicit(ptid, memory_order_relaxed))) { \
break; \
} else if (IsLinux()) { \
LinuxFutexWait(ptid, x, 0); \
} else { \
sched_yield(); \
} \
} while (1)
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_INTRIN_WAIT0_H_ */ #endif /* COSMOPOLITAN_LIBC_INTRIN_WAIT0_H_ */

4
libc/isystem/utmp.h Normal file
View file

@ -0,0 +1,4 @@
#ifndef COSMOPOLITAN_LIBC_ISYSTEM_UTMP_H_
#define COSMOPOLITAN_LIBC_ISYSTEM_UTMP_H_
#include "libc/runtime/utmp.h"
#endif /* COSMOPOLITAN_LIBC_ISYSTEM_UTMP_H_ */

4
libc/isystem/utmpx.h Normal file
View file

@ -0,0 +1,4 @@
#ifndef COSMOPOLITAN_LIBC_ISYSTEM_UTMPX_H_
#define COSMOPOLITAN_LIBC_ISYSTEM_UTMPX_H_
#include "libc/runtime/utmpx.h"
#endif /* COSMOPOLITAN_LIBC_ISYSTEM_UTMPX_H_ */

View file

@ -1,16 +1,16 @@
#ifndef COSMOPOLITAN_LIBC_LINUX_FUTEX_H_ #ifndef COSMOPOLITAN_LIBC_LINUX_FUTEX_H_
#define COSMOPOLITAN_LIBC_LINUX_FUTEX_H_ #define COSMOPOLITAN_LIBC_LINUX_FUTEX_H_
#if !(__ASSEMBLER__ + __LINKER__ + 0)
#include "libc/calls/struct/timespec.h" #include "libc/calls/struct/timespec.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0)
forceinline int LinuxFutexWait(void *addr, int expect, forceinline int LinuxFutexWait(void *addr, int expect,
struct timespec *timeout) { struct timespec *timeout) {
int ax; int ax;
register void *r10 asm("r10") = timeout; asm volatile("mov\t%5,%%r10\n\t"
asm volatile("syscall" "syscall"
: "=a"(ax) : "=a"(ax)
: "0"(202), "D"(addr), "S"(0), "d"(expect), "r"(r10) : "0"(202), "D"(addr), "S"(0), "d"(expect), "g"(timeout)
: "rcx", "r11", "memory"); : "rcx", "r10", "r11", "memory");
return ax; return ax;
} }

View file

@ -43,14 +43,7 @@ relegated wontreturn void __die(void) {
if (IsDebuggerPresent(false)) { if (IsDebuggerPresent(false)) {
DebugBreak(); DebugBreak();
} }
if (weaken(ShowBacktrace)) { ShowBacktrace(2, __builtin_frame_address(0));
weaken(ShowBacktrace)(2, __builtin_frame_address(0));
} else if (weaken(PrintBacktraceUsingSymbols) && weaken(GetSymbolTable)) {
weaken(PrintBacktraceUsingSymbols)(2, __builtin_frame_address(0),
weaken(GetSymbolTable)());
} else {
kprintf("can't backtrace b/c `ShowCrashReports` not linked\n");
}
__restorewintty(); __restorewintty();
_Exit(77); _Exit(77);
} else if (owner == me) { } else if (owner == me) {

View file

@ -16,6 +16,7 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "libc/fmt/itoa.h"
#include "libc/log/log.h" #include "libc/log/log.h"
#include "libc/str/str.h" #include "libc/str/str.h"
#include "libc/sysv/consts/sicode.h" #include "libc/sysv/consts/sicode.h"
@ -29,13 +30,17 @@ static bool IsSiUser(int si_code) {
} }
} }
static void NameIt(char p[17], const char *s, int si_code) {
p = stpcpy(p, s);
FormatInt32(p, si_code);
}
/** /**
* Returns symbolic name for siginfo::si_code value. * Returns symbolic name for siginfo::si_code value.
*/ */
const char *GetSiCodeName(int sig, int si_code) { const char *GetSiCodeName(int sig, int si_code) {
static char b[16]; static char b[17];
bzero(b, sizeof(b)); NameIt(b, "SI_", si_code);
strcpy(b, "SI_???");
if (si_code == SI_QUEUE) { if (si_code == SI_QUEUE) {
strcpy(b + 3, "QUEUE"); /* sent by sigqueue(2) */ strcpy(b + 3, "QUEUE"); /* sent by sigqueue(2) */
} else if (si_code == SI_TIMER) { } else if (si_code == SI_TIMER) {
@ -55,7 +60,7 @@ const char *GetSiCodeName(int sig, int si_code) {
} else if (IsSiUser(si_code)) { } else if (IsSiUser(si_code)) {
strcpy(b + 3, "USER"); /* sent by kill(2) i.e. from userspace */ strcpy(b + 3, "USER"); /* sent by kill(2) i.e. from userspace */
} else if (sig == SIGCHLD) { } else if (sig == SIGCHLD) {
strcpy(b, "CLD_???"); NameIt(b, "CLD_", si_code);
if (si_code == CLD_EXITED) { if (si_code == CLD_EXITED) {
strcpy(b + 4, "EXITED"); /* child exited */ strcpy(b + 4, "EXITED"); /* child exited */
} else if (si_code == CLD_KILLED) { } else if (si_code == CLD_KILLED) {
@ -70,14 +75,14 @@ const char *GetSiCodeName(int sig, int si_code) {
strcpy(b + 4, "CONTINUED"); /* stopped child continued */ strcpy(b + 4, "CONTINUED"); /* stopped child continued */
} }
} else if (sig == SIGTRAP) { } else if (sig == SIGTRAP) {
strcpy(b, "TRAP_???"); NameIt(b, "TRAP_", si_code);
if (si_code == TRAP_BRKPT) { if (si_code == TRAP_BRKPT) {
strcpy(b + 5, "BRKPT"); /* process breakpoint */ strcpy(b + 5, "BRKPT"); /* process breakpoint */
} else if (si_code == TRAP_TRACE) { } else if (si_code == TRAP_TRACE) {
strcpy(b + 5, "TRACE"); /* process trace trap */ strcpy(b + 5, "TRACE"); /* process trace trap */
} }
} else if (sig == SIGSEGV) { } else if (sig == SIGSEGV) {
strcpy(b, "SEGV_???"); NameIt(b, "SEGV_", si_code);
if (si_code == SEGV_MAPERR) { if (si_code == SEGV_MAPERR) {
strcpy(b + 5, "MAPERR"); /* address not mapped to object */ strcpy(b + 5, "MAPERR"); /* address not mapped to object */
} else if (si_code == SEGV_ACCERR) { } else if (si_code == SEGV_ACCERR) {
@ -86,7 +91,7 @@ const char *GetSiCodeName(int sig, int si_code) {
strcpy(b + 5, "PKUERR"); /* FreeBSD: x86: PKU violation */ strcpy(b + 5, "PKUERR"); /* FreeBSD: x86: PKU violation */
} }
} else if (sig == SIGFPE) { } else if (sig == SIGFPE) {
strcpy(b, "FPE_???"); NameIt(b, "FPE_???", si_code);
if (si_code == FPE_INTDIV) { if (si_code == FPE_INTDIV) {
strcpy(b + 4, "INTDIV"); /* integer divide by zero */ strcpy(b + 4, "INTDIV"); /* integer divide by zero */
} else if (si_code == FPE_INTOVF) { } else if (si_code == FPE_INTOVF) {
@ -105,7 +110,7 @@ const char *GetSiCodeName(int sig, int si_code) {
strcpy(b + 4, "FLTSUB"); /* subscript out of range */ strcpy(b + 4, "FLTSUB"); /* subscript out of range */
} }
} else if (sig == SIGILL) { } else if (sig == SIGILL) {
strcpy(b, "ILL_???"); NameIt(b, "ILL_", si_code);
if (si_code == ILL_ILLOPC) { if (si_code == ILL_ILLOPC) {
strcpy(b + 4, "ILLOPC"); /* illegal opcode */ strcpy(b + 4, "ILLOPC"); /* illegal opcode */
} else if (si_code == ILL_ILLOPN) { } else if (si_code == ILL_ILLOPN) {
@ -124,7 +129,7 @@ const char *GetSiCodeName(int sig, int si_code) {
strcpy(b + 4, "BADSTK"); /* internal stack error */ strcpy(b + 4, "BADSTK"); /* internal stack error */
} }
} else if (sig == SIGBUS) { } else if (sig == SIGBUS) {
strcpy(b, "BUS_???"); NameIt(b, "BUS_", si_code);
if (si_code == BUS_ADRALN) { if (si_code == BUS_ADRALN) {
strcpy(b + 4, "ADRALN"); /* invalid address alignment */ strcpy(b + 4, "ADRALN"); /* invalid address alignment */
} else if (si_code == BUS_ADRERR) { } else if (si_code == BUS_ADRERR) {
@ -139,7 +144,7 @@ const char *GetSiCodeName(int sig, int si_code) {
strcpy(b + 4, "MCEERR_AO"); /* Linux 2.6.32+ */ strcpy(b + 4, "MCEERR_AO"); /* Linux 2.6.32+ */
} }
} else if (sig == SIGIO) { } else if (sig == SIGIO) {
strcpy(b, "POLL_???"); NameIt(b, "POLL_", si_code);
if (si_code == POLL_IN) { if (si_code == POLL_IN) {
strcpy(b + 5, "IN"); /* data input available */ strcpy(b + 5, "IN"); /* data input available */
} else if (si_code == POLL_OUT) { } else if (si_code == POLL_OUT) {

View file

@ -8,7 +8,7 @@
COSMOPOLITAN_C_START_ COSMOPOLITAN_C_START_
extern hidden bool __nocolor; extern hidden bool __nocolor;
extern hidden int kCrashSigs[7]; extern hidden int kCrashSigs[8];
extern hidden bool g_isrunningundermake; extern hidden bool g_isrunningundermake;
void __start_fatal(const char *, int) hidden; void __start_fatal(const char *, int) hidden;

View file

@ -58,7 +58,7 @@ static const char kGregNames[17][4] forcealign(1) = {
static const char kCpuFlags[12] forcealign(1) = "CVPRAKZSTIDO"; static const char kCpuFlags[12] forcealign(1) = "CVPRAKZSTIDO";
static const char kFpuExceptions[6] forcealign(1) = "IDZOUP"; static const char kFpuExceptions[6] forcealign(1) = "IDZOUP";
int kCrashSigs[7]; int kCrashSigs[8];
relegated static void ShowFunctionCalls(ucontext_t *ctx) { relegated static void ShowFunctionCalls(ucontext_t *ctx) {
struct StackFrame *bp; struct StackFrame *bp;

View file

@ -24,7 +24,7 @@
__oncrash_thunks: __oncrash_thunks:
// <SYNC-LIST>: showcrashreports.c, oncrashthunks.S, oncrash.c // <SYNC-LIST>: showcrashreports.c, oncrashthunks.S, oncrash.c, internal.h
.org 11*0 .org 11*0
__oncrash_sigquit: __oncrash_sigquit:
@ -89,6 +89,15 @@ __oncrash_sigbus:
ret ret
.endfn __oncrash_sigbus,globl .endfn __oncrash_sigbus,globl
// </SYNC-LIST>: showcrashreports.c, oncrashthunks.S, oncrash.c .org 11*7
__oncrash_sigsys:
push %rbp
mov %rsp,%rbp
call __oncrash
pop %rbp
ret
.endfn __oncrash_sigsys,globl
// </SYNC-LIST>: showcrashreports.c, oncrashthunks.S, oncrash.c, internal.h
.endobj __oncrash_thunks,globl .endobj __oncrash_thunks,globl

View file

@ -39,7 +39,7 @@ STATIC_YOINK("__get_symbol_by_addr"); // for asan memory origin
extern const unsigned char __oncrash_thunks[8][11]; extern const unsigned char __oncrash_thunks[8][11];
static struct sigaltstack g_oldsigaltstack; static struct sigaltstack g_oldsigaltstack;
static struct sigaction g_oldcrashacts[7]; static struct sigaction g_oldcrashacts[8];
static void InstallCrashHandlers(int extraflags) { static void InstallCrashHandlers(int extraflags) {
size_t i; size_t i;
@ -104,6 +104,7 @@ void ShowCrashReports(void) {
kCrashSigs[4] = SIGTRAP; /* bad system call */ kCrashSigs[4] = SIGTRAP; /* bad system call */
kCrashSigs[5] = SIGABRT; /* abort() called */ kCrashSigs[5] = SIGABRT; /* abort() called */
kCrashSigs[6] = SIGBUS; /* misaligned, noncanonical ptr, etc. */ kCrashSigs[6] = SIGBUS; /* misaligned, noncanonical ptr, etc. */
kCrashSigs[7] = SIGSYS; /* bad system call */
/* </SYNC-LIST>: showcrashreports.c, oncrashthunks.S, oncrash.c */ /* </SYNC-LIST>: showcrashreports.c, oncrashthunks.S, oncrash.c */
if (!IsWindows()) { if (!IsWindows()) {
bzero(&ss, sizeof(ss)); bzero(&ss, sizeof(ss));

View file

@ -1,7 +1,7 @@
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│ /*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney Copyright 2022 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the any purpose with or without fee is hereby granted, provided that the
@ -18,12 +18,18 @@
*/ */
#include "libc/macros.internal.h" #include "libc/macros.internal.h"
// Divides 64-bit signed integer by 10,000. // Normally we call ShowCrashReports() from main, but if
// there's a crash in a constructor, this will help with
// troubleshooting it. You need to add:
// //
// @param rdi is number to divide // STATIC_YOINK("ShowCrashReportsEarly");
// @return truncated quotient //
div10000int64: // To the top of your main module to use this.
mov $11,%cl
movabs $0x346dc5d63886594b,%rdx .init.start 400,ShowCrashReportsEarly
jmp tinydivsi push %rdi
.endfn div10000int64,globl push %rsi
call ShowCrashReports
pop %rsi
pop %rdi
.init.end 400,ShowCrashReportsEarly

View file

@ -111,9 +111,9 @@ void(vflogf)(unsigned level, const char *file, int line, FILE *f,
if (bufmode == _IOLBF) f->bufmode = _IOFBF; if (bufmode == _IOLBF) f->bufmode = _IOFBF;
if ((fprintf_unlocked)(f, "%r%c%s%06ld:%s:%d:%.*s:%d] ", if ((fprintf_unlocked)(f, "%r%c%s%06ld:%s:%d:%.*s:%d] ",
"FEWIVDNT"[level & 7], buf32, "FEWIVDNT"[level & 7], buf32, dots / 1000 % 1000000,
rem1000000int64(div1000int64(dots)), file, line, file, line, strchrnul(prog, '.') - prog, prog,
strchrnul(prog, '.') - prog, prog, getpid()) <= 0) { getpid()) <= 0) {
vflogf_onfail(f); vflogf_onfail(f);
} }
(vfprintf_unlocked)(f, fmt, va); (vfprintf_unlocked)(f, fmt, va);

View file

@ -3,20 +3,6 @@
#if !(__ASSEMBLER__ + __LINKER__ + 0) #if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_ COSMOPOLITAN_C_START_
/*
* BIT SCANNING 101
* ctz(𝑥) 31^clz(𝑥) clz(𝑥)
* uint32 𝑥 bsf(𝑥) tzcnt(𝑥) ffs(𝑥) bsr(𝑥) lzcnt(𝑥)
* 0x00000000 wut 32 0 wut 32
* 0x00000001 0 0 1 0 31
* 0x80000001 0 0 1 31 0
* 0x80000000 31 31 32 31 0
* 0x00000010 4 4 5 4 27
* 0x08000010 4 4 5 27 4
* 0x08000000 27 27 28 27 4
* 0xffffffff 0 0 1 31 0
*/
int bsf(int) pureconst; int bsf(int) pureconst;
int bsfl(long) pureconst; int bsfl(long) pureconst;
int bsfll(long long) pureconst; int bsfll(long long) pureconst;

View file

@ -3,20 +3,6 @@
#if !(__ASSEMBLER__ + __LINKER__ + 0) #if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_ COSMOPOLITAN_C_START_
/*
* BIT SCANNING 101
* ctz(𝑥) 31^clz(𝑥) clz(𝑥)
* uint32 𝑥 bsf(𝑥) tzcnt(𝑥) ffs(𝑥) bsr(𝑥) lzcnt(𝑥)
* 0x00000000 wut 32 0 wut 32
* 0x00000001 0 0 1 0 31
* 0x80000001 0 0 1 31 0
* 0x80000000 31 31 32 31 0
* 0x00000010 4 4 5 4 27
* 0x08000010 4 4 5 27 4
* 0x08000000 27 27 28 27 4
* 0xffffffff 0 0 1 31 0
*/
int bsr(int) pureconst; int bsr(int) pureconst;
int bsrl(long) pureconst; int bsrl(long) pureconst;
int bsrll(long long) pureconst; int bsrll(long long) pureconst;

View file

@ -1,12 +1,13 @@
#ifndef COSMOPOLITAN_LIBC_NEXGEN32E_CACHESIZE_H_ #ifndef COSMOPOLITAN_LIBC_NEXGEN32E_CACHESIZE_H_
#define COSMOPOLITAN_LIBC_NEXGEN32E_CACHESIZE_H_ #define COSMOPOLITAN_LIBC_NEXGEN32E_CACHESIZE_H_
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
#define kCpuCacheTypeData 1 #define kCpuCacheTypeData 1
#define kCpuCacheTypeInstruction 2 #define kCpuCacheTypeInstruction 2
#define kCpuCacheTypeUnified 3 #define kCpuCacheTypeUnified 3
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
unsigned getcachesize(int, int); unsigned getcachesize(int, int);
COSMOPOLITAN_C_END_ COSMOPOLITAN_C_END_

View file

@ -1,34 +0,0 @@
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/macros.internal.h"
// Divides 64-bit signed integer by 100.
//
// @param rdi is number to divide
// @return rax has quotient
div100int64:
mov %rdi,%rax
movabs $-6640827866535438581,%rdx
imul %rdx
lea (%rdx,%rdi),%rax
sar $63,%rdi
sar $6,%rax
sub %rdi,%rax
ret
.endfn div100int64,globl

View file

@ -1 +0,0 @@
These files aren't intended to be compiled.

View file

@ -53,7 +53,19 @@ kCpuids:.long 0,0,0,0 # EAX=0 (Basic Processor Info)
mov %rdi,%r8 mov %rdi,%r8
xor %eax,%eax xor %eax,%eax
1: xor %ecx,%ecx 1: xor %ecx,%ecx
#ifdef FEATURELESS
// It's been reported that GDB reverse debugging doesn't
// understand VEX encoding. The workaround is to put:
//
// CPPFLAGS = -DFEATURELESS
//
// Inside your ~/.cosmo.mk file.
xor %eax,%eax
xor %ebx,%ebx
xor %edx,%edx
#else
cpuid cpuid
#endif
stosl stosl
xchg %eax,%ebx xchg %eax,%ebx
stosl stosl

View file

@ -1,48 +0,0 @@
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/macros.internal.h"
// Creates bit mask of which bytes are the same.
//
// @param %rdi points to bit mask (write-only)
// @param %rsi points to first buffer (read-only)
// @param %rdx points to second buffer (read-only)
// @param %rcx is byte length of both %rsi and %rdx
// @return %rax is set to %rdi
// @note buffers should be 128-byte aligned
memeqmask:
.leafprologue
xor %eax,%eax
test %ecx,%ecx
jz 1f
shr $3,%ecx
0: movdqa (%rsi,%rax,8),%xmm0
movdqa 16(%rsi,%rax,8),%xmm1
pcmpeqb (%rdx,%rax,8),%xmm0
pcmpeqb 16(%rdx,%rax,8),%xmm1
pmovmskb %xmm0,%r8d
pmovmskb %xmm1,%r9d
mov %r8w,(%rdi,%rax)
mov %r9w,2(%rdi,%rax)
add $4,%eax
cmp %ecx,%eax
jb 0b
1: mov %rdi,%rax
.leafepilogue
.endfn memeqmask,globl

View file

@ -1,62 +0,0 @@
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/nexgen32e/x86feature.h"
#include "libc/dce.h"
#include "libc/macros.internal.h"
// Searches for last instance of uint16_t in memory region.
//
// @param rdi points to data to search
// @param esi is treated as uint16_t
// @param rdx is short count in rdi
// @return rax is address of last %si in %rdi, or NULL
// @note AVX2 requires Haswell (2014+) or Excavator (2015+)
memrchr16:
.leafprologue
.profilable
#if !IsTiny()
cmp $16,%rdx
jb 5f
testb X86_HAVE(AVX2)+kCpuids(%rip)
jz 5f
vmovd %esi,%xmm0
vpbroadcastw %xmm0,%ymm0
3: vmovdqu -32(%rdi,%rdx,2),%ymm1
vpcmpeqw %ymm1,%ymm0,%ymm1
vpmovmskb %ymm1,%eax
lzcnt %eax,%eax
shr %eax
mov %eax,%ecx
sub %rcx,%rdx
cmp $16,%eax
jne 5f
cmp $15,%rdx
ja 3b
vzeroupper
#endif
5: xor %eax,%eax
mov %rdx,%rcx
6: sub $1,%rcx
jb 9f
cmp %si,-2(%rdi,%rdx,2)
mov %rcx,%rdx
jne 6b
lea (%rdi,%rcx,2),%rax
9: .leafepilogue
.endfn memrchr16,globl

View file

@ -1,62 +0,0 @@
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/nexgen32e/x86feature.h"
#include "libc/dce.h"
#include "libc/macros.internal.h"
// Searches for last instance of wchar_t in memory region.
//
// @param rdi points to data to search
// @param esi is treated as int32_t (officially wchar_t)
// @param rdx is short count in rdi
// @return rax is address of last %esi in %rdi, or NULL
// @note AVX2 requires Haswell (2014+) or Excavator (2015+)
wmemrchr:
.leafprologue
.profilable
#if !IsTiny()
cmp $8,%rdx
jb 5f
testb X86_HAVE(AVX2)+kCpuids(%rip)
jz 5f
vmovd %esi,%xmm0
vpbroadcastd %xmm0,%ymm0
3: vmovdqu -32(%rdi,%rdx,4),%ymm1
vpcmpeqd %ymm1,%ymm0,%ymm1
vpmovmskb %ymm1,%eax
lzcnt %eax,%eax
shr $2,%eax
mov %eax,%ecx
sub %rcx,%rdx
cmp $8,%eax
jne 5f
cmp $7,%rdx
ja 3b
vzeroupper
#endif
5: xor %eax,%eax
mov %rdx,%rcx
6: sub $1,%rcx
jb 9f
cmp %esi,-4(%rdi,%rdx,4)
mov %rcx,%rdx
jne 6b
lea (%rdi,%rcx,4),%rax
9: .leafepilogue
.endfn wmemrchr,globl

View file

@ -10,23 +10,6 @@ void imapxlatab(void *);
void insertionsort(int32_t *, size_t); void insertionsort(int32_t *, size_t);
void CheckStackIsAligned(void); void CheckStackIsAligned(void);
int64_t div10int64(int64_t) libcesque pureconst;
int64_t div100int64(int64_t) libcesque pureconst;
int64_t div1000int64(int64_t) libcesque pureconst;
int64_t div10000int64(int64_t) libcesque pureconst;
int64_t div1000000int64(int64_t) libcesque pureconst;
int64_t div1000000000int64(int64_t) libcesque pureconst;
int64_t rem10int64(int64_t) libcesque pureconst;
int64_t rem100int64(int64_t) libcesque pureconst;
int64_t rem1000int64(int64_t) libcesque pureconst;
int64_t rem10000int64(int64_t) libcesque pureconst;
int64_t rem1000000int64(int64_t) libcesque pureconst;
int64_t rem1000000000int64(int64_t) libcesque pureconst;
char sbb(uint64_t *, const uint64_t *, const uint64_t *, size_t);
char adc(uint64_t *, const uint64_t *, const uint64_t *, size_t);
COSMOPOLITAN_C_END_ COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_NEXGEN32E_NEXGEN32E_H_ */ #endif /* COSMOPOLITAN_LIBC_NEXGEN32E_NEXGEN32E_H_ */

View file

@ -1,38 +0,0 @@
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/macros.internal.h"
// Returns 𝑥 % 1,000,000,000.
//
// @param rdi int64 𝑥
// @return rax has remainder
rem1000000000int64:
movabs $0x112e0be826d694b3,%rdx
mov %rdi,%rax
imul %rdx
mov %rdx,%rax
sar $0x1a,%rax
mov %rdi,%rdx
sar $0x3f,%rdx
sub %rdx,%rax
imul $0x3b9aca00,%rax,%rax
sub %rax,%rdi
mov %rdi,%rax
ret
.endfn rem1000000000int64,globl

View file

@ -1,38 +0,0 @@
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/macros.internal.h"
// Returns 𝑥 % 1,000,000.
//
// @param rdi int64 𝑥
// @return rax has remainder
rem1000000int64:
movabs $0x431bde82d7b634db,%rdx
mov %rdi,%rax
imul %rdx
mov %rdx,%rax
sar $0x12,%rax
mov %rdi,%rdx
sar $0x3f,%rdx
sub %rdx,%rax
imul $0xf4240,%rax,%rax
sub %rax,%rdi
mov %rdi,%rax
ret
.endfn rem1000000int64,globl

View file

@ -1,38 +0,0 @@
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/macros.internal.h"
// Returns 𝑥 % 10,000.
//
// @param rdi int64 𝑥
// @return rax has remainder
rem10000int64:
mov %rdi,%rax
movabsq $0x346dc5d63886594b,%rdx
imulq %rdx
mov %rdx,%rax
mov %rdi,%rdx
sar $11,%rax
sar $63,%rdx
sub %rdx,%rax
imulq $10000,%rax,%rax
sub %rax,%rdi
mov %rdi,%rax
ret
.endfn rem10000int64,globl

View file

@ -1,38 +0,0 @@
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/macros.internal.h"
// Returns 𝑥 % 1,000.
//
// @param rdi int64 𝑥
// @return rax has remainder
rem1000int64:
movabs $0x20c49ba5e353f7cf,%rdx
mov %rdi,%rax
imul %rdx
mov %rdx,%rax
sar $0x7,%rax
mov %rdi,%rdx
sar $0x3f,%rdx
sub %rdx,%rax
imul $0x3e8,%rax,%rax
sub %rax,%rdi
mov %rdi,%rax
ret
.endfn rem1000int64,globl

View file

@ -1,38 +0,0 @@
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/macros.internal.h"
// Returns 𝑥 % 100.
//
// @param rdi int64 𝑥
// @return rax has remainder
rem100int64:
mov %rdi,%rax
movabsq $-6640827866535438581,%rdx
imul %rdx
lea (%rdx,%rdi),%rax
mov %rdi,%rdx
sar $6,%rax
sar $63,%rdx
sub %rdx,%rax
imul $100,%rax,%rax
sub %rax,%rdi
mov %rdi,%rax
ret
.endfn rem100int64,globl

View file

@ -1,39 +0,0 @@
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/macros.internal.h"
// Returns 𝑥 % 10.
//
// @param rdi int64 𝑥
// @return rax has remainder
rem10int64:
movabs $0x6666666666666667,%rdx
mov %rdi,%rax
imul %rdx
mov %rdx,%rax
sar $0x2,%rax
mov %rdi,%rdx
sar $0x3f,%rdx
sub %rdx,%rax
lea (%rax,%rax,4),%rax
add %rax,%rax
sub %rax,%rdi
mov %rdi,%rax
ret
.endfn rem10int64,globl

View file

@ -1,83 +0,0 @@
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/macros.internal.h"
#include "libc/notice.inc"
// Applies no-clobber guarantee to System Five function call.
//
// - Reentrant
// - Realigns stack
// - Doesn't assume red zone
// - Clobbers nothing (except %rax and flags)
//
// This function may be called using an stdcall convention. It's
// useful for files named FOO.hookabi.c and BAR.ncabi.c to make
// calls into other parts of the system, that don't conform to the
// same restricted ABI.
//
// @param six args and fn addr pushed on stack in reverse order
// @return %rax has function return value, and stack is cleaned up
// @see libc/shadowargs.hook.c for intended use case
slowcall:
#param %r9 # 0x40 arg6
#param %r8 # 0x38 arg5
#param %rcx # 0x30 arg4
#param %rdx # 0x28 arg3
#param %rsi # 0x20 arg2
#param %rdi # 0x18 arg1
#param %rax # 0x10 call address
#param # 0x08 return address
push %rbp # 0x00 parent frame
mov %rsp,%rbp # ----
push %rdi #-0x08
push %rsi #-0x10
push %rdx #-0x18
push %rcx #-0x20
push %r8 #-0x28
push %r9 #-0x30
push %r10 #-0x38
push %r11 #-0x40
mov 0x10(%rbp),%rax
mov 0x18(%rbp),%rdi
mov 0x20(%rbp),%rsi
mov 0x28(%rbp),%rdx
mov 0x30(%rbp),%rcx
mov 0x38(%rbp),%r8
mov 0x40(%rbp),%r9
and $-16,%rsp
call *%rax
push %rax
mov 0x00(%rbp),%rax
mov %rax,0x38(%rbp)
mov 0x08(%rbp),%rax
mov %rax,0x40(%rbp)
pop %rax
lea -0x40(%rbp),%rsp
pop %r11
pop %r10
pop %r9
pop %r8
pop %rcx
pop %rdx
pop %rsi
pop %rdi
lea 0x38(%rbp),%rsp
pop %rbp
ret
.endfn slowcall,globl

View file

@ -1,24 +0,0 @@
#ifndef COSMOPOLITAN_LIBC_NEXGEN32E_SLOWCALL_H_
#define COSMOPOLITAN_LIBC_NEXGEN32E_SLOWCALL_H_
#if !(__ASSEMBLER__ + __LINKER__ + 0)
#define slowcall(fn, arg1, arg2, arg3, arg4, arg5, arg6) \
({ \
void *ax; \
asm volatile("push\t%7\n\t" \
"push\t%6\n\t" \
"push\t%5\n\t" \
"push\t%4\n\t" \
"push\t%3\n\t" \
"push\t%2\n\t" \
"push\t%1\n\t" \
"call\tslowcall" \
: "=a"(ax) \
: "g"(fn), "g"(arg1), "g"(arg2), "g"(arg3), "g"(arg4), \
"g"(arg5), "g"(arg6) \
: "memory"); \
ax; \
})
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_NEXGEN32E_SLOWCALL_H_ */

View file

@ -1,406 +0,0 @@
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
vi: set et ft=asm ts=8 sw=8 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/nexgen32e/x86feature.h"
#include "libc/nexgen32e/macros.h"
#include "libc/macros.internal.h"
// Returns length of NUL-terminated string w/ security blankets.
//
// This is like strnlen() except it'll return 0 if (1) RDI is NULL
// or (2) a NUL-terminator wasn't found in the first RSI bytes.
//
// @param rdi is a nullable NUL-terminated string pointer
// @param rsi is the maximum number of bytes to consider
// @return rax is the number of bytes, excluding the NUL
strnlen_s:
.leafprologue
.profilable
xor %eax,%eax
xor %r10d,%r10d
test %rdi,%rdi
jnz 0f
.leafepilogue
0: xor %edx,%edx
mov %rdi,%r8
// 𝑠𝑙𝑖𝑑𝑒
.endfn strnlen_s,globl
// Swiss army knife of string character scanning.
// Used to be fourteen fast functions in one.
//
// @param rdi is non-null string memory
// @param rsi is max number of bytes to consider
// @param dl is search character #1
// @param dh is search character #2
// @param r8 is subtracted from result (for length vs. pointer)
// @param r9 masks result if DH is found (for NUL vs. NULL)
// @param r10 masks result on bytes exhausted (for length v. NULL)
// @return rax end pointer after r8/r9/r10 modifications
strsak: lea -1(%rdi),%rax
1: add $1,%rax
sub $1,%rsi
jb .Lend
test $31,%al
jz .Lfast
.Lbyte: mov (%rax),%cl
cmp %cl,%dl
je .Ldone
cmp %cl,%dh
je .Lnul
jmp 1b
.Ldone: sub %r8,%rax
jmp .Lret
.Lend: mov %r10,%r9
.Lnul: sub %r8,%rax
and %r9,%rax
.Lret: .leafepilogue
.Lslow: add $32,%rsi
jmp .Lbyte
.Lfast: movzbl %dl,%ecx
movd %ecx,%xmm0
movzbl %dh,%ecx
movd %ecx,%xmm1
sub $32,%rax
#if !X86_NEED(AVX2)
testb X86_HAVE(AVX2)+kCpuids(%rip)
jz .Lsse2
#endif
vpbroadcastb %xmm0,%ymm0
vpbroadcastb %xmm1,%ymm1
1: add $32,%rax
sub $32,%rsi
9: jb .Lslow
vmovdqa (%rax),%ymm2
vpcmpeqb %ymm0,%ymm2,%ymm3
vpcmpeqb %ymm1,%ymm2,%ymm2
vpor %ymm3,%ymm2,%ymm2
vpmovmskb %ymm2,%ecx
bsf %ecx,%ecx
je 1b
vzeroupper
2: add %rcx,%rax
jmp .Lbyte
#if !X86_NEED(AVX2)
.Lsse2: pbroadcastb %xmm0
pbroadcastb %xmm1
1: add $32,%rax
sub $32,%rsi
jb 9b
movdqa (%rax),%xmm2
movdqa 16(%rax),%xmm3
movdqa %xmm3,%xmm4
pcmpeqb %xmm0,%xmm3
pcmpeqb %xmm1,%xmm4
por %xmm4,%xmm3
pmovmskb %xmm3,%ecx
shl $16,%ecx
movdqa %xmm2,%xmm4
pcmpeqb %xmm0,%xmm2
pcmpeqb %xmm1,%xmm4
por %xmm4,%xmm2
pmovmskb %xmm2,%r11d
or %r11d,%ecx
bsf %ecx,%ecx
je 1b
jmp 2b
#endif
.endfn strsak,globl,hidden
/* benchmarked on intel core i7-6700 @ 3.40GHz (skylake)
includes function call overhead (unless marked otherwise)
your strlen, &c (strsak+avx2) for #c per n where c 0.293ns
N x1 x8 x64 mBps
------------------------------------------------------------
1 47.000 36.375 35.141 99
1 35.000 34.625 36.234 96
2 31.500 18.812 18.992 184
3 19.667 13.042 13.182 265
4 30.750 10.281 10.285 339
7 15.857 8.946 7.551 462
8 12.125 9.203 7.119 490
15 10.467 5.475 4.601 758
16 6.812 5.523 4.798 727
31 5.387 4.327 3.517 992
32 4.719 1.645 1.532 2278
63 5.000 2.403 2.034 1715
64 2.047 0.779 0.788 4427
127 2.134 1.194 1.027 3399
128 1.742 0.444 0.419 8327
255 0.945 0.594 0.554 6295
256 0.574 0.271 0.264 13226
511 0.785 0.362 0.307 11384
512 0.326 0.178 0.151 23134
1023 0.288 0.242 0.185 18862
1024 0.208 0.114 0.107 32565
2047 0.235 0.127 0.123 28430
2048 0.127 0.090 0.084 41413
4095 0.119 0.106 0.099 35116
4096 0.100 0.081 0.079 44372
8191 0.092 0.082 0.081 43176
8192 0.081 0.072 0.071 49419
16383 0.076 0.072 0.071 48847
16384 0.071 0.068 0.067 52381
32767 0.072 0.069 0.068 51154
32768 0.068 0.066 0.065 53409
your tinystrlen()
N x1 x8 x64 mBps
------------------------------------------------------------
1 53.000 33.625 33.672 97
1 33.000 32.125 32.234 101
2 24.500 19.438 17.711 184
3 23.667 12.875 11.911 273
4 13.750 9.281 9.238 352
7 11.000 6.125 5.801 560
8 7.625 5.609 5.232 621
15 11.800 3.825 3.364 966
16 4.562 3.648 3.173 1024 « optimal
31 3.710 2.851 2.298 1414
32 3.031 2.254 2.159 1506 « dropoff
63 2.683 1.827 1.691 1922
64 2.078 1.932 1.689 1924
127 1.630 1.647 1.622 2004
128 1.727 1.671 1.652 1968
255 1.392 1.450 1.435 2265
256 1.473 1.427 1.437 2262
511 1.325 1.353 1.337 2431
512 1.408 1.343 1.337 2431
1023 1.289 1.281 1.287 2525
1024 1.269 1.295 1.297 2506
2047 1.269 1.274 1.269 2561
2048 1.280 1.263 1.281 2538
4095 1.262 1.270 1.266 2568
4096 1.270 1.264 1.265 2570
8191 1.253 1.254 1.254 2592
8192 1.219 1.224 1.225 2653
16383 1.225 1.222 1.220 2663
16384 1.226 1.221 1.222 2659
32767 1.227 1.224 1.223 2658
32768 1.220 1.221 1.222 2659
glibc strlen for #c per n where c 0.273ns
N x1 x8 x64 mBps
------------------------------------------------------------
1 3497.000 53.125 42.641 82
1 69.000 44.875 42.547 82
2 45.500 24.188 21.852 160
3 23.000 15.625 14.557 240
4 22.250 11.406 10.637 328
7 10.143 6.768 6.230 560
8 11.125 5.797 5.486 636
15 5.800 3.142 2.859 1220
16 7.062 3.070 2.737 1275
31 2.806 1.585 1.407 2481
32 3.156 1.574 1.349 2587
63 2.016 0.895 0.691 5049
64 1.328 0.744 0.670 5207
127 1.441 0.521 0.407 8577
128 0.648 0.454 0.405 8619
255 0.553 0.286 0.214 16277
256 0.387 0.235 0.218 15984
511 0.456 0.151 0.129 27077
512 0.182 0.134 0.129 27117
1023 0.171 0.106 0.082 42795
1024 0.112 0.088 0.082 42741
2047 0.099 0.069 0.059 59537
2048 0.072 0.060 0.058 59925
4095 0.065 0.053 0.047 74122
4096 0.061 0.048 0.047 74478
8191 0.048 0.045 0.044 79117
8192 0.051 0.045 0.044 79181
16383 0.042 0.040 0.061 57018
16384 0.069 0.063 0.061 57245
32767 0.081 0.073 0.068 51426
32768 0.084 0.072 0.068 51285
GCC strlen (-Os REPNZ SCASB) for #c per n where c 0.293ns
N x1 x8 x64 mBps
------------------------------------------------------------
1 103.000 84.125 88.766 37
1 81.000 85.125 87.328 37
2 43.500 44.562 45.508 71
3 33.000 30.208 30.995 105
4 24.750 23.156 23.113 141
7 17.000 13.054 15.355 212
8 13.375 14.047 13.982 232
15 9.533 9.258 55.111 59
16 6.312 6.352 6.364 511
31 4.032 4.141 4.141 785
32 3.969 4.059 4.048 803
63 2.937 2.970 2.995 1086
64 2.922 2.939 2.956 1100
127 2.386 2.408 2.403 1353
128 2.383 2.403 2.401 1354
255 2.129 2.118 2.124 1530
256 2.137 2.133 2.130 1526
511 1.982 1.986 3.351 970
512 1.982 1.990 1.986 1637
1023 1.915 1.916 2.587 1257
1024 1.868 1.867 1.866 1742
2047 1.835 1.833 1.832 1775
2048 1.830 1.831 1.832 1775
4095 1.814 1.814 1.815 1791
4096 1.810 1.815 1.815 1791
8191 1.805 1.807 1.806 1800
8192 1.805 1.806 1.806 1800
16383 1.803 1.756 1.756 1851
16384 1.758 1.756 1.756 1851
32767 1.756 1.754 1.754 1853
32768 1.756 1.754 1.754 1853
Intel Optimz. Manual (SSE4.2) for #c per n where c 0.273ns
N x1 x8 x64 mBps
------------------------------------------------------------
1 37.000 43.125 34.078 102
1 33.000 33.875 34.016 103
2 39.500 17.188 17.555 199
3 18.333 12.208 12.036 290
4 30.250 9.344 9.137 382
7 14.429 5.732 5.766 605
8 7.875 6.797 5.354 652
15 10.733 5.825 3.516 993
16 3.812 2.383 2.325 1501
31 4.097 2.609 2.079 1678
32 3.031 1.395 1.349 2587
63 2.937 1.558 1.079 3235
64 2.016 0.893 0.690 5056
127 1.929 0.721 0.607 5745
128 0.617 0.483 0.428 8147
255 1.275 0.404 0.411 8486
256 0.480 0.319 0.299 11681
511 0.479 0.307 0.288 12127
512 0.322 0.244 0.232 15013
1023 0.324 0.224 0.225 15512
1024 0.245 0.240 0.223 15651
2047 0.222 0.213 0.206 16938
2048 0.204 0.194 0.192 18140
4095 0.204 0.188 0.185 18888
4096 0.183 0.179 0.179 19446
8191 0.179 0.176 0.174 20000
8192 0.174 0.172 0.171 20383
16383 0.171 0.170 0.169 20604
16384 0.169 0.169 0.168 20808
32767 0.213 0.225 0.267 13064
32768 0.231 0.215 0.220 15852
musl libc strlen for #c per n where c 0.273ns
N x1 x8 x64 mBps
------------------------------------------------------------
1 65.000 36.125 37.984 92
1 39.000 37.625 37.422 93
2 41.500 21.938 20.695 169
3 22.333 17.625 15.859 220
4 21.250 13.656 12.105 288
7 22.143 9.018 7.609 459
8 31.125 7.234 7.346 475
15 11.267 5.025 4.709 741
16 9.438 4.039 3.849 907
31 4.871 3.133 2.488 1402
32 5.219 2.246 2.039 1712
63 4.302 1.462 1.407 2479
64 2.109 1.428 1.155 3023
127 1.551 1.078 0.879 3971
128 1.742 0.903 0.760 4591
255 0.922 0.558 0.605 5764
256 0.934 0.575 0.537 6495
511 0.550 0.493 0.455 7674
512 0.646 0.490 0.426 8183
1023 0.550 0.439 0.425 8203
1024 0.472 0.421 0.408 8549
2047 0.507 0.334 0.373 9360
2048 0.403 0.426 0.409 8540
4095 0.391 0.240 0.236 14799
4096 0.238 0.222 0.221 15766
8191 0.225 0.223 0.221 15779
8192 0.225 0.214 0.215 16250
16383 0.212 0.212 0.210 16595
16384 0.209 0.210 0.211 16535
32767 0.214 0.208 0.205 17001
32768 0.207 0.207 0.291 12002
newlib strlen for #c per n where c 0.273ns
N x1 x8 x64 mBps
------------------------------------------------------------
1 33.000 34.625 34.141 102
1 33.000 34.125 33.984 103
2 58.500 18.562 17.508 199
3 16.333 12.792 12.016 290
4 19.250 9.219 9.215 379
7 17.571 6.089 5.685 614
8 16.625 5.078 5.432 642
15 8.467 4.042 3.207 1088
16 3.938 2.773 2.733 1277
31 3.645 1.673 1.598 2183
32 3.281 1.527 1.493 2338
63 2.619 1.042 0.895 3901
64 1.422 0.928 0.813 4294
127 0.984 0.718 0.561 6222
128 1.195 0.591 0.532 6558
255 0.600 0.404 0.397 8785
256 0.621 0.429 0.376 9280
511 0.346 0.311 0.306 11421
512 0.420 0.308 0.296 11776
1023 0.284 0.285 0.285 12237
1024 0.321 0.282 0.280 12456
2047 0.253 0.252 0.252 13864
2048 0.260 0.249 0.249 14012
4095 0.236 0.236 0.236 14811
4096 0.239 0.235 0.234 14906
8191 0.233 0.228 0.227 15371
8192 0.230 0.227 0.227 15397
16383 0.223 0.224 0.223 15638
16384 0.223 0.224 0.223 15663
32767 0.224 0.387 0.225 15527
32768 0.223 0.222 0.222 15724
Agner Fog's strlen (SSE2) for #c per n where c 0.273ns
N x1 x8 x64 mBps
------------------------------------------------------------
1 59.000 38.375 38.453 91
1 37.000 38.625 38.234 91
2 18.500 19.062 19.273 181
3 13.000 12.792 12.859 271
4 9.250 9.594 9.660 361
7 5.286 5.554 5.502 634
8 4.625 4.703 4.791 728
15 2.600 2.858 2.622 1331
16 2.438 2.414 2.421 1442
31 2.161 1.399 1.290 2706
32 1.219 1.262 1.250 2793
63 1.508 0.875 0.693 5038
64 0.641 0.654 0.655 5328
127 1.205 0.406 0.379 9200
128 0.367 0.372 0.369 9463
255 0.467 0.310 0.235 14835
256 0.230 0.232 0.232 15034
511 0.272 0.181 0.159 21918
512 0.174 0.161 0.158 22148
1023 0.175 0.134 0.120 29043
1024 0.140 0.122 0.120 29005
2047 0.128 0.114 0.112 31205
2048 0.130 0.113 0.112 31242
4095 0.105 0.098 0.097 35984
4096 0.105 0.098 0.097 35973
8191 0.093 0.090 0.090 38953
8192 0.094 0.090 0.090 38986
16383 0.088 0.086 0.086 40648
16384 0.088 0.086 0.086 40652
32767 0.088 0.086 0.085 40956
32768 0.087 0.085 0.085 41114 */

View file

@ -1,41 +0,0 @@
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/macros.internal.h"
#include "libc/nexgen32e/pcmpstr.inc"
#include "libc/nexgen32e/strstr.inc"
// TODO(jart): Fix me.
strstr_sse42:
.leafprologue
mov %rdi,%rax
xor %ecx,%ecx
0: mov $-16,%rdx
1: add $16,%rdx
movaps (%rsi,%rdx),%xmm0
2: add %rcx,%rax
lea (%rax,%rdx),%rdi
pcmpistri $.Lequalordered,(%rdi),%xmm0
3: ja 2b # !CF (no match) && !ZF (need NUL-term)
jnc 4f # !CF (no match) && ZF (NUL-terminator)
jno 0b # !OF CF && CX!=0 (matched at offset)
jns 1b # !SF NUL XMM1 (need to match more)
jmp 5f # youtu.be/nVk1DjMtLWs
4: xor %eax,%eax
5: .leafepilogue
.endfn strstr_sse42,globl,hidden

View file

@ -1,68 +0,0 @@
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-
│vi: set et ft=asm ts=8 sw=8 fenc=utf-8 :vi│
╞══════════════════════════════════════════════════════════════════════════════╡
Copyright 2020 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
╚─────────────────────────────────────────────────────────────────────────────*/
/* clang-format off */
// Searches for substring.
//
// @param rdi is NUL-terminated haystack string
// @param rsi is NUL-terminated needle string (16-byte aligned)
// @return rax is pointer to substring or NULL
// @todo 10x faster than naïve but could be 100x faster
.macro .strstr mode:req
push %rbp
mov %rsp,%rbp
.profilable
sub $32,%rsp
mov %rdi,%rax
xor %ecx,%ecx
0: mov $-16,%rdx
1: add $16,%rdx
movaps (%rsi,%rdx),%xmm0
2: add %rcx,%rax
lea (%rax,%rdx),%rdi
test $15,%edi
jnz 6f
pcmpistri $\mode,(%rdi),%xmm0
3: ja 2b # !CF (no match) && !ZF (need NUL-term)
jnc 4f # !CF (no match) && ZF (NUL-terminator)
jno 0b # !OF ← CF && CX!=0 (matched at offset)
jns 1b # !SF ← NUL ∉ XMM1 (need to match more)
jmp 5f # youtu.be/nVk1DjMtLWs
4: xor %eax,%eax
5: leave
ret
6: mov %rdi,%r9 # same w/ pointer realign
and $15,%r9d
mov %edi,%r8d
and $0xfff,%r8d
cmp $0xff0,%r8d
ja 8f
7: pcmpistri $\mode,(%rdi),%xmm0
cmova %r9d,%ecx
jmp 3b
8: pcmpeqd %xmm2,%xmm2 # handle danger memory
mov %rdi,%r8
and $-16,%r8
movaps (%r8),%xmm1
movaps %xmm1,-32(%rbp)
movaps %xmm2,-16(%rbp)
pcmpistri $\mode,-32(%rbp,%r9),%xmm2
jz 4b
jmp 7b
.endm

View file

@ -9,13 +9,14 @@ bool32 GetVersionEx(struct NtOsVersionInfo *lpVersionInformation);
#if defined(__GCC_ASM_FLAG_OUTPUTS__) && !defined(__STRICT_ANSI__) #if defined(__GCC_ASM_FLAG_OUTPUTS__) && !defined(__STRICT_ANSI__)
#define IsAtLeastWindows10() (GetNtMajorVersion() >= 10) #define IsAtLeastWindows10() (GetNtMajorVersion() >= 10)
static pureconst inline unsigned char GetNtMajorVersion(void) { #define GetNtMajorVersion() \
uintptr_t _x; ({ \
asm("mov\t%%gs:96,%q0\r\n" uintptr_t __x; \
"mov\t280(%q0),%b0" asm("mov\t%%gs:96,%q0\r\n" \
: "=q"(_x)); "mov\t280(%q0),%b0" \
return _x; : "=q"(__x)); \
} (unsigned char)__x; \
})
#endif #endif
COSMOPOLITAN_C_END_ COSMOPOLITAN_C_END_

View file

@ -19,6 +19,8 @@
#include "libc/bits/bits.h" #include "libc/bits/bits.h"
#include "libc/calls/calls.h" #include "libc/calls/calls.h"
#include "libc/calls/strace.internal.h" #include "libc/calls/strace.internal.h"
#include "libc/calls/struct/sigaction.h"
#include "libc/calls/struct/sigset.h"
#include "libc/calls/syscall-sysv.internal.h" #include "libc/calls/syscall-sysv.internal.h"
#include "libc/calls/syscall_support-nt.internal.h" #include "libc/calls/syscall_support-nt.internal.h"
#include "libc/dce.h" #include "libc/dce.h"
@ -37,6 +39,7 @@
#include "libc/sysv/consts/auxv.h" #include "libc/sysv/consts/auxv.h"
#include "libc/sysv/consts/grnd.h" #include "libc/sysv/consts/grnd.h"
#include "libc/sysv/consts/o.h" #include "libc/sysv/consts/o.h"
#include "libc/sysv/consts/sig.h"
#include "libc/sysv/errfuns.h" #include "libc/sysv/errfuns.h"
static bool have_getrandom; static bool have_getrandom;
@ -123,10 +126,20 @@ ssize_t getrandom(void *p, size_t n, unsigned f) {
static textstartup void getrandom_init(void) { static textstartup void getrandom_init(void) {
int e, rc; int e, rc;
e = errno; e = errno;
struct sigaction sa, oldsa;
if (IsBsd()) {
sa.sa_flags = 0;
sa.sa_handler = SIG_IGN;
sigemptyset(&sa.sa_mask);
sigaction(SIGSYS, &sa, &oldsa);
}
if (!(rc = sys_getrandom(0, 0, 0))) { if (!(rc = sys_getrandom(0, 0, 0))) {
have_getrandom = true; have_getrandom = true;
} }
KERNTRACE("sys_getrandom(0,0,0) → %d% m"); STRACE("sys_getrandom(0,0,0) → %d% m", rc);
if (IsBsd()) {
sigaction(SIGSYS, &oldsa, 0);
}
errno = e; errno = e;
} }

View file

@ -35,6 +35,7 @@ static dontinline uint64_t rdrand_failover(void) {
if (r == -1 && errno == EINTR) { if (r == -1 && errno == EINTR) {
r = 0; r = 0;
} else if (r == -1 && errno == EAGAIN) { } else if (r == -1 && errno == EAGAIN) {
r = 0;
f = 0; f = 0;
} else { } else {
return rand64(); return rand64();

View file

@ -1,7 +1,7 @@
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│ /*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney Copyright 2022 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the any purpose with or without fee is hereby granted, provided that the
@ -17,10 +17,12 @@
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "libc/macros.internal.h" #include "libc/macros.internal.h"
#include "libc/nexgen32e/pcmpstr.inc"
#include "libc/nexgen32e/strstr.inc"
// TODO(jart): Fix me. __utmpxname:
strstr16$sse42: .errno
.strstr .Lequalorder16 mov ENOTSUP(%rip),%edx
.endfn strstr16$sse42,globl,hidden mov %edx,(%rax)
ret
.endfn __utmpxname,globl
.alias __utmpxname,utmpname
.alias __utmpxname,utmpxname

View file

@ -18,6 +18,7 @@
*/ */
#include "libc/calls/calls.h" #include "libc/calls/calls.h"
#include "libc/calls/strace.internal.h" #include "libc/calls/strace.internal.h"
#include "libc/calls/struct/rlimit.h"
#include "libc/calls/struct/sigset.h" #include "libc/calls/struct/sigset.h"
#include "libc/calls/struct/termios.h" #include "libc/calls/struct/termios.h"
#include "libc/calls/struct/utsname.h" #include "libc/calls/struct/utsname.h"
@ -49,6 +50,7 @@
#include "libc/sysv/consts/auxv.h" #include "libc/sysv/consts/auxv.h"
#include "libc/sysv/consts/f.h" #include "libc/sysv/consts/f.h"
#include "libc/sysv/consts/poll.h" #include "libc/sysv/consts/poll.h"
#include "libc/sysv/consts/rlim.h"
#include "libc/sysv/consts/sig.h" #include "libc/sysv/consts/sig.h"
#include "libc/sysv/consts/termios.h" #include "libc/sysv/consts/termios.h"
#include "tool/decode/lib/idname.h" #include "tool/decode/lib/idname.h"
@ -140,6 +142,7 @@ textstartup void __printargs(const char *prologue) {
unsigned i, n; unsigned i, n;
int e, x, flags; int e, x, flags;
uintptr_t *auxp; uintptr_t *auxp;
struct rlimit rlim;
struct utsname uts; struct utsname uts;
struct termios termios; struct termios termios;
struct AuxiliaryValue *auxinfo; struct AuxiliaryValue *auxinfo;
@ -276,6 +279,17 @@ textstartup void __printargs(const char *prologue) {
PRINT(" error: sigprocmask() failed %m"); PRINT(" error: sigprocmask() failed %m");
} }
PRINT("");
PRINT("RESOURCE LIMITS");
for (i = 0; i < RLIM_NLIMITS; ++i) {
if (!getrlimit(i, &rlim)) {
if (rlim.rlim_cur == RLIM_INFINITY) rlim.rlim_cur = -1;
if (rlim.rlim_max == RLIM_INFINITY) rlim.rlim_max = -1;
PRINT(" ☼ %-20s %,16ld %,16ld", DescribeRlimitName(i), rlim.rlim_cur,
rlim.rlim_max);
}
}
PRINT(""); PRINT("");
PRINT("ARGUMENTS (%p)", __argv); PRINT("ARGUMENTS (%p)", __argv);
if (*__argv) { if (*__argv) {

47
libc/runtime/utmp.h Normal file
View file

@ -0,0 +1,47 @@
#ifndef COSMOPOLITAN_LIBC_RUNTIME_UTMP_H_
#define COSMOPOLITAN_LIBC_RUNTIME_UTMP_H_
#include "libc/calls/weirdtypes.h"
#include "libc/runtime/utmpx.h"
#define ACCOUNTING 9
#define UT_NAMESIZE 32
#define UT_HOSTSIZE 256
#define UT_LINESIZE 32
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
struct lastlog {
time_t ll_time;
char ll_line[UT_LINESIZE];
char ll_host[UT_HOSTSIZE];
};
#define ut_time ut_tv.tv_sec
#define ut_name ut_user
#define ut_addr ut_addr_v6[0]
#define utmp utmpx
#define e_exit __e_exit
#define e_termination __e_termination
int login_tty(int);
int utmpname(const char *);
struct utmp *getutent(void);
struct utmp *getutid(const struct utmp *);
struct utmp *getutline(const struct utmp *);
struct utmp *pututline(const struct utmp *);
void endutent(void);
void setutent(void);
void updwtmp(const char *, const struct utmp *);
#define _PATH_UTMP "/dev/null/utmp"
#define _PATH_WTMP "/dev/null/wtmp"
#define UTMP_FILE _PATH_UTMP
#define WTMP_FILE _PATH_WTMP
#define UTMP_FILENAME _PATH_UTMP
#define WTMP_FILENAME _PATH_WTMP
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_RUNTIME_UTMP_H_ */

51
libc/runtime/utmpx.h Normal file
View file

@ -0,0 +1,51 @@
#ifndef COSMOPOLITAN_LIBC_RUNTIME_UTMPX_H_
#define COSMOPOLITAN_LIBC_RUNTIME_UTMPX_H_
#include "libc/calls/struct/timeval.h"
#include "libc/calls/weirdtypes.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
struct utmpx {
short ut_type;
pid_t ut_pid;
char ut_line[32];
char ut_id[4];
char ut_user[32];
char ut_host[256];
struct {
short __e_termination;
short __e_exit;
} ut_exit;
long ut_session;
struct timeval ut_tv;
unsigned ut_addr_v6[4];
char __unused[20];
};
void endutxent(void);
struct utmpx *getutxent(void);
struct utmpx *getutxid(const struct utmpx *);
struct utmpx *getutxline(const struct utmpx *);
struct utmpx *pututxline(const struct utmpx *);
void setutxent(void);
#if defined(_BSD_SOURCE) || defined(_GNU_SOURCE)
#define e_exit __e_exit
#define e_termination __e_termination
void updwtmpx(const char *, const struct utmpx *);
int utmpxname(const char *);
#endif
#define EMPTY 0
#define RUN_LVL 1
#define BOOT_TIME 2
#define NEW_TIME 3
#define OLD_TIME 4
#define INIT_PROCESS 5
#define LOGIN_PROCESS 6
#define USER_PROCESS 7
#define DEAD_PROCESS 8
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_RUNTIME_UTMPX_H_ */

View file

@ -44,6 +44,10 @@ vfork:
testb IsWindows() testb IsWindows()
jnz sys_fork_nt # and we're lucky to have that jnz sys_fork_nt # and we're lucky to have that
#endif #endif
#if SupportsXnu()
testb IsXnu()
jnz fork
#endif
#if SupportsOpenbsd() #if SupportsOpenbsd()
testb IsOpenbsd() testb IsOpenbsd()
jnz fork # fake vfork plus msyscall issues jnz fork # fake vfork plus msyscall issues

View file

@ -21,8 +21,15 @@
int sys_accept(int server, void *addr, uint32_t *addrsize) { int sys_accept(int server, void *addr, uint32_t *addrsize) {
int client; int client;
if ((client = __sys_accept(server, addr, addrsize, 0)) != -1 && IsBsd()) { uint32_t size;
sockaddr2linux(addr); union sockaddr_storage_bsd bsd;
if (!IsBsd()) {
client = __sys_accept(server, addr, addrsize, 0);
} else {
size = sizeof(bsd);
if ((client = __sys_accept(server, &bsd, &size, 0)) != -1) {
sockaddr2linux(&bsd, size, addr, addrsize);
}
} }
return client; return client;
} }

View file

@ -21,27 +21,26 @@
#include "libc/sock/internal.h" #include "libc/sock/internal.h"
#include "libc/sock/sock.h" #include "libc/sock/sock.h"
#define __NR_accept4_linux 0x0120 /* rhel5:enosysevil */
int sys_accept4(int server, void *addr, uint32_t *addrsize, int flags) { int sys_accept4(int server, void *addr, uint32_t *addrsize, int flags) {
static bool once, demodernize; if (!flags) return sys_accept(server, addr, addrsize);
int olderr, client; int olderr, client;
if (!flags || demodernize) goto TriedAndTrue; union sockaddr_storage_bsd bsd;
uint32_t size = sizeof(bsd);
void *out_addr = !IsBsd() ? addr : &bsd;
uint32_t *out_addrsize = !IsBsd() ? addrsize : &size;
static bool demodernize;
if (demodernize) goto TriedAndTrue;
olderr = errno; olderr = errno;
client = __sys_accept4(server, addr, addrsize, flags); client = __sys_accept4(server, out_addr, out_addrsize, flags);
if (client == -1 && errno == ENOSYS) { if (client == -1 && errno == ENOSYS) {
errno = olderr; errno = olderr;
TriedAndTrue:
client = __fixupnewsockfd(__sys_accept(server, addr, addrsize, 0), flags);
} else if (SupportsLinux() && !once) {
once = true;
if (client == __NR_accept4_linux) {
demodernize = true; demodernize = true;
goto TriedAndTrue; TriedAndTrue:
} client = __fixupnewsockfd(__sys_accept(server, out_addr, out_addrsize, 0),
flags);
} }
if (client != -1 && IsBsd()) { if (client != -1 && IsBsd()) {
sockaddr2linux(addr); sockaddr2linux(&bsd, size, addr, addrsize);
} }
return client; return client;
} }

View file

@ -1,5 +1,5 @@
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney Copyright 2020 Justine Alexandra Roberts Tunney
@ -16,15 +16,16 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "libc/macros.internal.h" #include "libc/dce.h"
#include "libc/sock/internal.h"
// Divides 64-bit signed integer by 1,000,000,000. int sys_bind(int fd, const void *addr, uint32_t addrsize) {
// union sockaddr_storage_bsd bsd;
// @param rdi is number to divide if (!IsBsd()) {
// @return quotient return __sys_bind(fd, addr, addrsize);
div1000000000int64: } else if (!sockaddr2bsd(addr, addrsize, &bsd, &addrsize)) {
mov $0x1a,%cl return __sys_bind(fd, &bsd.sa, addrsize);
movabs $0x112e0be826d694b3,%rdx } else {
jmp tinydivsi return -1;
.globl tinydivsi }
.endfn div1000000000int64,globl }

View file

@ -16,7 +16,6 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "libc/assert.h"
#include "libc/calls/internal.h" #include "libc/calls/internal.h"
#include "libc/calls/strace.internal.h" #include "libc/calls/strace.internal.h"
#include "libc/dce.h" #include "libc/dce.h"
@ -25,7 +24,6 @@
#include "libc/sock/sock.h" #include "libc/sock/sock.h"
#include "libc/sock/sockdebug.h" #include "libc/sock/sockdebug.h"
#include "libc/sock/syscall_fd.internal.h" #include "libc/sock/syscall_fd.internal.h"
#include "libc/str/str.h"
#include "libc/sysv/errfuns.h" #include "libc/sysv/errfuns.h"
/** /**
@ -40,21 +38,11 @@
*/ */
int bind(int fd, const void *addr, uint32_t addrsize) { int bind(int fd, const void *addr, uint32_t addrsize) {
int rc; int rc;
char addrbuf[72];
if (!addr || (IsAsan() && !__asan_is_valid(addr, addrsize))) { if (!addr || (IsAsan() && !__asan_is_valid(addr, addrsize))) {
rc = efault(); rc = efault();
} else if (addrsize >= sizeof(struct sockaddr_in)) { } else if (addrsize >= sizeof(struct sockaddr_in)) {
if (!IsWindows()) { if (!IsWindows()) {
if (!IsBsd()) {
rc = sys_bind(fd, addr, addrsize); rc = sys_bind(fd, addr, addrsize);
} else {
char addr2[sizeof(
struct sockaddr_un_bsd)]; /* sockaddr_un_bsd is the largest */
assert(addrsize <= sizeof(addr2));
memcpy(&addr2, addr, addrsize);
sockaddr2bsd(&addr2[0]);
rc = sys_bind(fd, &addr2, addrsize);
}
} else if (__isfdkind(fd, kFdSocket)) { } else if (__isfdkind(fd, kFdSocket)) {
rc = sys_bind_nt(&g_fds.p[fd], addr, addrsize); rc = sys_bind_nt(&g_fds.p[fd], addr, addrsize);
} else { } else {

View file

@ -16,20 +16,16 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "libc/assert.h"
#include "libc/dce.h" #include "libc/dce.h"
#include "libc/sock/internal.h" #include "libc/sock/internal.h"
#include "libc/str/str.h"
#include "libc/sysv/errfuns.h"
int sys_connect(int fd, const void *addr, uint32_t addrsize) { int sys_connect(int fd, const void *addr, uint32_t addrsize) {
union sockaddr_storage_bsd bsd;
if (!IsBsd()) { if (!IsBsd()) {
return __sys_connect(fd, addr, addrsize); return __sys_connect(fd, addr, addrsize);
} else if (!sockaddr2bsd(addr, addrsize, &bsd, &addrsize)) {
return __sys_connect(fd, &bsd.sa, addrsize);
} else { } else {
char addr2[sizeof(struct sockaddr_un_bsd)]; /* sockaddr_un_bsd is the largest */ return -1;
assert(addrsize <= sizeof(addr2));
memcpy(&addr2, addr, addrsize);
sockaddr2bsd(&addr2[0]);
return __sys_connect(fd, &addr2, addrsize);
} }
} }

View file

@ -19,7 +19,9 @@
#include "libc/calls/strace.internal.h" #include "libc/calls/strace.internal.h"
#include "libc/dce.h" #include "libc/dce.h"
#include "libc/intrin/asan.internal.h" #include "libc/intrin/asan.internal.h"
#include "libc/intrin/kprintf.h"
#include "libc/sock/internal.h" #include "libc/sock/internal.h"
#include "libc/sock/sock.h"
#include "libc/sock/sockdebug.h" #include "libc/sock/sockdebug.h"
#include "libc/sock/syscall_fd.internal.h" #include "libc/sock/syscall_fd.internal.h"
#include "libc/sysv/errfuns.h" #include "libc/sysv/errfuns.h"

View file

@ -20,9 +20,16 @@
#include "libc/sock/internal.h" #include "libc/sock/internal.h"
int sys_getpeername(int fd, void *out_addr, uint32_t *out_addrsize) { int sys_getpeername(int fd, void *out_addr, uint32_t *out_addrsize) {
int rc = __sys_getpeername(fd, out_addr, out_addrsize); int rc;
if (rc != -1 && IsBsd()) { uint32_t size;
sockaddr2linux(out_addr); union sockaddr_storage_bsd bsd;
if (!IsBsd()) {
rc = __sys_getpeername(fd, out_addr, out_addrsize);
} else {
size = sizeof(bsd);
if ((rc = __sys_getpeername(fd, &bsd, &size)) != -1) {
sockaddr2linux(&bsd, size, out_addr, out_addrsize);
}
} }
return rc; return rc;
} }

View file

@ -20,9 +20,16 @@
#include "libc/sock/internal.h" #include "libc/sock/internal.h"
int sys_getsockname(int fd, void *out_addr, uint32_t *out_addrsize) { int sys_getsockname(int fd, void *out_addr, uint32_t *out_addrsize) {
int rc = __sys_getsockname(fd, out_addr, out_addrsize); int rc;
if (rc != -1 && IsBsd()) { uint32_t size;
sockaddr2linux(out_addr); union sockaddr_storage_bsd bsd;
if (!IsBsd()) {
rc = __sys_getsockname(fd, out_addr, out_addrsize);
} else {
size = sizeof(bsd);
if ((rc = __sys_getsockname(fd, &bsd, &size)) != -1) {
sockaddr2linux(&bsd, size, out_addr, out_addrsize);
}
} }
return rc; return rc;
} }

View file

@ -52,6 +52,18 @@ struct sockaddr_un_bsd {
char sun_path[108]; char sun_path[108];
}; };
union sockaddr_storage_bsd {
struct sockaddr_bsd sa;
struct sockaddr_in_bsd sin;
struct sockaddr_un_bsd sun;
};
union sockaddr_storage_linux {
struct sockaddr sa;
struct sockaddr_in sin;
struct sockaddr_un sun;
};
/* ------------------------------------------------------------------------------------*/ /* ------------------------------------------------------------------------------------*/
#define SOCKFD_OVERLAP_BUFSIZ 128 #define SOCKFD_OVERLAP_BUFSIZ 128
@ -79,10 +91,11 @@ void _firewall(const void *, uint32_t) hidden;
int32_t __sys_accept(int32_t, void *, uint32_t *, int) dontdiscard hidden; int32_t __sys_accept(int32_t, void *, uint32_t *, int) dontdiscard hidden;
int32_t __sys_accept4(int32_t, void *, uint32_t *, int) dontdiscard hidden; int32_t __sys_accept4(int32_t, void *, uint32_t *, int) dontdiscard hidden;
int32_t __sys_bind(int32_t, const void *, uint32_t) hidden;
int32_t __sys_connect(int32_t, const void *, uint32_t) hidden; int32_t __sys_connect(int32_t, const void *, uint32_t) hidden;
int32_t __sys_socket(int32_t, int32_t, int32_t) hidden;
int32_t __sys_getsockname(int32_t, void *, uint32_t *) hidden;
int32_t __sys_getpeername(int32_t, void *, uint32_t *) hidden; int32_t __sys_getpeername(int32_t, void *, uint32_t *) hidden;
int32_t __sys_getsockname(int32_t, void *, uint32_t *) hidden;
int32_t __sys_socket(int32_t, int32_t, int32_t) hidden;
int32_t __sys_socketpair(int32_t, int32_t, int32_t, int32_t[2]) hidden; int32_t __sys_socketpair(int32_t, int32_t, int32_t, int32_t[2]) hidden;
int32_t sys_accept4(int32_t, void *, uint32_t *, int) dontdiscard hidden; int32_t sys_accept4(int32_t, void *, uint32_t *, int) dontdiscard hidden;
@ -137,29 +150,10 @@ struct SockFd *_dupsockfd(struct SockFd *) hidden;
int64_t GetNtBaseSocket(int64_t) hidden; int64_t GetNtBaseSocket(int64_t) hidden;
int sys_close_epoll(int) hidden; int sys_close_epoll(int) hidden;
/** int sockaddr2bsd(const void *, uint32_t, union sockaddr_storage_bsd *,
* Converts sockaddr (Linux/Windows) sockaddr_bsd (XNU/BSD). uint32_t *);
*/ void sockaddr2linux(const union sockaddr_storage_bsd *, uint32_t,
forceinline void sockaddr2bsd(void *saddr) { union sockaddr_storage_linux *, uint32_t *);
char *p;
if (saddr) {
p = saddr;
p[1] = p[0];
p[0] = sizeof(struct sockaddr_in_bsd);
}
}
/**
* Converts sockaddr_in_bsd (XNU/BSD) sockaddr (Linux/Windows).
*/
forceinline void sockaddr2linux(void *saddr) {
char *p;
if (saddr) {
p = saddr;
p[0] = p[1];
p[1] = 0;
}
}
COSMOPOLITAN_C_END_ COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */

View file

@ -45,19 +45,26 @@
*/ */
ssize_t recvfrom(int fd, void *buf, size_t size, uint32_t flags, ssize_t recvfrom(int fd, void *buf, size_t size, uint32_t flags,
void *opt_out_srcaddr, uint32_t *opt_inout_srcaddrsize) { void *opt_out_srcaddr, uint32_t *opt_inout_srcaddrsize) {
ssize_t rc, got; ssize_t rc;
uint32_t sz;
union sockaddr_storage_bsd bsd;
if (IsAsan() && if (IsAsan() &&
(!__asan_is_valid(buf, size) || (!__asan_is_valid(buf, size) ||
(opt_out_srcaddr && (opt_out_srcaddr &&
!__asan_is_valid(opt_out_srcaddr, *opt_inout_srcaddrsize)))) { (!__asan_is_valid(opt_inout_srcaddrsize,
sizeof(*opt_inout_srcaddrsize)) ||
!__asan_is_valid(opt_out_srcaddr, *opt_inout_srcaddrsize))))) {
rc = efault(); rc = efault();
} else if (!IsWindows()) { } else if (!IsWindows()) {
got = sys_recvfrom(fd, buf, size, flags, opt_out_srcaddr, if (!IsBsd() || !opt_out_srcaddr) {
rc = sys_recvfrom(fd, buf, size, flags, opt_out_srcaddr,
opt_inout_srcaddrsize); opt_inout_srcaddrsize);
if (opt_out_srcaddr && IsBsd() && got != -1) { } else {
sockaddr2linux(opt_out_srcaddr); sz = sizeof(bsd);
if ((rc = sys_recvfrom(fd, buf, size, flags, &bsd, &sz)) != -1) {
sockaddr2linux(&bsd, sz, opt_out_srcaddr, opt_inout_srcaddrsize);
}
} }
rc = got;
} else if (__isfdopen(fd)) { } else if (__isfdopen(fd)) {
if (__isfdkind(fd, kFdSocket)) { if (__isfdkind(fd, kFdSocket)) {
rc = sys_recvfrom_nt(&g_fds.p[fd], (struct iovec[]){{buf, size}}, 1, rc = sys_recvfrom_nt(&g_fds.p[fd], (struct iovec[]){{buf, size}}, 1,

View file

@ -41,15 +41,24 @@
*/ */
ssize_t recvmsg(int fd, struct msghdr *msg, int flags) { ssize_t recvmsg(int fd, struct msghdr *msg, int flags) {
ssize_t rc, got; ssize_t rc, got;
struct msghdr msg2;
union sockaddr_storage_bsd bsd;
if (IsAsan() && !__asan_is_valid_msghdr(msg)) { if (IsAsan() && !__asan_is_valid_msghdr(msg)) {
rc = efault(); rc = efault();
} else if (!IsWindows()) { } else if (!IsWindows()) {
got = sys_recvmsg(fd, msg, flags); if (IsBsd() && msg->msg_name) {
// An address was provided, convert from BSD form memcpy(&msg2, msg, sizeof(msg2));
if (msg->msg_name && IsBsd() && got != -1) { if (!(rc = sockaddr2bsd(msg->msg_name, msg->msg_namelen, &bsd,
sockaddr2linux(msg->msg_name); &msg2.msg_namelen))) {
msg2.msg_name = &bsd.sa;
if ((rc = sys_recvmsg(fd, &msg2, flags)) != -1) {
sockaddr2linux(msg2.msg_name, msg2.msg_namelen, msg->msg_name,
&msg->msg_namelen);
}
}
} else {
rc = sys_recvmsg(fd, msg, flags);
} }
rc = got;
} else if (__isfdopen(fd)) { } else if (__isfdopen(fd)) {
if (!msg->msg_control) { if (!msg->msg_control) {
if (__isfdkind(fd, kFdSocket)) { if (__isfdkind(fd, kFdSocket)) {

View file

@ -44,27 +44,22 @@
*/ */
ssize_t sendmsg(int fd, const struct msghdr *msg, int flags) { ssize_t sendmsg(int fd, const struct msghdr *msg, int flags) {
int64_t rc; int64_t rc;
char addr2[128];
struct msghdr msg2; struct msghdr msg2;
union sockaddr_storage_bsd bsd;
if (IsAsan() && !__asan_is_valid_msghdr(msg)) { if (IsAsan() && !__asan_is_valid_msghdr(msg)) {
rc = efault(); rc = efault();
} else if (!IsWindows()) { } else if (!IsWindows()) {
if (IsBsd() && msg->msg_name) { if (IsBsd() && msg->msg_name) {
/* An optional address is provided, convert it to the BSD form */
if (msg->msg_namelen <= sizeof(addr2)) {
memcpy(&addr2[0], msg->msg_name, msg->msg_namelen);
sockaddr2bsd(&addr2[0]);
/* Copy all of msg (except for msg_name) into the new ephemeral local */
memcpy(&msg2, msg, sizeof(msg2)); memcpy(&msg2, msg, sizeof(msg2));
msg2.msg_name = &addr2[0]; if (!(rc = sockaddr2bsd(msg->msg_name, msg->msg_namelen, &bsd,
&msg2.msg_namelen))) {
msg2.msg_name = &bsd.sa;
rc = sys_sendmsg(fd, &msg2, flags); rc = sys_sendmsg(fd, &msg2, flags);
}
} else { } else {
rc = einval();
}
}
/* else do the syscall */
rc = sys_sendmsg(fd, msg, flags); rc = sys_sendmsg(fd, msg, flags);
}
} else if (__isfdopen(fd)) { } else if (__isfdopen(fd)) {
if (msg->msg_control) { if (msg->msg_control) {
rc = einval(); /* control msg not supported */ rc = einval(); /* control msg not supported */

View file

@ -52,7 +52,8 @@
ssize_t sendto(int fd, const void *buf, size_t size, uint32_t flags, ssize_t sendto(int fd, const void *buf, size_t size, uint32_t flags,
const void *opt_addr, uint32_t addrsize) { const void *opt_addr, uint32_t addrsize) {
ssize_t rc; ssize_t rc;
char addr2[sizeof(struct sockaddr_un_bsd)]; uint32_t bsdaddrsize;
union sockaddr_storage_bsd bsd;
if (IsAsan() && (!__asan_is_valid(buf, size) || if (IsAsan() && (!__asan_is_valid(buf, size) ||
(opt_addr && !__asan_is_valid(opt_addr, addrsize)))) { (opt_addr && !__asan_is_valid(opt_addr, addrsize)))) {
rc = efault(); rc = efault();
@ -61,12 +62,8 @@ ssize_t sendto(int fd, const void *buf, size_t size, uint32_t flags,
if (!IsWindows()) { if (!IsWindows()) {
if (!IsBsd() || !opt_addr) { if (!IsBsd() || !opt_addr) {
rc = sys_sendto(fd, buf, size, flags, opt_addr, addrsize); rc = sys_sendto(fd, buf, size, flags, opt_addr, addrsize);
} else if (addrsize > sizeof(addr2)) { } else if (!(rc = sockaddr2bsd(opt_addr, addrsize, &bsd, &bsdaddrsize))) {
rc = einval(); rc = sys_sendto(fd, buf, size, flags, &bsd, bsdaddrsize);
} else {
memcpy(&addr2, opt_addr, addrsize);
sockaddr2bsd(&addr2[0]);
rc = sys_sendto(fd, buf, size, flags, &addr2[0], addrsize);
} }
} else if (__isfdopen(fd)) { } else if (__isfdopen(fd)) {
if (__isfdkind(fd, kFdSocket)) { if (__isfdkind(fd, kFdSocket)) {

66
libc/sock/sockaddr2bsd.c Normal file
View file

@ -0,0 +1,66 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2022 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/sock/internal.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/af.h"
#include "libc/sysv/errfuns.h"
/**
* Converts sockaddr (Linux/Windows) sockaddr_bsd (XNU/BSD).
*/
int sockaddr2bsd(const void *addr, uint32_t addrsize,
union sockaddr_storage_bsd *out_addr, uint32_t *out_addrsize) {
uint32_t len, famsize;
if (addrsize >= sizeof(((struct sockaddr *)addr)->sa_family)) {
if (((struct sockaddr *)addr)->sa_family == AF_INET) {
if (addrsize >= sizeof(struct sockaddr_in)) {
out_addr->sin.sin_len = 0;
out_addr->sin.sin_family = AF_INET;
out_addr->sin.sin_port = ((struct sockaddr_in *)addr)->sin_port;
out_addr->sin.sin_addr = ((struct sockaddr_in *)addr)->sin_addr;
bzero(&out_addr->sin.sin_zero, sizeof(out_addr->sin.sin_zero));
*out_addrsize = sizeof(struct sockaddr_in_bsd);
return 0;
} else {
return einval();
}
} else if (((struct sockaddr *)addr)->sa_family == AF_UNIX) {
famsize = sizeof(((struct sockaddr_un *)addr)->sun_family);
if (addrsize >= famsize &&
(len = strnlen(((struct sockaddr_un *)addr)->sun_path,
addrsize - famsize)) <
sizeof(out_addr->sun.sun_path)) {
out_addr->sun.sun_len = 0;
out_addr->sun.sun_family = AF_UNIX;
memcpy(out_addr->sun.sun_path, ((struct sockaddr_un *)addr)->sun_path,
len);
out_addr->sun.sun_path[len] = 0;
*out_addrsize = sizeof(out_addr->sun.sun_len) +
sizeof(out_addr->sun.sun_family) + len;
return 0;
} else {
return einval();
}
} else {
return epfnosupport();
}
} else {
return einval();
}
}

View file

@ -0,0 +1,60 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2022 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/intrin/kprintf.h"
#include "libc/macros.internal.h"
#include "libc/sock/internal.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/af.h"
#include "libc/sysv/errfuns.h"
/**
* Converts sockaddr_bsd (XNU/BSD) sockaddr (Linux/Windows).
*/
void sockaddr2linux(const union sockaddr_storage_bsd *addr, uint32_t addrsize,
union sockaddr_storage_linux *out_addr,
uint32_t *inout_addrsize) {
uint32_t len, size;
if (out_addr && inout_addrsize) {
size = *inout_addrsize;
bzero(out_addr, size);
if (addrsize >= sizeof(addr->sa.sa_family)) {
if (addr->sa.sa_family == AF_INET) {
if (addrsize >= sizeof(struct sockaddr_in_bsd) &&
size >= sizeof(struct sockaddr_in)) {
out_addr->sin.sin_family = AF_INET;
out_addr->sin.sin_port = addr->sin.sin_port;
out_addr->sin.sin_addr = addr->sin.sin_addr;
*inout_addrsize = sizeof(struct sockaddr_in);
}
} else if (addr->sa.sa_family == AF_UNIX) {
if (addrsize >=
sizeof(addr->sun.sun_len) + sizeof(addr->sun.sun_family) &&
size >= sizeof(out_addr->sun.sun_family)) {
len = strnlen(((struct sockaddr_un *)addr)->sun_path,
MIN(addrsize - (sizeof(addr->sun.sun_len) +
sizeof(addr->sun.sun_family)),
size - sizeof(out_addr->sun.sun_family)));
out_addr->sun.sun_family = AF_UNIX;
if (len) memcpy(out_addr->sun.sun_path, addr->sun.sun_path, len);
*inout_addrsize = sizeof(out_addr->sun.sun_family) + len + 1;
}
}
}
}
}

View file

@ -70,9 +70,7 @@ noasan static inline const unsigned char *memchr_sse(const unsigned char *s,
void *memchr(const void *s, int c, size_t n) { void *memchr(const void *s, int c, size_t n) {
const void *r; const void *r;
if (!IsTiny() && X86_HAVE(SSE)) { if (!IsTiny() && X86_HAVE(SSE)) {
if (IsAsan()) { if (IsAsan()) __asan_verify(s, n);
__asan_verify(s, n);
}
r = memchr_sse(s, c, n); r = memchr_sse(s, c, n);
} else { } else {
r = memchr_pure(s, c, n); r = memchr_pure(s, c, n);

View file

@ -68,9 +68,7 @@ noasan static inline const unsigned char *memrchr_sse(const unsigned char *s,
void *memrchr(const void *s, int c, size_t n) { void *memrchr(const void *s, int c, size_t n) {
const void *r; const void *r;
if (!IsTiny() && X86_HAVE(SSE)) { if (!IsTiny() && X86_HAVE(SSE)) {
if (IsAsan()) { if (IsAsan()) __asan_verify(s, n);
__asan_verify(s, n);
}
r = memrchr_sse(s, c, n); r = memrchr_sse(s, c, n);
} else { } else {
r = memrchr_pure(s, c, n); r = memrchr_pure(s, c, n);

View file

@ -1,7 +1,7 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney Copyright 2021 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the any purpose with or without fee is hereby granted, provided that the
@ -16,46 +16,61 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "libc/bits/bits.h" #include "libc/dce.h"
#include "libc/str/internal.h" #include "libc/intrin/asan.internal.h"
#include "libc/nexgen32e/x86feature.h"
#include "libc/str/str.h"
#define kVectorSize 32 /* x86+avx2 is 256-bit cpu */ typedef char16_t xmm_t __attribute__((__vector_size__(16), __aligned__(2)));
typedef uint8_t uint8_v _Vector_size(kVectorSize); static inline const char16_t *memrchr16_pure(const char16_t *s, char16_t c,
typedef uint32_t vbitmask_t; size_t n) {
size_t i;
for (i = n; i--;) {
if (s[i] == c) {
return s + i;
}
}
return 0;
}
noasan static inline const char16_t *memrchr16_sse(const char16_t *s,
char16_t c, size_t n) {
size_t i;
unsigned k, m;
xmm_t v, t = {c, c, c, c, c, c, c, c};
for (i = n; i >= 8;) {
v = *(const xmm_t *)(s + (i -= 8));
m = __builtin_ia32_pmovmskb128(v == t);
if (m) {
m = __builtin_clzl(m) ^ (sizeof(long) * CHAR_BIT - 1);
return s + i + m / 2;
}
}
while (i--) {
if (s[i] == c) {
return s + i;
}
}
return 0;
}
/** /**
* Returns how many bytes the utf16 string would be as utf8. * Returns pointer to first instance of character.
*
* @param s is memory to search
* @param c is search byte which is masked with 65535
* @param n is number of char16_t elements in `s`
* @return is pointer to first instance of c or NULL if not found
* @asyncsignalsafe
*/ */
int strcmp_avx2(const char *s1, const char *s2) { void *memrchr16(const void *s, int c, size_t n) {
if (s1 == s2) return 0; const void *r;
const unsigned char *p1 = (const unsigned char *)s1; if (!IsTiny() && X86_HAVE(SSE)) {
const unsigned char *p2 = (const unsigned char *)s2; if (IsAsan()) __asan_verify(s, n * 2);
size_t i = -kVectorSize; r = memrchr16_sse(s, c, n);
vLoop:
i += kVectorSize;
bLoop:
if (!IsPointerDangerous(p1 + i) && !IsPointerDangerous(p2 + i)) {
unsigned char zf;
vbitmask_t r1;
uint8_v v1, v2;
const uint8_v kZero = {0};
asm(ZFLAG_ASM("vmovdqu\t%5,%2\n\t" /* move because gcc problematic */
"vpcmpeqb\t%4,%2,%1\n\t" /* check for equality in p1 and p2 */
"vpcmpeqb\t%6,%2,%2\n\t" /* check for nul in p1 */
"vpandn\t%7,%1,%2\n\t" /* most complicated bitwise not ever */
"vpor\t%2,%1,%1\n\t" /* check for nul in p2 */
"pmovmskb\t%1,%3\n\t" /* turn 256 bits into 32 bits */
"bsf\t%3,%3") /* find stop byte */
: ZFLAG_CONSTRAINT(zf), "=x"(v1), "=x"(v2), "=r"(r1)
: "m"(*(const uint8_v *)(p1 + i)), "m"(*(const uint8_v *)(p2 + i)),
"x"(kZero), "m"(kVectorSize));
if (zf) goto vLoop;
return p1[i + r1] - p2[i + r1];
} else { } else {
i += 1; r = memrchr16_pure(s, c, n);
int c;
if (!(c = p1[i - 1] - p2[i - 1]) && p1[i - 1] + p1[i - 1] != 0) goto bLoop;
return c;
} }
return (void *)r;
} }

View file

@ -4,14 +4,17 @@
#if !(__ASSEMBLER__ + __LINKER__ + 0) #if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_ COSMOPOLITAN_C_START_
forceinline bool SlicesEqual(const char *a, size_t n, const char *b, size_t m) { #define SlicesEqual(a, n, b, m) \
return n == m && !memcmp(a, b, n); ({ \
} size_t __n = (n); \
__n == (m) && !memcmp(a, b, __n); \
})
forceinline bool SlicesEqualCase(const void *a, size_t n, const void *b, #define SlicesEqualCase(a, n, b, m) \
size_t m) { ({ \
return n == m && !memcasecmp(a, b, n); size_t __n = (n); \
} __n == (m) && !memcasecmp(a, b, __n); \
})
int CompareSlices(const char *, size_t, const char *, size_t); int CompareSlices(const char *, size_t, const char *, size_t);
int CompareSlicesCase(const char *, size_t, const char *, size_t); int CompareSlicesCase(const char *, size_t, const char *, size_t);

View file

@ -88,7 +88,7 @@ void *memmove(void *, const void *, size_t) memcpyesque;
void *memcpy(void *restrict, const void *restrict, size_t) memcpyesque; void *memcpy(void *restrict, const void *restrict, size_t) memcpyesque;
void *mempcpy(void *restrict, const void *restrict, size_t) memcpyesque; void *mempcpy(void *restrict, const void *restrict, size_t) memcpyesque;
void *memccpy(void *restrict, const void *restrict, int, size_t) memcpyesque; void *memccpy(void *restrict, const void *restrict, int, size_t) memcpyesque;
void *memeqmask(void *, const void *, const void *, size_t) memcpyesque; void bcopy(const void *, void *, size_t) memcpyesque;
void explicit_bzero(void *, size_t); void explicit_bzero(void *, size_t);
int bcmp(const void *, const void *, size_t) strlenesque; int bcmp(const void *, const void *, size_t) strlenesque;
@ -172,7 +172,6 @@ wchar_t *wcsncat(wchar_t *, const wchar_t *, size_t) memcpyesque;
char *strncpy(char *, const char *, size_t) memcpyesque; char *strncpy(char *, const char *, size_t) memcpyesque;
char *strtok(char *, const char *) paramsnonnull((2)) libcesque; char *strtok(char *, const char *) paramsnonnull((2)) libcesque;
char *strtok_r(char *, const char *, char **) paramsnonnull((2, 3)); char *strtok_r(char *, const char *, char **) paramsnonnull((2, 3));
uint16_t *strcpyzbw(uint16_t *, const char *) memcpyesque;
wchar_t *wcstok(wchar_t *, const wchar_t *, wchar_t **) paramsnonnull((2, 3)); wchar_t *wcstok(wchar_t *, const wchar_t *, wchar_t **) paramsnonnull((2, 3));
char *wstrtrunc(uint16_t *) memcpyesque; char *wstrtrunc(uint16_t *) memcpyesque;
char *wstrntrunc(uint16_t *, size_t) memcpyesque; char *wstrntrunc(uint16_t *, size_t) memcpyesque;
@ -266,6 +265,7 @@ char *strerrno(int) nosideeffect libcesque;
char *strerdoc(int) nosideeffect libcesque; char *strerdoc(int) nosideeffect libcesque;
int strerror_r(int, char *, size_t) dontthrow nocallback; int strerror_r(int, char *, size_t) dontthrow nocallback;
int strerror_wr(int, uint32_t, char *, size_t) dontthrow nocallback; int strerror_wr(int, uint32_t, char *, size_t) dontthrow nocallback;
int __xpg_strerror_r(int, char *, size_t) dontthrow nocallback;
COSMOPOLITAN_C_END_ COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */

View file

@ -16,13 +16,11 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "libc/dce.h"
#include "libc/str/str.h" #include "libc/str/str.h"
static inline noasan uint64_t UncheckedAlignedRead64(const char *p) { static inline noasan uint64_t UncheckedAlignedRead64(const char *p) {
return (uint64_t)(255 & p[7]) << 070 | (uint64_t)(255 & p[6]) << 060 | return *(uint64_t *)p;
(uint64_t)(255 & p[5]) << 050 | (uint64_t)(255 & p[4]) << 040 |
(uint64_t)(255 & p[3]) << 030 | (uint64_t)(255 & p[2]) << 020 |
(uint64_t)(255 & p[1]) << 010 | (uint64_t)(255 & p[0]) << 000;
} }
/** /**
@ -39,7 +37,7 @@ int strcmp(const char *a, const char *b) {
uint64_t v, w, d; uint64_t v, w, d;
if (a == b) return 0; if (a == b) return 0;
if ((c = (*a & 255) - (*b & 255))) return c; if ((c = (*a & 255) - (*b & 255))) return c;
if (((uintptr_t)a & 7) == ((uintptr_t)b & 7)) { if (!IsTiny() && ((uintptr_t)a & 7) == ((uintptr_t)b & 7)) {
for (; (uintptr_t)(a + i) & 7; ++i) { for (; (uintptr_t)(a + i) & 7; ++i) {
if (a[i] != b[i] || !b[i]) { if (a[i] != b[i] || !b[i]) {
return (a[i] & 255) - (b[i] & 255); return (a[i] & 255) - (b[i] & 255);

View file

@ -18,12 +18,14 @@
*/ */
#include "libc/assert.h" #include "libc/assert.h"
#include "libc/bits/bits.h" #include "libc/bits/bits.h"
#include "libc/dce.h"
#include "libc/intrin/asan.internal.h"
#include "libc/str/str.h" #include "libc/str/str.h"
static noasan size_t strnlen_x64(const char *s, size_t n, size_t i) { static noasan size_t strnlen_x64(const char *s, size_t n, size_t i) {
uint64_t w; uint64_t w;
for (; i + 8 < n; i += 8) { for (; i + 8 < n; i += 8) {
w = READ64LE(s + i); w = *(uint64_t *)(s + i);
if ((w = ~w & (w - 0x0101010101010101) & 0x8080808080808080)) { if ((w = ~w & (w - 0x0101010101010101) & 0x8080808080808080)) {
i += (unsigned)__builtin_ctzll(w) >> 3; i += (unsigned)__builtin_ctzll(w) >> 3;
break; break;
@ -40,8 +42,9 @@ static noasan size_t strnlen_x64(const char *s, size_t n, size_t i) {
* @return byte length * @return byte length
* @asyncsignalsafe * @asyncsignalsafe
*/ */
size_t strnlen(const char *s, size_t n) { noasan size_t strnlen(const char *s, size_t n) {
size_t i; size_t i;
if (IsAsan() && n) __asan_verify(s, 1);
for (i = 0; (uintptr_t)(s + i) & 7; ++i) { for (i = 0; (uintptr_t)(s + i) & 7; ++i) {
if (i == n || !s[i]) return i; if (i == n || !s[i]) return i;
} }
@ -50,5 +53,6 @@ size_t strnlen(const char *s, size_t n) {
if (i == n || !s[i]) break; if (i == n || !s[i]) break;
} }
assert(i == n || (i < n && !s[i])); assert(i == n || (i < n && !s[i]));
if (IsAsan()) __asan_verify(s, i);
return i; return i;
} }

View file

@ -1,7 +1,7 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney Copyright 2022 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the any purpose with or without fee is hereby granted, provided that the
@ -16,32 +16,46 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "libc/nexgen32e/nexgen32e.h" #include "libc/assert.h"
#include "libc/testlib/testlib.h" #include "libc/dce.h"
#include "libc/intrin/asan.internal.h"
#include "libc/str/str.h"
TEST(sidiv, smoke) { static noasan size_t strnlen_s_x64(const char *s, size_t n, size_t i) {
EXPECT_EQ(13373133731337 / 10, div10int64(13373133731337)); uint64_t w;
EXPECT_EQ(13373133731337 / 100, div100int64(13373133731337)); for (; i + 8 < n; i += 8) {
EXPECT_EQ(13373133731337 / 1000, div1000int64(13373133731337)); w = *(uint64_t *)(s + i);
EXPECT_EQ(13373133731337 / 10000, div10000int64(13373133731337)); if ((w = ~w & (w - 0x0101010101010101) & 0x8080808080808080)) {
EXPECT_EQ(13373133731337 / 1000000, div1000000int64(13373133731337)); i += (unsigned)__builtin_ctzll(w) >> 3;
EXPECT_EQ(13373133731337 / 1000000000, div1000000000int64(13373133731337)); break;
}
}
return i;
} }
TEST(sirem, smoke) { /**
EXPECT_EQ(13373133731337 % 10, rem10int64(13373133731337)); * Returns length of NUL-terminated string... securely.
EXPECT_EQ(13373133731337 % 100, rem100int64(13373133731337)); *
EXPECT_EQ(13373133731337 % 1000, rem1000int64(13373133731337)); * This is like strnlen() except it'll return 0 if `s` is null. We also
EXPECT_EQ(13373133731337 % 10000, rem10000int64(13373133731337)); * make the assumption for the purposes of ASAN that `n` is the size of
EXPECT_EQ(13373133731337 % 1000000, rem1000000int64(13373133731337)); * the buffer if `s` is non-null.
EXPECT_EQ(13373133731337 % 1000000000, rem1000000000int64(13373133731337)); *
* @param s is string
* @param n is max length
* @return byte length
* @asyncsignalsafe
*/
noasan size_t strnlen_s(const char *s, size_t n) {
size_t i;
if (!s) return 0;
if (IsAsan()) __asan_verify(s, n);
for (i = 0; (uintptr_t)(s + i) & 7; ++i) {
if (i == n || !s[i]) return i;
} }
i = strnlen_s_x64(s, n, i);
TEST(rem, euclid) { for (;; ++i) {
ASSERT_EQ(-2, rem10int64(-12)); if (i == n || !s[i]) break;
ASSERT_EQ(-1, rem10int64(-1)); }
ASSERT_EQ(0, rem10int64(0)); assert(i == n || (i < n && !s[i]));
ASSERT_EQ(1, rem10int64(1)); return i;
ASSERT_EQ(9, rem10int64(9));
ASSERT_EQ(1, rem10int64(11));
} }

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