mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-07-01 00:38:31 +00:00
Support thread local storage
This commit is contained in:
parent
91ee2b19d4
commit
55de4ca6b5
197 changed files with 1483 additions and 874 deletions
|
@ -19,6 +19,7 @@
|
|||
#include "libc/bits/asmflag.h"
|
||||
#include "libc/bits/bits.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/nexgen32e/msr.h"
|
||||
#include "libc/nexgen32e/x86feature.h"
|
||||
|
@ -57,8 +58,6 @@
|
|||
"d"((uint32_t)(val_ >> 32))); \
|
||||
} while (0)
|
||||
|
||||
int sys_arch_prctl(int, int64_t) hidden;
|
||||
|
||||
static inline int arch_prctl_fsgsbase(int code, int64_t addr) {
|
||||
switch (code) {
|
||||
case ARCH_SET_GS:
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/strace.internal.h"
|
||||
#include "libc/calls/struct/ucontext-netbsd.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/intrin/asan.internal.h"
|
||||
#include "libc/intrin/kprintf.h"
|
||||
|
@ -34,6 +35,7 @@
|
|||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/sysv/consts/clone.h"
|
||||
#include "libc/sysv/consts/nr.h"
|
||||
#include "libc/sysv/consts/nrlinux.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
#include "libc/thread/freebsd.internal.h"
|
||||
#include "libc/thread/xnu.internal.h"
|
||||
|
@ -47,10 +49,56 @@ STATIC_YOINK("gettid"); // for kprintf()
|
|||
#define __NR__lwp_setprivate 317
|
||||
#define __NR_bsdthread_create 0x02000168
|
||||
#define __NR_thread_fast_set_cthread_self 0x03000003
|
||||
#define __NR_sysarch 0x000000a5
|
||||
#define __NR___set_tcb 0x00000149
|
||||
#define PTHREAD_START_CUSTOM_XNU 0x01000000
|
||||
#define LWP_DETACHED 0x00000040
|
||||
#define LWP_SUSPENDED 0x00000080
|
||||
|
||||
char __tls[512];
|
||||
int __errno_global;
|
||||
extern int __errno_index;
|
||||
|
||||
privileged void __setup_tls(void) {
|
||||
int ax, dx;
|
||||
uint64_t magic;
|
||||
unsigned char *p;
|
||||
*(intptr_t *)__tls = (intptr_t)__tls;
|
||||
*(intptr_t *)(__tls + 0x30) = (intptr_t)__tls;
|
||||
*(int *)(__tls + 0x3c) = __errno;
|
||||
if (IsWindows()) {
|
||||
__errno_index = TlsAlloc();
|
||||
TlsSetValue(__errno_index, (void *)(intptr_t)__errno);
|
||||
} else if (IsLinux()) {
|
||||
asm volatile("syscall"
|
||||
: "=a"(ax)
|
||||
: "0"(__NR_linux_arch_prctl), "D"(ARCH_SET_FS), "S"(__tls)
|
||||
: "rcx", "r11", "memory");
|
||||
} else if (IsFreebsd()) {
|
||||
asm volatile("syscall"
|
||||
: "=a"(ax)
|
||||
: "0"(__NR_sysarch), "D"(129), "S"(__tls)
|
||||
: "rcx", "r11", "memory", "cc");
|
||||
} else if (IsXnu()) {
|
||||
asm volatile("syscall"
|
||||
: "=a"(ax)
|
||||
: "0"(__NR_thread_fast_set_cthread_self),
|
||||
"D"((intptr_t)__tls - 0x30)
|
||||
: "rcx", "r11", "memory", "cc");
|
||||
} else if (IsOpenbsd()) {
|
||||
asm volatile("syscall"
|
||||
: "=a"(ax)
|
||||
: "0"(__NR___set_tcb), "D"(__tls)
|
||||
: "rcx", "r11", "memory", "cc");
|
||||
} else if (IsNetbsd()) {
|
||||
asm volatile("syscall"
|
||||
: "=a"(ax), "=d"(dx)
|
||||
: "0"(__NR__lwp_setprivate), "D"(__tls)
|
||||
: "rcx", "r11", "memory", "cc");
|
||||
}
|
||||
__hastls = true;
|
||||
}
|
||||
|
||||
uint32_t WinThreadThunk(void *warg);
|
||||
asm(".section\t.text.windows,\"ax\",@progbits\n\t"
|
||||
".local\tWinThreadThunk\n"
|
||||
|
@ -58,7 +106,8 @@ asm(".section\t.text.windows,\"ax\",@progbits\n\t"
|
|||
"xor\t%ebp,%ebp\n\t"
|
||||
"mov\t%rcx,%rdi\n\t"
|
||||
"mov\t%rcx,%rsp\n\t"
|
||||
"jmp\tWinThreadMain\n\t"
|
||||
"and\t$-16,%rsp\n\t"
|
||||
"call\tWinThreadMain\n\t"
|
||||
".size\tWinThreadThunk,.-WinThreadThunk\n\t"
|
||||
".previous");
|
||||
__attribute__((__used__, __no_reorder__))
|
||||
|
@ -69,7 +118,6 @@ WinThreadMain(struct WinThread *wt) {
|
|||
if (wt->flags & CLONE_CHILD_SETTID) {
|
||||
*wt->ctid = wt->tid;
|
||||
}
|
||||
// TlsSetValue(__winthread, wt);
|
||||
rc = wt->func(wt->arg);
|
||||
if (wt->flags & CLONE_CHILD_CLEARTID) {
|
||||
*wt->ctid = 0;
|
||||
|
@ -380,32 +428,25 @@ static int CloneLinux(int (*func)(void *), char *stk, size_t stksz, int flags,
|
|||
void *arg, int *ptid, void *tls, size_t tlssz,
|
||||
int *ctid) {
|
||||
int ax;
|
||||
bool failed;
|
||||
intptr_t *stack;
|
||||
register int *r8 asm("r8") = tls;
|
||||
register int (*r9)(void *) asm("r9") = func;
|
||||
register int *r10 asm("r10") = ctid;
|
||||
stack = (intptr_t *)(stk + stksz);
|
||||
*--stack = (long)arg; // push 1
|
||||
asm volatile("syscall"
|
||||
: "=a"(ax)
|
||||
: "0"(__NR_clone_linux), "D"(flags), "S"(stack), "d"(ptid),
|
||||
"r"(r10), "r"(r8), "r"(r9)
|
||||
: "rcx", "r11", "memory");
|
||||
if (ax > -4096u) {
|
||||
errno = -ax;
|
||||
return -1;
|
||||
}
|
||||
if (ax) return ax;
|
||||
asm volatile("xor\t%%ebp,%%ebp\n\t"
|
||||
"pop\t%%rdi\n\t" // pop 1
|
||||
"call\t*%0\n\t"
|
||||
register void *r9 asm("r9") = func;
|
||||
intptr_t *stack = (intptr_t *)(stk + stksz);
|
||||
*--stack = (intptr_t)arg;
|
||||
asm volatile("syscall\n\t"
|
||||
"test\t%0,%0\n\t"
|
||||
"jnz\t1f\n\t"
|
||||
"xor\t%%ebp,%%ebp\n\t"
|
||||
"pop\t%%rdi\n\t" // arg
|
||||
"call\t*%%r9\n\t" // func
|
||||
"xchg\t%%eax,%%edi\n\t"
|
||||
"jmp\t_Exit1"
|
||||
: /* no outputs */
|
||||
: "r"(r9)
|
||||
: "memory");
|
||||
unreachable;
|
||||
"jmp\t_Exit1\n1:"
|
||||
: "=a"(ax)
|
||||
: "0"(__NR_clone_linux), "D"(flags), "S"(stack), "r"(r10),
|
||||
"r"(r8), "r"(r9)
|
||||
: "rcx", "r11", "memory");
|
||||
if (ax > -4096u) errno = -ax, ax = -1;
|
||||
return ax;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -433,8 +474,8 @@ static int CloneLinux(int (*func)(void *), char *stk, size_t stksz, int flags,
|
|||
* if the fork() or vfork() equivalent flags are used it's highly
|
||||
* recommended that this value be GetStackSize(), or else kprintf
|
||||
* and other runtime services providing memory safety can't do as
|
||||
* good and quick of a job; this value must be 4096-aligned, plus
|
||||
* it must be at minimum 4096 bytes in size
|
||||
* good and quick of a job; this value must be 16-aligned plus it
|
||||
* must be at minimum 4096 bytes in size
|
||||
* @param flags usually has one of
|
||||
* - `SIGCHLD` will delegate to fork()
|
||||
* - `CLONE_VFORK|CLONE_VM|SIGCHLD` means vfork()
|
||||
|
@ -454,15 +495,17 @@ static int CloneLinux(int (*func)(void *), char *stk, size_t stksz, int flags,
|
|||
* @param tlssz is the size of tls in bytes
|
||||
* @param ctid lets the child receive its thread id;
|
||||
* this parameter is ignored if `CLONE_CHILD_SETTID` is not set
|
||||
* @return tid on success and 0 to the child, otherwise -1 w/ errno
|
||||
* @return tid on success and 0 to the child, or -1 w/ errno
|
||||
* @threadsafe
|
||||
*/
|
||||
int clone(int (*func)(void *), void *stk, size_t stksz, int flags, void *arg,
|
||||
int *ptid, void *tls, size_t tlssz, int *ctid) {
|
||||
int rc;
|
||||
|
||||
// let kprintf() switch from pids to tids
|
||||
__threaded = true;
|
||||
if (tls && !__hastls) {
|
||||
__setup_tls();
|
||||
}
|
||||
|
||||
// verify memory is kosher
|
||||
if (IsAsan() &&
|
||||
|
@ -504,7 +547,7 @@ int clone(int (*func)(void *), void *stk, size_t stksz, int flags, void *arg,
|
|||
|
||||
// we now assume we're creating a thread
|
||||
// these platforms can't do signals the way linux does
|
||||
else if (!IsTiny() && ((stksz < PAGESIZE || (stksz & (PAGESIZE - 1))) ||
|
||||
else if (!IsTiny() && ((stksz < PAGESIZE || (stksz & 15)) ||
|
||||
(flags & ~(CLONE_SETTLS | CLONE_PARENT_SETTID |
|
||||
CLONE_CHILD_SETTID)) !=
|
||||
(CLONE_THREAD | CLONE_VM | CLONE_FS | CLONE_FILES |
|
||||
|
@ -521,15 +564,13 @@ int clone(int (*func)(void *), void *stk, size_t stksz, int flags, void *arg,
|
|||
}
|
||||
|
||||
// These platforms can't do segment registers like linux does
|
||||
else if (flags & CLONE_SETTLS) {
|
||||
rc = einval();
|
||||
} else if (IsWindows()) {
|
||||
else if (IsWindows()) {
|
||||
rc = CloneWindows(func, stk, stksz, flags, arg, ptid, tls, tlssz, ctid);
|
||||
} else {
|
||||
rc = enosys();
|
||||
}
|
||||
|
||||
STRACE("clone(%p, %p, %'zu, %#x, %p, %p, %p, %'zu, %p) → %d% m", func, stk,
|
||||
STRACE("clone(%p, %p, %'zu, %#x, %p, %p, %p, %'zu, %p) → %d", func, stk,
|
||||
stksz, flags, arg, ptid, tls, tlssz, ctid, rc);
|
||||
return rc;
|
||||
}
|
|
@ -89,8 +89,8 @@ privileged noinstrument noasan noubsan void ftracer(void) {
|
|||
frame = __builtin_frame_address(0);
|
||||
frame = frame->next;
|
||||
if (frame->addr != g_lastaddr) {
|
||||
kprintf("+ %*s%t %d\r\n", GetNestingLevel(frame) * 2, "", frame->addr,
|
||||
ClocksToNanos(stamp, g_laststamp));
|
||||
kprintf("%rFUN %5P %'18T %*s%t\r\n", GetNestingLevel(frame) * 2, "",
|
||||
frame->addr);
|
||||
g_laststamp = X86_HAVE(RDTSCP) ? rdtscp(0) : rdtsc();
|
||||
g_lastaddr = frame->addr;
|
||||
}
|
||||
|
|
59
libc/runtime/getinstructionlengths.c
Normal file
59
libc/runtime/getinstructionlengths.c
Normal file
|
@ -0,0 +1,59 @@
|
|||
/*-*- 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/macros.internal.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/sysv/consts/map.h"
|
||||
#include "libc/sysv/consts/prot.h"
|
||||
#include "third_party/xed/x86.h"
|
||||
|
||||
/**
|
||||
* Returns lengths of x86 ops in binary.
|
||||
*
|
||||
* The first decoded instruction is at `_ereal`. Lengths can be 1 to 15
|
||||
* bytes. Each byte in the return value is in that range, and the array
|
||||
* is NUL terminated. The returned memory is memoized, since this costs
|
||||
* some time. For example, for a 10mb Python binary, it takes 20 millis
|
||||
* so the basic idea is is you can use this output multiple times which
|
||||
* is a faster way to iterate over the binary than calling Xed.
|
||||
*
|
||||
* @return nul-terminated length array on success, or null
|
||||
*/
|
||||
privileged unsigned char *GetInstructionLengths(void) {
|
||||
static bool once;
|
||||
int i, n, err, len, rem;
|
||||
static unsigned char *res;
|
||||
struct XedDecodedInst xedd;
|
||||
unsigned char *p, *mem, *code;
|
||||
if (!once) {
|
||||
if ((mem = mmap(0, ROUNDUP(__privileged_addr - _ereal + 1, FRAMESIZE),
|
||||
PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1,
|
||||
0)) != MAP_FAILED) {
|
||||
for (p = mem, code = _ereal; code < __privileged_addr; code += len) {
|
||||
rem = __privileged_addr - code;
|
||||
xed_decoded_inst_zero_set_mode(&xedd, XED_MACHINE_MODE_LONG_64);
|
||||
err = xed_instruction_length_decode(&xedd, code, rem);
|
||||
*p++ = len = !err ? xedd.length : 1;
|
||||
}
|
||||
res = mem;
|
||||
}
|
||||
once = true;
|
||||
}
|
||||
return res;
|
||||
}
|
|
@ -23,6 +23,7 @@
|
|||
#include "libc/calls/struct/sigset.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/intrin/kprintf.h"
|
||||
#include "libc/log/libfatal.internal.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/runtime/symbols.internal.h"
|
||||
|
@ -56,82 +57,69 @@ privileged noinstrument noasan int __hook(void *ifunc,
|
|||
uint64_t code, mcode;
|
||||
sigset_t mask, oldmask;
|
||||
intptr_t kMcount = (intptr_t)&mcount;
|
||||
intptr_t kProgramCodeStart = (intptr_t)&_ereal;
|
||||
intptr_t kPrivilegedStart = (intptr_t)&__privileged_start;
|
||||
bool kIsBinaryAligned = !(kPrivilegedStart & (PAGESIZE - 1));
|
||||
if (!IsWindows()) {
|
||||
sigfillset(&mask);
|
||||
sys_sigprocmask(SIG_BLOCK, &mask, &oldmask);
|
||||
}
|
||||
if ((rc = mprotect(
|
||||
(void *)symbols->addr_base, kPrivilegedStart - symbols->addr_base,
|
||||
kIsBinaryAligned ? PROT_READ | PROT_WRITE
|
||||
: PROT_READ | PROT_WRITE | PROT_EXEC)) != -1) {
|
||||
for (i = 0; i < symbols->count; ++i) {
|
||||
if (symbols->addr_base + symbols->symbols[i].x < kProgramCodeStart) {
|
||||
continue;
|
||||
}
|
||||
if (symbols->addr_base + symbols->symbols[i].y >= kPrivilegedStart) {
|
||||
intptr_t kProgramCodeStart = (intptr_t)_ereal;
|
||||
intptr_t kPrivilegedStart = (intptr_t)__privileged_addr;
|
||||
__morph_begin();
|
||||
for (i = 0; i < symbols->count; ++i) {
|
||||
if (symbols->addr_base + symbols->symbols[i].x < kProgramCodeStart) {
|
||||
continue;
|
||||
}
|
||||
if (symbols->addr_base + symbols->symbols[i].y >= kPrivilegedStart) {
|
||||
break;
|
||||
}
|
||||
for (p = (char *)symbols->addr_base + symbols->symbols[i].x,
|
||||
pe = (char *)symbols->addr_base + symbols->symbols[i].y;
|
||||
p + 8 - 1 <= pe; ++p) {
|
||||
code = ((uint64_t)(255 & p[7]) << 070 | (uint64_t)(255 & p[6]) << 060 |
|
||||
(uint64_t)(255 & p[5]) << 050 | (uint64_t)(255 & p[4]) << 040 |
|
||||
(uint64_t)(255 & p[3]) << 030 | (uint64_t)(255 & p[2]) << 020 |
|
||||
(uint64_t)(255 & p[1]) << 010 | (uint64_t)(255 & p[0]) << 000);
|
||||
|
||||
/*
|
||||
* Test for -mrecord-mcount (w/ -fpie or -fpic)
|
||||
*
|
||||
* nopw 0x00(%rax,%rax,1) ← morphed by package.com
|
||||
* call *mcount(%rip) ← linked w/o -static
|
||||
* addr32 call mcount ← relaxed w/ -static
|
||||
* addr32 call mcount ← relaxed w/ -static
|
||||
*
|
||||
* Note that gcc refuses to insert the six byte nop.
|
||||
*/
|
||||
if ((code & 0x0000FFFFFFFFFFFF) == 0x0000441F0F66 ||
|
||||
(code & 0x0000FFFFFFFFFFFF) ==
|
||||
((((kMcount - ((intptr_t)&p[2] + 4)) << 16) | 0xE867) &
|
||||
0x0000FFFFFFFFFFFF) ||
|
||||
(code & 0x0000FFFFFFFFFFFF) ==
|
||||
((((kMcount - ((intptr_t)&p[2] + 4)) << 16) | 0xFF15) &
|
||||
0x0000FFFFFFFFFFFF)) {
|
||||
p[0] = 0x67;
|
||||
p[1] = 0xE8;
|
||||
addr = (intptr_t)ifunc - ((intptr_t)&p[2] + 4);
|
||||
p[2] = (addr & 0x000000ff) >> 000;
|
||||
p[3] = (addr & 0x0000ff00) >> 010;
|
||||
p[4] = (addr & 0x00ff0000) >> 020;
|
||||
p[5] = (addr & 0xff000000) >> 030;
|
||||
break;
|
||||
}
|
||||
for (p = (char *)symbols->addr_base + symbols->symbols[i].x,
|
||||
pe = (char *)symbols->addr_base + symbols->symbols[i].y;
|
||||
p + 8 - 1 <= pe; ++p) {
|
||||
code = ((uint64_t)(255 & p[7]) << 070 | (uint64_t)(255 & p[6]) << 060 |
|
||||
(uint64_t)(255 & p[5]) << 050 | (uint64_t)(255 & p[4]) << 040 |
|
||||
(uint64_t)(255 & p[3]) << 030 | (uint64_t)(255 & p[2]) << 020 |
|
||||
(uint64_t)(255 & p[1]) << 010 | (uint64_t)(255 & p[0]) << 000);
|
||||
|
||||
/*
|
||||
* Test for -mrecord-mcount (w/ -fpie or -fpic)
|
||||
*
|
||||
* nopw 0x00(%rax,%rax,1) ← morphed by package.com
|
||||
* call *mcount(%rip) ← linked w/o -static
|
||||
* addr32 call mcount ← relaxed w/ -static
|
||||
* addr32 call mcount ← relaxed w/ -static
|
||||
*
|
||||
* Note that gcc refuses to insert the six byte nop.
|
||||
*/
|
||||
if ((code & 0x0000FFFFFFFFFFFF) == 0x0000441F0F66 ||
|
||||
(code & 0x0000FFFFFFFFFFFF) ==
|
||||
((((kMcount - ((intptr_t)&p[2] + 4)) << 16) | 0xE867) &
|
||||
0x0000FFFFFFFFFFFF) ||
|
||||
(code & 0x0000FFFFFFFFFFFF) ==
|
||||
((((kMcount - ((intptr_t)&p[2] + 4)) << 16) | 0xFF15) &
|
||||
0x0000FFFFFFFFFFFF)) {
|
||||
p[0] = 0x67;
|
||||
p[1] = 0xE8;
|
||||
addr = (intptr_t)ifunc - ((intptr_t)&p[2] + 4);
|
||||
p[2] = (addr & 0x000000ff) >> 000;
|
||||
p[3] = (addr & 0x0000ff00) >> 010;
|
||||
p[4] = (addr & 0x00ff0000) >> 020;
|
||||
p[5] = (addr & 0xff000000) >> 030;
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* Test for -mnop-mcount (w/ -fno-pie)
|
||||
*/
|
||||
mcode = code & 0x000000FFFFFFFFFF;
|
||||
if ((mcode == 0x00441F0F /* nopl 0x00(%eax,%eax,1) [canonical] */) ||
|
||||
(mcode == 0x00041F0F67 /* nopl (%eax,%eax,1) [older gcc] */)) {
|
||||
if (p[-1] != 0x66 /* nopw 0x0(%rax,%rax,1) [donotwant] */) {
|
||||
p[0] = 0xE8 /* call Jvds */;
|
||||
addr = (intptr_t)ifunc - ((intptr_t)&p[1] + 4);
|
||||
p[1] = (addr & 0x000000ff) >> 000;
|
||||
p[2] = (addr & 0x0000ff00) >> 010;
|
||||
p[3] = (addr & 0x00ff0000) >> 020;
|
||||
p[4] = (addr & 0xff000000) >> 030;
|
||||
}
|
||||
break;
|
||||
/*
|
||||
* Test for -mnop-mcount (w/ -fno-pie)
|
||||
*/
|
||||
mcode = code & 0x000000FFFFFFFFFF;
|
||||
if ((mcode == 0x00441F0F /* nopl 0x00(%eax,%eax,1) [canonical] */) ||
|
||||
(mcode == 0x00041F0F67 /* nopl (%eax,%eax,1) [older gcc] */)) {
|
||||
if (p[-1] != 0x66 /* nopw 0x0(%rax,%rax,1) [donotwant] */) {
|
||||
p[0] = 0xE8 /* call Jvds */;
|
||||
addr = (intptr_t)ifunc - ((intptr_t)&p[1] + 4);
|
||||
p[1] = (addr & 0x000000ff) >> 000;
|
||||
p[2] = (addr & 0x0000ff00) >> 010;
|
||||
p[3] = (addr & 0x00ff0000) >> 020;
|
||||
p[4] = (addr & 0xff000000) >> 030;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
mprotect((void *)symbols->addr_base, kPrivilegedStart - symbols->addr_base,
|
||||
PROT_READ | PROT_EXEC);
|
||||
}
|
||||
if (!IsWindows()) {
|
||||
sys_sigprocmask(SIG_SETMASK, &oldmask, NULL);
|
||||
}
|
||||
return rc;
|
||||
__morph_end();
|
||||
return 0;
|
||||
}
|
||||
|
|
79
libc/runtime/morph.greg.c
Normal file
79
libc/runtime/morph.greg.c
Normal file
|
@ -0,0 +1,79 @@
|
|||
/*-*- 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. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#define ShouldUseMsabiAttribute() 1
|
||||
#include "libc/bits/asmflag.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/sigbits.h"
|
||||
#include "libc/calls/struct/sigset.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/intrin/kprintf.h"
|
||||
#include "libc/nt/enum/pageflags.h"
|
||||
#include "libc/nt/memory.h"
|
||||
#include "libc/nt/runtime.h"
|
||||
#include "libc/nt/thunk/msabi.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/sysv/consts/nr.h"
|
||||
#include "libc/sysv/consts/prot.h"
|
||||
#include "libc/sysv/consts/sig.h"
|
||||
|
||||
__msabi extern typeof(VirtualProtect) *const __imp_VirtualProtect;
|
||||
|
||||
static int64_t vector;
|
||||
static sigset_t oldss;
|
||||
|
||||
static privileged void __morph_mprotect(void *addr, size_t size, int prot,
|
||||
int ntprot) {
|
||||
int ax, dx;
|
||||
uint32_t op;
|
||||
if (!IsWindows()) {
|
||||
asm volatile("syscall"
|
||||
: "=a"(ax), "=d"(dx)
|
||||
: "0"(__NR_mprotect), "D"(addr), "S"(size), "1"(prot)
|
||||
: "rcx", "r11", "memory");
|
||||
} else {
|
||||
__imp_VirtualProtect(addr, size, ntprot, &op);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Begins code morphing execuatble.
|
||||
*
|
||||
* @return 0 on success, or -1 w/ errno
|
||||
*/
|
||||
privileged void __morph_begin(void) {
|
||||
sigset_t ss;
|
||||
if (!IsWindows()) {
|
||||
sigfillset(&ss);
|
||||
sys_sigprocmask(SIG_BLOCK, &ss, &oldss);
|
||||
}
|
||||
__morph_mprotect(_base, __privileged_addr - _base, PROT_READ | PROT_WRITE,
|
||||
kNtPageWritecopy);
|
||||
}
|
||||
|
||||
/**
|
||||
* Begins code morphing execuatble.
|
||||
*/
|
||||
privileged void __morph_end(void) {
|
||||
__morph_mprotect(_base, __privileged_addr - _base, PROT_READ | PROT_EXEC,
|
||||
kNtPageExecuteRead);
|
||||
if (!IsWindows()) {
|
||||
sys_sigprocmask(SIG_SETMASK, &oldss, 0);
|
||||
}
|
||||
}
|
|
@ -20,6 +20,7 @@
|
|||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/strace.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/intrin/describeflags.internal.h"
|
||||
#include "libc/intrin/kprintf.h"
|
||||
#include "libc/runtime/internal.h"
|
||||
|
@ -35,15 +36,17 @@
|
|||
* @return 0 on success, or -1 w/ errno
|
||||
* @see mmap()
|
||||
*/
|
||||
privileged int mprotect(void *addr, size_t size, int prot) {
|
||||
int mprotect(void *addr, size_t size, int prot) {
|
||||
int64_t rc;
|
||||
if (SupportsWindows() && (prot & ~(PROT_READ | PROT_WRITE | PROT_EXEC |
|
||||
PROT_GROWSDOWN | PROT_GROWSUP))) {
|
||||
rc = einval(); // unix checks prot before checking size
|
||||
errno = EINVAL; // unix checks prot before checking size
|
||||
rc = -1;
|
||||
} else if (!size) {
|
||||
return 0; // make new technology consistent with unix
|
||||
} else if (UNLIKELY((intptr_t)addr & 4095)) {
|
||||
rc = einval();
|
||||
errno = EINVAL; // unix checks prot before checking size
|
||||
rc = -1;
|
||||
} else if (!IsWindows()) {
|
||||
rc = sys_mprotect(addr, size, prot);
|
||||
} else {
|
||||
|
|
|
@ -28,10 +28,12 @@ extern unsigned char _etext[] forcealign(PAGESIZE); /* αpε */
|
|||
extern unsigned char _edata[] forcealign(PAGESIZE); /* αpε */
|
||||
extern unsigned char _ezip[]; /* αpε */
|
||||
extern unsigned char _end[] forcealign(FRAMESIZE); /* αpε */
|
||||
extern unsigned char _ereal; /* αpε */
|
||||
extern unsigned char __privileged_start; /* αpε */
|
||||
extern unsigned char __test_start; /* αpε */
|
||||
extern unsigned char __ro; /* αpε */
|
||||
extern unsigned char _ereal[]; /* αpε */
|
||||
extern unsigned char __privileged_start[]; /* αpε */
|
||||
extern unsigned char __privileged_addr[]; /* αpε */
|
||||
extern unsigned char __privileged_size[]; /* αpε */
|
||||
extern unsigned char __test_start[]; /* αpε */
|
||||
extern unsigned char __ro[]; /* αpε */
|
||||
extern unsigned char *__relo_start[]; /* αpε */
|
||||
extern unsigned char *__relo_end[]; /* αpε */
|
||||
extern uint8_t __zip_start[]; /* αpε */
|
||||
|
@ -105,6 +107,10 @@ char *GetInterpreterExecutableName(char *, size_t);
|
|||
void __printargs(const char *);
|
||||
void __paginate(int, const char *);
|
||||
int __arg_max(void);
|
||||
void __morph_begin(void);
|
||||
void __morph_end(void);
|
||||
unsigned char *GetFirstInstruction(void);
|
||||
unsigned char *GetInstructionLengths(void);
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
|
|
|
@ -43,7 +43,8 @@ LIBC_RUNTIME_A_DIRECTDEPS = \
|
|||
LIBC_STR \
|
||||
LIBC_STUBS \
|
||||
LIBC_SYSV \
|
||||
LIBC_SYSV_CALLS
|
||||
LIBC_SYSV_CALLS \
|
||||
THIRD_PARTY_XED
|
||||
|
||||
LIBC_RUNTIME_A_DEPS := \
|
||||
$(call uniq,$(foreach x,$(LIBC_RUNTIME_A_DIRECTDEPS),$($(x))))
|
||||
|
@ -64,11 +65,13 @@ o/$(MODE)/libc/runtime/directmap.o \
|
|||
o/$(MODE)/libc/runtime/directmapnt.o \
|
||||
o/$(MODE)/libc/runtime/findmemoryinterval.o \
|
||||
o/$(MODE)/libc/runtime/ftrace.greg.o \
|
||||
o/$(MODE)/libc/runtime/sys_mprotect.greg.o \
|
||||
o/$(MODE)/libc/runtime/ftracer.o \
|
||||
o/$(MODE)/libc/runtime/ezmap.o \
|
||||
o/$(MODE)/libc/runtime/getdosargv.o \
|
||||
o/$(MODE)/libc/runtime/getdosenviron.o \
|
||||
o/$(MODE)/libc/runtime/hook.greg.o \
|
||||
o/$(MODE)/libc/runtime/morph.greg.o \
|
||||
o/$(MODE)/libc/runtime/mprotect.greg.o \
|
||||
o/$(MODE)/libc/runtime/mprotect-nt.greg.o \
|
||||
o/$(MODE)/libc/runtime/ismemtracked.greg.o \
|
||||
|
@ -85,6 +88,7 @@ o/$(MODE)/libc/runtime/winmain.greg.o \
|
|||
o/$(MODE)/libc/runtime/opensymboltable.o \
|
||||
o/$(MODE)/libc/runtime/getsymboltable.greg.o: \
|
||||
OVERRIDE_CFLAGS += \
|
||||
-Os \
|
||||
-ffreestanding \
|
||||
$(NO_MAGIC)
|
||||
|
||||
|
|
|
@ -53,7 +53,7 @@ vfork:
|
|||
call __stracef
|
||||
#endif /* SYSDEBUG */
|
||||
mov __NR_vfork(%rip),%eax
|
||||
mov errno(%rip),%r8d # avoid question of @vforksafe errno
|
||||
mov __errno(%rip),%r8d # avoid question of @vforksafe errno
|
||||
pop %rsi # saves return address in a register
|
||||
#if SupportsBsd()
|
||||
testb IsBsd()
|
||||
|
@ -65,7 +65,7 @@ vfork:
|
|||
cmp $-4095,%eax
|
||||
jae systemfive_error
|
||||
#endif
|
||||
0: mov %r8d,errno(%rip)
|
||||
0: mov %r8d,__errno(%rip)
|
||||
ezlea __vforked,di
|
||||
test %eax,%eax
|
||||
jz 1f
|
||||
|
|
|
@ -216,7 +216,7 @@ __msabi static textwindows wontreturn void WinMainNew(const char16_t *cmdline) {
|
|||
_mmi.p[0].x = allocaddr >> 16;
|
||||
_mmi.p[0].y = (allocaddr >> 16) + ((allocsize >> 16) - 1);
|
||||
_mmi.p[0].prot = prot;
|
||||
_mmi.p[0].flags = MAP_PRIVATE | MAP_ANONYMOUS;
|
||||
_mmi.p[0].flags = 0x00000026; // stack+anonymous
|
||||
_mmi.p[0].size = allocsize;
|
||||
_mmi.i = 1;
|
||||
wa = (struct WinArgs *)allocaddr;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue