mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-08-09 03:10:27 +00:00
Merge branch 'master' into feature/sqliteSerialization
This commit is contained in:
commit
de54cee6ef
242 changed files with 9015 additions and 2635 deletions
29
.github/workflows/build.yml
vendored
Normal file
29
.github/workflows/build.yml
vendored
Normal 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
|
|
@ -1,6 +0,0 @@
|
||||||
virt: lxd
|
|
||||||
os: linux
|
|
||||||
language: c
|
|
||||||
script: make -j4 V=0
|
|
||||||
notifications:
|
|
||||||
email: false
|
|
1
Makefile
1
Makefile
|
@ -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
|
||||||
|
|
13
README.md
13
README.md
|
@ -1,5 +1,6 @@
|
||||||

|

|
||||||
|
|
||||||
|
[](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.
|
||||||
|
|
52
ape/ape.lds
52
ape/ape.lds
|
@ -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.
|
@ -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%
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -1,50 +1,46 @@
|
||||||
SYNOPSIS
|
# Cosmopolitan Standard Library
|
||||||
|
|
||||||
Cosmopolitan Standard Library.
|
This directory defines static archives defining functions, like
|
||||||
|
`printf()`, `mmap()`, win32, etc. Please note that the Cosmopolitan
|
||||||
|
build configuration doesn't link any C/C++ library dependencies
|
||||||
|
by default, so you still have the flexibility to choose the one
|
||||||
|
provided by your system. If you'd prefer Cosmopolitan, just add
|
||||||
|
`$(LIBC)` and `$(CRT)` to your linker arguments.
|
||||||
|
|
||||||
OVERVIEW
|
Your library is compromised of many bite-sized static archives.
|
||||||
|
We use the checkdeps tool to guarantee that the contents of the
|
||||||
|
archives are organized in a logical way that's easy to use with
|
||||||
|
or without our makefile infrastructure, since there's no cyclic
|
||||||
|
dependencies.
|
||||||
|
|
||||||
This directory defines static archives defining functions, like
|
The Cosmopolitan Library exports only the most stable canonical
|
||||||
printf(), mmap(), win32, etc. Please note that the Cosmopolitan
|
system calls for all supported operating systems, regardless of
|
||||||
build configuration doesn't link any C/C++ library dependencies
|
which platform is used for compilation. We polyfill many of the
|
||||||
by default, so you still have the flexibility to choose the one
|
APIs, e.g. `read()`, `write()` so they work consistently everywhere
|
||||||
provided by your system. If you'd prefer Cosmopolitan, just add
|
while other apis, e.g. `CreateWindowEx()`, might only work on one
|
||||||
$(LIBC) and $(CRT) to your linker arguments.
|
platform, in which case they become no-op functions on others.
|
||||||
|
|
||||||
Your library is compromised of many bite-sized static archives.
|
Cosmopolitan polyfill wrappers will usually use the dollar sign
|
||||||
We use the checkdeps tool to guarantee that the contents of the
|
naming convention, so they may be bypassed when necessary. This
|
||||||
archives are organized in a logical way that's easy to use with
|
same convention is used when multiple implementations of string
|
||||||
or without our makefile infrastructure, since there's no cyclic
|
library and other performance-critical function are provided to
|
||||||
dependencies.
|
allow Cosmopolitan to go fast on both old and newer computers.
|
||||||
|
|
||||||
The Cosmopolitan Library exports only the most stable canonical
|
We take an approach to configuration that relies heavily on the
|
||||||
system calls for all supported operating systems, regardless of
|
compiler's dead code elimination pass (`libc/dce.h`). Most of the
|
||||||
which platform is used for compilation. We polyfill many of the
|
code is written so that, for example, folks not wanting support
|
||||||
APIs, e.g. read(), write() so they work consistently everywhere
|
for OpenBSD can flip a bit in `SUPPORT_VECTOR` and that code will
|
||||||
while other apis, e.g. CreateWindowEx(), might only work on one
|
be omitted from the build. The same is true for builds that are
|
||||||
platform, in which case they become no-op functions on others.
|
tuned using `-march=native` which effectively asks the library to
|
||||||
|
not include runtime support hooks for x86 processors older than
|
||||||
|
what you use.
|
||||||
|
|
||||||
Cosmopolitan polyfill wrappers will usually use the dollar sign
|
Please note that, unlike Cygwin or MinGW, Cosmopolitan does not
|
||||||
naming convention, so they may be bypassed when necessary. This
|
achieve broad support by bolting on a POSIX emulation layer. We
|
||||||
same convention is used when multiple implementations of string
|
do nothing more than (in most cases) stateless API translations
|
||||||
library and other performance-critical function are provided to
|
that get you 90% of the way there in a fast lightweight manner.
|
||||||
allow Cosmopolitan to go fast on both old and newer computers.
|
We therefore can't address some of the subtle differences, such
|
||||||
|
as the nuances of absolute paths on Windows. Our approach could
|
||||||
We take an approach to configuration that relies heavily on the
|
be compared to something more along the lines of, "the Russians
|
||||||
compiler's dead code elimination pass (libc/dce.h). Most of the
|
just used a pencil to write in space", versus spending millions
|
||||||
code is written so that, for example, folks not wanting support
|
researching a pen like NASA.
|
||||||
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
|
|
||||||
tuned using -march=native which effectively asks the library to
|
|
||||||
not include runtime support hooks for x86 processors older than
|
|
||||||
what you use.
|
|
||||||
|
|
||||||
Please note that, unlike Cygwin or MinGW, Cosmopolitan does not
|
|
||||||
achieve broad support by bolting on a POSIX emulation layer. We
|
|
||||||
do nothing more than (in most cases) stateless API translations
|
|
||||||
that get you 90% of the way there in a fast lightweight manner.
|
|
||||||
We therefore can't address some of the subtle differences, such
|
|
||||||
as the nuances of absolute paths on Windows. Our approach could
|
|
||||||
be compared to something more along the lines of, "the Russians
|
|
||||||
just used a pencil to write in space", versus spending millions
|
|
||||||
researching a pen like NASA.
|
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -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
79
libc/calls/getcontext.S
Normal 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;
|
||||||
|
}
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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});
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
73
libc/calls/setcontext.S
Normal 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;
|
||||||
|
}
|
|
@ -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;
|
||||||
|
|
|
@ -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_ */
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -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
|
|
|
@ -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))
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
12
libc/intrin/futex.internal.h
Normal file
12
libc/intrin/futex.internal.h
Normal 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
44
libc/intrin/futex_wait.c
Normal 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
49
libc/intrin/futex_wake.c
Normal 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;
|
||||||
|
}
|
|
@ -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 \
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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_ */
|
|
|
@ -30,6 +30,7 @@ sched_yield:
|
||||||
testb IsXnu()
|
testb IsXnu()
|
||||||
jz 1f
|
jz 1f
|
||||||
pause
|
pause
|
||||||
|
xor %eax,%eax
|
||||||
ret
|
ret
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -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;
|
} else {
|
||||||
case '\r':
|
sched_yield();
|
||||||
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 {
|
|
||||||
return ch;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -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
4
libc/isystem/utmp.h
Normal 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
4
libc/isystem/utmpx.h
Normal 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_ */
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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));
|
||||||
|
|
|
@ -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
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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_
|
||||||
|
|
|
@ -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
|
|
|
@ -1 +0,0 @@
|
||||||
These files aren't intended to be compiled.
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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_ */
|
||||||
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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_ */
|
|
|
@ -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 */
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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_
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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
|
|
@ -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
47
libc/runtime/utmp.h
Normal 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
51
libc/runtime/utmpx.h
Normal 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_ */
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
demodernize = true;
|
||||||
TriedAndTrue:
|
TriedAndTrue:
|
||||||
client = __fixupnewsockfd(__sys_accept(server, addr, addrsize, 0), flags);
|
client = __fixupnewsockfd(__sys_accept(server, out_addr, out_addrsize, 0),
|
||||||
} else if (SupportsLinux() && !once) {
|
flags);
|
||||||
once = true;
|
|
||||||
if (client == __NR_accept4_linux) {
|
|
||||||
demodernize = true;
|
|
||||||
goto TriedAndTrue;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (client != -1 && IsBsd()) {
|
if (client != -1 && IsBsd()) {
|
||||||
sockaddr2linux(addr);
|
sockaddr2linux(&bsd, size, addr, addrsize);
|
||||||
}
|
}
|
||||||
return client;
|
return client;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
}
|
|
@ -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 {
|
||||||
|
|
|
@ -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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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) */
|
||||||
|
|
|
@ -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) {
|
||||||
opt_inout_srcaddrsize);
|
rc = sys_recvfrom(fd, buf, size, flags, opt_out_srcaddr,
|
||||||
if (opt_out_srcaddr && IsBsd() && got != -1) {
|
opt_inout_srcaddrsize);
|
||||||
sockaddr2linux(opt_out_srcaddr);
|
} else {
|
||||||
|
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,
|
||||||
|
|
|
@ -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)) {
|
||||||
|
|
|
@ -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 */
|
memcpy(&msg2, msg, sizeof(msg2));
|
||||||
if (msg->msg_namelen <= sizeof(addr2)) {
|
if (!(rc = sockaddr2bsd(msg->msg_name, msg->msg_namelen, &bsd,
|
||||||
memcpy(&addr2[0], msg->msg_name, msg->msg_namelen);
|
&msg2.msg_namelen))) {
|
||||||
sockaddr2bsd(&addr2[0]);
|
msg2.msg_name = &bsd.sa;
|
||||||
/* Copy all of msg (except for msg_name) into the new ephemeral local */
|
|
||||||
memcpy(&msg2, msg, sizeof(msg2));
|
|
||||||
msg2.msg_name = &addr2[0];
|
|
||||||
rc = sys_sendmsg(fd, &msg2, flags);
|
rc = sys_sendmsg(fd, &msg2, flags);
|
||||||
} else {
|
|
||||||
rc = einval();
|
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
rc = sys_sendmsg(fd, msg, flags);
|
||||||
}
|
}
|
||||||
/* else do the syscall */
|
|
||||||
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 */
|
||||||
|
|
|
@ -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
66
libc/sock/sockaddr2bsd.c
Normal 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();
|
||||||
|
}
|
||||||
|
}
|
60
libc/sock/sockaddr2linux.c
Normal file
60
libc/sock/sockaddr2linux.c
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
|
@ -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);
|
||||||
|
|
|
@ -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) */
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
TEST(rem, euclid) {
|
* @return byte length
|
||||||
ASSERT_EQ(-2, rem10int64(-12));
|
* @asyncsignalsafe
|
||||||
ASSERT_EQ(-1, rem10int64(-1));
|
*/
|
||||||
ASSERT_EQ(0, rem10int64(0));
|
noasan size_t strnlen_s(const char *s, size_t n) {
|
||||||
ASSERT_EQ(1, rem10int64(1));
|
size_t i;
|
||||||
ASSERT_EQ(9, rem10int64(9));
|
if (!s) return 0;
|
||||||
ASSERT_EQ(1, rem10int64(11));
|
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);
|
||||||
|
for (;; ++i) {
|
||||||
|
if (i == n || !s[i]) break;
|
||||||
|
}
|
||||||
|
assert(i == n || (i < n && !s[i]));
|
||||||
|
return i;
|
||||||
}
|
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue