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

@ -8,6 +8,7 @@
*/
#endif
#include "libc/log/log.h"
#include "libc/runtime/symbols.internal.h"
/**
* @fileoverview How to print backtraces and cpu state on crash.

View file

@ -143,14 +143,6 @@ o/$(MODE)/examples/nesemu1.com: \
@$(COMPILE) -AZIP -T$@ o/$(MODE)/third_party/zip/zip.com -0qj $@ \
o/$(MODE)/examples/.nesemu1/.symtab
o/$(MODE)/examples/hello.com.dbg: \
$(EXAMPLES_DEPS) \
o/$(MODE)/examples/hello.o \
o/$(MODE)/examples/examples.pkg \
$(CRT) \
$(APE_NO_MODIFY_SELF)
@$(APELINK)
o/$(MODE)/examples/nesemu1.o: QUOTA += -M512m
$(EXAMPLES_OBJS): examples/examples.mk

View file

@ -16,6 +16,7 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/assert.h"
#include "libc/bits/atomic.h"
#include "libc/calls/calls.h"
#include "libc/calls/sigbits.h"
@ -27,6 +28,7 @@
#include "libc/intrin/kprintf.h"
#include "libc/log/check.h"
#include "libc/log/log.h"
#include "libc/macros.internal.h"
#include "libc/mem/mem.h"
#include "libc/runtime/runtime.h"
#include "libc/sock/goodsocket.internal.h"
@ -90,7 +92,8 @@
*
*/
#define THREADS 512
#define PORT 8080
#define THREADS 10000
#define HEARTBEAT 100
#define KEEPALIVE 5000
#define LOGGING 0
@ -100,120 +103,39 @@
"Referrer-Policy: origin\r\n" \
"Cache-Control: private; max-age=0\r\n"
////////////////////////////////////////////////////////////////////////////////
// BEGIN: Chris Wellons's Public Domain GNU Atomics Library
#define BARRIER_INC(x) __atomic_add_fetch(x, 1, __ATOMIC_SEQ_CST)
#define BARRIER_GET(x) __atomic_load_n(x, __ATOMIC_SEQ_CST)
#define ATOMIC_LOAD(q) __atomic_load_n(q, __ATOMIC_ACQUIRE)
#define ATOMIC_RLOAD(q) __atomic_load_n(q, __ATOMIC_RELAXED)
#define ATOMIC_STORE(q, v) __atomic_store_n(q, v, __ATOMIC_RELEASE)
#define ATOMIC_ADD(q, c) __atomic_add_fetch(q, c, __ATOMIC_RELEASE)
#define ATOMIC_AND(q, m) __atomic_and_fetch(q, m, __ATOMIC_RELEASE)
#define ATOMIC_CAS(q, e, d) \
__atomic_compare_exchange_n(q, e, d, 0, __ATOMIC_RELEASE, __ATOMIC_RELAXED)
// Return the array index for then next value to be pushed. The size of this
// array must be (1 << exp) elements. Write the value into this array index,
// then commit it. With a single-consumer queue, this element store need not
// be atomic. The value will appear in the queue after the commit. Returns
// -1 if the queue is full.
static int queue_push(uint32_t *q, int exp) {
uint32_t r = ATOMIC_LOAD(q);
int mask = (1u << exp) - 1;
int head = r & mask;
int tail = r >> 16 & mask;
int next = (head + 1u) & mask;
if (r & 0x8000) { // avoid overflow on commit
ATOMIC_AND(q, ~0x8000);
}
return next == tail ? -1 : head;
}
// Commits and completes the push operation. Do this after storing into the
// array. This operation cannot fail.
static void queue_push_commit(uint32_t *q) {
ATOMIC_ADD(q, 1);
}
// Return the array index for the next value to be popped. The size of this
// array must be (1 << exp) elements. Read from this array index, then
// commit the pop. This element load need not be atomic. The value will be
// removed from the queue after the commit. Returns -1 if the queue is
// empty.
static int queue_pop(uint32_t *q, int exp) {
uint32_t r = ATOMIC_LOAD(q);
int mask = (1u << exp) - 1;
int head = r & mask;
int tail = r >> 16 & mask;
return head == tail ? -1 : tail;
}
// Commits and completes the pop operation. Do this after loading from the
// array. This operation cannot fail.
static void queue_pop_commit(uint32_t *q) {
ATOMIC_ADD(q, 0x10000);
}
// Like queue_pop() but for multiple-consumer queues. The element load must
// be atomic since it is concurrent with the producer's push, though it can
// use a relaxed memory order. The loaded value must not be used unless the
// commit is successful. Stores a temporary "save" to be used at commit.
static int queue_mpop(uint32_t *q, int exp, uint32_t *save) {
uint32_t r = *save = ATOMIC_LOAD(q);
int mask = (1u << exp) - 1;
int head = r & mask;
int tail = r >> 16 & mask;
return head == tail ? -1 : tail;
}
// Like queue_pop_commit() but for multiple-consumer queues. It may fail if
// another consumer pops concurrently, in which case the pop must be retried
// from the beginning.
static bool queue_mpop_commit(uint32_t *q, uint32_t save) {
return ATOMIC_CAS(q, &save, save + 0x10000);
}
// Spin-lock barrier for n threads, where n is a power of two.
// Initialize *barrier to zero.
static void barrier_waitn(int *barrier, int n) {
int v = BARRIER_INC(barrier);
if (v & (n - 1)) {
for (v &= n; (BARRIER_GET(barrier) & n) == v;) {
donothing;
}
}
}
// END: Chris Wellons's Public Domain GNU Atomics Library
////////////////////////////////////////////////////////////////////////////////
int barrier1;
int itsbegun;
int workers;
int messages;
int connections;
int closingtime;
int barrier2;
int itsdone;
const char *status;
int Worker(void *id) {
int server, yes = 1;
kprintf(" %d", id);
barrier_waitn(&barrier1, THREADS);
itsbegun = true;
// load balance incoming connections for port 8080 across all threads
// hangup on any browser clients that lag for more than a few seconds
struct timeval timeo = {KEEPALIVE / 1000, KEEPALIVE % 1000};
struct sockaddr_in addr = {.sin_family = AF_INET, .sin_port = htons(8080)};
CHECK_NE(-1, (server = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)));
struct sockaddr_in addr = {.sin_family = AF_INET, .sin_port = htons(PORT)};
server = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (server == -1) {
if (LOGGING) kprintf("%s() failed %m\n", "socket");
goto WorkerFinished;
}
setsockopt(server, SOL_SOCKET, SO_RCVTIMEO, &timeo, sizeof(timeo));
setsockopt(server, SOL_SOCKET, SO_SNDTIMEO, &timeo, sizeof(timeo));
setsockopt(server, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes));
setsockopt(server, SOL_SOCKET, SO_REUSEPORT, &yes, sizeof(yes));
setsockopt(server, SOL_TCP, TCP_FASTOPEN, &yes, sizeof(yes));
setsockopt(server, SOL_TCP, TCP_QUICKACK, &yes, sizeof(yes));
CHECK_EQ(0, bind(server, &addr, sizeof(addr)));
CHECK_EQ(0, listen(server, 10));
if (bind(server, &addr, sizeof(addr)) == -1) {
if (LOGGING) kprintf("%s() failed %m\n", "socket");
goto WorkerFinished;
}
listen(server, 10);
// connection loop
while (!closingtime) {
@ -228,8 +150,12 @@ int Worker(void *id) {
char inbuf[1500], outbuf[512], *p, *q;
int clientip, client, inmsglen, outmsglen;
if (!IsLinux() &&
poll(&(struct pollfd){server, POLLIN}, 1, HEARTBEAT) < 1) {
continue;
}
// wait for client connection
if (poll(&(struct pollfd){server, POLLIN}, 1, HEARTBEAT) < 1) continue;
clientaddrsize = sizeof(clientaddr);
client = accept(server, &clientaddr, &clientaddrsize);
@ -245,6 +171,8 @@ int Worker(void *id) {
continue;
}
asm volatile("lock incl\t%0" : "+m"(connections));
// message loop
do {
// parse the incoming http message
@ -253,6 +181,7 @@ int Worker(void *id) {
if ((got = read(client, inbuf, sizeof(inbuf))) <= 0) break;
// check that client message wasn't fragmented into more reads
if (!(inmsglen = ParseHttpMessage(&msg, inbuf, got))) break;
asm volatile("lock incl\t%0" : "+m"(messages));
#if LOGGING
// log the incoming http message
@ -313,35 +242,46 @@ int Worker(void *id) {
(msg.method == kHttpGet || msg.method == kHttpHead));
DestroyHttpMessage(&msg);
close(client);
asm volatile("lock decl\t%0" : "+m"(connections));
}
// inform the parent that this clone has finished
WorkerFinished:
close(server);
kprintf(" %d", id);
barrier_waitn(&barrier2, THREADS);
itsdone = true;
asm volatile("lock decl\t%0" : "+m"(workers));
return 0;
}
void OnCtrlC(int sig) {
closingtime = true;
status = " shutting down...";
}
int main(int argc, char *argv[]) {
/* ShowCrashReports(); */
int64_t loadtzdbearly;
kprintf("welcome to greenbean\n");
gmtime(&loadtzdbearly);
for (int i = 0; i < THREADS; ++i) {
int i;
uint32_t *hostips;
ShowCrashReports();
sigaction(SIGINT, &(struct sigaction){.sa_handler = OnCtrlC}, 0);
for (hostips = GetHostIps(), i = 0; hostips[i]; ++i) {
kprintf("listening on http://%d.%d.%d.%d:%d\n",
(hostips[i] & 0xff000000) >> 030, (hostips[i] & 0x00ff0000) >> 020,
(hostips[i] & 0x0000ff00) >> 010, (hostips[i] & 0x000000ff) >> 000,
PORT);
}
workers = THREADS;
for (i = 0; i < THREADS; ++i) {
void *stack = mmap(0, 65536, PROT_READ | PROT_WRITE,
MAP_STACK | MAP_ANONYMOUS, -1, 0);
clone(Worker, stack, 65536,
CLONE_THREAD | CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND,
(void *)(intptr_t)i, 0, 0, 0, 0);
}
while (!ATOMIC_LOAD(&itsbegun)) usleep(HEARTBEAT * 1000);
sigaction(SIGINT, &(struct sigaction){.sa_handler = OnCtrlC}, 0);
kprintf("\nit's begun\n");
while (!ATOMIC_LOAD(&itsdone)) usleep(HEARTBEAT * 1000);
kprintf("\nthank you for flying greenbean\n");
status = "";
while (workers) {
kprintf(
"\r\e[K\e[32mgreenbean\e[0m workers=%d connections=%d messages=%d%s ",
workers, connections, messages, status);
usleep(HEARTBEAT * 1000);
}
kprintf("\r\e[K");
}

View file

@ -65,10 +65,21 @@ $(LIBC_CALLS_A).pkg: \
$(LIBC_CALLS_A_OBJS) \
$(foreach x,$(LIBC_CALLS_A_DIRECTDEPS),$($(x)_A).pkg)
o/$(MODE)/libc/calls/sigenter-freebsd.o \
o/$(MODE)/libc/calls/sigenter-netbsd.o \
o/$(MODE)/libc/calls/sigenter-openbsd.o \
o/$(MODE)/libc/calls/sigenter-xnu.o: \
OVERRIDE_COPTS += \
-mno-fentry \
-fno-stack-protector \
-fno-sanitize=all
o/$(MODE)/libc/calls/sys_mprotect.greg.o \
o/$(MODE)/libc/calls/vdsofunc.greg.o \
o/$(MODE)/libc/calls/directmap.o \
o/$(MODE)/libc/calls/directmap-nt.o \
o/$(MODE)/libc/calls/mapstack.greg.o \
o/$(MODE)/libc/calls/execve-nt.greg.o \
o/$(MODE)/libc/calls/getcwd.greg.o \
o/$(MODE)/libc/calls/getcwd-xnu.greg.o \
o/$(MODE)/libc/calls/getprogramexecutablename.greg.o \
@ -114,7 +125,7 @@ o/$(MODE)/libc/calls/execl.o \
o/$(MODE)/libc/calls/execle.o \
o/$(MODE)/libc/calls/execlp.o \
o/$(MODE)/libc/calls/copyfile.o \
o/$(MODE)/libc/calls/execve-nt.o \
o/$(MODE)/libc/calls/execve-nt.greg.o \
o/$(MODE)/libc/calls/linkat-nt.o \
o/$(MODE)/libc/calls/renameat-nt.o \
o/$(MODE)/libc/calls/execve-sysv.o \

View file

@ -16,44 +16,95 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#define ShouldUseMsabiAttribute() 1
#include "libc/bits/weaken.h"
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/calls/ntspawn.h"
#include "libc/calls/strace.internal.h"
#include "libc/mem/alloca.h"
#include "libc/nt/accounting.h"
#include "libc/nt/console.h"
#include "libc/nt/enum/startf.h"
#include "libc/nt/enum/status.h"
#include "libc/nt/memory.h"
#include "libc/nt/runtime.h"
#include "libc/nt/struct/processinformation.h"
#include "libc/nt/struct/startupinfo.h"
#include "libc/nt/synchronization.h"
#include "libc/nt/thunk/msabi.h"
#include "libc/runtime/memtrack.internal.h"
#include "libc/runtime/runtime.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/at.h"
#include "libc/sysv/consts/map.h"
#include "libc/sysv/consts/o.h"
#include "libc/sysv/consts/ok.h"
#include "libc/sysv/errfuns.h"
__msabi extern typeof(CloseHandle) *const __imp_CloseHandle;
__msabi extern typeof(WaitForSingleObject) *const __imp_WaitForSingleObject;
__msabi extern typeof(GetExitCodeProcess) *const __imp_GetExitCodeProcess;
__msabi extern typeof(UnmapViewOfFile) *const __imp_UnmapViewOfFile;
static noinstrument __msabi bool32
BlockExecveConsoleEvent(uint32_t dwCtrlType) {
// block SIGINT and SIGQUIT in execve() parent process
return true;
}
textwindows int sys_execve_nt(const char *program, char *const argv[],
char *const envp[]) {
int rc;
size_t i;
uint32_t dwExitCode;
struct MemoryIntervals *mm;
struct NtStartupInfo startinfo;
struct NtProcessInformation procinfo;
// this is a non-recoverable operation, so do some manual validation
if (sys_faccessat_nt(AT_FDCWD, program, X_OK, 0) == -1) {
return eacces();
}
//////////////////////////////////////////////////////////////////////////////
// execve operation is unrecoverable from this point
// close cloexec handles
for (i = 3; i < g_fds.n; ++i) {
if (g_fds.p[i].kind != kFdEmpty && (g_fds.p[i].flags & O_CLOEXEC)) {
__imp_CloseHandle(g_fds.p[i].handle);
}
}
bzero(&startinfo, sizeof(startinfo));
startinfo.cb = sizeof(struct NtStartupInfo);
startinfo.dwFlags = kNtStartfUsestdhandles;
startinfo.hStdInput = __getfdhandleactual(0);
startinfo.hStdOutput = __getfdhandleactual(1);
startinfo.hStdError = __getfdhandleactual(2);
// spawn the process
rc = ntspawn(program, argv, envp, 0, 0, 0, 1, 0, 0, &startinfo, &procinfo);
if (rc == -1) return -1;
CloseHandle(g_fds.p[0].handle);
CloseHandle(g_fds.p[1].handle);
CloseHandle(procinfo.hThread);
if (rc == -1) {
STRACE("panic: unrecoverable ntspawn(%#s) error: %m", program);
__imp_ExitProcess(6543);
}
//////////////////////////////////////////////////////////////////////////////
// zombie shell process remains, to wait for child and propagate its exit
// code
__imp_CloseHandle(g_fds.p[0].handle);
__imp_CloseHandle(g_fds.p[1].handle);
__imp_CloseHandle(procinfo.hThread);
__imp_SetConsoleCtrlHandler((void *)BlockExecveConsoleEvent, 1);
do {
WaitForSingleObject(procinfo.hProcess, -1);
__imp_WaitForSingleObject(procinfo.hProcess, -1);
dwExitCode = kNtStillActive;
GetExitCodeProcess(procinfo.hProcess, &dwExitCode);
__imp_GetExitCodeProcess(procinfo.hProcess, &dwExitCode);
} while (dwExitCode == kNtStillActive);
CloseHandle(procinfo.hProcess);
_Exit(dwExitCode);
__imp_CloseHandle(procinfo.hProcess);
__imp_ExitProcess(dwExitCode);
unreachable;
}

View file

@ -63,11 +63,6 @@ int execve(const char *prog, char *const argv[], char *const envp[]) {
kprintf("})\n");
}
#endif
for (i = 3; i < g_fds.n; ++i) {
if (g_fds.p[i].kind != kFdEmpty && (g_fds.p[i].flags & O_CLOEXEC)) {
close(i);
}
}
if (!IsWindows()) {
rc = sys_execve(prog, argv, envp);
} else {

View file

@ -134,6 +134,7 @@ i32 __sys_pipe2(i32[hasatleast 2], u32) hidden;
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_arch_prctl(i32, i64) hidden;
i32 sys_chdir(const char *) hidden;
i32 sys_chroot(const char *) hidden;
i32 sys_clock_gettime(i32, struct timespec *) hidden;

View file

@ -18,10 +18,11 @@
*/
#include "libc/calls/internal.h"
#include "libc/calls/ucontext.h"
#include "libc/log/libfatal.internal.h"
#include "libc/nt/struct/context.h"
#include "libc/str/str.h"
textwindows void _ntcontext2linux(ucontext_t *ctx, const struct NtContext *cr) {
privileged void _ntcontext2linux(ucontext_t *ctx, const struct NtContext *cr) {
if (!cr) return;
ctx->uc_flags = cr->EFlags;
ctx->uc_mcontext.eflags = cr->EFlags;
@ -46,10 +47,10 @@ textwindows void _ntcontext2linux(ucontext_t *ctx, const struct NtContext *cr) {
ctx->uc_mcontext.gs = cr->SegGs;
ctx->uc_mcontext.fs = cr->SegFs;
ctx->uc_mcontext.fpregs = &ctx->__fpustate;
memcpy(&ctx->__fpustate, &cr->FltSave, sizeof(ctx->__fpustate));
__repmovsb(&ctx->__fpustate, &cr->FltSave, sizeof(ctx->__fpustate));
}
textwindows void _ntlinux2context(struct NtContext *cr, const ucontext_t *ctx) {
privileged void _ntlinux2context(struct NtContext *cr, const ucontext_t *ctx) {
if (!cr) return;
cr->EFlags = ctx->uc_flags;
cr->EFlags = ctx->uc_mcontext.eflags;
@ -73,5 +74,5 @@ textwindows void _ntlinux2context(struct NtContext *cr, const ucontext_t *ctx) {
cr->SegCs = ctx->uc_mcontext.cs;
cr->SegGs = ctx->uc_mcontext.gs;
cr->SegFs = ctx->uc_mcontext.fs;
memcpy(&cr->FltSave, &ctx->__fpustate, sizeof(ctx->__fpustate));
__repmovsb(&cr->FltSave, &ctx->__fpustate, sizeof(ctx->__fpustate));
}

View file

@ -22,6 +22,7 @@
#include "libc/calls/strace.internal.h"
#include "libc/intrin/cmpxchg.h"
#include "libc/intrin/spinlock.h"
#include "libc/log/libfatal.internal.h"
#include "libc/macros.internal.h"
#include "libc/runtime/internal.h"
#include "libc/runtime/runtime.h"
@ -90,8 +91,8 @@ static textwindows struct Signal *__sig_remove(void) {
* @note called from main thread
* @return true if EINTR should be returned by caller
*/
static textwindows bool __sig_deliver(bool restartable, int sig, int si_code,
ucontext_t *ctx) {
static privileged bool __sig_deliver(bool restartable, int sig, int si_code,
ucontext_t *ctx) {
unsigned rva, flags;
siginfo_t info, *infop;
STRACE("delivering %G", sig);
@ -113,7 +114,7 @@ static textwindows bool __sig_deliver(bool restartable, int sig, int si_code,
// setup the somewhat expensive information args
// only if they're requested by the user in sigaction()
if (flags & SA_SIGINFO) {
bzero(&info, sizeof(info));
__repstosb(&info, 0, sizeof(info));
info.si_signo = sig;
info.si_code = si_code;
infop = &info;
@ -162,8 +163,8 @@ static textwindows bool __sig_isfatal(int sig) {
* @param restartable can be used to suppress true return if SA_RESTART
* @return true if signal was delivered
*/
textwindows bool __sig_handle(bool restartable, int sig, int si_code,
ucontext_t *ctx) {
privileged bool __sig_handle(bool restartable, int sig, int si_code,
ucontext_t *ctx) {
bool delivered;
switch (__sighandrvas[sig]) {
case (intptr_t)SIG_DFL:

View file

@ -25,13 +25,13 @@
#include "libc/calls/typedef/sigaction_f.h"
#include "libc/calls/ucontext.h"
#include "libc/intrin/kprintf.h"
#include "libc/intrin/repstosb.h"
#include "libc/log/libfatal.internal.h"
#include "libc/macros.internal.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/sa.h"
void __sigenter_freebsd(int sig, struct siginfo_freebsd *freebsdinfo,
struct ucontext_freebsd *ctx) {
privileged void __sigenter_freebsd(int sig, struct siginfo_freebsd *freebsdinfo,
struct ucontext_freebsd *ctx) {
int rva, flags;
struct Goodies {
ucontext_t uc;
@ -43,14 +43,14 @@ void __sigenter_freebsd(int sig, struct siginfo_freebsd *freebsdinfo,
if (~flags & SA_SIGINFO) {
((sigaction_f)(_base + rva))(sig, 0, 0);
} else {
repstosb(&g, 0, sizeof(g));
__repstosb(&g, 0, sizeof(g));
g.uc.uc_mcontext.fpregs = &g.uc.__fpustate;
g.uc.uc_stack.ss_sp = ctx->uc_stack.ss_sp;
g.uc.uc_stack.ss_size = ctx->uc_stack.ss_size;
g.uc.uc_stack.ss_flags = ctx->uc_stack.ss_flags;
g.uc.uc_flags = ctx->uc_flags;
memcpy(&g.uc.uc_sigmask, &ctx->uc_sigmask,
MIN(sizeof(g.uc.uc_sigmask), sizeof(ctx->uc_sigmask)));
__repmovsb(&g.uc.uc_sigmask, &ctx->uc_sigmask,
MIN(sizeof(g.uc.uc_sigmask), sizeof(ctx->uc_sigmask)));
g.uc.uc_mcontext.r8 = ctx->uc_mcontext.mc_r8;
g.uc.uc_mcontext.r9 = ctx->uc_mcontext.mc_r9;
g.uc.uc_mcontext.r10 = ctx->uc_mcontext.mc_r10;
@ -73,7 +73,7 @@ void __sigenter_freebsd(int sig, struct siginfo_freebsd *freebsdinfo,
g.uc.uc_mcontext.gs = ctx->uc_mcontext.mc_gs;
g.uc.uc_mcontext.err = ctx->uc_mcontext.mc_err;
g.uc.uc_mcontext.trapno = ctx->uc_mcontext.mc_trapno;
memcpy(&g.uc.__fpustate, &ctx->uc_mcontext.mc_fpstate, 512);
__repmovsb(&g.uc.__fpustate, &ctx->uc_mcontext.mc_fpstate, 512);
g.si.si_signo = freebsdinfo->si_signo;
g.si.si_errno = freebsdinfo->si_errno;
g.si.si_code = freebsdinfo->si_code;
@ -89,8 +89,8 @@ void __sigenter_freebsd(int sig, struct siginfo_freebsd *freebsdinfo,
ctx->uc_stack.ss_size = g.uc.uc_stack.ss_size;
ctx->uc_stack.ss_flags = g.uc.uc_stack.ss_flags;
ctx->uc_flags = g.uc.uc_flags;
memcpy(&ctx->uc_sigmask, &g.uc.uc_sigmask,
MIN(sizeof(g.uc.uc_sigmask), sizeof(ctx->uc_sigmask)));
__repmovsb(&ctx->uc_sigmask, &g.uc.uc_sigmask,
MIN(sizeof(g.uc.uc_sigmask), sizeof(ctx->uc_sigmask)));
ctx->uc_mcontext.mc_rdi = g.uc.uc_mcontext.rdi;
ctx->uc_mcontext.mc_rsi = g.uc.uc_mcontext.rsi;
ctx->uc_mcontext.mc_rdx = g.uc.uc_mcontext.rdx;
@ -113,7 +113,7 @@ void __sigenter_freebsd(int sig, struct siginfo_freebsd *freebsdinfo,
ctx->uc_mcontext.mc_err = g.uc.uc_mcontext.err;
ctx->uc_mcontext.mc_rip = g.uc.uc_mcontext.rip;
ctx->uc_mcontext.mc_rsp = g.uc.uc_mcontext.rsp;
memcpy(&ctx->uc_mcontext.mc_fpstate, &g.uc.__fpustate, 512);
__repmovsb(&ctx->uc_mcontext.mc_fpstate, &g.uc.__fpustate, 512);
}
}
/*

View file

@ -24,12 +24,13 @@
#include "libc/calls/struct/ucontext-netbsd.internal.h"
#include "libc/calls/typedef/sigaction_f.h"
#include "libc/calls/ucontext.h"
#include "libc/log/libfatal.internal.h"
#include "libc/macros.internal.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/sa.h"
void __sigenter_netbsd(int sig, struct siginfo_netbsd *si,
struct ucontext_netbsd *ctx) {
privileged void __sigenter_netbsd(int sig, struct siginfo_netbsd *si,
struct ucontext_netbsd *ctx) {
int rva, flags;
ucontext_t uc;
struct siginfo si2;
@ -39,8 +40,8 @@ void __sigenter_netbsd(int sig, struct siginfo_netbsd *si,
if (~flags & SA_SIGINFO) {
((sigaction_f)(_base + rva))(sig, 0, 0);
} else {
bzero(&uc, sizeof(uc));
bzero(&si2, sizeof(si2));
__repstosb(&uc, 0, sizeof(uc));
__repstosb(&si2, 0, sizeof(si2));
si2.si_signo = si->si_signo;
si2.si_code = si->si_code;
si2.si_errno = si->si_errno;
@ -52,8 +53,8 @@ void __sigenter_netbsd(int sig, struct siginfo_netbsd *si,
uc.uc_stack.ss_sp = ctx->uc_stack.ss_sp;
uc.uc_stack.ss_size = ctx->uc_stack.ss_size;
uc.uc_stack.ss_flags = ctx->uc_stack.ss_flags;
memcpy(&uc.uc_sigmask, &ctx->uc_sigmask,
MIN(sizeof(uc.uc_sigmask), sizeof(ctx->uc_sigmask)));
__repmovsb(&uc.uc_sigmask, &ctx->uc_sigmask,
MIN(sizeof(uc.uc_sigmask), sizeof(ctx->uc_sigmask)));
uc.uc_mcontext.rdi = ctx->uc_mcontext.rdi;
uc.uc_mcontext.rsi = ctx->uc_mcontext.rsi;
uc.uc_mcontext.rdx = ctx->uc_mcontext.rdx;

View file

@ -24,13 +24,13 @@
#include "libc/calls/struct/ucontext-openbsd.internal.h"
#include "libc/calls/typedef/sigaction_f.h"
#include "libc/calls/ucontext.h"
#include "libc/intrin/repstosb.h"
#include "libc/log/libfatal.internal.h"
#include "libc/macros.internal.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/sa.h"
void __sigenter_openbsd(int sig, struct siginfo_openbsd *openbsdinfo,
struct ucontext_openbsd *ctx) {
privileged void __sigenter_openbsd(int sig, struct siginfo_openbsd *openbsdinfo,
struct ucontext_openbsd *ctx) {
int rva, flags;
struct Goodies {
ucontext_t uc;
@ -42,7 +42,7 @@ void __sigenter_openbsd(int sig, struct siginfo_openbsd *openbsdinfo,
if (~flags & SA_SIGINFO) {
((sigaction_f)(_base + rva))(sig, 0, 0);
} else {
repstosb(&g, 0, sizeof(g));
__repstosb(&g, 0, sizeof(g));
g.si.si_signo = openbsdinfo->si_signo;
g.si.si_code = openbsdinfo->si_code;
g.si.si_errno = openbsdinfo->si_errno;
@ -54,8 +54,8 @@ void __sigenter_openbsd(int sig, struct siginfo_openbsd *openbsdinfo,
}
g.si.si_value = openbsdinfo->si_value;
g.uc.uc_mcontext.fpregs = &g.uc.__fpustate;
memcpy(&g.uc.uc_sigmask, &ctx->sc_mask,
MIN(sizeof(g.uc.uc_sigmask), sizeof(ctx->sc_mask)));
__repmovsb(&g.uc.uc_sigmask, &ctx->sc_mask,
MIN(sizeof(g.uc.uc_sigmask), sizeof(ctx->sc_mask)));
g.uc.uc_mcontext.rdi = ctx->sc_rdi;
g.uc.uc_mcontext.rsi = ctx->sc_rsi;
g.uc.uc_mcontext.rdx = ctx->sc_rdx;

View file

@ -25,6 +25,7 @@
#include "libc/calls/ucontext.h"
#include "libc/intrin/kprintf.h"
#include "libc/intrin/repstosb.h"
#include "libc/log/libfatal.internal.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/sa.h"
@ -355,19 +356,19 @@ struct __darwin_ucontext {
struct __darwin_mcontext64 *uc_mcontext;
};
noasan static void xnuexceptionstate2linux(
static privileged void xnuexceptionstate2linux(
mcontext_t *mc, struct __darwin_x86_exception_state64 *xnues) {
mc->trapno = xnues->__trapno;
mc->err = xnues->__err;
}
noasan static void linuxexceptionstate2xnu(
static privileged void linuxexceptionstate2xnu(
struct __darwin_x86_exception_state64 *xnues, mcontext_t *mc) {
xnues->__trapno = mc->trapno;
xnues->__err = mc->err;
}
noasan static void xnuthreadstate2linux(
static privileged void xnuthreadstate2linux(
mcontext_t *mc, struct __darwin_x86_thread_state64 *xnuss) {
mc->rdi = xnuss->__rdi;
mc->rsi = xnuss->__rsi;
@ -392,7 +393,7 @@ noasan static void xnuthreadstate2linux(
mc->r15 = xnuss->__r15;
}
noasan static void linuxthreadstate2xnu(
static privileged void linuxthreadstate2xnu(
struct __darwin_x86_thread_state64 *xnuss, ucontext_t *uc, mcontext_t *mc) {
xnuss->__rdi = mc->rdi;
xnuss->__rsi = mc->rsi;
@ -417,14 +418,14 @@ noasan static void linuxthreadstate2xnu(
xnuss->__r15 = mc->r15;
}
noasan static void CopyFpXmmRegs(void *d, const void *s) {
static privileged void CopyFpXmmRegs(void *d, const void *s) {
size_t i;
for (i = 0; i < (8 + 16) * 16; i += 16) {
__builtin_memcpy((char *)d + i, (const char *)s + i, 16);
}
}
noasan static void xnussefpustate2linux(
static privileged void xnussefpustate2linux(
struct FpuState *fs, struct __darwin_x86_float_state64 *xnufs) {
fs->cwd = xnufs->__fpu_fcw;
fs->swd = xnufs->__fpu_fsw;
@ -437,7 +438,7 @@ noasan static void xnussefpustate2linux(
CopyFpXmmRegs(fs->st, &xnufs->__fpu_stmm0);
}
noasan static void linuxssefpustate2xnu(
static privileged void linuxssefpustate2xnu(
struct __darwin_x86_float_state64 *xnufs, struct FpuState *fs) {
xnufs->__fpu_fcw = fs->cwd;
xnufs->__fpu_fsw = fs->swd;
@ -450,9 +451,9 @@ noasan static void linuxssefpustate2xnu(
CopyFpXmmRegs(&xnufs->__fpu_stmm0, fs->st);
}
noasan void __sigenter_xnu(void *fn, int infostyle, int sig,
struct siginfo_xnu *xnuinfo,
struct __darwin_ucontext *xnuctx) {
privileged void __sigenter_xnu(void *fn, int infostyle, int sig,
struct siginfo_xnu *xnuinfo,
struct __darwin_ucontext *xnuctx) {
intptr_t ax;
int rva, flags;
struct Goodies {
@ -465,7 +466,7 @@ noasan void __sigenter_xnu(void *fn, int infostyle, int sig,
if (~flags & SA_SIGINFO) {
((sigaction_f)(_base + rva))(sig, 0, 0);
} else {
repstosb(&g, 0, sizeof(g));
__repstosb(&g, 0, sizeof(g));
if (xnuctx) {
g.uc.uc_flags = xnuctx->uc_onstack ? SA_ONSTACK : 0;
g.uc.uc_sigmask.__bits[0] = xnuctx->uc_sigmask;

View file

@ -30,7 +30,7 @@
#include "libc/sysv/consts/sicode.h"
#include "libc/sysv/consts/sig.h"
textwindows unsigned __wincrash(struct NtExceptionPointers *ep) {
privileged unsigned __wincrash(struct NtExceptionPointers *ep) {
int64_t rip;
int sig, code;
ucontext_t ctx;

View file

@ -8,7 +8,7 @@ COSMOPOLITAN_C_START_
* @see libc/sysv/consts.sh for numbers
*/
extern errno_t errno;
#define errno (*__errno_location())
/**
* System call unavailable.
@ -686,6 +686,10 @@ extern const long EXFULL;
#define EXDEV EXDEV
#define EXFULL EXFULL
extern errno_t __errno;
errno_t *__errno_location(void);
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_ERRNO_H_ */

View file

@ -16,8 +16,10 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/bits/weaken.h"
#include "libc/fmt/fmt.h"
#include "libc/limits.h"
#include "libc/log/log.h"
/**
* Formats string to buffer that's hopefully large enough.

View file

@ -66,6 +66,7 @@ o/$(MODE)/libc/intrin/kprintf.greg.o: \
o/$(MODE)/libc/intrin/tls.greg.o \
o/$(MODE)/libc/intrin/exit.greg.o \
o/$(MODE)/libc/intrin/errno.greg.o \
o/$(MODE)/libc/intrin/exit1.greg.o \
o/$(MODE)/libc/intrin/gettid.greg.o \
o/$(MODE)/libc/intrin/getenv.greg.o \

View file

@ -262,6 +262,7 @@ privileged static size_t kformat(char *b, size_t n, const char *fmt, va_list va,
continue;
case '#':
case '`':
hash = '0';
continue;

View file

@ -21,7 +21,7 @@
#define _seizelock(lock) \
do { \
typeof(*(lock)) x = 1; \
__atomic_store(lock, &x, __ATOMIC_SEQ_CST); \
__atomic_store(lock, &x, __ATOMIC_RELEASE); \
} while (0)
#define _spinlock_tiny(lock) \

View file

@ -3,6 +3,7 @@
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
extern bool __hastls;
extern bool __threaded;
COSMOPOLITAN_C_END_

View file

@ -83,6 +83,9 @@ void *TlsGetValue(uint32_t dwTlsIndex) {
: "=r"(lpTlsValue)
: "m"(*((long *)0x1480 + dwTlsIndex)));
return lpTlsValue;
// // this could also be written as...
// asm("movq\t%%gs:0x30,%0" : "=a"(tib));
// return (void *)tib[0x1480 / 8 + dwTlsIndex];
} else {
return __imp_TlsGetValue(dwTlsIndex);
}

View file

@ -74,15 +74,18 @@ static int PrintBacktraceUsingAddr2line(int fd, const struct StackFrame *bp) {
return -1;
}
/*
* DWARF is a weak standard. Platforms that use LLVM or old GNU
* usually can't be counted upon to print backtraces correctly.
*/
// DWARF is a weak standard. Platforms that use LLVM or old GNU
// usually can't be counted upon to print backtraces correctly.
if (!IsLinux() && !IsWindows()) {
ShowHint("won't print addr2line backtrace because probably llvm");
return -1;
}
if (IsWindows()) {
// TODO: We need a way to *not* pass //?/C:/... paths to mingw
return -1;
}
i = 0;
j = 0;
argv[i++] = "addr2line";

View file

@ -277,6 +277,7 @@ relegated noinstrument void __oncrash(int sig, struct siginfo *si,
intptr_t rip;
int gdbpid, err;
static bool noreentry, notpossible;
STRACE("__oncrash rip %x", ctx->uc_mcontext.rip);
__atomic_fetch_sub(&g_ftrace, 1, __ATOMIC_RELAXED);
__atomic_fetch_sub(&__strace, 1, __ATOMIC_RELAXED);
if (_lockcmpxchg(&noreentry, false, true)) {

View file

@ -124,6 +124,15 @@
.section .privileged,"ax",@progbits
.endm
// Loads address of errno into %rcx
.macro .errno
call __errno_location
// cs
// cs
// cs
// mov $__errno,%eax
.endm
// Post-Initialization Read-Only (PIRO) BSS section.
// @param ss is an optional string, for control image locality
.macro .piro ss

21
libc/nexgen32e/hastls.c Normal file
View file

@ -0,0 +1,21 @@
/*-*- 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/intrin/threaded.internal.h"
bool __hastls;

View file

@ -42,7 +42,8 @@ $(LIBC_NEXGEN32E_A).pkg: \
$(LIBC_NEXGEN32E_A_OBJS) \
$(foreach x,$(LIBC_NEXGEN32E_A_DIRECTDEPS),$($(x)_A).pkg)
o/$(MODE)/libc/nexgen32e/errno.o: \
o/$(MODE)/libc/nexgen32e/hastls.o \
o/$(MODE)/libc/nexgen32e/threaded.o: \
OVERRIDE_CFLAGS += \
$(NO_MAGIC) \
-fno-sanitize=all

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;

View file

@ -31,6 +31,8 @@
_ehead = 0
_ereal = 0
__privileged_start = 0
__privileged_addr = 0
__privileged_size = 0
__test_start = 0
__ro = 0
__relo_start = 0
@ -51,6 +53,8 @@
.globl ape_xlm
.globl __relo_start
.globl __relo_end
.globl __privileged_size
.globl __privileged_addr
.globl __privileged_start
.globl __ro
.globl __test_start
@ -72,6 +76,8 @@
.weak ape_xlm
.weak __relo_start
.weak __relo_end
.weak __privileged_size
.weak __privileged_addr
.weak __privileged_start
.weak __ro
.weak __test_start

View file

@ -1,10 +1,12 @@
#include "libc/macros.internal.h"
.text.unlikely
.section .privileged,"ax",@progbits
e2big: .leafprologue
.profilable
mov E2BIG(%rip),%eax
mov %eax,errno(%rip)
mov E2BIG(%rip),%ecx
.errno
mov %ecx,(%rax)
push $-1
pop %rax
.leafepilogue

View file

@ -1,10 +1,12 @@
#include "libc/macros.internal.h"
.text.unlikely
.section .privileged,"ax",@progbits
eacces: .leafprologue
.profilable
mov EACCES(%rip),%eax
mov %eax,errno(%rip)
mov EACCES(%rip),%ecx
.errno
mov %ecx,(%rax)
push $-1
pop %rax
.leafepilogue

View file

@ -1,11 +1,13 @@
#include "libc/macros.internal.h"
.text.unlikely
.section .privileged,"ax",@progbits
eaddrinuse:
.leafprologue
.profilable
mov EADDRINUSE(%rip),%eax
mov %eax,errno(%rip)
mov EADDRINUSE(%rip),%ecx
.errno
mov %ecx,(%rax)
push $-1
pop %rax
.leafepilogue

View file

@ -1,11 +1,13 @@
#include "libc/macros.internal.h"
.text.unlikely
.section .privileged,"ax",@progbits
eaddrnotavail:
.leafprologue
.profilable
mov EADDRNOTAVAIL(%rip),%eax
mov %eax,errno(%rip)
mov EADDRNOTAVAIL(%rip),%ecx
.errno
mov %ecx,(%rax)
push $-1
pop %rax
.leafepilogue

View file

@ -1,10 +1,12 @@
#include "libc/macros.internal.h"
.text.unlikely
.section .privileged,"ax",@progbits
eadv: .leafprologue
.profilable
mov EADV(%rip),%eax
mov %eax,errno(%rip)
mov EADV(%rip),%ecx
.errno
mov %ecx,(%rax)
push $-1
pop %rax
.leafepilogue

View file

@ -1,11 +1,13 @@
#include "libc/macros.internal.h"
.text.unlikely
.section .privileged,"ax",@progbits
eafnosupport:
.leafprologue
.profilable
mov EAFNOSUPPORT(%rip),%eax
mov %eax,errno(%rip)
mov EAFNOSUPPORT(%rip),%ecx
.errno
mov %ecx,(%rax)
push $-1
pop %rax
.leafepilogue

View file

@ -1,10 +1,12 @@
#include "libc/macros.internal.h"
.text.unlikely
.section .privileged,"ax",@progbits
eagain: .leafprologue
.profilable
mov EAGAIN(%rip),%eax
mov %eax,errno(%rip)
mov EAGAIN(%rip),%ecx
.errno
mov %ecx,(%rax)
push $-1
pop %rax
.leafepilogue

View file

@ -1,11 +1,13 @@
#include "libc/macros.internal.h"
.text.unlikely
.section .privileged,"ax",@progbits
ealready:
.leafprologue
.profilable
mov EALREADY(%rip),%eax
mov %eax,errno(%rip)
mov EALREADY(%rip),%ecx
.errno
mov %ecx,(%rax)
push $-1
pop %rax
.leafepilogue

View file

@ -1,10 +1,12 @@
#include "libc/macros.internal.h"
.text.unlikely
.section .privileged,"ax",@progbits
ebade: .leafprologue
.profilable
mov EBADE(%rip),%eax
mov %eax,errno(%rip)
mov EBADE(%rip),%ecx
.errno
mov %ecx,(%rax)
push $-1
pop %rax
.leafepilogue

View file

@ -1,10 +1,12 @@
#include "libc/macros.internal.h"
.text.unlikely
.section .privileged,"ax",@progbits
ebadf: .leafprologue
.profilable
mov EBADF(%rip),%eax
mov %eax,errno(%rip)
mov EBADF(%rip),%ecx
.errno
mov %ecx,(%rax)
push $-1
pop %rax
.leafepilogue

View file

@ -1,10 +1,12 @@
#include "libc/macros.internal.h"
.text.unlikely
.section .privileged,"ax",@progbits
ebadfd: .leafprologue
.profilable
mov EBADFD(%rip),%eax
mov %eax,errno(%rip)
mov EBADFD(%rip),%ecx
.errno
mov %ecx,(%rax)
push $-1
pop %rax
.leafepilogue

View file

@ -1,11 +1,13 @@
#include "libc/macros.internal.h"
.text.unlikely
.section .privileged,"ax",@progbits
ebadmsg:
.leafprologue
.profilable
mov EBADMSG(%rip),%eax
mov %eax,errno(%rip)
mov EBADMSG(%rip),%ecx
.errno
mov %ecx,(%rax)
push $-1
pop %rax
.leafepilogue

View file

@ -1,10 +1,12 @@
#include "libc/macros.internal.h"
.text.unlikely
.section .privileged,"ax",@progbits
ebadr: .leafprologue
.profilable
mov EBADR(%rip),%eax
mov %eax,errno(%rip)
mov EBADR(%rip),%ecx
.errno
mov %ecx,(%rax)
push $-1
pop %rax
.leafepilogue

View file

@ -1,11 +1,13 @@
#include "libc/macros.internal.h"
.text.unlikely
.section .privileged,"ax",@progbits
ebadrqc:
.leafprologue
.profilable
mov EBADRQC(%rip),%eax
mov %eax,errno(%rip)
mov EBADRQC(%rip),%ecx
.errno
mov %ecx,(%rax)
push $-1
pop %rax
.leafepilogue

View file

@ -1,11 +1,13 @@
#include "libc/macros.internal.h"
.text.unlikely
.section .privileged,"ax",@progbits
ebadslt:
.leafprologue
.profilable
mov EBADSLT(%rip),%eax
mov %eax,errno(%rip)
mov EBADSLT(%rip),%ecx
.errno
mov %ecx,(%rax)
push $-1
pop %rax
.leafepilogue

View file

@ -1,10 +1,12 @@
#include "libc/macros.internal.h"
.text.unlikely
.section .privileged,"ax",@progbits
ebusy: .leafprologue
.profilable
mov EBUSY(%rip),%eax
mov %eax,errno(%rip)
mov EBUSY(%rip),%ecx
.errno
mov %ecx,(%rax)
push $-1
pop %rax
.leafepilogue

View file

@ -1,11 +1,13 @@
#include "libc/macros.internal.h"
.text.unlikely
.section .privileged,"ax",@progbits
ecanceled:
.leafprologue
.profilable
mov ECANCELED(%rip),%eax
mov %eax,errno(%rip)
mov ECANCELED(%rip),%ecx
.errno
mov %ecx,(%rax)
push $-1
pop %rax
.leafepilogue

View file

@ -1,10 +1,12 @@
#include "libc/macros.internal.h"
.text.unlikely
.section .privileged,"ax",@progbits
echild: .leafprologue
.profilable
mov ECHILD(%rip),%eax
mov %eax,errno(%rip)
mov ECHILD(%rip),%ecx
.errno
mov %ecx,(%rax)
push $-1
pop %rax
.leafepilogue

View file

@ -1,10 +1,12 @@
#include "libc/macros.internal.h"
.text.unlikely
.section .privileged,"ax",@progbits
echrng: .leafprologue
.profilable
mov ECHRNG(%rip),%eax
mov %eax,errno(%rip)
mov ECHRNG(%rip),%ecx
.errno
mov %ecx,(%rax)
push $-1
pop %rax
.leafepilogue

View file

@ -1,10 +1,12 @@
#include "libc/macros.internal.h"
.text.unlikely
.section .privileged,"ax",@progbits
ecomm: .leafprologue
.profilable
mov ECOMM(%rip),%eax
mov %eax,errno(%rip)
mov ECOMM(%rip),%ecx
.errno
mov %ecx,(%rax)
push $-1
pop %rax
.leafepilogue

View file

@ -1,11 +1,13 @@
#include "libc/macros.internal.h"
.text.unlikely
.section .privileged,"ax",@progbits
econnaborted:
.leafprologue
.profilable
mov ECONNABORTED(%rip),%eax
mov %eax,errno(%rip)
mov ECONNABORTED(%rip),%ecx
.errno
mov %ecx,(%rax)
push $-1
pop %rax
.leafepilogue

View file

@ -1,11 +1,13 @@
#include "libc/macros.internal.h"
.text.unlikely
.section .privileged,"ax",@progbits
econnrefused:
.leafprologue
.profilable
mov ECONNREFUSED(%rip),%eax
mov %eax,errno(%rip)
mov ECONNREFUSED(%rip),%ecx
.errno
mov %ecx,(%rax)
push $-1
pop %rax
.leafepilogue

View file

@ -1,11 +1,13 @@
#include "libc/macros.internal.h"
.text.unlikely
.section .privileged,"ax",@progbits
econnreset:
.leafprologue
.profilable
mov ECONNRESET(%rip),%eax
mov %eax,errno(%rip)
mov ECONNRESET(%rip),%ecx
.errno
mov %ecx,(%rax)
push $-1
pop %rax
.leafepilogue

View file

@ -1,11 +1,13 @@
#include "libc/macros.internal.h"
.text.unlikely
.section .privileged,"ax",@progbits
edeadlk:
.leafprologue
.profilable
mov EDEADLK(%rip),%eax
mov %eax,errno(%rip)
mov EDEADLK(%rip),%ecx
.errno
mov %ecx,(%rax)
push $-1
pop %rax
.leafepilogue

View file

@ -1,11 +1,13 @@
#include "libc/macros.internal.h"
.text.unlikely
.section .privileged,"ax",@progbits
edestaddrreq:
.leafprologue
.profilable
mov EDESTADDRREQ(%rip),%eax
mov %eax,errno(%rip)
mov EDESTADDRREQ(%rip),%ecx
.errno
mov %ecx,(%rax)
push $-1
pop %rax
.leafepilogue

View file

@ -1,10 +1,12 @@
#include "libc/macros.internal.h"
.text.unlikely
.section .privileged,"ax",@progbits
edom: .leafprologue
.profilable
mov EDOM(%rip),%eax
mov %eax,errno(%rip)
mov EDOM(%rip),%ecx
.errno
mov %ecx,(%rax)
push $-1
pop %rax
.leafepilogue

View file

@ -1,11 +1,13 @@
#include "libc/macros.internal.h"
.text.unlikely
.section .privileged,"ax",@progbits
edotdot:
.leafprologue
.profilable
mov EDOTDOT(%rip),%eax
mov %eax,errno(%rip)
mov EDOTDOT(%rip),%ecx
.errno
mov %ecx,(%rax)
push $-1
pop %rax
.leafepilogue

View file

@ -1,10 +1,12 @@
#include "libc/macros.internal.h"
.text.unlikely
.section .privileged,"ax",@progbits
edquot: .leafprologue
.profilable
mov EDQUOT(%rip),%eax
mov %eax,errno(%rip)
mov EDQUOT(%rip),%ecx
.errno
mov %ecx,(%rax)
push $-1
pop %rax
.leafepilogue

View file

@ -1,10 +1,12 @@
#include "libc/macros.internal.h"
.text.unlikely
.section .privileged,"ax",@progbits
eexist: .leafprologue
.profilable
mov EEXIST(%rip),%eax
mov %eax,errno(%rip)
mov EEXIST(%rip),%ecx
.errno
mov %ecx,(%rax)
push $-1
pop %rax
.leafepilogue

View file

@ -1,10 +1,12 @@
#include "libc/macros.internal.h"
.text.unlikely
.section .privileged,"ax",@progbits
efault: .leafprologue
.profilable
mov EFAULT(%rip),%eax
mov %eax,errno(%rip)
mov EFAULT(%rip),%ecx
.errno
mov %ecx,(%rax)
push $-1
pop %rax
.leafepilogue

View file

@ -1,10 +1,12 @@
#include "libc/macros.internal.h"
.text.unlikely
.section .privileged,"ax",@progbits
efbig: .leafprologue
.profilable
mov EFBIG(%rip),%eax
mov %eax,errno(%rip)
mov EFBIG(%rip),%ecx
.errno
mov %ecx,(%rax)
push $-1
pop %rax
.leafepilogue

View file

@ -1,11 +1,13 @@
#include "libc/macros.internal.h"
.text.unlikely
.section .privileged,"ax",@progbits
ehostdown:
.leafprologue
.profilable
mov EHOSTDOWN(%rip),%eax
mov %eax,errno(%rip)
mov EHOSTDOWN(%rip),%ecx
.errno
mov %ecx,(%rax)
push $-1
pop %rax
.leafepilogue

View file

@ -1,11 +1,13 @@
#include "libc/macros.internal.h"
.text.unlikely
.section .privileged,"ax",@progbits
ehostunreach:
.leafprologue
.profilable
mov EHOSTUNREACH(%rip),%eax
mov %eax,errno(%rip)
mov EHOSTUNREACH(%rip),%ecx
.errno
mov %ecx,(%rax)
push $-1
pop %rax
.leafepilogue

View file

@ -1,11 +1,13 @@
#include "libc/macros.internal.h"
.text.unlikely
.section .privileged,"ax",@progbits
ehwpoison:
.leafprologue
.profilable
mov EHWPOISON(%rip),%eax
mov %eax,errno(%rip)
mov EHWPOISON(%rip),%ecx
.errno
mov %ecx,(%rax)
push $-1
pop %rax
.leafepilogue

View file

@ -1,10 +1,12 @@
#include "libc/macros.internal.h"
.text.unlikely
.section .privileged,"ax",@progbits
eidrm: .leafprologue
.profilable
mov EIDRM(%rip),%eax
mov %eax,errno(%rip)
mov EIDRM(%rip),%ecx
.errno
mov %ecx,(%rax)
push $-1
pop %rax
.leafepilogue

View file

@ -1,10 +1,12 @@
#include "libc/macros.internal.h"
.text.unlikely
.section .privileged,"ax",@progbits
eilseq: .leafprologue
.profilable
mov EILSEQ(%rip),%eax
mov %eax,errno(%rip)
mov EILSEQ(%rip),%ecx
.errno
mov %ecx,(%rax)
push $-1
pop %rax
.leafepilogue

View file

@ -1,11 +1,13 @@
#include "libc/macros.internal.h"
.text.unlikely
.section .privileged,"ax",@progbits
einprogress:
.leafprologue
.profilable
mov EINPROGRESS(%rip),%eax
mov %eax,errno(%rip)
mov EINPROGRESS(%rip),%ecx
.errno
mov %ecx,(%rax)
push $-1
pop %rax
.leafepilogue

View file

@ -1,10 +1,12 @@
#include "libc/macros.internal.h"
.text.unlikely
.section .privileged,"ax",@progbits
eintr: .leafprologue
.profilable
mov EINTR(%rip),%eax
mov %eax,errno(%rip)
mov EINTR(%rip),%ecx
.errno
mov %ecx,(%rax)
push $-1
pop %rax
.leafepilogue

View file

@ -1,10 +1,12 @@
#include "libc/macros.internal.h"
.text.unlikely
.section .privileged,"ax",@progbits
einval: .leafprologue
.profilable
mov EINVAL(%rip),%eax
mov %eax,errno(%rip)
mov EINVAL(%rip),%ecx
.errno
mov %ecx,(%rax)
push $-1
pop %rax
.leafepilogue

View file

@ -1,10 +1,12 @@
#include "libc/macros.internal.h"
.text.unlikely
.section .privileged,"ax",@progbits
eio: .leafprologue
.profilable
mov EIO(%rip),%eax
mov %eax,errno(%rip)
mov EIO(%rip),%ecx
.errno
mov %ecx,(%rax)
push $-1
pop %rax
.leafepilogue

View file

@ -1,11 +1,13 @@
#include "libc/macros.internal.h"
.text.unlikely
.section .privileged,"ax",@progbits
eisconn:
.leafprologue
.profilable
mov EISCONN(%rip),%eax
mov %eax,errno(%rip)
mov EISCONN(%rip),%ecx
.errno
mov %ecx,(%rax)
push $-1
pop %rax
.leafepilogue

View file

@ -1,10 +1,12 @@
#include "libc/macros.internal.h"
.text.unlikely
.section .privileged,"ax",@progbits
eisdir: .leafprologue
.profilable
mov EISDIR(%rip),%eax
mov %eax,errno(%rip)
mov EISDIR(%rip),%ecx
.errno
mov %ecx,(%rax)
push $-1
pop %rax
.leafepilogue

View file

@ -1,10 +1,12 @@
#include "libc/macros.internal.h"
.text.unlikely
.section .privileged,"ax",@progbits
eisnam: .leafprologue
.profilable
mov EISNAM(%rip),%eax
mov %eax,errno(%rip)
mov EISNAM(%rip),%ecx
.errno
mov %ecx,(%rax)
push $-1
pop %rax
.leafepilogue

View file

@ -1,11 +1,13 @@
#include "libc/macros.internal.h"
.text.unlikely
.section .privileged,"ax",@progbits
ekeyexpired:
.leafprologue
.profilable
mov EKEYEXPIRED(%rip),%eax
mov %eax,errno(%rip)
mov EKEYEXPIRED(%rip),%ecx
.errno
mov %ecx,(%rax)
push $-1
pop %rax
.leafepilogue

View file

@ -1,11 +1,13 @@
#include "libc/macros.internal.h"
.text.unlikely
.section .privileged,"ax",@progbits
ekeyrejected:
.leafprologue
.profilable
mov EKEYREJECTED(%rip),%eax
mov %eax,errno(%rip)
mov EKEYREJECTED(%rip),%ecx
.errno
mov %ecx,(%rax)
push $-1
pop %rax
.leafepilogue

View file

@ -1,11 +1,13 @@
#include "libc/macros.internal.h"
.text.unlikely
.section .privileged,"ax",@progbits
ekeyrevoked:
.leafprologue
.profilable
mov EKEYREVOKED(%rip),%eax
mov %eax,errno(%rip)
mov EKEYREVOKED(%rip),%ecx
.errno
mov %ecx,(%rax)
push $-1
pop %rax
.leafepilogue

View file

@ -1,10 +1,12 @@
#include "libc/macros.internal.h"
.text.unlikely
.section .privileged,"ax",@progbits
el2hlt: .leafprologue
.profilable
mov EL2HLT(%rip),%eax
mov %eax,errno(%rip)
mov EL2HLT(%rip),%ecx
.errno
mov %ecx,(%rax)
push $-1
pop %rax
.leafepilogue

View file

@ -1,11 +1,13 @@
#include "libc/macros.internal.h"
.text.unlikely
.section .privileged,"ax",@progbits
el2nsync:
.leafprologue
.profilable
mov EL2NSYNC(%rip),%eax
mov %eax,errno(%rip)
mov EL2NSYNC(%rip),%ecx
.errno
mov %ecx,(%rax)
push $-1
pop %rax
.leafepilogue

View file

@ -1,10 +1,12 @@
#include "libc/macros.internal.h"
.text.unlikely
.section .privileged,"ax",@progbits
el3hlt: .leafprologue
.profilable
mov EL3HLT(%rip),%eax
mov %eax,errno(%rip)
mov EL3HLT(%rip),%ecx
.errno
mov %ecx,(%rax)
push $-1
pop %rax
.leafepilogue

View file

@ -1,10 +1,12 @@
#include "libc/macros.internal.h"
.text.unlikely
.section .privileged,"ax",@progbits
el3rst: .leafprologue
.profilable
mov EL3RST(%rip),%eax
mov %eax,errno(%rip)
mov EL3RST(%rip),%ecx
.errno
mov %ecx,(%rax)
push $-1
pop %rax
.leafepilogue

View file

@ -1,11 +1,13 @@
#include "libc/macros.internal.h"
.text.unlikely
.section .privileged,"ax",@progbits
elibacc:
.leafprologue
.profilable
mov ELIBACC(%rip),%eax
mov %eax,errno(%rip)
mov ELIBACC(%rip),%ecx
.errno
mov %ecx,(%rax)
push $-1
pop %rax
.leafepilogue

View file

@ -1,11 +1,13 @@
#include "libc/macros.internal.h"
.text.unlikely
.section .privileged,"ax",@progbits
elibbad:
.leafprologue
.profilable
mov ELIBBAD(%rip),%eax
mov %eax,errno(%rip)
mov ELIBBAD(%rip),%ecx
.errno
mov %ecx,(%rax)
push $-1
pop %rax
.leafepilogue

View file

@ -1,11 +1,13 @@
#include "libc/macros.internal.h"
.text.unlikely
.section .privileged,"ax",@progbits
elibexec:
.leafprologue
.profilable
mov ELIBEXEC(%rip),%eax
mov %eax,errno(%rip)
mov ELIBEXEC(%rip),%ecx
.errno
mov %ecx,(%rax)
push $-1
pop %rax
.leafepilogue

View file

@ -1,11 +1,13 @@
#include "libc/macros.internal.h"
.text.unlikely
.section .privileged,"ax",@progbits
elibmax:
.leafprologue
.profilable
mov ELIBMAX(%rip),%eax
mov %eax,errno(%rip)
mov ELIBMAX(%rip),%ecx
.errno
mov %ecx,(%rax)
push $-1
pop %rax
.leafepilogue

View file

@ -1,11 +1,13 @@
#include "libc/macros.internal.h"
.text.unlikely
.section .privileged,"ax",@progbits
elibscn:
.leafprologue
.profilable
mov ELIBSCN(%rip),%eax
mov %eax,errno(%rip)
mov ELIBSCN(%rip),%ecx
.errno
mov %ecx,(%rax)
push $-1
pop %rax
.leafepilogue

View file

@ -1,10 +1,12 @@
#include "libc/macros.internal.h"
.text.unlikely
.section .privileged,"ax",@progbits
elnrng: .leafprologue
.profilable
mov ELNRNG(%rip),%eax
mov %eax,errno(%rip)
mov ELNRNG(%rip),%ecx
.errno
mov %ecx,(%rax)
push $-1
pop %rax
.leafepilogue

View file

@ -1,10 +1,12 @@
#include "libc/macros.internal.h"
.text.unlikely
.section .privileged,"ax",@progbits
eloop: .leafprologue
.profilable
mov ELOOP(%rip),%eax
mov %eax,errno(%rip)
mov ELOOP(%rip),%ecx
.errno
mov %ecx,(%rax)
push $-1
pop %rax
.leafepilogue

View file

@ -1,11 +1,13 @@
#include "libc/macros.internal.h"
.text.unlikely
.section .privileged,"ax",@progbits
emediumtype:
.leafprologue
.profilable
mov EMEDIUMTYPE(%rip),%eax
mov %eax,errno(%rip)
mov EMEDIUMTYPE(%rip),%ecx
.errno
mov %ecx,(%rax)
push $-1
pop %rax
.leafepilogue

View file

@ -1,10 +1,12 @@
#include "libc/macros.internal.h"
.text.unlikely
.section .privileged,"ax",@progbits
emfile: .leafprologue
.profilable
mov EMFILE(%rip),%eax
mov %eax,errno(%rip)
mov EMFILE(%rip),%ecx
.errno
mov %ecx,(%rax)
push $-1
pop %rax
.leafepilogue

View file

@ -1,10 +1,12 @@
#include "libc/macros.internal.h"
.text.unlikely
.section .privileged,"ax",@progbits
emlink: .leafprologue
.profilable
mov EMLINK(%rip),%eax
mov %eax,errno(%rip)
mov EMLINK(%rip),%ecx
.errno
mov %ecx,(%rax)
push $-1
pop %rax
.leafepilogue

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