Support thread local storage

This commit is contained in:
Justine Tunney 2022-05-16 13:20:08 -07:00
parent 91ee2b19d4
commit 55de4ca6b5
197 changed files with 1483 additions and 874 deletions

View file

@ -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:

View file

@ -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;
}

View file

@ -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;
}

View 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;
}

View file

@ -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
View 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);
}
}

View file

@ -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 {

View file

@ -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) */

View file

@ -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)

View file

@ -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

View file

@ -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;