Get threads working well on MacOS Arm64

- Now using 10x better GCD semaphores
- We now generate Linux-like thread ids
- We now use fast system clock / sleep libraries
- The APE M1 loader now generates Linux-like stacks
This commit is contained in:
Justine Tunney 2023-06-04 01:57:10 -07:00
parent b5eab2b0b7
commit bcf9af94bf
No known key found for this signature in database
GPG key ID: BE714B4575D6E328
2037 changed files with 4664 additions and 4451 deletions

View file

@ -16,53 +16,45 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include <time.h>
#include <fcntl.h>
#include <dispatch/dispatch.h>
#include <errno.h>
#include <stdarg.h>
#include <unistd.h>
#include <signal.h>
#include <fcntl.h>
#include <libkern/OSCacheControl.h>
#include <limits.h>
#include <pthread.h>
#include <sys/uio.h>
#include <signal.h>
#include <stdarg.h>
#include <stdint.h>
#include <sys/mman.h>
#include <libkern/OSCacheControl.h>
#include <sys/random.h>
#include <sys/uio.h>
#include <time.h>
#include <unistd.h>
#define SYSLIB_MAGIC ('s' | 'l' << 8 | 'i' << 16 | 'b' << 24)
#define SYSLIB_VERSION 0
#define SYSLIB_VERSION 1
struct Syslib {
int magic;
int version;
void (*exit)(int) __attribute__((__noreturn__));
long (*fork)(void);
long (*read)(int, void *, size_t);
long (*pread)(int, void *, size_t, off_t);
long (*readv)(int, const struct iovec *, int);
long (*write)(int, const void *, size_t);
long (*pwrite)(int, const void *, size_t, off_t);
long (*writev)(int, const struct iovec *, int);
long (*openat)(int, const char *, int, ...);
long (*pipe)(int[2]);
long (*close)(int);
long (*clock_gettime)(int, struct timespec *);
long (*nanosleep)(const struct timespec *, struct timespec *);
long (*mmap)(void *, size_t, int, int, int, off_t);
long (*sigaction)(int, const struct sigaction *restrict, struct sigaction *restrict);
int (*pthread_jit_write_protect_supported_np)(void);
void (*pthread_jit_write_protect_np)(int);
void (*sys_icache_invalidate)(void *, size_t);
pthread_t (*pthread_self)(void);
int (*pthread_create)(pthread_t *, const pthread_attr_t *, void *(*)(void *), void *);
int (*pthread_detach)(pthread_t);
int (*pthread_join)(pthread_t, void **);
int (*pthread_create)(pthread_t *, const pthread_attr_t *, void *(*)(void *),
void *);
void (*pthread_exit)(void *);
int (*pthread_kill)(pthread_t, int);
int (*pthread_sigmask)(int, const sigset_t *restrict, sigset_t *restrict);
int (*pthread_setname_np)(const char *);
int (*pthread_key_create)(pthread_key_t *, void (*)(void *));
int (*pthread_setspecific)(pthread_key_t, const void *);
void *(*pthread_getspecific)(pthread_key_t);
dispatch_semaphore_t (*dispatch_semaphore_create)(long);
long (*dispatch_semaphore_signal)(dispatch_semaphore_t);
long (*dispatch_semaphore_wait)(dispatch_semaphore_t, dispatch_time_t);
dispatch_time_t (*dispatch_walltime)(const struct timespec *, int64_t);
};
#define TROUBLESHOOT 0
@ -94,8 +86,9 @@ struct Syslib {
#define AT_RANDOM 25
#define AT_EXECFN 31
#define STACK_SIZE (8ul * 1024 * 1024)
#define STACK_ALIGN (sizeof(long) * 2)
#define AUXV_BYTES (sizeof(long) * 2 * 14)
#define AUXV_BYTES (sizeof(long) * 2 * 15)
// from the xnu codebase
#define _COMM_PAGE_START_ADDRESS 0x0000000FFFFFC000ul
@ -104,14 +97,12 @@ struct Syslib {
#define _COMM_PAGE_APRR_WRITE_DISABLE (_COMM_PAGE_START_ADDRESS + 0x118)
#define Min(X, Y) ((Y) > (X) ? (X) : (Y))
#define Roundup(X, K) (((X) + (K) - 1) & -(K))
#define Roundup(X, K) (((X) + (K)-1) & -(K))
#define Rounddown(X, K) ((X) & -(K))
#define Read32(S) \
((unsigned)(255 & (S)[3]) << 030 | \
(unsigned)(255 & (S)[2]) << 020 | \
(unsigned)(255 & (S)[1]) << 010 | \
(unsigned)(255 & (S)[0]) << 000)
((unsigned)(255 & (S)[3]) << 030 | (unsigned)(255 & (S)[2]) << 020 | \
(unsigned)(255 & (S)[1]) << 010 | (unsigned)(255 & (S)[0]) << 000)
#define Read64(S) \
((unsigned long)(255 & (S)[7]) << 070 | \
@ -123,13 +114,6 @@ struct Syslib {
(unsigned long)(255 & (S)[1]) << 010 | \
(unsigned long)(255 & (S)[0]) << 000)
struct PathSearcher {
unsigned long namelen;
const char *name;
const char *syspath;
char path[1024];
};
struct ElfEhdr {
unsigned char e_ident[16];
unsigned short e_type;
@ -168,10 +152,44 @@ union ElfPhdrBuf {
char buf[0x1000];
};
struct PathSearcher {
unsigned long namelen;
const char *name;
const char *syspath;
char path[1024];
};
struct ApeLoader {
union ElfEhdrBuf ehdr;
struct PathSearcher ps;
// this memory shall be discarded by the guest
//////////////////////////////////////////////
// this memory shall be known to guest program
union {
char argblock[ARG_MAX];
long numblock[ARG_MAX / sizeof(long)];
};
union ElfPhdrBuf phdr;
struct Syslib lib;
char rando[16];
};
static int ToLower(int c) {
return 'A' <= c && c <= 'Z' ? c + ('a' - 'A') : c;
}
static unsigned long StrLen(const char *s) {
unsigned long n = 0;
while (*s++) ++n;
return n;
}
static int StrCmp(const char *l, const char *r) {
unsigned long i = 0;
while (l[i] == r[i] && r[i]) ++i;
return (l[i] & 255) - (r[i] & 255);
}
static void *MemSet(void *a, int c, unsigned long n) {
char *d = a;
unsigned long i;
@ -197,12 +215,6 @@ static void *MemMove(void *a, const void *b, unsigned long n) {
return d;
}
static unsigned long StrLen(const char *s) {
unsigned long n = 0;
while (*s++) ++n;
return n;
}
static const char *MemChr(const char *s, unsigned char c, unsigned long n) {
for (; n; --n, ++s) {
if ((*s & 255) == c) {
@ -267,6 +279,7 @@ static void Perror(const char *c, int failed, const char *s) {
Emit(": ");
Emit(s);
if (failed) {
#include <sys/random.h>
Emit(" failed errno=");
Itoa(ibuf, errno);
Emit(ibuf);
@ -274,18 +287,12 @@ static void Perror(const char *c, int failed, const char *s) {
Emit("\n");
}
__attribute__((__noreturn__))
static void Pexit(const char *c, int failed, const char *s) {
__attribute__((__noreturn__)) static void Pexit(const char *c, int failed,
const char *s) {
Perror(c, failed, s);
_exit(127);
}
static int StrCmp(const char *l, const char *r) {
unsigned long i = 0;
while (l[i] == r[i] && r[i]) ++i;
return (l[i] & 255) - (r[i] & 255);
}
static char EndsWithIgnoreCase(const char *p, unsigned long n, const char *s) {
unsigned long i, m;
if (n >= (m = StrLen(s))) {
@ -347,8 +354,7 @@ static char FindCommand(struct PathSearcher *ps, const char *suffix) {
return SearchPath(ps, suffix);
}
static char *Commandv(struct PathSearcher *ps,
const char *name,
static char *Commandv(struct PathSearcher *ps, const char *name,
const char *syspath) {
ps->syspath = syspath ? syspath : "/bin:/usr/local/bin:/usr/bin";
if (!(ps->namelen = StrLen((ps->name = name)))) return 0;
@ -416,15 +422,14 @@ static void pthread_jit_write_protect_np_workaround(int enabled) {
Pexit("ape-m1", 0, "failed to set jit write protection");
}
__attribute__((__noreturn__))
static void Spawn(const char *exe,
int fd, long *sp,
struct ElfEhdr *e,
__attribute__((__noreturn__)) static void Spawn(const char *exe, int fd,
long *sp, struct ElfEhdr *e,
struct ElfPhdr *p,
struct Syslib *lib) {
int prot, flags;
long code, codesize;
unsigned long a, b, i;
code = 0;
codesize = 0;
for (i = e->e_phnum; i--;) {
@ -460,8 +465,8 @@ static void Spawn(const char *exe,
codesize = p[i].p_filesz;
}
if (p[i].p_filesz) {
if (mmap((char *)p[i].p_vaddr, p[i].p_filesz, prot,
flags, fd, p[i].p_offset) == MAP_FAILED) {
if (mmap((char *)p[i].p_vaddr, p[i].p_filesz, prot, flags, fd,
p[i].p_offset) == MAP_FAILED) {
Pexit(exe, -1, "image mmap()");
}
if ((a = Min(-p[i].p_filesz & 0x3fff, p[i].p_memsz - p[i].p_filesz))) {
@ -470,8 +475,8 @@ static void Spawn(const char *exe,
}
if ((b = Roundup(p[i].p_memsz, 0x4000)) >
(a = Roundup(p[i].p_filesz, 0x4000))) {
if (mmap((char *)p[i].p_vaddr + a, b - a,
prot, flags | MAP_ANONYMOUS, -1, 0) == MAP_FAILED) {
if (mmap((char *)p[i].p_vaddr + a, b - a, prot, flags | MAP_ANONYMOUS, -1,
0) == MAP_FAILED) {
Pexit(exe, -1, "bss mmap()");
}
}
@ -521,21 +526,21 @@ static void Spawn(const char *exe,
__builtin_unreachable();
}
static void TryElf(const char *exe, int fd, long *sp, long *bp, char *execfn,
union ElfEhdrBuf *ehdr, union ElfPhdrBuf *phdr, struct Syslib *lib) {
static void TryElf(struct ApeLoader *M, const char *exe, int fd, long *sp,
long *bp, char *execfn) {
unsigned long n;
if (Read32(ehdr->buf) == Read32("\177ELF") &&
ehdr->ehdr.e_type == ET_EXEC &&
ehdr->ehdr.e_machine == EM_AARCH64 &&
ehdr->ehdr.e_ident[EI_CLASS] == ELFCLASS64 &&
ehdr->ehdr.e_ident[EI_DATA] == ELFDATA2LSB &&
(n = ehdr->ehdr.e_phnum * sizeof(phdr->phdr)) <= sizeof(phdr->buf) &&
pread(fd, phdr->buf, n, ehdr->ehdr.e_phoff) == n) {
if (Read32(M->ehdr.buf) == Read32("\177ELF") &&
M->ehdr.ehdr.e_type == ET_EXEC && M->ehdr.ehdr.e_machine == EM_AARCH64 &&
M->ehdr.ehdr.e_ident[EI_CLASS] == ELFCLASS64 &&
M->ehdr.ehdr.e_ident[EI_DATA] == ELFDATA2LSB &&
(n = M->ehdr.ehdr.e_phnum * sizeof(M->phdr.phdr)) <=
sizeof(M->phdr.buf) &&
pread(fd, M->phdr.buf, n, M->ehdr.ehdr.e_phoff) == n) {
long auxv[][2] = {
{AT_PHDR, (long)&phdr->phdr}, //
{AT_PHENT, ehdr->ehdr.e_phentsize}, //
{AT_PHNUM, ehdr->ehdr.e_phnum}, //
{AT_ENTRY, ehdr->ehdr.e_entry}, //
{AT_PHDR, (long)&M->phdr.phdr}, //
{AT_PHENT, M->ehdr.ehdr.e_phentsize}, //
{AT_PHNUM, M->ehdr.ehdr.e_phnum}, //
{AT_ENTRY, M->ehdr.ehdr.e_entry}, //
{AT_PAGESZ, 0x4000}, //
{AT_UID, getuid()}, //
{AT_EUID, geteuid()}, //
@ -544,18 +549,18 @@ static void TryElf(const char *exe, int fd, long *sp, long *bp, char *execfn,
{AT_HWCAP, 0xffb3ffffu}, //
{AT_HWCAP2, 0x181}, //
{AT_SECURE, issetugid()}, //
{AT_RANDOM, (long)M->rando}, //
{AT_EXECFN, (long)execfn}, //
{0, 0}, //
};
_Static_assert(sizeof(auxv) == AUXV_BYTES,
"Please update the AUXV_BYTES constant");
MemMove(bp, auxv, sizeof(auxv));
Spawn(exe, fd, sp, &ehdr->ehdr, &phdr->phdr, lib);
Spawn(exe, fd, sp, &M->ehdr.ehdr, &M->phdr.phdr, &M->lib);
}
}
__attribute__((__noinline__))
static long sysret(long rc) {
__attribute__((__noinline__)) static long sysret(long rc) {
return rc == -1 ? -errno : rc;
}
@ -563,47 +568,10 @@ static long sys_fork(void) {
return sysret(fork());
}
static long sys_read(int fd, void *p, size_t n) {
return sysret(read(fd, p, n));
}
static long sys_pread(int fd, void *p, size_t n, off_t o) {
return sysret(pread(fd, p, n, o));
}
static long sys_readv(int fd, const struct iovec *p, int n) {
return sysret(readv(fd, p, n));
}
static long sys_write(int fd, const void *p, size_t n) {
return sysret(write(fd, p, n));
}
static long sys_pwrite(int fd, const void *p, size_t n, off_t o) {
return sysret(pwrite(fd, p, n, o));
}
static long sys_writev(int fd, const struct iovec *p, int n) {
return sysret(writev(fd, p, n));
}
static long sys_openat(int dirfd, const char *path, int oflag, ...) {
va_list va;
unsigned mode;
va_start(va, oflag);
mode = va_arg(va, unsigned);
va_end(va);
return sysret(openat(dirfd, path, oflag, mode));
}
static long sys_pipe(int pfds[2]) {
return sysret(pipe(pfds));
}
static long sys_close(int fd) {
return sysret(close(fd));
}
static long sys_clock_gettime(int clock, struct timespec *ts) {
return sysret(clock_gettime(clock, ts));
}
@ -612,69 +580,62 @@ static long sys_nanosleep(const struct timespec *req, struct timespec *rem) {
return sysret(nanosleep(req, rem));
}
static long sys_mmap(void *addr, size_t size, int prot, int flags, int fd, off_t off) {
static long sys_mmap(void *addr, size_t size, int prot, int flags, int fd,
off_t off) {
return sysret((long)mmap(addr, size, prot, flags, fd, off));
}
static long sys_sigaction(int sig, const struct sigaction *restrict act,
struct sigaction *restrict oact) {
return sysret(sigaction(sig, act, oact));
}
int loader(int argc, char **argv, char **envp) {
int main(int argc, char **argv, char **envp) {
long z;
void *map;
long *sp, *bp, *ip;
int c, i, n, fd, rc;
struct ApeLoader *M;
unsigned char rando[24];
char *p, *tp, *exe, *prog, *execfn;
struct {
union ElfEhdrBuf ehdr;
struct PathSearcher ps;
// this memory shall be discarded by the guest
//////////////////////////////////////////////
// this memory shall be known to guest program
union {
char argblock[ARG_MAX];
long numblock[ARG_MAX / sizeof(long)];
};
union ElfPhdrBuf phdr;
struct Syslib lib;
} M;
// generate some hard random data
if (getentropy(rando, sizeof(rando))) {
Pexit(argv[0], -1, "getentropy");
}
// expose some apple libraries
M.lib.magic = SYSLIB_MAGIC;
M.lib.version = SYSLIB_VERSION;
M.lib.exit = _exit;
M.lib.fork = sys_fork;
M.lib.read = sys_read;
M.lib.pread = sys_pread;
M.lib.readv = sys_readv;
M.lib.write = sys_write;
M.lib.pwrite = sys_pwrite;
M.lib.writev = sys_writev;
M.lib.openat = sys_openat;
M.lib.close = sys_close;
M.lib.clock_gettime = sys_clock_gettime;
M.lib.nanosleep = sys_nanosleep;
M.lib.mmap = sys_mmap;
M.lib.sigaction = sys_sigaction;
M.lib.pthread_jit_write_protect_supported_np =
// make the stack look like a linux one
map = mmap((void *)(0x7f0000000000 | (long)rando[23] << 32), STACK_SIZE,
PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
if (map == MAP_FAILED) {
Pexit(argv[0], -1, "stack mmap");
}
// put argument block at top of allocated stack
z = (long)map;
z += STACK_SIZE - sizeof(struct ApeLoader);
z &= -_Alignof(struct ApeLoader);
M = (struct ApeLoader *)z;
// expose screwy apple libs
M->lib.magic = SYSLIB_MAGIC;
M->lib.version = SYSLIB_VERSION;
M->lib.fork = sys_fork;
M->lib.pipe = sys_pipe;
M->lib.clock_gettime = sys_clock_gettime;
M->lib.nanosleep = sys_nanosleep;
M->lib.mmap = sys_mmap;
M->lib.pthread_jit_write_protect_supported_np =
pthread_jit_write_protect_supported_np;
M.lib.pthread_jit_write_protect_np =
pthread_jit_write_protect_np_workaround;
M.lib.pthread_self = pthread_self;
M.lib.pthread_create = pthread_create;
M.lib.pthread_join = pthread_join;
M.lib.pthread_exit = pthread_exit;
M.lib.pthread_kill = pthread_kill;
M.lib.pthread_sigmask = pthread_sigmask;
M.lib.pthread_setname_np = pthread_setname_np;
M.lib.pthread_key_create = pthread_key_create;
M.lib.pthread_getspecific = pthread_getspecific;
M.lib.pthread_setspecific = pthread_setspecific;
M->lib.pthread_jit_write_protect_np = pthread_jit_write_protect_np_workaround;
M->lib.pthread_create = pthread_create;
M->lib.pthread_exit = pthread_exit;
M->lib.pthread_kill = pthread_kill;
M->lib.pthread_sigmask = pthread_sigmask;
M->lib.pthread_setname_np = pthread_setname_np;
M->lib.dispatch_semaphore_create = dispatch_semaphore_create;
M->lib.dispatch_semaphore_signal = dispatch_semaphore_signal;
M->lib.dispatch_semaphore_wait = dispatch_semaphore_wait;
M->lib.dispatch_walltime = dispatch_walltime;
// copy system provided argument block
bp = M.numblock;
tp = M.argblock + sizeof(M.argblock);
bp = M->numblock;
tp = M->argblock + sizeof(M->argblock);
*bp++ = argc;
for (i = 0; i < argc; ++i) {
tp -= (n = StrLen(argv[i]) + 1);
@ -690,7 +651,7 @@ int loader(int argc, char **argv, char **envp) {
*bp++ = 0;
// get arguments that point into our block
sp = M.numblock;
sp = M->numblock;
argc = *sp;
argv = (char **)(sp + 1);
envp = (char **)(sp + 1 + argc + 1);
@ -734,14 +695,18 @@ int loader(int argc, char **argv, char **envp) {
bp = ip + n;
sp = ip;
// relocate the guest's random numbers
MemMove(M->rando, rando, sizeof(M->rando));
MemSet(rando, 0, sizeof(rando));
// search for executable
if (!(exe = Commandv(&M.ps, prog, GetEnv(envp, "PATH")))) {
if (!(exe = Commandv(&M->ps, prog, GetEnv(envp, "PATH")))) {
Pexit(prog, 0, "not found (maybe chmod +x)");
} else if ((fd = openat(AT_FDCWD, exe, O_RDONLY)) < 0) {
Pexit(exe, -1, "open");
} else if ((rc = read(fd, M.ehdr.buf, sizeof(M.ehdr.buf))) < 0) {
} else if ((rc = read(fd, M->ehdr.buf, sizeof(M->ehdr.buf))) < 0) {
Pexit(exe, -1, "read");
} else if (rc != sizeof(M.ehdr.buf)) {
} else if (rc != sizeof(M->ehdr.buf)) {
Pexit(exe, 0, "too small");
}
@ -759,13 +724,14 @@ int loader(int argc, char **argv, char **envp) {
// 3. shell script may have multiple lines producing elf headers
// 4. all elf printf lines must exist in the first 4096 bytes of file
// 5. elf program headers may appear anywhere in the binary
if (Read64(M.ehdr.buf) == Read64("MZqFpD='") ||
Read64(M.ehdr.buf) == Read64("jartsr='")) {
for (p = M.ehdr.buf; p < M.ehdr.buf + sizeof(M.ehdr.buf); ++p) {
if (Read64(M->ehdr.buf) == Read64("MZqFpD='") ||
Read64(M->ehdr.buf) == Read64("jartsr='")) {
for (p = M->ehdr.buf; p < M->ehdr.buf + sizeof(M->ehdr.buf); ++p) {
if (Read64(p) != Read64("printf '")) {
continue;
}
for (i = 0, p += 8; p + 3 < M.ehdr.buf + sizeof(M.ehdr.buf) && (c = *p++) != '\'';) {
for (i = 0, p += 8;
p + 3 < M->ehdr.buf + sizeof(M->ehdr.buf) && (c = *p++) != '\'';) {
if (c == '\\') {
if ('0' <= *p && *p <= '7') {
c = *p++ - '0';
@ -779,22 +745,13 @@ int loader(int argc, char **argv, char **envp) {
}
}
}
M.ehdr.buf[i++] = c;
M->ehdr.buf[i++] = c;
}
if (i >= sizeof(M.ehdr.ehdr)) {
TryElf(exe, fd, sp, bp, execfn, &M.ehdr, &M.phdr, &M.lib);
if (i >= sizeof(M->ehdr.ehdr)) {
TryElf(M, exe, fd, sp, bp, execfn);
}
}
}
TryElf(exe, fd, sp, bp, execfn, &M.ehdr, &M.phdr, &M.lib);
TryElf(M, exe, fd, sp, bp, execfn);
Pexit(exe, 0, "Not an acceptable APE/ELF executable for AARCH64");
}
asm(".globl\t_main\n_main:\t"
"stp\tx29,x30,[sp,#-16]!\n\t"
"mov\tx29,sp\n\t"
"mov\tx9,sp\n\t"
"and\tsp,x9,#-(2*1024*1024)\n\t"
"bl\t_loader\n\t"
"ldp\tx29,x30,[sp],#16\n\t"
"ret");

View file

@ -0,0 +1,26 @@
/*-*- 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/calls/struct/timespec.h"
#include "libc/calls/struct/timespec.internal.h"
#include "libc/calls/syscall-sysv.internal.h"
#include "libc/runtime/syslib.internal.h"
int sys_clock_gettime_m1(int clock, struct timespec *ts) {
return _sysret(__syslib->clock_gettime(clock, ts));
}

View file

@ -110,8 +110,15 @@ clock_gettime_f *__clock_gettime_get(bool *opt_out_isfast) {
if (IsLinux() && (res = CGT_VDSO)) {
isfast = true;
} else if (IsXnu()) {
isfast = false;
#ifdef __x86_64__
res = sys_clock_gettime_xnu;
isfast = false;
#elif defined(__aarch64__)
res = sys_clock_gettime_m1;
isfast = true;
#else
#error "unsupported architecture"
#endif
} else if (IsWindows()) {
isfast = true;
res = sys_clock_gettime_nt;

View file

@ -16,10 +16,13 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/struct/timespec.h"
#include "libc/calls/struct/timespec.internal.h"
#include "libc/calls/struct/timeval.h"
#include "libc/calls/struct/timeval.internal.h"
#include "libc/calls/syscall-sysv.internal.h"
#include "libc/fmt/conv.h"
#include "libc/runtime/syslib.internal.h"
#include "libc/sock/internal.h"
#include "libc/sysv/consts/clock.h"
#include "libc/sysv/consts/timer.h"
@ -27,23 +30,38 @@
int sys_clock_nanosleep_xnu(int clock, int flags, const struct timespec *req,
struct timespec *rem) {
int res;
struct timeval now, abs, rel;
#ifdef __x86_64__
struct timeval abs, now, rel;
if (clock == CLOCK_REALTIME) {
if (flags & TIMER_ABSTIME) {
abs = timespec_totimeval(*req);
sys_gettimeofday_xnu(&now, 0, 0);
if (timeval_cmp(abs, now) > 0) {
rel = timeval_sub(abs, now);
res = sys_select(0, 0, 0, 0, &rel);
return sys_select(0, 0, 0, 0, &rel);
} else {
res = 0;
return 0;
}
} else {
res = sys_nanosleep_xnu(req, rem);
return sys_nanosleep_xnu(req, rem);
}
} else {
res = enotsup();
return enotsup();
}
return res;
#else
long res;
struct timespec abs, now, rel;
if (flags & TIMER_ABSTIME) {
abs = *req;
if (!(res = __syslib->clock_gettime(clock, &now))) {
if (timespec_cmp(abs, now) > 0) {
rel = timespec_sub(abs, now);
res = __syslib->nanosleep(&rel, 0);
}
}
} else {
res = __syslib->nanosleep(req, rem);
}
return _sysret(res);
#endif
}

View file

@ -0,0 +1,35 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/struct/timespec.h"
#include "libc/calls/struct/timeval.h"
#include "libc/calls/struct/timeval.internal.h"
#include "libc/calls/syscall-sysv.internal.h"
#include "libc/runtime/syslib.internal.h"
#include "libc/sysv/consts/clock.h"
axdx_t sys_gettimeofday_m1(struct timeval *tv, struct timezone *tz, void *wut) {
axdx_t ad;
struct timespec ts;
ad.ax = _sysret(__syslib->clock_gettime(CLOCK_REALTIME, &ts));
ad.dx = 0;
if (!ad.ax && tv) {
*tv = timespec_totimeval(ts);
}
return ad;
}

View file

@ -82,8 +82,15 @@ gettimeofday_f *__gettimeofday_get(bool *opt_out_isfast) {
isfast = true;
res = sys_gettimeofday_nt;
} else if (IsXnu()) {
isfast = false;
#ifdef __x86_64__
res = sys_gettimeofday_xnu;
isfast = false;
#elif defined(__aarch64__)
res = sys_gettimeofday_m1;
isfast = true;
#else
#error "unsupported architecture"
#endif
} else if (IsMetal()) {
isfast = false;
res = sys_gettimeofday_metal;

View file

@ -20,24 +20,21 @@
#include "libc/calls/struct/timespec.internal.h"
#include "libc/calls/struct/timeval.h"
#include "libc/calls/struct/timeval.internal.h"
#include "libc/calls/syscall-sysv.internal.h"
#include "libc/errno.h"
#include "libc/runtime/syslib.internal.h"
#include "libc/sock/internal.h"
// nanosleep() on xnu: a bloodbath of a polyfill
// consider using clock_nanosleep(TIMER_ABSTIME)
int sys_nanosleep_xnu(const struct timespec *req, struct timespec *rem) {
#ifdef __x86_64__
int rc;
struct timeval wt, t1, t2, td;
if (rem) sys_gettimeofday_xnu(&t1, 0, 0);
wt = timespec_totimeval(*req); // rounds up
rc = sys_select(0, 0, 0, 0, &wt);
if (rem) {
if (!rc) {
rem->tv_sec = 0;
rem->tv_nsec = 0;
} else if (rc == -1 && errno == EINTR) {
// xnu select() doesn't modify timeout
// so we need, yet another system call
if (rem && rc == -1 && errno == EINTR) {
sys_gettimeofday_xnu(&t2, 0, 0);
td = timeval_sub(t2, t1);
if (timeval_cmp(td, wt) >= 0) {
@ -47,6 +44,8 @@ int sys_nanosleep_xnu(const struct timespec *req, struct timespec *rem) {
*rem = timeval_totimespec(timeval_sub(wt, td));
}
}
}
return rc;
#else
return _sysret(__syslib->nanosleep(req, rem));
#endif
}

View file

@ -12,6 +12,7 @@ int __utimens(int, const char *, const struct timespec[2], int) _Hide;
int sys_clock_getres(int, struct timespec *) _Hide;
int sys_clock_gettime(int, struct timespec *) _Hide;
int sys_clock_gettime_nt(int, struct timespec *) _Hide;
int sys_clock_gettime_m1(int, struct timespec *) _Hide;
int sys_clock_gettime_xnu(int, struct timespec *) _Hide;
int sys_clock_nanosleep_nt(int, int, const struct timespec *, struct timespec *) _Hide;
int sys_clock_nanosleep_openbsd(int, int, const struct timespec *, struct timespec *) _Hide;

View file

@ -9,6 +9,7 @@ axdx_t sys_gettimeofday(struct timeval *, struct timezone *, void *) _Hide;
int sys_futimes(int, const struct timeval *) _Hide;
int sys_lutimes(const char *, const struct timeval *) _Hide;
int sys_utimes(const char *, const struct timeval *) _Hide;
axdx_t sys_gettimeofday_m1(struct timeval *, struct timezone *, void *) _Hide;
axdx_t sys_gettimeofday_xnu(struct timeval *, struct timezone *, void *) _Hide;
axdx_t sys_gettimeofday_nt(struct timeval *, struct timezone *, void *) _Hide;
int sys_utimes_nt(const char *, const struct timeval[2]) _Hide;

View file

@ -66,6 +66,12 @@
#define IsAsan() 0
#endif
#ifdef __aarch64__
#define IsXnuSilicon() IsXnu()
#else
#define IsXnuSilicon() 0
#endif
#if defined(__PIE__) || defined(__PIC__)
#define IsPositionIndependent() 1
#else

View file

@ -29,6 +29,7 @@
#include "libc/runtime/runtime.h"
#include "libc/runtime/symbols.internal.h"
#include "libc/thread/thread.h"
#include "libc/thread/tls.h"
relegated void __assert_fail(const char *expr, const char *file, int line) {
int me, owner;
@ -37,7 +38,7 @@ relegated void __assert_fail(const char *expr, const char *file, int line) {
strace_enabled(-1);
ftrace_enabled(-1);
owner = 0;
me = sys_gettid();
me = __tls_enabled ? __get_tls()->tib_tid : sys_gettid();
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, 0);
kprintf("%s:%d: assert(%s) failed (tid %d) %m\n", file, line, expr, me);
if (__vforked ||

View file

@ -20,6 +20,7 @@
#include "libc/intrin/asmflag.h"
#include "libc/nt/thread.h"
#include "libc/runtime/runtime.h"
#include "libc/runtime/syslib.internal.h"
#include "libc/sysv/consts/nr.h"
#include "libc/thread/tls.h"
@ -74,13 +75,16 @@ privileged wontreturn void _Exit1(int rc) {
}
notpossible;
#elif defined(__aarch64__)
if (IsLinux()) {
register long r0 asm("x0") = rc;
asm volatile("mov\tx8,%0\n\t"
"mov\tx16,%1\n\t"
"svc\t0"
: /* no outputs */
: "i"(93), "i"(0x169), "r"(r0)
: "i"(93), "r"(r0)
: "x8", "memory");
} else if (IsXnu()) {
__syslib->pthread_exit(0);
}
notpossible;
#else
#error "arch unsupported"

View file

@ -227,8 +227,8 @@ privileged dontinline void klog(const char *b, size_t n) {
register long r0 asm("x0") = (long)2;
register long r1 asm("x1") = (long)b;
register long r2 asm("x2") = (long)n;
register long r8 asm("x8") = (long)__NR_write & 0x7ff;
register long r16 asm("x16") = (long)__NR_write & 0x7ff;
register long r8 asm("x8") = (long)__NR_write;
register long r16 asm("x16") = (long)__NR_write;
register long res_x0 asm("x0");
asm volatile("svc\t0"
: "=r"(res_x0)

View file

@ -90,13 +90,18 @@ sched_yield:
#elif defined(__aarch64__)
mov x0,#0
mov x1,#0
mov x2,#0
mov x3,#0
mov x8,#0x7c // sched_yield() for linux
mov x16,#0x85d // select(0,0,0,0) for xnu
stp x29,x30,[sp,-32]!
mov x29,sp
mov x3,0
mov x2,0
add x4,sp,16
mov x1,0
mov w0,0
stp xzr,xzr,[sp,16]
mov x8,#0x7c // sched_yield() for gnu/systemd
mov x16,#0x5d // select(0,0,0,0,&blah) for xnu
svc 0
ldp x29,x30,[sp],32
ret
#else

View file

@ -63,14 +63,15 @@ privileged int sys_gettid(void) {
}
return tid;
#elif defined(__aarch64__)
register long res_x0 asm("x0");
// this can't be used on xnu
if (!IsLinux()) notpossible;
register long res asm("x0");
asm volatile("mov\tx8,%1\n\t"
"mov\tx16,%2\n\t"
"svc\t0"
: "=r"(res_x0)
: "i"(178), "i"(186)
: "=r"(res)
: "i"(178)
: "x8", "memory");
return res_x0;
return res;
#else
#error "arch unsupported"
#endif

View file

@ -45,7 +45,7 @@ relegated wontreturn void __die(void) {
int me, owner;
static atomic_int once;
owner = 0;
me = sys_gettid();
me = __tls_enabled ? __get_tls()->tib_tid : sys_gettid();
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, 0);
if (__vforked ||
atomic_compare_exchange_strong_explicit(

View file

@ -270,7 +270,7 @@ static wontreturn relegated noinstrument void __minicrash(int sig,
"\n",
kind, sig, __argv[0], ctx ? ctx->uc_mcontext.rip : 0,
ctx ? ctx->uc_mcontext.rsp : 0, ctx ? ctx->uc_mcontext.rbp : 0, __pid,
sys_gettid());
__tls_enabled ? __get_tls()->tib_tid : sys_gettid());
_Exitr(119);
}
@ -302,7 +302,7 @@ relegated void __oncrash_amd64(int sig, struct siginfo *si, void *arg) {
ftrace_enabled(-1);
strace_enabled(-1);
owner = 0;
me = sys_gettid();
me = __tls_enabled ? __get_tls()->tib_tid : sys_gettid();
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, 0);
if (atomic_compare_exchange_strong_explicit(
&once, &owner, me, memory_order_relaxed, memory_order_relaxed)) {

View file

@ -27,7 +27,6 @@
#include "libc/intrin/asan.internal.h"
#include "libc/intrin/atomic.h"
#include "libc/intrin/describeflags.internal.h"
#include "libc/intrin/kprintf.h"
#include "libc/intrin/strace.internal.h"
#include "libc/limits.h"
#include "libc/macros.internal.h"
@ -53,6 +52,9 @@
#include "libc/thread/tls2.h"
#include "libc/thread/xnu.internal.h"
#define kMaxThreadIds 32768
#define kMinThreadId 262144
#define __NR_thr_new 455
#define __NR_clone_linux 56
#define __NR__lwp_create 309
@ -64,8 +66,11 @@
#define LWP_SUSPENDED 0x00000080
struct CloneArgs {
union {
_Alignas(16) union {
struct {
int tid;
int this;
};
uint32_t utid;
int64_t tid64;
};
@ -77,6 +82,12 @@ struct CloneArgs {
void *arg;
};
static struct CloneArgs *AllocateCloneArgs(char *stk, size_t stksz) {
return (struct CloneArgs *)(((uintptr_t)(stk + stksz) -
sizeof(struct CloneArgs)) &
-16);
}
#ifdef __x86_64__
////////////////////////////////////////////////////////////////////////////////
@ -108,7 +119,7 @@ WinThreadEntry(int rdi, // rcx
int rc;
if (wt->tls) __set_tls_win32(wt->tls);
*wt->ctid = wt->tid;
rc = WinThreadLaunch(wt->arg, wt->tid, wt->func, (intptr_t)wt & -16);
rc = WinThreadLaunch(wt->arg, wt->tid, wt->func, (intptr_t)wt);
// we can now clear ctid directly since we're no longer using our own
// stack memory, which can now be safely free'd by the parent thread.
*wt->ztid = 0;
@ -124,9 +135,7 @@ static textwindows errno_t CloneWindows(int (*func)(void *, int), char *stk,
void *tls, int *ptid, int *ctid) {
int64_t h;
struct CloneArgs *wt;
wt = (struct CloneArgs *)(((intptr_t)(stk + stksz) -
sizeof(struct CloneArgs)) &
-alignof(struct CloneArgs));
wt = AllocateCloneArgs(stk, stksz);
wt->ctid = flags & CLONE_CHILD_SETTID ? ctid : &wt->tid;
wt->ztid = flags & CLONE_CHILD_CLEARTID ? ctid : &wt->tid;
wt->func = func;
@ -155,7 +164,6 @@ void XnuThreadThunk(void *pthread, // rdi x0
asm("XnuThreadThunk:\n\t"
"xor\t%ebp,%ebp\n\t"
"mov\t%r8,%rsp\n\t"
"and\t$-16,%rsp\n\t"
"push\t%rax\n\t"
"jmp\tXnuThreadMain\n\t"
".size\tXnuThreadThunk,.-XnuThreadThunk");
@ -209,9 +217,7 @@ static errno_t CloneXnu(int (*fn)(void *), char *stk, size_t stksz, int flags,
_npassert(sys_bsdthread_register(XnuThreadThunk, 0, 0, 0, 0, 0, 0) != -1);
once = true;
}
wt = (struct CloneArgs *)(((intptr_t)(stk + stksz) -
sizeof(struct CloneArgs)) &
-alignof(struct CloneArgs));
wt = AllocateCloneArgs(stk, stksz);
wt->ptid = flags & CLONE_PARENT_SETTID ? ptid : &wt->tid;
wt->ctid = flags & CLONE_CHILD_SETTID ? ctid : &wt->tid;
wt->ztid = flags & CLONE_CHILD_CLEARTID ? ctid : &wt->tid;
@ -248,9 +254,7 @@ static errno_t CloneFreebsd(int (*func)(void *, int), char *stk, size_t stksz,
bool failed;
int64_t tid;
struct CloneArgs *wt;
wt = (struct CloneArgs *)(((intptr_t)(stk + stksz) -
sizeof(struct CloneArgs)) &
-alignof(struct CloneArgs));
wt = AllocateCloneArgs(stk, stksz);
wt->ctid = flags & CLONE_CHILD_SETTID ? ctid : &wt->tid;
wt->ztid = flags & CLONE_CHILD_CLEARTID ? ctid : &wt->tid;
wt->tls = tls;
@ -260,7 +264,7 @@ static errno_t CloneFreebsd(int (*func)(void *, int), char *stk, size_t stksz,
.start_func = FreebsdThreadMain,
.arg = wt,
.stack_base = stk,
.stack_size = (((intptr_t)wt - (intptr_t)stk) & -16) - 8,
.stack_size = (uintptr_t)wt - (uintptr_t)stk,
.tls_base = flags & CLONE_SETTLS ? tls : 0,
.tls_size = 64,
.child_tid = &wt->tid64,
@ -346,8 +350,7 @@ static wontreturn void NetbsdThreadMain(void *arg, // rdi
// we no longer use the stack after this point
// %eax = int __lwp_exit(void);
asm volatile("movl\t$0,%2\n\t" // *wt->ztid = 0
"syscall\n\t" // __lwp_exit()
"ud2"
"syscall" // __lwp_exit()
: "=a"(ax), "=d"(dx), "=m"(*ztid)
: "0"(310)
: "rcx", "r11", "memory");
@ -440,20 +443,18 @@ static int CloneNetbsd(int (*func)(void *, int), char *stk, size_t stksz,
static void *SiliconThreadMain(void *arg) {
register struct CloneArgs *wt asm("x21") = arg;
asm volatile("ldr\tx28,%0" : /* no outputs */ : "m"(wt->tls));
int tid = sys_gettid();
*wt->ctid = tid;
*wt->ptid = tid;
*wt->ctid = wt->this;
register long x0 asm("x0") = (long)wt->arg;
register long x1 asm("x1") = (long)tid;
register long x1 asm("x1") = (long)wt->tid;
asm volatile("mov\tx19,x29\n\t" // save frame pointer
"mov\tx20,sp\n\t" // save stack pointer
"mov\tx29,#0\n\t" // reset backtrace
"mov\tsp,x21\n\t" // switch stack
"mov\tsp,%3\n\t" // switch stack
"blr\t%2\n\t" // wt->func(wt->arg, tid)
"mov\tx29,x19\n\t" // restore frame pointer
"mov\tsp,x20" // restore stack pointer
: "+r"(x0)
: "r"(x1), "r"(wt->func)
: "r"(x1), "r"(wt->func), "r"(wt)
: "x19", "x20", "memory");
*wt->ztid = 0;
return 0;
@ -462,18 +463,24 @@ static void *SiliconThreadMain(void *arg) {
static errno_t CloneSilicon(int (*fn)(void *, int), char *stk, size_t stksz,
int flags, void *arg, void *tls, int *ptid,
int *ctid) {
errno_t res;
unsigned tid;
pthread_t th;
struct CloneArgs *wt;
wt = (struct CloneArgs *)(((intptr_t)(stk + stksz) -
sizeof(struct CloneArgs)) &
-MAX(16, alignof(struct CloneArgs)));
static atomic_uint tids;
wt = AllocateCloneArgs(stk, stksz);
tid = atomic_fetch_add_explicit(&tids, 1, memory_order_acq_rel);
wt->this = tid = (tid & (kMaxThreadIds - 1)) + kMinThreadId;
wt->ctid = flags & CLONE_CHILD_SETTID ? ctid : &wt->tid;
wt->ptid = flags & CLONE_PARENT_SETTID ? ptid : &wt->tid;
wt->ztid = flags & CLONE_CHILD_CLEARTID ? ctid : &wt->tid;
wt->tls = flags & CLONE_SETTLS ? tls : 0;
wt->func = fn;
wt->arg = arg;
return __syslib->pthread_create(&th, 0, SiliconThreadMain, wt);
if (!(res = __syslib->pthread_create(&th, 0, SiliconThreadMain, wt)) &&
(flags & CLONE_PARENT_SETTID)) {
*ptid = tid;
}
return res;
}
#endif /* __aarch64__ */

View file

@ -16,6 +16,7 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/calls.h"
#include "libc/calls/syscall-sysv.internal.h"
#include "libc/dce.h"
#include "libc/intrin/strace.internal.h"
@ -27,11 +28,16 @@
#include "libc/runtime/stack.h"
#include "libc/runtime/syslib.internal.h"
#include "libc/sysv/consts/prot.h"
#include "libc/sysv/consts/sig.h"
#include "libc/thread/thread.h"
#include "libc/thread/tls.h"
#ifndef __x86_64__
void __wipe(uintptr_t);
/**
* @fileoverview Cosmopolitan C Runtime, Second Edition
*/
void __wipe(uintptr_t) _Hide;
int main(int, char **, char **) __attribute__((__weak__));
typedef int init_f(int argc, char **argv, char **envp, unsigned long *auxv);
@ -75,12 +81,14 @@ textstartup void cosmo(long *sp, struct Syslib *m1) {
while (*auxv++) donothing;
// detect apple m1 environment
if ((__syslib = m1)) {
if (SupportsXnu() && (__syslib = m1)) {
hostos = _HOSTXNU;
magnums = syscon_xnu;
} else {
} else if (SupportsLinux()) {
hostos = _HOSTLINUX;
magnums = syscon_linux;
} else {
notpossible;
}
// setup system magic numbers
@ -88,6 +96,18 @@ textstartup void cosmo(long *sp, struct Syslib *m1) {
*mp = *magnums++;
}
// check system call abi compatibility
if (SupportsXnu() && __syslib && __syslib->version < SYSLIB_VERSION) {
sys_write(2, "need newer ape loader\n", 22);
_Exit(127);
}
// disable enosys trapping
if (IsBsd()) {
void *act[6] = {SIG_IGN};
sys_sigaction(SIGSYS, act, 0, 8, 0);
}
// needed by kisdangerous()
__oldstack = (intptr_t)sp;
__pid = sys_getpid().ax;
@ -97,7 +117,7 @@ textstartup void cosmo(long *sp, struct Syslib *m1) {
_mmi.p = _mmi.s;
__mmi_lock_obj._type = PTHREAD_MUTEX_RECURSIVE;
// record system-provided stack to memory manager
// record provided stack to memory manager
_mmi.i = 1;
_mmi.p->x = (uintptr_t)GetStackAddr() >> 16;
_mmi.p->y = (uintptr_t)(GetStackAddr() + (GetStackSize() - FRAMESIZE)) >> 16;
@ -106,6 +126,7 @@ textstartup void cosmo(long *sp, struct Syslib *m1) {
#if 0
#if IsAsan()
// TODO(jart): Figure out ASAN data model on AARCH64.
__asan_init(argc, argv, envp, auxv);
#endif
#endif

View file

@ -66,5 +66,5 @@ void __enable_threads(void) {
STRACE("__enable_threads()");
FixupLockNops();
#endif
__threaded = sys_gettid();
__threaded = __tls_enabled ? __get_tls()->tib_tid : sys_gettid();
}

View file

@ -190,7 +190,7 @@ textstartup void __enable_tls(void) {
tib->tib_strace = __strace;
tib->tib_ftrace = __ftrace;
tib->tib_pthread = (pthread_t)&_pthread_main;
if (IsLinux()) {
if (IsLinux() || IsXnuSilicon()) {
// gnu/systemd guarantees pid==tid for the main thread so we can
// avoid issuing a superfluous system call at startup in program
tid = __pid;

View file

@ -39,6 +39,7 @@ int sys_fork(void) {
#elif defined(__aarch64__)
if (IsLinux()) {
int flags = 17; // SIGCHLD
void *child_stack = 0;
void *parent_tidptr = 0;
@ -50,17 +51,17 @@ int sys_fork(void) {
register long r3 asm("x3") = (long)newtls;
register long r4 asm("x4") = (long)child_tidptr;
register int res_x0 asm("x0");
register int res_x1 asm("x1");
asm volatile("mov\tx8,%2\n\t"
"mov\tx16,%3\n\t"
asm volatile("mov\tx8,%1\n\t"
"svc\t0"
: "=r"(res_x0), "=r"(res_x1)
: "i"(220), "i"(2), "r"(r0), "r"(r1), "r"(r2), "r"(r3), "r"(r4)
: "=r"(res_x0)
: "i"(220), "r"(r0), "r"(r1), "r"(r2), "r"(r3), "r"(r4)
: "x8", "x16", "memory");
if (IsXnu() && res_x0 != -1) {
res_x0 &= res_x1 - 1;
}
return _sysret(res_x0);
} else if (__syslib) {
return _sysret(__syslib->fork());
} else {
return enosys();
}
#else

View file

@ -56,7 +56,7 @@ int _fork(uint32_t dwCreationFlags) {
__pid = dx;
if (__tls_enabled) {
tib = __get_tls();
tid = IsLinux() ? dx : sys_gettid();
tid = IsLinux() || IsXnuSilicon() ? dx : sys_gettid();
atomic_store_explicit(&tib->tib_tid, tid, memory_order_relaxed);
if ((pt = (struct PosixThread *)tib->tib_pthread)) {
atomic_store_explicit(&pt->ptid, tid, memory_order_relaxed);

View file

@ -1,6 +1,5 @@
#ifndef COSMOPOLITAN_LIBC_RUNTIME_SYSLIB_H_
#define COSMOPOLITAN_LIBC_RUNTIME_SYSLIB_H_
#include "libc/calls/struct/iovec.h"
#include "libc/calls/struct/sigaction.h"
#include "libc/calls/struct/sigset.h"
#include "libc/calls/struct/timespec.h"
@ -8,43 +7,41 @@
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
/**
* @fileoverview System DSO interfaces provided by APE loader.
*
* These functions are owned by the platform C library. Regardless of
* platform, POSIX APIs returning `long` will follow the Linux Kernel
* `-errno` convention, and hence should be wrapped with `_sysret()`.
*/
#define SYSLIB_MAGIC ('s' | 'l' << 8 | 'i' << 16 | 'b' << 24)
#define SYSLIB_VERSION 0
#define SYSLIB_VERSION 1
typedef uint64_t dispatch_time_t;
typedef uint64_t dispatch_semaphore_t;
struct Syslib {
int magic;
int version;
void (*exit)(int) wontreturn;
long (*fork)(void);
long (*read)(int, void *, size_t);
long (*pread)(int, void *, size_t, int64_t);
long (*readv)(int, const struct iovec *, int);
long (*write)(int, const void *, size_t);
long (*pwrite)(int, const void *, size_t, int64_t);
long (*writev)(int, const struct iovec *, int);
long (*openat)(int, const char *, int, ...);
long (*pipe)(int[2]);
long (*close)(int);
long (*clock_gettime)(int, struct timespec *);
long (*nanosleep)(const struct timespec *, struct timespec *);
long (*mmap)(void *, size_t, int, int, int, int64_t);
long (*sigaction)(int, const struct sigaction *restrict,
struct sigaction *restrict);
int (*pthread_jit_write_protect_supported_np)(void);
void (*pthread_jit_write_protect_np)(int);
void (*sys_icache_invalidate)(void *, size_t);
pthread_t (*pthread_self)(void);
int (*pthread_create)(pthread_t *, const pthread_attr_t *, void *(*)(void *),
void *);
int (*pthread_detach)(pthread_t);
int (*pthread_join)(pthread_t, void **);
void (*pthread_exit)(void *);
int (*pthread_kill)(pthread_t, int);
int (*pthread_sigmask)(int, const sigset_t *restrict, sigset_t *restrict);
int (*pthread_setname_np)(const char *);
int (*pthread_key_create)(pthread_key_t *, void (*)(void *));
int (*pthread_setspecific)(pthread_key_t, const void *);
void *(*pthread_getspecific)(pthread_key_t);
dispatch_semaphore_t (*dispatch_semaphore_create)(long);
long (*dispatch_semaphore_signal)(dispatch_semaphore_t);
long (*dispatch_semaphore_wait)(dispatch_semaphore_t, dispatch_time_t);
dispatch_time_t (*dispatch_walltime)(const struct timespec *, int64_t);
};
extern struct Syslib *__syslib;

File diff suppressed because it is too large Load diff

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon misc,ABORTED_COMMAND,11,11,0,0,0,0,0
.syscon misc,ABORTED_COMMAND,11,11,0,0,0,0,0,0

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon misc,ACCT_BYTEORDER,0,0,0,0,0,0,0
.syscon misc,ACCT_BYTEORDER,0,0,0,0,0,0,0,0

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon misc,ACCT_COMM,0x10,0x10,0,0,0,0,0
.syscon misc,ACCT_COMM,0x10,0x10,0,0,0,0,0,0

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon misc,ACK,4,4,4,4,4,4,0
.syscon misc,ACK,4,4,4,4,4,4,4,0

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon misc,ACORE,0,0,8,8,8,8,0
.syscon misc,ACORE,0,0,8,8,8,8,8,0

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon misc,AFORK,0,0,1,1,1,1,0
.syscon misc,AFORK,0,0,1,1,1,1,1,0

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon af,AF_ALG,38,38,0,0,0,0,0
.syscon af,AF_ALG,38,38,0,0,0,0,0,0

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon af,AF_APPLETALK,5,5,0x10,0x10,0x10,0x10,0x10
.syscon af,AF_APPLETALK,5,5,0x10,0x10,0x10,0x10,0x10,0x10

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon af,AF_ASH,18,18,0,0,0,0,0
.syscon af,AF_ASH,18,18,0,0,0,0,0,0

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon af,AF_ATMPVC,8,8,0,0,0,0,0
.syscon af,AF_ATMPVC,8,8,0,0,0,0,0,0

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon af,AF_ATMSVC,20,20,0,0,0,0,0
.syscon af,AF_ATMSVC,20,20,0,0,0,0,0,0

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon af,AF_AX25,3,3,0,0,0,0,0
.syscon af,AF_AX25,3,3,0,0,0,0,0,0

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon af,AF_BLUETOOTH,31,31,0,36,0x20,31,0
.syscon af,AF_BLUETOOTH,31,31,0,0,36,0x20,31,0

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon af,AF_BRIDGE,7,7,0,0,0,0,0
.syscon af,AF_BRIDGE,7,7,0,0,0,0,0,0

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon af,AF_CAIF,37,37,0,0,0,0,0
.syscon af,AF_CAIF,37,37,0,0,0,0,0,0

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon af,AF_CAN,29,29,0,0,0,35,0
.syscon af,AF_CAN,29,29,0,0,0,0,35,0

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon af,AF_ECONET,19,19,0,0,0,0,0
.syscon af,AF_ECONET,19,19,0,0,0,0,0,0

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon af,AF_FILE,1,1,0,0,0,0,0
.syscon af,AF_FILE,1,1,0,0,0,0,0,0

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon af,AF_IB,27,27,0,0,0,0,0
.syscon af,AF_IB,27,27,0,0,0,0,0,0

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon af,AF_IEEE802154,36,36,0,0,0,0,0
.syscon af,AF_IEEE802154,36,36,0,0,0,0,0,0

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon af,AF_INET,2,2,2,2,2,2,2
.syscon af,AF_INET,2,2,2,2,2,2,2,2

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon af,AF_INET6,10,10,30,28,24,24,23
.syscon af,AF_INET6,10,10,30,30,28,24,24,23

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon af,AF_IPX,4,4,23,23,23,23,6
.syscon af,AF_IPX,4,4,23,23,23,23,23,6

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon af,AF_IRDA,23,23,0,0,0,0,0
.syscon af,AF_IRDA,23,23,0,0,0,0,0,0

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon af,AF_ISDN,34,34,28,26,26,26,0
.syscon af,AF_ISDN,34,34,28,28,26,26,26,0

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon af,AF_IUCV,0x20,0x20,0,0,0,0,0
.syscon af,AF_IUCV,0x20,0x20,0,0,0,0,0,0

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon af,AF_KCM,41,41,0,0,0,0,0
.syscon af,AF_KCM,41,41,0,0,0,0,0,0

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon af,AF_KEY,15,15,0,0,30,0,0
.syscon af,AF_KEY,15,15,0,0,0,30,0,0

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon af,AF_LINK,0,0,18,18,18,18,0
.syscon af,AF_LINK,0,0,18,18,18,18,18,0

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon af,AF_LLC,26,26,0,0,0,0,0
.syscon af,AF_LLC,26,26,0,0,0,0,0,0

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon af,AF_LOCAL,1,1,1,1,1,1,1
.syscon af,AF_LOCAL,1,1,1,1,1,1,1,1

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon af,AF_MAX,42,42,40,42,36,37,35
.syscon af,AF_MAX,42,42,40,40,42,36,37,35

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon af,AF_MPLS,28,28,0,0,33,33,0
.syscon af,AF_MPLS,28,28,0,0,0,33,33,0

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon af,AF_NETBEUI,13,13,0,0,0,0,0
.syscon af,AF_NETBEUI,13,13,0,0,0,0,0,0

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon af,AF_NETLINK,16,16,0,0,0,0,0
.syscon af,AF_NETLINK,16,16,0,0,0,0,0,0

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon af,AF_NETROM,6,6,0,0,0,0,0
.syscon af,AF_NETROM,6,6,0,0,0,0,0,0

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon af,AF_NFC,39,39,0,0,0,0,0
.syscon af,AF_NFC,39,39,0,0,0,0,0,0

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon af,AF_PACKET,17,17,0,0,0,0,0
.syscon af,AF_PACKET,17,17,0,0,0,0,0,0

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon af,AF_PHONET,35,35,0,0,0,0,0
.syscon af,AF_PHONET,35,35,0,0,0,0,0,0

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon af,AF_PPPOX,24,24,0,0,0,0,0
.syscon af,AF_PPPOX,24,24,0,0,0,0,0,0

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon af,AF_RDS,21,21,0,0,0,0,0
.syscon af,AF_RDS,21,21,0,0,0,0,0,0

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon af,AF_ROSE,11,11,0,0,0,0,0
.syscon af,AF_ROSE,11,11,0,0,0,0,0,0

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon af,AF_ROUTE,16,16,17,17,17,34,0
.syscon af,AF_ROUTE,16,16,17,17,17,17,34,0

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon af,AF_RXRPC,33,33,0,0,0,0,0
.syscon af,AF_RXRPC,33,33,0,0,0,0,0,0

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon af,AF_SECURITY,14,14,0,0,0,0,0
.syscon af,AF_SECURITY,14,14,0,0,0,0,0,0

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon af,AF_SNA,22,22,11,11,11,11,11
.syscon af,AF_SNA,22,22,11,11,11,11,11,11

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon af,AF_TIPC,30,30,0,0,0,0,0
.syscon af,AF_TIPC,30,30,0,0,0,0,0,0

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon af,AF_UNIX,1,1,1,1,1,1,1
.syscon af,AF_UNIX,1,1,1,1,1,1,1,1

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon af,AF_UNSPEC,0,0,0,0,0,0,0
.syscon af,AF_UNSPEC,0,0,0,0,0,0,0,0

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon af,AF_VSOCK,40,40,0,0,0,0,0
.syscon af,AF_VSOCK,40,40,0,0,0,0,0,0

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon af,AF_WANPIPE,25,25,0,0,0,0,0
.syscon af,AF_WANPIPE,25,25,0,0,0,0,0,0

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon af,AF_X25,9,9,0,0,0,0,0
.syscon af,AF_X25,9,9,0,0,0,0,0,0

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon misc,AIO_ALLDONE,2,2,1,3,0,0,0
.syscon misc,AIO_ALLDONE,2,2,1,1,3,0,0,0

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon misc,AIO_CANCELED,0,0,2,1,0,0,0
.syscon misc,AIO_CANCELED,0,0,2,2,1,0,0,0

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon misc,AIO_NOTCANCELED,1,1,4,2,0,0,0
.syscon misc,AIO_NOTCANCELED,1,1,4,4,2,0,0,0

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon alg,ALG_SET_AEAD_ASSOCLEN,4,4,0,0,0,0,0
.syscon alg,ALG_SET_AEAD_ASSOCLEN,4,4,0,0,0,0,0,0

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon alg,ALG_SET_AEAD_AUTHSIZE,5,5,0,0,0,0,0
.syscon alg,ALG_SET_AEAD_AUTHSIZE,5,5,0,0,0,0,0,0

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon alg,ALG_SET_DRBG_ENTROPY,6,6,0,0,0,0,0
.syscon alg,ALG_SET_DRBG_ENTROPY,6,6,0,0,0,0,0,0

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon alg,ALG_SET_IV,2,2,0,0,0,0,0
.syscon alg,ALG_SET_IV,2,2,0,0,0,0,0,0

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon alg,ALG_SET_KEY,1,1,0,0,0,0,0
.syscon alg,ALG_SET_KEY,1,1,0,0,0,0,0,0

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon alg,ALG_SET_OP,3,3,0,0,0,0,0
.syscon alg,ALG_SET_OP,3,3,0,0,0,0,0,0

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon misc,AREGTYPE,0,0,0,0,0,0,0
.syscon misc,AREGTYPE,0,0,0,0,0,0,0,0

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon auxv,AT_BASE,7,7,7,7,0,7,0
.syscon auxv,AT_BASE,7,7,7,7,7,0,7,0

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon auxv,AT_BASE_PLATFORM,24,24,0,0,0,0,0
.syscon auxv,AT_BASE_PLATFORM,24,24,0,0,0,0,0,0

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon auxv,AT_CANARY,0,0,0,16,0,0,0
.syscon auxv,AT_CANARY,0,0,0,0,16,0,0,0

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon auxv,AT_CANARYLEN,0,0,0,17,0,0,0
.syscon auxv,AT_CANARYLEN,0,0,0,0,17,0,0,0

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon auxv,AT_CLKTCK,17,17,0,0,0,0,0
.syscon auxv,AT_CLKTCK,17,17,0,0,0,0,0,0

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon auxv,AT_DCACHEBSIZE,19,19,0,0,0,0,0
.syscon auxv,AT_DCACHEBSIZE,19,19,0,0,0,0,0,0

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon at,AT_EACCESS,0x0200,0x0200,0x10,0x0100,1,0x100,0
.syscon at,AT_EACCESS,0x0200,0x0200,0x10,0x10,0x0100,1,0x100,0

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon auxv,AT_EGID,14,14,14,0,0,2002,0
.syscon auxv,AT_EGID,14,14,14,14,0,0,2002,0

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon auxv,AT_EHDRFLAGS,0,0,0,24,0,0,0
.syscon auxv,AT_EHDRFLAGS,0,0,0,0,24,0,0,0

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon at,AT_EMPTY_PATH,0x1000,0x1000,0,0,0,0,0
.syscon at,AT_EMPTY_PATH,0x1000,0x1000,0,0,0,0,0,0

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon auxv,AT_ENTRY,9,9,9,9,0,9,0
.syscon auxv,AT_ENTRY,9,9,9,9,9,0,9,0

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon auxv,AT_EUID,12,12,12,0,0,2000,0
.syscon auxv,AT_EUID,12,12,12,12,0,0,2000,0

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon auxv,AT_EXECFD,2,2,0,2,0,2,0
.syscon auxv,AT_EXECFD,2,2,0,0,2,0,2,0

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