mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-01-31 03:27:39 +00:00
Remove some problematic APIs
In order to improve our chances of success building other open source projects we shouldn't define APIs that'll lead any ./configure script astray. For example: - brk() and sbrk() can break mac/windows support - syscall() is a superb way to break portability - arch_prctl() is the greatest of all horror shows
This commit is contained in:
parent
7512318a2a
commit
32682f0ce7
24 changed files with 37 additions and 919 deletions
|
@ -130,7 +130,6 @@ o/$(MODE)/ape/ape-no-modify-self.o: \
|
|||
libc/runtime/e820.internal.h \
|
||||
libc/runtime/mman.internal.h \
|
||||
libc/runtime/pc.internal.h \
|
||||
libc/runtime/symbolic.h \
|
||||
libc/sysv/consts/prot.h \
|
||||
ape/blink-aarch64.gz \
|
||||
ape/blink-darwin-arm64.gz \
|
||||
|
@ -160,7 +159,6 @@ o/$(MODE)/ape/ape-copy-self.o: \
|
|||
libc/runtime/e820.internal.h \
|
||||
libc/runtime/mman.internal.h \
|
||||
libc/runtime/pc.internal.h \
|
||||
libc/runtime/symbolic.h \
|
||||
libc/sysv/consts/prot.h \
|
||||
ape/blink-aarch64.gz \
|
||||
ape/blink-darwin-arm64.gz
|
||||
|
|
|
@ -68,13 +68,7 @@ COSMOPOLITAN_C_START_
|
|||
|
||||
typedef int sig_atomic_t;
|
||||
|
||||
bool fileexists(const char *);
|
||||
bool isdirectory(const char *);
|
||||
bool isexecutable(const char *);
|
||||
bool isregularfile(const char *);
|
||||
bool issymlink(const char *);
|
||||
bool32 isatty(int) nosideeffect;
|
||||
bool32 ischardev(int) nosideeffect;
|
||||
char *commandv(const char *, char *, size_t);
|
||||
char *get_current_dir_name(void) dontdiscard;
|
||||
char *getcwd(char *, size_t);
|
||||
|
@ -82,7 +76,6 @@ char *realpath(const char *, char *);
|
|||
char *replaceuser(const char *) dontdiscard;
|
||||
char *ttyname(int);
|
||||
int access(const char *, int) dontthrow;
|
||||
int arch_prctl();
|
||||
int chdir(const char *);
|
||||
int chmod(const char *, unsigned);
|
||||
int chown(const char *, unsigned, unsigned);
|
||||
|
@ -166,7 +159,6 @@ int reboot(int);
|
|||
int remove(const char *);
|
||||
int rename(const char *, const char *);
|
||||
int renameat(int, const char *, int, const char *);
|
||||
int renameat2(long, const char *, long, const char *, int);
|
||||
int rmdir(const char *);
|
||||
int sched_yield(void);
|
||||
int seccomp(unsigned, unsigned, void *);
|
||||
|
@ -214,11 +206,8 @@ int usleep(unsigned);
|
|||
int vfork(void) returnstwice;
|
||||
int wait(int *);
|
||||
int waitpid(int, int *, int);
|
||||
intptr_t syscall(int, ...);
|
||||
long ptrace(int, ...);
|
||||
ssize_t copy_file_range(int, long *, int, long *, size_t, unsigned);
|
||||
ssize_t copyfd(int, int64_t *, int, int64_t *, size_t, unsigned);
|
||||
ssize_t getfiledescriptorsize(int);
|
||||
ssize_t lseek(int, int64_t, int);
|
||||
ssize_t pread(int, void *, size_t, int64_t);
|
||||
ssize_t pwrite(int, const void *, size_t, int64_t);
|
||||
|
@ -235,6 +224,23 @@ unsigned getuid(void) libcesque;
|
|||
unsigned umask(unsigned);
|
||||
void sync(void);
|
||||
|
||||
#ifdef COSMO
|
||||
#define fileexists __fileexists
|
||||
#define isdirectory __isdirectory
|
||||
#define isexecutable __isexecutable
|
||||
#define isregularfile __isregularfile
|
||||
#define issymlink __issymlink
|
||||
#define ischardev __ischardev
|
||||
#define copyfd __copyfd
|
||||
bool fileexists(const char *);
|
||||
bool isdirectory(const char *);
|
||||
bool isexecutable(const char *);
|
||||
bool isregularfile(const char *);
|
||||
bool issymlink(const char *);
|
||||
bool32 ischardev(int) nosideeffect;
|
||||
ssize_t copyfd(int, int64_t *, int, int64_t *, size_t, unsigned);
|
||||
#endif
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_LIBC_CALLS_SYSCALLS_H_ */
|
||||
|
|
|
@ -1,90 +0,0 @@
|
|||
/*-*- 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/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/metalfile.internal.h"
|
||||
#include "libc/calls/struct/metastat.internal.h"
|
||||
#include "libc/calls/struct/stat.h"
|
||||
#include "libc/calls/syscall-sysv.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/intrin/weaken.h"
|
||||
#include "libc/limits.h"
|
||||
#include "libc/nt/enum/fileinfobyhandleclass.h"
|
||||
#include "libc/nt/files.h"
|
||||
#include "libc/nt/struct/filestandardinformation.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
#include "libc/zipos/zipos.internal.h"
|
||||
|
||||
/**
|
||||
* Determines size of open file.
|
||||
*
|
||||
* This function is equivalent to:
|
||||
*
|
||||
* struct stat st;
|
||||
* !fstat(fd, &st) ? st.st_size : -1
|
||||
*
|
||||
* Except faster on BSD/Windows and a much smaller link size.
|
||||
*
|
||||
* @return file byte length, or -1 w/ errno
|
||||
* @asyncsignalsafe
|
||||
*/
|
||||
ssize_t getfiledescriptorsize(int fd) {
|
||||
int e;
|
||||
ssize_t rc;
|
||||
union metastat st;
|
||||
struct NtFileStandardInformation info;
|
||||
e = errno;
|
||||
if (__isfdkind(fd, kFdZip)) {
|
||||
if (_weaken(__zipos_fstat)(
|
||||
(struct ZiposHandle *)(intptr_t)g_fds.p[fd].handle, &st.cosmo) !=
|
||||
-1) {
|
||||
rc = st.cosmo.st_size;
|
||||
} else {
|
||||
rc = -1;
|
||||
}
|
||||
} else if (IsMetal()) {
|
||||
if (fd < 0 || fd >= g_fds.n) {
|
||||
rc = ebadf();
|
||||
} else if (g_fds.p[fd].kind != kFdFile) {
|
||||
rc = eacces();
|
||||
} else {
|
||||
struct MetalFile *state = (struct MetalFile *)g_fds.p[fd].handle;
|
||||
rc = state->size;
|
||||
}
|
||||
} else if (!IsWindows()) {
|
||||
if (!__sys_fstat(fd, &st)) {
|
||||
rc = METASTAT(st, st_size);
|
||||
} else {
|
||||
rc = -1;
|
||||
}
|
||||
} else if (__isfdopen(fd)) {
|
||||
if (GetFileInformationByHandleEx(g_fds.p[fd].handle, kNtFileStandardInfo,
|
||||
&info, sizeof(info))) {
|
||||
rc = info.EndOfFile;
|
||||
} else {
|
||||
rc = ebadf();
|
||||
}
|
||||
} else {
|
||||
rc = ebadf();
|
||||
}
|
||||
STRACE("getfiledescriptorsize(%d) → %'zd% m", fd, rc);
|
||||
return rc;
|
||||
}
|
|
@ -21,7 +21,6 @@
|
|||
#include "libc/intrin/kprintf.h"
|
||||
#include "libc/intrin/weaken.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/runtime/brk.internal.h"
|
||||
#include "libc/runtime/memtrack.internal.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/runtime/winargs.internal.h"
|
||||
|
@ -29,11 +28,6 @@
|
|||
#define UNSHADOW(x) ((int64_t)(MAX(0, (x)-0x7fff8000)) << 3)
|
||||
#define FRAME(x) ((int)((x) >> 16))
|
||||
|
||||
forceinline pureconst bool IsBrkFrame(int x) {
|
||||
unsigned char *p = (unsigned char *)ADDR_32_TO_48(x);
|
||||
return _weaken(__brk) && p >= _end && p < _weaken(__brk)->p;
|
||||
}
|
||||
|
||||
static const char *GetFrameName(int x) {
|
||||
if (!x) {
|
||||
return "null";
|
||||
|
@ -47,8 +41,6 @@ static const char *GetFrameName(int x) {
|
|||
return "arena";
|
||||
} else if (IsStaticStackFrame(x)) {
|
||||
return "stack";
|
||||
} else if (IsBrkFrame(x)) {
|
||||
return "brk";
|
||||
} else if (IsGfdsFrame(x)) {
|
||||
return "g_fds";
|
||||
} else if (IsZiposFrame(x)) {
|
||||
|
|
|
@ -45,7 +45,6 @@
|
|||
#include "libc/nt/runtime.h"
|
||||
#include "libc/nt/thunk/msabi.h"
|
||||
#include "libc/nt/winsock.h"
|
||||
#include "libc/runtime/brk.internal.h"
|
||||
#include "libc/runtime/internal.h"
|
||||
#include "libc/runtime/memtrack.internal.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
|
|
|
@ -8,7 +8,6 @@
|
|||
* Reads scalar from memory, offset by segment.
|
||||
*
|
||||
* @return *(MEM) relative to segment
|
||||
* @see arch_prctl()
|
||||
* @see pushpop()
|
||||
*/
|
||||
#define fs(MEM) __peek("fs", MEM)
|
||||
|
|
|
@ -50,12 +50,12 @@ static struct timespec vflogf_ts;
|
|||
static void vflogf_onfail(FILE *f) {
|
||||
errno_t err;
|
||||
int64_t size;
|
||||
struct stat st;
|
||||
if (IsTiny()) return;
|
||||
err = ferror_unlocked(f);
|
||||
if (fileno_unlocked(f) != -1 &&
|
||||
(err == ENOSPC || err == EDQUOT || err == EFBIG) &&
|
||||
((size = getfiledescriptorsize(fileno_unlocked(f))) == -1 ||
|
||||
size > kNontrivialSize)) {
|
||||
(fstat(fileno_unlocked(f), &st) == -1 || st.st_size > kNontrivialSize)) {
|
||||
ftruncate(fileno_unlocked(f), 0);
|
||||
fseeko_unlocked(f, SEEK_SET, 0);
|
||||
f->beg = f->end = 0;
|
||||
|
|
|
@ -1,243 +0,0 @@
|
|||
/*-*- 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/calls.h"
|
||||
#include "libc/calls/syscall-sysv.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/intrin/asan.internal.h"
|
||||
#include "libc/intrin/asmflag.h"
|
||||
#include "libc/intrin/bits.h"
|
||||
#include "libc/intrin/describeflags.internal.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/nexgen32e/msr.internal.h"
|
||||
#include "libc/nexgen32e/x86feature.h"
|
||||
#include "libc/runtime/pc.internal.h"
|
||||
#include "libc/sysv/consts/sig.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
#ifdef __x86_64__
|
||||
|
||||
#define rdmsr(msr) \
|
||||
({ \
|
||||
uint32_t lo, hi; \
|
||||
asm volatile("rdmsr" : "=a"(lo), "=d"(hi) : "c"(msr)); \
|
||||
(uint64_t) hi << 32 | lo; \
|
||||
})
|
||||
|
||||
#define wrmsr(msr, val) \
|
||||
do { \
|
||||
uint64_t val_ = (val); \
|
||||
asm volatile("wrmsr" \
|
||||
: /* no outputs */ \
|
||||
: "c"(msr), "a"((uint32_t)val_), \
|
||||
"d"((uint32_t)(val_ >> 32))); \
|
||||
} while (0)
|
||||
|
||||
int sys_set_tls();
|
||||
|
||||
static int arch_prctl_msr(int code, int64_t addr) {
|
||||
switch (code) {
|
||||
case ARCH_SET_GS:
|
||||
wrmsr(MSR_IA32_GS_BASE, addr);
|
||||
return 0;
|
||||
case ARCH_SET_FS:
|
||||
wrmsr(MSR_IA32_FS_BASE, addr);
|
||||
return 0;
|
||||
case ARCH_GET_GS:
|
||||
*(int64_t *)addr = rdmsr(MSR_IA32_GS_BASE);
|
||||
return 0;
|
||||
case ARCH_GET_FS:
|
||||
*(int64_t *)addr = rdmsr(MSR_IA32_FS_BASE);
|
||||
return 0;
|
||||
default:
|
||||
return einval();
|
||||
}
|
||||
}
|
||||
|
||||
static int arch_prctl_freebsd(int code, int64_t addr) {
|
||||
switch (code) {
|
||||
case ARCH_GET_FS:
|
||||
// sysarch(AMD64_GET_FSBASE)
|
||||
return sys_arch_prctl(128, addr);
|
||||
case ARCH_SET_FS:
|
||||
// sysarch(AMD64_SET_FSBASE)
|
||||
return sys_arch_prctl(129, (intptr_t)&addr);
|
||||
case ARCH_GET_GS:
|
||||
// sysarch(AMD64_GET_GSBASE)
|
||||
return sys_arch_prctl(130, addr);
|
||||
case ARCH_SET_GS:
|
||||
// sysarch(AMD64_SET_GSBASE)
|
||||
return sys_arch_prctl(131, (intptr_t)&addr);
|
||||
default:
|
||||
return einval();
|
||||
}
|
||||
}
|
||||
|
||||
static int arch_prctl_netbsd(int code, int64_t addr) {
|
||||
switch (code) {
|
||||
case ARCH_GET_FS:
|
||||
// sysarch(X86_GET_FSBASE)
|
||||
return sys_arch_prctl(15, addr);
|
||||
case ARCH_SET_FS:
|
||||
// we use _lwp_setprivate() instead of sysarch(X86_SET_FSBASE)
|
||||
// because the latter has a bug where signal handlers cause it
|
||||
// to be clobbered. please note, this doesn't apply to %gs :-)
|
||||
return sys_set_tls(addr);
|
||||
case ARCH_GET_GS:
|
||||
// sysarch(X86_GET_GSBASE)
|
||||
return sys_arch_prctl(14, addr);
|
||||
case ARCH_SET_GS:
|
||||
// sysarch(X86_SET_GSBASE)
|
||||
return sys_arch_prctl(16, (intptr_t)&addr);
|
||||
default:
|
||||
return einval();
|
||||
}
|
||||
}
|
||||
|
||||
static int arch_prctl_xnu(int code, int64_t addr) {
|
||||
int e;
|
||||
switch (code) {
|
||||
case ARCH_SET_GS:
|
||||
// thread_fast_set_cthread_self has a weird ABI
|
||||
e = errno;
|
||||
sys_set_tls(addr);
|
||||
errno = e;
|
||||
return 0;
|
||||
case ARCH_GET_FS:
|
||||
case ARCH_SET_FS:
|
||||
case ARCH_GET_GS:
|
||||
return enosys();
|
||||
default:
|
||||
return einval();
|
||||
}
|
||||
}
|
||||
|
||||
static dontinline int arch_prctl_openbsd(int code, int64_t addr) {
|
||||
bool failed;
|
||||
int64_t rax;
|
||||
switch (code) {
|
||||
case ARCH_GET_FS:
|
||||
asm volatile(CFLAG_ASM("syscall")
|
||||
: CFLAG_CONSTRAINT(failed), "=a"(rax)
|
||||
: "1"(0x014a /* __get_tcb */)
|
||||
: "rcx", "rdx", "rdi", "rsi", "r8", "r9", "r10", "r11", "cc",
|
||||
"memory");
|
||||
if (failed) {
|
||||
errno = rax;
|
||||
return -1;
|
||||
}
|
||||
*(int64_t *)addr = rax;
|
||||
return 0;
|
||||
case ARCH_SET_FS:
|
||||
asm volatile(CFLAG_ASM("syscall")
|
||||
: CFLAG_CONSTRAINT(failed), "=a"(rax)
|
||||
: "1"(0x0149 /* __set_tcb */), "D"(addr)
|
||||
: "rcx", "rdx", "rsi", "r8", "r9", "r10", "r11", "cc",
|
||||
"memory");
|
||||
if (failed) {
|
||||
errno = rax;
|
||||
rax = -1;
|
||||
}
|
||||
return rax;
|
||||
case ARCH_GET_GS:
|
||||
case ARCH_SET_GS:
|
||||
return enosys();
|
||||
default:
|
||||
return einval();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes x86 segment registers.
|
||||
*
|
||||
* Support for segment registers is spotty across platforms. See the
|
||||
* table of tested combinations below.
|
||||
*
|
||||
* This wrapper has the same weird ABI as the Linux Kernel. The type
|
||||
* Cosmopolitan type signature of the prototype for this function is
|
||||
* variadic, so no value safety checking will be performed w/o asan.
|
||||
*
|
||||
* Cosmopolitan Libc initializes your process by default, to use the
|
||||
* segment register %fs, for thread-local storage. To safely disable
|
||||
* this TLS you need to either set `__tls_enabled` to 0, or you must
|
||||
* follow the same memory layout assumptions as your C library. When
|
||||
* TLS is disabled you can't use threads unless you call clone() and
|
||||
* that's not really a good idea since `errno` won't be thread-safe.
|
||||
*
|
||||
* Please note if you're only concerned about running on Linux, then
|
||||
* consider using Cosmopolitan's fsgsbase macros which don't need to
|
||||
* issue system calls to change %fs and %gs. See _have_fsgsbase() to
|
||||
* learn more.
|
||||
*
|
||||
* @param code may be
|
||||
* - `ARCH_SET_FS` works on Linux, FreeBSD, NetBSD, OpenBSD, Metal
|
||||
* - `ARCH_GET_FS` works on Linux, FreeBSD, NetBSD, OpenBSD, Metal
|
||||
* - `ARCH_SET_GS` works on Linux, FreeBSD, NetBSD, XNU, Metal
|
||||
* - `ARCH_GET_GS` works on Linux, FreeBSD, NetBSD, Metal
|
||||
* @param addr is treated as `intptr_t` when setting a register, and
|
||||
* is an output parameter (i.e. `intptr_t *`) when reading one
|
||||
* @raise ENOSYS if operating system didn't support changing `code`
|
||||
* @raise EINVAL if `code` wasn't valid
|
||||
* @raise EFAULT if `ARCH_SET_FS` or `ARCH_SET_GS` was used and memory
|
||||
* pointed to by `addr` was invalid
|
||||
* @see _have_fsgsbase()
|
||||
*/
|
||||
int arch_prctl(int code, int64_t addr) {
|
||||
int rc;
|
||||
if (IsAsan() && //
|
||||
(code == ARCH_GET_FS || //
|
||||
code == ARCH_GET_GS) && //
|
||||
!__asan_is_valid((int64_t *)addr, 8)) {
|
||||
rc = efault();
|
||||
} else {
|
||||
switch (__hostos) {
|
||||
case _HOSTMETAL:
|
||||
rc = arch_prctl_msr(code, addr);
|
||||
break;
|
||||
case _HOSTFREEBSD:
|
||||
rc = arch_prctl_freebsd(code, addr);
|
||||
break;
|
||||
case _HOSTNETBSD:
|
||||
rc = arch_prctl_netbsd(code, addr);
|
||||
break;
|
||||
case _HOSTOPENBSD:
|
||||
rc = arch_prctl_openbsd(code, addr);
|
||||
break;
|
||||
case _HOSTLINUX:
|
||||
rc = sys_arch_prctl(code, addr);
|
||||
break;
|
||||
case _HOSTXNU:
|
||||
rc = arch_prctl_xnu(code, addr);
|
||||
break;
|
||||
default:
|
||||
rc = enosys();
|
||||
break;
|
||||
}
|
||||
}
|
||||
#ifdef SYSDEBUG
|
||||
if (!rc && (code == ARCH_GET_FS || code == ARCH_GET_GS)) {
|
||||
STRACE("arch_prctl(%s, [%p]) → %d% m", DescribeArchPrctlCode(code),
|
||||
*(int64_t *)addr, rc);
|
||||
} else {
|
||||
STRACE("arch_prctl(%s, %p) → %d% m", DescribeArchPrctlCode(code), addr, rc);
|
||||
}
|
||||
#endif
|
||||
return rc;
|
||||
}
|
||||
|
||||
#endif /* __x86_64__ */
|
|
@ -1,186 +0,0 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2021 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/assert.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/syscall-sysv.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/intrin/directmap.internal.h"
|
||||
#include "libc/intrin/nopl.internal.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/runtime/brk.internal.h"
|
||||
#include "libc/runtime/memtrack.internal.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/sysv/consts/map.h"
|
||||
#include "libc/sysv/consts/prot.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
#include "libc/thread/thread.h"
|
||||
#include "libc/thread/tls.h"
|
||||
|
||||
struct Brk __brk;
|
||||
|
||||
static bool OverlapsMmappedMemory(unsigned char *p, size_t n) {
|
||||
int a, b, i;
|
||||
_unassert(n);
|
||||
a = (intptr_t)p >> 16;
|
||||
b = (intptr_t)(p + n - 1) >> 16;
|
||||
i = FindMemoryInterval(&_mmi, a);
|
||||
if (i < _mmi.i) {
|
||||
if (a <= _mmi.p[i].x && _mmi.p[i].x <= b) return true;
|
||||
if (a <= _mmi.p[i].y && _mmi.p[i].y <= b) return true;
|
||||
if (_mmi.p[i].x <= a && b <= _mmi.p[i].y) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static unsigned char *brk_unlocked(unsigned char *p) {
|
||||
int rc;
|
||||
struct DirectMap dm;
|
||||
_unassert(!((intptr_t)__brk.p & (PAGESIZE - 1)));
|
||||
if (p >= __brk.p) {
|
||||
p = (unsigned char *)ROUNDUP((intptr_t)p, PAGESIZE);
|
||||
} else {
|
||||
p = (unsigned char *)ROUNDDOWN((intptr_t)p, PAGESIZE);
|
||||
}
|
||||
if (IsWindows()) {
|
||||
rc = enosys();
|
||||
} else if (p < _end) {
|
||||
rc = einval();
|
||||
} else if (p > __brk.p) {
|
||||
if (!OverlapsMmappedMemory(__brk.p, p - __brk.p)) {
|
||||
// we always polyfill this system call because
|
||||
// 1. Linux has brk() but its behavior is poorly documented
|
||||
// 2. FreeBSD has sbrk(int):int but it's foreseeable it could go away
|
||||
// 3. XNU/OpenBSD/NetBSD have all deleted this interface in the kernel
|
||||
dm = sys_mmap(__brk.p, p - __brk.p, PROT_READ | PROT_WRITE,
|
||||
MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, 0);
|
||||
rc = (int)(intptr_t)dm.addr; // safe b/c __brk.p is page-aligned
|
||||
} else {
|
||||
rc = eexist();
|
||||
}
|
||||
} else if (p < __brk.p) {
|
||||
rc = sys_munmap(p, __brk.p - p);
|
||||
} else {
|
||||
rc = 0;
|
||||
}
|
||||
if (rc != -1) {
|
||||
__brk.p = p;
|
||||
return 0;
|
||||
} else {
|
||||
return (unsigned char *)-1;
|
||||
}
|
||||
}
|
||||
|
||||
void brk_lock(void) {
|
||||
pthread_mutex_lock(&__brk.m);
|
||||
}
|
||||
|
||||
void brk_unlock(void) {
|
||||
pthread_mutex_unlock(&__brk.m);
|
||||
}
|
||||
|
||||
void brk_funlock(void) {
|
||||
pthread_mutex_init(&__brk.m, 0);
|
||||
}
|
||||
|
||||
__attribute__((__constructor__)) static void brk_init(void) {
|
||||
brk_funlock();
|
||||
pthread_atfork(brk_lock, brk_unlock, brk_funlock);
|
||||
}
|
||||
|
||||
#ifdef _NOPL0
|
||||
#define brk_lock() _NOPL0("__threadcalls", brk_lock)
|
||||
#define brk_unlock() _NOPL0("__threadcalls", brk_unlock)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Sets end of data section.
|
||||
*
|
||||
* Your program break starts right after end of `.bss` as defined
|
||||
* by the external linker-defined variable `end`. Setting it to a
|
||||
* higher address will allocate more memory. After using this you
|
||||
* may dealocate memory by specifying it back to a lower address.
|
||||
*
|
||||
* The only virtue of brk(), and sbrk(), aside from compatibility
|
||||
* with legacy software, is it's tinier than mmap() because since
|
||||
* this API only supports Unix, we don't bother doing the complex
|
||||
* memory interval tracking that mmap() does.
|
||||
*
|
||||
* @param neu is the new end address of data segment, which shall
|
||||
* be rounded automatically to a 4096-byte granularity
|
||||
* @return 0 on success, or -1 w/ errno
|
||||
* @raise EINVAL if `neu` is less than the `end` of `.bss`
|
||||
* @raise EEXIST if expanded break would overlap existing mmap() memory
|
||||
* @raise ENOMEM if `RLIMIT_DATA` / `RLIMIT_AS` / `RLIMIT_RSS` is exceeded
|
||||
* @raise ENOSYS on Windows because WIN32 puts random stuff after your break
|
||||
* @threadsafe
|
||||
*/
|
||||
int brk(void *neu) {
|
||||
unsigned char *rc;
|
||||
brk_lock();
|
||||
if (!__brk.p) __brk.p = _end;
|
||||
rc = brk_unlocked(neu);
|
||||
brk_unlock();
|
||||
STRACE("brk(%p) → %d% m", neu, rc);
|
||||
return (int)(intptr_t)rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adjusts end of data section.
|
||||
*
|
||||
* This shrinks or increases the program break by delta bytes. On
|
||||
* success, the previous program break is returned. It's possible
|
||||
* to pass 0 to this function to obtain the current program break
|
||||
* which is initially set to the linker-defined external variable
|
||||
* `end` which is the end of the `.bss` segment. Your allocations
|
||||
* are rounded automatically to a 4096-byte granularity.
|
||||
*
|
||||
* The only virtue of sbrk(), and brk(), aside from compatibility
|
||||
* with legacy software, is it's tinier than mmap() because since
|
||||
* this API only supports Unix, we don't bother doing the complex
|
||||
* memory interval tracking that mmap() does.
|
||||
*
|
||||
* @param delta is the number of bytes to allocate (or free if negative)
|
||||
* noting that your delta may be tuned to a number further from zero
|
||||
* to accommodate the page size granularity of this allocator
|
||||
* @return previous break on success, or `(void *)-1` w/ errno
|
||||
* @raise EINVAL if new break would be less than the `end` of `.bss`
|
||||
* @raise EEXIST if expanded break would overlap existing mmap() memory
|
||||
* @raise EOVERFLOW if `delta` added to break overflows the address space
|
||||
* @raise ENOMEM if `RLIMIT_DATA` / `RLIMIT_AS` / `RLIMIT_RSS` is exceeded
|
||||
* @raise ENOSYS on Windows because WIN32 puts random stuff after your break
|
||||
* @threadsafe
|
||||
*/
|
||||
void *sbrk(intptr_t delta) {
|
||||
intptr_t neu;
|
||||
unsigned char *rc, *old;
|
||||
brk_lock();
|
||||
if (!__brk.p) __brk.p = _end;
|
||||
old = __brk.p;
|
||||
if (!__builtin_add_overflow((intptr_t)__brk.p, delta, &neu) &&
|
||||
IsLegalPointer((unsigned char *)neu)) {
|
||||
rc = brk_unlocked((unsigned char *)neu);
|
||||
if (!rc) rc = old;
|
||||
} else {
|
||||
rc = (void *)eoverflow();
|
||||
}
|
||||
brk_unlock();
|
||||
STRACE("sbrk(%'ld) → %p% m", delta, rc);
|
||||
return rc;
|
||||
}
|
|
@ -1,16 +0,0 @@
|
|||
#ifndef COSMOPOLITAN_LIBC_RUNTIME_BRK_INTERNAL_H_
|
||||
#define COSMOPOLITAN_LIBC_RUNTIME_BRK_INTERNAL_H_
|
||||
#include "libc/thread/thread.h"
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
struct Brk {
|
||||
unsigned char *p;
|
||||
pthread_mutex_t m;
|
||||
};
|
||||
|
||||
extern struct Brk __brk;
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_LIBC_RUNTIME_BRK_INTERNAL_H_ */
|
|
@ -31,7 +31,7 @@
|
|||
_Hide int MapFileRead(const char *filename, struct MappedFile *mf) {
|
||||
mf->addr = MAP_FAILED;
|
||||
if ((mf->fd = open(filename, O_RDONLY)) != -1 &&
|
||||
(mf->size = getfiledescriptorsize(mf->fd)) < INT_MAX &&
|
||||
(mf->size = lseek(mf->fd, 0, SEEK_END)) < INT_MAX &&
|
||||
(mf->addr = mf->size ? mmap(NULL, mf->size, PROT_READ,
|
||||
MAP_PRIVATE | MAP_POPULATE, mf->fd, 0)
|
||||
: NULL) != MAP_FAILED) {
|
||||
|
|
|
@ -78,8 +78,7 @@ const char *FindDebugBinary(void) {
|
|||
if ((n > 4 && READ32LE(p + n - 4) == READ32LE(".dbg")) ||
|
||||
IsMyDebugBinary(p)) {
|
||||
res = p;
|
||||
} else if (n > 4 && READ32LE(p + n - 4) == READ32LE(".com") &&
|
||||
n + 4 < ARRAYLEN(buf)) {
|
||||
} else if (n + 4 < ARRAYLEN(buf)) {
|
||||
mempcpy(mempcpy(buf, p, n), ".dbg", 5);
|
||||
if (IsMyDebugBinary(buf)) {
|
||||
res = buf;
|
||||
|
|
|
@ -1,208 +0,0 @@
|
|||
/*-*- 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/sysv/consts/mremap.h"
|
||||
#include "libc/assert.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/intrin/asan.internal.h"
|
||||
#include "libc/intrin/describeflags.internal.h"
|
||||
#include "libc/intrin/directmap.internal.h"
|
||||
#include "libc/intrin/likely.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/intrin/weaken.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/nt/runtime.h"
|
||||
#include "libc/runtime/memtrack.internal.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/sysv/consts/map.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
#define IP(X) (intptr_t)(X)
|
||||
#define VIP(X) (void *)IP(X)
|
||||
#define ALIGNED(p) (!(IP(p) & (FRAMESIZE - 1)))
|
||||
#define SHADE(x) (((intptr_t)(x) >> 3) + 0x7fff8000)
|
||||
#define FRAME(x) ((int)((intptr_t)(x) >> 16))
|
||||
|
||||
static size_t GetMapSize(size_t i, size_t *j) {
|
||||
size_t n;
|
||||
n = (size_t)(_mmi.p[i].y - _mmi.p[i].x + 1) << 16;
|
||||
while (i + 1 < _mmi.i) {
|
||||
if (_mmi.p[i + 1].x != _mmi.p[i].y + 1) break;
|
||||
++i;
|
||||
n += (size_t)(_mmi.p[i].y - _mmi.p[i].x + 1) << 16;
|
||||
}
|
||||
*j = i;
|
||||
return n;
|
||||
}
|
||||
|
||||
static bool MustMoveMap(intptr_t y, size_t j) {
|
||||
return ADDR_32_TO_48(_mmi.p[j].y) + FRAMESIZE > y ||
|
||||
(j + 1 < _mmi.i && ADDR_32_TO_48(_mmi.p[j + 1].x) < y);
|
||||
}
|
||||
|
||||
/**
|
||||
* Extends and/or relocates memory pages.
|
||||
*
|
||||
* @param p is old address
|
||||
* @param n is old size
|
||||
* @param m is new size
|
||||
* @param f should have MREMAP_MAYMOVE and may have MAP_FIXED
|
||||
* @param q is new address
|
||||
*/
|
||||
void *mremap(void *p, size_t n, size_t m, int f, ... /* void *q */) {
|
||||
enosys();
|
||||
return MAP_FAILED;
|
||||
|
||||
#if 0
|
||||
va_list va;
|
||||
void *res, *q;
|
||||
if (f & MREMAP_FIXED) {
|
||||
va_start(va, f);
|
||||
q = va_arg(va, void *);
|
||||
va_end(va);
|
||||
} else {
|
||||
q = 0;
|
||||
}
|
||||
enosys();
|
||||
res = MAP_FAILED;
|
||||
STRACE("mremap(%p, %'zu, %'zu, %s, %p) → %p% m", p, n, m,
|
||||
DescribeRemapFlags(f), q, res);
|
||||
return res;
|
||||
|
||||
// TODO(jart): perhaps some day?
|
||||
// probably not a big perf gain at this point :|
|
||||
size_t i, j, k;
|
||||
struct DirectMap dm;
|
||||
int a, b, prot, flags;
|
||||
_unassert(!__vforked);
|
||||
if (UNLIKELY(!m)) {
|
||||
STRACE("m=0");
|
||||
return VIP(einval());
|
||||
} else if (UNLIKELY(!n)) {
|
||||
STRACE("n=0");
|
||||
return VIP(eopnotsupp());
|
||||
} else if (UNLIKELY(!ALIGNED(n))) {
|
||||
STRACE("n align");
|
||||
return VIP(eopnotsupp());
|
||||
} else if (UNLIKELY(!ALIGNED(m))) {
|
||||
STRACE("n align");
|
||||
return VIP(eopnotsupp());
|
||||
} else if (UNLIKELY(!ALIGNED(p))) {
|
||||
STRACE("64kb align");
|
||||
return VIP(einval());
|
||||
} else if (UNLIKELY(!IsLegalSize(n))) {
|
||||
STRACE("n too big");
|
||||
return VIP(enomem());
|
||||
} else if (UNLIKELY(!IsLegalSize(m))) {
|
||||
STRACE("m too big");
|
||||
return VIP(enomem());
|
||||
} else if (f & ~(MREMAP_MAYMOVE | MREMAP_FIXED)) {
|
||||
STRACE("bad flag");
|
||||
return VIP(einval());
|
||||
} else if (!IsMemtracked(FRAME(p), FRAME((intptr_t)p + (n - 1)))) {
|
||||
STRACE("interval not tracked");
|
||||
return VIP(efault());
|
||||
}
|
||||
STRACE("mremap(%p, %'zu, %'zu, %#b)", p, n, m, f);
|
||||
i = FindMemoryInterval(&_mmi, FRAME(p));
|
||||
if (i >= _mmi.i) return VIP(efault());
|
||||
flags = _mmi.p[i].flags;
|
||||
if (!(flags & MAP_ANONYMOUS)) {
|
||||
return VIP(eopnotsupp()); /* TODO */
|
||||
}
|
||||
if (f & MREMAP_FIXED) {
|
||||
if (!ALIGNED(q)) return VIP(einval());
|
||||
return VIP(eopnotsupp()); /* TODO */
|
||||
}
|
||||
prot = _mmi.p[i].prot;
|
||||
for (k = i + 1; k <= j; ++k) {
|
||||
prot |= _mmi.p[k].prot;
|
||||
if (_mmi.p[k].flags != flags) {
|
||||
return VIP(enomem());
|
||||
}
|
||||
}
|
||||
if (m == n) {
|
||||
return p;
|
||||
} else if (m < n) {
|
||||
if (munmap((char *)p + n, m - n) != -1) {
|
||||
return p;
|
||||
} else {
|
||||
return MAP_FAILED;
|
||||
}
|
||||
} else if (!MustMoveMap(j, (intptr_t)p + n)) {
|
||||
dm = sys_mmap((char *)p + n, m - n, prot, flags | MAP_FIXED, -1, 0);
|
||||
if (dm.addr == MAP_FAILED) return 0;
|
||||
if (TrackMemoryInterval(&_mmi, ((uintptr_t)p + n) >> 16,
|
||||
((uintptr_t)p + m - FRAMESIZE) >> 16, dm.maphandle,
|
||||
prot, flags, false, false, 0, m - n) != -1) {
|
||||
if (_weaken(__asan_map_shadow)) {
|
||||
_weaken(__asan_map_shadow)((uintptr_t)dm.addr, m - n);
|
||||
}
|
||||
return p;
|
||||
} else {
|
||||
abort();
|
||||
}
|
||||
} else if (!(f & MREMAP_MAYMOVE)) {
|
||||
return VIP(enomem());
|
||||
} else if (IsLinux()) {
|
||||
a = (uint32_t)(kAutomapStart >> 16);
|
||||
i = FindMemoryInterval(&_mmi, a);
|
||||
if (i < _mmi.i) {
|
||||
for (; i + 1 < _mmi.i; ++i) {
|
||||
if (((size_t)(_mmi.p[i + 1].x - _mmi.p[i].y - 1) << 16) >= m) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (__builtin_add_overflow(_mmi.p[i].y, 1, &a)) {
|
||||
return VIP(enomem());
|
||||
}
|
||||
}
|
||||
if (__builtin_add_overflow(a, (int)((m >> 16) - 1), &b)) {
|
||||
return VIP(enomem());
|
||||
}
|
||||
q = sys_mremap((void *)p, n, m, MREMAP_MAYMOVE | MREMAP_FIXED,
|
||||
(void *)ADDR_32_TO_48(a));
|
||||
KERNTRACE("sys_mremap(%p, %'zu, %'zu, %#b, %p) → %p", p, n, m,
|
||||
MREMAP_MAYMOVE | MREMAP_FIXED, ADDR_32_TO_48(a), q);
|
||||
if (q == MAP_FAILED) return 0;
|
||||
if (ReleaseMemoryIntervals(&_mmi, (uintptr_t)p >> 16,
|
||||
((uintptr_t)p + n - FRAMESIZE) >> 16, 0) != -1 &&
|
||||
TrackMemoryInterval(&_mmi, a, b, -1, prot, flags, false, false, 0, m) !=
|
||||
-1) {
|
||||
if (_weaken(__asan_poison)) {
|
||||
if (!OverlapsShadowSpace(p, n)) {
|
||||
_weaken(__asan_poison)((intptr_t)p, n, kAsanUnmapped);
|
||||
}
|
||||
if (!OverlapsShadowSpace(q, m)) {
|
||||
_weaken(__asan_map_shadow)((intptr_t)q, m);
|
||||
}
|
||||
}
|
||||
return (void *)ADDR_32_TO_48(a);
|
||||
} else {
|
||||
abort();
|
||||
}
|
||||
} else if ((q = mmap(0, m, prot, flags, -1, 0)) != MAP_FAILED) {
|
||||
memcpy(q, p, n);
|
||||
munmap(p, n);
|
||||
return q;
|
||||
} else {
|
||||
return q;
|
||||
}
|
||||
#endif
|
||||
}
|
|
@ -51,7 +51,7 @@ static struct SymbolTable *OpenSymbolTableImpl(const char *filename) {
|
|||
ptrdiff_t names_offset, name_base_offset, stp_offset;
|
||||
map = MAP_FAILED;
|
||||
if ((fd = open(filename, O_RDONLY)) == -1) return 0;
|
||||
if ((filesize = getfiledescriptorsize(fd)) == -1) goto SystemError;
|
||||
if ((filesize = lseek(fd, 0, SEEK_END)) == -1) goto SystemError;
|
||||
if (filesize > INT_MAX) goto RaiseE2big;
|
||||
if (filesize < 64) goto RaiseEnoexec;
|
||||
elf = map = mmap(0, filesize, PROT_READ, MAP_PRIVATE, fd, 0);
|
||||
|
|
|
@ -76,14 +76,11 @@ int unsetenv(const char *);
|
|||
int clearenv(void);
|
||||
void fpreset(void);
|
||||
void *mmap(void *, uint64_t, int32_t, int32_t, int32_t, int64_t);
|
||||
void *mremap(void *, size_t, size_t, int, ...);
|
||||
int munmap(void *, uint64_t);
|
||||
int mprotect(void *, uint64_t, int);
|
||||
int msync(void *, size_t, int);
|
||||
int mlock(const void *, size_t);
|
||||
int munlock(const void *, size_t);
|
||||
void *sbrk(intptr_t);
|
||||
int brk(void *);
|
||||
long gethostid(void);
|
||||
int sethostid(long);
|
||||
char *getlogin(void);
|
||||
|
|
|
@ -29,7 +29,9 @@
|
|||
*/
|
||||
char *setlocale(int category, const char *locale) {
|
||||
if (!locale || (*locale == '\0')) return "C";
|
||||
if (!strcmp(locale, "C") || !strcmp(locale, "POSIX")) {
|
||||
if (!strcmp(locale, "C") || //
|
||||
!strcmp(locale, "POSIX") || //
|
||||
!strcmp(locale, "C.UTF-8")) {
|
||||
return locale;
|
||||
} else {
|
||||
return NULL;
|
||||
|
|
|
@ -32,9 +32,12 @@ struct lconv {
|
|||
|
||||
int wcwidth(wchar_t) pureconst;
|
||||
int wcswidth(const wchar_t *, size_t) strlenesque;
|
||||
int wcsnwidth(const wchar_t *, size_t, size_t) strlenesque;
|
||||
struct lconv *localeconv(void);
|
||||
|
||||
#ifdef COSMO
|
||||
int wcsnwidth(const wchar_t *, size_t, size_t) strlenesque;
|
||||
#endif
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_LIBC_STR_UNICODE_H_ */
|
||||
|
|
|
@ -38,7 +38,7 @@ void *xslurp(const char *path, size_t *opt_out_size) {
|
|||
ssize_t rc, size;
|
||||
res = NULL;
|
||||
if ((fd = open(path, O_RDONLY)) != -1) {
|
||||
if ((size = getfiledescriptorsize(fd)) != -1 &&
|
||||
if ((size = lseek(fd, 0, SEEK_END)) != -1 &&
|
||||
(res = memalign(PAGESIZE, size + 1))) {
|
||||
if (size > 2 * 1024 * 1024) {
|
||||
fadvise(fd, 0, size, MADV_SEQUENTIAL);
|
||||
|
@ -47,7 +47,7 @@ void *xslurp(const char *path, size_t *opt_out_size) {
|
|||
TryAgain:
|
||||
if ((rc = pread(fd, res + i, size - i, i)) != -1) {
|
||||
if (!(got = rc)) {
|
||||
if (getfiledescriptorsize(fd) == -1) {
|
||||
if (lseek(fd, 0, SEEK_CUR) == -1) {
|
||||
abort(); // TODO(jart): what is this
|
||||
}
|
||||
}
|
||||
|
|
|
@ -81,7 +81,7 @@ struct Zipos *__zipos_get(void) {
|
|||
fd = open(progpath, O_RDONLY);
|
||||
}
|
||||
if (fd != -1) {
|
||||
if ((size = getfiledescriptorsize(fd)) != -1ul &&
|
||||
if ((size = lseek(fd, 0, SEEK_END)) != -1 &&
|
||||
(map = mmap(0, size, PROT_READ, MAP_SHARED, fd, 0)) != MAP_FAILED) {
|
||||
if ((base = FindEmbeddedApe(map, size))) {
|
||||
size -= base - map;
|
||||
|
|
|
@ -73,7 +73,6 @@ o/$(MODE)/test/libc/mem/prog/sock.o: \
|
|||
libc/sock/sock.h \
|
||||
libc/intrin/bswap.h \
|
||||
libc/sysv/consts/af.h \
|
||||
libc/runtime/symbolic.h \
|
||||
libc/sysv/consts/sock.h
|
||||
|
||||
################################################################################
|
||||
|
|
|
@ -1,131 +0,0 @@
|
|||
/*-*- 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/calls.h"
|
||||
#include "libc/calls/struct/sigaction.h"
|
||||
#include "libc/calls/syscall-sysv.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/intrin/fsgsbase.h"
|
||||
#include "libc/intrin/kprintf.h"
|
||||
#include "libc/intrin/segmentation.h"
|
||||
#include "libc/nt/version.h"
|
||||
#include "libc/sysv/consts/sa.h"
|
||||
#include "libc/sysv/consts/sig.h"
|
||||
#include "libc/testlib/testlib.h"
|
||||
#include "libc/thread/tls.h"
|
||||
#ifdef __x86_64__
|
||||
|
||||
void SetUpOnce(void) {
|
||||
__tls_enabled_set(false);
|
||||
ASSERT_SYS(0, 0, pledge("stdio rpath", 0));
|
||||
}
|
||||
|
||||
void OnTrap(int sig, struct siginfo *si, void *vctx) {
|
||||
struct ucontext *ctx = vctx;
|
||||
}
|
||||
|
||||
void TriggerSignal(void) {
|
||||
struct sigaction old;
|
||||
struct sigaction sig = {.sa_sigaction = OnTrap, .sa_flags = SA_SIGINFO};
|
||||
sched_yield();
|
||||
sigaction(SIGTRAP, &sig, &old);
|
||||
asm("int3");
|
||||
sigaction(SIGTRAP, &old, 0);
|
||||
sched_yield();
|
||||
}
|
||||
|
||||
TEST(arch_prctl, fs) {
|
||||
if (IsLinux() || IsFreebsd() || IsNetbsd() || IsOpenbsd()) {
|
||||
uint64_t n, x;
|
||||
x = 0xdeadbeef;
|
||||
arch_prctl(ARCH_SET_FS, &x);
|
||||
ASSERT_NE(-1, arch_prctl(ARCH_GET_FS, (intptr_t)&n));
|
||||
ASSERT_EQ((intptr_t)&x, n);
|
||||
ASSERT_EQ(0xdeadbeef, fs((int64_t *)0));
|
||||
TriggerSignal();
|
||||
ASSERT_EQ(0xdeadbeef, fs((int64_t *)0));
|
||||
}
|
||||
}
|
||||
|
||||
TEST(arch_prctl, pointerRebasingFs) {
|
||||
if (IsLinux() || IsFreebsd() || IsOpenbsd() || IsNetbsd()) {
|
||||
unsigned long s[] = {0x0706050403020100, 0x0f0e0d0c0b0a0908};
|
||||
ASSERT_EQ(0x0706050403020100, s[0]);
|
||||
ASSERT_EQ(0, arch_prctl(ARCH_SET_FS, 1));
|
||||
ASSERT_EQ(0x0807060504030201, fs(&s[0]));
|
||||
ASSERT_EQ(0, arch_prctl(ARCH_SET_FS, 2));
|
||||
ASSERT_EQ(0x0908070605040302, fs(&s[0]));
|
||||
intptr_t fs;
|
||||
ASSERT_EQ(0, arch_prctl(ARCH_GET_FS, &fs));
|
||||
ASSERT_EQ(2, fs);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(arch_prctl, gs) {
|
||||
if (IsLinux() || IsFreebsd() || IsNetbsd() || IsXnu()) {
|
||||
uint64_t n, x;
|
||||
x = 0xdeadbeef;
|
||||
arch_prctl(ARCH_SET_GS, &x);
|
||||
if (!IsXnu()) {
|
||||
ASSERT_NE(-1, arch_prctl(ARCH_GET_GS, (intptr_t)&n));
|
||||
ASSERT_EQ((intptr_t)&x, n);
|
||||
}
|
||||
ASSERT_EQ(0xdeadbeef, gs((int64_t *)0));
|
||||
TriggerSignal();
|
||||
ASSERT_EQ(0xdeadbeef, gs((int64_t *)0));
|
||||
}
|
||||
}
|
||||
|
||||
TEST(arch_prctl, pointerRebasing) {
|
||||
if (IsLinux() || IsFreebsd() || IsNetbsd() || IsXnu()) {
|
||||
unsigned long s[] = {0x0706050403020100, 0x0f0e0d0c0b0a0908};
|
||||
ASSERT_EQ(0x0706050403020100, s[0]);
|
||||
ASSERT_EQ(0, arch_prctl(ARCH_SET_GS, 1));
|
||||
ASSERT_EQ(0x0807060504030201, gs(&s[0]));
|
||||
ASSERT_EQ(0, arch_prctl(ARCH_SET_GS, 2));
|
||||
ASSERT_EQ(0x0908070605040302, gs(&s[0]));
|
||||
if (!IsXnu()) {
|
||||
intptr_t gs;
|
||||
ASSERT_EQ(0, arch_prctl(ARCH_GET_GS, &gs));
|
||||
ASSERT_EQ(2, gs);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(fsgsbase, fs) {
|
||||
if (!_have_fsgsbase()) return;
|
||||
int64_t mem = 0xdeadbeef;
|
||||
_wrfsbase(&mem);
|
||||
ASSERT_EQ(&mem, _rdfsbase());
|
||||
ASSERT_EQ(0xdeadbeef, fs((int64_t *)0));
|
||||
TriggerSignal();
|
||||
ASSERT_EQ(0xdeadbeef, fs((int64_t *)0));
|
||||
}
|
||||
|
||||
TEST(fsgsbase, gs) {
|
||||
if (!_have_fsgsbase()) return;
|
||||
int64_t mem = 0xdeadbeef;
|
||||
_wrgsbase(&mem);
|
||||
ASSERT_EQ(&mem, _rdgsbase());
|
||||
ASSERT_EQ(0xdeadbeef, gs((int64_t *)0));
|
||||
TriggerSignal();
|
||||
ASSERT_EQ(0xdeadbeef, gs((int64_t *)0));
|
||||
}
|
||||
|
||||
#endif /* __x86_64__ */
|
4
third_party/make/main.c
vendored
4
third_party/make/main.c
vendored
|
@ -636,13 +636,11 @@ expand_command_line_file (const char *name)
|
|||
|
||||
/* Toggle -d on receipt of SIGUSR1. */
|
||||
|
||||
#ifdef SIGUSR1
|
||||
static RETSIGTYPE
|
||||
debug_signal_handler (int sig UNUSED)
|
||||
{
|
||||
db_level = db_level ? DB_NONE : DB_BASIC;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void
|
||||
decode_debug_flags (void)
|
||||
|
@ -1609,9 +1607,7 @@ main (int argc, char **argv, char **envp)
|
|||
#endif
|
||||
|
||||
/* Let the user send us SIGUSR1 to toggle the -d flag during the run. */
|
||||
#ifdef SIGUSR1
|
||||
bsd_signal (SIGUSR1, debug_signal_handler);
|
||||
#endif
|
||||
|
||||
/* Define the initial list of suffixes for old-style rules. */
|
||||
set_default_suffixes ();
|
||||
|
|
|
@ -38,6 +38,7 @@ TOOL_PLINKO_LIB_A_DIRECTDEPS = \
|
|||
LIBC_STR \
|
||||
LIBC_STUBS \
|
||||
LIBC_SYSV \
|
||||
LIBC_SYSV_CALLS \
|
||||
THIRD_PARTY_COMPILER_RT \
|
||||
THIRD_PARTY_GETOPT
|
||||
|
||||
|
|
|
@ -16,8 +16,10 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "tool/plinko/lib/plinko.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/struct/sigaction.h"
|
||||
#include "libc/calls/syscall-sysv.internal.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/intrin/likely.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
|
@ -43,7 +45,6 @@
|
|||
#include "tool/plinko/lib/gc.h"
|
||||
#include "tool/plinko/lib/histo.h"
|
||||
#include "tool/plinko/lib/index.h"
|
||||
#include "tool/plinko/lib/plinko.h"
|
||||
#include "tool/plinko/lib/print.h"
|
||||
#include "tool/plinko/lib/printf.h"
|
||||
#include "tool/plinko/lib/stack.h"
|
||||
|
@ -935,8 +936,8 @@ int Plinko(int argc, char *argv[]) {
|
|||
}
|
||||
}
|
||||
|
||||
if (arch_prctl(ARCH_SET_FS, 0x200000000000) == -1 ||
|
||||
arch_prctl(ARCH_SET_GS, (intptr_t)DispatchPlan) == -1) {
|
||||
if (sys_arch_prctl(ARCH_SET_FS, 0x200000000000) == -1 ||
|
||||
sys_arch_prctl(ARCH_SET_GS, (intptr_t)DispatchPlan) == -1) {
|
||||
fputs("error: ", stderr);
|
||||
fputs(strerror(errno), stderr);
|
||||
fputs("\nyour operating system doesn't allow you change both "
|
||||
|
|
Loading…
Reference in a new issue