mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-05-28 16:22:29 +00:00
Make improvements
- Implement openpty() - Add `--assimilate` flag to APE bootloader - Restore Linux vDSO clock_gettime() support - Use `$(APE_NO_MODIFY_SELF)` on more programs
This commit is contained in:
parent
cef50f2a6b
commit
d44ff6ce1f
33 changed files with 600 additions and 251 deletions
30
libc/calls/__clock_gettime.S
Normal file
30
libc/calls/__clock_gettime.S
Normal file
|
@ -0,0 +1,30 @@
|
|||
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
|
||||
│vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2022 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/macros.internal.h"
|
||||
|
||||
.initbss 201,_init___clock_gettime
|
||||
__clock_gettime:
|
||||
.quad 0
|
||||
.endobj __clock_gettime,globl,hidden
|
||||
.previous
|
||||
|
||||
.init.start 201,_init___clock_gettime
|
||||
ezlea __clock_gettime_init,ax
|
||||
stosq
|
||||
.init.end 201,_init___clock_gettime
|
19
libc/calls/asan.internal.h
Normal file
19
libc/calls/asan.internal.h
Normal file
|
@ -0,0 +1,19 @@
|
|||
#ifndef COSMOPOLITAN_LIBC_CALLS_ASAN_INTERNAL_H_
|
||||
#define COSMOPOLITAN_LIBC_CALLS_ASAN_INTERNAL_H_
|
||||
#include "libc/bits/asmflag.h"
|
||||
#include "libc/calls/struct/timespec.h"
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
forceinline bool __asan_is_valid_timespec(const struct timespec *ts) {
|
||||
bool zf;
|
||||
asm(ZFLAG_ASM("cmpw\t$0,0x7fff8000(%1)")
|
||||
: ZFLAG_CONSTRAINT(zf)
|
||||
: "r"((intptr_t)ts >> 3)
|
||||
: "memory");
|
||||
return zf;
|
||||
}
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_LIBC_CALLS_ASAN_INTERNAL_H_ */
|
|
@ -27,6 +27,7 @@ textwindows int sys_clock_gettime_nt(int clockid, struct timespec *ts) {
|
|||
struct timespec res;
|
||||
struct NtFileTime ft;
|
||||
static struct timespec mono;
|
||||
if (!ts) return efault();
|
||||
if (clockid == CLOCK_REALTIME) {
|
||||
GetSystemTimeAsFileTime(&ft);
|
||||
*ts = FileTimeToTimeSpec(ft);
|
||||
|
|
35
libc/calls/clock_gettime-xnu.c
Normal file
35
libc/calls/clock_gettime-xnu.c
Normal 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 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/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
|
||||
int sys_clock_gettime_xnu(int clockid, struct timespec *ts) {
|
||||
axdx_t ad;
|
||||
ad = sys_gettimeofday((struct timeval *)ts, NULL, NULL);
|
||||
if (ad.ax != -1) {
|
||||
if (ad.ax) {
|
||||
ts->tv_sec = ad.ax;
|
||||
ts->tv_nsec = ad.dx;
|
||||
}
|
||||
ts->tv_nsec *= 1000;
|
||||
return 0;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
|
@ -17,6 +17,10 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/assert.h"
|
||||
#include "libc/bits/asmflag.h"
|
||||
#include "libc/bits/bits.h"
|
||||
#include "libc/calls/asan.internal.h"
|
||||
#include "libc/calls/clock_gettime.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/state.internal.h"
|
||||
#include "libc/calls/strace.internal.h"
|
||||
|
@ -26,11 +30,10 @@
|
|||
#include "libc/fmt/conv.h"
|
||||
#include "libc/intrin/asan.internal.h"
|
||||
#include "libc/intrin/describeflags.internal.h"
|
||||
#include "libc/mem/alloca.h"
|
||||
#include "libc/nt/synchronization.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
static typeof(sys_clock_gettime) *__clock_gettime = sys_clock_gettime;
|
||||
|
||||
/**
|
||||
* Returns nanosecond time.
|
||||
*
|
||||
|
@ -38,6 +41,13 @@ static typeof(sys_clock_gettime) *__clock_gettime = sys_clock_gettime;
|
|||
* time. Among the more popular is CLOCK_MONOTONIC. This function has a
|
||||
* zero syscall implementation of that on modern x86.
|
||||
*
|
||||
* nowl l: 45𝑐 15𝑛𝑠
|
||||
* rdtsc l: 13𝑐 4𝑛𝑠
|
||||
* gettimeofday l: 44𝑐 14𝑛𝑠
|
||||
* clock_gettime l: 40𝑐 13𝑛𝑠
|
||||
* __clock_gettime l: 35𝑐 11𝑛𝑠
|
||||
* sys_clock_gettime l: 220𝑐 71𝑛𝑠
|
||||
*
|
||||
* @param clockid can be CLOCK_REALTIME, CLOCK_MONOTONIC, etc.
|
||||
* @param ts is where the result is stored
|
||||
* @return 0 on success, or -1 w/ errno
|
||||
|
@ -46,54 +56,49 @@ static typeof(sys_clock_gettime) *__clock_gettime = sys_clock_gettime;
|
|||
* @asyncsignalsafe
|
||||
*/
|
||||
noinstrument int clock_gettime(int clockid, struct timespec *ts) {
|
||||
int rc, e;
|
||||
axdx_t ad;
|
||||
char buf[45];
|
||||
if (!ts) {
|
||||
int rc;
|
||||
char *buf;
|
||||
if (IsAsan() && !__asan_is_valid_timespec(ts)) {
|
||||
rc = efault();
|
||||
} else if (IsAsan() && !__asan_is_valid(ts, sizeof(*ts))) {
|
||||
rc = efault();
|
||||
} else if (clockid == -1) {
|
||||
rc = einval();
|
||||
} else if (!IsWindows()) {
|
||||
e = errno;
|
||||
if ((rc = __clock_gettime(clockid, ts))) {
|
||||
errno = e;
|
||||
ad = sys_gettimeofday((struct timeval *)ts, NULL, NULL);
|
||||
assert(ad.ax != -1);
|
||||
if (SupportsXnu() && ad.ax) {
|
||||
ts->tv_sec = ad.ax;
|
||||
ts->tv_nsec = ad.dx;
|
||||
}
|
||||
ts->tv_nsec *= 1000;
|
||||
rc = 0;
|
||||
}
|
||||
} else {
|
||||
rc = sys_clock_gettime_nt(clockid, ts);
|
||||
rc = __clock_gettime(clockid, ts);
|
||||
}
|
||||
#if SYSDEBUG
|
||||
if (!__time_critical) {
|
||||
buf = alloca(45);
|
||||
STRACE("clock_gettime(%d, [%s]) → %d% m", clockid,
|
||||
DescribeTimespec(buf, sizeof(buf), rc, ts), rc);
|
||||
DescribeTimespec(buf, 45, rc, ts), rc);
|
||||
}
|
||||
#endif
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns fast system clock_gettime() if it exists.
|
||||
* Returns pointer to fastest clock_gettime().
|
||||
*/
|
||||
void *__get_clock_gettime(void) {
|
||||
void *vdso;
|
||||
static bool once;
|
||||
static void *result;
|
||||
if (!once) {
|
||||
if ((vdso = __vdsofunc("__vdso_clock_gettime"))) {
|
||||
__clock_gettime = result = vdso;
|
||||
}
|
||||
once = true;
|
||||
clock_gettime_f *__get_clock_gettime(bool *opt_out_isfast) {
|
||||
bool isfast;
|
||||
clock_gettime_f *res;
|
||||
if (IsLinux() && (res = __vdsosym("LINUX_2.6", "__vdso_clock_gettime"))) {
|
||||
isfast = true;
|
||||
} else if (IsXnu()) {
|
||||
isfast = false;
|
||||
res = sys_clock_gettime_xnu;
|
||||
} else if (IsWindows()) {
|
||||
isfast = true;
|
||||
res = sys_clock_gettime_nt;
|
||||
} else {
|
||||
isfast = false;
|
||||
res = sys_clock_gettime;
|
||||
}
|
||||
return result;
|
||||
if (opt_out_isfast) {
|
||||
*opt_out_isfast = isfast;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
const void *const __clock_gettime_ctor[] initarray = {
|
||||
__get_clock_gettime,
|
||||
};
|
||||
hidden int __clock_gettime_init(int clockid, struct timespec *ts) {
|
||||
clock_gettime_f *gettime;
|
||||
__clock_gettime = gettime = __get_clock_gettime(0);
|
||||
return gettime(clockid, ts);
|
||||
}
|
||||
|
|
15
libc/calls/clock_gettime.h
Normal file
15
libc/calls/clock_gettime.h
Normal file
|
@ -0,0 +1,15 @@
|
|||
#ifndef COSMOPOLITAN_LIBC_CALLS_CLOCK_GETTIME_H_
|
||||
#define COSMOPOLITAN_LIBC_CALLS_CLOCK_GETTIME_H_
|
||||
#include "libc/calls/struct/timespec.h"
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
typedef int clock_gettime_f(int, struct timespec *);
|
||||
|
||||
extern clock_gettime_f *__clock_gettime;
|
||||
hidden clock_gettime_f __clock_gettime_init;
|
||||
hidden clock_gettime_f *__get_clock_gettime(bool *);
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_LIBC_CALLS_CLOCK_GETTIME_H_ */
|
|
@ -59,7 +59,7 @@ int gettimeofday(struct timeval *tv, struct timezone *tz) {
|
|||
|
||||
static textstartup void __gettimeofday_init(void) {
|
||||
void *vdso;
|
||||
if ((vdso = __vdsofunc("__vdso_gettimeofday"))) {
|
||||
if ((vdso = __vdsosym("LINUX_2.6", "__vdso_gettimeofday"))) {
|
||||
__gettimeofday = vdso;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -118,6 +118,7 @@ i32 __sys_sigprocmask(i32, const sigset *, sigset *, u64) hidden;
|
|||
i32 __sys_utimensat(i32, const char *, const struct timespec *, i32) hidden;
|
||||
i32 __sys_wait4(i32, i32 *, i32, struct rusage *) hidden;
|
||||
i32 sys_clock_gettime(i32, struct timespec *) hidden;
|
||||
i32 sys_clock_gettime_xnu(i32, struct timespec *) hidden;
|
||||
i32 sys_fstat(i32, struct stat *) hidden;
|
||||
i32 sys_fstatat(i32, const char *, struct stat *, i32) hidden;
|
||||
i32 sys_futimes(i32, const struct timeval *) hidden;
|
||||
|
|
|
@ -83,7 +83,7 @@ noasan textreal uint64_t *__get_virtual(struct mman *mm, uint64_t *t,
|
|||
/**
|
||||
* Sorts, rounds, and filters BIOS memory map.
|
||||
*/
|
||||
static noasan texthead void __normalize_e820(struct mman *mm) {
|
||||
static noasan textreal void __normalize_e820(struct mman *mm) {
|
||||
uint64_t a, b;
|
||||
uint64_t x, y;
|
||||
unsigned i, j, n;
|
||||
|
@ -113,7 +113,7 @@ static noasan texthead void __normalize_e820(struct mman *mm) {
|
|||
/**
|
||||
* Identity maps all usable physical memory to its negative address.
|
||||
*/
|
||||
static noasan texthead void __invert_memory(struct mman *mm, uint64_t *pml4t) {
|
||||
static noasan textreal void __invert_memory(struct mman *mm, uint64_t *pml4t) {
|
||||
uint64_t i, j, *m, p, pe;
|
||||
for (i = 0; i < mm->e820n; ++i) {
|
||||
for (p = mm->e820[i].addr, pe = mm->e820[i].addr + mm->e820[i].size;
|
||||
|
@ -126,7 +126,7 @@ static noasan texthead void __invert_memory(struct mman *mm, uint64_t *pml4t) {
|
|||
}
|
||||
}
|
||||
|
||||
noasan texthead void __setup_mman(struct mman *mm, uint64_t *pml4t) {
|
||||
noasan textreal void __setup_mman(struct mman *mm, uint64_t *pml4t) {
|
||||
__normalize_e820(mm);
|
||||
__invert_memory(mm, pml4t);
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/asan.internal.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/state.internal.h"
|
||||
|
@ -31,7 +32,8 @@
|
|||
noinstrument int nanosleep(const struct timespec *req, struct timespec *rem) {
|
||||
int rc;
|
||||
char buf[2][45];
|
||||
if (!req) {
|
||||
if (!req || (IsAsan() && (!__asan_is_valid_timespec(req) ||
|
||||
(rem && !__asan_is_valid_timespec(rem))))) {
|
||||
rc = efault();
|
||||
} else if (req->tv_sec < 0 ||
|
||||
!(0 <= req->tv_nsec && req->tv_nsec <= 999999999)) {
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include "libc/bits/initializer.internal.h"
|
||||
#include "libc/bits/safemacros.internal.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/clock_gettime.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/state.internal.h"
|
||||
#include "libc/calls/strace.internal.h"
|
||||
|
@ -32,10 +33,11 @@
|
|||
#include "libc/sysv/consts/clock.h"
|
||||
#include "libc/time/time.h"
|
||||
|
||||
static clock_gettime_f *__gettime;
|
||||
|
||||
static struct Now {
|
||||
uint64_t k0;
|
||||
long double r0, cpn;
|
||||
typeof(sys_clock_gettime) *clock_gettime;
|
||||
} g_now;
|
||||
|
||||
static long double GetTimeSample(void) {
|
||||
|
@ -90,7 +92,7 @@ static long double nowl_art(void) {
|
|||
static long double nowl_vdso(void) {
|
||||
long double secs;
|
||||
struct timespec tv;
|
||||
g_now.clock_gettime(CLOCK_REALTIME, &tv);
|
||||
__gettime(CLOCK_REALTIME, &tv);
|
||||
secs = tv.tv_nsec;
|
||||
secs *= 1 / 1e9L;
|
||||
secs += tv.tv_sec;
|
||||
|
@ -98,9 +100,10 @@ static long double nowl_vdso(void) {
|
|||
}
|
||||
|
||||
long double nowl_setup(void) {
|
||||
bool isfast;
|
||||
uint64_t ticks;
|
||||
if (0 && (g_now.clock_gettime = __get_clock_gettime())) {
|
||||
// TODO(jart): Re-enable this.
|
||||
__gettime = __get_clock_gettime(&isfast);
|
||||
if (isfast) {
|
||||
nowl = nowl_vdso;
|
||||
} else if (X86_HAVE(INVTSC)) {
|
||||
RefreshTime();
|
||||
|
|
|
@ -17,33 +17,44 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/ioctl.h"
|
||||
#include "libc/calls/termios.h"
|
||||
#include "libc/fmt/itoa.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
#include "libc/sysv/consts/pty.h"
|
||||
#include "libc/sysv/consts/termios.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
/**
|
||||
* Opens new pseudo teletypewriter.
|
||||
*
|
||||
* @param ilduce receives controlling tty rw fd on success
|
||||
* @param aworker receives subordinate tty rw fd on success
|
||||
* @param termp may be passed to tune a century of legacy behaviors
|
||||
* @param winp may be passed to set terminal display dimensions
|
||||
* @param mfd receives controlling tty rw fd on success
|
||||
* @param sfd receives subordinate tty rw fd on success
|
||||
* @param tio may be passed to tune a century of legacy behaviors
|
||||
* @param wsz may be passed to set terminal display dimensions
|
||||
* @params flags is usually O_RDWR|O_NOCTTY
|
||||
* @return file descriptor, or -1 w/ errno
|
||||
* @return 0 on success, or -1 w/ errno
|
||||
*/
|
||||
int openpty(int *ilduce, int *aworker, char *name, const struct termios *termp,
|
||||
const struct winsize *winp) {
|
||||
return enosys();
|
||||
/* TODO(jart) */
|
||||
/* int fd, flags; */
|
||||
/* flags = O_RDWR | O_NOCTTY; */
|
||||
/* if ((fd = posix_openpt(flags)) != -1) { */
|
||||
/* if (ioctl(m, TIOCSPTLCK, &n) || ioctl(m, TIOCGPTN, &n)) { */
|
||||
/* } else { */
|
||||
/* close(fd); */
|
||||
/* } */
|
||||
/* } else { */
|
||||
/* return -1; */
|
||||
/* } */
|
||||
int openpty(int *mfd, int *sfd, char *name, const struct termios *tio,
|
||||
const struct winsize *wsz) {
|
||||
int m, s, n;
|
||||
char buf[20];
|
||||
if ((m = open("/dev/ptmx", O_RDWR | O_NOCTTY)) != -1) {
|
||||
n = 0;
|
||||
if (!ioctl(m, TIOCSPTLCK, &n) || !ioctl(m, TIOCGPTN, &n)) {
|
||||
if (!name) name = buf;
|
||||
name[0] = '/', name[1] = 'd', name[2] = 'e', name[3] = 'v';
|
||||
name[4] = '/', name[5] = 'p', name[6] = 't', name[7] = 's';
|
||||
name[8] = '/', FormatInt32(name + 9, n);
|
||||
if ((s = open(name, O_RDWR | O_NOCTTY)) != -1) {
|
||||
if (tio) ioctl(s, TCSETS, tio);
|
||||
if (wsz) ioctl(s, TIOCSWINSZ, wsz);
|
||||
*mfd = m;
|
||||
*sfd = s;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
close(m);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
|
|
@ -12,8 +12,7 @@ int __notziposat(int, const char *);
|
|||
int gethostname_bsd(char *, size_t) hidden;
|
||||
int gethostname_linux(char *, size_t) hidden;
|
||||
int gethostname_nt(char *, size_t, int) hidden;
|
||||
void *__get_clock_gettime(void) hidden;
|
||||
void *__vdsofunc(const char *) hidden;
|
||||
void *__vdsosym(const char *, const char *) hidden;
|
||||
void __onfork(void) hidden;
|
||||
void __restore_rt() hidden;
|
||||
void __restore_rt_netbsd(void) hidden;
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/bits/weaken.h"
|
||||
#include "libc/calls/asan.internal.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/strace.internal.h"
|
||||
|
@ -39,7 +40,8 @@ int utimensat(int dirfd, const char *path, const struct timespec ts[2],
|
|||
int rc;
|
||||
char buf[12];
|
||||
if (IsAsan() && (!__asan_is_valid(path, 1) ||
|
||||
(ts && !__asan_is_valid(ts, sizeof(struct timespec) * 2)))) {
|
||||
(ts && (!__asan_is_valid_timespec(ts + 0) ||
|
||||
!__asan_is_valid_timespec(ts + 1))))) {
|
||||
rc = efault();
|
||||
} else if (weaken(__zipos_notat) && (rc = __zipos_notat(dirfd, path)) == -1) {
|
||||
STRACE("zipos mkdirat not supported yet");
|
||||
|
|
|
@ -18,76 +18,136 @@
|
|||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/bits/bits.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/strace.internal.h"
|
||||
#include "libc/elf/scalar.h"
|
||||
#include "libc/elf/struct/ehdr.h"
|
||||
#include "libc/elf/struct/phdr.h"
|
||||
#include "libc/elf/struct/shdr.h"
|
||||
#include "libc/elf/struct/sym.h"
|
||||
#include "libc/log/libfatal.internal.h"
|
||||
#include "libc/elf/struct/verdaux.h"
|
||||
#include "libc/elf/struct/verdef.h"
|
||||
#include "libc/intrin/kprintf.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/sysv/consts/auxv.h"
|
||||
|
||||
#define LAZY_RHEL7_RELOCATION 0xfffff
|
||||
|
||||
#define GetStr(tab, rva) ((char *)(tab) + (rva))
|
||||
#define GetSection(e, s) ((void *)((intptr_t)(e) + (size_t)(s)->sh_offset))
|
||||
#define GetShstrtab(e) GetSection(e, GetShdr(e, (e)->e_shstrndx))
|
||||
#define GetSectionName(e, s) GetStr(GetShstrtab(e), (s)->sh_name)
|
||||
#define GetPhdr(e, i) \
|
||||
((Elf64_Phdr *)((intptr_t)(e) + (e)->e_phoff + \
|
||||
(size_t)(e)->e_phentsize * (i)))
|
||||
#define GetShdr(e, i) \
|
||||
((Elf64_Shdr *)((intptr_t)(e) + (e)->e_shoff + \
|
||||
(size_t)(e)->e_shentsize * (i)))
|
||||
|
||||
static char *GetDynamicStringTable(Elf64_Ehdr *e, size_t *n) {
|
||||
char *name;
|
||||
Elf64_Half i;
|
||||
Elf64_Shdr *shdr;
|
||||
for (i = 0; i < e->e_shnum; ++i) {
|
||||
shdr = GetShdr(e, i);
|
||||
name = GetSectionName(e, GetShdr(e, i));
|
||||
if (shdr->sh_type == SHT_STRTAB) {
|
||||
name = GetSectionName(e, GetShdr(e, i));
|
||||
if (name && READ64LE(name) == READ64LE(".dynstr")) {
|
||||
if (n) *n = shdr->sh_size;
|
||||
return GetSection(e, shdr);
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
static inline int CompareStrings(const char *l, const char *r) {
|
||||
size_t i = 0;
|
||||
while (l[i] == r[i] && r[i]) ++i;
|
||||
return (l[i] & 255) - (r[i] & 255);
|
||||
}
|
||||
|
||||
static Elf64_Sym *GetDynamicSymbolTable(Elf64_Ehdr *e, Elf64_Xword *n) {
|
||||
Elf64_Half i;
|
||||
Elf64_Shdr *shdr;
|
||||
for (i = e->e_shnum; i > 0; --i) {
|
||||
shdr = GetShdr(e, i - 1);
|
||||
if (shdr->sh_type == SHT_DYNSYM) {
|
||||
if (shdr->sh_entsize != sizeof(Elf64_Sym)) continue;
|
||||
if (n) *n = shdr->sh_size / shdr->sh_entsize;
|
||||
return GetSection(e, shdr);
|
||||
static inline int CheckDsoSymbolVersion(Elf64_Verdef *vd, int sym,
|
||||
const char *name, char *strtab) {
|
||||
Elf64_Verdaux *aux;
|
||||
for (;; vd = (Elf64_Verdef *)((char *)vd + vd->vd_next)) {
|
||||
if (!(vd->vd_flags & VER_FLG_BASE) &&
|
||||
(vd->vd_ndx & 0x7fff) == (sym & 0x7fff)) {
|
||||
aux = (Elf64_Verdaux *)((char *)vd + vd->vd_aux);
|
||||
return !CompareStrings(name, strtab + aux->vda_name);
|
||||
}
|
||||
if (!vd->vd_next) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns Linux Kernel Virtual Dynamic Shared Object function address.
|
||||
* Returns address of vDSO function.
|
||||
*/
|
||||
void *__vdsofunc(const char *name) {
|
||||
size_t m;
|
||||
char *names;
|
||||
void *__vdsosym(const char *version, const char *name) {
|
||||
void *p;
|
||||
size_t i;
|
||||
Elf64_Ehdr *ehdr;
|
||||
Elf64_Xword i, n;
|
||||
Elf64_Sym *symtab, *sym;
|
||||
if ((ehdr = (Elf64_Ehdr *)getauxval(AT_SYSINFO_EHDR)) &&
|
||||
(names = GetDynamicStringTable(ehdr, &m)) &&
|
||||
(symtab = GetDynamicSymbolTable(ehdr, &n))) {
|
||||
for (i = 0; i < n; ++i) {
|
||||
if (!__strcmp(names + symtab[i].st_name, name)) {
|
||||
return (char *)ehdr + (symtab[i].st_value & LAZY_RHEL7_RELOCATION);
|
||||
}
|
||||
Elf64_Phdr *phdr;
|
||||
char *strtab = 0;
|
||||
size_t *dyn, base;
|
||||
unsigned long *ap;
|
||||
Elf64_Sym *symtab = 0;
|
||||
uint16_t *versym = 0;
|
||||
Elf_Symndx *hashtab = 0;
|
||||
Elf64_Verdef *verdef = 0;
|
||||
|
||||
for (ehdr = 0, ap = __auxv; ap[0]; ap += 2) {
|
||||
if (ap[0] == AT_SYSINFO_EHDR) {
|
||||
ehdr = (void *)ap[1];
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!ehdr || READ32LE(ehdr->e_ident) != READ32LE("\177ELF")) {
|
||||
KERNTRACE("__vdsosym() → AT_SYSINFO_EHDR ELF not found");
|
||||
return 0;
|
||||
}
|
||||
|
||||
phdr = (void *)((char *)ehdr + ehdr->e_phoff);
|
||||
for (base = -1, dyn = 0, i = 0; i < ehdr->e_phnum;
|
||||
i++, phdr = (void *)((char *)phdr + ehdr->e_phentsize)) {
|
||||
switch (phdr->p_type) {
|
||||
case PT_LOAD:
|
||||
// modern linux uses the base address zero, but elders
|
||||
// e.g. rhel7 uses the base address 0xffffffffff700000
|
||||
base = (size_t)ehdr + phdr->p_offset - phdr->p_vaddr;
|
||||
break;
|
||||
case PT_DYNAMIC:
|
||||
dyn = (void *)((char *)ehdr + phdr->p_offset);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!dyn || base == -1) {
|
||||
KERNTRACE("__vdsosym() → missing program headers");
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (i = 0; dyn[i]; i += 2) {
|
||||
p = (void *)(base + dyn[i + 1]);
|
||||
switch (dyn[i]) {
|
||||
case DT_STRTAB:
|
||||
strtab = p;
|
||||
break;
|
||||
case DT_SYMTAB:
|
||||
symtab = p;
|
||||
break;
|
||||
case DT_HASH:
|
||||
hashtab = p;
|
||||
break;
|
||||
case DT_VERSYM:
|
||||
versym = p;
|
||||
break;
|
||||
case DT_VERDEF:
|
||||
verdef = p;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!strtab || !symtab || !hashtab) {
|
||||
KERNTRACE("__vdsosym() → tables not found");
|
||||
return 0;
|
||||
}
|
||||
if (!verdef) {
|
||||
versym = 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < hashtab[1]; i++) {
|
||||
if (ELF64_ST_TYPE(symtab[i].st_info) != STT_FUNC &&
|
||||
ELF64_ST_TYPE(symtab[i].st_info) != STT_OBJECT &&
|
||||
ELF64_ST_TYPE(symtab[i].st_info) != STT_NOTYPE) {
|
||||
continue;
|
||||
}
|
||||
if (ELF64_ST_BIND(symtab[i].st_info) != STB_GLOBAL) {
|
||||
continue;
|
||||
}
|
||||
if (!symtab[i].st_shndx) {
|
||||
continue;
|
||||
}
|
||||
if (CompareStrings(name, strtab + symtab[i].st_name)) {
|
||||
continue;
|
||||
}
|
||||
if (versym && !CheckDsoSymbolVersion(verdef, versym[i], version, strtab)) {
|
||||
continue;
|
||||
}
|
||||
return (void *)(base + symtab[i].st_value);
|
||||
}
|
||||
|
||||
KERNTRACE("__vdsosym() → symbol not found");
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -17,12 +17,16 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/elf/elf.h"
|
||||
#include "libc/intrin/kprintf.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
|
||||
void CheckElfAddress(const Elf64_Ehdr *elf, size_t mapsize, intptr_t addr,
|
||||
size_t addrsize) {
|
||||
#if !(TRUSTWORTHY + ELF_TRUSTWORTHY + 0) || ELF_UNTRUSTWORTHY + 0
|
||||
if (addr < (intptr_t)elf || addr + addrsize > (intptr_t)elf + mapsize) {
|
||||
/* kprintf("%p-%p falls outside interval %p-%p", // */
|
||||
/* addr, addr + addrsize, // */
|
||||
/* elf, (char *)elf + mapsize); // */
|
||||
abort();
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -2,15 +2,16 @@
|
|||
#define COSMOPOLITAN_LIBC_ELF_SCALAR_H_
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
|
||||
#define Elf64_Half uint16_t
|
||||
#define Elf64_Word uint32_t
|
||||
#define Elf64_Sword int32_t
|
||||
#define Elf64_Xword uint64_t
|
||||
#define Elf64_Sxword int64_t
|
||||
#define Elf64_Addr uint64_t
|
||||
#define Elf64_Off uint64_t
|
||||
#define Elf64_Addr uint64_t
|
||||
#define Elf64_Half uint16_t
|
||||
#define Elf64_Off uint64_t
|
||||
#define Elf64_Section uint16_t
|
||||
#define Elf64_Versym Elf64_Half
|
||||
#define Elf64_Sword int32_t
|
||||
#define Elf64_Sxword int64_t
|
||||
#define Elf64_Versym Elf64_Half
|
||||
#define Elf64_Word uint32_t
|
||||
#define Elf64_Xword uint64_t
|
||||
#define Elf_Symndx uint32_t
|
||||
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_LIBC_ELF_SCALAR_H_ */
|
||||
|
|
|
@ -1323,7 +1323,6 @@ syscon termios TIOCSETD 0x5423 0x8004741b 0x8004741b 0x8004741b 0x800474
|
|||
syscon termios TIOCSIG 0x40045436 0x2000745f 0x2004745f 0x8004745f 0x8004745f 0 # boop
|
||||
syscon termios TIOCSPGRP 0x5410 0x80047476 0x80047476 0x80047476 0x80047476 0 # boop
|
||||
syscon termios TIOCSTI 0x5412 0x80017472 0x80017472 0 0 0 # boop
|
||||
syscon termios TIOCGPTN 0x80045430 0 0x4004740f 0 0 0 # boop
|
||||
syscon termios TIOCGSID 0x5429 0x40047463 0x40047463 0x40047463 0x40047463 0 # boop
|
||||
syscon termios TABLDISC 0 0x3 0 0x3 0x3 0 # boop
|
||||
syscon termios SLIPDISC 0 0x4 0x4 0x4 0x4 0 # boop
|
||||
|
@ -1508,6 +1507,8 @@ syscon termios CSTOP 19 19 19 19 19 0 # unix consensus
|
|||
# Pseudoteletypewriter Control
|
||||
#
|
||||
# group name GNU/Systemd XNU's Not UNIX! FreeBSD OpenBSD NetBSD The New Technology Commentary
|
||||
syscon pty TIOCGPTN 0x80045430 0 0x4004740f 0 0 0 # boop
|
||||
syscon pty TIOCSPTLCK 0x40045431 0 0 0 0 0 # boop
|
||||
syscon pty TIOCPKT 0x5420 0x80047470 0x80047470 0x80047470 0x80047470 -1 # boop
|
||||
syscon pty TIOCPKT_DATA 0 0 0 0 0 0 # consensus
|
||||
syscon pty TIOCPKT_FLUSHREAD 1 1 1 1 1 1 # unix consensus
|
||||
|
@ -1517,7 +1518,6 @@ syscon pty TIOCPKT_START 8 8 8 8 8 8 # unix consensus
|
|||
syscon pty TIOCPKT_NOSTOP 16 16 16 16 16 16 # unix consensus
|
||||
syscon pty TIOCPKT_DOSTOP 32 32 32 32 32 32 # unix consensus
|
||||
syscon pty TIOCPKT_IOCTL 64 64 64 64 64 64 # unix consensus
|
||||
syscon pty TIOCSPTLCK 0x40045431 0 0 0 0 -1 # boop
|
||||
syscon pty PTMGET 0 0 0 0x40287401 0x40287401 -1 # for /dev/ptm
|
||||
|
||||
# Modem Control
|
||||
|
|
|
@ -154,11 +154,14 @@ intptr_t erfkill(void) relegated;
|
|||
intptr_t ehwpoison(void) relegated;
|
||||
|
||||
#if defined(__MNO_RED_ZONE__) && defined(__GNUC__) && !defined(__STRICT_ANSI__)
|
||||
#define __ERRFUN(FUNC) \
|
||||
({ \
|
||||
intptr_t NegOne; \
|
||||
asm("call\t" FUNC : "=a"(NegOne), "=m"(errno)); \
|
||||
NegOne; \
|
||||
#define __ERRFUN(FUNC) \
|
||||
({ \
|
||||
intptr_t NegOne; \
|
||||
asm volatile("call\t" FUNC \
|
||||
: "=a"(NegOne) \
|
||||
: /* no outputs */ \
|
||||
: "rcx", "memory"); \
|
||||
NegOne; \
|
||||
})
|
||||
#define einval() __ERRFUN("einval")
|
||||
#define eperm() __ERRFUN("eperm")
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue