From 7cf66bc1617b77ecfa37b66b13f63817726c95a4 Mon Sep 17 00:00:00 2001 From: Justine Tunney Date: Fri, 12 Aug 2022 05:17:06 -0700 Subject: [PATCH] Prevent Make from talking to public Internet This change introduces the nointernet() function which may be called to prevent a process and its descendants from communicating with publicly routable Internet addresses. GNU Make has been modified to always call this function. In the future Landlock Make will have a way to whitelist subnets to override this behavior, or disable it entirely. Support is available for Linux only. Our firewall does not require root access. Calling nointernet() will return control to the caller inside a new process that has a SECCOMP BPF filter installed, which traps network related system calls. Your original process then becomes a permanent ptrace() supervisor that monitors all processes and threads descending from the returned child. Whenever a networking system call happens the kernel will stop the process and wakes up the monitor, which then peeks into the child memory to read the sockaddr_in to determine if it's ok. The downside to doing this is that there can be only one supervisor at a time using ptrace() on a process. So this firewall won't be enabled if you run make under strace or inside gdb. It also makes testing tricky. --- build/rules.mk | 2 +- libc/calls/calls.h | 12 +- libc/calls/pledge-linux.c | 3 +- libc/calls/ptrace.c | 51 +- libc/{sock/firewall.c => calls/sys_ptrace.c} | 60 +- libc/calls/syscall-sysv.internal.h | 2 +- libc/calls/sysparam.h | 5 - libc/calls/truncate.c | 8 +- libc/dns/resolvedns.c | 5 +- libc/intrin/describeflags.internal.h | 4 + libc/intrin/describeptrace.c | 57 + .../describeptraceevent.c} | 32 +- libc/sock/connect.c | 1 - libc/sock/internal.h | 2 - libc/sock/nointernet.c | 348 +++ libc/sock/sendto.c | 1 - libc/sock/sock.h | 1 + libc/sysv/calls/__sys_ptrace.s | 2 + libc/sysv/calls/sys_ptrace.s | 2 - libc/sysv/syscalls.sh | 2 +- test/libc/calls/ptrace_test.c | 0 test/libc/calls/sys_ptrace_test.c | 0 test/libc/sock/nointernet_test.c | 85 + test/libc/sock/sendrecvmsg_test.c | 3 + test/libc/sock/test.mk | 1 + test/tool/build/lib/xlaterrno_test.c | 1 + third_party/make/job.c | 1 + third_party/make/main.c | 27 +- third_party/make/make.mk | 1 + tool/build/blinkenlights.c | 56 +- tool/build/lib/bits.h | 166 ++ tool/build/lib/cvt.c | 288 ++- tool/build/lib/fds.h | 2 +- tool/build/lib/fpu.c | 363 ++- tool/build/lib/fpu.h | 53 +- tool/build/lib/ldbl.c | 49 + tool/build/lib/ldbl.h | 11 + tool/build/lib/machine.h | 16 + tool/build/lib/pun.h | 28 + tool/build/lib/signal.c | 165 ++ tool/build/lib/signal.h | 15 + tool/build/lib/sse.c | 2213 +++++++++++------ tool/build/lib/ssefloat.c | 775 +++--- tool/build/lib/syscall.c | 977 ++++---- tool/build/lib/xlat.c | 1002 ++++++++ tool/build/lib/xlat.h | 53 + tool/build/lib/xlaterrno.h | 10 - tool/net/redbean.c | 9 +- 48 files changed, 4924 insertions(+), 2046 deletions(-) rename libc/{sock/firewall.c => calls/sys_ptrace.c} (62%) create mode 100644 libc/intrin/describeptrace.c rename libc/{calls/getfilesize.c => intrin/describeptraceevent.c} (70%) create mode 100644 libc/sock/nointernet.c create mode 100644 libc/sysv/calls/__sys_ptrace.s delete mode 100644 libc/sysv/calls/sys_ptrace.s create mode 100644 test/libc/calls/ptrace_test.c create mode 100644 test/libc/calls/sys_ptrace_test.c create mode 100644 test/libc/sock/nointernet_test.c create mode 100755 tool/build/lib/bits.h create mode 100644 tool/build/lib/ldbl.c create mode 100644 tool/build/lib/ldbl.h create mode 100644 tool/build/lib/pun.h create mode 100644 tool/build/lib/signal.c create mode 100644 tool/build/lib/signal.h create mode 100644 tool/build/lib/xlat.c create mode 100644 tool/build/lib/xlat.h mode change 100644 => 100755 tool/build/lib/xlaterrno.h diff --git a/build/rules.mk b/build/rules.mk index f3b3c3ac3..309dedd6d 100644 --- a/build/rules.mk +++ b/build/rules.mk @@ -44,7 +44,7 @@ o/$(MODE)/%.initabi.o: %.initabi.c ; @$(COMPILE) -AOBJECTIFY.init $(OBJECTIFY.in o/$(MODE)/%.ncabi.o: %.ncabi.c ; @$(COMPILE) -AOBJECTIFY.nc $(OBJECTIFY.ncabi.c) $(OUTPUT_OPTION) $< o/$(MODE)/%.real.o: %.c ; @$(COMPILE) -AOBJECTIFY.real $(OBJECTIFY.real.c) $(OUTPUT_OPTION) $< -o/$(MODE)/%.runs: o/$(MODE)/% ; @$(COMPILE) -ACHECK -tT$@ $< $(TESTARGS) +o/$(MODE)/%.runs: o/$(MODE)/% ; @$(COMPILE) -ACHECK -wtT$@ $< $(TESTARGS) o/$(MODE)/%.zip.o: % ; @$(COMPILE) -wAZIPOBJ $(ZIPOBJ) $(ZIPOBJ_FLAGS) $(OUTPUT_OPTION) $< o/$(MODE)/%-gcc.asm: %.c ; @$(COMPILE) -AOBJECTIFY.c $(OBJECTIFY.c) -S -g0 $(OUTPUT_OPTION) $< o/$(MODE)/%-gcc.asm: %.cc ; @$(COMPILE) -AOBJECTIFY.c $(OBJECTIFY.cxx) -S -g0 $(OUTPUT_OPTION) $< diff --git a/libc/calls/calls.h b/libc/calls/calls.h index dbe977a71..1daf12ad4 100644 --- a/libc/calls/calls.h +++ b/libc/calls/calls.h @@ -35,10 +35,11 @@ #define WIFCONTINUED(s) ((s) == 0xffff) #define WIFEXITED(s) (!WTERMSIG(s)) #define WIFSIGNALED(s) ((0xffff & (s)) - 1u < 0xffu) -#define WIFSTOPPED(s) ((short)(((0xffff & (s)) * 0x10001) >> 8) > 0x7f00) -#define WSTOPSIG(s) WEXITSTATUS(s) -#define WTERMSIG(s) (127 & (s)) -#define W_STOPCODE(s) ((s) << 8 | 0177) +#define WIFSTOPPED(s) \ + ((short)(((0xffff & (unsigned)(s)) * 0x10001) >> 8) > 0x7f00) +#define WSTOPSIG(s) WEXITSTATUS(s) +#define WTERMSIG(s) (127 & (s)) +#define W_STOPCODE(s) ((s) << 8 | 0177) #if !(__ASSEMBLER__ + __LINKER__ + 0) COSMOPOLITAN_C_START_ @@ -115,6 +116,7 @@ int getresuid(uint32_t *, uint32_t *, uint32_t *); int getsid(int) nosideeffect libcesque; int gettid(void) libcesque; int getuid(void) libcesque; +int iopl(int); int ioprio_get(int, int); int ioprio_set(int, int, int); int issetugid(void); @@ -178,6 +180,7 @@ int siginterrupt(int, int); int symlink(const char *, const char *); int symlinkat(const char *, int, const char *); int sync_file_range(int, int64_t, int64_t, unsigned); +int sys_ptrace(int, ...); int sysctl(const int *, unsigned, void *, size_t *, void *, size_t); int tgkill(int, int, int); int tkill(int, int); @@ -194,7 +197,6 @@ int wait(int *); int waitpid(int, int *, int); intptr_t syscall(int, ...); long ptrace(int, ...); -size_t GetFileSize(const char *); ssize_t copy_file_range(int, long *, int, long *, size_t, uint32_t); ssize_t copyfd(int, int64_t *, int, int64_t *, size_t, uint32_t); ssize_t getfiledescriptorsize(int); diff --git a/libc/calls/pledge-linux.c b/libc/calls/pledge-linux.c index a3275c827..8ed6a96c8 100644 --- a/libc/calls/pledge-linux.c +++ b/libc/calls/pledge-linux.c @@ -16,7 +16,6 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/intrin/likely.h" #include "libc/calls/calls.h" #include "libc/calls/pledge.internal.h" #include "libc/calls/struct/bpf.h" @@ -25,6 +24,7 @@ #include "libc/calls/struct/sigaction.h" #include "libc/calls/syscall_support-sysv.internal.h" #include "libc/intrin/kprintf.h" +#include "libc/intrin/likely.h" #include "libc/intrin/promises.internal.h" #include "libc/macros.internal.h" #include "libc/nexgen32e/bsr.h" @@ -517,6 +517,7 @@ static const uint16_t kPledgeStdio[] = { __NR_linux_migrate_pages, // __NR_linux_sync_file_range, // __NR_linux_set_tid_address, // + __NR_linux_membarrier, // __NR_linux_nanosleep, // __NR_linux_pipe, // __NR_linux_pipe2, // diff --git a/libc/calls/ptrace.c b/libc/calls/ptrace.c index a2e8d2c62..c79191c8b 100644 --- a/libc/calls/ptrace.c +++ b/libc/calls/ptrace.c @@ -19,47 +19,15 @@ #include "libc/calls/strace.internal.h" #include "libc/calls/syscall-sysv.internal.h" #include "libc/dce.h" +#include "libc/intrin/describeflags.internal.h" #include "libc/sysv/consts/ptrace.h" #include "libc/sysv/errfuns.h" -static const char *__ptrace_describe_request(int x) { - if (x == -1) return "-1"; - if (x == PTRACE_TRACEME) return "PTRACE_TRACEME"; - if (x == PTRACE_PEEKDATA) return "PTRACE_PEEKDATA"; - if (x == PTRACE_GETFPREGS) return "PTRACE_GETFPREGS"; - if (x == PTRACE_PEEKTEXT) return "PTRACE_PEEKTEXT"; - if (x == PTRACE_POKEDATA) return "PTRACE_POKEDATA"; - if (x == PTRACE_PEEKUSER) return "PTRACE_PEEKUSER"; - if (x == PTRACE_POKETEXT) return "PTRACE_POKETEXT"; - if (x == PTRACE_POKEUSER) return "PTRACE_POKEUSER"; - if (x == PTRACE_GETREGS) return "PTRACE_GETREGS"; - if (x == PTRACE_GETREGSET) return "PTRACE_GETREGSET"; - if (x == PTRACE_SETFPREGS) return "PTRACE_SETFPREGS"; - if (x == PTRACE_SETREGS) return "PTRACE_SETREGS"; - if (x == PTRACE_SETREGSET) return "PTRACE_SETREGSET"; - if (x == PTRACE_GETSIGINFO) return "PTRACE_GETSIGINFO"; - if (x == PTRACE_SETSIGINFO) return "PTRACE_SETSIGINFO"; - if (x == PTRACE_PEEKSIGINFO) return "PTRACE_PEEKSIGINFO"; - if (x == PTRACE_GETSIGMASK) return "PTRACE_GETSIGMASK"; - if (x == PTRACE_SETSIGMASK) return "PTRACE_SETSIGMASK"; - if (x == PTRACE_SETOPTIONS) return "PTRACE_SETOPTIONS"; - if (x == PTRACE_GETEVENTMSG) return "PTRACE_GETEVENTMSG"; - if (x == PTRACE_CONT) return "PTRACE_CONT"; - if (x == PTRACE_SINGLESTEP) return "PTRACE_SINGLESTEP"; - if (x == PTRACE_SYSCALL) return "PTRACE_SYSCALL"; - if (x == PTRACE_LISTEN) return "PTRACE_LISTEN"; - if (x == PTRACE_KILL) return "PTRACE_KILL"; - if (x == PTRACE_INTERRUPT) return "PTRACE_INTERRUPT"; - if (x == PTRACE_ATTACH) return "PTRACE_ATTACH"; - if (x == PTRACE_SEIZE) return "PTRACE_SEIZE"; - if (x == PTRACE_SECCOMP_GET_FILTER) return "PTRACE_SECCOMP_GET_FILTER"; - if (x == PTRACE_DETACH) return "PTRACE_DETACH"; - return "PTRACE_WUT"; -} - /** * Traces process. * + * This API is terrible. Consider using sys_ptrace(). + * * @param request can be PTRACE_xxx * @note de facto linux only atm * @vforksafe @@ -69,22 +37,21 @@ long ptrace(int request, ...) { int pid; va_list va; bool ispeek; - long rc, peek; - void *addr, *data; + long rc, peek, addr, *data; va_start(va, request); pid = va_arg(va, int); - addr = va_arg(va, void *); - data = va_arg(va, void *); + addr = va_arg(va, long); + data = va_arg(va, long *); va_end(va); if (request == -1) { rc = einval(); /* see consts.sh */ } else { ispeek = IsLinux() && request - 1u < 3; if (ispeek) data = &peek; - rc = sys_ptrace(request, pid, addr, data); + rc = __sys_ptrace(request, pid, addr, data); if (rc != -1 && ispeek) rc = peek; } - STRACE("ptrace(%s, %d, %p, %p) → %ld% m", __ptrace_describe_request(request), - pid, addr, data); + STRACE("ptrace(%s, %d, %p, %p) → %p% m", DescribePtrace(request), pid, addr, + data, rc); return rc; } diff --git a/libc/sock/firewall.c b/libc/calls/sys_ptrace.c similarity index 62% rename from libc/sock/firewall.c rename to libc/calls/sys_ptrace.c index 1bc654b6c..8d8ca1be3 100644 --- a/libc/sock/firewall.c +++ b/libc/calls/sys_ptrace.c @@ -1,7 +1,7 @@ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│ ╞══════════════════════════════════════════════════════════════════════════════╡ -│ Copyright 2021 Justine Alexandra Roberts Tunney │ +│ 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 │ @@ -16,35 +16,45 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/intrin/weaken.h" #include "libc/calls/calls.h" +#include "libc/calls/strace.internal.h" +#include "libc/calls/syscall-sysv.internal.h" #include "libc/dce.h" -#include "libc/log/log.h" -#include "libc/runtime/internal.h" -#include "libc/runtime/runtime.h" -#include "libc/sock/internal.h" -#include "libc/sock/sock.h" -#include "libc/sysv/consts/af.h" -#include "net/http/ip.h" +#include "libc/intrin/describeflags.internal.h" +#include "libc/intrin/likely.h" + +#define IsPeek(request) (IsLinux() && (request)-1u < 3) /** - * Checks outbound address against firewall. + * Traces process. * - * The goal is to keep local software local, by raising an error if our - * Makefile tries to talk to the Internet. + * @param op can be PTRACE_xxx + * @param pid is child process id + * @param addr points inside child address space + * @param data is address of output word when peeking + * @note de facto linux only + * @vforksafe */ -void _firewall(const void *addr, uint32_t addrsize) { - char b[64], *p; - if (!IsTiny() && addr && addrsize >= sizeof(struct sockaddr_in) && - ((struct sockaddr_in *)addr)->sin_family == AF_INET && - IsPublicIp(ntohl(((struct sockaddr_in *)addr)->sin_addr.s_addr)) && - IsRunningUnderMake()) { - p = stpcpy(b, "make shan't internet: "); - p = stpcpy(p, inet_ntoa(((struct sockaddr_in *)addr)->sin_addr)); - *p++ = '\n'; - write(2, b, p - b); - if (weaken(__die)) weaken(__die)(); - __restorewintty(); - _Exit(66); +int sys_ptrace(int op, ...) { + va_list va; + int rc, pid; + long addr, *data; + va_start(va, op); + pid = va_arg(va, int); + addr = va_arg(va, long); + data = va_arg(va, long *); + va_end(va); + rc = __sys_ptrace(op, pid, addr, data); +#ifdef SYSDEBUG + if (UNLIKELY(__strace > 0)) { + if (rc != -1 && IsPeek(op) && data) { + STRACE("sys_ptrace(%s, %d, %p, [%p]) → %p% m", DescribePtrace(op), pid, + addr, *data, rc); + } else { + STRACE("sys_ptrace(%s, %d, %p, %p) → %p% m", DescribePtrace(op), pid, + addr, data, rc); + } } +#endif + return rc; } diff --git a/libc/calls/syscall-sysv.internal.h b/libc/calls/syscall-sysv.internal.h index 186f35b60..38624643e 100644 --- a/libc/calls/syscall-sysv.internal.h +++ b/libc/calls/syscall-sysv.internal.h @@ -104,10 +104,10 @@ i32 sys_uname(void *) hidden; i32 sys_unlinkat(i32, const char *, i32) hidden; i32 sys_unmount(const char *, i32) hidden; i32 sys_unveil(const char *, const char *) hidden; +i64 __sys_ptrace(i32, i32, i64, long *) hidden; i64 sys_copy_file_range(i32, long *, i32, long *, u64, u32) hidden; i64 sys_getrandom(void *, u64, u32) hidden; i64 sys_pread(i32, void *, u64, i64, i64) hidden; -i64 sys_ptrace(int, i32, void *, void *) hidden; i64 sys_pwrite(i32, const void *, u64, i64, i64) hidden; i64 sys_read(i32, void *, u64) hidden; i64 sys_readlink(const char *, char *, u64) hidden; diff --git a/libc/calls/sysparam.h b/libc/calls/sysparam.h index 57c5c6834..3f2425dbf 100644 --- a/libc/calls/sysparam.h +++ b/libc/calls/sysparam.h @@ -13,11 +13,6 @@ #define DEV_BSIZE 512 #define NOGROUP (-1) -#undef MIN -#undef MAX -#define MIN(a, b) (((a) < (b)) ? (a) : (b)) -#define MAX(a, b) (((a) > (b)) ? (a) : (b)) - #if !(__ASSEMBLER__ + __LINKER__ + 0) COSMOPOLITAN_C_START_ diff --git a/libc/calls/truncate.c b/libc/calls/truncate.c index 752116066..7e0d82ce9 100644 --- a/libc/calls/truncate.c +++ b/libc/calls/truncate.c @@ -17,6 +17,7 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/calls.h" +#include "libc/calls/strace.internal.h" #include "libc/calls/syscall-nt.internal.h" #include "libc/calls/syscall-sysv.internal.h" #include "libc/dce.h" @@ -32,9 +33,12 @@ * @error ENOENT */ int truncate(const char *path, uint64_t length) { + int rc; if (!IsWindows()) { - return sys_truncate(path, length, length); + rc = sys_truncate(path, length, length); } else { - return sys_truncate_nt(path, length); + rc = sys_truncate_nt(path, length); } + STRACE("truncate(%#s, %'ld) → %d% m", path, length, rc); + return rc; } diff --git a/libc/dns/resolvedns.c b/libc/dns/resolvedns.c index 6791ac78c..4606ecb16 100644 --- a/libc/dns/resolvedns.c +++ b/libc/dns/resolvedns.c @@ -16,18 +16,18 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/intrin/bits.h" #include "libc/calls/calls.h" #include "libc/dns/consts.h" #include "libc/dns/dns.h" #include "libc/dns/dnsheader.h" #include "libc/dns/dnsquestion.h" #include "libc/dns/resolvconf.h" +#include "libc/intrin/bits.h" #include "libc/mem/mem.h" -#include "libc/stdio/rand.h" #include "libc/runtime/runtime.h" #include "libc/sock/internal.h" #include "libc/sock/sock.h" +#include "libc/stdio/rand.h" #include "libc/stdio/stdio.h" #include "libc/str/str.h" #include "libc/sysv/consts/af.h" @@ -101,7 +101,6 @@ int ResolveDns(const struct ResolvConf *resolvconf, int af, const char *name, a4 = (struct sockaddr_in *)addr; a4->sin_family = AF_INET; memcpy(&a4->sin_addr.s_addr, p + 10, 4); - _firewall(a4, sizeof(struct sockaddr_in)); break; } p += 10 + rdlength; diff --git a/libc/intrin/describeflags.internal.h b/libc/intrin/describeflags.internal.h index ac11b220e..290ee8514 100644 --- a/libc/intrin/describeflags.internal.h +++ b/libc/intrin/describeflags.internal.h @@ -53,6 +53,8 @@ const char *DescribePersonalityFlags(char[128], int); const char *DescribePollFlags(char[64], int); const char *DescribePrctlOperation(int); const char *DescribeProtFlags(char[48], int); +const char *DescribePtrace(char[12], int); +const char *DescribePtraceEvent(char[32], int); const char *DescribeRemapFlags(char[48], int); const char *DescribeRlimit(char[64], int, const struct rlimit *); const char *DescribeRlimitName(char[20], int); @@ -101,6 +103,8 @@ void DescribeIovNt(const struct NtIovec *, uint32_t, ssize_t); #define DescribePersonalityFlags(p) DescribePersonalityFlags(alloca(128), p) #define DescribePollFlags(p) DescribePollFlags(alloca(64), p) #define DescribeProtFlags(dirfd) DescribeProtFlags(alloca(48), dirfd) +#define DescribePtrace(i) DescribePtrace(alloca(12), i) +#define DescribePtraceEvent(x) DescribePtraceEvent(alloca(32), x) #define DescribeRemapFlags(dirfd) DescribeRemapFlags(alloca(48), dirfd) #define DescribeRlimit(rc, rl) DescribeRlimit(alloca(64), rc, rl) #define DescribeRlimitName(rl) DescribeRlimitName(alloca(20), rl) diff --git a/libc/intrin/describeptrace.c b/libc/intrin/describeptrace.c new file mode 100644 index 000000000..f266599fe --- /dev/null +++ b/libc/intrin/describeptrace.c @@ -0,0 +1,57 @@ +/*-*- 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/fmt/itoa.h" +#include "libc/intrin/describeflags.internal.h" +#include "libc/sysv/consts/ptrace.h" + +const char *(DescribePtrace)(char buf[12], int x) { + if (x == -1) return "-1"; + if (x == PTRACE_TRACEME) return "PTRACE_TRACEME"; + if (x == PTRACE_PEEKDATA) return "PTRACE_PEEKDATA"; + if (x == PTRACE_GETFPREGS) return "PTRACE_GETFPREGS"; + if (x == PTRACE_PEEKTEXT) return "PTRACE_PEEKTEXT"; + if (x == PTRACE_POKEDATA) return "PTRACE_POKEDATA"; + if (x == PTRACE_PEEKUSER) return "PTRACE_PEEKUSER"; + if (x == PTRACE_POKETEXT) return "PTRACE_POKETEXT"; + if (x == PTRACE_POKEUSER) return "PTRACE_POKEUSER"; + if (x == PTRACE_GETREGS) return "PTRACE_GETREGS"; + if (x == PTRACE_GETREGSET) return "PTRACE_GETREGSET"; + if (x == PTRACE_SETFPREGS) return "PTRACE_SETFPREGS"; + if (x == PTRACE_SETREGS) return "PTRACE_SETREGS"; + if (x == PTRACE_SETREGSET) return "PTRACE_SETREGSET"; + if (x == PTRACE_GETSIGINFO) return "PTRACE_GETSIGINFO"; + if (x == PTRACE_SETSIGINFO) return "PTRACE_SETSIGINFO"; + if (x == PTRACE_PEEKSIGINFO) return "PTRACE_PEEKSIGINFO"; + if (x == PTRACE_GETSIGMASK) return "PTRACE_GETSIGMASK"; + if (x == PTRACE_SETSIGMASK) return "PTRACE_SETSIGMASK"; + if (x == PTRACE_SETOPTIONS) return "PTRACE_SETOPTIONS"; + if (x == PTRACE_GETEVENTMSG) return "PTRACE_GETEVENTMSG"; + if (x == PTRACE_CONT) return "PTRACE_CONT"; + if (x == PTRACE_SINGLESTEP) return "PTRACE_SINGLESTEP"; + if (x == PTRACE_SYSCALL) return "PTRACE_SYSCALL"; + if (x == PTRACE_LISTEN) return "PTRACE_LISTEN"; + if (x == PTRACE_KILL) return "PTRACE_KILL"; + if (x == PTRACE_INTERRUPT) return "PTRACE_INTERRUPT"; + if (x == PTRACE_ATTACH) return "PTRACE_ATTACH"; + if (x == PTRACE_SEIZE) return "PTRACE_SEIZE"; + if (x == PTRACE_SECCOMP_GET_FILTER) return "PTRACE_SECCOMP_GET_FILTER"; + if (x == PTRACE_DETACH) return "PTRACE_DETACH"; + FormatInt32(buf, x); + return buf; +} diff --git a/libc/calls/getfilesize.c b/libc/intrin/describeptraceevent.c similarity index 70% rename from libc/calls/getfilesize.c rename to libc/intrin/describeptraceevent.c index 69da98ad1..b9b003f03 100644 --- a/libc/calls/getfilesize.c +++ b/libc/intrin/describeptraceevent.c @@ -1,7 +1,7 @@ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│ ╞══════════════════════════════════════════════════════════════════════════════╡ -│ Copyright 2020 Justine Alexandra Roberts Tunney │ +│ 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 │ @@ -16,21 +16,19 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/calls/calls.h" -#include "libc/calls/struct/stat.h" -#include "libc/dce.h" -#include "libc/limits.h" -#include "libc/nt/files.h" -#include "libc/str/str.h" +#include "libc/fmt/itoa.h" +#include "libc/intrin/describeflags.internal.h" +#include "libc/sysv/consts/ptrace.h" -/** - * Returns the byte length of file by path. - * - * @return number of bytes, or -1ul w/ errno - * @see getfiledescriptorsize() - */ -size_t GetFileSize(const char *pathname) { - struct stat st; - if (stat(pathname, &st) == -1) return SIZE_MAX; - return st.st_size; +const char *(DescribePtraceEvent)(char buf[32], int x) { + if (x == PTRACE_EVENT_FORK) return "PTRACE_EVENT_FORK"; + if (x == PTRACE_EVENT_VFORK) return "PTRACE_EVENT_VFORK"; + if (x == PTRACE_EVENT_CLONE) return "PTRACE_EVENT_CLONE"; + if (x == PTRACE_EVENT_EXEC) return "PTRACE_EVENT_EXEC"; + if (x == PTRACE_EVENT_VFORK_DONE) return "PTRACE_EVENT_VFORK_DONE"; + if (x == PTRACE_EVENT_EXIT) return "PTRACE_EVENT_EXIT"; + if (x == PTRACE_EVENT_SECCOMP) return "PTRACE_EVENT_SECCOMP"; + if (x == PTRACE_EVENT_STOP) return "PTRACE_EVENT_STOP"; + FormatInt32(buf, x); + return buf; } diff --git a/libc/sock/connect.c b/libc/sock/connect.c index ec56fba68..d81be9414 100644 --- a/libc/sock/connect.c +++ b/libc/sock/connect.c @@ -40,7 +40,6 @@ int connect(int fd, const void *addr, uint32_t addrsize) { int rc; if (addr && !(IsAsan() && !__asan_is_valid(addr, addrsize))) { - _firewall(addr, addrsize); if (!IsWindows()) { rc = sys_connect(fd, addr, addrsize); } else if (__isfdkind(fd, kFdSocket)) { diff --git a/libc/sock/internal.h b/libc/sock/internal.h index 5dbf00991..11a3f7026 100644 --- a/libc/sock/internal.h +++ b/libc/sock/internal.h @@ -91,8 +91,6 @@ struct SockFd { errno_t __dos2errno(uint32_t) hidden; -void _firewall(const void *, uint32_t) hidden; - int32_t __sys_accept(int32_t, void *, uint32_t *, int) dontdiscard hidden; int32_t __sys_accept4(int32_t, void *, uint32_t *, int) dontdiscard hidden; int32_t __sys_bind(int32_t, const void *, uint32_t) hidden; diff --git a/libc/sock/nointernet.c b/libc/sock/nointernet.c new file mode 100644 index 000000000..f9accce18 --- /dev/null +++ b/libc/sock/nointernet.c @@ -0,0 +1,348 @@ +/*-*- 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/assert.h" +#include "libc/calls/calls.h" +#include "libc/calls/struct/bpf.h" +#include "libc/calls/struct/filter.h" +#include "libc/calls/struct/seccomp.h" +#include "libc/calls/struct/sigaction.h" +#include "libc/calls/struct/sigset.h" +#include "libc/calls/syscall_support-sysv.internal.h" +#include "libc/dce.h" +#include "libc/errno.h" +#include "libc/intrin/describeflags.internal.h" +#include "libc/intrin/kprintf.h" +#include "libc/intrin/likely.h" +#include "libc/macros.internal.h" +#include "libc/runtime/runtime.h" +#include "libc/sock/sock.h" +#include "libc/sock/struct/msghdr.h" +#include "libc/sock/struct/sockaddr.h" +#include "libc/str/str.h" +#include "libc/sysv/consts/af.h" +#include "libc/sysv/consts/audit.h" +#include "libc/sysv/consts/nr.h" +#include "libc/sysv/consts/nrlinux.h" +#include "libc/sysv/consts/pr.h" +#include "libc/sysv/consts/ptrace.h" +#include "libc/sysv/consts/sig.h" +#include "libc/sysv/errfuns.h" +#include "net/http/ip.h" + +#define ORIG_RAX 120 +#define RAX 80 +#define RDI 112 +#define RSI 104 +#define RDX 96 +#define R8 72 +#define R9 64 +#define __WALL 0x40000000 + +#define OFF(f) offsetof(struct seccomp_data, f) + +#if 0 +#define DEBUG(...) kprintf(__VA_ARGS__) +#else +#define DEBUG(...) donothing +#endif + +#define ORDIE(x) \ + do { \ + if (UNLIKELY((x) == -1)) { \ + DEBUG("%s:%d: %s failed %m\n", __FILE__, __LINE__, #x); \ + asm("hlt"); \ + unreachable; \ + } \ + } while (0) + +static const struct sock_filter kInetBpf[] = { + // cargo culted architecture assertion + BPF_STMT(BPF_LD | BPF_W | BPF_ABS, OFF(arch)), + BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, AUDIT_ARCH_X86_64, 1, 0), + BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_KILL_PROCESS), + // block system calls from the future + BPF_STMT(BPF_LD + BPF_W + BPF_ABS, OFF(nr)), + BPF_JUMP(BPF_JMP | BPF_JGE | BPF_K, __NR_linux_memfd_secret, 0, 1), + BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ERRNO | 38), // ENOSYS + // only allow local and internet sockets + BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, __NR_linux_socket, 0, 5), + BPF_STMT(BPF_LD | BPF_W | BPF_ABS, OFF(args[0])), + BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0x001, 2, 0), // AF_UNIX + BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0x002, 1, 0), // AF_INET + BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ERRNO | 1), // EPERM + BPF_STMT(BPF_LD | BPF_W | BPF_ABS, OFF(nr)), + // support for these not implemented yet + BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0x133, 0, 1), // sendmmsg + BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ERRNO | 1), // EPERM + // trace syscalls with struct sockaddr + BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0x02e, 3, 0), // sendmsg + BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0x02c, 2, 0), // sendto + BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0x031, 1, 0), // bind + BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0x02a, 0, 1), // connect + BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_TRACE), + // default course of action + BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ALLOW), +}; + +static int PeekData(int pid, long addr, void *buf, size_t size) { + long i, j, w; + for (i = 0; i < size; i += sizeof(long)) { + if (sys_ptrace(PTRACE_PEEKTEXT, pid, addr + i, &w) != -1) { + for (j = 0; i + j < size && j < sizeof(long); ++j) { + ((char *)buf)[i + j] = w; + w >>= 8; + } + } else { + return -1; + } + } + return 0; +} + +static void LogProcessEvent(int main, int pid, int ws) { + DEBUG("trace: %s%06d%s 0x%06x", // + pid == main ? "\e[31;1m" : "", // + pid, // + pid == main ? "\e[0m" : "", // + ws); + if (WIFEXITED(ws)) { + DEBUG(" exit %d", WEXITSTATUS(ws)); + } + if (WIFSIGNALED(ws)) { + DEBUG(" sig %d", WTERMSIG(ws)); + } + if (WIFSTOPPED(ws)) { + DEBUG(" stop %s %s", strsignal(WSTOPSIG(ws)), + DescribePtraceEvent((ws & 0xff0000) >> 16)); + } + if (WIFCONTINUED(ws)) { + DEBUG(" cont"); + } + if (WCOREDUMP(ws)) { + DEBUG(" core"); + } + DEBUG("\n"); +} + +static int Raise(int sig) { + sigset_t mask; + sigaction(sig, &(struct sigaction){0}, 0); + sigfillset(&mask); + sigprocmask(SIG_SETMASK, &mask, 0); + kill(getpid(), sig); + sigdelset(&mask, sig); + sigprocmask(SIG_SETMASK, &mask, 0); + _Exit(128 + sig); +} + +static bool IsSockaddrAllowed(struct sockaddr_storage *addr) { + uint32_t ip; + if (addr->ss_family == AF_UNIX) { + return true; + } + if (addr->ss_family == AF_INET) { + ip = ntohl(((struct sockaddr_in *)addr)->sin_addr.s_addr); + if (!IsPublicIp(ip)) { + return true; + } else { + kprintf("warning: attempted to communicate with public ip " + "%hhd.%hhd.%hhd.%hhd\n", + ip >> 24, ip >> 16, ip >> 8, ip); + return false; + } + } + DEBUG("bad family %d\n", addr->ss_family); + return false; +} + +static void OnSockaddrSyscall(int pid, int r1, int r2) { + long si, dx; + uint32_t addrlen; + struct sockaddr_storage addr = {0}; + ORDIE(sys_ptrace(PTRACE_PEEKUSER, pid, r1, &si)); + ORDIE(sys_ptrace(PTRACE_PEEKUSER, pid, r2, &dx)); + addrlen = dx; + if (!si) { + // if address isn't supplied, it's probably safe. for example, + // send() is implemented in cosmo using sendto() with 0/0 addr + return; + } + if (PeekData(pid, si, &addr, MIN(addrlen, sizeof(addr))) == -1) { + DEBUG("failed to peek addr\n"); // probably an efault + goto Deny; + } + if (IsSockaddrAllowed(&addr)) { + return; + } else { + goto Deny; + } +Deny: + ORDIE(sys_ptrace(PTRACE_POKEUSER, pid, ORIG_RAX, -1)); +} + +static void OnSendmsg(int pid) { + long si; + struct msghdr msg = {0}; + struct sockaddr_storage addr = {0}; + ORDIE(sys_ptrace(PTRACE_PEEKUSER, pid, RSI, &si)); + if (PeekData(pid, si, &msg, sizeof(msg)) == -1) { + DEBUG("failed to peek msg\n"); // probably an efault + goto Deny; + } + if (!msg.msg_name) { + // if address isn't supplied, it's probably fine. + return; + } + if (PeekData(pid, (long)msg.msg_name, &addr, + MIN(msg.msg_namelen, sizeof(addr))) == -1) { + DEBUG("failed to peek msg name\n"); // probably an efault + goto Deny; + } + if (IsSockaddrAllowed(&addr)) { + return; + } else { + goto Deny; + } +Deny: + ORDIE(sys_ptrace(PTRACE_POKEUSER, pid, ORIG_RAX, -1)); +} + +static void HandleSeccompTrace(int pid) { + long ax; + ORDIE(sys_ptrace(PTRACE_PEEKUSER, pid, ORIG_RAX, &ax)); + switch (ax) { + case 0x031: // bind + case 0x02a: // connect + OnSockaddrSyscall(pid, RSI, RDX); + break; + case 0x02c: // sendto + OnSockaddrSyscall(pid, R8, R9); + break; + case 0x02e: // sendmsg + OnSendmsg(pid); + break; + default: + break; + } +} + +static int WaitForTrace(int main) { + int ws, pid; + for (;;) { + // waits for state change on any child process or thread + // eintr isn't possible since we're blocking all signals + ORDIE(pid = waitpid(-1, &ws, __WALL)); + LogProcessEvent(main, pid, ws); + // once main child exits or dies, we exit / die the same way. we're + // not currently tracking pids, so it's important that a child does + // not exit before its children. otherwise the grandchildren get in + // a permanently stopped state. to address that, we'll send sigterm + // to the process group which we defined earlier. + if (WIFEXITED(ws)) { + if (pid == main) { + kill(-getpid(), SIGTERM); + _Exit(WEXITSTATUS(ws)); + } + } else if (WIFSIGNALED(ws)) { + if (pid == main) { + kill(-getpid(), SIGTERM); + Raise(WTERMSIG(ws)); + } + } else if (WIFSTOPPED(ws)) { + if ((ws >> 8) == (SIGTRAP | (PTRACE_EVENT_SECCOMP << 8))) { + return pid; + } else if ((ws >> 8) == (SIGTRAP | (PTRACE_EVENT_EXEC << 8))) { + ORDIE(ptrace(PTRACE_CONT, pid, 0, 0)); + } else if ((ws >> 8) == (SIGTRAP | (PTRACE_EVENT_FORK << 8)) || + (ws >> 8) == (SIGTRAP | (PTRACE_EVENT_VFORK << 8)) || + (ws >> 8) == (SIGTRAP | (PTRACE_EVENT_CLONE << 8))) { + ORDIE(ptrace(PTRACE_CONT, pid, 0, 0)); + } else { + ORDIE(ptrace(PTRACE_CONT, pid, 0, WSTOPSIG(ws))); + } + } + } +} + +/** + * Disables internet access. + */ +int nointernet(void) { + int ws, act, main; + sigset_t set, old; + char path[PATH_MAX]; + struct sock_fprog prog = {.filter = kInetBpf, .len = ARRAYLEN(kInetBpf)}; + + // seccomp bpf and ptrace are pretty much just linux for now. + if (!IsLinux() || !__is_linux_2_6_23()) { + return enosys(); + } + + // ensure we're at the root of a process group, so we're able to + // broadcast a termination signal later on that catches dangling + // subprocesss our child forgot to destroy. without calling this + // subprocesses could end up permanently stopped if monitor dies + setpgrp(); + + // prevent crash handlers from intercepting sigsegv + ORDIE(sigfillset(&set)); + ORDIE(sigprocmask(SIG_SETMASK, &set, &old)); + + // create traced child that'll replace this program + if ((main = fork()) == -1) { + ORDIE(sigprocmask(SIG_SETMASK, &old, 0)); + return -1; + } + if (!main) { + if (sys_ptrace(PTRACE_TRACEME, 0, 0, 0) == -1) { + // there can be only one + // throw sigsegv on eperm + // we're already being traced + asm("hlt"); + } + prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0); + ORDIE(prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog)); + ORDIE(kill(getpid(), SIGSTOP)); + ORDIE(sigprocmask(SIG_SETMASK, &old, 0)); + // return to caller from child + return 0; + } + + // wait for child to stop itself + ORDIE(waitpid(main, &ws, 0)); + if (WIFSIGNALED(ws)) { + // child couldn't enable ptrace or seccomp + sigprocmask(SIG_SETMASK, &old, 0); + return eperm(); + } + assert(WIFSTOPPED(ws)); + + // parent process becomes monitor of subprocess tree. all signals + // continue to be blocked since we assume they'll also be sent to + // children, which will die, and then the monitor dies afterwards + ORDIE(sys_ptrace(PTRACE_SETOPTIONS, main, 0, + PTRACE_O_TRACESECCOMP | PTRACE_O_TRACEFORK | + PTRACE_O_TRACEVFORK | PTRACE_O_TRACECLONE | + PTRACE_O_TRACEEXEC)); + for (act = main;;) { + ORDIE(sys_ptrace(PTRACE_CONT, act, 0, 0)); + act = WaitForTrace(main); + HandleSeccompTrace(act); + } +} diff --git a/libc/sock/sendto.c b/libc/sock/sendto.c index a90d4c696..506a9b798 100644 --- a/libc/sock/sendto.c +++ b/libc/sock/sendto.c @@ -58,7 +58,6 @@ ssize_t sendto(int fd, const void *buf, size_t size, uint32_t flags, (opt_addr && !__asan_is_valid(opt_addr, addrsize)))) { rc = efault(); } else { - _firewall(opt_addr, addrsize); if (!IsWindows()) { if (!IsBsd() || !opt_addr) { rc = sys_sendto(fd, buf, size, flags, opt_addr, addrsize); diff --git a/libc/sock/sock.h b/libc/sock/sock.h index c1af5f745..800851433 100644 --- a/libc/sock/sock.h +++ b/libc/sock/sock.h @@ -24,6 +24,7 @@ uint32_t inet_addr(const char *); int parseport(const char *); uint32_t *GetHostIps(void); +int nointernet(void); int socket(int, int, int); int accept(int, void *, uint32_t *); int accept4(int, void *, uint32_t *, int); diff --git a/libc/sysv/calls/__sys_ptrace.s b/libc/sysv/calls/__sys_ptrace.s new file mode 100644 index 000000000..20505f254 --- /dev/null +++ b/libc/sysv/calls/__sys_ptrace.s @@ -0,0 +1,2 @@ +.include "o/libc/sysv/macros.internal.inc" +.scall __sys_ptrace,0x01a01a01a201a065,globl,hidden diff --git a/libc/sysv/calls/sys_ptrace.s b/libc/sysv/calls/sys_ptrace.s deleted file mode 100644 index d68c6c913..000000000 --- a/libc/sysv/calls/sys_ptrace.s +++ /dev/null @@ -1,2 +0,0 @@ -.include "o/libc/sysv/macros.internal.inc" -.scall sys_ptrace,0x01a01a01a201a065,globl,hidden diff --git a/libc/sysv/syscalls.sh b/libc/sysv/syscalls.sh index 9d40592a0..39c3ff0c5 100755 --- a/libc/sysv/syscalls.sh +++ b/libc/sysv/syscalls.sh @@ -139,7 +139,7 @@ scall sys_getrlimit 0x0c20c20c220c2061 globl hidden scall __sys_getrusage 0x1bd0130752075062 globl hidden scall sys_sysinfo 0xfffffffffffff063 globl hidden scall sys_times 0xfffffffffffff064 globl hidden -scall sys_ptrace 0x01a01a01a201a065 globl hidden +scall __sys_ptrace 0x01a01a01a201a065 globl hidden # ptrace() wrapper api is terrible scall sys_syslog 0xfffffffffffff067 globl hidden scall sys_getuid 0x0180180182018066 globl hidden scall sys_getgid 0x02f02f02f202f068 globl hidden diff --git a/test/libc/calls/ptrace_test.c b/test/libc/calls/ptrace_test.c new file mode 100644 index 000000000..e69de29bb diff --git a/test/libc/calls/sys_ptrace_test.c b/test/libc/calls/sys_ptrace_test.c new file mode 100644 index 000000000..e69de29bb diff --git a/test/libc/sock/nointernet_test.c b/test/libc/sock/nointernet_test.c new file mode 100644 index 000000000..ff4261044 --- /dev/null +++ b/test/libc/sock/nointernet_test.c @@ -0,0 +1,85 @@ +/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ +│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│ +╞══════════════════════════════════════════════════════════════════════════════╡ +│ Copyright 2022 Justine Alexandra Roberts Tunney │ +│ │ +│ Permission to use, copy, modify, and/or distribute this software for │ +│ any purpose with or without fee is hereby granted, provided that the │ +│ above copyright notice and this permission notice appear in all copies. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ +│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ +│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ +│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ +│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ +│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ +│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ +│ PERFORMANCE OF THIS SOFTWARE. │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/calls/calls.h" +#include "libc/calls/struct/stat.h" +#include "libc/calls/syscall_support-sysv.internal.h" +#include "libc/dce.h" +#include "libc/errno.h" +#include "libc/log/log.h" +#include "libc/runtime/runtime.h" +#include "libc/sock/sock.h" +#include "libc/sock/struct/msghdr.h" +#include "libc/sock/struct/sockaddr.h" +#include "libc/sysv/consts/af.h" +#include "libc/sysv/consts/ipproto.h" +#include "libc/sysv/consts/o.h" +#include "libc/sysv/consts/sock.h" +#include "libc/testlib/testlib.h" + +char testlib_enable_tmp_setup_teardown; + +void SetUpOnce(void) { + if (nointernet() == -1) { + ASSERT_TRUE(errno == EPERM || // already traced + errno == ENOSYS); // non-linux or ancient linux + if (errno == ENOSYS) { + exit(0); + } + } +} + +TEST(nointernet, testLocalhost_isAllowed) { + struct sockaddr_in addr = {AF_INET, 0, {htonl(0x7f000001)}}; + ASSERT_SYS(0, 3, socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)); + ASSERT_SYS(0, 0, bind(3, &addr, sizeof(addr))); + ASSERT_SYS(ECONNREFUSED, -1, connect(3, &addr, sizeof(addr))); + ASSERT_SYS(0, 0, close(3)); +} + +TEST(nointernet, testPublicInternet_isDenied) { + struct sockaddr_in addr = {AF_INET, 0, {htonl(0x06060600)}}; + ASSERT_SYS(EPERM, -1, socket(AF_BLUETOOTH, SOCK_STREAM, IPPROTO_TCP)); + ASSERT_SYS(0, 3, socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)); + ASSERT_SYS(ENOSYS, -1, bind(3, &addr, sizeof(addr))); + ASSERT_SYS(ENOSYS, -1, connect(3, &addr, sizeof(addr))); + ASSERT_SYS(0, 0, close(3)); +} + +TEST(nointernet, sendmsgPrivateNetwork_doesntGetBlocked) { + struct msghdr msg = { + .msg_name = &(struct sockaddr_in){AF_INET, 31337, {htonl(0x0a000001)}}, + .msg_namelen = sizeof(struct sockaddr_in), + .msg_iov = &(struct iovec){"hi", 2}, + .msg_iovlen = 1, + }; + ASSERT_SYS(EBADF, -1, sendmsg(-1, &msg, 0)); +} + +TEST(nointernet, sendmsgPublicNetwork_raisesEnosys_whichPreemptsEbadf) { + struct msghdr msg = { + .msg_name = &(struct sockaddr_in){AF_INET, 31337, {htonl(0x06060600)}}, + .msg_namelen = sizeof(struct sockaddr_in), + .msg_iov = &(struct iovec){"hi", 2}, + .msg_iovlen = 1, + }; + ASSERT_SYS(ENOSYS, -1, sendmsg(-1, &msg, 0)); + ASSERT_SYS(0, 3, socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)); + ASSERT_SYS(ENOSYS, -1, sendmsg(3, &msg, 0)); + ASSERT_SYS(0, 0, close(3)); +} diff --git a/test/libc/sock/sendrecvmsg_test.c b/test/libc/sock/sendrecvmsg_test.c index ff92fb599..c7381a69a 100644 --- a/test/libc/sock/sendrecvmsg_test.c +++ b/test/libc/sock/sendrecvmsg_test.c @@ -19,11 +19,14 @@ #include "libc/assert.h" #include "libc/calls/struct/iovec.h" #include "libc/dce.h" +#include "libc/errno.h" #include "libc/runtime/gc.internal.h" #include "libc/sock/sock.h" #include "libc/sock/struct/msghdr.h" +#include "libc/sock/struct/sockaddr.h" #include "libc/str/str.h" #include "libc/sysv/consts/af.h" +#include "libc/sysv/consts/ipproto.h" #include "libc/sysv/consts/o.h" #include "libc/sysv/consts/sock.h" #include "libc/testlib/testlib.h" diff --git a/test/libc/sock/test.mk b/test/libc/sock/test.mk index 375d3e4fc..7582ac7e2 100644 --- a/test/libc/sock/test.mk +++ b/test/libc/sock/test.mk @@ -34,6 +34,7 @@ TEST_LIBC_SOCK_DIRECTDEPS = \ LIBC_STR \ LIBC_STUBS \ LIBC_SYSV \ + LIBC_SYSV_CALLS \ LIBC_TESTLIB \ LIBC_X \ TOOL_DECODE_LIB diff --git a/test/tool/build/lib/xlaterrno_test.c b/test/tool/build/lib/xlaterrno_test.c index b641e559d..9e5aa2ad5 100644 --- a/test/tool/build/lib/xlaterrno_test.c +++ b/test/tool/build/lib/xlaterrno_test.c @@ -18,6 +18,7 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/errno.h" #include "libc/testlib/testlib.h" +#include "tool/build/lib/xlat.h" #include "tool/build/lib/xlaterrno.h" TEST(xlaterrno, test) { diff --git a/third_party/make/job.c b/third_party/make/job.c index 6dc9cb239..fa7509565 100644 --- a/third_party/make/job.c +++ b/third_party/make/job.c @@ -67,6 +67,7 @@ this program. If not, see . */ #include "libc/macros.internal.h" #include "libc/log/rop.h" #include "libc/intrin/kprintf.h" +#include "libc/sock/sock.h" #include "third_party/make/dep.h" #define GOTO_SLOW \ diff --git a/third_party/make/main.c b/third_party/make/main.c index eba98d7d9..faab247fa 100644 --- a/third_party/make/main.c +++ b/third_party/make/main.c @@ -30,6 +30,21 @@ this program. If not, see . */ #include "libc/log/log.h" #include "libc/log/log.h" #include "libc/log/log.h" +#include "libc/sock/sock.h" +#include "libc/dce.h" +#include "libc/calls/syscall_support-sysv.internal.h" +#include "libc/calls/struct/seccomp.h" +#include "libc/calls/struct/bpf.h" +#include "libc/sysv/consts/audit.h" +#include "libc/calls/struct/seccomp.h" +#include "libc/sysv/consts/pr.h" +#include "libc/calls/calls.h" +#include "libc/macros.internal.h" +#include "libc/stdio/stdio.h" +#include "libc/calls/struct/filter.h" +#include "libc/runtime/runtime.h" +#include "libc/runtime/runtime.h" +#include "libc/runtime/runtime.h" #include "third_party/make/getopt.h" STATIC_STACK_SIZE(0x200000); // 2mb stack @@ -963,16 +978,10 @@ main (int argc, char **argv, char **envp) unsigned int restarts = 0; unsigned int syncing = 0; int argv_slots; -#ifdef WINDOWS32 - const char *unix_path = NULL; - const char *windows32_path = NULL; - SetUnhandledExceptionFilter (handle_runtime_exceptions); - - /* start off assuming we have no shell */ - unixy_shell = 0; - no_default_sh_exe = 1; -#endif + // block internet access + if (!getenv("MAKE_RESTARTS")) + nointernet (); /* Useful for attaching debuggers, etc. */ SPIN ("main-entry"); diff --git a/third_party/make/make.mk b/third_party/make/make.mk index 36e8a5671..47670bd78 100644 --- a/third_party/make/make.mk +++ b/third_party/make/make.mk @@ -119,6 +119,7 @@ THIRD_PARTY_MAKE_DIRECTDEPS = \ LIBC_RUNTIME \ LIBC_STDIO \ LIBC_STR \ + LIBC_SOCK \ LIBC_SYSV \ LIBC_SYSV_CALLS \ LIBC_TIME \ diff --git a/tool/build/blinkenlights.c b/tool/build/blinkenlights.c index af867a057..449baccc9 100644 --- a/tool/build/blinkenlights.c +++ b/tool/build/blinkenlights.c @@ -20,8 +20,6 @@ #include "dsp/tty/tty.h" #include "libc/alg/arraylist2.internal.h" #include "libc/assert.h" -#include "libc/intrin/bits.h" -#include "libc/intrin/safemacros.internal.h" #include "libc/calls/calls.h" #include "libc/calls/ioctl.h" #include "libc/calls/struct/iovec.h" @@ -30,14 +28,17 @@ #include "libc/calls/struct/termios.h" #include "libc/calls/struct/winsize.h" #include "libc/calls/termios.h" +#include "libc/calls/ucontext.h" #include "libc/dce.h" #include "libc/fmt/bing.internal.h" #include "libc/fmt/conv.h" #include "libc/fmt/fmt.h" #include "libc/fmt/itoa.h" #include "libc/intrin/asan.internal.h" +#include "libc/intrin/bits.h" #include "libc/intrin/pcmpeqb.h" #include "libc/intrin/pmovmskb.h" +#include "libc/intrin/safemacros.internal.h" #include "libc/limits.h" #include "libc/log/check.h" #include "libc/log/color.internal.h" @@ -46,11 +47,11 @@ #include "libc/macros.internal.h" #include "libc/math.h" #include "libc/mem/mem.h" -#include "libc/stdio/rand.h" #include "libc/runtime/gc.internal.h" #include "libc/runtime/runtime.h" #include "libc/sock/sock.h" #include "libc/stdio/append.internal.h" +#include "libc/stdio/rand.h" #include "libc/stdio/stdio.h" #include "libc/str/str.h" #include "libc/str/thompike.h" @@ -94,6 +95,7 @@ #include "tool/build/lib/panel.h" #include "tool/build/lib/pml4t.h" #include "tool/build/lib/pty.h" +#include "tool/build/lib/signal.h" #include "tool/build/lib/stats.h" #include "tool/build/lib/syscall.h" #include "tool/build/lib/throw.h" @@ -1647,6 +1649,18 @@ static char *GetStatus(int m) { if (!first) { appendw(&b, ')'); } + if (action & RESTART) appends(&b, " RESTART"); + if (action & REDRAW) appends(&b, " REDRAW"); + if (action & CONTINUE) appends(&b, " CONTINUE"); + if (action & STEP) appends(&b, " STEP"); + if (action & NEXT) appends(&b, " NEXT"); + if (action & FINISH) appends(&b, " FINISH"); + if (action & FAILURE) appends(&b, " FAILURE"); + if (action & WINCHED) appends(&b, " WINCHED"); + if (action & INT) appends(&b, " INT"); + if (action & QUIT) appends(&b, " QUIT"); + if (action & EXIT) appends(&b, " EXIT"); + if (action & ALARM) appends(&b, " ALARM"); return b; } @@ -2023,7 +2037,7 @@ static int OnPtyFdTcsets(int fd, uint64_t request, struct termios *c) { return 0; } -static int OnPtyFdIoctl(int fd, uint64_t request, void *memory) { +static int OnPtyFdIoctl(int fd, int request, void *memory) { if (request == TIOCGWINSZ) { return OnPtyFdTiocgwinsz(fd, memory); } else if (request == TCGETS) { @@ -2039,7 +2053,7 @@ static const struct MachineFdCb kMachineFdCbPty = { .close = OnPtyFdClose, .readv = OnPtyFdReadv, .writev = OnPtyFdWritev, - .ioctl = OnPtyFdIoctl, + .ioctl = (void *)OnPtyFdIoctl, .poll = OnPtyFdPoll, }; @@ -2808,6 +2822,9 @@ static void Exec(void) { tuimode = true; LoadInstruction(m); ExecuteInstruction(m); + if (m->signals.i < m->signals.n) { + ConsumeSignal(m); + } ++opcount; CheckFramePointer(); } else { @@ -2822,6 +2839,9 @@ static void Exec(void) { break; } ExecuteInstruction(m); + if (m->signals.i < m->signals.n) { + ConsumeSignal(m); + } ++opcount; KeepGoing: CheckFramePointer(); @@ -2960,6 +2980,9 @@ static void Tui(void) { if (!IsDebugBreak()) { UpdateXmmType(m, &xmmtype); ExecuteInstruction(m); + if (m->signals.i < m->signals.n) { + ConsumeSignal(m); + } ++opcount; if (!(action & CONTINUE) || interactive) { if (!(action & CONTINUE)) ReactiveDraw(); @@ -3102,7 +3125,12 @@ static void OnlyRunOnFirstCpu(void) { sched_setaffinity(0, sizeof(bs), &bs); } +static void OnSignal(int sig, siginfo_t *si, ucontext_t *uc) { + EnqueueSignal(m, sig, si->si_code); +} + int main(int argc, char *argv[]) { + struct sigaction sa; if (!NoDebug()) { ShowCrashReports(); } @@ -3110,6 +3138,7 @@ int main(int argc, char *argv[]) { pty->conf |= kPtyNocanon; m = NewMachine(); m->mode = XED_MACHINE_MODE_LONG_64; + m->redraw = Redraw; m->onbinbase = OnBinbase; m->onlongbranch = OnLongBranch; speed = 4; @@ -3124,7 +3153,22 @@ int main(int argc, char *argv[]) { g_high.quote = 215; } GetOpts(argc, argv); + if (optind == argc) { + PrintUsage(EX_USAGE, stderr); + } xsigaction(SIGALRM, OnSigAlarm, 0, 0, 0); - if (optind == argc) PrintUsage(EX_USAGE, stderr); + memset(&sa, 0, sizeof(sa)); + sigfillset(&sa.sa_mask); + sa.sa_flags |= SA_SIGINFO; + sa.sa_sigaction = OnSignal; + sigaction(SIGHUP, &sa, 0); + sigaction(SIGQUIT, &sa, 0); + sigaction(SIGABRT, &sa, 0); + sigaction(SIGUSR1, &sa, 0); + sigaction(SIGUSR2, &sa, 0); + sigaction(SIGPIPE, &sa, 0); + sigaction(SIGTERM, &sa, 0); + sigaction(SIGCHLD, &sa, 0); + sigaction(SIGWINCH, &sa, 0); return Emulator(argc, argv); } diff --git a/tool/build/lib/bits.h b/tool/build/lib/bits.h new file mode 100755 index 000000000..c8332ccfc --- /dev/null +++ b/tool/build/lib/bits.h @@ -0,0 +1,166 @@ +#ifndef COSMOPOLITAN_TOOL_BUILD_LIB_BITS_H_ +#define COSMOPOLITAN_TOOL_BUILD_LIB_BITS_H_ +#if !(__ASSEMBLER__ + __LINKER__ + 0) +COSMOPOLITAN_C_START_ + +struct iovec_bits { + uint8_t iov_base[8]; + uint8_t iov_len[8]; +}; + +struct pollfd_bits { + uint8_t fd[4]; + uint8_t events[2]; + uint8_t revents[2]; +}; + +struct timeval_bits { + uint8_t tv_sec[8]; + uint8_t tv_usec[8]; +}; + +struct timespec_bits { + uint8_t tv_sec[8]; + uint8_t tv_nsec[8]; +}; + +struct timezone_bits { + uint8_t tz_minuteswest[4]; + uint8_t tz_dsttime[4]; +}; + +struct sigaction_bits { + uint8_t handler[8]; + uint8_t flags[8]; + uint8_t restorer[8]; + uint8_t mask[8]; +}; + +struct winsize_bits { + uint8_t ws_row[2]; + uint8_t ws_col[2]; + uint8_t ws_xpixel[2]; + uint8_t ws_ypixel[2]; +}; + +struct termios_bits { + uint8_t c_iflag[4]; + uint8_t c_oflag[4]; + uint8_t c_cflag[4]; + uint8_t c_lflag[4]; + uint8_t c_cc[32]; + uint8_t c_ispeed[4]; + uint8_t c_ospeed[4]; +}; + +struct sockaddr_in_bits { + uint8_t sin_family[2]; + uint16_t sin_port; + uint32_t sin_addr; + uint8_t sin_zero[8]; +}; + +struct stat_bits { + uint8_t st_dev[8]; + uint8_t st_ino[8]; + uint8_t st_nlink[8]; + uint8_t st_mode[4]; + uint8_t st_uid[4]; + uint8_t st_gid[4]; + uint8_t __pad[4]; + uint8_t st_rdev[8]; + uint8_t st_size[8]; + uint8_t st_blksize[8]; + uint8_t st_blocks[8]; + struct timespec_bits st_atim; + struct timespec_bits st_mtim; + struct timespec_bits st_ctim; +}; + +struct itimerval_bits { + struct timeval_bits it_interval; + struct timeval_bits it_value; +}; + +struct rusage_bits { + struct timeval_bits ru_utime; + struct timeval_bits ru_stime; + uint8_t ru_maxrss[8]; + uint8_t ru_ixrss[8]; + uint8_t ru_idrss[8]; + uint8_t ru_isrss[8]; + uint8_t ru_minflt[8]; + uint8_t ru_majflt[8]; + uint8_t ru_nswap[8]; + uint8_t ru_inblock[8]; + uint8_t ru_oublock[8]; + uint8_t ru_msgsnd[8]; + uint8_t ru_msgrcv[8]; + uint8_t ru_nsignals[8]; + uint8_t ru_nvcsw[8]; + uint8_t ru_nivcsw[8]; +}; + +struct siginfo_bits { + uint8_t si_signo[4]; + uint8_t si_errno[4]; + uint8_t si_code[4]; + uint8_t __pad[4]; + uint8_t payload[112]; +}; + +struct fpstate_bits { + uint8_t cwd[2]; + uint8_t swd[2]; + uint8_t ftw[2]; + uint8_t fop[2]; + uint8_t rip[8]; + uint8_t rdp[8]; + uint8_t mxcsr[4]; + uint8_t mxcr_mask[4]; + uint8_t st[8][16]; + uint8_t xmm[16][16]; + uint8_t __padding[96]; +}; + +struct ucontext_bits { + uint8_t uc_flags[8]; + uint8_t uc_link[8]; + uint8_t ss_sp[8]; + uint8_t ss_flags[4]; + uint8_t __pad0[4]; + uint8_t ss_size[8]; + uint8_t r8[8]; + uint8_t r9[8]; + uint8_t r10[8]; + uint8_t r11[8]; + uint8_t r12[8]; + uint8_t r13[8]; + uint8_t r14[8]; + uint8_t r15[8]; + uint8_t rdi[8]; + uint8_t rsi[8]; + uint8_t rbp[8]; + uint8_t rbx[8]; + uint8_t rdx[8]; + uint8_t rax[8]; + uint8_t rcx[8]; + uint8_t rsp[8]; + uint8_t rip[8]; + uint8_t eflags[8]; + uint8_t cs[2]; + uint8_t gs[2]; + uint8_t fs[2]; + uint8_t ss[2]; + uint8_t err[8]; + uint8_t trapno[8]; + uint8_t oldmask[8]; + uint8_t cr2[8]; + uint8_t fpstate[8]; + uint8_t __pad1[64]; + uint8_t uc_sigmask[8]; +}; + +COSMOPOLITAN_C_END_ +#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ +#endif /* COSMOPOLITAN_TOOL_BUILD_LIB_BITS_H_ */ diff --git a/tool/build/lib/cvt.c b/tool/build/lib/cvt.c index 04f4373dc..f0756cf27 100644 --- a/tool/build/lib/cvt.c +++ b/tool/build/lib/cvt.c @@ -21,9 +21,11 @@ #include "libc/str/str.h" #include "tool/build/lib/cvt.h" #include "tool/build/lib/endian.h" +#include "tool/build/lib/fpu.h" #include "tool/build/lib/machine.h" #include "tool/build/lib/memory.h" #include "tool/build/lib/modrm.h" +#include "tool/build/lib/pun.h" #include "tool/build/lib/throw.h" #define kOpCvt0f2a 0 @@ -34,7 +36,7 @@ #define kOpCvt0fE6 20 static double SseRoundDouble(struct Machine *m, double x) { - switch (m->sse.rc) { + switch ((m->mxcsr & kMxcsrRc) >> 13) { case 0: return rint(x); case 1: @@ -44,252 +46,318 @@ static double SseRoundDouble(struct Machine *m, double x) { case 3: return trunc(x); default: - unreachable; + for (;;) (void)0; } } static void OpGdqpWssCvttss2si(struct Machine *m, uint32_t rde) { - float f; int64_t n; - memcpy(&f, GetModrmRegisterXmmPointerRead4(m, rde), 4); - n = f; + union FloatPun f; + f.i = Read32(GetModrmRegisterXmmPointerRead4(m, rde)); + n = f.f; if (!Rexw(rde)) n &= 0xffffffff; Write64(RegRexrReg(m, rde), n); } static void OpGdqpWsdCvttsd2si(struct Machine *m, uint32_t rde) { - double d; int64_t n; - memcpy(&d, GetModrmRegisterXmmPointerRead8(m, rde), 8); - n = d; + union DoublePun d; + d.i = Read64(GetModrmRegisterXmmPointerRead8(m, rde)); + n = d.f; if (!Rexw(rde)) n &= 0xffffffff; Write64(RegRexrReg(m, rde), n); } static void OpGdqpWssCvtss2si(struct Machine *m, uint32_t rde) { - float f; int64_t n; - memcpy(&f, GetModrmRegisterXmmPointerRead4(m, rde), 4); - n = rintf(f); + union FloatPun f; + f.i = Read32(GetModrmRegisterXmmPointerRead4(m, rde)); + n = rintf(f.f); if (!Rexw(rde)) n &= 0xffffffff; Write64(RegRexrReg(m, rde), n); } static void OpGdqpWsdCvtsd2si(struct Machine *m, uint32_t rde) { - double d; int64_t n; - memcpy(&d, GetModrmRegisterXmmPointerRead8(m, rde), 8); - n = SseRoundDouble(m, d); + union DoublePun d; + d.i = Read64(GetModrmRegisterXmmPointerRead8(m, rde)); + n = SseRoundDouble(m, d.f); if (!Rexw(rde)) n &= 0xffffffff; Write64(RegRexrReg(m, rde), n); } static void OpVssEdqpCvtsi2ss(struct Machine *m, uint32_t rde) { - float f; - int64_t n; - uint8_t *p; + union FloatPun f; if (Rexw(rde)) { - n = (int64_t)Read64(GetModrmRegisterWordPointerRead8(m, rde)); + int64_t n; + n = Read64(GetModrmRegisterWordPointerRead8(m, rde)); + f.f = n; + Write32(XmmRexrReg(m, rde), f.i); } else { - n = (int32_t)Read32(GetModrmRegisterWordPointerRead4(m, rde)); + int32_t n; + n = Read32(GetModrmRegisterWordPointerRead4(m, rde)); + f.f = n; + Write32(XmmRexrReg(m, rde), f.i); } - f = n; - memcpy(XmmRexrReg(m, rde), &f, 4); } static void OpVsdEdqpCvtsi2sd(struct Machine *m, uint32_t rde) { - double d; - int64_t n; - uint8_t *p; + union DoublePun d; if (Rexw(rde)) { - n = (int64_t)Read64(GetModrmRegisterWordPointerRead8(m, rde)); + int64_t n; + n = Read64(GetModrmRegisterWordPointerRead8(m, rde)); + d.f = n; + Write64(XmmRexrReg(m, rde), d.i); } else { - n = (int32_t)Read32(GetModrmRegisterWordPointerRead4(m, rde)); + int32_t n; + n = Read32(GetModrmRegisterWordPointerRead4(m, rde)); + d.f = n; + Write64(XmmRexrReg(m, rde), d.i); } - d = n; - memcpy(XmmRexrReg(m, rde), &d, 8); } static void OpVpsQpiCvtpi2ps(struct Machine *m, uint32_t rde) { uint8_t *p; - float f[2]; int32_t i[2]; + union FloatPun f[2]; p = GetModrmRegisterMmPointerRead8(m, rde); i[0] = Read32(p + 0); i[1] = Read32(p + 4); - f[0] = i[0]; - f[1] = i[1]; - memcpy(XmmRexrReg(m, rde), f, 8); + f[0].f = i[0]; + f[1].f = i[1]; + Write32(XmmRexrReg(m, rde) + 0, f[0].i); + Write32(XmmRexrReg(m, rde) + 4, f[1].i); } static void OpVpdQpiCvtpi2pd(struct Machine *m, uint32_t rde) { uint8_t *p; - double f[2]; int32_t n[2]; + union DoublePun f[2]; p = GetModrmRegisterMmPointerRead8(m, rde); n[0] = Read32(p + 0); n[1] = Read32(p + 4); - f[0] = n[0]; - f[1] = n[1]; - memcpy(XmmRexrReg(m, rde), f, 16); + f[0].f = n[0]; + f[1].f = n[1]; + Write64(XmmRexrReg(m, rde) + 0, f[0].i); + Write64(XmmRexrReg(m, rde) + 8, f[1].i); } static void OpPpiWpsqCvtps2pi(struct Machine *m, uint32_t rde) { + uint8_t *p; unsigned i; - float f[2]; int32_t n[2]; - memcpy(f, GetModrmRegisterXmmPointerRead8(m, rde), 8); - switch (m->sse.rc) { + union FloatPun f[2]; + p = GetModrmRegisterXmmPointerRead8(m, rde); + f[0].i = Read32(p + 0 * 4); + f[1].i = Read32(p + 1 * 4); + switch ((m->mxcsr & kMxcsrRc) >> 13) { case 0: - for (i = 0; i < 2; ++i) n[i] = rintf(f[i]); + for (i = 0; i < 2; ++i) n[i] = rintf(f[i].f); break; case 1: - for (i = 0; i < 2; ++i) n[i] = floorf(f[i]); + for (i = 0; i < 2; ++i) n[i] = floorf(f[i].f); break; case 2: - for (i = 0; i < 2; ++i) n[i] = ceilf(f[i]); + for (i = 0; i < 2; ++i) n[i] = ceilf(f[i].f); break; case 3: - for (i = 0; i < 2; ++i) n[i] = truncf(f[i]); + for (i = 0; i < 2; ++i) n[i] = truncf(f[i].f); break; default: - unreachable; + for (;;) (void)0; } Write32(MmReg(m, rde) + 0, n[0]); Write32(MmReg(m, rde) + 4, n[1]); } static void OpPpiWpsqCvttps2pi(struct Machine *m, uint32_t rde) { - float f[2]; + uint8_t *p; int32_t n[2]; - memcpy(&f, GetModrmRegisterXmmPointerRead8(m, rde), 8); - n[0] = f[0]; - n[1] = f[1]; + union FloatPun f[2]; + p = GetModrmRegisterXmmPointerRead8(m, rde); + f[0].i = Read32(p + 0); + f[1].i = Read32(p + 4); + n[0] = f[0].f; + n[1] = f[1].f; Write32(MmReg(m, rde) + 0, n[0]); Write32(MmReg(m, rde) + 4, n[1]); } static void OpPpiWpdCvtpd2pi(struct Machine *m, uint32_t rde) { + uint8_t *p; unsigned i; - double d[2]; int32_t n[2]; - memcpy(d, GetModrmRegisterXmmPointerRead16(m, rde), 16); - for (i = 0; i < 2; ++i) n[i] = SseRoundDouble(m, d[i]); + union DoublePun d[2]; + p = GetModrmRegisterXmmPointerRead16(m, rde); + d[0].i = Read64(p + 0); + d[1].i = Read64(p + 8); + for (i = 0; i < 2; ++i) n[i] = SseRoundDouble(m, d[i].f); Write32(MmReg(m, rde) + 0, n[0]); Write32(MmReg(m, rde) + 4, n[1]); } static void OpPpiWpdCvttpd2pi(struct Machine *m, uint32_t rde) { - double d[2]; + uint8_t *p; int32_t n[2]; - memcpy(&d, GetModrmRegisterXmmPointerRead16(m, rde), 16); - n[0] = d[0]; - n[1] = d[1]; + union DoublePun d[2]; + p = GetModrmRegisterXmmPointerRead16(m, rde); + d[0].i = Read64(p + 0); + d[1].i = Read64(p + 8); + n[0] = d[0].f; + n[1] = d[1].f; Write32(MmReg(m, rde) + 0, n[0]); Write32(MmReg(m, rde) + 4, n[1]); } static void OpVpdWpsCvtps2pd(struct Machine *m, uint32_t rde) { - float f[2]; - double d[2]; - memcpy(f, GetModrmRegisterXmmPointerRead8(m, rde), 8); - d[0] = f[0]; - d[1] = f[1]; - memcpy(XmmRexrReg(m, rde), d, 16); + uint8_t *p; + union FloatPun f[2]; + union DoublePun d[2]; + p = GetModrmRegisterXmmPointerRead8(m, rde); + f[0].i = Read32(p + 0); + f[1].i = Read32(p + 4); + d[0].f = f[0].f; + d[1].f = f[1].f; + Write64(XmmRexrReg(m, rde) + 0, d[0].i); + Write64(XmmRexrReg(m, rde) + 8, d[1].i); } static void OpVpsWpdCvtpd2ps(struct Machine *m, uint32_t rde) { - float f[2]; - double d[2]; - memcpy(d, GetModrmRegisterXmmPointerRead16(m, rde), 16); - f[0] = d[0]; - f[1] = d[1]; - memcpy(XmmRexrReg(m, rde), f, 8); + uint8_t *p; + union FloatPun f[2]; + union DoublePun d[2]; + p = GetModrmRegisterXmmPointerRead16(m, rde); + d[0].i = Read64(p + 0); + d[1].i = Read64(p + 8); + f[0].f = d[0].f; + f[1].f = d[1].f; + Write32(XmmRexrReg(m, rde) + 0, f[0].i); + Write32(XmmRexrReg(m, rde) + 4, f[1].i); } static void OpVssWsdCvtsd2ss(struct Machine *m, uint32_t rde) { - float f; - double d; - memcpy(&d, GetModrmRegisterXmmPointerRead8(m, rde), 8); - f = d; - memcpy(XmmRexrReg(m, rde), &f, 4); + union FloatPun f; + union DoublePun d; + d.i = Read64(GetModrmRegisterXmmPointerRead8(m, rde)); + f.f = d.f; + Write32(XmmRexrReg(m, rde), f.i); } static void OpVsdWssCvtss2sd(struct Machine *m, uint32_t rde) { - float f; - double d; - memcpy(&f, GetModrmRegisterXmmPointerRead4(m, rde), 4); - d = f; - memcpy(XmmRexrReg(m, rde), &d, 8); + union FloatPun f; + union DoublePun d; + f.i = Read32(GetModrmRegisterXmmPointerRead4(m, rde)); + d.f = f.f; + Write64(XmmRexrReg(m, rde), d.i); } static void OpVpsWdqCvtdq2ps(struct Machine *m, uint32_t rde) { - unsigned i; - float f[4]; + uint8_t *p; int32_t n[4]; - memcpy(n, GetModrmRegisterXmmPointerRead16(m, rde), 16); - for (i = 0; i < 4; ++i) f[i] = n[i]; - memcpy(XmmRexrReg(m, rde), f, 16); + union FloatPun f[4]; + p = GetModrmRegisterXmmPointerRead16(m, rde); + n[0] = Read32(p + 0 * 4); + n[1] = Read32(p + 1 * 4); + n[2] = Read32(p + 2 * 4); + n[3] = Read32(p + 3 * 4); + f[0].f = n[0]; + f[1].f = n[1]; + f[2].f = n[2]; + f[3].f = n[3]; + Write32(XmmRexrReg(m, rde) + 0 * 4, f[0].i); + Write32(XmmRexrReg(m, rde) + 1 * 4, f[1].i); + Write32(XmmRexrReg(m, rde) + 2 * 4, f[2].i); + Write32(XmmRexrReg(m, rde) + 3 * 4, f[3].i); } static void OpVpdWdqCvtdq2pd(struct Machine *m, uint32_t rde) { - unsigned i; - double d[2]; + uint8_t *p; int32_t n[2]; - memcpy(n, GetModrmRegisterXmmPointerRead8(m, rde), 8); - for (i = 0; i < 2; ++i) d[i] = n[i]; - memcpy(XmmRexrReg(m, rde), d, 16); + union DoublePun d[2]; + p = GetModrmRegisterXmmPointerRead8(m, rde); + n[0] = Read32(p + 0 * 4); + n[1] = Read32(p + 1 * 4); + d[0].f = n[0]; + d[1].f = n[1]; + Write64(XmmRexrReg(m, rde) + 0, d[0].i); + Write64(XmmRexrReg(m, rde) + 8, d[1].i); } static void OpVdqWpsCvttps2dq(struct Machine *m, uint32_t rde) { - unsigned i; - float f[4]; + uint8_t *p; int32_t n[4]; - memcpy(f, GetModrmRegisterXmmPointerRead16(m, rde), 16); - for (i = 0; i < 4; ++i) n[i] = f[i]; - memcpy(XmmRexrReg(m, rde), n, 16); + union FloatPun f[4]; + p = GetModrmRegisterXmmPointerRead16(m, rde); + f[0].i = Read32(p + 0 * 4); + f[1].i = Read32(p + 1 * 4); + f[2].i = Read32(p + 2 * 4); + f[3].i = Read32(p + 3 * 4); + n[0] = f[0].f; + n[1] = f[1].f; + n[2] = f[2].f; + n[3] = f[3].f; + Write32(XmmRexrReg(m, rde) + 0 * 4, n[0]); + Write32(XmmRexrReg(m, rde) + 1 * 4, n[1]); + Write32(XmmRexrReg(m, rde) + 2 * 4, n[2]); + Write32(XmmRexrReg(m, rde) + 3 * 4, n[3]); } static void OpVdqWpsCvtps2dq(struct Machine *m, uint32_t rde) { + uint8_t *p; unsigned i; - float f[4]; int32_t n[4]; - memcpy(f, GetModrmRegisterXmmPointerRead16(m, rde), 16); - switch (m->sse.rc) { + union FloatPun f[4]; + p = GetModrmRegisterXmmPointerRead16(m, rde); + f[0].i = Read32(p + 0 * 4); + f[1].i = Read32(p + 1 * 4); + f[2].i = Read32(p + 2 * 4); + f[3].i = Read32(p + 3 * 4); + switch ((m->mxcsr & kMxcsrRc) >> 13) { case 0: - for (i = 0; i < 4; ++i) n[i] = rintf(f[i]); + for (i = 0; i < 4; ++i) n[i] = rintf(f[i].f); break; case 1: - for (i = 0; i < 4; ++i) n[i] = floorf(f[i]); + for (i = 0; i < 4; ++i) n[i] = floorf(f[i].f); break; case 2: - for (i = 0; i < 4; ++i) n[i] = ceilf(f[i]); + for (i = 0; i < 4; ++i) n[i] = ceilf(f[i].f); break; case 3: - for (i = 0; i < 4; ++i) n[i] = truncf(f[i]); + for (i = 0; i < 4; ++i) n[i] = truncf(f[i].f); break; default: - unreachable; + for (;;) (void)0; } - memcpy(XmmRexrReg(m, rde), n, 16); + Write32(XmmRexrReg(m, rde) + 0 * 4, n[0]); + Write32(XmmRexrReg(m, rde) + 1 * 4, n[1]); + Write32(XmmRexrReg(m, rde) + 2 * 4, n[2]); + Write32(XmmRexrReg(m, rde) + 3 * 4, n[3]); } static void OpVdqWpdCvttpd2dq(struct Machine *m, uint32_t rde) { - unsigned i; - double d[2]; + uint8_t *p; int32_t n[2]; - memcpy(d, GetModrmRegisterXmmPointerRead16(m, rde), 16); - for (i = 0; i < 2; ++i) n[i] = d[i]; - memcpy(XmmRexrReg(m, rde), n, 8); + union DoublePun d[2]; + p = GetModrmRegisterXmmPointerRead16(m, rde); + d[0].i = Read64(p + 0); + d[1].i = Read64(p + 8); + n[0] = d[0].f; + n[1] = d[1].f; + Write32(XmmRexrReg(m, rde) + 0, n[0]); + Write32(XmmRexrReg(m, rde) + 4, n[1]); } static void OpVdqWpdCvtpd2dq(struct Machine *m, uint32_t rde) { + uint8_t *p; unsigned i; - double d[2]; int32_t n[2]; - memcpy(d, GetModrmRegisterXmmPointerRead16(m, rde), 16); - for (i = 0; i < 2; ++i) n[i] = SseRoundDouble(m, d[i]); - memcpy(XmmRexrReg(m, rde), n, 8); + union DoublePun d[2]; + p = GetModrmRegisterXmmPointerRead16(m, rde); + d[0].i = Read64(p + 0); + d[1].i = Read64(p + 8); + for (i = 0; i < 2; ++i) n[i] = SseRoundDouble(m, d[i].f); + Write32(XmmRexrReg(m, rde) + 0, n[0]); + Write32(XmmRexrReg(m, rde) + 4, n[1]); } static void OpCvt(struct Machine *m, uint32_t rde, unsigned long op) { diff --git a/tool/build/lib/fds.h b/tool/build/lib/fds.h index 85aa27fb8..62f270249 100644 --- a/tool/build/lib/fds.h +++ b/tool/build/lib/fds.h @@ -15,7 +15,7 @@ struct MachineFdCb { int (*close)(int); ssize_t (*readv)(int, const struct iovec *, int); ssize_t (*writev)(int, const struct iovec *, int); - int (*ioctl)(int, uint64_t, void *); + int (*ioctl)(int, int, ...); int (*poll)(struct pollfd *, uint64_t, int32_t); }; diff --git a/tool/build/lib/fpu.c b/tool/build/lib/fpu.c index 1469f6b93..b123d9e8b 100644 --- a/tool/build/lib/fpu.c +++ b/tool/build/lib/fpu.c @@ -24,69 +24,68 @@ #include "tool/build/lib/endian.h" #include "tool/build/lib/flags.h" #include "tool/build/lib/fpu.h" +#include "tool/build/lib/ldbl.h" #include "tool/build/lib/machine.h" #include "tool/build/lib/memory.h" #include "tool/build/lib/modrm.h" +#include "tool/build/lib/pun.h" #include "tool/build/lib/throw.h" #include "tool/build/lib/word.h" #define FPUREG 0 #define MEMORY 1 -#define DISP(x, y, z) (((x)&0b111) << 4 | (y) << 3 | (z)) +#define DISP(x, y, z) ((7 & (x)) << 4 | (y) << 3 | (z)) static void OnFpuStackOverflow(struct Machine *m) { - m->fpu.ie = true; - m->fpu.c1 = true; - m->fpu.sf = true; + m->fpu.sw |= kFpuSwIe | kFpuSwC1 | kFpuSwSf; } -static long double OnFpuStackUnderflow(struct Machine *m) { - m->fpu.ie = true; - m->fpu.c1 = false; - m->fpu.sf = true; +static double OnFpuStackUnderflow(struct Machine *m) { + m->fpu.sw |= kFpuSwIe | kFpuSwSf; + m->fpu.sw &= ~kFpuSwC1; return -NAN; } -static long double St(struct Machine *m, int i) { +static double St(struct Machine *m, int i) { if (FpuGetTag(m, i) == kFpuTagEmpty) OnFpuStackUnderflow(m); return *FpuSt(m, i); } -static long double St0(struct Machine *m) { +static double St0(struct Machine *m) { return St(m, 0); } -static long double St1(struct Machine *m) { +static double St1(struct Machine *m) { return St(m, 1); } -static long double StRm(struct Machine *m) { +static double StRm(struct Machine *m) { return St(m, ModrmRm(m->xedd->op.rde)); } static void FpuClearRoundup(struct Machine *m) { - m->fpu.c1 = false; + m->fpu.sw &= ~kFpuSwC1; } static void FpuClearOutOfRangeIndicator(struct Machine *m) { - m->fpu.c2 = false; + m->fpu.sw &= ~kFpuSwC2; } -static void FpuSetSt0(struct Machine *m, long double x) { +static void FpuSetSt0(struct Machine *m, double x) { *FpuSt(m, 0) = x; } -static void FpuSetStRm(struct Machine *m, long double x) { +static void FpuSetStRm(struct Machine *m, double x) { *FpuSt(m, ModrmRm(m->xedd->op.rde)) = x; } -static void FpuSetStPop(struct Machine *m, int i, long double x) { +static void FpuSetStPop(struct Machine *m, int i, double x) { *FpuSt(m, i) = x; FpuPop(m); } -static void FpuSetStRmPop(struct Machine *m, long double x) { +static void FpuSetStRmPop(struct Machine *m, double x) { FpuSetStPop(m, ModrmRm(m->xedd->op.rde), x); } @@ -106,156 +105,156 @@ static int64_t FpuGetMemoryLong(struct Machine *m) { } static float FpuGetMemoryFloat(struct Machine *m) { - float f; - uint8_t b[4]; - memcpy(&f, Load(m, m->fpu.dp, 4, b), 4); - return f; + union FloatPun u; + u.i = FpuGetMemoryInt(m); + return u.f; } static double FpuGetMemoryDouble(struct Machine *m) { - double f; - uint8_t b[8]; - memcpy(&f, Load(m, m->fpu.dp, 8, b), 8); - return f; -} - -static long double FpuGetMemoryLongDouble(struct Machine *m) { - long double f; - uint8_t b[10]; - memcpy(&f, Load(m, m->fpu.dp, 10, b), 10); - return f; + union DoublePun u; + u.i = FpuGetMemoryLong(m); + return u.f; } static void FpuSetMemoryShort(struct Machine *m, int16_t i) { - SetMemoryShort(m, m->fpu.dp, i); + void *p[2]; + uint8_t b[2]; + Write16(BeginStore(m, m->fpu.dp, 2, p, b), i); + EndStore(m, m->fpu.dp, 2, p, b); } static void FpuSetMemoryInt(struct Machine *m, int32_t i) { - SetMemoryInt(m, m->fpu.dp, i); + void *p[2]; + uint8_t b[4]; + Write32(BeginStore(m, m->fpu.dp, 4, p, b), i); + EndStore(m, m->fpu.dp, 4, p, b); } static void FpuSetMemoryLong(struct Machine *m, int64_t i) { - SetMemoryLong(m, m->fpu.dp, i); + void *p[2]; + uint8_t b[8]; + Write64(BeginStore(m, m->fpu.dp, 8, p, b), i); + EndStore(m, m->fpu.dp, 8, p, b); } static void FpuSetMemoryFloat(struct Machine *m, float f) { - SetMemoryFloat(m, m->fpu.dp, f); + union FloatPun u = {f}; + FpuSetMemoryInt(m, u.i); } static void FpuSetMemoryDouble(struct Machine *m, double f) { - SetMemoryDouble(m, m->fpu.dp, f); + union DoublePun u = {f}; + FpuSetMemoryLong(m, u.i); } -static void FpuSetMemoryLdbl(struct Machine *m, long double f) { - SetMemoryLdbl(m, m->fpu.dp, f); +static double FpuGetMemoryLdbl(struct Machine *m) { + uint8_t b[10]; + return DeserializeLdbl(Load(m, m->fpu.dp, 10, b)); } -static long ltruncl(long double x) { - return x; +static void FpuSetMemoryLdbl(struct Machine *m, double f) { + void *p[2]; + uint8_t b[10], t[10]; + SerializeLdbl(b, f); + memcpy(BeginStore(m, m->fpu.dp, 10, p, t), b, 10); + EndStore(m, m->fpu.dp, 10, p, t); } -static int ClearC2(int sw) { - return sw & ~FPU_C2; +static double f2xm1(double x) { + return exp2(x) - 1; } -static long double f2xm1(long double x) { - return exp2l(x) - 1; +static double fyl2x(double x, double y) { + return y * log2(x); } -static long double fyl2x(long double x, long double y) { - return y * log2l(x); +static double fyl2xp1(double x, double y) { + return y * log2(x + 1); } -static long double fyl2xp1(long double x, long double y) { - return y * log2l(x + 1); -} - -static long double fscale(long double significand, long double exponent) { +static double fscale(double significand, double exponent) { if (isunordered(significand, exponent)) return NAN; return ldexp(significand, exponent); } -static long double x87remainder(long double x, long double y, uint32_t *sw, - long double rem(long double, long double), - long rnd(long double)) { +static double x87remainder(double x, double y, uint32_t *sw, + double rem(double, double), double rnd(double)) { int s; long q; - long double r; + double r; s = 0; r = rem(x, y); q = rnd(x / y); - s &= ~FPU_C2; /* ty libm */ - if (q & 0b001) s |= FPU_C1; - if (q & 0b010) s |= FPU_C3; - if (q & 0b100) s |= FPU_C0; - if (sw) *sw = s | (*sw & ~(FPU_C0 | FPU_C1 | FPU_C2 | FPU_C3)); + s &= ~kFpuSwC2; /* ty libm */ + if (q & 1) s |= kFpuSwC1; + if (q & 2) s |= kFpuSwC3; + if (q & 4) s |= kFpuSwC0; + if (sw) *sw = s | (*sw & ~(kFpuSwC0 | kFpuSwC1 | kFpuSwC2 | kFpuSwC3)); return r; } -static long double fprem(long double dividend, long double modulus, - uint32_t *sw) { - return x87remainder(dividend, modulus, sw, fmodl, ltruncl); +static double fprem(double dividend, double modulus, uint32_t *sw) { + return x87remainder(dividend, modulus, sw, fmod, trunc); } -static long double fprem1(long double dividend, long double modulus, - uint32_t *sw) { - return x87remainder(dividend, modulus, sw, remainderl, lrintl); +static double fprem1(double dividend, double modulus, uint32_t *sw) { + return x87remainder(dividend, modulus, sw, remainder, rint); } -static long double FpuAdd(struct Machine *m, long double x, long double y) { +static double FpuAdd(struct Machine *m, double x, double y) { if (!isunordered(x, y)) { switch (isinf(y) << 1 | isinf(x)) { - case 0b00: + case 0: return x + y; - case 0b01: + case 1: return x; - case 0b10: + case 2: return y; - case 0b11: + case 3: if (signbit(x) == signbit(y)) { return x; } else { - m->fpu.ie = true; + m->fpu.sw |= kFpuSwIe; return copysign(NAN, x); } default: - unreachable; + for (;;) (void)0; } } else { return NAN; } } -static long double FpuSub(struct Machine *m, long double x, long double y) { +static double FpuSub(struct Machine *m, double x, double y) { if (!isunordered(x, y)) { switch (isinf(y) << 1 | isinf(x)) { - case 0b00: + case 0: return x - y; - case 0b01: + case 1: return -x; - case 0b10: + case 2: return y; - case 0b11: + case 3: if (signbit(x) == signbit(y)) { - m->fpu.ie = true; + m->fpu.sw |= kFpuSwIe; return copysign(NAN, x); } else { return y; } default: - unreachable; + for (;;) (void)0; } } else { return NAN; } } -static long double FpuMul(struct Machine *m, long double x, long double y) { +static double FpuMul(struct Machine *m, double x, double y) { if (!isunordered(x, y)) { if (!((isinf(x) && !y) || (isinf(y) && !x))) { return x * y; } else { - m->fpu.ie = true; + m->fpu.sw |= kFpuSwIe; return -NAN; } } else { @@ -263,17 +262,17 @@ static long double FpuMul(struct Machine *m, long double x, long double y) { } } -static long double FpuDiv(struct Machine *m, long double x, long double y) { +static double FpuDiv(struct Machine *m, double x, double y) { if (!isunordered(x, y)) { if (x || y) { if (y) { return x / y; } else { - m->fpu.ze = true; + m->fpu.sw |= kFpuSwZe; return copysign(INFINITY, x); } } else { - m->fpu.ie = true; + m->fpu.sw |= kFpuSwIe; return copysign(NAN, x); } } else { @@ -281,73 +280,58 @@ static long double FpuDiv(struct Machine *m, long double x, long double y) { } } -static long double FpuRound(struct Machine *m, long double x) { - switch (m->fpu.rc) { +static double FpuRound(struct Machine *m, double x) { + switch ((m->fpu.cw & kFpuCwRc) >> 10) { case 0: - return rintl(x); + return rint(x); case 1: - return floorl(x); + return floor(x); case 2: - return ceill(x); + return ceil(x); case 3: - return truncl(x); + return trunc(x); default: - unreachable; + for (;;) (void)0; } } -static void FpuCompare(struct Machine *m, long double y) { - long double x = St0(m); - m->fpu.c1 = false; +static void FpuCompare(struct Machine *m, double y) { + double x = St0(m); + m->fpu.sw &= ~(kFpuSwC0 | kFpuSwC1 | kFpuSwC2 | kFpuSwC3); if (!isunordered(x, y)) { - m->fpu.c0 = x < y; - m->fpu.c2 = false; - m->fpu.c3 = x == y; + if (x < y) m->fpu.sw |= kFpuSwC0; + if (x == y) m->fpu.sw |= kFpuSwC3; } else { - m->fpu.c0 = true; - m->fpu.c2 = true; - m->fpu.c3 = true; - m->fpu.ie = true; + m->fpu.sw |= kFpuSwC0 | kFpuSwC2 | kFpuSwC3 | kFpuSwIe; } } static void OpFxam(struct Machine *m) { - long double x; + double x; x = *FpuSt(m, 0); - m->fpu.c1 = !!signbit(x); + m->fpu.sw &= ~(kFpuSwC0 | kFpuSwC1 | kFpuSwC2 | kFpuSwC3); + if (signbit(x)) m->fpu.sw |= kFpuSwC1; if (FpuGetTag(m, 0) == kFpuTagEmpty) { - m->fpu.c0 = true; - m->fpu.c2 = false; - m->fpu.c3 = true; + m->fpu.sw |= kFpuSwC0 | kFpuSwC3; } else { switch (fpclassify(x)) { case FP_NAN: - m->fpu.c0 = true; - m->fpu.c2 = false; - m->fpu.c3 = false; + m->fpu.sw |= kFpuSwC0; break; case FP_INFINITE: - m->fpu.c0 = true; - m->fpu.c2 = true; - m->fpu.c3 = false; + m->fpu.sw |= kFpuSwC0 | kFpuSwC2; break; case FP_ZERO: - m->fpu.c0 = false; - m->fpu.c2 = false; - m->fpu.c3 = true; + m->fpu.sw |= kFpuSwC3; break; case FP_SUBNORMAL: - m->fpu.c0 = false; - m->fpu.c2 = true; - m->fpu.c3 = true; + m->fpu.sw |= kFpuSwC2 | kFpuSwC3; break; case FP_NORMAL: - m->fpu.c0 = false; - m->fpu.c2 = true; - m->fpu.c3 = false; + m->fpu.sw |= kFpuSwC2; break; default: - abort(); + for (;;) (void)0; } } } @@ -409,7 +393,7 @@ static void OpFchs(struct Machine *m) { } static void OpFabs(struct Machine *m) { - FpuSetSt0(m, fabsl(St0(m))); + FpuSetSt0(m, fabs(St0(m))); } static void OpF2xm1(struct Machine *m) { @@ -426,31 +410,32 @@ static void OpFyl2xp1(struct Machine *m) { static void OpFcos(struct Machine *m) { FpuClearOutOfRangeIndicator(m); - FpuSetSt0(m, cosl(St0(m))); + FpuSetSt0(m, cos(St0(m))); } static void OpFsin(struct Machine *m) { FpuClearOutOfRangeIndicator(m); - FpuSetSt0(m, sinl(St0(m))); + FpuSetSt0(m, sin(St0(m))); } static void OpFptan(struct Machine *m) { FpuClearOutOfRangeIndicator(m); - FpuSetSt0(m, tanl(St0(m))); + FpuSetSt0(m, tan(St0(m))); FpuPush(m, 1); } static void OpFsincos(struct Machine *m) { - long double tsin, tcos; + double tsin, tcos; FpuClearOutOfRangeIndicator(m); - sincosl(St0(m), &tsin, &tcos); + tsin = sin(St0(m)); + tcos = cos(St0(m)); FpuSetSt0(m, tsin); FpuPush(m, tcos); } static void OpFpatan(struct Machine *m) { FpuClearRoundup(m); - FpuSetStPop(m, 1, atan2l(St1(m), St0(m))); + FpuSetStPop(m, 1, atan2(St1(m), St0(m))); } static void OpFcom(struct Machine *m) { @@ -673,7 +658,7 @@ static void OpFidivrs(struct Machine *m) { static void OpFsqrt(struct Machine *m) { FpuClearRoundup(m); - FpuSetSt0(m, sqrtl(St0(m))); + FpuSetSt0(m, sqrt(St0(m))); } static void OpFrndint(struct Machine *m) { @@ -694,17 +679,17 @@ static void OpFprem1(struct Machine *m) { } static void OpFdecstp(struct Machine *m) { - --m->fpu.sp; + m->fpu.sw = (m->fpu.sw & ~kFpuSwSp) | ((m->fpu.sw - (1 << 11)) & kFpuSwSp); } static void OpFincstp(struct Machine *m) { - ++m->fpu.sp; + m->fpu.sw = (m->fpu.sw & ~kFpuSwSp) | ((m->fpu.sw + (1 << 11)) & kFpuSwSp); } static void OpFxtract(struct Machine *m) { - long double x = St0(m); - FpuSetSt0(m, logbl(x)); - FpuPush(m, significandl(x)); + double x = St0(m); + FpuSetSt0(m, logb(x)); + FpuPush(m, ldexp(x, -ilogb(x))); } static void OpFld(struct Machine *m) { @@ -746,7 +731,7 @@ static void OpFstp(struct Machine *m) { } static void OpFxch(struct Machine *m) { - long double t = StRm(m); + double t = StRm(m); FpuSetStRm(m, St0(m)); FpuSetSt0(m, t); } @@ -756,43 +741,43 @@ static void OpFldcw(struct Machine *m) { } static void OpFldt(struct Machine *m) { - FpuPush(m, FpuGetMemoryLongDouble(m)); + FpuPush(m, FpuGetMemoryLdbl(m)); } static void OpFldl(struct Machine *m) { FpuPush(m, FpuGetMemoryDouble(m)); } -static long double Fld1(void) { +static double Fld1(void) { return 1; } -static long double Fldl2t(void) { +static double Fldl2t(void) { return 0xd.49a784bcd1b8afep-2L; /* log₂10 */ } -static long double Fldl2e(void) { +static double Fldl2e(void) { return 0xb.8aa3b295c17f0bcp-3L; /* log₂𝑒 */ } -static long double Fldpi(void) { +static double Fldpi(void) { return 0x1.921fb54442d1846ap+1L; /* π */ } -static long double Fldlg2(void) { +static double Fldlg2(void) { return 0x9.a209a84fbcff799p-5L; /* log₁₀2 */ } -static long double Fldln2(void) { +static double Fldln2(void) { return 0xb.17217f7d1cf79acp-4L; /* logₑ2 */ } -static long double Fldz(void) { +static double Fldz(void) { return 0; } static void OpFldConstant(struct Machine *m) { - long double x; + double x; switch (ModrmRm(m->xedd->op.rde)) { CASE(0, x = Fld1()); CASE(1, x = Fldl2t()); @@ -863,7 +848,7 @@ static void OpFistps(struct Machine *m) { } static void OpFcomi(struct Machine *m) { - long double x, y; + double x, y; x = St0(m); y = StRm(m); if (!isunordered(x, y)) { @@ -871,7 +856,7 @@ static void OpFcomi(struct Machine *m) { m->flags = SetFlag(m->flags, FLAGS_CF, x < y); m->flags = SetFlag(m->flags, FLAGS_PF, false); } else { - m->fpu.ie = true; + m->fpu.sw |= kFpuSwIe; m->flags = SetFlag(m->flags, FLAGS_ZF, true); m->flags = SetFlag(m->flags, FLAGS_CF, true); m->flags = SetFlag(m->flags, FLAGS_PF, true); @@ -945,42 +930,32 @@ static void OpFldenv(struct Machine *m) { } static void OpFsave(struct Machine *m) { - long i; + int i; void *p[2]; - long double x; - uint8_t *a, b[108]; + uint8_t *a, b[108], t[16]; a = BeginStore(m, m->fpu.dp, sizeof(b), p, b); SetFpuEnv(m, a); + memset(t, 0, sizeof(t)); for (i = 0; i < 8; ++i) { - x = *FpuSt(m, i); - memcpy(a + 28 + i * 10, &x, 10); + SerializeLdbl(a + 28 + i * 10, *FpuSt(m, i)); } EndStore(m, m->fpu.dp, sizeof(b), p, b); OpFinit(m); } static void OpFrstor(struct Machine *m) { - long i; - long double x; + int i; uint8_t *a, b[108]; a = Load(m, m->fpu.dp, sizeof(b), b); GetFpuEnv(m, a); for (i = 0; i < 8; ++i) { - bzero(&x, sizeof(x)); - memcpy(&x, a + 28 + i * 10, 10); - *FpuSt(m, i) = x; + *FpuSt(m, i) = DeserializeLdbl(a + 28 + i * 10); } } static void OpFnclex(struct Machine *m) { - m->fpu.ie = false; - m->fpu.de = false; - m->fpu.ze = false; - m->fpu.oe = false; - m->fpu.ue = false; - m->fpu.pe = false; - m->fpu.es = false; - m->fpu.bf = false; + m->fpu.sw &= ~(kFpuSwIe | kFpuSwDe | kFpuSwZe | kFpuSwOe | kFpuSwUe | + kFpuSwPe | kFpuSwEs | kFpuSwSf | kFpuSwBf); } static void OpFnop(struct Machine *m) { @@ -994,64 +969,64 @@ void OpFinit(struct Machine *m) { } void OpFwait(struct Machine *m, uint32_t rde) { - if ((m->fpu.ie & !m->fpu.im) | (m->fpu.de & !m->fpu.dm) | - (m->fpu.ze & !m->fpu.zm) | (m->fpu.oe & !m->fpu.om) | - (m->fpu.ue & !m->fpu.um) | (m->fpu.pe & !m->fpu.pm) | - (m->fpu.sf & !m->fpu.im)) { + int sw, cw; + sw = m->fpu.sw; + cw = m->fpu.cw; + if (((sw & kFpuSwIe) && !(cw & kFpuCwIm)) || + ((sw & kFpuSwDe) && !(cw & kFpuCwDm)) || + ((sw & kFpuSwZe) && !(cw & kFpuCwZm)) || + ((sw & kFpuSwOe) && !(cw & kFpuCwOm)) || + ((sw & kFpuSwUe) && !(cw & kFpuCwUm)) || + ((sw & kFpuSwPe) && !(cw & kFpuCwPm)) || + ((sw & kFpuSwSf) && !(cw & kFpuCwIm))) { HaltMachine(m, kMachineFpuException); } } -long double *FpuSt(struct Machine *m, unsigned i) { - i += m->fpu.sp; - i &= 0b111; - return m->fpu.st + i; -} - int FpuGetTag(struct Machine *m, unsigned i) { unsigned t; t = m->fpu.tw; - i += m->fpu.sp; - i &= 0b111; + i += (m->fpu.sw & kFpuSwSp) >> 11; + i &= 7; i *= 2; - t &= 0b11 << i; + t &= 3 << i; t >>= i; return t; } void FpuSetTag(struct Machine *m, unsigned i, unsigned t) { - i += m->fpu.sp; - t &= 0b11; - i &= 0b111; + i += (m->fpu.sw & kFpuSwSp) >> 11; + t &= 3; + i &= 7; i *= 2; - m->fpu.tw &= ~(0b11 << i); + m->fpu.tw &= ~(3 << i); m->fpu.tw |= t << i; } -void FpuPush(struct Machine *m, long double x) { +void FpuPush(struct Machine *m, double x) { if (FpuGetTag(m, -1) != kFpuTagEmpty) OnFpuStackOverflow(m); - m->fpu.sp -= 1; + m->fpu.sw = (m->fpu.sw & ~kFpuSwSp) | ((m->fpu.sw - (1 << 11)) & kFpuSwSp); *FpuSt(m, 0) = x; FpuSetTag(m, 0, kFpuTagValid); } -long double FpuPop(struct Machine *m) { - long double x; +double FpuPop(struct Machine *m) { + double x; if (FpuGetTag(m, 0) != kFpuTagEmpty) { x = *FpuSt(m, 0); FpuSetTag(m, 0, kFpuTagEmpty); } else { x = OnFpuStackUnderflow(m); } - m->fpu.sp += 1; + m->fpu.sw = (m->fpu.sw & ~kFpuSwSp) | ((m->fpu.sw + (1 << 11)) & kFpuSwSp); return x; } void OpFpu(struct Machine *m, uint32_t rde) { unsigned op; bool ismemory; - op = m->xedd->op.opcode & 0b111; - ismemory = ModrmMod(rde) != 0b11; + op = m->xedd->op.opcode & 7; + ismemory = ModrmMod(rde) != 3; m->fpu.ip = m->ip - m->xedd->length; m->fpu.op = op << 8 | ModrmMod(rde) << 6 | ModrmReg(rde) << 3 | ModrmRm(rde); m->fpu.dp = ismemory ? ComputeAddress(m, rde) : 0; @@ -1187,7 +1162,7 @@ void OpFpu(struct Machine *m, uint32_t rde) { CASE(6, OpFdecstp(m)); CASE(7, OpFincstp(m)); default: - unreachable; + for (;;) (void)0; } break; case DISP(0xD9, FPUREG, 7): @@ -1201,7 +1176,7 @@ void OpFpu(struct Machine *m, uint32_t rde) { CASE(6, OpFsin(m)); CASE(7, OpFcos(m)); default: - unreachable; + for (;;) (void)0; } break; case DISP(0xDb, FPUREG, 4): diff --git a/tool/build/lib/fpu.h b/tool/build/lib/fpu.h index acfdd924c..48c6fb1e1 100644 --- a/tool/build/lib/fpu.h +++ b/tool/build/lib/fpu.h @@ -7,17 +7,58 @@ #define kFpuTagSpecial 0b10 #define kFpuTagEmpty 0b11 +#define kFpuCwIm 0x0001 /* invalid operation mask */ +#define kFpuCwDm 0x0002 /* denormal operand mask */ +#define kFpuCwZm 0x0004 /* zero divide mask */ +#define kFpuCwOm 0x0008 /* overflow mask */ +#define kFpuCwUm 0x0010 /* underflow mask */ +#define kFpuCwPm 0x0020 /* precision mask */ +#define kFpuCwPc 0x0300 /* precision: 32,∅,64,80 */ +#define kFpuCwRc 0x0c00 /* rounding: even,→-∞,→+∞,→0 */ + +#define kFpuSwIe 0x0001 /* invalid operation */ +#define kFpuSwDe 0x0002 /* denormalized operand */ +#define kFpuSwZe 0x0004 /* zero divide */ +#define kFpuSwOe 0x0008 /* overflow */ +#define kFpuSwUe 0x0010 /* underflow */ +#define kFpuSwPe 0x0020 /* precision */ +#define kFpuSwSf 0x0040 /* stack fault */ +#define kFpuSwEs 0x0080 /* exception summary status */ +#define kFpuSwC0 0x0100 /* condition 0 */ +#define kFpuSwC1 0x0200 /* condition 1 */ +#define kFpuSwC2 0x0400 /* condition 2 */ +#define kFpuSwSp 0x3800 /* top stack */ +#define kFpuSwC3 0x4000 /* condition 3 */ +#define kFpuSwBf 0x8000 /* busy flag */ + +#define kMxcsrIe 0x0001 /* invalid operation flag */ +#define kMxcsrDe 0x0002 /* denormal flag */ +#define kMxcsrZe 0x0004 /* divide by zero flag */ +#define kMxcsrOe 0x0008 /* overflow flag */ +#define kMxcsrUe 0x0010 /* underflow flag */ +#define kMxcsrPe 0x0020 /* precision flag */ +#define kMxcsrDaz 0x0040 /* denormals are zeros */ +#define kMxcsrIm 0x0080 /* invalid operation mask */ +#define kMxcsrDm 0x0100 /* denormal mask */ +#define kMxcsrZm 0x0200 /* divide by zero mask */ +#define kMxcsrOm 0x0400 /* overflow mask */ +#define kMxcsrUm 0x0800 /* underflow mask */ +#define kMxcsrPm 0x1000 /* precision mask */ +#define kMxcsrRc 0x6000 /* rounding control */ +#define kMxcsrFtz 0x8000 /* flush to zero */ + +#define FpuSt(m, i) ((m)->fpu.st + (((i) + ((m->fpu.sw & kFpuSwSp) >> 11)) & 7)) + #if !(__ASSEMBLER__ + __LINKER__ + 0) COSMOPOLITAN_C_START_ -void OpFpu(struct Machine *, uint32_t); -void OpFinit(struct Machine *); -void OpFwait(struct Machine *, uint32_t); -void FpuPush(struct Machine *, long double); -long double FpuPop(struct Machine *); -long double *FpuSt(struct Machine *, unsigned); +double FpuPop(struct Machine *); int FpuGetTag(struct Machine *, unsigned); +void FpuPush(struct Machine *, double); void FpuSetTag(struct Machine *, unsigned, unsigned); +void OpFinit(struct Machine *); +void OpFpu(struct Machine *, uint32_t); +void OpFwait(struct Machine *, uint32_t); COSMOPOLITAN_C_END_ #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ diff --git a/tool/build/lib/ldbl.c b/tool/build/lib/ldbl.c new file mode 100644 index 000000000..3d4339805 --- /dev/null +++ b/tool/build/lib/ldbl.c @@ -0,0 +1,49 @@ +/*-*- 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/macros.internal.h" +#include "tool/build/lib/endian.h" +#include "tool/build/lib/ldbl.h" +#include "tool/build/lib/pun.h" + +uint8_t *SerializeLdbl(uint8_t b[10], double f) { + int e; + union DoublePun u = {f}; + e = (u.i >> 52) & 0x7ff; + if (!e) { + e = 0; + } else if (e == 0x7ff) { + e = 0x7fff; + } else { + e -= 0x3ff; + e += 0x3fff; + } + Write16(b + 8, e | u.i >> 63 << 15); + Write64(b, (u.i & 0x000fffffffffffff) << 11 | (uint64_t) !!u.f << 63); + return b; +} + +double DeserializeLdbl(const uint8_t b[10]) { + union DoublePun u; + u.i = (uint64_t)(MAX(-1023, MIN(1024, ((Read16(b + 8) & 0x7fff) - 0x3fff))) + + 1023) + << 52 | + ((Read64(b) & 0x7fffffffffffffff) + (1 << (11 - 1))) >> 11 | + (uint64_t)(b[9] >> 7) << 63; + return u.f; +} diff --git a/tool/build/lib/ldbl.h b/tool/build/lib/ldbl.h new file mode 100644 index 000000000..656046945 --- /dev/null +++ b/tool/build/lib/ldbl.h @@ -0,0 +1,11 @@ +#ifndef COSMOPOLITAN_TOOL_BUILD_LIB_LDBL_H_ +#define COSMOPOLITAN_TOOL_BUILD_LIB_LDBL_H_ +#if !(__ASSEMBLER__ + __LINKER__ + 0) +COSMOPOLITAN_C_START_ + +double DeserializeLdbl(const uint8_t[10]); +uint8_t *SerializeLdbl(uint8_t[10], double); + +COSMOPOLITAN_C_END_ +#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ +#endif /* COSMOPOLITAN_TOOL_BUILD_LIB_LDBL_H_ */ diff --git a/tool/build/lib/machine.h b/tool/build/lib/machine.h index 3df6270ce..c9cf4db0f 100644 --- a/tool/build/lib/machine.h +++ b/tool/build/lib/machine.h @@ -2,6 +2,7 @@ #define COSMOPOLITAN_TOOL_BUILD_LIB_MACHINE_H_ #include "libc/runtime/runtime.h" #include "third_party/xed/x86.h" +#include "tool/build/lib/bits.h" #include "tool/build/lib/fds.h" #define kMachineHalt -1 @@ -138,6 +139,7 @@ struct Machine { uint64_t idt_base; uint16_t gdt_limit; uint16_t idt_limit; + uint32_t mxcsr; struct MachineRealFree { uint64_t i; uint64_t n; @@ -161,12 +163,26 @@ struct Machine { jmp_buf onhalt; int64_t faultaddr; bool dlab; + bool isfork; bool ismetal; struct MachineFds fds; uint8_t stash[4096]; uint8_t icache[1024][40]; void (*onbinbase)(struct Machine *); void (*onlongbranch)(struct Machine *); + void (*redraw)(void); + struct sigaction_bits sighand[28]; + uint8_t sigmask[8]; + int sig; + uint64_t siguc; + uint64_t sigfp; + struct { + int i, n; + struct { + int sig; + int code; + } p[64]; + } signals; } forcealign(64); struct Machine *NewMachine(void) dontdiscard; diff --git a/tool/build/lib/pun.h b/tool/build/lib/pun.h new file mode 100644 index 000000000..3186e574d --- /dev/null +++ b/tool/build/lib/pun.h @@ -0,0 +1,28 @@ +#ifndef COSMOPOLITAN_TOOL_BUILD_LIB_PUN_H_ +#define COSMOPOLITAN_TOOL_BUILD_LIB_PUN_H_ +#if !(__ASSEMBLER__ + __LINKER__ + 0) +COSMOPOLITAN_C_START_ + +union FloatPun { + float f; + uint32_t i; +}; + +union DoublePun { + double f; + uint64_t i; +}; + +union FloatVectorPun { + union FloatPun u[4]; + float f[4]; +}; + +union DoubleVectorPun { + union DoublePun u[2]; + double f[2]; +}; + +COSMOPOLITAN_C_END_ +#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ +#endif /* COSMOPOLITAN_TOOL_BUILD_LIB_PUN_H_ */ diff --git a/tool/build/lib/signal.c b/tool/build/lib/signal.c new file mode 100644 index 000000000..100cf9f50 --- /dev/null +++ b/tool/build/lib/signal.c @@ -0,0 +1,165 @@ +/*-*- 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/str/str.h" +#include "tool/build/lib/bits.h" +#include "tool/build/lib/endian.h" +#include "tool/build/lib/machine.h" +#include "tool/build/lib/memory.h" +#include "tool/build/lib/signal.h" +#include "tool/build/lib/xlat.h" + +#define SIGCHLD_LINUX 17 +#define SIGURG_LINUX 23 +#define SIGWINCH_LINUX 28 + +void OpRestore(struct Machine *m) { + union { + struct fpstate_bits fp; + struct ucontext_bits uc; + } u; + VirtualSendRead(m, &u.uc, m->siguc, sizeof(u.uc)); + m->ip = Read64(u.uc.rip); + m->flags = Read64(u.uc.eflags); + memcpy(m->r8, u.uc.r8, 8); + memcpy(m->r9, u.uc.r9, 8); + memcpy(m->r10, u.uc.r10, 8); + memcpy(m->r11, u.uc.r11, 8); + memcpy(m->r12, u.uc.r12, 8); + memcpy(m->r13, u.uc.r13, 8); + memcpy(m->r14, u.uc.r14, 8); + memcpy(m->r15, u.uc.r15, 8); + memcpy(m->di, u.uc.rdi, 8); + memcpy(m->si, u.uc.rsi, 8); + memcpy(m->bp, u.uc.rbp, 8); + memcpy(m->bx, u.uc.rbx, 8); + memcpy(m->dx, u.uc.rdx, 8); + memcpy(m->ax, u.uc.rax, 8); + memcpy(m->cx, u.uc.rcx, 8); + memcpy(m->sp, u.uc.rsp, 8); + VirtualSendRead(m, &u.fp, m->sigfp, sizeof(u.fp)); + m->fpu.cw = Read16(u.fp.cwd); + m->fpu.sw = Read16(u.fp.swd); + m->fpu.tw = Read16(u.fp.ftw); + m->fpu.op = Read16(u.fp.fop); + m->fpu.ip = Read64(u.fp.rip); + m->fpu.dp = Read64(u.fp.rdp); + memcpy(m->fpu.st, u.fp.st, 128); + memcpy(m->xmm, u.fp.xmm, 256); + m->sig = 0; +} + +int DeliverSignal(struct Machine *m, int sig, int code) { + uint64_t sp, siaddr; + static struct siginfo_bits si; + static struct fpstate_bits fp; + static struct ucontext_bits uc; + switch (Read64(m->sighand[sig - 1].handler)) { + case 1: // SIG_IGN + return 0; + case 0: // SIG_DFL + if (sig == SIGCHLD_LINUX || sig == SIGURG_LINUX || + sig == SIGWINCH_LINUX) { + return 0; + } + raise(sig); + _exit(128 + sig); + default: + break; + } + Write32(si.si_signo, sig); + Write32(si.si_code, code); + memcpy(uc.r8, m->r8, 8); + memcpy(uc.r9, m->r9, 8); + memcpy(uc.r10, m->r10, 8); + memcpy(uc.r11, m->r11, 8); + memcpy(uc.r12, m->r12, 8); + memcpy(uc.r13, m->r13, 8); + memcpy(uc.r14, m->r14, 8); + memcpy(uc.r15, m->r15, 8); + memcpy(uc.rdi, m->di, 8); + memcpy(uc.rsi, m->si, 8); + memcpy(uc.rbp, m->bp, 8); + memcpy(uc.rbx, m->bx, 8); + memcpy(uc.rdx, m->dx, 8); + memcpy(uc.rax, m->ax, 8); + memcpy(uc.rcx, m->cx, 8); + memcpy(uc.rsp, m->sp, 8); + Write64(uc.rip, m->ip); + Write64(uc.eflags, m->flags); + Write16(fp.cwd, m->fpu.cw); + Write16(fp.swd, m->fpu.sw); + Write16(fp.ftw, m->fpu.tw); + Write16(fp.fop, m->fpu.op); + Write64(fp.rip, m->fpu.ip); + Write64(fp.rdp, m->fpu.dp); + memcpy(fp.st, m->fpu.st, 128); + memcpy(fp.xmm, m->xmm, 256); + sp = Read64(m->sp); + sp = ROUNDDOWN(sp - sizeof(si), 16); + VirtualRecvWrite(m, sp, &si, sizeof(si)); + siaddr = sp; + sp = ROUNDDOWN(sp - sizeof(fp), 16); + VirtualRecvWrite(m, sp, &fp, sizeof(fp)); + m->sigfp = sp; + Write64(uc.fpstate, sp); + sp = ROUNDDOWN(sp - sizeof(uc), 16); + VirtualRecvWrite(m, sp, &uc, sizeof(uc)); + m->siguc = sp; + m->sig = sig; + sp -= 8; + VirtualRecvWrite(m, sp, m->sighand[sig - 1].restorer, 8); + Write64(m->sp, sp); + Write64(m->di, sig); + Write64(m->si, siaddr); + Write64(m->dx, m->siguc); + m->ip = Read64(m->sighand[sig - 1].handler); + return 0; +} + +void EnqueueSignal(struct Machine *m, int sig, int code) { + if (m->signals.n < ARRAYLEN(m->signals.p)) { + m->signals.p[m->signals.n].code = UnXlatSicode(sig, code); + m->signals.p[m->signals.n].sig = UnXlatSignal(sig); + m->signals.n++; + } +} + +int ConsumeSignal(struct Machine *m) { + int sig, code; + sig = m->signals.p[m->signals.i].sig; + code = m->signals.p[m->signals.i].code; + if (!m->sig || + ((sig != m->sig || (Read64(m->sighand[m->sig - 1].flags) & 0x40000000)) && + !(Read64(m->sighand[m->sig - 1].mask) & (1ull << (m->sig - 1))))) { + if (++m->signals.i == m->signals.n) m->signals.i = m->signals.n = 0; + return DeliverSignal(m, sig, code); + } + return 0; +} + +void TerminateSignal(struct Machine *m, int sig) { + if (m->isfork) { + _exit(28 + sig); + } else { + exit(128 + sig); + } +} diff --git a/tool/build/lib/signal.h b/tool/build/lib/signal.h new file mode 100644 index 000000000..fd0743be0 --- /dev/null +++ b/tool/build/lib/signal.h @@ -0,0 +1,15 @@ +#ifndef COSMOPOLITAN_TOOL_BUILD_LIB_SIGNAL_H_ +#define COSMOPOLITAN_TOOL_BUILD_LIB_SIGNAL_H_ +#include "tool/build/lib/machine.h" +#if !(__ASSEMBLER__ + __LINKER__ + 0) +COSMOPOLITAN_C_START_ + +void OpRestore(struct Machine *); +void TerminateSignal(struct Machine *, int); +int DeliverSignal(struct Machine *, int, int); +int ConsumeSignal(struct Machine *); +void EnqueueSignal(struct Machine *, int, int); + +COSMOPOLITAN_C_END_ +#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ +#endif /* COSMOPOLITAN_TOOL_BUILD_LIB_SIGNAL_H_ */ diff --git a/tool/build/lib/sse.c b/tool/build/lib/sse.c index 6fb85273c..077233c67 100644 --- a/tool/build/lib/sse.c +++ b/tool/build/lib/sse.c @@ -16,724 +16,1426 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/intrin/pabsb.h" -#include "libc/intrin/pabsd.h" -#include "libc/intrin/pabsw.h" -#include "libc/intrin/packssdw.h" -#include "libc/intrin/packsswb.h" -#include "libc/intrin/packuswb.h" -#include "libc/intrin/paddb.h" -#include "libc/intrin/paddd.h" -#include "libc/intrin/paddq.h" -#include "libc/intrin/paddsb.h" -#include "libc/intrin/paddsw.h" -#include "libc/intrin/paddusb.h" -#include "libc/intrin/paddusw.h" -#include "libc/intrin/paddw.h" -#include "libc/intrin/palignr.h" -#include "libc/intrin/pand.h" -#include "libc/intrin/pandn.h" -#include "libc/intrin/pavgb.h" -#include "libc/intrin/pavgw.h" -#include "libc/intrin/pcmpeqb.h" -#include "libc/intrin/pcmpeqd.h" -#include "libc/intrin/pcmpeqw.h" -#include "libc/intrin/pcmpgtb.h" -#include "libc/intrin/pcmpgtd.h" -#include "libc/intrin/pcmpgtw.h" -#include "libc/intrin/phaddd.h" -#include "libc/intrin/phaddsw.h" -#include "libc/intrin/phaddw.h" -#include "libc/intrin/phsubd.h" -#include "libc/intrin/phsubsw.h" -#include "libc/intrin/phsubw.h" -#include "libc/intrin/pmaddubsw.h" -#include "libc/intrin/pmaddwd.h" -#include "libc/intrin/pmaxsw.h" -#include "libc/intrin/pmaxub.h" -#include "libc/intrin/pminsw.h" -#include "libc/intrin/pminub.h" -#include "libc/intrin/pmulhrsw.h" -#include "libc/intrin/pmulhuw.h" -#include "libc/intrin/pmulhw.h" -#include "libc/intrin/pmulld.h" -#include "libc/intrin/pmullw.h" -#include "libc/intrin/pmuludq.h" -#include "libc/intrin/por.h" -#include "libc/intrin/psadbw.h" -#include "libc/intrin/pshufb.h" -#include "libc/intrin/psignb.h" -#include "libc/intrin/psignd.h" -#include "libc/intrin/psignw.h" -#include "libc/intrin/pslld.h" -#include "libc/intrin/pslldq.h" -#include "libc/intrin/psllq.h" -#include "libc/intrin/psllw.h" -#include "libc/intrin/psrad.h" -#include "libc/intrin/psraw.h" -#include "libc/intrin/psrld.h" -#include "libc/intrin/psrldq.h" -#include "libc/intrin/psrlq.h" -#include "libc/intrin/psrlw.h" -#include "libc/intrin/psubb.h" -#include "libc/intrin/psubd.h" -#include "libc/intrin/psubq.h" -#include "libc/intrin/psubsb.h" -#include "libc/intrin/psubsw.h" -#include "libc/intrin/psubusb.h" -#include "libc/intrin/psubusw.h" -#include "libc/intrin/psubw.h" -#include "libc/intrin/punpckhbw.h" -#include "libc/intrin/punpckhdq.h" -#include "libc/intrin/punpckhqdq.h" -#include "libc/intrin/punpckhwd.h" -#include "libc/intrin/punpcklbw.h" -#include "libc/intrin/punpckldq.h" -#include "libc/intrin/punpcklqdq.h" -#include "libc/intrin/punpcklwd.h" -#include "libc/intrin/pxor.h" #include "libc/macros.internal.h" -#include "tool/build/lib/case.h" +#include "tool/build/lib/endian.h" #include "tool/build/lib/machine.h" -#include "tool/build/lib/memory.h" #include "tool/build/lib/modrm.h" -#include "tool/build/lib/sse.h" #include "tool/build/lib/throw.h" -static void SsePsubb(void *b, const void *a) { - psubb(b, b, a); -} - -static void SsePaddb(void *b, const void *a) { - paddb(b, b, a); -} - -static void SsePsubw(void *b, const void *a) { - psubw(b, b, a); -} - -static void SsePaddw(void *b, const void *a) { - paddw(b, b, a); -} - -static void SsePsubd(void *b, const void *a) { - psubd(b, b, a); -} - -static void SsePaddd(void *b, const void *a) { - paddd(b, b, a); -} - -static void SsePaddq(void *b, const void *a) { - paddq(b, b, a); -} - -static void SsePsubq(void *b, const void *a) { - psubq(b, b, a); -} - -static void SsePsubsb(void *b, const void *a) { - psubsb(b, b, a); -} - -static void SsePsubsw(void *b, const void *a) { - psubsw(b, b, a); -} - -static void SsePaddsb(void *b, const void *a) { - paddsb(b, b, a); -} - -static void SsePaddsw(void *b, const void *a) { - paddsw(b, b, a); -} - -static void SsePaddusb(void *b, const void *a) { - paddusb(b, b, a); -} - -static void SsePaddusw(void *b, const void *a) { - paddusw(b, b, a); -} - -static void SsePor(void *b, const void *a) { - por(b, b, a); -} - -static void SsePxor(void *b, const void *a) { - pxor(b, b, a); -} - -static void SsePand(void *b, const void *a) { - pand(b, b, a); -} - -static void SsePandn(void *b, const void *a) { - pandn(b, b, a); -} - -static void SsePsubusb(void *b, const void *a) { - psubusb(b, b, a); -} - -static void SsePsubusw(void *b, const void *a) { - psubusw(b, b, a); -} - -static void SsePminub(void *b, const void *a) { - pminub(b, b, a); -} - -static void SsePmaxub(void *b, const void *a) { - pmaxub(b, b, a); -} - -static void SsePminsw(void *b, const void *a) { - pminsw(b, b, a); -} - -static void SsePmaxsw(void *b, const void *a) { - pmaxsw(b, b, a); -} - -static void SsePunpcklbw(void *b, const void *a) { - punpcklbw(b, b, a); -} - -static void SsePunpckhbw(void *b, const void *a) { - punpckhbw(b, b, a); -} - -static void SsePunpcklwd(void *b, const void *a) { - punpcklwd(b, b, a); -} - -static void SsePunpckldq(void *b, const void *a) { - punpckldq(b, b, a); -} - -static void SsePunpckhwd(void *b, const void *a) { - punpckhwd(b, b, a); -} - -static void SsePunpckhdq(void *b, const void *a) { - punpckhdq(b, b, a); -} - -static void SsePunpcklqdq(void *b, const void *a) { - punpcklqdq(b, b, a); -} - -static void SsePunpckhqdq(void *b, const void *a) { - punpckhqdq(b, b, a); -} - -static void SsePacksswb(void *b, const void *a) { - packsswb(b, b, a); -} - -static void SsePackuswb(void *b, const void *a) { - packuswb(b, b, a); -} - -static void SsePackssdw(void *b, const void *a) { - packssdw(b, b, a); -} - -static void SsePcmpgtb(void *b, const void *a) { - pcmpgtb(b, b, a); -} - -static void SsePcmpgtw(void *b, const void *a) { - pcmpgtw(b, b, a); -} - -static void SsePcmpgtd(void *b, const void *a) { - pcmpgtd(b, b, a); -} - -static void SsePcmpeqb(void *b, const void *a) { - pcmpeqb(b, b, a); -} - -static void SsePcmpeqw(void *b, const void *a) { - pcmpeqw(b, b, a); -} - -static void SsePcmpeqd(void *b, const void *a) { - pcmpeqd(b, b, a); -} - -static void SsePsrawv(void *b, const void *a) { - psrawv(b, b, a); -} - -static void SsePsrlwv(void *b, const void *a) { - psrlwv(b, b, a); -} - -static void SsePsllwv(void *b, const void *a) { - psllwv(b, b, a); -} - -static void SsePsradv(void *b, const void *a) { - psradv(b, b, a); -} - -static void SsePsrldv(void *b, const void *a) { - psrldv(b, b, a); -} - -static void SsePslldv(void *b, const void *a) { - pslldv(b, b, a); -} - -static void SsePsrlqv(void *b, const void *a) { - psrlqv(b, b, a); -} - -static void SsePsllqv(void *b, const void *a) { - psllqv(b, b, a); -} - -static void SsePavgb(void *b, const void *a) { - pavgb(b, b, a); -} - -static void SsePavgw(void *b, const void *a) { - pavgw(b, b, a); -} - -static void SsePsadbw(void *b, const void *a) { - psadbw(b, b, a); -} - -static void SsePmaddwd(void *b, const void *a) { - pmaddwd(b, b, a); -} - -static void SsePmulhuw(void *b, const void *a) { - pmulhuw(b, b, a); -} - -static void SsePmulhw(void *b, const void *a) { - pmulhw(b, b, a); -} - -static void SsePmuludq(void *b, const void *a) { - pmuludq(b, b, a); -} - -static void SsePmullw(void *b, const void *a) { - pmullw(b, b, a); -} - -static void SsePmulld(void *b, const void *a) { - pmulld(b, b, a); -} - -static void SsePshufb(void *b, const void *a) { - pshufb(b, b, a); -} - -static void SsePhaddw(void *b, const void *a) { - phaddw(b, b, a); -} - -static void SsePhaddd(void *b, const void *a) { - phaddd(b, b, a); -} - -static void SsePhaddsw(void *b, const void *a) { - phaddsw(b, b, a); -} - -static void SsePmaddubsw(void *b, const void *a) { - pmaddubsw(b, b, a); -} - -static void SsePhsubw(void *b, const void *a) { - phsubw(b, b, a); -} - -static void SsePhsubd(void *b, const void *a) { - phsubd(b, b, a); -} - -static void SsePhsubsw(void *b, const void *a) { - phsubsw(b, b, a); -} - -static void SsePsignb(void *b, const void *a) { - psignb(b, b, a); -} - -static void SsePsignw(void *b, const void *a) { - psignw(b, b, a); -} - -static void SsePsignd(void *b, const void *a) { - psignd(b, b, a); -} - -static void SsePmulhrsw(void *b, const void *a) { - pmulhrsw(b, b, a); -} - -static void SsePabsb(void *b, const void *a) { - pabsb(b, a); -} - -static void SsePabsw(void *b, const void *a) { - pabsw(b, a); -} - -static void SsePabsd(void *b, const void *a) { - pabsd(b, a); -} - -static void OpSse(struct Machine *m, uint32_t rde, - void kernel(void *, const void *)) { - char x[16], y[16]; - if (Osz(rde)) { - kernel(XmmRexrReg(m, rde), GetModrmRegisterXmmPointerRead16(m, rde)); - } else { - memcpy(x, XmmRexrReg(m, rde), 8); - memcpy(y, GetModrmRegisterXmmPointerRead16(m, rde), 8); - kernel(x, y); - memcpy(XmmRexrReg(m, rde), x, 8); +static void MmxPor(uint8_t x[8], const uint8_t y[8]) { + unsigned i; + for (i = 0; i < 8; ++i) { + x[i] |= y[i]; } } -void OpSsePunpcklbw(struct Machine *m, uint32_t rde) { - OpSse(m, rde, SsePunpcklbw); -} - -void OpSsePunpcklwd(struct Machine *m, uint32_t rde) { - OpSse(m, rde, SsePunpcklwd); -} - -void OpSsePunpckldq(struct Machine *m, uint32_t rde) { - OpSse(m, rde, SsePunpckldq); -} - -void OpSsePacksswb(struct Machine *m, uint32_t rde) { - OpSse(m, rde, SsePacksswb); -} - -void OpSsePcmpgtb(struct Machine *m, uint32_t rde) { - OpSse(m, rde, SsePcmpgtb); -} - -void OpSsePcmpgtw(struct Machine *m, uint32_t rde) { - OpSse(m, rde, SsePcmpgtw); -} - -void OpSsePcmpgtd(struct Machine *m, uint32_t rde) { - OpSse(m, rde, SsePcmpgtd); -} - -void OpSsePackuswb(struct Machine *m, uint32_t rde) { - OpSse(m, rde, SsePackuswb); -} - -void OpSsePunpckhbw(struct Machine *m, uint32_t rde) { - OpSse(m, rde, SsePunpckhbw); -} - -void OpSsePunpckhwd(struct Machine *m, uint32_t rde) { - OpSse(m, rde, SsePunpckhwd); -} - -void OpSsePunpckhdq(struct Machine *m, uint32_t rde) { - OpSse(m, rde, SsePunpckhdq); -} - -void OpSsePackssdw(struct Machine *m, uint32_t rde) { - OpSse(m, rde, SsePackssdw); -} - -void OpSsePunpcklqdq(struct Machine *m, uint32_t rde) { - OpSse(m, rde, SsePunpcklqdq); -} - -void OpSsePunpckhqdq(struct Machine *m, uint32_t rde) { - OpSse(m, rde, SsePunpckhqdq); -} - -void OpSsePcmpeqb(struct Machine *m, uint32_t rde) { - OpSse(m, rde, SsePcmpeqb); -} - -void OpSsePcmpeqw(struct Machine *m, uint32_t rde) { - OpSse(m, rde, SsePcmpeqw); -} - -void OpSsePcmpeqd(struct Machine *m, uint32_t rde) { - OpSse(m, rde, SsePcmpeqd); -} - -void OpSsePsrlwv(struct Machine *m, uint32_t rde) { - OpSse(m, rde, SsePsrlwv); -} - -void OpSsePsrldv(struct Machine *m, uint32_t rde) { - OpSse(m, rde, SsePsrldv); -} - -void OpSsePsrlqv(struct Machine *m, uint32_t rde) { - OpSse(m, rde, SsePsrlqv); -} - -void OpSsePaddq(struct Machine *m, uint32_t rde) { - OpSse(m, rde, SsePaddq); -} - -void OpSsePmullw(struct Machine *m, uint32_t rde) { - OpSse(m, rde, SsePmullw); -} - -void OpSsePsubusb(struct Machine *m, uint32_t rde) { - OpSse(m, rde, SsePsubusb); -} - -void OpSsePsubusw(struct Machine *m, uint32_t rde) { - OpSse(m, rde, SsePsubusw); -} - -void OpSsePminub(struct Machine *m, uint32_t rde) { - OpSse(m, rde, SsePminub); -} - -void OpSsePand(struct Machine *m, uint32_t rde) { - OpSse(m, rde, SsePand); -} - -void OpSsePaddusb(struct Machine *m, uint32_t rde) { - OpSse(m, rde, SsePaddusb); -} - -void OpSsePaddusw(struct Machine *m, uint32_t rde) { - OpSse(m, rde, SsePaddusw); -} - -void OpSsePmaxub(struct Machine *m, uint32_t rde) { - OpSse(m, rde, SsePmaxub); -} - -void OpSsePandn(struct Machine *m, uint32_t rde) { - OpSse(m, rde, SsePandn); -} - -void OpSsePavgb(struct Machine *m, uint32_t rde) { - OpSse(m, rde, SsePavgb); -} - -void OpSsePsrawv(struct Machine *m, uint32_t rde) { - OpSse(m, rde, SsePsrawv); -} - -void OpSsePsradv(struct Machine *m, uint32_t rde) { - OpSse(m, rde, SsePsradv); -} - -void OpSsePavgw(struct Machine *m, uint32_t rde) { - OpSse(m, rde, SsePavgw); -} - -void OpSsePmulhuw(struct Machine *m, uint32_t rde) { - OpSse(m, rde, SsePmulhuw); -} - -void OpSsePmulhw(struct Machine *m, uint32_t rde) { - OpSse(m, rde, SsePmulhw); -} - -void OpSsePsubsb(struct Machine *m, uint32_t rde) { - OpSse(m, rde, SsePsubsb); -} - -void OpSsePsubsw(struct Machine *m, uint32_t rde) { - OpSse(m, rde, SsePsubsw); -} - -void OpSsePminsw(struct Machine *m, uint32_t rde) { - OpSse(m, rde, SsePminsw); -} - -void OpSsePor(struct Machine *m, uint32_t rde) { - OpSse(m, rde, SsePor); -} - -void OpSsePaddsb(struct Machine *m, uint32_t rde) { - OpSse(m, rde, SsePaddsb); -} - -void OpSsePaddsw(struct Machine *m, uint32_t rde) { - OpSse(m, rde, SsePaddsw); -} - -void OpSsePmaxsw(struct Machine *m, uint32_t rde) { - OpSse(m, rde, SsePmaxsw); -} - -void OpSsePxor(struct Machine *m, uint32_t rde) { - OpSse(m, rde, SsePxor); -} - -void OpSsePsllwv(struct Machine *m, uint32_t rde) { - OpSse(m, rde, SsePsllwv); -} - -void OpSsePslldv(struct Machine *m, uint32_t rde) { - OpSse(m, rde, SsePslldv); -} - -void OpSsePsllqv(struct Machine *m, uint32_t rde) { - OpSse(m, rde, SsePsllqv); -} - -void OpSsePmuludq(struct Machine *m, uint32_t rde) { - OpSse(m, rde, SsePmuludq); -} - -void OpSsePmaddwd(struct Machine *m, uint32_t rde) { - OpSse(m, rde, SsePmaddwd); -} - -void OpSsePsadbw(struct Machine *m, uint32_t rde) { - OpSse(m, rde, SsePsadbw); -} - -void OpSsePsubb(struct Machine *m, uint32_t rde) { - OpSse(m, rde, SsePsubb); -} - -void OpSsePsubw(struct Machine *m, uint32_t rde) { - OpSse(m, rde, SsePsubw); -} - -void OpSsePsubd(struct Machine *m, uint32_t rde) { - OpSse(m, rde, SsePsubd); -} - -void OpSsePsubq(struct Machine *m, uint32_t rde) { - OpSse(m, rde, SsePsubq); -} - -void OpSsePaddb(struct Machine *m, uint32_t rde) { - OpSse(m, rde, SsePaddb); -} - -void OpSsePaddw(struct Machine *m, uint32_t rde) { - OpSse(m, rde, SsePaddw); -} - -void OpSsePaddd(struct Machine *m, uint32_t rde) { - OpSse(m, rde, SsePaddd); -} - -void OpSsePshufb(struct Machine *m, uint32_t rde) { - OpSse(m, rde, SsePshufb); -} - -void OpSsePhaddw(struct Machine *m, uint32_t rde) { - OpSse(m, rde, SsePhaddw); -} - -void OpSsePhaddd(struct Machine *m, uint32_t rde) { - OpSse(m, rde, SsePhaddd); -} - -void OpSsePhaddsw(struct Machine *m, uint32_t rde) { - OpSse(m, rde, SsePhaddsw); -} - -void OpSsePmaddubsw(struct Machine *m, uint32_t rde) { - OpSse(m, rde, SsePmaddubsw); -} - -void OpSsePhsubw(struct Machine *m, uint32_t rde) { - OpSse(m, rde, SsePhsubw); -} - -void OpSsePhsubd(struct Machine *m, uint32_t rde) { - OpSse(m, rde, SsePhsubd); -} - -void OpSsePhsubsw(struct Machine *m, uint32_t rde) { - OpSse(m, rde, SsePhsubsw); -} - -void OpSsePsignb(struct Machine *m, uint32_t rde) { - OpSse(m, rde, SsePsignb); -} - -void OpSsePsignw(struct Machine *m, uint32_t rde) { - OpSse(m, rde, SsePsignw); -} - -void OpSsePsignd(struct Machine *m, uint32_t rde) { - OpSse(m, rde, SsePsignd); -} - -void OpSsePmulhrsw(struct Machine *m, uint32_t rde) { - OpSse(m, rde, SsePmulhrsw); -} - -void OpSsePabsb(struct Machine *m, uint32_t rde) { - OpSse(m, rde, SsePabsb); -} - -void OpSsePabsw(struct Machine *m, uint32_t rde) { - OpSse(m, rde, SsePabsw); -} - -void OpSsePabsd(struct Machine *m, uint32_t rde) { - OpSse(m, rde, SsePabsd); -} - -void OpSsePmulld(struct Machine *m, uint32_t rde) { - OpSse(m, rde, SsePmulld); -} - -static void SseUdqIb(struct Machine *m, uint32_t rde, int kernel) { - void *y; - uint8_t i; - uint8_t x[16]; - i = m->xedd->op.uimm0; - y = XmmRexbRm(m, rde); - switch (kernel) { - CASE(0, (psrlw)((void *)x, y, i)); - CASE(1, (psraw)((void *)x, y, i)); - CASE(2, (psllw)((void *)x, y, i)); - CASE(3, (psrld)((void *)x, y, i)); - CASE(4, (psrad)((void *)x, y, i)); - CASE(5, (pslld)((void *)x, y, i)); - CASE(6, (psrlq)((void *)x, y, i)); - CASE(7, (psrldq)((void *)x, y, i)); - CASE(8, (psllq)((void *)x, y, i)); - CASE(9, (pslldq)((void *)x, y, i)); - default: - unreachable; +static void MmxPxor(uint8_t x[8], const uint8_t y[8]) { + unsigned i; + for (i = 0; i < 8; ++i) { + x[i] ^= y[i]; } - if (Osz(rde)) { - memcpy(XmmRexbRm(m, rde), x, 16); +} + +static void MmxPsubb(uint8_t x[8], const uint8_t y[8]) { + unsigned i; + for (i = 0; i < 8; ++i) { + x[i] -= y[i]; + } +} + +static void MmxPaddb(uint8_t x[8], const uint8_t y[8]) { + unsigned i; + for (i = 0; i < 8; ++i) { + x[i] += y[i]; + } +} + +static void MmxPand(uint8_t x[8], const uint8_t y[8]) { + unsigned i; + for (i = 0; i < 8; ++i) { + x[i] &= y[i]; + } +} + +static void MmxPandn(uint8_t x[8], const uint8_t y[8]) { + unsigned i; + for (i = 0; i < 8; ++i) { + x[i] = ~x[i] & y[i]; + } +} + +static void MmxPavgb(uint8_t x[8], const uint8_t y[8]) { + unsigned i; + for (i = 0; i < 8; ++i) { + x[i] = (x[i] + y[i] + 1) >> 1; + } +} + +static void MmxPabsb(uint8_t x[8], const uint8_t y[8]) { + unsigned i; + for (i = 0; i < 8; ++i) { + x[i] = ABS((int8_t)y[i]); + } +} + +static void MmxPminub(uint8_t x[8], const uint8_t y[8]) { + unsigned i; + for (i = 0; i < 8; ++i) { + x[i] = MIN(x[i], y[i]); + } +} + +static void MmxPmaxub(uint8_t x[8], const uint8_t y[8]) { + unsigned i; + for (i = 0; i < 8; ++i) { + x[i] = MAX(x[i], y[i]); + } +} + +static void MmxPaddusb(uint8_t x[8], const uint8_t y[8]) { + unsigned i; + for (i = 0; i < 8; ++i) { + x[i] = MIN(255, x[i] + y[i]); + } +} + +static void MmxPsubusb(uint8_t x[8], const uint8_t y[8]) { + unsigned i; + for (i = 0; i < 8; ++i) { + x[i] = MIN(255, MAX(0, x[i] - y[i])); + } +} + +static void MmxPcmpeqb(uint8_t x[8], const uint8_t y[8]) { + unsigned i; + for (i = 0; i < 8; ++i) { + x[i] = -(x[i] == y[i]); + } +} + +static void MmxPcmpgtb(uint8_t x[8], const uint8_t y[8]) { + unsigned i; + for (i = 0; i < 8; ++i) { + x[i] = -((int8_t)x[i] > (int8_t)y[i]); + } +} + +static void MmxPsubsb(uint8_t x[8], const uint8_t y[8]) { + unsigned i; + for (i = 0; i < 8; ++i) { + x[i] = MAX(-128, MIN(127, (int8_t)x[i] - (int8_t)y[i])); + } +} + +static void MmxPaddsb(uint8_t x[8], const uint8_t y[8]) { + unsigned i; + for (i = 0; i < 8; ++i) { + x[i] = MAX(-128, MIN(127, (int8_t)x[i] + (int8_t)y[i])); + } +} + +static void MmxPmulhrsw(uint8_t x[8], const uint8_t y[8]) { + unsigned i; + int16_t a, b; + for (i = 0; i < 4; ++i) { + a = Read16(x + i * 2); + b = Read16(y + i * 2); + Write16(x + i * 2, (((a * b) >> 14) + 1) >> 1); + } +} + +static void MmxPmaddubsw(uint8_t x[8], const uint8_t y[8]) { + unsigned i; + for (i = 0; i < 4; ++i) { + Write16(x + i * 2, + MAX(-32768, MIN(32767, (x[i * 2 + 0] * (int8_t)y[i * 2 + 0] + + x[i * 2 + 1] * (int8_t)y[i * 2 + 1])))); + } +} + +static void MmxPsraw(uint8_t x[8], unsigned k) { + unsigned i; + if (k > 15) k = 15; + for (i = 0; i < 4; ++i) { + Write16(x + i * 2, (int16_t)Read16(x + i * 2) >> k); + } +} + +static void MmxPsrad(uint8_t x[8], unsigned k) { + unsigned i; + if (k > 31) k = 31; + for (i = 0; i < 2; ++i) { + Write32(x + i * 4, (int32_t)Read32(x + i * 4) >> k); + } +} + +static void MmxPsrlw(uint8_t x[8], unsigned k) { + unsigned i; + if (k < 16) { + for (i = 0; i < 4; ++i) { + Write16(x + i * 2, Read16(x + i * 2) >> k); + } } else { - memcpy(XmmRexbRm(m, rde), x, 8); + memset(x, 0, 8); + } +} + +static void MmxPsllw(uint8_t x[8], unsigned k) { + unsigned i; + if (k <= 15) { + for (i = 0; i < 4; ++i) { + Write16(x + i * 2, Read16(x + i * 2) << k); + } + } else { + memset(x, 0, 8); + } +} + +static void MmxPsrld(uint8_t x[8], unsigned k) { + unsigned i; + if (k <= 31) { + for (i = 0; i < 2; ++i) { + Write32(x + i * 4, Read32(x + i * 4) >> k); + } + } else { + memset(x, 0, 8); + } +} + +static void MmxPslld(uint8_t x[8], unsigned k) { + unsigned i; + if (k <= 31) { + for (i = 0; i < 2; ++i) { + Write32(x + i * 4, Read32(x + i * 4) << k); + } + } else { + memset(x, 0, 8); + } +} + +static void MmxPsrlq(uint8_t x[8], unsigned k) { + if (k <= 63) { + Write64(x, Read64(x) >> k); + } else { + memset(x, 0, 8); + } +} + +static void MmxPsllq(uint8_t x[8], unsigned k) { + if (k <= 63) { + Write64(x, Read64(x) << k); + } else { + memset(x, 0, 8); + } +} + +static void MmxPslldq(uint8_t x[8], unsigned k) { + unsigned i; + uint8_t t[8]; + if (k > 8) k = 8; + for (i = 0; i < k; ++i) t[i] = 0; + for (i = 0; i < 8 - k; ++i) t[k + i] = x[i]; + memcpy(x, t, 8); +} + +static void MmxPsrldq(uint8_t x[8], unsigned k) { + uint8_t t[8]; + if (k > 8) k = 8; + memcpy(t, x + k, 8 - k); + memset(t + (8 - k), 0, k); + memcpy(x, t, 8); +} + +static void MmxPalignr(uint8_t x[8], const uint8_t y[8], unsigned k) { + uint8_t t[24]; + memcpy(t, y, 8); + memcpy(t + 8, x, 8); + memset(t + 16, 0, 8); + memcpy(x, t + MIN(k, 16), 8); +} + +static void MmxPsubw(uint8_t x[8], const uint8_t y[8]) { + unsigned i; + for (i = 0; i < 4; ++i) { + Write16(x + i * 2, Read16(x + i * 2) - Read16(y + i * 2)); + } +} + +static void MmxPaddw(uint8_t x[8], const uint8_t y[8]) { + unsigned i; + for (i = 0; i < 4; ++i) { + Write16(x + i * 2, Read16(x + i * 2) + Read16(y + i * 2)); + } +} + +static void MmxPsubd(uint8_t x[8], const uint8_t y[8]) { + unsigned i; + for (i = 0; i < 2; ++i) { + Write32(x + i * 4, Read32(x + i * 4) - Read32(y + i * 4)); + } +} + +static void MmxPaddd(uint8_t x[8], const uint8_t y[8]) { + unsigned i; + for (i = 0; i < 2; ++i) { + Write32(x + i * 4, Read32(x + i * 4) + Read32(y + i * 4)); + } +} + +static void MmxPaddq(uint8_t x[8], const uint8_t y[8]) { + Write64(x, Read64(x) + Read64(y)); +} + +static void MmxPsubq(uint8_t x[8], const uint8_t y[8]) { + Write64(x, Read64(x) - Read64(y)); +} + +static void MmxPaddsw(uint8_t x[8], const uint8_t y[8]) { + unsigned i; + for (i = 0; i < 4; ++i) { + Write16(x + i * 2, MAX(-32768, MIN(32767, ((int16_t)Read16(x + i * 2) + + (int16_t)Read16(y + i * 2))))); + } +} + +static void MmxPsubsw(uint8_t x[8], const uint8_t y[8]) { + unsigned i; + for (i = 0; i < 4; ++i) { + Write16(x + i * 2, MAX(-32768, MIN(32767, ((int16_t)Read16(x + i * 2) - + (int16_t)Read16(y + i * 2))))); + } +} + +static void MmxPaddusw(uint8_t x[8], const uint8_t y[8]) { + unsigned i; + for (i = 0; i < 4; ++i) { + Write16(x + i * 2, MIN(65535, Read16(x + i * 2) + Read16(y + i * 2))); + } +} + +static void MmxPsubusw(uint8_t x[8], const uint8_t y[8]) { + unsigned i; + for (i = 0; i < 4; ++i) { + Write16(x + i * 2, + MIN(65535, MAX(0, Read16(x + i * 2) - Read16(y + i * 2)))); + } +} + +static void MmxPminsw(uint8_t x[8], const uint8_t y[8]) { + unsigned i; + for (i = 0; i < 4; ++i) { + Write16(x + i * 2, + MIN((int16_t)Read16(x + i * 2), (int16_t)Read16(y + i * 2))); + } +} + +static void MmxPmaxsw(uint8_t x[8], const uint8_t y[8]) { + unsigned i; + for (i = 0; i < 4; ++i) { + Write16(x + i * 2, + MAX((int16_t)Read16(x + i * 2), (int16_t)Read16(y + i * 2))); + } +} + +static void MmxPackuswb(uint8_t x[8], const uint8_t y[8]) { + unsigned i; + uint8_t t[8]; + for (i = 0; i < 4; ++i) { + t[i + 0] = MIN(255, MAX(0, (int16_t)Read16(x + i * 2))); + } + for (i = 0; i < 4; ++i) { + t[i + 4] = MIN(255, MAX(0, (int16_t)Read16(y + i * 2))); + } + memcpy(x, t, 8); +} + +static void MmxPacksswb(uint8_t x[8], const uint8_t y[8]) { + unsigned i; + uint8_t t[8]; + for (i = 0; i < 4; ++i) { + t[i + 0] = MAX(-128, MIN(127, (int16_t)Read16(x + i * 2))); + } + for (i = 0; i < 4; ++i) { + t[i + 4] = MAX(-128, MIN(127, (int16_t)Read16(y + i * 2))); + } + memcpy(x, t, 8); +} + +static void MmxPackssdw(uint8_t x[8], const uint8_t y[8]) { + unsigned i; + uint8_t t[8]; + for (i = 0; i < 2; ++i) { + Write16(t + i * 2 + 0, MAX(-32768, MIN(32767, (int32_t)Read32(x + i * 4)))); + } + for (i = 0; i < 2; ++i) { + Write16(t + i * 2 + 4, MAX(-32768, MIN(32767, (int32_t)Read32(y + i * 4)))); + } + memcpy(x, t, 8); +} + +static void MmxPcmpgtw(uint8_t x[8], const uint8_t y[8]) { + unsigned i; + for (i = 0; i < 4; ++i) { + Write16(x + i * 2, + -((int16_t)Read16(x + i * 2) > (int16_t)Read16(y + i * 2))); + } +} + +static void MmxPcmpeqw(uint8_t x[8], const uint8_t y[8]) { + unsigned i; + for (i = 0; i < 4; ++i) { + Write16(x + i * 2, -(Read16(x + i * 2) == Read16(y + i * 2))); + } +} + +static void MmxPcmpgtd(uint8_t x[8], const uint8_t y[8]) { + unsigned i; + for (i = 0; i < 2; ++i) { + Write32(x + i * 4, + -((int32_t)Read32(x + i * 4) > (int32_t)Read32(y + i * 4))); + } +} + +static void MmxPcmpeqd(uint8_t x[8], const uint8_t y[8]) { + unsigned i; + for (i = 0; i < 2; ++i) { + Write32(x + i * 4, -(Read32(x + i * 4) == Read32(y + i * 4))); + } +} + +static void MmxPsrawv(uint8_t x[8], const uint8_t y[8]) { + unsigned i; + uint64_t k; + k = Read64(y); + if (k > 15) k = 15; + for (i = 0; i < 4; ++i) { + Write16(x + i * 2, (int16_t)Read16(x + i * 2) >> k); + } +} + +static void MmxPsradv(uint8_t x[8], const uint8_t y[8]) { + unsigned i; + uint64_t k; + k = Read64(y); + if (k > 31) k = 31; + for (i = 0; i < 2; ++i) { + Write32(x + i * 4, (int32_t)Read32(x + i * 4) >> k); + } +} + +static void MmxPsrlwv(uint8_t x[8], const uint8_t y[8]) { + unsigned i; + uint64_t k; + k = Read64(y); + if (k < 16) { + for (i = 0; i < 4; ++i) { + Write16(x + i * 2, Read16(x + i * 2) >> k); + } + } else { + memset(x, 0, 8); + } +} + +static void MmxPsllwv(uint8_t x[8], const uint8_t y[8]) { + unsigned i; + uint64_t k; + k = Read64(y); + if (k < 16) { + for (i = 0; i < 4; ++i) { + Write16(x + i * 2, Read16(x + i * 2) << k); + } + } else { + memset(x, 0, 8); + } +} + +static void MmxPsrldv(uint8_t x[8], const uint8_t y[8]) { + unsigned i; + uint64_t k; + k = Read64(y); + if (k < 32) { + for (i = 0; i < 2; ++i) { + Write32(x + i * 4, Read32(x + i * 4) >> k); + } + } else { + memset(x, 0, 8); + } +} + +static void MmxPslldv(uint8_t x[8], const uint8_t y[8]) { + unsigned i; + uint64_t k; + k = Read64(y); + if (k < 32) { + for (i = 0; i < 2; ++i) { + Write32(x + i * 4, Read32(x + i * 4) << k); + } + } else { + memset(x, 0, 8); + } +} + +static void MmxPsrlqv(uint8_t x[8], const uint8_t y[8]) { + uint64_t k; + k = Read64(y); + if (k < 64) { + Write64(x, Read64(x) >> k); + } else { + memset(x, 0, 8); + } +} + +static void MmxPsllqv(uint8_t x[8], const uint8_t y[8]) { + uint64_t k; + k = Read64(y); + if (k < 64) { + Write64(x, Read64(x) << k); + } else { + memset(x, 0, 8); + } +} + +static void MmxPavgw(uint8_t x[8], const uint8_t y[8]) { + unsigned i; + for (i = 0; i < 4; ++i) { + Write16(x + i * 2, (Read16(x + i * 2) + Read16(y + i * 2) + 1) >> 1); + } +} + +static void MmxPsadbw(uint8_t x[8], const uint8_t y[8]) { + unsigned i, s, t; + for (s = i = 0; i < 4; ++i) s += ABS(x[i] - y[i]); + for (t = 0; i < 8; ++i) t += ABS(x[i] - y[i]); + Write32(x + 0, s); + Write32(x + 4, t); +} + +static void MmxPmaddwd(uint8_t x[8], const uint8_t y[8]) { + unsigned i; + for (i = 0; i < 2; ++i) { + Write32(x + i * 4, + ((int16_t)Read16(x + i * 4 + 0) * (int16_t)Read16(y + i * 4 + 0) + + (int16_t)Read16(x + i * 4 + 2) * (int16_t)Read16(y + i * 4 + 2))); + } +} + +static void MmxPmulhuw(uint8_t x[8], const uint8_t y[8]) { + uint32_t v; + unsigned i; + for (i = 0; i < 4; ++i) { + v = Read16(x + i * 2); + v *= Read16(y + i * 2); + v >>= 16; + Write16(x + i * 2, v); + } +} + +static void MmxPmulhw(uint8_t x[8], const uint8_t y[8]) { + unsigned i; + for (i = 0; i < 4; ++i) { + Write16(x + i * 2, + ((int16_t)Read16(x + i * 2) * (int16_t)Read16(y + i * 2)) >> 16); + } +} + +static void MmxPmuludq(uint8_t x[8], const uint8_t y[8]) { + Write64(x, (uint64_t)Read32(x) * Read32(y)); +} + +static void MmxPmullw(uint8_t x[8], const uint8_t y[8]) { + unsigned i; + for (i = 0; i < 4; ++i) { + Write16(x + i * 2, (int16_t)Read16(x + i * 2) * (int16_t)Read16(y + i * 2)); + } +} + +static void MmxPmulld(uint8_t x[8], const uint8_t y[8]) { + unsigned i; + for (i = 0; i < 2; ++i) { + Write32(x + i * 4, Read32(x + i * 4) * Read32(y + i * 4)); + } +} + +static void MmxPshufb(uint8_t x[8], const uint8_t y[8]) { + unsigned i; + uint8_t t[8]; + for (i = 0; i < 8; ++i) { + t[i] = (y[i] & 128) ? 0 : x[y[i] & 7]; + } + memcpy(x, t, 8); +} + +static void MmxPsignb(uint8_t x[8], const uint8_t y[8]) { + int v; + unsigned i; + for (i = 0; i < 8; ++i) { + v = (int8_t)y[i]; + if (!v) { + x[i] = 0; + } else if (v < 0) { + x[i] = -(int8_t)x[i]; + } + } +} + +static void MmxPsignw(uint8_t x[8], const uint8_t y[8]) { + int v; + unsigned i; + for (i = 0; i < 4; ++i) { + v = (int16_t)Read16(y + i * 2); + if (!v) { + Write16(x + i * 2, 0); + } else if (v < 0) { + Write16(x + i * 2, -(int16_t)Read16(x + i * 2)); + } + } +} + +static void MmxPsignd(uint8_t x[8], const uint8_t y[8]) { + int32_t v; + unsigned i; + for (i = 0; i < 2; ++i) { + v = Read32(y + i * 4); + if (!v) { + Write32(x + i * 4, 0); + } else if (v < 0) { + Write32(x + i * 4, -Read32(x + i * 4)); + } + } +} + +static void MmxPabsw(uint8_t x[8], const uint8_t y[8]) { + unsigned i; + for (i = 0; i < 4; ++i) { + Write16(x + i * 2, ABS((int16_t)Read16(y + i * 2))); + } +} + +static void MmxPabsd(uint8_t x[8], const uint8_t y[8]) { + int32_t v; + unsigned i; + for (i = 0; i < 2; ++i) { + v = Read32(y + i * 4); + Write32(x + i * 4, v >= 0 ? v : -(uint32_t)v); + } +} + +static void MmxPhaddw(uint8_t x[8], const uint8_t y[8]) { + uint8_t t[8]; + Write16(t + 0 * 2, Read16(x + 0 * 2) + Read16(x + 1 * 2)); + Write16(t + 1 * 2, Read16(x + 2 * 2) + Read16(x + 3 * 2)); + Write16(t + 2 * 2, Read16(y + 0 * 2) + Read16(y + 1 * 2)); + Write16(t + 3 * 2, Read16(y + 2 * 2) + Read16(y + 3 * 2)); + memcpy(x, t, 8); +} + +static void MmxPhsubw(uint8_t x[8], const uint8_t y[8]) { + uint8_t t[8]; + Write16(t + 0 * 2, Read16(x + 0 * 2) - Read16(x + 1 * 2)); + Write16(t + 1 * 2, Read16(x + 2 * 2) - Read16(x + 3 * 2)); + Write16(t + 2 * 2, Read16(y + 0 * 2) - Read16(y + 1 * 2)); + Write16(t + 3 * 2, Read16(y + 2 * 2) - Read16(y + 3 * 2)); + memcpy(x, t, 8); +} + +static void MmxPhaddd(uint8_t x[8], const uint8_t y[8]) { + uint8_t t[8]; + Write32(t + 0 * 4, Read32(x + 0 * 4) + Read32(x + 1 * 4)); + Write32(t + 1 * 4, Read32(y + 0 * 4) + Read32(y + 1 * 4)); + memcpy(x, t, 8); +} + +static void MmxPhsubd(uint8_t x[8], const uint8_t y[8]) { + uint8_t t[8]; + Write32(t + 0 * 4, Read32(x + 0 * 4) - Read32(x + 1 * 4)); + Write32(t + 1 * 4, Read32(y + 0 * 4) - Read32(y + 1 * 4)); + memcpy(x, t, 8); +} + +static void MmxPhaddsw(uint8_t x[8], const uint8_t y[8]) { + uint8_t t[8]; + Write16(t + 0 * 2, MAX(-32768, MIN(32767, ((int16_t)Read16(x + 0 * 2) + + (int16_t)Read16(x + 1 * 2))))); + Write16(t + 1 * 2, MAX(-32768, MIN(32767, ((int16_t)Read16(x + 2 * 2) + + (int16_t)Read16(x + 3 * 2))))); + Write16(t + 2 * 2, MAX(-32768, MIN(32767, ((int16_t)Read16(y + 0 * 2) + + (int16_t)Read16(y + 1 * 2))))); + Write16(t + 3 * 2, MAX(-32768, MIN(32767, ((int16_t)Read16(y + 2 * 2) + + (int16_t)Read16(y + 3 * 2))))); + memcpy(x, t, 8); +} + +static void MmxPhsubsw(uint8_t x[8], const uint8_t y[8]) { + uint8_t t[8]; + Write16(t + 0 * 2, MAX(-32768, MIN(32767, ((int16_t)Read16(x + 0 * 2) - + (int16_t)Read16(x + 1 * 2))))); + Write16(t + 1 * 2, MAX(-32768, MIN(32767, ((int16_t)Read16(x + 2 * 2) - + (int16_t)Read16(x + 3 * 2))))); + Write16(t + 2 * 2, MAX(-32768, MIN(32767, ((int16_t)Read16(y + 0 * 2) - + (int16_t)Read16(x + 1 * 2))))); + Write16(t + 3 * 2, MAX(-32768, MIN(32767, ((int16_t)Read16(y + 2 * 2) - + (int16_t)Read16(y + 3 * 2))))); + memcpy(x, t, 8); +} + +static void MmxPunpcklbw(uint8_t x[8], const uint8_t y[8]) { + x[7] = y[3]; + x[6] = x[3]; + x[5] = y[2]; + x[4] = x[2]; + x[3] = y[1]; + x[2] = x[1]; + x[1] = y[0]; + x[0] = x[0]; +} + +static void MmxPunpckhbw(uint8_t x[8], const uint8_t y[8]) { + x[0] = x[4]; + x[1] = y[4]; + x[2] = x[5]; + x[3] = y[5]; + x[4] = x[6]; + x[5] = y[6]; + x[6] = x[7]; + x[7] = y[7]; +} + +static void MmxPunpcklwd(uint8_t x[8], const uint8_t y[8]) { + x[6] = y[2]; + x[7] = y[3]; + x[4] = x[2]; + x[5] = x[3]; + x[2] = y[0]; + x[3] = y[1]; + x[0] = x[0]; + x[1] = x[1]; +} + +static void MmxPunpckldq(uint8_t x[8], const uint8_t y[8]) { + x[4] = y[0]; + x[5] = y[1]; + x[6] = y[2]; + x[7] = y[3]; + x[0] = x[0]; + x[1] = x[1]; + x[2] = x[2]; + x[3] = x[3]; +} + +static void MmxPunpckhwd(uint8_t x[8], const uint8_t y[8]) { + x[0] = x[4]; + x[1] = x[5]; + x[2] = y[4]; + x[3] = y[5]; + x[4] = x[6]; + x[5] = x[7]; + x[6] = y[6]; + x[7] = y[7]; +} + +static void MmxPunpckhdq(uint8_t x[8], const uint8_t y[8]) { + x[0] = x[4]; + x[1] = x[5]; + x[2] = x[6]; + x[3] = x[7]; + x[4] = y[4]; + x[5] = y[5]; + x[6] = y[6]; + x[7] = y[7]; +} + +static void MmxPunpcklqdq(uint8_t x[8], const uint8_t y[8]) { +} + +static void MmxPunpckhqdq(uint8_t x[8], const uint8_t y[8]) { +} + +static void SsePsubb(uint8_t x[16], const uint8_t y[16]) { + unsigned i; + for (i = 0; i < 16; ++i) { + x[i] -= y[i]; + } +} + +static void SsePaddb(uint8_t x[16], const uint8_t y[16]) { + unsigned i; + for (i = 0; i < 16; ++i) { + x[i] += y[i]; + } +} + +static void SsePor(uint8_t x[16], const uint8_t y[16]) { + unsigned i; + for (i = 0; i < 16; ++i) { + x[i] |= y[i]; + } +} + +static void SsePxor(uint8_t x[16], const uint8_t y[16]) { + unsigned i; + for (i = 0; i < 16; ++i) { + x[i] ^= y[i]; + } +} + +static void SsePand(uint8_t x[16], const uint8_t y[16]) { + unsigned i; + for (i = 0; i < 16; ++i) { + x[i] &= y[i]; + } +} + +static void SsePandn(uint8_t x[16], const uint8_t y[16]) { + unsigned i; + for (i = 0; i < 16; ++i) { + x[i] = ~x[i] & y[i]; + } +} + +static void SsePcmpeqb(uint8_t x[16], const uint8_t y[16]) { + unsigned i; + for (i = 0; i < 16; ++i) { + x[i] = -(x[i] == y[i]); + } +} + +static void SsePcmpgtb(uint8_t x[16], const uint8_t y[16]) { + unsigned i; + for (i = 0; i < 16; ++i) { + x[i] = -((int8_t)x[i] > (int8_t)y[i]); + } +} + +static void SsePavgb(uint8_t x[16], const uint8_t y[16]) { + unsigned i; + for (i = 0; i < 16; ++i) { + x[i] = (x[i] + y[i] + 1) >> 1; + } +} + +static void SsePabsb(uint8_t x[16], const uint8_t y[16]) { + unsigned i; + for (i = 0; i < 16; ++i) { + x[i] = ABS((int8_t)y[i]); + } +} + +static void SsePminub(uint8_t x[16], const uint8_t y[16]) { + unsigned i; + for (i = 0; i < 16; ++i) { + x[i] = MIN(x[i], y[i]); + } +} + +static void SsePmaxub(uint8_t x[16], const uint8_t y[16]) { + unsigned i; + for (i = 0; i < 16; ++i) { + x[i] = MAX(x[i], y[i]); + } +} + +static void SsePslldq(uint8_t x[16], unsigned k) { + unsigned i; + uint8_t t[16]; + if (k > 16) k = 16; + for (i = 0; i < k; ++i) t[i] = 0; + for (i = 0; i < 16 - k; ++i) t[k + i] = x[i]; + memcpy(x, t, 16); +} + +static void SsePsrldq(uint8_t x[16], unsigned k) { + uint8_t t[16]; + if (k > 16) k = 16; + memcpy(t, x + k, 16 - k); + memset(t + (16 - k), 0, k); + memcpy(x, t, 16); +} + +static void SsePalignr(uint8_t x[16], const uint8_t y[16], unsigned k) { + uint8_t t[48]; + memcpy(t, y, 16); + memcpy(t + 16, x, 16); + memset(t + 32, 0, 16); + memcpy(x, t + MIN(k, 32), 16); +} + +static void SsePsubw(uint8_t x[16], const uint8_t y[16]) { + unsigned i; + for (i = 0; i < 8; ++i) { + Write16(x + i * 2, Read16(x + i * 2) - Read16(y + i * 2)); + } +} + +static void SsePaddw(uint8_t x[16], const uint8_t y[16]) { + unsigned i; + for (i = 0; i < 8; ++i) { + Write16(x + i * 2, Read16(x + i * 2) + Read16(y + i * 2)); + } +} + +static void SsePsubd(uint8_t x[16], const uint8_t y[16]) { + unsigned i; + for (i = 0; i < 4; ++i) { + Write32(x + i * 4, Read32(x + i * 4) - Read32(y + i * 4)); + } +} + +static void SsePaddd(uint8_t x[16], const uint8_t y[16]) { + unsigned i; + for (i = 0; i < 4; ++i) { + Write32(x + i * 4, Read32(x + i * 4) + Read32(y + i * 4)); + } +} + +static void SsePaddq(uint8_t x[16], const uint8_t y[16]) { + unsigned i; + for (i = 0; i < 2; ++i) { + Write64(x + i * 8, Read64(x + i * 8) + Read64(y + i * 8)); + } +} + +static void SsePsubq(uint8_t x[16], const uint8_t y[16]) { + unsigned i; + for (i = 0; i < 2; ++i) { + Write64(x + i * 8, Read64(x + i * 8) - Read64(y + i * 8)); + } +} + +static void SsePaddusw(uint8_t x[16], const uint8_t y[16]) { + unsigned i; + for (i = 0; i < 8; ++i) { + Write16(x + i * 2, MIN(65535, Read16(x + i * 2) + Read16(y + i * 2))); + } +} + +static void SsePackuswb(uint8_t x[16], const uint8_t y[16]) { + unsigned i; + uint8_t t[16]; + for (i = 0; i < 8; ++i) { + t[i + 0] = MIN(255, MAX(0, (int16_t)Read16(x + i * 2))); + } + for (i = 0; i < 8; ++i) { + t[i + 8] = MIN(255, MAX(0, (int16_t)Read16(y + i * 2))); + } + memcpy(x, t, 16); +} + +static void SsePacksswb(uint8_t x[16], const uint8_t y[16]) { + unsigned i; + uint8_t t[16]; + for (i = 0; i < 8; ++i) { + t[i + 0] = MAX(-128, MIN(127, (int16_t)Read16(x + i * 2))); + } + for (i = 0; i < 8; ++i) { + t[i + 8] = MAX(-128, MIN(127, (int16_t)Read16(y + i * 2))); + } + memcpy(x, t, 16); +} + +static void SsePackssdw(uint8_t x[16], const uint8_t y[16]) { + unsigned i; + uint8_t t[16]; + for (i = 0; i < 4; ++i) { + Write16(t + i * 2 + 0, MAX(-32768, MIN(32767, (int32_t)Read32(x + i * 4)))); + } + for (i = 0; i < 4; ++i) { + Write16(t + i * 2 + 8, MAX(-32768, MIN(32767, (int32_t)Read32(y + i * 4)))); + } + memcpy(x, t, 16); +} + +static void SsePsadbw(uint8_t x[16], const uint8_t y[16]) { + unsigned i, s, t; + for (s = i = 0; i < 8; ++i) s += ABS(x[i] - y[i]); + for (t = 0; i < 16; ++i) t += ABS(x[i] - y[i]); + Write64(x + 0, s); + Write64(x + 8, t); +} + +static void SsePmuludq(uint8_t x[16], const uint8_t y[16]) { + unsigned i; + for (i = 0; i < 2; ++i) { + Write64(x + i * 8, (uint64_t)Read32(x + i * 8) * Read32(y + i * 8)); + } +} + +static void SsePshufb(uint8_t x[16], const uint8_t y[16]) { + unsigned i; + uint8_t t[16]; + for (i = 0; i < 16; ++i) { + t[i] = (y[i] & 128) ? 0 : x[y[i] & 15]; + } + memcpy(x, t, 16); +} + +static void SsePhaddd(uint8_t x[16], const uint8_t y[16]) { + uint8_t t[16]; + Write32(t + 0 * 4, Read32(x + 0 * 4) + Read32(x + 1 * 4)); + Write32(t + 1 * 4, Read32(x + 2 * 4) + Read32(x + 3 * 4)); + Write32(t + 2 * 4, Read32(y + 0 * 4) + Read32(y + 1 * 4)); + Write32(t + 3 * 4, Read32(y + 2 * 4) + Read32(y + 3 * 4)); + memcpy(x, t, 16); +} + +static void SsePhsubd(uint8_t x[16], const uint8_t y[16]) { + uint8_t t[16]; + Write32(t + 0 * 4, Read32(x + 0 * 4) - Read32(x + 1 * 4)); + Write32(t + 1 * 4, Read32(x + 2 * 4) - Read32(x + 3 * 4)); + Write32(t + 2 * 4, Read32(y + 0 * 4) - Read32(y + 1 * 4)); + Write32(t + 3 * 4, Read32(y + 2 * 4) - Read32(y + 3 * 4)); + memcpy(x, t, 16); +} + +static void SsePhaddw(uint8_t x[16], const uint8_t y[16]) { + uint8_t t[16]; + Write16(t + 0 * 2, Read16(x + 0 * 2) + Read16(x + 1 * 2)); + Write16(t + 1 * 2, Read16(x + 2 * 2) + Read16(x + 3 * 2)); + Write16(t + 2 * 2, Read16(x + 4 * 2) + Read16(x + 5 * 2)); + Write16(t + 3 * 2, Read16(x + 6 * 2) + Read16(x + 7 * 2)); + Write16(t + 4 * 2, Read16(y + 0 * 2) + Read16(y + 1 * 2)); + Write16(t + 5 * 2, Read16(y + 2 * 2) + Read16(y + 3 * 2)); + Write16(t + 6 * 2, Read16(y + 4 * 2) + Read16(y + 5 * 2)); + Write16(t + 7 * 2, Read16(y + 6 * 2) + Read16(y + 7 * 2)); + memcpy(x, t, 16); +} + +static void SsePhsubw(uint8_t x[16], const uint8_t y[16]) { + uint8_t t[16]; + Write16(t + 0 * 2, Read16(x + 0 * 2) - Read16(x + 1 * 2)); + Write16(t + 1 * 2, Read16(x + 2 * 2) - Read16(x + 3 * 2)); + Write16(t + 2 * 2, Read16(x + 4 * 2) - Read16(x + 5 * 2)); + Write16(t + 3 * 2, Read16(x + 6 * 2) - Read16(x + 7 * 2)); + Write16(t + 4 * 2, Read16(y + 0 * 2) - Read16(y + 1 * 2)); + Write16(t + 5 * 2, Read16(y + 2 * 2) - Read16(y + 3 * 2)); + Write16(t + 6 * 2, Read16(y + 4 * 2) - Read16(y + 5 * 2)); + Write16(t + 7 * 2, Read16(y + 6 * 2) - Read16(y + 7 * 2)); + memcpy(x, t, 16); +} + +static void SsePhaddsw(uint8_t x[16], const uint8_t y[16]) { + uint8_t t[16]; + Write16(t + 0 * 2, MAX(-32768, MIN(32767, ((int16_t)Read16(x + 0 * 2) + + (int16_t)Read16(x + 1 * 2))))); + Write16(t + 1 * 2, MAX(-32768, MIN(32767, ((int16_t)Read16(x + 2 * 2) + + (int16_t)Read16(x + 3 * 2))))); + Write16(t + 2 * 2, MAX(-32768, MIN(32767, ((int16_t)Read16(x + 4 * 2) + + (int16_t)Read16(x + 5 * 2))))); + Write16(t + 3 * 2, MAX(-32768, MIN(32767, ((int16_t)Read16(x + 6 * 2) + + (int16_t)Read16(x + 7 * 2))))); + Write16(t + 4 * 2, MAX(-32768, MIN(32767, ((int16_t)Read16(y + 0 * 2) + + (int16_t)Read16(y + 1 * 2))))); + Write16(t + 5 * 2, MAX(-32768, MIN(32767, ((int16_t)Read16(y + 2 * 2) + + (int16_t)Read16(y + 3 * 2))))); + Write16(t + 6 * 2, MAX(-32768, MIN(32767, ((int16_t)Read16(y + 4 * 2) + + (int16_t)Read16(y + 5 * 2))))); + Write16(t + 7 * 2, MAX(-32768, MIN(32767, ((int16_t)Read16(y + 6 * 2) + + (int16_t)Read16(y + 7 * 2))))); + memcpy(x, t, 16); +} + +static void SsePhsubsw(uint8_t x[16], const uint8_t y[16]) { + uint8_t t[16]; + Write16(t + 0 * 2, MAX(-32768, MIN(32767, ((int16_t)Read16(x + 0 * 2) - + (int16_t)Read16(x + 1 * 2))))); + Write16(t + 1 * 2, MAX(-32768, MIN(32767, ((int16_t)Read16(x + 2 * 2) - + (int16_t)Read16(x + 3 * 2))))); + Write16(t + 2 * 2, MAX(-32768, MIN(32767, ((int16_t)Read16(x + 4 * 2) - + (int16_t)Read16(x + 5 * 2))))); + Write16(t + 3 * 2, MAX(-32768, MIN(32767, ((int16_t)Read16(x + 6 * 2) - + (int16_t)Read16(x + 7 * 2))))); + Write16(t + 4 * 2, MAX(-32768, MIN(32767, ((int16_t)Read16(y + 0 * 2) - + (int16_t)Read16(y + 1 * 2))))); + Write16(t + 5 * 2, MAX(-32768, MIN(32767, ((int16_t)Read16(y + 2 * 2) - + (int16_t)Read16(y + 3 * 2))))); + Write16(t + 6 * 2, MAX(-32768, MIN(32767, ((int16_t)Read16(y + 4 * 2) - + (int16_t)Read16(y + 5 * 2))))); + Write16(t + 7 * 2, MAX(-32768, MIN(32767, ((int16_t)Read16(y + 6 * 2) - + (int16_t)Read16(y + 7 * 2))))); + memcpy(x, t, 16); +} + +static void SsePunpcklbw(uint8_t x[16], const uint8_t y[16]) { + x[0xf] = y[0x7]; + x[0xe] = x[0x7]; + x[0xd] = y[0x6]; + x[0xc] = x[0x6]; + x[0xb] = y[0x5]; + x[0xa] = x[0x5]; + x[0x9] = y[0x4]; + x[0x8] = x[0x4]; + x[0x7] = y[0x3]; + x[0x6] = x[0x3]; + x[0x5] = y[0x2]; + x[0x4] = x[0x2]; + x[0x3] = y[0x1]; + x[0x2] = x[0x1]; + x[0x1] = y[0x0]; + x[0x0] = x[0x0]; +} + +static void SsePunpckhbw(uint8_t x[16], const uint8_t y[16]) { + x[0x0] = x[0x8]; + x[0x1] = y[0x8]; + x[0x2] = x[0x9]; + x[0x3] = y[0x9]; + x[0x4] = x[0xa]; + x[0x5] = y[0xa]; + x[0x6] = x[0xb]; + x[0x7] = y[0xb]; + x[0x8] = x[0xc]; + x[0x9] = y[0xc]; + x[0xa] = x[0xd]; + x[0xb] = y[0xd]; + x[0xc] = x[0xe]; + x[0xd] = y[0xe]; + x[0xe] = x[0xf]; + x[0xf] = y[0xf]; +} + +static void SsePunpcklwd(uint8_t x[16], const uint8_t y[16]) { + x[0xe] = y[0x6]; + x[0xf] = y[0x7]; + x[0xc] = x[0x6]; + x[0xd] = x[0x7]; + x[0xa] = y[0x4]; + x[0xb] = y[0x5]; + x[0x8] = x[0x4]; + x[0x9] = x[0x5]; + x[0x6] = y[0x2]; + x[0x7] = y[0x3]; + x[0x4] = x[0x2]; + x[0x5] = x[0x3]; + x[0x2] = y[0x0]; + x[0x3] = y[0x1]; + x[0x0] = x[0x0]; + x[0x1] = x[0x1]; +} + +static void SsePunpckldq(uint8_t x[16], const uint8_t y[16]) { + x[0xc] = y[0x4]; + x[0xd] = y[0x5]; + x[0xe] = y[0x6]; + x[0xf] = y[0x7]; + x[0x8] = x[0x4]; + x[0x9] = x[0x5]; + x[0xa] = x[0x6]; + x[0xb] = x[0x7]; + x[0x4] = y[0x0]; + x[0x5] = y[0x1]; + x[0x6] = y[0x2]; + x[0x7] = y[0x3]; + x[0x0] = x[0x0]; + x[0x1] = x[0x1]; + x[0x2] = x[0x2]; + x[0x3] = x[0x3]; +} + +static void SsePunpckhwd(uint8_t x[16], const uint8_t y[16]) { + x[0x0] = x[0x8]; + x[0x1] = x[0x9]; + x[0x2] = y[0x8]; + x[0x3] = y[0x9]; + x[0x4] = x[0xa]; + x[0x5] = x[0xb]; + x[0x6] = y[0xa]; + x[0x7] = y[0xb]; + x[0x8] = x[0xc]; + x[0x9] = x[0xd]; + x[0xa] = y[0xc]; + x[0xb] = y[0xd]; + x[0xc] = x[0xe]; + x[0xd] = x[0xf]; + x[0xe] = y[0xe]; + x[0xf] = y[0xf]; +} + +static void SsePunpckhdq(uint8_t x[16], const uint8_t y[16]) { + x[0x0] = x[0x8]; + x[0x1] = x[0x9]; + x[0x2] = x[0xa]; + x[0x3] = x[0xb]; + x[0x4] = y[0x8]; + x[0x5] = y[0x9]; + x[0x6] = y[0xa]; + x[0x7] = y[0xb]; + x[0x8] = x[0xc]; + x[0x9] = x[0xd]; + x[0xa] = x[0xe]; + x[0xb] = x[0xf]; + x[0xc] = y[0xc]; + x[0xd] = y[0xd]; + x[0xe] = y[0xe]; + x[0xf] = y[0xf]; +} + +static void SsePunpcklqdq(uint8_t x[16], const uint8_t y[16]) { + x[0x8] = y[0x0]; + x[0x9] = y[0x1]; + x[0xa] = y[0x2]; + x[0xb] = y[0x3]; + x[0xc] = y[0x4]; + x[0xd] = y[0x5]; + x[0xe] = y[0x6]; + x[0xf] = y[0x7]; + x[0x0] = x[0x0]; + x[0x1] = x[0x1]; + x[0x2] = x[0x2]; + x[0x3] = x[0x3]; + x[0x4] = x[0x4]; + x[0x5] = x[0x5]; + x[0x6] = x[0x6]; + x[0x7] = x[0x7]; +} + +static void SsePunpckhqdq(uint8_t x[16], const uint8_t y[16]) { + x[0x0] = x[0x8]; + x[0x1] = x[0x9]; + x[0x2] = x[0xa]; + x[0x3] = x[0xb]; + x[0x4] = x[0xc]; + x[0x5] = x[0xd]; + x[0x6] = x[0xe]; + x[0x7] = x[0xf]; + x[0x8] = y[0x8]; + x[0x9] = y[0x9]; + x[0xa] = y[0xa]; + x[0xb] = y[0xb]; + x[0xc] = y[0xc]; + x[0xd] = y[0xd]; + x[0xe] = y[0xe]; + x[0xf] = y[0xf]; +} + +static void SsePsrlw(uint8_t x[16], unsigned k) { + MmxPsrlw(x + 0, k); + MmxPsrlw(x + 8, k); +} + +static void SsePsraw(uint8_t x[16], unsigned k) { + MmxPsraw(x + 0, k); + MmxPsraw(x + 8, k); +} + +static void SsePsllw(uint8_t x[16], unsigned k) { + MmxPsllw(x + 0, k); + MmxPsllw(x + 8, k); +} + +static void SsePsrld(uint8_t x[16], unsigned k) { + MmxPsrld(x + 0, k); + MmxPsrld(x + 8, k); +} + +static void SsePsrad(uint8_t x[16], unsigned k) { + MmxPsrad(x + 0, k); + MmxPsrad(x + 8, k); +} + +static void SsePslld(uint8_t x[16], unsigned k) { + MmxPslld(x + 0, k); + MmxPslld(x + 8, k); +} + +static void SsePsrlq(uint8_t x[16], unsigned k) { + MmxPsrlq(x + 0, k); + MmxPsrlq(x + 8, k); +} + +static void SsePsllq(uint8_t x[16], unsigned k) { + MmxPsllq(x + 0, k); + MmxPsllq(x + 8, k); +} + +static void SsePsubsb(uint8_t x[16], const uint8_t y[16]) { + MmxPsubsb(x + 0, y + 0); + MmxPsubsb(x + 8, y + 8); +} + +static void SsePaddsb(uint8_t x[16], const uint8_t y[16]) { + MmxPaddsb(x + 0, y + 0); + MmxPaddsb(x + 8, y + 8); +} + +static void SsePsubsw(uint8_t x[16], const uint8_t y[16]) { + MmxPsubsw(x + 0, y + 0); + MmxPsubsw(x + 8, y + 8); +} + +static void SsePaddsw(uint8_t x[16], const uint8_t y[16]) { + MmxPaddsw(x + 0, y + 0); + MmxPaddsw(x + 8, y + 8); +} + +static void SsePaddusb(uint8_t x[16], const uint8_t y[16]) { + MmxPaddusb(x + 0, y + 0); + MmxPaddusb(x + 8, y + 8); +} + +static void SsePsubusb(uint8_t x[16], const uint8_t y[16]) { + MmxPsubusb(x + 0, y + 0); + MmxPsubusb(x + 8, y + 8); +} + +static void SsePsubusw(uint8_t x[16], const uint8_t y[16]) { + MmxPsubusw(x + 0, y + 0); + MmxPsubusw(x + 8, y + 8); +} + +static void SsePminsw(uint8_t x[16], const uint8_t y[16]) { + MmxPminsw(x + 0, y + 0); + MmxPminsw(x + 8, y + 8); +} + +static void SsePmaxsw(uint8_t x[16], const uint8_t y[16]) { + MmxPmaxsw(x + 0, y + 0); + MmxPmaxsw(x + 8, y + 8); +} + +static void SsePsignb(uint8_t x[16], const uint8_t y[16]) { + MmxPsignb(x + 0, y + 0); + MmxPsignb(x + 8, y + 8); +} + +static void SsePsignw(uint8_t x[16], const uint8_t y[16]) { + MmxPsignw(x + 0, y + 0); + MmxPsignw(x + 8, y + 8); +} + +static void SsePsignd(uint8_t x[16], const uint8_t y[16]) { + MmxPsignd(x + 0, y + 0); + MmxPsignd(x + 8, y + 8); +} + +static void SsePmulhrsw(uint8_t x[16], const uint8_t y[16]) { + MmxPmulhrsw(x + 0, y + 0); + MmxPmulhrsw(x + 8, y + 8); +} + +static void SsePabsw(uint8_t x[16], const uint8_t y[16]) { + MmxPabsw(x + 0, y + 0); + MmxPabsw(x + 8, y + 8); +} + +static void SsePabsd(uint8_t x[16], const uint8_t y[16]) { + MmxPabsd(x + 0, y + 0); + MmxPabsd(x + 8, y + 8); +} + +static void SsePcmpgtw(uint8_t x[16], const uint8_t y[16]) { + MmxPcmpgtw(x + 0, y + 0); + MmxPcmpgtw(x + 8, y + 8); +} + +static void SsePcmpeqw(uint8_t x[16], const uint8_t y[16]) { + MmxPcmpeqw(x + 0, y + 0); + MmxPcmpeqw(x + 8, y + 8); +} + +static void SsePcmpgtd(uint8_t x[16], const uint8_t y[16]) { + MmxPcmpgtd(x + 0, y + 0); + MmxPcmpgtd(x + 8, y + 8); +} + +static void SsePcmpeqd(uint8_t x[16], const uint8_t y[16]) { + MmxPcmpeqd(x + 0, y + 0); + MmxPcmpeqd(x + 8, y + 8); +} + +static void SsePsrawv(uint8_t x[16], const uint8_t y[16]) { + MmxPsrawv(x + 0, y); + MmxPsrawv(x + 8, y); +} + +static void SsePsradv(uint8_t x[16], const uint8_t y[16]) { + MmxPsradv(x + 0, y); + MmxPsradv(x + 8, y); +} + +static void SsePsrlwv(uint8_t x[16], const uint8_t y[16]) { + MmxPsrlwv(x + 0, y); + MmxPsrlwv(x + 8, y); +} + +static void SsePsllwv(uint8_t x[16], const uint8_t y[16]) { + MmxPsllwv(x + 0, y); + MmxPsllwv(x + 8, y); +} + +static void SsePsrldv(uint8_t x[16], const uint8_t y[16]) { + MmxPsrldv(x + 0, y); + MmxPsrldv(x + 8, y); +} + +static void SsePslldv(uint8_t x[16], const uint8_t y[16]) { + MmxPslldv(x + 0, y); + MmxPslldv(x + 8, y); +} + +static void SsePsrlqv(uint8_t x[16], const uint8_t y[16]) { + MmxPsrlqv(x + 0, y); + MmxPsrlqv(x + 8, y); +} + +static void SsePsllqv(uint8_t x[16], const uint8_t y[16]) { + MmxPsllqv(x + 0, y); + MmxPsllqv(x + 8, y); +} + +static void SsePavgw(uint8_t x[16], const uint8_t y[16]) { + MmxPavgw(x + 0, y + 0); + MmxPavgw(x + 8, y + 8); +} + +static void SsePmaddwd(uint8_t x[16], const uint8_t y[16]) { + MmxPmaddwd(x + 0, y + 0); + MmxPmaddwd(x + 8, y + 8); +} + +static void SsePmulhuw(uint8_t x[16], const uint8_t y[16]) { + MmxPmulhuw(x + 0, y + 0); + MmxPmulhuw(x + 8, y + 8); +} + +static void SsePmulhw(uint8_t x[16], const uint8_t y[16]) { + MmxPmulhw(x + 0, y + 0); + MmxPmulhw(x + 8, y + 8); +} + +static void SsePmullw(uint8_t x[16], const uint8_t y[16]) { + MmxPmullw(x + 0, y + 0); + MmxPmullw(x + 8, y + 8); +} + +static void SsePmulld(uint8_t x[16], const uint8_t y[16]) { + MmxPmulld(x + 0, y + 0); + MmxPmulld(x + 8, y + 8); +} + +static void SsePmaddubsw(uint8_t x[16], const uint8_t y[16]) { + MmxPmaddubsw(x + 0, y + 0); + MmxPmaddubsw(x + 8, y + 8); +} + +static void OpPsb(struct Machine *m, uint32_t rde, + void MmxKernel(uint8_t[8], unsigned), + void SseKernel(uint8_t[16], unsigned)) { + if (Osz(rde)) { + SseKernel(XmmRexbRm(m, rde), m->xedd->op.uimm0); + } else { + MmxKernel(XmmRexbRm(m, rde), m->xedd->op.uimm0); } } void Op171(struct Machine *m, uint32_t rde) { switch (ModrmReg(rde)) { case 2: - SseUdqIb(m, rde, 0); + OpPsb(m, rde, MmxPsrlw, SsePsrlw); break; case 4: - SseUdqIb(m, rde, 1); + OpPsb(m, rde, MmxPsraw, SsePsraw); break; case 6: - SseUdqIb(m, rde, 2); + OpPsb(m, rde, MmxPsllw, SsePsllw); break; default: OpUd(m, rde); @@ -743,13 +1445,13 @@ void Op171(struct Machine *m, uint32_t rde) { void Op172(struct Machine *m, uint32_t rde) { switch (ModrmReg(rde)) { case 2: - SseUdqIb(m, rde, 3); + OpPsb(m, rde, MmxPsrld, SsePsrld); break; case 4: - SseUdqIb(m, rde, 4); + OpPsb(m, rde, MmxPsrad, SsePsrad); break; case 6: - SseUdqIb(m, rde, 5); + OpPsb(m, rde, MmxPslld, SsePslld); break; default: OpUd(m, rde); @@ -759,35 +1461,114 @@ void Op172(struct Machine *m, uint32_t rde) { void Op173(struct Machine *m, uint32_t rde) { switch (ModrmReg(rde)) { case 2: - SseUdqIb(m, rde, 6); + OpPsb(m, rde, MmxPsrlq, SsePsrlq); break; case 3: - SseUdqIb(m, rde, 7); + OpPsb(m, rde, MmxPsrldq, SsePsrldq); break; case 6: - SseUdqIb(m, rde, 8); + OpPsb(m, rde, MmxPsllq, SsePsllq); break; case 7: - SseUdqIb(m, rde, 9); + OpPsb(m, rde, MmxPslldq, SsePslldq); break; default: OpUd(m, rde); } } -static void OpSsePalignrMmx(struct Machine *m, uint32_t rde) { - char t[24]; - memcpy(t, GetModrmRegisterXmmPointerRead8(m, rde), 8); - memcpy(t + 8, XmmRexrReg(m, rde), 8); - bzero(t + 16, 8); - memcpy(XmmRexrReg(m, rde), t + MIN(m->xedd->op.uimm0, 16), 8); -} - void OpSsePalignr(struct Machine *m, uint32_t rde) { if (Osz(rde)) { - palignr(XmmRexrReg(m, rde), XmmRexrReg(m, rde), - GetModrmRegisterXmmPointerRead8(m, rde), m->xedd->op.uimm0); + SsePalignr(XmmRexrReg(m, rde), GetModrmRegisterXmmPointerRead16(m, rde), + m->xedd->op.uimm0); } else { - OpSsePalignrMmx(m, rde); + MmxPalignr(XmmRexrReg(m, rde), GetModrmRegisterXmmPointerRead8(m, rde), + m->xedd->op.uimm0); } } + +static void OpSse(struct Machine *m, uint32_t rde, + void MmxKernel(uint8_t[8], const uint8_t[8]), + void SseKernel(uint8_t[16], const uint8_t[16])) { + if (Osz(rde)) { + SseKernel(XmmRexrReg(m, rde), GetModrmRegisterXmmPointerRead16(m, rde)); + } else { + MmxKernel(XmmRexrReg(m, rde), GetModrmRegisterXmmPointerRead8(m, rde)); + } +} + +/* clang-format off */ +void OpSsePunpcklbw(struct Machine *m, uint32_t rde) { OpSse(m, rde, MmxPunpcklbw, SsePunpcklbw); } +void OpSsePunpcklwd(struct Machine *m, uint32_t rde) { OpSse(m, rde, MmxPunpcklwd, SsePunpcklwd); } +void OpSsePunpckldq(struct Machine *m, uint32_t rde) { OpSse(m, rde, MmxPunpckldq, SsePunpckldq); } +void OpSsePacksswb(struct Machine *m, uint32_t rde) { OpSse(m, rde, MmxPacksswb, SsePacksswb); } +void OpSsePcmpgtb(struct Machine *m, uint32_t rde) { OpSse(m, rde, MmxPcmpgtb, SsePcmpgtb); } +void OpSsePcmpgtw(struct Machine *m, uint32_t rde) { OpSse(m, rde, MmxPcmpgtw, SsePcmpgtw); } +void OpSsePcmpgtd(struct Machine *m, uint32_t rde) { OpSse(m, rde, MmxPcmpgtd, SsePcmpgtd); } +void OpSsePackuswb(struct Machine *m, uint32_t rde) { OpSse(m, rde, MmxPackuswb, SsePackuswb); } +void OpSsePunpckhbw(struct Machine *m, uint32_t rde) { OpSse(m, rde, MmxPunpckhbw, SsePunpckhbw); } +void OpSsePunpckhwd(struct Machine *m, uint32_t rde) { OpSse(m, rde, MmxPunpckhwd, SsePunpckhwd); } +void OpSsePunpckhdq(struct Machine *m, uint32_t rde) { OpSse(m, rde, MmxPunpckhdq, SsePunpckhdq); } +void OpSsePackssdw(struct Machine *m, uint32_t rde) { OpSse(m, rde, MmxPackssdw, SsePackssdw); } +void OpSsePunpcklqdq(struct Machine *m, uint32_t rde) { OpSse(m, rde, MmxPunpcklqdq, SsePunpcklqdq); } +void OpSsePunpckhqdq(struct Machine *m, uint32_t rde) { OpSse(m, rde, MmxPunpckhqdq, SsePunpckhqdq); } +void OpSsePcmpeqb(struct Machine *m, uint32_t rde) { OpSse(m, rde, MmxPcmpeqb, SsePcmpeqb); } +void OpSsePcmpeqw(struct Machine *m, uint32_t rde) { OpSse(m, rde, MmxPcmpeqw, SsePcmpeqw); } +void OpSsePcmpeqd(struct Machine *m, uint32_t rde) { OpSse(m, rde, MmxPcmpeqd, SsePcmpeqd); } +void OpSsePsrlwv(struct Machine *m, uint32_t rde) { OpSse(m, rde, MmxPsrlwv, SsePsrlwv); } +void OpSsePsrldv(struct Machine *m, uint32_t rde) { OpSse(m, rde, MmxPsrldv, SsePsrldv); } +void OpSsePsrlqv(struct Machine *m, uint32_t rde) { OpSse(m, rde, MmxPsrlqv, SsePsrlqv); } +void OpSsePaddq(struct Machine *m, uint32_t rde) { OpSse(m, rde, MmxPaddq, SsePaddq); } +void OpSsePmullw(struct Machine *m, uint32_t rde) { OpSse(m, rde, MmxPmullw, SsePmullw); } +void OpSsePsubusb(struct Machine *m, uint32_t rde) { OpSse(m, rde, MmxPsubusb, SsePsubusb); } +void OpSsePsubusw(struct Machine *m, uint32_t rde) { OpSse(m, rde, MmxPsubusw, SsePsubusw); } +void OpSsePminub(struct Machine *m, uint32_t rde) { OpSse(m, rde, MmxPminub, SsePminub); } +void OpSsePand(struct Machine *m, uint32_t rde) { OpSse(m, rde, MmxPand, SsePand); } +void OpSsePaddusb(struct Machine *m, uint32_t rde) { OpSse(m, rde, MmxPaddusb, SsePaddusb); } +void OpSsePaddusw(struct Machine *m, uint32_t rde) { OpSse(m, rde, MmxPaddusw, SsePaddusw); } +void OpSsePmaxub(struct Machine *m, uint32_t rde) { OpSse(m, rde, MmxPmaxub, SsePmaxub); } +void OpSsePandn(struct Machine *m, uint32_t rde) { OpSse(m, rde, MmxPandn, SsePandn); } +void OpSsePavgb(struct Machine *m, uint32_t rde) { OpSse(m, rde, MmxPavgb, SsePavgb); } +void OpSsePsrawv(struct Machine *m, uint32_t rde) { OpSse(m, rde, MmxPsrawv, SsePsrawv); } +void OpSsePsradv(struct Machine *m, uint32_t rde) { OpSse(m, rde, MmxPsradv, SsePsradv); } +void OpSsePavgw(struct Machine *m, uint32_t rde) { OpSse(m, rde, MmxPavgw, SsePavgw); } +void OpSsePmulhuw(struct Machine *m, uint32_t rde) { OpSse(m, rde, MmxPmulhuw, SsePmulhuw); } +void OpSsePmulhw(struct Machine *m, uint32_t rde) { OpSse(m, rde, MmxPmulhw, SsePmulhw); } +void OpSsePsubsb(struct Machine *m, uint32_t rde) { OpSse(m, rde, MmxPsubsb, SsePsubsb); } +void OpSsePsubsw(struct Machine *m, uint32_t rde) { OpSse(m, rde, MmxPsubsw, SsePsubsw); } +void OpSsePminsw(struct Machine *m, uint32_t rde) { OpSse(m, rde, MmxPminsw, SsePminsw); } +void OpSsePor(struct Machine *m, uint32_t rde) { OpSse(m, rde, MmxPor, SsePor); } +void OpSsePaddsb(struct Machine *m, uint32_t rde) { OpSse(m, rde, MmxPaddsb, SsePaddsb); } +void OpSsePaddsw(struct Machine *m, uint32_t rde) { OpSse(m, rde, MmxPaddsw, SsePaddsw); } +void OpSsePmaxsw(struct Machine *m, uint32_t rde) { OpSse(m, rde, MmxPmaxsw, SsePmaxsw); } +void OpSsePxor(struct Machine *m, uint32_t rde) { OpSse(m, rde, MmxPxor, SsePxor); } +void OpSsePsllwv(struct Machine *m, uint32_t rde) { OpSse(m, rde, MmxPsllwv, SsePsllwv); } +void OpSsePslldv(struct Machine *m, uint32_t rde) { OpSse(m, rde, MmxPslldv, SsePslldv); } +void OpSsePsllqv(struct Machine *m, uint32_t rde) { OpSse(m, rde, MmxPsllqv, SsePsllqv); } +void OpSsePmuludq(struct Machine *m, uint32_t rde) { OpSse(m, rde, MmxPmuludq, SsePmuludq); } +void OpSsePmaddwd(struct Machine *m, uint32_t rde) { OpSse(m, rde, MmxPmaddwd, SsePmaddwd); } +void OpSsePsadbw(struct Machine *m, uint32_t rde) { OpSse(m, rde, MmxPsadbw, SsePsadbw); } +void OpSsePsubb(struct Machine *m, uint32_t rde) { OpSse(m, rde, MmxPsubb, SsePsubb); } +void OpSsePsubw(struct Machine *m, uint32_t rde) { OpSse(m, rde, MmxPsubw, SsePsubw); } +void OpSsePsubd(struct Machine *m, uint32_t rde) { OpSse(m, rde, MmxPsubd, SsePsubd); } +void OpSsePsubq(struct Machine *m, uint32_t rde) { OpSse(m, rde, MmxPsubq, SsePsubq); } +void OpSsePaddb(struct Machine *m, uint32_t rde) { OpSse(m, rde, MmxPaddb, SsePaddb); } +void OpSsePaddw(struct Machine *m, uint32_t rde) { OpSse(m, rde, MmxPaddw, SsePaddw); } +void OpSsePaddd(struct Machine *m, uint32_t rde) { OpSse(m, rde, MmxPaddd, SsePaddd); } +void OpSsePshufb(struct Machine *m, uint32_t rde) { OpSse(m, rde, MmxPshufb, SsePshufb); } +void OpSsePhaddw(struct Machine *m, uint32_t rde) { OpSse(m, rde, MmxPhaddw, SsePhaddw); } +void OpSsePhaddd(struct Machine *m, uint32_t rde) { OpSse(m, rde, MmxPhaddd, SsePhaddd); } +void OpSsePhaddsw(struct Machine *m, uint32_t rde) { OpSse(m, rde, MmxPhaddsw, SsePhaddsw); } +void OpSsePmaddubsw(struct Machine *m, uint32_t rde) { OpSse(m, rde, MmxPmaddubsw, SsePmaddubsw); } +void OpSsePhsubw(struct Machine *m, uint32_t rde) { OpSse(m, rde, MmxPhsubw, SsePhsubw); } +void OpSsePhsubd(struct Machine *m, uint32_t rde) { OpSse(m, rde, MmxPhsubd, SsePhsubd); } +void OpSsePhsubsw(struct Machine *m, uint32_t rde) { OpSse(m, rde, MmxPhsubsw, SsePhsubsw); } +void OpSsePsignb(struct Machine *m, uint32_t rde) { OpSse(m, rde, MmxPsignb, SsePsignb); } +void OpSsePsignw(struct Machine *m, uint32_t rde) { OpSse(m, rde, MmxPsignw, SsePsignw); } +void OpSsePsignd(struct Machine *m, uint32_t rde) { OpSse(m, rde, MmxPsignd, SsePsignd); } +void OpSsePmulhrsw(struct Machine *m, uint32_t rde) { OpSse(m, rde, MmxPmulhrsw, SsePmulhrsw); } +void OpSsePabsb(struct Machine *m, uint32_t rde) { OpSse(m, rde, MmxPabsb, SsePabsb); } +void OpSsePabsw(struct Machine *m, uint32_t rde) { OpSse(m, rde, MmxPabsw, SsePabsw); } +void OpSsePabsd(struct Machine *m, uint32_t rde) { OpSse(m, rde, MmxPabsd, SsePabsd); } +void OpSsePmulld(struct Machine *m, uint32_t rde) { OpSse(m, rde, MmxPmulld, SsePmulld); } +/* clang-format on */ diff --git a/tool/build/lib/ssefloat.c b/tool/build/lib/ssefloat.c index 22935f222..aa4ee85de 100644 --- a/tool/build/lib/ssefloat.c +++ b/tool/build/lib/ssefloat.c @@ -17,22 +17,74 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/dce.h" -#include "libc/intrin/pshufd.h" -#include "libc/intrin/pshufhw.h" -#include "libc/intrin/pshuflw.h" -#include "libc/intrin/pshufw.h" -#include "libc/intrin/shufpd.h" -#include "libc/intrin/shufps.h" #include "libc/log/log.h" #include "libc/macros.internal.h" #include "libc/math.h" #include "libc/str/str.h" #include "tool/build/lib/endian.h" #include "tool/build/lib/flags.h" +#include "tool/build/lib/fpu.h" #include "tool/build/lib/modrm.h" +#include "tool/build/lib/pun.h" #include "tool/build/lib/ssefloat.h" #include "tool/build/lib/throw.h" +static void pshufw(int16_t b[4], const int16_t a[4], int m) { + int16_t t[4]; + t[0] = a[(m & 0003) >> 0]; + t[1] = a[(m & 0014) >> 2]; + t[2] = a[(m & 0060) >> 4]; + t[3] = a[(m & 0300) >> 6]; + b[0] = t[0]; + b[1] = t[1]; + b[2] = t[2]; + b[3] = t[3]; +} + +static void pshufd(int32_t b[4], const int32_t a[4], int m) { + int32_t t[4]; + t[0] = a[(m & 0003) >> 0]; + t[1] = a[(m & 0014) >> 2]; + t[2] = a[(m & 0060) >> 4]; + t[3] = a[(m & 0300) >> 6]; + b[0] = t[0]; + b[1] = t[1]; + b[2] = t[2]; + b[3] = t[3]; +} + +static void pshuflw(int16_t b[8], const int16_t a[8], int m) { + int16_t t[4]; + t[0] = a[(m & 0003) >> 0]; + t[1] = a[(m & 0014) >> 2]; + t[2] = a[(m & 0060) >> 4]; + t[3] = a[(m & 0300) >> 6]; + b[0] = t[0]; + b[1] = t[1]; + b[2] = t[2]; + b[3] = t[3]; + b[4] = a[4]; + b[5] = a[5]; + b[6] = a[6]; + b[7] = a[7]; +} + +static void pshufhw(int16_t b[8], const int16_t a[8], int m) { + int16_t t[4]; + t[0] = a[4 + ((m & 0003) >> 0)]; + t[1] = a[4 + ((m & 0014) >> 2)]; + t[2] = a[4 + ((m & 0060) >> 4)]; + t[3] = a[4 + ((m & 0300) >> 6)]; + b[0] = a[0]; + b[1] = a[1]; + b[2] = a[2]; + b[3] = a[3]; + b[4] = t[0]; + b[5] = t[1]; + b[6] = t[2]; + b[7] = t[3]; +} + void OpUnpcklpsd(struct Machine *m, uint32_t rde) { uint8_t *a, *b; a = XmmRexrReg(m, rde); @@ -83,37 +135,65 @@ void OpShuffle(struct Machine *m, uint32_t rde) { switch (Rep(rde) | Osz(rde)) { case 0: memcpy(q16, GetModrmRegisterXmmPointerRead8(m, rde), 8); - (pshufw)(q16, q16, m->xedd->op.uimm0); + pshufw(q16, q16, m->xedd->op.uimm0); memcpy(XmmRexrReg(m, rde), q16, 8); break; case 1: memcpy(x32, GetModrmRegisterXmmPointerRead16(m, rde), 16); - (pshufd)(x32, x32, m->xedd->op.uimm0); + pshufd(x32, x32, m->xedd->op.uimm0); memcpy(XmmRexrReg(m, rde), x32, 16); break; case 2: memcpy(x16, GetModrmRegisterXmmPointerRead16(m, rde), 16); - (pshuflw)(x16, x16, m->xedd->op.uimm0); + pshuflw(x16, x16, m->xedd->op.uimm0); memcpy(XmmRexrReg(m, rde), x16, 16); break; case 3: memcpy(x16, GetModrmRegisterXmmPointerRead16(m, rde), 16); - (pshufhw)(x16, x16, m->xedd->op.uimm0); + pshufhw(x16, x16, m->xedd->op.uimm0); memcpy(XmmRexrReg(m, rde), x16, 16); break; default: - unreachable; + for (;;) (void)0; } } static void Shufps(struct Machine *m, uint32_t rde) { - shufps((void *)XmmRexrReg(m, rde), (void *)XmmRexrReg(m, rde), - (void *)GetModrmRegisterXmmPointerRead16(m, rde), m->xedd->op.uimm0); + uint8_t *p; + union FloatPun x[4], y[4], z[4]; + p = GetModrmRegisterXmmPointerRead16(m, rde); + y[0].i = Read32(p + 0 * 4); + y[1].i = Read32(p + 1 * 4); + y[2].i = Read32(p + 2 * 4); + y[3].i = Read32(p + 3 * 4); + p = XmmRexrReg(m, rde); + x[0].i = Read32(p + 0 * 4); + x[1].i = Read32(p + 1 * 4); + x[2].i = Read32(p + 2 * 4); + x[3].i = Read32(p + 3 * 4); + z[0].f = y[(m->xedd->op.uimm0 & 0003) >> 0].f; + z[1].f = y[(m->xedd->op.uimm0 & 0014) >> 2].f; + z[2].f = x[(m->xedd->op.uimm0 & 0060) >> 4].f; + z[3].f = x[(m->xedd->op.uimm0 & 0300) >> 6].f; + Write32(p + 0 * 4, z[0].i); + Write32(p + 1 * 4, z[1].i); + Write32(p + 2 * 4, z[2].i); + Write32(p + 3 * 4, z[3].i); } static void Shufpd(struct Machine *m, uint32_t rde) { - shufpd((void *)XmmRexrReg(m, rde), (void *)XmmRexrReg(m, rde), - (void *)GetModrmRegisterXmmPointerRead16(m, rde), m->xedd->op.uimm0); + uint8_t *p; + union DoublePun x[2], y[2], z[2]; + p = GetModrmRegisterXmmPointerRead16(m, rde); + y[0].i = Read64(p + 0 * 4); + y[1].i = Read64(p + 1 * 4); + p = XmmRexrReg(m, rde); + x[0].i = Read64(p + 0 * 4); + x[1].i = Read64(p + 1 * 4); + z[0].f = y[(m->xedd->op.uimm0 & 0001) >> 0].f; + z[1].f = x[(m->xedd->op.uimm0 & 0002) >> 1].f; + Write64(p + 0 * 4, z[0].i); + Write64(p + 1 * 4, z[1].i); } void OpShufpsd(struct Machine *m, uint32_t rde) { @@ -125,84 +205,125 @@ void OpShufpsd(struct Machine *m, uint32_t rde) { } void OpSqrtpsd(struct Machine *m, uint32_t rde) { - long i; - float xf[4]; - double xd[2]; switch (Rep(rde) | Osz(rde)) { - case 0: - memcpy(xf, GetModrmRegisterXmmPointerRead16(m, rde), 16); - for (i = 0; i < 4; ++i) xf[i] = sqrtf(xf[i]); - memcpy(XmmRexrReg(m, rde), xf, 16); + case 0: { + int i; + uint8_t *p; + union FloatPun u[4]; + p = GetModrmRegisterXmmPointerRead16(m, rde); + u[0].i = Read32(p + 0 * 4); + u[1].i = Read32(p + 1 * 4); + u[2].i = Read32(p + 2 * 4); + u[3].i = Read32(p + 3 * 4); + for (i = 0; i < 4; ++i) u[i].f = sqrtf(u[i].f); + p = XmmRexrReg(m, rde); + Write32(p + 0 * 4, u[0].i); + Write32(p + 1 * 4, u[1].i); + Write32(p + 2 * 4, u[2].i); + Write32(p + 3 * 4, u[3].i); break; - case 1: - memcpy(xd, GetModrmRegisterXmmPointerRead16(m, rde), 16); - for (i = 0; i < 2; ++i) xd[i] = sqrt(xd[i]); - memcpy(XmmRexrReg(m, rde), xd, 16); + } + case 1: { + int i; + uint8_t *p; + union DoublePun u[2]; + p = GetModrmRegisterXmmPointerRead16(m, rde); + u[0].i = Read32(p + 0 * 8); + u[1].i = Read32(p + 1 * 8); + for (i = 0; i < 2; ++i) u[i].f = sqrt(u[i].f); + p = XmmRexrReg(m, rde); + Write32(p + 0 * 8, u[0].i); + Write32(p + 1 * 8, u[1].i); break; - case 2: - memcpy(xd, GetModrmRegisterXmmPointerRead8(m, rde), 8); - xd[0] = sqrt(xd[0]); - memcpy(XmmRexrReg(m, rde), xd, 8); + } + case 2: { + union DoublePun u; + u.i = Read64(GetModrmRegisterXmmPointerRead8(m, rde)); + u.f = sqrt(u.f); + Write64(XmmRexrReg(m, rde), u.i); break; - case 3: - memcpy(xf, GetModrmRegisterXmmPointerRead4(m, rde), 4); - xf[0] = sqrtf(xf[0]); - memcpy(XmmRexrReg(m, rde), xf, 4); + } + case 3: { + union FloatPun u; + u.i = Read32(GetModrmRegisterXmmPointerRead4(m, rde)); + u.f = sqrtf(u.f); + Write32(XmmRexrReg(m, rde), u.i); break; + } default: - unreachable; + for (;;) (void)0; } } void OpRsqrtps(struct Machine *m, uint32_t rde) { - float x[4]; - unsigned i; if (Rep(rde) != 3) { - memcpy(x, GetModrmRegisterXmmPointerRead16(m, rde), 16); - for (i = 0; i < 4; ++i) x[i] = 1.f / sqrtf(x[i]); - memcpy(XmmRexrReg(m, rde), x, 16); + int i; + uint8_t *p; + union FloatPun u[4]; + p = GetModrmRegisterXmmPointerRead16(m, rde); + u[0].i = Read32(p + 0 * 4); + u[1].i = Read32(p + 1 * 4); + u[2].i = Read32(p + 2 * 4); + u[3].i = Read32(p + 3 * 4); + for (i = 0; i < 4; ++i) u[i].f = 1.f / sqrtf(u[i].f); + p = XmmRexrReg(m, rde); + Write32(p + 0 * 4, u[0].i); + Write32(p + 1 * 4, u[1].i); + Write32(p + 2 * 4, u[2].i); + Write32(p + 3 * 4, u[3].i); } else { - memcpy(x, GetModrmRegisterXmmPointerRead4(m, rde), 4); - x[0] = 1.f / sqrtf(x[0]); - memcpy(XmmRexrReg(m, rde), x, 4); + union FloatPun u; + u.i = Read32(GetModrmRegisterXmmPointerRead4(m, rde)); + u.f = 1.f / sqrtf(u.f); + Write32(XmmRexrReg(m, rde), u.i); } } void OpRcpps(struct Machine *m, uint32_t rde) { - float x[4]; - unsigned i; if (Rep(rde) != 3) { - memcpy(x, GetModrmRegisterXmmPointerRead16(m, rde), 16); - for (i = 0; i < 4; ++i) x[i] = 1.f / x[i]; - memcpy(XmmRexrReg(m, rde), x, 16); + int i; + uint8_t *p; + union FloatPun u[4]; + p = GetModrmRegisterXmmPointerRead16(m, rde); + u[0].i = Read32(p + 0 * 4); + u[1].i = Read32(p + 1 * 4); + u[2].i = Read32(p + 2 * 4); + u[3].i = Read32(p + 3 * 4); + for (i = 0; i < 4; ++i) u[i].f = 1.f / u[i].f; + p = XmmRexrReg(m, rde); + Write32(p + 0 * 4, u[0].i); + Write32(p + 1 * 4, u[1].i); + Write32(p + 2 * 4, u[2].i); + Write32(p + 3 * 4, u[3].i); } else { - memcpy(x, GetModrmRegisterXmmPointerRead4(m, rde), 4); - x[0] = 1.f / x[0]; - memcpy(XmmRexrReg(m, rde), x, 4); + union FloatPun u; + u.i = Read32(GetModrmRegisterXmmPointerRead4(m, rde)); + u.f = 1.f / u.f; + Write32(XmmRexrReg(m, rde), u.i); } } void OpComissVsWs(struct Machine *m, uint32_t rde) { - float xf, yf; - double xd, yd; uint8_t zf, cf, pf, ie; if (!Osz(rde)) { - memcpy(&xf, XmmRexrReg(m, rde), 4); - memcpy(&yf, GetModrmRegisterXmmPointerRead4(m, rde), 4); - if (!isnan(xf) && !isnan(yf)) { - zf = xf == yf; - cf = xf < yf; + union FloatPun xf, yf; + xf.i = Read32(XmmRexrReg(m, rde)); + yf.i = Read32(GetModrmRegisterXmmPointerRead4(m, rde)); + if (!isnan(xf.f) && !isnan(yf.f)) { + zf = xf.f == yf.f; + cf = xf.f < yf.f; pf = false; ie = false; } else { zf = cf = pf = ie = true; } } else { - memcpy(&xd, XmmRexrReg(m, rde), 8); - memcpy(&yd, GetModrmRegisterXmmPointerRead8(m, rde), 8); - if (!isnan(xd) && !isnan(yd)) { - zf = xd == yd; - cf = xd < yd; + union DoublePun xd, yd; + xd.i = Read64(XmmRexrReg(m, rde)); + yd.i = Read64(GetModrmRegisterXmmPointerRead8(m, rde)); + if (!isnan(xd.f) && !isnan(yd.f)) { + zf = xd.f == yd.f; + cf = xd.f < yd.f; pf = false; ie = false; } else { @@ -214,11 +335,141 @@ void OpComissVsWs(struct Machine *m, uint32_t rde) { m->flags = SetFlag(m->flags, FLAGS_CF, cf); m->flags = SetFlag(m->flags, FLAGS_SF, false); m->flags = SetFlag(m->flags, FLAGS_OF, false); - if ((m->xedd->op.opcode & 1) && (m->sse.ie = ie) && !m->sse.im) { - HaltMachine(m, kMachineSimdException); + if (m->xedd->op.opcode & 1) { + m->mxcsr &= ~kMxcsrIe; + if (ie) { + m->mxcsr |= kMxcsrIe; + if (!(m->mxcsr & kMxcsrIm)) { + HaltMachine(m, kMachineSimdException); + } + } } } +static inline void OpPsd(struct Machine *m, uint32_t rde, + float fs(float x, float y), + double fd(double x, double y)) { + if (Rep(rde) == 2) { + union DoublePun x, y; + y.i = Read64(GetModrmRegisterXmmPointerRead8(m, rde)); + x.i = Read64(XmmRexrReg(m, rde)); + x.f = fd(x.f, y.f); + Write64(XmmRexrReg(m, rde), x.i); + } else if (Rep(rde) == 3) { + union FloatPun x, y; + y.i = Read32(GetModrmRegisterXmmPointerRead4(m, rde)); + x.i = Read32(XmmRexrReg(m, rde)); + x.f = fs(x.f, y.f); + Write32(XmmRexrReg(m, rde), x.i); + } else if (Osz(rde)) { + uint8_t *p; + union DoublePun x[2], y[2]; + p = GetModrmRegisterXmmPointerRead16(m, rde); + y[0].i = Read64(p + 0 * 8); + y[1].i = Read64(p + 1 * 8); + p = XmmRexrReg(m, rde); + x[0].i = Read64(p + 0 * 8); + x[1].i = Read64(p + 1 * 8); + x[0].f = fd(x[0].f, y[0].f); + x[1].f = fd(x[1].f, y[1].f); + Write64(p + 0 * 8, x[0].i); + Write64(p + 1 * 8, x[1].i); + } else { + uint8_t *p; + union FloatPun x[4], y[4]; + p = GetModrmRegisterXmmPointerRead16(m, rde); + y[0].i = Read32(p + 0 * 4); + y[1].i = Read32(p + 1 * 4); + y[2].i = Read32(p + 2 * 4); + y[3].i = Read32(p + 3 * 4); + p = XmmRexrReg(m, rde); + x[0].i = Read32(p + 0 * 4); + x[1].i = Read32(p + 1 * 4); + x[2].i = Read32(p + 2 * 4); + x[3].i = Read32(p + 3 * 4); + x[0].f = fs(x[0].f, y[0].f); + x[1].f = fs(x[1].f, y[1].f); + x[2].f = fs(x[2].f, y[2].f); + x[3].f = fs(x[3].f, y[3].f); + Write32(p + 0 * 4, x[0].i); + Write32(p + 1 * 4, x[1].i); + Write32(p + 2 * 4, x[2].i); + Write32(p + 3 * 4, x[3].i); + } +} + +static inline float Adds(float x, float y) { + return x + y; +} + +static inline double Addd(double x, double y) { + return x + y; +} + +void OpAddpsd(struct Machine *m, uint32_t rde) { + OpPsd(m, rde, Adds, Addd); +} + +static inline float Subs(float x, float y) { + return x - y; +} + +static inline double Subd(double x, double y) { + return x - y; +} + +void OpSubpsd(struct Machine *m, uint32_t rde) { + OpPsd(m, rde, Subs, Subd); +} + +static inline float Muls(float x, float y) { + return x * y; +} + +static inline double Muld(double x, double y) { + return x * y; +} + +void OpMulpsd(struct Machine *m, uint32_t rde) { + OpPsd(m, rde, Muls, Muld); +} + +static inline float Divs(float x, float y) { + return x / y; +} + +static inline double Divd(double x, double y) { + return x / y; +} + +void OpDivpsd(struct Machine *m, uint32_t rde) { + OpPsd(m, rde, Divs, Divd); +} + +static inline float Mins(float x, float y) { + return MIN(x, y); +} + +static inline double Mind(double x, double y) { + return MIN(x, y); +} + +void OpMinpsd(struct Machine *m, uint32_t rde) { + OpPsd(m, rde, Mins, Mind); +} + +static inline float Maxs(float x, float y) { + return MAX(x, y); +} + +static inline double Maxd(double x, double y) { + return MAX(x, y); +} + +void OpMaxpsd(struct Machine *m, uint32_t rde) { + OpPsd(m, rde, Maxs, Maxd); +} + static int Cmps(int imm, float x, float y) { switch (imm) { case 0: @@ -243,7 +494,6 @@ static int Cmps(int imm, float x, float y) { } static int32_t Cmpd(int imm, double x, double y) { - long i; switch (imm) { case 0: return x == y ? -1 : 0; @@ -266,228 +516,54 @@ static int32_t Cmpd(int imm, double x, double y) { } } -void OpAddpsd(struct Machine *m, uint32_t rde) { - if (Rep(rde) == 2) { - double x, y; - memcpy(&y, GetModrmRegisterXmmPointerRead8(m, rde), 8); - memcpy(&x, XmmRexrReg(m, rde), 8); - x += y; - memcpy(XmmRexrReg(m, rde), &x, 8); - } else if (Rep(rde) == 3) { - float x, y; - memcpy(&y, GetModrmRegisterXmmPointerRead4(m, rde), 4); - memcpy(&x, XmmRexrReg(m, rde), 4); - x += y; - memcpy(XmmRexrReg(m, rde), &x, 4); - } else if (Osz(rde)) { - double x[2], y[2]; - memcpy(y, GetModrmRegisterXmmPointerRead16(m, rde), 16); - memcpy(x, XmmRexrReg(m, rde), 16); - x[0] += y[0]; - x[1] += y[1]; - memcpy(XmmRexrReg(m, rde), x, 16); - } else { - float x[4], y[4]; - memcpy(y, GetModrmRegisterXmmPointerRead16(m, rde), 16); - memcpy(x, XmmRexrReg(m, rde), 16); - x[0] += y[0]; - x[1] += y[1]; - x[2] += y[2]; - x[3] += y[3]; - memcpy(XmmRexrReg(m, rde), x, 16); - } -} - -void OpMulpsd(struct Machine *m, uint32_t rde) { - if (Rep(rde) == 2) { - double x, y; - memcpy(&y, GetModrmRegisterXmmPointerRead8(m, rde), 8); - memcpy(&x, XmmRexrReg(m, rde), 8); - x *= y; - memcpy(XmmRexrReg(m, rde), &x, 8); - } else if (Rep(rde) == 3) { - float x, y; - memcpy(&y, GetModrmRegisterXmmPointerRead4(m, rde), 4); - memcpy(&x, XmmRexrReg(m, rde), 4); - x *= y; - memcpy(XmmRexrReg(m, rde), &x, 4); - } else if (Osz(rde)) { - double x[2], y[2]; - memcpy(y, GetModrmRegisterXmmPointerRead16(m, rde), 16); - memcpy(x, XmmRexrReg(m, rde), 16); - x[0] *= y[0]; - x[1] *= y[1]; - memcpy(XmmRexrReg(m, rde), x, 16); - } else { - float x[4], y[4]; - memcpy(y, GetModrmRegisterXmmPointerRead16(m, rde), 16); - memcpy(x, XmmRexrReg(m, rde), 16); - x[0] *= y[0]; - x[1] *= y[1]; - x[2] *= y[2]; - x[3] *= y[3]; - memcpy(XmmRexrReg(m, rde), x, 16); - } -} - -void OpSubpsd(struct Machine *m, uint32_t rde) { - if (Rep(rde) == 2) { - double x, y; - memcpy(&y, GetModrmRegisterXmmPointerRead8(m, rde), 8); - memcpy(&x, XmmRexrReg(m, rde), 8); - x -= y; - memcpy(XmmRexrReg(m, rde), &x, 8); - } else if (Rep(rde) == 3) { - float x, y; - memcpy(&y, GetModrmRegisterXmmPointerRead4(m, rde), 4); - memcpy(&x, XmmRexrReg(m, rde), 4); - x -= y; - memcpy(XmmRexrReg(m, rde), &x, 4); - } else if (Osz(rde)) { - double x[2], y[2]; - memcpy(y, GetModrmRegisterXmmPointerRead16(m, rde), 16); - memcpy(x, XmmRexrReg(m, rde), 16); - x[0] -= y[0]; - x[1] -= y[1]; - memcpy(XmmRexrReg(m, rde), x, 16); - } else { - float x[4], y[4]; - memcpy(y, GetModrmRegisterXmmPointerRead16(m, rde), 16); - memcpy(x, XmmRexrReg(m, rde), 16); - x[0] -= y[0]; - x[1] -= y[1]; - x[2] -= y[2]; - x[3] -= y[3]; - memcpy(XmmRexrReg(m, rde), x, 16); - } -} - -void OpDivpsd(struct Machine *m, uint32_t rde) { - if (Rep(rde) == 2) { - double x, y; - memcpy(&y, GetModrmRegisterXmmPointerRead8(m, rde), 8); - memcpy(&x, XmmRexrReg(m, rde), 8); - x /= y; - memcpy(XmmRexrReg(m, rde), &x, 8); - } else if (Rep(rde) == 3) { - float x, y; - memcpy(&y, GetModrmRegisterXmmPointerRead4(m, rde), 4); - memcpy(&x, XmmRexrReg(m, rde), 4); - x /= y; - memcpy(XmmRexrReg(m, rde), &x, 4); - } else if (Osz(rde)) { - double x[2], y[2]; - memcpy(y, GetModrmRegisterXmmPointerRead16(m, rde), 16); - memcpy(x, XmmRexrReg(m, rde), 16); - x[0] /= y[0]; - x[1] /= y[1]; - memcpy(XmmRexrReg(m, rde), x, 16); - } else { - float x[4], y[4]; - memcpy(y, GetModrmRegisterXmmPointerRead16(m, rde), 16); - memcpy(x, XmmRexrReg(m, rde), 16); - x[0] /= y[0]; - x[1] /= y[1]; - x[2] /= y[2]; - x[3] /= y[3]; - memcpy(XmmRexrReg(m, rde), x, 16); - } -} - -void OpMinpsd(struct Machine *m, uint32_t rde) { - if (Rep(rde) == 2) { - double x, y; - memcpy(&y, GetModrmRegisterXmmPointerRead8(m, rde), 8); - memcpy(&x, XmmRexrReg(m, rde), 8); - x = MIN(x, y); - memcpy(XmmRexrReg(m, rde), &x, 8); - } else if (Rep(rde) == 3) { - float x, y; - memcpy(&y, GetModrmRegisterXmmPointerRead4(m, rde), 4); - memcpy(&x, XmmRexrReg(m, rde), 4); - x = MIN(x, y); - memcpy(XmmRexrReg(m, rde), &x, 4); - } else if (Osz(rde)) { - double x[2], y[2]; - memcpy(y, GetModrmRegisterXmmPointerRead16(m, rde), 16); - memcpy(x, XmmRexrReg(m, rde), 16); - x[0] = MIN(x[0], y[0]); - x[1] = MIN(x[1], y[1]); - memcpy(XmmRexrReg(m, rde), x, 16); - } else { - float x[4], y[4]; - memcpy(y, GetModrmRegisterXmmPointerRead16(m, rde), 16); - memcpy(x, XmmRexrReg(m, rde), 16); - x[0] = MIN(x[0], y[0]); - x[1] = MIN(x[1], y[1]); - x[2] = MIN(x[2], y[2]); - x[3] = MIN(x[3], y[3]); - memcpy(XmmRexrReg(m, rde), x, 16); - } -} - -void OpMaxpsd(struct Machine *m, uint32_t rde) { - if (Rep(rde) == 2) { - double x, y; - memcpy(&y, GetModrmRegisterXmmPointerRead8(m, rde), 8); - memcpy(&x, XmmRexrReg(m, rde), 8); - x = MAX(x, y); - memcpy(XmmRexrReg(m, rde), &x, 8); - } else if (Rep(rde) == 3) { - float x, y; - memcpy(&y, GetModrmRegisterXmmPointerRead4(m, rde), 4); - memcpy(&x, XmmRexrReg(m, rde), 4); - x = MAX(x, y); - memcpy(XmmRexrReg(m, rde), &x, 4); - } else if (Osz(rde)) { - double x[2], y[2]; - memcpy(y, GetModrmRegisterXmmPointerRead16(m, rde), 16); - memcpy(x, XmmRexrReg(m, rde), 16); - x[0] = MAX(x[0], y[0]); - x[1] = MAX(x[1], y[1]); - memcpy(XmmRexrReg(m, rde), x, 16); - } else { - float x[4], y[4]; - memcpy(y, GetModrmRegisterXmmPointerRead16(m, rde), 16); - memcpy(x, XmmRexrReg(m, rde), 16); - x[0] = MAX(x[0], y[0]); - x[1] = MAX(x[1], y[1]); - x[2] = MAX(x[2], y[2]); - x[3] = MAX(x[3], y[3]); - memcpy(XmmRexrReg(m, rde), x, 16); - } -} - void OpCmppsd(struct Machine *m, uint32_t rde) { int imm = m->xedd->op.uimm0; if (Rep(rde) == 2) { - double x, y; - memcpy(&y, GetModrmRegisterXmmPointerRead8(m, rde), 8); - memcpy(&x, XmmRexrReg(m, rde), 8); - x = Cmpd(imm, x, y); - memcpy(XmmRexrReg(m, rde), &x, 8); + union DoublePun x, y; + y.i = Read64(GetModrmRegisterXmmPointerRead8(m, rde)); + x.i = Read64(XmmRexrReg(m, rde)); + x.f = Cmpd(imm, x.f, y.f); + Write64(XmmRexrReg(m, rde), x.i); } else if (Rep(rde) == 3) { - float x, y; - memcpy(&y, GetModrmRegisterXmmPointerRead4(m, rde), 4); - memcpy(&x, XmmRexrReg(m, rde), 4); - x = Cmps(imm, x, y); - memcpy(XmmRexrReg(m, rde), &x, 4); + union FloatPun x, y; + y.i = Read32(GetModrmRegisterXmmPointerRead4(m, rde)); + x.i = Read32(XmmRexrReg(m, rde)); + x.f = Cmps(imm, x.f, y.f); + Write32(XmmRexrReg(m, rde), x.i); } else if (Osz(rde)) { - double x[2], y[2]; - memcpy(y, GetModrmRegisterXmmPointerRead16(m, rde), 16); - memcpy(x, XmmRexrReg(m, rde), 16); - x[0] = Cmpd(imm, x[0], y[0]); - x[1] = Cmpd(imm, x[1], y[1]); - memcpy(XmmRexrReg(m, rde), x, 16); + uint8_t *p; + union DoublePun x[2], y[2]; + p = GetModrmRegisterXmmPointerRead16(m, rde); + y[0].i = Read64(p + 0 * 8); + y[1].i = Read64(p + 1 * 8); + p = XmmRexrReg(m, rde); + x[0].i = Read64(p + 0 * 8); + x[1].i = Read64(p + 1 * 8); + x[0].f = Cmpd(imm, x[0].f, y[0].f); + x[1].f = Cmpd(imm, x[1].f, y[1].f); + Write64(p + 0 * 8, x[0].i); + Write64(p + 1 * 8, x[1].i); } else { - float x[4], y[4]; - memcpy(y, GetModrmRegisterXmmPointerRead16(m, rde), 16); - memcpy(x, XmmRexrReg(m, rde), 16); - x[0] = Cmps(imm, x[0], y[0]); - x[1] = Cmps(imm, x[1], y[1]); - x[2] = Cmps(imm, x[2], y[2]); - x[3] = Cmps(imm, x[3], y[3]); - memcpy(XmmRexrReg(m, rde), x, 16); + uint8_t *p; + union FloatPun x[4], y[4]; + p = GetModrmRegisterXmmPointerRead16(m, rde); + y[0].i = Read32(p + 0 * 4); + y[1].i = Read32(p + 1 * 4); + y[2].i = Read32(p + 2 * 4); + y[3].i = Read32(p + 3 * 4); + p = XmmRexrReg(m, rde); + x[0].i = Read32(p + 0 * 4); + x[1].i = Read32(p + 1 * 4); + x[2].i = Read32(p + 2 * 4); + x[3].i = Read32(p + 3 * 4); + x[0].f = Cmps(imm, x[0].f, y[0].f); + x[1].f = Cmps(imm, x[1].f, y[1].f); + x[2].f = Cmps(imm, x[2].f, y[2].f); + x[3].f = Cmps(imm, x[3].f, y[3].f); + Write32(p + 0 * 4, x[0].i); + Write32(p + 1 * 4, x[1].i); + Write32(p + 2 * 4, x[2].i); + Write32(p + 3 * 4, x[3].i); } } @@ -528,66 +604,117 @@ void OpXorpsd(struct Machine *m, uint32_t rde) { } void OpHaddpsd(struct Machine *m, uint32_t rde) { + uint8_t *p; if (Rep(rde) == 2) { - float x[4], y[4], z[4]; - memcpy(x, XmmRexrReg(m, rde), 16); - memcpy(y, GetModrmRegisterXmmPointerRead16(m, rde), 16); - z[0] = x[0] + x[1]; - z[1] = x[2] + x[3]; - z[2] = y[0] + y[1]; - z[3] = y[2] + y[3]; - memcpy(XmmRexrReg(m, rde), x, 16); + union FloatPun x[4], y[4], z[4]; + p = GetModrmRegisterXmmPointerRead16(m, rde); + y[0].i = Read32(p + 0 * 4); + y[1].i = Read32(p + 1 * 4); + y[2].i = Read32(p + 2 * 4); + y[3].i = Read32(p + 3 * 4); + p = XmmRexrReg(m, rde); + x[0].i = Read32(p + 0 * 4); + x[1].i = Read32(p + 1 * 4); + x[2].i = Read32(p + 2 * 4); + x[3].i = Read32(p + 3 * 4); + z[0].f = x[0].f + x[1].f; + z[1].f = x[2].f + x[3].f; + z[2].f = y[0].f + y[1].f; + z[3].f = y[2].f + y[3].f; + Write32(p + 0 * 4, z[0].i); + Write32(p + 1 * 4, z[1].i); + Write32(p + 2 * 4, z[2].i); + Write32(p + 3 * 4, z[3].i); } else if (Osz(rde)) { - double x[2], y[2], z[2]; - memcpy(x, XmmRexrReg(m, rde), 16); - memcpy(y, GetModrmRegisterXmmPointerRead16(m, rde), 16); - z[0] = x[0] + x[1]; - z[1] = y[0] + y[1]; - memcpy(XmmRexrReg(m, rde), z, 16); + union DoublePun x[2], y[2], z[2]; + p = GetModrmRegisterXmmPointerRead16(m, rde); + y[0].i = Read64(p + 0 * 8); + y[1].i = Read64(p + 1 * 8); + p = XmmRexrReg(m, rde); + x[0].i = Read64(p + 0 * 8); + x[1].i = Read64(p + 1 * 8); + z[0].f = x[0].f + x[1].f; + z[1].f = y[0].f + y[1].f; + Write64(p + 0 * 8, z[0].i); + Write64(p + 1 * 8, z[1].i); } else { OpUd(m, rde); } } void OpHsubpsd(struct Machine *m, uint32_t rde) { + uint8_t *p; if (Rep(rde) == 2) { - float x[4], y[4], z[4]; - memcpy(x, XmmRexrReg(m, rde), 16); - memcpy(y, GetModrmRegisterXmmPointerRead16(m, rde), 16); - z[0] = x[0] - x[1]; - z[1] = x[2] - x[3]; - z[2] = y[0] - y[1]; - z[3] = y[2] - y[3]; - memcpy(XmmRexrReg(m, rde), x, 16); + union FloatPun x[4], y[4], z[4]; + p = GetModrmRegisterXmmPointerRead16(m, rde); + y[0].i = Read32(p + 0 * 4); + y[1].i = Read32(p + 1 * 4); + y[2].i = Read32(p + 2 * 4); + y[3].i = Read32(p + 3 * 4); + p = XmmRexrReg(m, rde); + x[0].i = Read32(p + 0 * 4); + x[1].i = Read32(p + 1 * 4); + x[2].i = Read32(p + 2 * 4); + x[3].i = Read32(p + 3 * 4); + z[0].f = x[0].f - x[1].f; + z[1].f = x[2].f - x[3].f; + z[2].f = y[0].f - y[1].f; + z[3].f = y[2].f - y[3].f; + Write32(p + 0 * 4, z[0].i); + Write32(p + 1 * 4, z[1].i); + Write32(p + 2 * 4, z[2].i); + Write32(p + 3 * 4, z[3].i); } else if (Osz(rde)) { - double x[2], y[2], z[2]; - memcpy(x, XmmRexrReg(m, rde), 16); - memcpy(y, GetModrmRegisterXmmPointerRead16(m, rde), 16); - z[0] = x[0] - x[1]; - z[1] = y[0] - y[1]; - memcpy(XmmRexrReg(m, rde), z, 16); + union DoublePun x[2], y[2], z[2]; + p = GetModrmRegisterXmmPointerRead16(m, rde); + y[0].i = Read64(p + 0 * 8); + y[1].i = Read64(p + 1 * 8); + p = XmmRexrReg(m, rde); + x[0].i = Read64(p + 0 * 8); + x[1].i = Read64(p + 1 * 8); + z[0].f = x[0].f - x[1].f; + z[1].f = y[0].f - y[1].f; + Write64(p + 0 * 8, z[0].i); + Write64(p + 1 * 8, z[1].i); } else { OpUd(m, rde); } } void OpAddsubpsd(struct Machine *m, uint32_t rde) { + uint8_t *p; if (Rep(rde) == 2) { - float x[4], y[4], z[4]; - memcpy(x, XmmRexrReg(m, rde), 16); - memcpy(y, GetModrmRegisterXmmPointerRead16(m, rde), 16); - z[0] = x[0] - y[0]; - z[1] = x[1] + y[1]; - z[2] = x[2] - y[2]; - z[3] = x[3] + y[3]; - memcpy(XmmRexrReg(m, rde), x, 16); + union FloatPun x[4], y[4], z[4]; + p = GetModrmRegisterXmmPointerRead16(m, rde); + y[0].i = Read32(p + 0 * 4); + y[1].i = Read32(p + 1 * 4); + y[2].i = Read32(p + 2 * 4); + y[3].i = Read32(p + 3 * 4); + p = XmmRexrReg(m, rde); + x[0].i = Read32(p + 0 * 4); + x[1].i = Read32(p + 1 * 4); + x[2].i = Read32(p + 2 * 4); + x[3].i = Read32(p + 3 * 4); + z[0].f = x[0].f - y[0].f; + z[1].f = x[1].f + y[1].f; + z[2].f = x[2].f - y[2].f; + z[3].f = x[3].f + y[3].f; + Write32(p + 0 * 4, z[0].i); + Write32(p + 1 * 4, z[1].i); + Write32(p + 2 * 4, z[2].i); + Write32(p + 3 * 4, z[3].i); } else if (Osz(rde)) { - double x[2], y[2], z[2]; - memcpy(x, XmmRexrReg(m, rde), 16); - memcpy(y, GetModrmRegisterXmmPointerRead16(m, rde), 16); - z[0] = x[0] - y[0]; - z[1] = x[1] + y[1]; - memcpy(XmmRexrReg(m, rde), z, 16); + union DoublePun x[2], y[2], z[2]; + p = GetModrmRegisterXmmPointerRead16(m, rde); + y[0].i = Read64(p + 0 * 8); + y[1].i = Read64(p + 1 * 8); + p = XmmRexrReg(m, rde); + x[0].i = Read64(p + 0 * 8); + x[1].i = Read64(p + 1 * 8); + z[0].f = x[0].f - y[0].f; + z[1].f = x[1].f + y[1].f; + Write64(p + 0 * 8, z[0].i); + Write64(p + 1 * 8, z[1].i); } else { OpUd(m, rde); } diff --git a/tool/build/lib/syscall.c b/tool/build/lib/syscall.c index c9d1dbb63..d1a78e5b6 100644 --- a/tool/build/lib/syscall.c +++ b/tool/build/lib/syscall.c @@ -19,6 +19,7 @@ #include "libc/calls/calls.h" #include "libc/calls/internal.h" #include "libc/calls/ioctl.h" +#include "libc/calls/sig.internal.h" #include "libc/calls/struct/dirent.h" #include "libc/calls/struct/iovec.h" #include "libc/calls/struct/rusage.h" @@ -31,6 +32,7 @@ #include "libc/calls/struct/tms.h" #include "libc/calls/struct/utsname.h" #include "libc/calls/struct/winsize.h" +#include "libc/calls/weirdtypes.h" #include "libc/errno.h" #include "libc/fmt/fmt.h" #include "libc/log/check.h" @@ -56,10 +58,12 @@ #include "libc/sysv/consts/msync.h" #include "libc/sysv/consts/o.h" #include "libc/sysv/consts/ok.h" +#include "libc/sysv/consts/poll.h" #include "libc/sysv/consts/pr.h" #include "libc/sysv/consts/prot.h" #include "libc/sysv/consts/rusage.h" #include "libc/sysv/consts/sa.h" +#include "libc/sysv/consts/sicode.h" #include "libc/sysv/consts/sig.h" #include "libc/sysv/consts/so.h" #include "libc/sysv/consts/sock.h" @@ -72,19 +76,39 @@ #include "libc/time/struct/timezone.h" #include "libc/time/time.h" #include "libc/x/x.h" +#include "third_party/mbedtls/endian.h" +#include "tool/build/lib/bits.h" #include "tool/build/lib/case.h" #include "tool/build/lib/endian.h" #include "tool/build/lib/iovs.h" #include "tool/build/lib/machine.h" #include "tool/build/lib/memory.h" #include "tool/build/lib/pml4t.h" +#include "tool/build/lib/signal.h" #include "tool/build/lib/syscall.h" #include "tool/build/lib/throw.h" +#include "tool/build/lib/xlat.h" #include "tool/build/lib/xlaterrno.h" -#define SA_RESTORER 0x04000000 +#define TIOCGWINSZ_LINUX 0x5413 +#define TCGETS_LINUX 0x5401 +#define TCSETS_LINUX 0x5402 +#define TCSETSW_LINUX 0x5403 +#define TCSETSF_LINUX 0x5404 +#define ARCH_SET_GS_LINUX 0x1001 +#define ARCH_SET_FS_LINUX 0x1002 +#define ARCH_GET_FS_LINUX 0x1003 +#define ARCH_GET_GS_LINUX 0x1004 +#define SOCK_CLOEXEC_LINUX 0x080000 +#define O_CLOEXEC_LINUX 0x080000 +#define SA_RESTORER 0x04000000 +#define POLLIN_LINUX 0x01 +#define POLLPRI_LINUX 0x02 +#define POLLOUT_LINUX 0x04 +#define POLLERR_LINUX 0x08 +#define POLLHUP_LINUX 0x10 +#define POLLNVAL_LINUX 0x20 -#define AT_FDCWD_LINUX -100 #define TIOCGWINSZ_LINUX 0x5413 #define TCGETS_LINUX 0x5401 #define TCSETS_LINUX 0x5402 @@ -111,321 +135,15 @@ const struct MachineFdCb kMachineFdCbHost = { .ioctl = (void *)ioctl, }; -static int XlatSignal(int sig) { - switch (sig) { - XLAT(1, SIGHUP); - XLAT(2, SIGINT); - XLAT(3, SIGQUIT); - XLAT(4, SIGILL); - XLAT(5, SIGTRAP); - XLAT(6, SIGABRT); - XLAT(7, SIGBUS); - XLAT(8, SIGFPE); - XLAT(9, SIGKILL); - XLAT(10, SIGUSR1); - XLAT(11, SIGSEGV); - XLAT(13, SIGPIPE); - XLAT(14, SIGALRM); - XLAT(15, SIGTERM); - XLAT(21, SIGTTIN); - XLAT(22, SIGTTOU); - XLAT(24, SIGXCPU); - XLAT(25, SIGXFSZ); - XLAT(26, SIGVTALRM); - XLAT(27, SIGPROF); - XLAT(28, SIGWINCH); - XLAT(17, SIGCHLD); - XLAT(18, SIGCONT); - XLAT(29, SIGIO); - XLAT(19, SIGSTOP); - XLAT(31, SIGSYS); - XLAT(20, SIGTSTP); - XLAT(23, SIGURG); - XLAT(12, SIGUSR2); - XLAT(0x2000, SIGSTKSZ); - XLAT(30, SIGPWR); - XLAT(0x10, SIGSTKFLT); - default: - return einval(); - } -} - -static int XlatSig(int x) { - switch (x) { - XLAT(0, SIG_BLOCK); - XLAT(1, SIG_UNBLOCK); - XLAT(2, SIG_SETMASK); - default: - return einval(); - } -} - -static int XlatSocketFamily(int x) { - switch (x) { - XLAT(0, AF_INET); - XLAT(2, AF_INET); - default: - return epfnosupport(); - } -} - -static int XlatSocketType(int x) { - switch (x) { - XLAT(1, SOCK_STREAM); - XLAT(2, SOCK_DGRAM); - default: - return einval(); - } -} - -static int XlatSocketProtocol(int x) { - switch (x) { - XLAT(6, IPPROTO_TCP); - XLAT(17, IPPROTO_UDP); - default: - return einval(); - } -} - -static unsigned XlatSocketFlags(int flags) { - unsigned res = 0; - if (flags & 0x080000) res |= SOCK_CLOEXEC; - if (flags & 0x000800) res |= SOCK_NONBLOCK; - return res; -} - -static int XlatSocketLevel(int x) { - switch (x) { - XLAT(0, SOL_IP); - XLAT(1, SOL_SOCKET); - XLAT(6, SOL_TCP); - XLAT(17, SOL_UDP); - default: - return einval(); - } -} - -static int XlatSocketOptname(int x) { - switch (x) { - XLAT(2, SO_REUSEADDR); - XLAT(15, SO_REUSEPORT); - XLAT(9, SO_KEEPALIVE); - XLAT(5, SO_DONTROUTE); - XLAT(7, SO_SNDBUF); - XLAT(8, SO_RCVBUF); - XLAT(1, TCP_NODELAY); - XLAT(12, TCP_QUICKACK); - XLAT(13, SO_LINGER); - XLAT(23, TCP_FASTOPEN); - XLAT(30, TCP_FASTOPEN_CONNECT); - default: - return einval(); - } -} - -static int XlatMapFlags(int x) { - unsigned res = 0; - if (x & 1) res |= MAP_SHARED; - if (x & 2) res |= MAP_PRIVATE; - if (x & 16) res |= MAP_FIXED; - if (x & 32) res |= MAP_ANONYMOUS; - if (x & 256) res |= MAP_GROWSDOWN; - return res; -} - -static int XlatAccess(int x) { - unsigned res = F_OK; - if (x & 1) res |= X_OK; - if (x & 2) res |= W_OK; - if (x & 4) res |= R_OK; - return res; -} - -static int XlatSigaction(int x) { - unsigned res = 0; - if (x & 0x00000001) res |= SA_NOCLDSTOP; - if (x & 0x00000002) res |= SA_NOCLDWAIT; - if (x & 0x00000004) res |= SA_SIGINFO; - if (x & 0x04000000) res |= SA_RESTORER; - if (x & 0x08000000) res |= SA_ONSTACK; - if (x & 0x10000000) res |= SA_RESTART; - if (x & 0x40000000) res |= SA_NODEFER; - if (x & 0x40000000) res |= SA_NOMASK; - if (x & 0x80000000) res |= SA_RESETHAND; - if (x & 0x80000000) res |= SA_ONESHOT; - return res; -} - -static int XlatSo(int x) { - switch (x) { - XLAT(-1, SO_EXCLUSIVEADDRUSE); - XLAT(1, SO_DEBUG); - XLAT(2, SO_REUSEADDR); - XLAT(3, SO_TYPE); - XLAT(4, SO_ERROR); - XLAT(5, SO_DONTROUTE); - XLAT(6, SO_BROADCAST); - XLAT(7, SO_SNDBUF); - XLAT(8, SO_RCVBUF); - XLAT(9, SO_KEEPALIVE); - XLAT(10, SO_OOBINLINE); - XLAT(13, SO_LINGER); - XLAT(15, SO_REUSEPORT); - XLAT(17, SO_PEERCRED); - XLAT(18, SO_RCVLOWAT); - XLAT(19, SO_SNDLOWAT); - XLAT(20, SO_RCVTIMEO); - XLAT(21, SO_SNDTIMEO); - XLAT(29, SO_TIMESTAMP); - XLAT(30, SO_ACCEPTCONN); - XLAT(38, SO_PROTOCOL); - XLAT(39, SO_DOMAIN); - XLAT(47, SO_MAX_PACING_RATE); - default: - return x; - } -} - -static int XlatClock(int x) { - switch (x) { - XLAT(0, CLOCK_REALTIME); - XLAT(4, CLOCK_MONOTONIC); - default: - return x; - } -} - -static int XlatTcp(int x) { - switch (x) { - XLAT(1, TCP_NODELAY); - XLAT(2, TCP_MAXSEG); - XLAT(4, TCP_KEEPIDLE); - XLAT(5, TCP_KEEPINTVL); - XLAT(6, TCP_KEEPCNT); - XLAT(23, TCP_FASTOPEN); - default: - return x; - } -} - -static int XlatFd(struct Machine *m, int fd) { +static int GetFd(struct Machine *m, int fd) { if (!(0 <= fd && fd < m->fds.i)) return ebadf(); if (!m->fds.p[fd].cb) return ebadf(); return m->fds.p[fd].fd; } -static int XlatAfd(struct Machine *m, int fd) { - if (fd == AT_FDCWD_LINUX) return AT_FDCWD; - return XlatFd(m, fd); -} - -static int XlatAtf(int x) { - unsigned res = 0; - if (x & 0x0100) res |= AT_SYMLINK_NOFOLLOW; - if (x & 0x0200) res |= AT_REMOVEDIR; - if (x & 0x0400) res |= AT_SYMLINK_FOLLOW; - if (x & 0x1000) res |= AT_EMPTY_PATH; - return res; -} - -static int XlatMsyncFlags(int x) { - unsigned res = 0; - if (x & 1) res |= MS_ASYNC; - if (x & 2) res |= MS_INVALIDATE; - if (x & 4) res |= MS_SYNC; - return res; -} - -static unsigned XlatOpenMode(unsigned flags) { - switch (flags & 3) { - case 0: - return O_RDONLY; - case 1: - return O_WRONLY; - case 2: - return O_RDWR; - default: - unreachable; - } -} - -static unsigned XlatOpenFlags(unsigned flags) { - unsigned res = 0; - res = XlatOpenMode(flags); - if (flags & 0x80000) res |= O_CLOEXEC; - if (flags & 0x400) res |= O_APPEND; - if (flags & 0x40) res |= O_CREAT; - if (flags & 0x80) res |= O_EXCL; - if (flags & 0x200) res |= O_TRUNC; - if (flags & 0x0800) res |= O_NDELAY; - if (flags & 0x4000) res |= O_DIRECT; - if (flags & 0x0800) res |= O_NONBLOCK; - if (flags & 0x1000) res |= O_DSYNC; - if (flags & 0x101000) res |= O_RSYNC; - if (flags & 0x040000) res |= O_NOATIME; - return res; -} - -static int XlatFcntlCmd(int x) { - switch (x) { - XLAT(1, F_GETFD); - XLAT(2, F_SETFD); - XLAT(3, F_GETFL); - XLAT(4, F_SETFL); - default: - return einval(); - } -} - -static int XlatFcntlArg(int x) { - switch (x) { - XLAT(0, 0); - XLAT(1, FD_CLOEXEC); - XLAT(0x0800, O_NONBLOCK); - default: - return einval(); - } -} - -static int XlatAdvice(int x) { - switch (x) { - XLAT(0, MADV_NORMAL); - XLAT(1, MADV_RANDOM); - XLAT(2, MADV_SEQUENTIAL); - XLAT(3, MADV_WILLNEED); - XLAT(4, MADV_DONTNEED); - XLAT(8, MADV_FREE); - XLAT(12, MADV_MERGEABLE); - default: - return einval(); - } -} - -static int XlatLock(int x) { - unsigned res = 0; - if (x & 1) res |= LOCK_SH; - if (x & 2) res |= LOCK_EX; - if (x & 4) res |= LOCK_NB; - if (x & 8) res |= LOCK_UN; - return res; -} - -static int XlatWait(int x) { - unsigned res = 0; - if (x & 1) res |= WNOHANG; - if (x & 2) res |= WUNTRACED; - if (x & 8) res |= WCONTINUED; - return res; -} - -static int XlatRusage(int x) { - switch (x) { - XLAT(0, RUSAGE_SELF); - XLAT(-1, RUSAGE_CHILDREN); - XLAT(1, RUSAGE_THREAD); - default: - return einval(); - } +static int GetAfd(struct Machine *m, int fd) { + if (fd == -100) return AT_FDCWD; + return GetFd(m, fd); } static const char *GetSimulated(void) { @@ -478,28 +196,6 @@ static int AppendIovsGuest(struct Machine *m, struct Iovs *iv, int64_t iovaddr, return rc; } -static struct sigaction *CoerceSigactionToCosmo( - struct sigaction *dst, const struct sigaction_linux *src) { - if (!src) return NULL; - bzero(dst, sizeof(*dst)); - ASSIGN(dst->sa_handler, src->sa_handler); - ASSIGN(dst->sa_restorer, src->sa_restorer); - ASSIGN(dst->sa_flags, src->sa_flags); - ASSIGN(dst->sa_mask, src->sa_mask); - return dst; -} - -static struct sigaction_linux *CoerceSigactionToLinux( - struct sigaction_linux *dst, const struct sigaction *src) { - if (!dst) return NULL; - bzero(dst, sizeof(*dst)); - ASSIGN(dst->sa_handler, src->sa_handler); - ASSIGN(dst->sa_restorer, src->sa_restorer); - ASSIGN(dst->sa_flags, src->sa_flags); - ASSIGN(dst->sa_mask, src->sa_mask); - return dst; -} - static int OpPrctl(struct Machine *m, int op, int64_t a, int64_t b, int64_t c, int64_t d) { return einval(); @@ -565,7 +261,7 @@ static int64_t OpMmap(struct Machine *m, int64_t virt, size_t size, int prot, if (!(prot & PROT_EXEC)) key |= PAGE_XD; if (flags & 256 /* MAP_GROWSDOWN */) key |= PAGE_GROD; flags = XlatMapFlags(flags); - if (fd != -1 && (fd = XlatFd(m, fd)) == -1) return -1; + if (fd != -1 && (fd = GetFd(m, fd)) == -1) return -1; if (!(flags & MAP_FIXED)) { if (!virt) { if ((virt = FindVirtual(m, m->brk, size)) == -1) return -1; @@ -622,7 +318,7 @@ static int OpOpenat(struct Machine *m, int dirfd, int64_t pathaddr, int flags, int fd, i; const char *path; flags = XlatOpenFlags(flags); - if ((dirfd = XlatAfd(m, dirfd)) == -1) return -1; + if ((dirfd = GetAfd(m, dirfd)) == -1) return -1; if ((i = MachineFdAdd(&m->fds)) == -1) return -1; path = LoadStr(m, pathaddr); if ((fd = openat(dirfd, path, flags, mode)) != -1) { @@ -661,7 +357,7 @@ static int OpPipe(struct Machine *m, int64_t pipefds_addr) { static int OpDup(struct Machine *m, int fd) { int i; - if ((fd = XlatFd(m, fd)) != -1) { + if ((fd = GetFd(m, fd)) != -1) { if ((i = MachineFdAdd(&m->fds)) != -1) { if ((fd = dup(fd)) != -1) { m->fds.p[i].cb = &kMachineFdCbHost; @@ -676,7 +372,7 @@ static int OpDup(struct Machine *m, int fd) { static int OpDup2(struct Machine *m, int fd, int newfd) { int i, rc; - if ((fd = XlatFd(m, fd)) == -1) return -1; + if ((fd = GetFd(m, fd)) == -1) return -1; if ((0 <= newfd && newfd < m->fds.i)) { if ((rc = dup2(fd, m->fds.p[newfd].fd)) != -1) { m->fds.p[newfd].cb = &kMachineFdCbHost; @@ -695,6 +391,34 @@ static int OpDup2(struct Machine *m, int fd, int newfd) { return rc; } +static int OpDup3(struct Machine *m, int fd, int newfd, int flags) { + int i, rc; + if (!(flags & ~O_CLOEXEC_LINUX)) { + if ((fd = GetFd(m, fd)) == -1) return -1; + if ((0 <= newfd && newfd < m->fds.i)) { + if ((rc = dup2(fd, m->fds.p[newfd].fd)) != -1) { + if (flags & O_CLOEXEC_LINUX) { + fcntl(rc, F_SETFD, FD_CLOEXEC); + } + m->fds.p[newfd].cb = &kMachineFdCbHost; + m->fds.p[newfd].fd = rc; + rc = newfd; + } + } else if ((i = MachineFdAdd(&m->fds)) != -1) { + if ((rc = dup(fd)) != -1) { + m->fds.p[i].cb = &kMachineFdCbHost; + m->fds.p[i].fd = rc; + rc = i; + } + } else { + rc = -1; + } + return rc; + } else { + return einval(); + } +} + static int OpSocket(struct Machine *m, int family, int type, int protocol) { int i, fd; if ((family = XlatSocketFamily(family)) == -1) return -1; @@ -711,53 +435,61 @@ static int OpSocket(struct Machine *m, int family, int type, int protocol) { return fd; } -static int OpAccept4(struct Machine *m, int fd, int64_t addraddr, - int64_t addrsizeaddr, int flags) { +static int OpAccept4(struct Machine *m, int fd, int64_t aa, int64_t asa, + int flags) { int i, rc; - void *addr; - uint8_t b[4]; uint32_t addrsize; - if ((fd = XlatFd(m, fd)) == -1) return -1; - VirtualSendRead(m, b, addrsizeaddr, 4); - addrsize = Read32(b); - if (!(addr = malloc(addrsize))) return -1; - if ((i = rc = MachineFdAdd(&m->fds)) != -1) { - if ((rc = accept4(fd, addr, &addrsize, XlatSocketFlags(flags))) != -1) { - Write32(b, addrsize); - VirtualRecv(m, addrsizeaddr, b, 4); - VirtualRecvWrite(m, addraddr, addr, addrsize); - m->fds.p[i].cb = &kMachineFdCbHost; - m->fds.p[i].fd = rc; - rc = i; - } else { - MachineFdRemove(&m->fds, i); + uint8_t gaddrsize[4]; + struct sockaddr_in addr; + struct sockaddr_in_bits gaddr; + if (!(flags & ~SOCK_CLOEXEC_LINUX)) { + if ((fd = GetFd(m, fd)) == -1) return -1; + if (aa) { + VirtualSendRead(m, gaddrsize, asa, sizeof(gaddrsize)); + if (Read32(gaddrsize) < sizeof(gaddr)) return einval(); } + if ((i = rc = MachineFdAdd(&m->fds)) != -1) { + addrsize = sizeof(addr); + if ((rc = accept(fd, (struct sockaddr *)&addr, &addrsize)) != -1) { + if (flags & SOCK_CLOEXEC_LINUX) { + fcntl(fd, F_SETFD, FD_CLOEXEC); + } + if (aa) { + Write32(gaddrsize, sizeof(gaddr)); + XlatSockaddrToLinux(&gaddr, &addr); + VirtualRecv(m, asa, gaddrsize, sizeof(gaddrsize)); + VirtualRecvWrite(m, aa, &gaddr, sizeof(gaddr)); + } + m->fds.p[i].cb = &kMachineFdCbHost; + m->fds.p[i].fd = rc; + rc = i; + } else { + MachineFdRemove(&m->fds, i); + } + } + return rc; + } else { + return einval(); } - free(addr); - return rc; } -static int OpConnectBind(struct Machine *m, int fd, intptr_t addraddr, - uint32_t addrsize, +static int OpConnectBind(struct Machine *m, int fd, int64_t aa, uint32_t as, int impl(int, const void *, uint32_t)) { - int rc; - void *addr; - if ((fd = XlatFd(m, fd)) == -1) return -1; - if (!(addr = malloc(addrsize))) return -1; - VirtualSendRead(m, addr, addraddr, addrsize); - rc = impl(fd, addr, addrsize); - free(addr); - return rc; + struct sockaddr_in addr; + struct sockaddr_in_bits gaddr; + if (as != sizeof(gaddr)) return einval(); + if ((fd = GetFd(m, fd)) == -1) return -1; + VirtualSendRead(m, &gaddr, aa, sizeof(gaddr)); + XlatSockaddrToHost(&addr, &gaddr); + return impl(fd, (const struct sockaddr *)&addr, sizeof(addr)); } -static int OpBind(struct Machine *m, int fd, intptr_t addraddr, - uint32_t addrsize) { - return OpConnectBind(m, fd, addraddr, addrsize, bind); +static int OpBind(struct Machine *m, int fd, int64_t aa, uint32_t as) { + return OpConnectBind(m, fd, aa, as, bind); } -static int OpConnect(struct Machine *m, int fd, int64_t addraddr, - uint32_t addrsize) { - return OpConnectBind(m, fd, addraddr, addrsize, connect); +static int OpConnect(struct Machine *m, int fd, int64_t aa, uint32_t as) { + return OpConnectBind(m, fd, aa, as, connect); } static int OpSetsockopt(struct Machine *m, int fd, int level, int optname, @@ -765,8 +497,8 @@ static int OpSetsockopt(struct Machine *m, int fd, int level, int optname, int rc; void *optval; if ((level = XlatSocketLevel(level)) == -1) return -1; - if ((optname = XlatSocketOptname(optname)) == -1) return -1; - if ((fd = XlatFd(m, fd)) == -1) return -1; + if ((optname = XlatSocketOptname(level, optname)) == -1) return -1; + if ((fd = GetFd(m, fd)) == -1) return -1; if (!(optval = malloc(optvalsize))) return -1; VirtualSendRead(m, optval, optvaladdr, optvalsize); rc = setsockopt(fd, level, optname, optval, optvalsize); @@ -780,8 +512,8 @@ static int OpGetsockopt(struct Machine *m, int fd, int level, int optname, void *optval; uint32_t optsize; if ((level = XlatSocketLevel(level)) == -1) return -1; - if ((optname = XlatSocketOptname(optname)) == -1) return -1; - if ((fd = XlatFd(m, fd)) == -1) return -1; + if ((optname = XlatSocketOptname(level, optname)) == -1) return -1; + if ((fd = GetFd(m, fd)) == -1) return -1; if (!optvaladdr) { rc = getsockopt(fd, level, optname, 0, 0); } else { @@ -796,36 +528,32 @@ static int OpGetsockopt(struct Machine *m, int fd, int level, int optname, return rc; } -static int OpGetsockname(struct Machine *m, int fd, int64_t addraddr, - int64_t addrlenaddr) { +static int OpSocketName(struct Machine *m, int fd, int64_t aa, int64_t asa, + int SocketName(int, void *, socklen_t *)) { int rc; - void *addr; - uint32_t addrlen; - if ((fd = XlatFd(m, fd)) == -1) return -1; - VirtualSendRead(m, &addrlen, addrlenaddr, sizeof(addrlen)); - if (!(addr = malloc(addrlen))) return -1; - if ((rc = getsockname(fd, addr, &addrlen)) != -1) { - VirtualRecvWrite(m, addraddr, addr, addrlen); - VirtualRecvWrite(m, addrlenaddr, &addrlen, sizeof(addrlen)); + uint32_t addrsize; + uint8_t gaddrsize[4]; + struct sockaddr_in addr; + struct sockaddr_in_bits gaddr; + if ((fd = GetFd(m, fd)) == -1) return -1; + VirtualSendRead(m, gaddrsize, asa, sizeof(gaddrsize)); + if (Read32(gaddrsize) < sizeof(gaddr)) return einval(); + addrsize = sizeof(addr); + if ((rc = SocketName(fd, (struct sockaddr *)&addr, &addrsize)) != -1) { + Write32(gaddrsize, sizeof(gaddr)); + XlatSockaddrToLinux(&gaddr, &addr); + VirtualRecv(m, asa, gaddrsize, sizeof(gaddrsize)); + VirtualRecvWrite(m, aa, &gaddr, sizeof(gaddr)); } - free(addr); return rc; } -static int OpGetpeername(struct Machine *m, int fd, int64_t addraddr, - int64_t addrlenaddr) { - int rc; - void *addr; - uint32_t addrlen; - if ((fd = XlatFd(m, fd)) == -1) return -1; - VirtualSendRead(m, &addrlen, addrlenaddr, sizeof(addrlen)); - if (!(addr = malloc(addrlen))) return -1; - if ((rc = getpeername(fd, addr, &addrlen)) != -1) { - VirtualRecvWrite(m, addraddr, addr, addrlen); - VirtualRecvWrite(m, addrlenaddr, &addrlen, sizeof(addrlen)); - } - free(addr); - return rc; +static int OpGetsockname(struct Machine *m, int fd, int64_t aa, int64_t asa) { + return OpSocketName(m, fd, aa, asa, getsockname); +} + +static int OpGetpeername(struct Machine *m, int fd, int64_t aa, int64_t asa) { + return OpSocketName(m, fd, aa, asa, getpeername); } static ssize_t OpRead(struct Machine *m, int fd, int64_t addr, size_t size) { @@ -874,7 +602,7 @@ static ssize_t OpPread(struct Machine *m, int fd, int64_t addr, size_t size, ssize_t rc; struct Iovs iv; InitIovs(&iv); - if ((rc = XlatFd(m, fd)) != -1) { + if ((rc = GetFd(m, fd)) != -1) { fd = rc; if ((rc = AppendIovsReal(m, &iv, addr, size)) != -1) { if ((rc = preadv(fd, iv.p, iv.i, offset)) != -1) { @@ -912,7 +640,7 @@ static ssize_t OpPwrite(struct Machine *m, int fd, int64_t addr, size_t size, ssize_t rc; struct Iovs iv; InitIovs(&iv); - if ((rc = XlatFd(m, fd)) != -1) { + if ((rc = GetFd(m, fd)) != -1) { fd = rc; if ((rc = AppendIovsReal(m, &iv, addr, size)) != -1) { if ((rc = pwritev(fd, iv.p, iv.i, offset)) != -1) { @@ -925,48 +653,40 @@ static ssize_t OpPwrite(struct Machine *m, int fd, int64_t addr, size_t size, } static int IoctlTiocgwinsz(struct Machine *m, int fd, int64_t addr, - int (*fn)(int, uint64_t, void *)) { + int fn(int, int, ...)) { int rc; struct winsize ws; + struct winsize_bits gws; if ((rc = fn(fd, TIOCGWINSZ, &ws)) != -1) { - VirtualRecvWrite(m, addr, &ws, sizeof(ws)); + XlatWinsizeToLinux(&gws, &ws); + VirtualRecvWrite(m, addr, &gws, sizeof(gws)); } return rc; } static int IoctlTcgets(struct Machine *m, int fd, int64_t addr, - int (*fn)(int, uint64_t, void *)) { + int fn(int, int, ...)) { int rc; - struct termios tio, tio2; + struct termios tio; + struct termios_bits gtio; if ((rc = fn(fd, TCGETS, &tio)) != -1) { - memcpy(&tio2, &tio, sizeof(tio)); - tio2.c_iflag = 0; - if (tio.c_lflag & ISIG) tio2.c_lflag |= ISIG_LINUX; - if (tio.c_lflag & ICANON) tio2.c_lflag |= ICANON_LINUX; - if (tio.c_lflag & ECHO) tio2.c_lflag |= ECHO_LINUX; - tio2.c_oflag = 0; - if (tio.c_oflag & OPOST) tio2.c_oflag |= OPOST_LINUX; - VirtualRecvWrite(m, addr, &tio2, sizeof(tio2)); + XlatTermiosToLinux(>io, &tio); + VirtualRecvWrite(m, addr, >io, sizeof(gtio)); } return rc; } static int IoctlTcsets(struct Machine *m, int fd, int64_t request, int64_t addr, - int (*fn)(int, uint64_t, void *)) { - struct termios tio, tio2; - VirtualSendRead(m, &tio, addr, sizeof(tio)); - memcpy(&tio2, &tio, sizeof(tio)); - tio2.c_iflag = 0; - if (tio.c_lflag & ISIG_LINUX) tio2.c_lflag |= ISIG; - if (tio.c_lflag & ICANON_LINUX) tio2.c_lflag |= ICANON; - if (tio.c_lflag & ECHO_LINUX) tio2.c_lflag |= ECHO; - tio2.c_oflag = 0; - if (tio.c_oflag & OPOST_LINUX) tio2.c_oflag |= OPOST; - return fn(fd, request, &tio2); + int (*fn)(int, int, ...)) { + struct termios tio; + struct termios_bits gtio; + VirtualSendRead(m, >io, addr, sizeof(gtio)); + XlatLinuxToTermios(&tio, >io); + return fn(fd, request, &tio); } static int OpIoctl(struct Machine *m, int fd, uint64_t request, int64_t addr) { - int (*fn)(int, uint64_t, void *); + int (*fn)(int, int, ...); if (!(0 <= fd && fd < m->fds.i) || !m->fds.p[fd].cb) return ebadf(); fn = m->fds.p[fd].cb->ioctl; fd = m->fds.p[fd].fd; @@ -1018,12 +738,12 @@ static ssize_t OpWritev(struct Machine *m, int fd, int64_t iovaddr, } static int64_t OpLseek(struct Machine *m, int fd, int64_t offset, int whence) { - if ((fd = XlatFd(m, fd)) == -1) return -1; + if ((fd = GetFd(m, fd)) == -1) return -1; return lseek(fd, offset, whence); } static ssize_t OpFtruncate(struct Machine *m, int fd, int64_t size) { - if ((fd = XlatFd(m, fd)) == -1) return -1; + if ((fd = GetFd(m, fd)) == -1) return -1; return ftruncate(fd, size); } @@ -1031,7 +751,7 @@ static int OpFaccessat(struct Machine *m, int dirfd, int64_t path, int mode, int flags) { flags = XlatAtf(flags); mode = XlatAccess(mode); - if ((dirfd = XlatAfd(m, dirfd)) == -1) return -1; + if ((dirfd = GetAfd(m, dirfd)) == -1) return -1; return faccessat(dirfd, LoadStr(m, path), mode, flags); } @@ -1039,10 +759,12 @@ static int OpFstatat(struct Machine *m, int dirfd, int64_t path, int64_t staddr, int flags) { int rc; struct stat st; + struct stat_bits gst; flags = XlatAtf(flags); - if ((dirfd = XlatAfd(m, dirfd)) == -1) return -1; + if ((dirfd = GetAfd(m, dirfd)) == -1) return -1; if ((rc = fstatat(dirfd, LoadStr(m, path), &st, flags)) != -1) { - VirtualRecvWrite(m, staddr, &st, sizeof(struct stat)); + XlatStatToLinux(&gst, &st); + VirtualRecvWrite(m, staddr, &gst, sizeof(gst)); } return rc; } @@ -1050,54 +772,56 @@ static int OpFstatat(struct Machine *m, int dirfd, int64_t path, int64_t staddr, static int OpFstat(struct Machine *m, int fd, int64_t staddr) { int rc; struct stat st; - if ((fd = XlatFd(m, fd)) == -1) return -1; + struct stat_bits gst; + if ((fd = GetFd(m, fd)) == -1) return -1; if ((rc = fstat(fd, &st)) != -1) { - VirtualRecvWrite(m, staddr, &st, sizeof(struct stat)); + XlatStatToLinux(&gst, &st); + VirtualRecvWrite(m, staddr, &gst, sizeof(gst)); } return rc; } static int OpListen(struct Machine *m, int fd, int backlog) { - if ((fd = XlatFd(m, fd)) == -1) return -1; + if ((fd = GetFd(m, fd)) == -1) return -1; return listen(fd, backlog); } static int OpShutdown(struct Machine *m, int fd, int how) { - if ((fd = XlatFd(m, fd)) == -1) return -1; + if ((fd = GetFd(m, fd)) == -1) return -1; return shutdown(fd, how); } static int OpFsync(struct Machine *m, int fd) { - if ((fd = XlatFd(m, fd)) == -1) return -1; + if ((fd = GetFd(m, fd)) == -1) return -1; return fsync(fd); } static int OpFdatasync(struct Machine *m, int fd) { - if ((fd = XlatFd(m, fd)) == -1) return -1; + if ((fd = GetFd(m, fd)) == -1) return -1; return fdatasync(fd); } static int OpFchmod(struct Machine *m, int fd, uint32_t mode) { - if ((fd = XlatFd(m, fd)) == -1) return -1; + if ((fd = GetFd(m, fd)) == -1) return -1; return fchmod(fd, mode); } static int OpFcntl(struct Machine *m, int fd, int cmd, int arg) { if ((cmd = XlatFcntlCmd(cmd)) == -1) return -1; if ((arg = XlatFcntlArg(arg)) == -1) return -1; - if ((fd = XlatFd(m, fd)) == -1) return -1; + if ((fd = GetFd(m, fd)) == -1) return -1; return fcntl(fd, cmd, arg); } static int OpFadvise(struct Machine *m, int fd, uint64_t offset, uint64_t len, int advice) { - if ((fd = XlatFd(m, fd)) == -1) return -1; + if ((fd = GetFd(m, fd)) == -1) return -1; if ((advice = XlatAdvice(advice)) == -1) return -1; return fadvise(fd, offset, len, advice); } static int OpFlock(struct Machine *m, int fd, int lock) { - if ((fd = XlatFd(m, fd)) == -1) return -1; + if ((fd = GetFd(m, fd)) == -1) return -1; if ((lock = XlatLock(lock)) == -1) return -1; return flock(fd, lock); } @@ -1111,7 +835,7 @@ static int OpMkdir(struct Machine *m, int64_t path, int mode) { } static int OpMkdirat(struct Machine *m, int dirfd, int64_t path, int mode) { - return mkdirat(XlatAfd(m, dirfd), LoadStr(m, path), mode); + return mkdirat(GetAfd(m, dirfd), LoadStr(m, path), mode); } static int OpMknod(struct Machine *m, int64_t path, uint32_t mode, @@ -1128,7 +852,7 @@ static int OpUnlink(struct Machine *m, int64_t path) { } static int OpUnlinkat(struct Machine *m, int dirfd, int64_t path, int flags) { - return unlinkat(XlatAfd(m, dirfd), LoadStr(m, path), XlatAtf(flags)); + return unlinkat(GetAfd(m, dirfd), LoadStr(m, path), XlatAtf(flags)); } static int OpRename(struct Machine *m, int64_t src, int64_t dst) { @@ -1137,7 +861,7 @@ static int OpRename(struct Machine *m, int64_t src, int64_t dst) { static int OpRenameat(struct Machine *m, int srcdirfd, int64_t src, int dstdirfd, int64_t dst) { - return renameat(XlatAfd(m, srcdirfd), LoadStr(m, src), XlatAfd(m, dstdirfd), + return renameat(GetAfd(m, srcdirfd), LoadStr(m, src), GetAfd(m, dstdirfd), LoadStr(m, dst)); } @@ -1158,7 +882,10 @@ static int OpChmod(struct Machine *m, int64_t path, uint32_t mode) { } static int OpFork(struct Machine *m) { - return enosys(); + int pid; + pid = fork(); + if (!pid) m->isfork = true; + return pid; } static int OpExecve(struct Machine *m, int64_t programaddr, int64_t argvaddr, @@ -1166,18 +893,32 @@ static int OpExecve(struct Machine *m, int64_t programaddr, int64_t argvaddr, return enosys(); } +wontreturn static void OpExit(struct Machine *m, int rc) { + if (m->isfork) { + _Exit(rc); + } else { + HaltMachine(m, rc | 0x100); + } +} + +_Noreturn static void OpExitGroup(struct Machine *m, int rc) { + OpExit(m, rc); +} + static int OpWait4(struct Machine *m, int pid, int64_t opt_out_wstatus_addr, int options, int64_t opt_out_rusage_addr) { int rc; int32_t wstatus; - struct rusage rusage; + struct rusage hrusage; + struct rusage_bits grusage; if ((options = XlatWait(options)) == -1) return -1; - if ((rc = wait4(pid, &wstatus, options, &rusage)) != -1) { + if ((rc = wait4(pid, &wstatus, options, &hrusage)) != -1) { if (opt_out_wstatus_addr) { VirtualRecvWrite(m, opt_out_wstatus_addr, &wstatus, sizeof(wstatus)); } if (opt_out_rusage_addr) { - VirtualRecvWrite(m, opt_out_rusage_addr, &rusage, sizeof(rusage)); + XlatRusageToLinux(&grusage, &hrusage); + VirtualRecvWrite(m, opt_out_rusage_addr, &grusage, sizeof(grusage)); } } return rc; @@ -1185,10 +926,12 @@ static int OpWait4(struct Machine *m, int pid, int64_t opt_out_wstatus_addr, static int OpGetrusage(struct Machine *m, int resource, int64_t rusageaddr) { int rc; - struct rusage rusage; + struct rusage hrusage; + struct rusage_bits grusage; if ((resource = XlatRusage(resource)) == -1) return -1; - if ((rc = getrusage(resource, &rusage)) != -1) { - VirtualRecvWrite(m, rusageaddr, &rusage, sizeof(rusage)); + if ((rc = getrusage(resource, &hrusage)) != -1) { + XlatRusageToLinux(&grusage, &hrusage); + VirtualRecvWrite(m, rusageaddr, &grusage, sizeof(grusage)); } return rc; } @@ -1202,7 +945,7 @@ static ssize_t OpReadlinkat(struct Machine *m, int dirfd, int64_t pathaddr, char *buf; ssize_t rc; const char *path; - if ((dirfd = XlatAfd(m, dirfd)) == -1) return -1; + if ((dirfd = GetAfd(m, dirfd)) == -1) return -1; path = LoadStr(m, pathaddr); if (!(buf = malloc(size))) return enomem(); if ((rc = readlinkat(dirfd, path, buf, size)) != -1) { @@ -1229,120 +972,231 @@ static int64_t OpGetcwd(struct Machine *m, int64_t bufaddr, size_t size) { return res; } -static int OpSigaction(struct Machine *m, int sig, int64_t act, int64_t old) { - return 0; - int rc; - struct OpSigactionMemory { - struct sigaction act, old; - uint8_t b[sizeof(struct sigaction_linux)]; - void *p[2]; - } * mem; - if (!(mem = malloc(sizeof(*mem)))) return enomem(); - if ((rc = sigaction( - XlatSignal(sig), - CoerceSigactionToCosmo( - &mem->act, LoadBuf(m, act, sizeof(struct sigaction_linux))), - &mem->old)) != -1) { - CoerceSigactionToLinux(BeginStoreNp(m, old, sizeof(mem->b), mem->p, mem->b), - &mem->old); - EndStoreNp(m, old, sizeof(mem->b), mem->p, mem->b); +static int OpSigaction(struct Machine *m, int sig, int64_t act, int64_t old, + uint64_t sigsetsize) { + if ((sig = XlatSignal(sig) - 1) != -1 && + (0 <= sig && sig < ARRAYLEN(m->sighand)) && sigsetsize == 8) { + if (old) VirtualRecvWrite(m, old, &m->sighand[sig], sizeof(m->sighand[0])); + if (act) VirtualSendRead(m, &m->sighand[sig], act, sizeof(m->sighand[0])); + return 0; + } else { + return einval(); + } +} + +static int OpSigprocmask(struct Machine *m, int how, int64_t setaddr, + int64_t oldsetaddr, uint64_t sigsetsize) { + uint8_t set[8]; + if ((how = XlatSig(how)) != -1 && sigsetsize == sizeof(set)) { + if (oldsetaddr) { + VirtualRecvWrite(m, oldsetaddr, m->sigmask, sizeof(set)); + } + if (setaddr) { + VirtualSendRead(m, set, setaddr, sizeof(set)); + if (how == SIG_BLOCK) { + Write64(m->sigmask, Read64(m->sigmask) | Read64(set)); + } else if (how == SIG_UNBLOCK) { + Write64(m->sigmask, Read64(m->sigmask) & ~Read64(set)); + } else { + Write64(m->sigmask, Read64(set)); + } + } + return 0; + } else { + return einval(); + } +} + +static int OpGetitimer(struct Machine *m, int which, int64_t curvaladdr) { + int rc; + struct itimerval it; + struct itimerval_bits git; + if ((rc = getitimer(which, &it)) != -1) { + XlatItimervalToLinux(&git, &it); + VirtualRecvWrite(m, curvaladdr, &git, sizeof(git)); + } + return rc; +} + +static int OpSetitimer(struct Machine *m, int which, int64_t neuaddr, + int64_t oldaddr) { + int rc; + struct itimerval neu, old; + struct itimerval_bits git; + VirtualSendRead(m, &git, neuaddr, sizeof(git)); + XlatLinuxToItimerval(&neu, &git); + if ((rc = setitimer(which, &neu, &old)) != -1) { + if (oldaddr) { + XlatItimervalToLinux(&git, &old); + VirtualRecvWrite(m, oldaddr, &git, sizeof(git)); + } } - free(mem); return rc; } static int OpNanosleep(struct Machine *m, int64_t req, int64_t rem) { int rc; - void *p[2]; - uint8_t b[sizeof(struct timespec)]; - if ((rc = nanosleep(LoadBuf(m, req, sizeof(b)), - BeginStoreNp(m, rem, sizeof(b), p, b))) != -1) { - EndStoreNp(m, rem, sizeof(b), p, b); + struct timespec hreq, hrem; + struct timespec_bits gtimespec; + if (req) { + VirtualSendRead(m, >imespec, req, sizeof(gtimespec)); + hreq.tv_sec = Read64(gtimespec.tv_sec); + hreq.tv_nsec = Read64(gtimespec.tv_nsec); + } + if ((rc = nanosleep(req ? &hreq : 0, rem ? &hrem : 0)) != -1) { + if (rem) { + Write64(gtimespec.tv_sec, hrem.tv_sec); + Write64(gtimespec.tv_nsec, hrem.tv_nsec); + VirtualRecvWrite(m, rem, >imespec, sizeof(gtimespec)); + } } return rc; } static int OpSigsuspend(struct Machine *m, int64_t maskaddr) { - void *p; sigset_t mask; - if (!(p = LoadBuf(m, maskaddr, 8))) return efault(); - bzero(&mask, sizeof(mask)); - memcpy(&mask, p, 8); + uint8_t gmask[8]; + VirtualSendRead(m, &gmask, maskaddr, 8); + XlatLinuxToSigset(&mask, gmask); return sigsuspend(&mask); } static int OpClockGettime(struct Machine *m, int clockid, int64_t ts) { int rc; - void *tsp[2]; - uint8_t tsb[sizeof(struct timespec)]; - if ((rc = clock_gettime(XlatClock(clockid), - BeginStoreNp(m, ts, sizeof(tsb), tsp, tsb))) != -1) { - EndStoreNp(m, ts, sizeof(tsb), tsp, tsb); + struct timespec htimespec; + struct timespec_bits gtimespec; + if ((rc = clock_gettime(XlatClock(clockid), ts ? &htimespec : 0)) != -1) { + if (ts) { + Write64(gtimespec.tv_sec, htimespec.tv_sec); + Write64(gtimespec.tv_nsec, htimespec.tv_nsec); + VirtualRecvWrite(m, ts, >imespec, sizeof(gtimespec)); + } } return rc; } static int OpGettimeofday(struct Machine *m, int64_t tv, int64_t tz) { int rc; - void *tvp[2], *tzp[2]; - uint8_t tvb[sizeof(struct timeval)]; - uint8_t tzb[sizeof(struct timezone)]; - if ((rc = gettimeofday(BeginStoreNp(m, tv, sizeof(tvb), tvp, tvb), - BeginStoreNp(m, tz, sizeof(tzb), tzp, tzb))) != -1) { - EndStoreNp(m, tv, sizeof(tvb), tvp, tvb); - EndStoreNp(m, tz, sizeof(tzb), tzp, tzb); + struct timeval htimeval; + struct timezone htimezone; + struct timeval_bits gtimeval; + struct timezone_bits gtimezone; + if ((rc = gettimeofday(&htimeval, tz ? &htimezone : 0)) != -1) { + Write64(gtimeval.tv_sec, htimeval.tv_sec); + Write64(gtimeval.tv_usec, htimeval.tv_usec); + VirtualRecvWrite(m, tv, >imeval, sizeof(gtimeval)); + if (tz) { + Write32(gtimezone.tz_minuteswest, htimezone.tz_minuteswest); + Write32(gtimezone.tz_dsttime, htimezone.tz_dsttime); + VirtualRecvWrite(m, tz, >imezone, sizeof(gtimezone)); + } } return rc; } +static int OpUtimes(struct Machine *m, int64_t pathaddr, int64_t tvsaddr) { + const char *path; + struct timeval tvs[2]; + struct timeval_bits gtvs[2]; + path = LoadStr(m, pathaddr); + if (tvsaddr) { + VirtualSendRead(m, gtvs, tvsaddr, sizeof(gtvs)); + tvs[0].tv_sec = Read64(gtvs[0].tv_sec); + tvs[0].tv_usec = Read64(gtvs[0].tv_usec); + tvs[1].tv_sec = Read64(gtvs[1].tv_sec); + tvs[1].tv_usec = Read64(gtvs[1].tv_usec); + return utimes(path, tvs); + } else { + return utimes(path, 0); + } +} + static int OpPoll(struct Machine *m, int64_t fdsaddr, uint64_t nfds, int32_t timeout_ms) { - int count, i; - uint64_t fdssize; - struct pollfd *hostfds, *guestfds; - if (!__builtin_mul_overflow(nfds, sizeof(struct pollfd), &fdssize) && - fdssize <= 0x7ffff000) { - hostfds = malloc(fdssize); - guestfds = malloc(fdssize); - if (hostfds && guestfds) { - VirtualSendRead(m, guestfds, fdsaddr, fdssize); - memcpy(hostfds, guestfds, fdssize); - for (i = 0; i < nfds; ++i) { - hostfds[i].fd = XlatFd(m, hostfds[i].fd); - } - if ((count = poll(hostfds, nfds, timeout_ms)) != -1) { - for (i = 0; i < count; ++i) { - hostfds[i].fd = guestfds[i].fd; + uint64_t gfdssize; + struct pollfd hfds[1]; + int i, fd, rc, ev, count; + struct timespec ts1, ts2; + struct pollfd_bits *gfds; + int64_t wait, elapsed, timeout; + timeout = timeout_ms * 1000L; + if (!__builtin_mul_overflow(nfds, sizeof(struct pollfd_bits), &gfdssize) && + gfdssize <= 0x7ffff000) { + if ((gfds = malloc(gfdssize))) { + rc = 0; + VirtualSendRead(m, gfds, fdsaddr, gfdssize); + ts1 = _timespec_mono(); + for (;;) { + for (i = 0; i < nfds; ++i) { + fd = Read32(gfds[i].fd); + if ((0 <= fd && fd < m->fds.i) && m->fds.p[fd].cb) { + hfds[0].fd = m->fds.p[fd].fd; + ev = Read16(gfds[i].events); + hfds[0].events = (((ev & POLLIN_LINUX) ? POLLIN : 0) | + ((ev & POLLOUT_LINUX) ? POLLOUT : 0) | + ((ev & POLLPRI_LINUX) ? POLLPRI : 0)); + switch (m->fds.p[fd].cb->poll(hfds, 1, 0)) { + case 0: + Write16(gfds[i].revents, 0); + break; + case 1: + ++rc; + ev = 0; + if (hfds[0].revents & POLLIN) ev |= POLLIN_LINUX; + if (hfds[0].revents & POLLPRI) ev |= POLLPRI_LINUX; + if (hfds[0].revents & POLLOUT) ev |= POLLOUT_LINUX; + if (hfds[0].revents & POLLERR) ev |= POLLERR_LINUX; + if (hfds[0].revents & POLLHUP) ev |= POLLHUP_LINUX; + if (hfds[0].revents & POLLNVAL) ev |= POLLERR_LINUX; + if (!ev) ev |= POLLERR_LINUX; + Write16(gfds[i].revents, ev); + break; + case -1: + ++rc; + Write16(gfds[i].revents, POLLERR_LINUX); + break; + default: + break; + } + } else { + Write16(gfds[i].revents, POLLNVAL_LINUX); + } + } + if (rc || !timeout) break; + wait = __SIG_POLLING_INTERVAL_MS * 1000; + if (timeout < 0) { + if (usleep(wait)) { + errno = EINTR; + rc = -1; + goto Finished; + } + } else { + ts2 = _timespec_mono(); + elapsed = _timespec_tomicros(_timespec_sub(ts2, ts1)); + if (elapsed >= timeout) { + break; + } + if (timeout - elapsed < wait) { + wait = timeout - elapsed; + } + if (usleep(wait)) { + errno = EINTR; + rc = -1; + goto Finished; + } } - VirtualRecvWrite(m, fdsaddr, hostfds, count * sizeof(struct pollfd)); } + VirtualRecvWrite(m, fdsaddr, gfds, nfds * sizeof(*gfds)); } else { - count = enomem(); + errno = ENOMEM; + rc = -1; } - free(guestfds); - free(hostfds); + Finished: + free(gfds); + return rc; } else { - count = einval(); + return einval(); } - return count; -} - -static int OpSigprocmask(struct Machine *m, int how, int64_t setaddr, - int64_t oldsetaddr) { - int rc; - sigset_t *set, oldset, ss; - if (setaddr) { - set = &ss; - bzero(set, sizeof(ss)); - VirtualSendRead(m, set, setaddr, 8); - } else { - set = NULL; - } - if ((rc = sigprocmask(XlatSig(how), set, &oldset)) != -1) { - if (setaddr) VirtualRecvWrite(m, setaddr, set, 8); - if (oldsetaddr) VirtualRecvWrite(m, oldsetaddr, &oldset, 8); - } - return rc; } static int OpGetPid(struct Machine *m) { @@ -1353,11 +1207,11 @@ static int OpGetPpid(struct Machine *m) { return getppid(); } -static int OpKill(struct Machine *m, int pid, int sig) { - if (pid == getpid()) { - ThrowProtectionFault(m); +static void OpKill(struct Machine *m, int pid, int sig) { + if (!pid || pid == getpid()) { + DeliverSignal(m, sig, SI_USER); } else { - return kill(pid, sig); + Write64(m->ax, -3); // ESRCH } } @@ -1386,7 +1240,7 @@ static int OpPause(struct Machine *m) { } static int DoOpen(struct Machine *m, int64_t path, int flags, int mode) { - return OpOpenat(m, AT_FDCWD_LINUX, path, flags, mode); + return OpOpenat(m, -100, path, flags, mode); } static int DoCreat(struct Machine *m, int64_t file, int mode) { @@ -1394,24 +1248,26 @@ static int DoCreat(struct Machine *m, int64_t file, int mode) { } static int DoAccess(struct Machine *m, int64_t path, int mode) { - return OpFaccessat(m, AT_FDCWD_LINUX, path, mode, 0); + return OpFaccessat(m, -100, path, mode, 0); } static int DoStat(struct Machine *m, int64_t path, int64_t st) { - return OpFstatat(m, AT_FDCWD_LINUX, path, st, 0); + return OpFstatat(m, -100, path, st, 0); } static int DoLstat(struct Machine *m, int64_t path, int64_t st) { - return OpFstatat(m, AT_FDCWD_LINUX, path, st, 0x0400); + return OpFstatat(m, -100, path, st, 0x0400); } -static int DoAccept(struct Machine *m, int fd, int64_t addraddr, - int64_t addrsizeaddr) { - return OpAccept4(m, fd, addraddr, addrsizeaddr, 0); +static int OpAccept(struct Machine *m, int fd, int64_t sa, int64_t sas) { + return OpAccept4(m, fd, sa, sas, 0); } void OpSyscall(struct Machine *m, uint32_t rde) { uint64_t i, ax, di, si, dx, r0, r8, r9; + if (m->redraw) { + m->redraw(); + } ax = Read64(m->ax); if (m->ismetal) { WARNF("metal syscall 0x%03x", ax); @@ -1437,8 +1293,8 @@ void OpSyscall(struct Machine *m, uint32_t rde) { SYSCALL(0x00A, OpMprotect(m, di, si, dx)); SYSCALL(0x00B, OpMunmap(m, di, si)); SYSCALL(0x00C, OpBrk(m, di)); - SYSCALL(0x00D, OpSigaction(m, di, si, dx)); - SYSCALL(0x00E, OpSigprocmask(m, di, si, dx)); + SYSCALL(0x00D, OpSigaction(m, di, si, dx, r0)); + SYSCALL(0x00E, OpSigprocmask(m, di, si, dx, r0)); SYSCALL(0x010, OpIoctl(m, di, si, dx)); SYSCALL(0x011, OpPread(m, di, si, dx, r0)); SYSCALL(0x012, OpPwrite(m, di, si, dx, r0)); @@ -1451,16 +1307,17 @@ void OpSyscall(struct Machine *m, uint32_t rde) { SYSCALL(0x01C, OpMadvise(m, di, si, dx)); SYSCALL(0x020, OpDup(m, di)); SYSCALL(0x021, OpDup2(m, di, si)); + SYSCALL(0x124, OpDup3(m, di, si, dx)); SYSCALL(0x022, OpPause(m)); SYSCALL(0x023, OpNanosleep(m, di, si)); - SYSCALL(0x024, getitimer(di, PNN(si))); + SYSCALL(0x024, OpGetitimer(m, di, si)); SYSCALL(0x025, OpAlarm(m, di)); - SYSCALL(0x026, setitimer(di, PNN(si), P(dx))); + SYSCALL(0x026, OpSetitimer(m, di, si, dx)); SYSCALL(0x027, OpGetPid(m)); SYSCALL(0x028, sendfile(di, si, P(dx), r0)); SYSCALL(0x029, OpSocket(m, di, si, dx)); SYSCALL(0x02A, OpConnect(m, di, si, dx)); - SYSCALL(0x02B, DoAccept(m, di, di, dx)); + SYSCALL(0x02B, OpAccept(m, di, di, dx)); SYSCALL(0x02C, sendto(di, PNN(si), dx, r0, P(r8), r9)); SYSCALL(0x02D, recvfrom(di, P(si), dx, r0, P(r8), P(r9))); SYSCALL(0x030, OpShutdown(m, di, si)); @@ -1473,7 +1330,6 @@ void OpSyscall(struct Machine *m, uint32_t rde) { SYSCALL(0x039, OpFork(m)); SYSCALL(0x03B, OpExecve(m, di, si, dx)); SYSCALL(0x03D, OpWait4(m, di, si, dx, r0)); - SYSCALL(0x03E, OpKill(m, di, si)); SYSCALL(0x03F, uname(P(di))); SYSCALL(0x048, OpFcntl(m, di, si, dx)); SYSCALL(0x049, OpFlock(m, di, si)); @@ -1508,7 +1364,7 @@ void OpSyscall(struct Machine *m, uint32_t rde) { SYSCALL(0x08D, setpriority(di, si, dx)); SYSCALL(0x0A0, setrlimit(di, P(si))); SYSCALL(0x084, utime(PNN(di), PNN(si))); - SYSCALL(0x0EB, utimes(P(di), P(si))); + SYSCALL(0x0EB, OpUtimes(m, di, si)); SYSCALL(0x09D, OpPrctl(m, di, si, dx, r0, r8)); SYSCALL(0x09E, OpArchPrctl(m, di, si)); SYSCALL(0x0BA, OpGetTid(m)); @@ -1518,8 +1374,8 @@ void OpSyscall(struct Machine *m, uint32_t rde) { SYSCALL(0x0E4, OpClockGettime(m, di, si)); SYSCALL(0x101, OpOpenat(m, di, si, dx, r0)); SYSCALL(0x102, OpMkdirat(m, di, si, dx)); - SYSCALL(0x104, fchownat(XlatAfd(m, di), P(si), dx, r0, XlatAtf(r8))); - SYSCALL(0x105, futimesat(XlatAfd(m, di), P(si), P(dx))); + SYSCALL(0x104, fchownat(GetAfd(m, di), P(si), dx, r0, XlatAtf(r8))); + SYSCALL(0x105, futimesat(GetAfd(m, di), P(si), P(dx))); SYSCALL(0x106, OpFstatat(m, di, si, dx, r0)); SYSCALL(0x107, OpUnlinkat(m, di, si, dx)); SYSCALL(0x108, OpRenameat(m, di, si, dx, r0)); @@ -1527,10 +1383,19 @@ void OpSyscall(struct Machine *m, uint32_t rde) { SYSCALL(0x10D, OpFaccessat(m, di, si, dx, r0)); SYSCALL(0x113, splice(di, P(si), dx, P(r0), r8, XlatAtf(r9))); SYSCALL(0x115, sync_file_range(di, si, dx, XlatAtf(r0))); - SYSCALL(0x118, utimensat(XlatAfd(m, di), P(si), P(dx), XlatAtf(r0))); + SYSCALL(0x118, utimensat(GetAfd(m, di), P(si), P(dx), XlatAtf(r0))); SYSCALL(0x120, OpAccept4(m, di, si, dx, r0)); SYSCALL(0x177, vmsplice(di, P(si), dx, r0)); - CASE(0xE7, HaltMachine(m, di | 0x100)); + case 0x3C: + OpExit(m, di); + case 0xE7: + OpExitGroup(m, di); + case 0x00F: + OpRestore(m); + return; + case 0x03E: + OpKill(m, di, si); + return; default: WARNF("missing syscall 0x%03x", ax); ax = enosys(); diff --git a/tool/build/lib/xlat.c b/tool/build/lib/xlat.c new file mode 100644 index 000000000..856d37913 --- /dev/null +++ b/tool/build/lib/xlat.c @@ -0,0 +1,1002 @@ +/*-*- 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/errno.h" +#include "libc/sysv/consts/af.h" +#include "libc/sysv/consts/at.h" +#include "libc/sysv/consts/clock.h" +#include "libc/sysv/consts/f.h" +#include "libc/sysv/consts/fd.h" +#include "libc/sysv/consts/ip.h" +#include "libc/sysv/consts/ipproto.h" +#include "libc/sysv/consts/lock.h" +#include "libc/sysv/consts/madv.h" +#include "libc/sysv/consts/map.h" +#include "libc/sysv/consts/msync.h" +#include "libc/sysv/consts/o.h" +#include "libc/sysv/consts/ok.h" +#include "libc/sysv/consts/rusage.h" +#include "libc/sysv/consts/sicode.h" +#include "libc/sysv/consts/sig.h" +#include "libc/sysv/consts/so.h" +#include "libc/sysv/consts/sock.h" +#include "libc/sysv/consts/sol.h" +#include "libc/sysv/consts/tcp.h" +#include "libc/sysv/consts/termios.h" +#include "libc/sysv/consts/w.h" +#include "libc/sysv/errfuns.h" +#include "tool/build/lib/case.h" +#include "tool/build/lib/endian.h" +#include "tool/build/lib/xlat.h" + +#define XLAT(x, y) CASE(x, return y) + +int XlatSignal(int x) { + switch (x) { + XLAT(1, SIGHUP); + XLAT(2, SIGINT); + XLAT(3, SIGQUIT); + XLAT(4, SIGILL); + XLAT(5, SIGTRAP); + XLAT(6, SIGABRT); + XLAT(7, SIGBUS); + XLAT(8, SIGFPE); + XLAT(9, SIGKILL); + XLAT(10, SIGUSR1); + XLAT(11, SIGSEGV); + XLAT(12, SIGUSR2); + XLAT(13, SIGPIPE); + XLAT(14, SIGALRM); + XLAT(15, SIGTERM); + XLAT(17, SIGCHLD); + XLAT(18, SIGCONT); + XLAT(21, SIGTTIN); + XLAT(22, SIGTTOU); + XLAT(24, SIGXCPU); + XLAT(25, SIGXFSZ); + XLAT(26, SIGVTALRM); + XLAT(27, SIGPROF); + XLAT(28, SIGWINCH); + XLAT(29, SIGIO); + XLAT(19, SIGSTOP); + XLAT(31, SIGSYS); + XLAT(20, SIGTSTP); + XLAT(23, SIGURG); + default: + return einval(); + } +} + +int UnXlatSignal(int x) { + if (x == SIGHUP) return 1; + if (x == SIGINT) return 2; + if (x == SIGQUIT) return 3; + if (x == SIGILL) return 4; + if (x == SIGTRAP) return 5; + if (x == SIGABRT) return 6; + if (x == SIGBUS) return 7; + if (x == SIGFPE) return 8; + if (x == SIGKILL) return 9; + if (x == SIGUSR1) return 10; + if (x == SIGSEGV) return 11; + if (x == SIGUSR2) return 12; + if (x == SIGPIPE) return 13; + if (x == SIGALRM) return 14; + if (x == SIGTERM) return 15; + if (x == SIGCHLD) return 17; + if (x == SIGCONT) return 18; + if (x == SIGTTIN) return 21; + if (x == SIGTTOU) return 22; + if (x == SIGXCPU) return 24; + if (x == SIGXFSZ) return 25; + if (x == SIGVTALRM) return 26; + if (x == SIGPROF) return 27; + if (x == SIGWINCH) return 28; + if (x == SIGIO) return 29; + if (x == SIGSTOP) return 19; + if (x == SIGSYS) return 31; + if (x == SIGTSTP) return 20; + if (x == SIGURG) return 23; + return 15; +} + +int UnXlatSicode(int sig, int code) { + if (code == SI_USER) return 0; + if (code == SI_QUEUE) return -1; + if (code == SI_TIMER) return -2; + if (code == SI_TKILL) return -6; + if (code == SI_MESGQ) return -3; + if (code == SI_ASYNCIO) return -4; + if (code == SI_ASYNCNL) return -60; + if (code == SI_KERNEL) return 0x80; + if (sig == SIGCHLD) { + if (code == CLD_EXITED) return 1; + if (code == CLD_KILLED) return 2; + if (code == CLD_DUMPED) return 3; + if (code == CLD_TRAPPED) return 4; + if (code == CLD_STOPPED) return 5; + if (code == CLD_CONTINUED) return 6; + return -1; + } + if (sig == SIGTRAP) { + if (code == TRAP_BRKPT) return 1; + if (code == TRAP_TRACE) return 2; + return -1; + } + if (sig == SIGSEGV) { + if (code == SEGV_MAPERR) return 1; + if (code == SEGV_ACCERR) return 2; + return -1; + } + if (sig == SIGFPE) { + if (code == FPE_INTDIV) return 1; + if (code == FPE_INTOVF) return 2; + if (code == FPE_FLTDIV) return 3; + if (code == FPE_FLTOVF) return 4; + if (code == FPE_FLTUND) return 5; + if (code == FPE_FLTRES) return 6; + if (code == FPE_FLTINV) return 7; + if (code == FPE_FLTSUB) return 8; + return -1; + } + if (sig == SIGILL) { + if (code == ILL_ILLOPC) return 1; + if (code == ILL_ILLOPN) return 2; + if (code == ILL_ILLADR) return 3; + if (code == ILL_ILLTRP) return 4; + if (code == ILL_PRVOPC) return 5; + if (code == ILL_PRVREG) return 6; + if (code == ILL_COPROC) return 7; + if (code == ILL_BADSTK) return 8; + return -1; + } + if (sig == SIGBUS) { + if (code == BUS_ADRALN) return 1; + if (code == BUS_ADRERR) return 2; + if (code == BUS_OBJERR) return 3; + if (code == BUS_MCEERR_AR) return 4; + if (code == BUS_MCEERR_AO) return 5; + return -1; + } + if (sig == SIGIO) { + if (code == POLL_IN) return 1; + if (code == POLL_OUT) return 2; + if (code == POLL_MSG) return 3; + if (code == POLL_ERR) return 4; + if (code == POLL_PRI) return 5; + if (code == POLL_HUP) return 6; + return -1; + } + return -1; +} + +int XlatSig(int x) { + switch (x) { + XLAT(0, SIG_BLOCK); + XLAT(1, SIG_UNBLOCK); + XLAT(2, SIG_SETMASK); + default: + return einval(); + } +} + +int XlatRusage(int x) { + switch (x) { + XLAT(0, RUSAGE_SELF); + XLAT(-1, RUSAGE_CHILDREN); + XLAT(1, RUSAGE_THREAD); + default: + return einval(); + } +} + +int XlatSocketFamily(int x) { + switch (x) { + XLAT(0, AF_UNSPEC); + XLAT(1, AF_UNIX); + XLAT(2, AF_INET); + default: + errno = EPFNOSUPPORT; + return -1; + } +} + +int UnXlatSocketFamily(int x) { + switch (x) { + XLAT(AF_UNSPEC, 0); + XLAT(AF_UNIX, 1); + XLAT(AF_INET, 2); + default: + return x; + } +} + +int XlatSocketType(int x) { + switch (x) { + XLAT(1, SOCK_STREAM); + XLAT(2, SOCK_DGRAM); + default: + return einval(); + } +} + +int XlatSocketFlags(int flags) { + unsigned res = 0; + if (flags & 0x080000) res |= SOCK_CLOEXEC; + if (flags & 0x000800) res |= SOCK_NONBLOCK; + return res; +} + +int XlatSocketProtocol(int x) { + switch (x) { + XLAT(0, 0); + XLAT(6, IPPROTO_TCP); + XLAT(17, IPPROTO_UDP); + default: + return einval(); + } +} + +int XlatSocketLevel(int level) { + switch (level) { + XLAT(0, SOL_IP); + XLAT(1, SOL_SOCKET); + XLAT(6, SOL_TCP); + XLAT(17, SOL_UDP); + default: + return einval(); + } +} + +int XlatSocketOptname(int level, int optname) { + if (level == SOL_SOCKET) { + switch (optname) { + XLAT(1, SO_DEBUG); + XLAT(2, SO_REUSEADDR); + XLAT(3, SO_TYPE); + XLAT(4, SO_ERROR); + XLAT(5, SO_DONTROUTE); + XLAT(6, SO_BROADCAST); + XLAT(7, SO_SNDBUF); + XLAT(8, SO_RCVBUF); + XLAT(9, SO_KEEPALIVE); + XLAT(13, SO_LINGER); + XLAT(15, SO_REUSEPORT); + XLAT(18, SO_RCVLOWAT); + XLAT(19, SO_SNDLOWAT); + XLAT(30, SO_ACCEPTCONN); + default: + return einval(); + } + } + if (level == SOL_TCP) { + switch (optname) { + XLAT(1, TCP_NODELAY); + XLAT(2, TCP_MAXSEG); +#if defined(TCP_CORK) + XLAT(3, TCP_CORK); +#elif defined(TCP_NOPUSH) + XLAT(3, TCP_NOPUSH); +#endif +#ifdef TCP_KEEPIDLE + XLAT(4, TCP_KEEPIDLE); +#endif +#ifdef TCP_KEEPINTVL + XLAT(5, TCP_KEEPINTVL); +#endif +#ifdef TCP_KEEPCNT + XLAT(6, TCP_KEEPCNT); +#endif +#ifdef TCP_SYNCNT + XLAT(7, TCP_SYNCNT); +#endif +#ifdef TCP_WINDOW_CLAMP + XLAT(10, TCP_WINDOW_CLAMP); +#endif +#ifdef TCP_FASTOPEN + XLAT(23, TCP_FASTOPEN); +#endif +#ifdef TCP_QUICKACK + XLAT(12, TCP_QUICKACK); +#endif +#ifdef TCP_NOTSENT_LOWAT + XLAT(25, TCP_NOTSENT_LOWAT); +#endif +#ifdef TCP_SAVE_SYN + XLAT(27, TCP_SAVE_SYN); +#endif +#ifdef TCP_FASTOPEN_CONNECT + XLAT(30, TCP_FASTOPEN_CONNECT); +#endif + default: + return einval(); + } + } + if (level == SOL_IP) { + switch (optname) { + XLAT(1, IP_TOS); + XLAT(2, IP_TTL); + XLAT(3, IP_HDRINCL); + XLAT(14, IP_MTU); + default: + return einval(); + } + } + return einval(); +} + +int XlatAccess(int x) { + int r = F_OK; + if (x & 1) r |= X_OK; + if (x & 2) r |= W_OK; + if (x & 4) r |= R_OK; + return r; +} + +int XlatLock(int x) { + int r = 0; + if (x & 1) r |= LOCK_SH; + if (x & 2) r |= LOCK_EX; + if (x & 4) r |= LOCK_NB; + if (x & 8) r |= LOCK_UN; + return r; +} + +int XlatWait(int x) { + int r = 0; + if (x & 1) r |= WNOHANG; + if (x & 2) r |= WUNTRACED; + if (x & 8) r |= WCONTINUED; + return r; +} + +int XlatMapFlags(int x) { + int r = 0; + if (x & 1) r |= MAP_SHARED; + if (x & 2) r |= MAP_PRIVATE; + if (x & 16) r |= MAP_FIXED; + if (x & 32) r |= MAP_ANONYMOUS; + if (x & 256) r |= MAP_GROWSDOWN; + return r; +} + +int XlatMsyncFlags(int x) { + unsigned res = 0; + if (x & 1) res |= MS_ASYNC; + if (x & 2) res |= MS_INVALIDATE; + if (x & 4) res |= MS_SYNC; + return res; +} + +int XlatClock(int x) { + switch (x) { + XLAT(0, CLOCK_REALTIME); + XLAT(1, CLOCK_MONOTONIC); + XLAT(2, CLOCK_PROCESS_CPUTIME_ID); +#ifdef CLOCK_MONOTONIC_RAW + XLAT(4, CLOCK_MONOTONIC_RAW); +#endif + default: + return x; + } +} + +int XlatAtf(int x) { + int res = 0; + if (x & 0x0100) res |= AT_SYMLINK_NOFOLLOW; + if (x & 0x0200) res |= AT_REMOVEDIR; + if (x & 0x0400) res |= AT_SYMLINK_FOLLOW; + if (x & 0x1000) res |= AT_EMPTY_PATH; + return res; +} + +int XlatOpenMode(int flags) { + switch (flags & 3) { + case 0: + return O_RDONLY; + case 1: + return O_WRONLY; + case 2: + return O_RDWR; + default: + for (;;) (void)0; + } +} + +int XlatOpenFlags(int flags) { + int res; + res = XlatOpenMode(flags); + if (flags & 0x00400) res |= O_APPEND; + if (flags & 0x00040) res |= O_CREAT; + if (flags & 0x00080) res |= O_EXCL; + if (flags & 0x00200) res |= O_TRUNC; + if (flags & 0x00800) res |= O_NDELAY; + if (flags & 0x04000) res |= O_DIRECT; + if (flags & 0x10000) res |= O_DIRECTORY; + if (flags & 0x20000) res |= O_NOFOLLOW; + if (flags & 0x80000) res |= O_CLOEXEC; + if (flags & 0x00100) res |= O_NOCTTY; +#ifdef O_ASYNC + if (flags & 0x02000) res |= O_ASYNC; +#endif +#ifdef O_NOATIME + if (flags & 0x40000) res |= O_NOATIME; +#endif +#ifdef O_DSYNC + if (flags & 0x000001000) res |= O_DSYNC; +#endif +#ifdef O_SYNC + if ((flags & 0x00101000) == 0x00101000) res |= O_SYNC; +#endif + return res; +} + +int XlatFcntlCmd(int x) { + switch (x) { + XLAT(1, F_GETFD); + XLAT(2, F_SETFD); + XLAT(3, F_GETFL); + XLAT(4, F_SETFL); + default: + return einval(); + } +} + +int XlatFcntlArg(int x) { + switch (x) { + XLAT(0, 0); + XLAT(1, FD_CLOEXEC); + XLAT(0x0800, O_NONBLOCK); + default: + return einval(); + } +} + +int XlatAdvice(int x) { + switch (x) { + XLAT(0, MADV_NORMAL); + XLAT(1, MADV_RANDOM); + XLAT(2, MADV_SEQUENTIAL); + XLAT(3, MADV_WILLNEED); + XLAT(4, MADV_DONTNEED); + XLAT(8, MADV_FREE); + XLAT(12, MADV_MERGEABLE); + default: + return einval(); + } +} + +void XlatSockaddrToHost(struct sockaddr_in *dst, + const struct sockaddr_in_bits *src) { + memset(dst, 0, sizeof(*dst)); + dst->sin_family = XlatSocketFamily(Read16(src->sin_family)); + dst->sin_port = src->sin_port; + dst->sin_addr.s_addr = src->sin_addr; +} + +void XlatSockaddrToLinux(struct sockaddr_in_bits *dst, + const struct sockaddr_in *src) { + memset(dst, 0, sizeof(*dst)); + Write16(dst->sin_family, UnXlatSocketFamily(src->sin_family)); + dst->sin_port = src->sin_port; + dst->sin_addr = src->sin_addr.s_addr; +} + +void XlatStatToLinux(struct stat_bits *dst, const struct stat *src) { + Write64(dst->st_dev, src->st_dev); + Write64(dst->st_ino, src->st_ino); + Write64(dst->st_nlink, src->st_nlink); + Write32(dst->st_mode, src->st_mode); + Write32(dst->st_uid, src->st_uid); + Write32(dst->st_gid, src->st_gid); + Write32(dst->__pad, 0); + Write64(dst->st_rdev, src->st_rdev); + Write64(dst->st_size, src->st_size); + Write64(dst->st_blksize, src->st_blksize); + Write64(dst->st_blocks, src->st_blocks); + Write64(dst->st_dev, src->st_dev); + Write64(dst->st_atim.tv_sec, src->st_atim.tv_sec); + Write64(dst->st_atim.tv_nsec, src->st_atim.tv_nsec); + Write64(dst->st_mtim.tv_sec, src->st_mtim.tv_sec); + Write64(dst->st_mtim.tv_nsec, src->st_mtim.tv_nsec); + Write64(dst->st_ctim.tv_sec, src->st_ctim.tv_sec); + Write64(dst->st_ctim.tv_nsec, src->st_ctim.tv_nsec); +} + +void XlatRusageToLinux(struct rusage_bits *dst, const struct rusage *src) { + Write64(dst->ru_utime.tv_sec, src->ru_utime.tv_sec); + Write64(dst->ru_utime.tv_usec, src->ru_utime.tv_usec); + Write64(dst->ru_stime.tv_sec, src->ru_stime.tv_sec); + Write64(dst->ru_stime.tv_usec, src->ru_stime.tv_usec); + Write64(dst->ru_maxrss, src->ru_maxrss); + Write64(dst->ru_ixrss, src->ru_ixrss); + Write64(dst->ru_idrss, src->ru_idrss); + Write64(dst->ru_isrss, src->ru_isrss); + Write64(dst->ru_minflt, src->ru_minflt); + Write64(dst->ru_majflt, src->ru_majflt); + Write64(dst->ru_nswap, src->ru_nswap); + Write64(dst->ru_inblock, src->ru_inblock); + Write64(dst->ru_oublock, src->ru_oublock); + Write64(dst->ru_msgsnd, src->ru_msgsnd); + Write64(dst->ru_msgrcv, src->ru_msgrcv); + Write64(dst->ru_nsignals, src->ru_nsignals); + Write64(dst->ru_nvcsw, src->ru_nvcsw); + Write64(dst->ru_nivcsw, src->ru_nivcsw); +} + +void XlatItimervalToLinux(struct itimerval_bits *dst, + const struct itimerval *src) { + Write64(dst->it_interval.tv_sec, src->it_interval.tv_sec); + Write64(dst->it_interval.tv_usec, src->it_interval.tv_usec); + Write64(dst->it_value.tv_sec, src->it_value.tv_sec); + Write64(dst->it_value.tv_usec, src->it_value.tv_usec); +} + +void XlatLinuxToItimerval(struct itimerval *dst, + const struct itimerval_bits *src) { + dst->it_interval.tv_sec = Read64(src->it_interval.tv_sec); + dst->it_interval.tv_usec = Read64(src->it_interval.tv_usec); + dst->it_value.tv_sec = Read64(src->it_value.tv_sec); + dst->it_value.tv_usec = Read64(src->it_value.tv_usec); +} + +void XlatWinsizeToLinux(struct winsize_bits *dst, const struct winsize *src) { + memset(dst, 0, sizeof(*dst)); + Write16(dst->ws_row, src->ws_row); + Write16(dst->ws_col, src->ws_col); +} + +void XlatSigsetToLinux(uint8_t dst[8], const sigset_t *src) { + int i; + uint64_t x; + for (x = i = 0; i < 64; ++i) { + if (sigismember(src, i + 1)) { + x |= 1ull << i; + } + } + Write64(dst, x); +} + +void XlatLinuxToSigset(sigset_t *dst, const uint8_t src[8]) { + int i; + uint64_t x; + x = Read64(src); + sigemptyset(dst); + for (i = 0; i < 64; ++i) { + if ((1ull << i) & x) { + sigaddset(dst, i + 1); + } + } +} + +static int XlatTermiosCflag(int x) { + int r = 0; + if (x & 0x0001) r |= ISIG; + if (x & 0x0040) r |= CSTOPB; + if (x & 0x0080) r |= CREAD; + if (x & 0x0100) r |= PARENB; + if (x & 0x0200) r |= PARODD; + if (x & 0x0400) r |= HUPCL; + if (x & 0x0800) r |= CLOCAL; + if ((x & 0x0030) == 0x0010) { + r |= CS6; + } else if ((x & 0x0030) == 0x0020) { + r |= CS7; + } else if ((x & 0x0030) == 0x0030) { + r |= CS8; + } + return r; +} + +static int UnXlatTermiosCflag(int x) { + int r = 0; + if (x & ISIG) r |= 0x0001; + if (x & CSTOPB) r |= 0x0040; + if (x & CREAD) r |= 0x0080; + if (x & PARENB) r |= 0x0100; + if (x & PARODD) r |= 0x0200; + if (x & HUPCL) r |= 0x0400; + if (x & CLOCAL) r |= 0x0800; + if ((x & CSIZE) == CS5) { + r |= 0x0000; + } else if ((x & CSIZE) == CS6) { + r |= 0x0010; + } else if ((x & CSIZE) == CS7) { + r |= 0x0020; + } else if ((x & CSIZE) == CS8) { + r |= 0x0030; + } + return r; +} + +static int XlatTermiosLflag(int x) { + int r = 0; + if (x & 0x0001) r |= ISIG; + if (x & 0x0002) r |= ICANON; + if (x & 0x0008) r |= ECHO; + if (x & 0x0010) r |= ECHOE; + if (x & 0x0020) r |= ECHOK; + if (x & 0x0040) r |= ECHONL; + if (x & 0x0080) r |= NOFLSH; + if (x & 0x0100) r |= TOSTOP; + if (x & 0x8000) r |= IEXTEN; +#ifdef ECHOCTL + if (x & 0x0200) r |= ECHOCTL; +#endif +#ifdef ECHOPRT + if (x & 0x0400) r |= ECHOPRT; +#endif +#ifdef ECHOKE + if (x & 0x0800) r |= ECHOKE; +#endif +#ifdef FLUSHO + if (x & 0x1000) r |= FLUSHO; +#endif +#ifdef PENDIN + if (x & 0x4000) r |= PENDIN; +#endif +#ifdef XCASE + if (x & 0x0004) r |= XCASE; +#endif + return r; +} + +static int UnXlatTermiosLflag(int x) { + int r = 0; + if (x & ISIG) r |= 0x0001; + if (x & ICANON) r |= 0x0002; + if (x & ECHO) r |= 0x0008; + if (x & ECHOE) r |= 0x0010; + if (x & ECHOK) r |= 0x0020; + if (x & ECHONL) r |= 0x0040; + if (x & NOFLSH) r |= 0x0080; + if (x & TOSTOP) r |= 0x0100; + if (x & IEXTEN) r |= 0x8000; +#ifdef ECHOCTL + if (x & ECHOCTL) r |= 0x0200; +#endif +#ifdef ECHOPRT + if (x & ECHOPRT) r |= 0x0400; +#endif +#ifdef ECHOKE + if (x & ECHOKE) r |= 0x0800; +#endif +#ifdef FLUSHO + if (x & FLUSHO) r |= 0x1000; +#endif +#ifdef PENDIN + if (x & PENDIN) r |= 0x4000; +#endif +#ifdef XCASE + if (x & XCASE) r |= 0x0004; +#endif + return r; +} + +static int XlatTermiosIflag(int x) { + int r = 0; + if (x & 0x0001) r |= IGNBRK; + if (x & 0x0002) r |= BRKINT; + if (x & 0x0004) r |= IGNPAR; + if (x & 0x0008) r |= PARMRK; + if (x & 0x0010) r |= INPCK; + if (x & 0x0020) r |= ISTRIP; + if (x & 0x0040) r |= INLCR; + if (x & 0x0080) r |= IGNCR; + if (x & 0x0100) r |= ICRNL; + if (x & 0x0400) r |= IXON; + if (x & 0x0800) r |= IXANY; + if (x & 0x1000) r |= IXOFF; +#ifdef IMAXBEL + if (x & 0x2000) r |= IMAXBEL; +#endif +#ifdef IUTF8 + if (x & 0x4000) r |= IUTF8; +#endif +#ifdef IUCLC + if (x & 0x0200) r |= IUCLC; +#endif + return r; +} + +static int UnXlatTermiosIflag(int x) { + int r = 0; + if (x & IGNBRK) r |= 0x0001; + if (x & BRKINT) r |= 0x0002; + if (x & IGNPAR) r |= 0x0004; + if (x & PARMRK) r |= 0x0008; + if (x & INPCK) r |= 0x0010; + if (x & ISTRIP) r |= 0x0020; + if (x & INLCR) r |= 0x0040; + if (x & IGNCR) r |= 0x0080; + if (x & ICRNL) r |= 0x0100; + if (x & IXON) r |= 0x0400; + if (x & IXANY) r |= 0x0800; + if (x & IXOFF) r |= 0x1000; +#ifdef IMAXBEL + if (x & IMAXBEL) r |= 0x2000; +#endif +#ifdef IUTF8 + if (x & IUTF8) r |= 0x4000; +#endif +#ifdef IUCLC + if (x & IUCLC) r |= 0x0200; +#endif + return r; +} + +static int XlatTermiosOflag(int x) { + int r = 0; + if (x & 0x0001) r |= OPOST; +#ifdef ONLCR + if (x & 0x0004) r |= ONLCR; +#endif +#ifdef OCRNL + if (x & 0x0008) r |= OCRNL; +#endif +#ifdef ONOCR + if (x & 0x0010) r |= ONOCR; +#endif +#ifdef ONLRET + if (x & 0x0020) r |= ONLRET; +#endif +#ifdef OFILL + if (x & 0x0040) r |= OFILL; +#endif +#ifdef OFDEL + if (x & 0x0080) r |= OFDEL; +#endif +#ifdef NLDLY + if ((x & 0x0100) == 0x0000) { + r |= NL0; + } else if ((x & 0x0100) == 0x0100) { + r |= NL1; +#ifdef NL2 + } else if ((x & 0x0100) == 0x0000) { + r |= NL2; +#endif +#ifdef NL3 + } else if ((x & 0x0100) == 0x0000) { + r |= NL3; +#endif + } +#endif +#ifdef CRDLY + if ((x & 0x0600) == 0x0000) { + r |= CR0; + } else if ((x & 0x0600) == 0x0200) { + r |= CR1; + } else if ((x & 0x0600) == 0x0400) { + r |= CR2; + } else if ((x & 0x0600) == 0x0600) { + r |= CR3; + } +#endif +#ifdef TABDLY + if ((x & 0x1800) == 0x0000) { + r |= TAB0; +#ifdef TAB1 + } else if ((x & 0x1800) == 0x0800) { + r |= TAB1; +#endif +#ifdef TAB1 + } else if ((x & 0x1800) == 0x1000) { + r |= TAB2; +#endif + } else if ((x & 0x1800) == 0x1800) { + r |= TAB3; + } +#endif +#ifdef BSDLY + if ((x & 0x2000) == 0x0000) { + r |= BS0; + } else if ((x & 0x2000) == 0x2000) { + r |= BS1; + } +#endif +#ifdef VTBDLY + if ((x & 0x4000) == 0x0000) { + r |= VT0; + } else if ((x & 0x4000) == 0x4000) { + r |= VT1; + } +#endif +#ifdef FFBDLY + if ((x & 0x8000) == 0x0000) { + r |= FF0; + } else if ((x & 0x8000) == 0x8000) { + r |= FF1; + } +#endif +#ifdef OLCUC + if (x & 0x0002) r |= OLCUC; +#endif + return r; +} + +static int UnXlatTermiosOflag(int x) { + int r = 0; + if (x & OPOST) r |= 0x0001; +#ifdef ONLCR + if (x & ONLCR) r |= 0x0004; +#endif +#ifdef OCRNL + if (x & OCRNL) r |= 0x0008; +#endif +#ifdef ONOCR + if (x & ONOCR) r |= 0x0010; +#endif +#ifdef ONLRET + if (x & ONLRET) r |= 0x0020; +#endif +#ifdef OFILL + if (x & OFILL) r |= 0x0040; +#endif +#ifdef OFDEL + if (x & OFDEL) r |= 0x0080; +#endif +#ifdef NLDLY + if ((x & NLDLY) == NL0) { + r |= 0x0000; + } else if ((x & NLDLY) == NL1) { + r |= 0x0100; +#ifdef NL2 + } else if ((x & NLDLY) == NL2) { + r |= 0x0000; +#endif +#ifdef NL3 + } else if ((x & NLDLY) == NL3) { + r |= 0x0000; +#endif + } +#endif +#ifdef CRDLY + if ((x & CRDLY) == CR0) { + r |= 0x0000; + } else if ((x & CRDLY) == CR1) { + r |= 0x0200; + } else if ((x & CRDLY) == CR2) { + r |= 0x0400; + } else if ((x & CRDLY) == CR3) { + r |= 0x0600; + } +#endif +#ifdef TABDLY + if ((x & TABDLY) == TAB0) { + r |= 0x0000; +#ifdef TAB1 + } else if ((x & TABDLY) == TAB1) { + r |= 0x0800; +#endif +#ifdef TAB2 + } else if ((x & TABDLY) == TAB2) { + r |= 0x1000; +#endif + } else if ((x & TABDLY) == TAB3) { + r |= 0x1800; + } +#endif +#ifdef BSDLY + if ((x & BSDLY) == BS0) { + r |= 0x0000; + } else if ((x & BSDLY) == BS1) { + r |= 0x2000; + } +#endif +#ifdef VTDLY + if ((x & VTDLY) == VT0) { + r |= 0x0000; + } else if ((x & VTDLY) == VT1) { + r |= 0x4000; + } +#endif +#ifdef FFDLY + if ((x & FFDLY) == FF0) { + r |= 0x0000; + } else if ((x & FFDLY) == FF1) { + r |= 0x8000; + } +#endif +#ifdef OLCUC + if (x & OLCUC) r |= 0x0002; +#endif + return r; +} + +static void XlatTermiosCc(struct termios *dst, const struct termios_bits *src) { + dst->c_cc[VINTR] = src->c_cc[0]; + dst->c_cc[VQUIT] = src->c_cc[1]; + dst->c_cc[VERASE] = src->c_cc[2]; + dst->c_cc[VKILL] = src->c_cc[3]; + dst->c_cc[VEOF] = src->c_cc[4]; + dst->c_cc[VTIME] = src->c_cc[5]; + dst->c_cc[VMIN] = src->c_cc[6]; + dst->c_cc[VSTART] = src->c_cc[8]; + dst->c_cc[VSTOP] = src->c_cc[9]; + dst->c_cc[VSUSP] = src->c_cc[10]; + dst->c_cc[VEOL] = src->c_cc[11]; +#ifdef VSWTC + dst->c_cc[VSWTC] = src->c_cc[7]; +#endif +#ifdef VREPRINT + dst->c_cc[VREPRINT] = src->c_cc[12]; +#endif +#ifdef VDISCARD + dst->c_cc[VDISCARD] = src->c_cc[13]; +#endif +#ifdef VWERASE + dst->c_cc[VWERASE] = src->c_cc[14]; +#endif +#ifdef VLNEXT + dst->c_cc[VLNEXT] = src->c_cc[15]; +#endif +#ifdef VEOL2 + dst->c_cc[VEOL2] = src->c_cc[16]; +#endif +} + +static void UnXlatTermiosCc(struct termios_bits *dst, + const struct termios *src) { + dst->c_cc[0] = src->c_cc[VINTR]; + dst->c_cc[1] = src->c_cc[VQUIT]; + dst->c_cc[2] = src->c_cc[VERASE]; + dst->c_cc[3] = src->c_cc[VKILL]; + dst->c_cc[4] = src->c_cc[VEOF]; + dst->c_cc[5] = src->c_cc[VTIME]; + dst->c_cc[6] = src->c_cc[VMIN]; + dst->c_cc[8] = src->c_cc[VSTART]; + dst->c_cc[9] = src->c_cc[VSTOP]; + dst->c_cc[10] = src->c_cc[VSUSP]; + dst->c_cc[11] = src->c_cc[VEOL]; +#ifdef VSWTC + dst->c_cc[7] = src->c_cc[VSWTC]; +#endif +#ifdef VREPRINT + dst->c_cc[12] = src->c_cc[VREPRINT]; +#endif +#ifdef VDISCARD + dst->c_cc[13] = src->c_cc[VDISCARD]; +#endif +#ifdef VWERASE + dst->c_cc[14] = src->c_cc[VWERASE]; +#endif +#ifdef VLNEXT + dst->c_cc[15] = src->c_cc[VLNEXT]; +#endif +#ifdef VEOL2 + dst->c_cc[16] = src->c_cc[VEOL2]; +#endif +} + +void XlatLinuxToTermios(struct termios *dst, const struct termios_bits *src) { + memset(dst, 0, sizeof(*dst)); + dst->c_iflag = XlatTermiosIflag(Read32(src->c_iflag)); + dst->c_oflag = XlatTermiosOflag(Read32(src->c_oflag)); + dst->c_cflag = XlatTermiosCflag(Read32(src->c_cflag)); + dst->c_lflag = XlatTermiosLflag(Read32(src->c_lflag)); + XlatTermiosCc(dst, src); +} + +void XlatTermiosToLinux(struct termios_bits *dst, const struct termios *src) { + memset(dst, 0, sizeof(*dst)); + Write32(dst->c_iflag, UnXlatTermiosIflag(src->c_iflag)); + Write32(dst->c_oflag, UnXlatTermiosOflag(src->c_oflag)); + Write32(dst->c_cflag, UnXlatTermiosCflag(src->c_cflag)); + Write32(dst->c_lflag, UnXlatTermiosLflag(src->c_lflag)); + UnXlatTermiosCc(dst, src); +} diff --git a/tool/build/lib/xlat.h b/tool/build/lib/xlat.h new file mode 100644 index 000000000..747a4e83c --- /dev/null +++ b/tool/build/lib/xlat.h @@ -0,0 +1,53 @@ +#ifndef COSMOPOLITAN_TOOL_BUILD_LIB_XLAT_H_ +#define COSMOPOLITAN_TOOL_BUILD_LIB_XLAT_H_ +#include "libc/calls/struct/itimerval.h" +#include "libc/calls/struct/rusage.h" +#include "libc/calls/struct/sigset.h" +#include "libc/calls/struct/stat.h" +#include "libc/calls/struct/termios.h" +#include "libc/calls/struct/winsize.h" +#include "libc/sock/struct/sockaddr.h" +#include "tool/build/lib/bits.h" +#if !(__ASSEMBLER__ + __LINKER__ + 0) +COSMOPOLITAN_C_START_ + +int UnXlatSicode(int, int); +int UnXlatSignal(int); +int XlatAccess(int); +int XlatAdvice(int); +int XlatAtf(int); +int XlatClock(int); +int XlatErrno(int); +int XlatFcntlArg(int); +int XlatFcntlCmd(int); +int XlatLock(int); +int XlatMapFlags(int); +int XlatMsyncFlags(int); +int XlatOpenFlags(int); +int XlatOpenMode(int); +int XlatRusage(int); +int XlatSig(int); +int XlatSignal(int); +int XlatSocketFamily(int); +int XlatSocketFlags(int); +int XlatSocketLevel(int); +int XlatSocketOptname(int, int); +int XlatSocketProtocol(int); +int XlatSocketType(int); +int XlatWait(int); + +void XlatSockaddrToHost(struct sockaddr_in *, const struct sockaddr_in_bits *); +void XlatSockaddrToLinux(struct sockaddr_in_bits *, const struct sockaddr_in *); +void XlatStatToLinux(struct stat_bits *, const struct stat *); +void XlatRusageToLinux(struct rusage_bits *, const struct rusage *); +void XlatItimervalToLinux(struct itimerval_bits *, const struct itimerval *); +void XlatLinuxToItimerval(struct itimerval *, const struct itimerval_bits *); +void XlatLinuxToTermios(struct termios *, const struct termios_bits *); +void XlatTermiosToLinux(struct termios_bits *, const struct termios *); +void XlatWinsizeToLinux(struct winsize_bits *, const struct winsize *); +void XlatSigsetToLinux(uint8_t[8], const sigset_t *); +void XlatLinuxToSigset(sigset_t *, const uint8_t[]); + +COSMOPOLITAN_C_END_ +#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ +#endif /* COSMOPOLITAN_TOOL_BUILD_LIB_XLAT_H_ */ diff --git a/tool/build/lib/xlaterrno.h b/tool/build/lib/xlaterrno.h old mode 100644 new mode 100755 index 0632f4e90..e69de29bb --- a/tool/build/lib/xlaterrno.h +++ b/tool/build/lib/xlaterrno.h @@ -1,10 +0,0 @@ -#ifndef COSMOPOLITAN_TOOL_BUILD_LIB_XLATERRNO_H_ -#define COSMOPOLITAN_TOOL_BUILD_LIB_XLATERRNO_H_ -#if !(__ASSEMBLER__ + __LINKER__ + 0) -COSMOPOLITAN_C_START_ - -int XlatErrno(int); - -COSMOPOLITAN_C_END_ -#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ -#endif /* COSMOPOLITAN_TOOL_BUILD_LIB_XLATERRNO_H_ */ diff --git a/tool/net/redbean.c b/tool/net/redbean.c index f269d1f9f..01d78dbe6 100644 --- a/tool/net/redbean.c +++ b/tool/net/redbean.c @@ -16,9 +16,6 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/intrin/atomic.h" -#include "libc/intrin/likely.h" -#include "libc/intrin/safemacros.internal.h" #include "libc/calls/calls.h" #include "libc/calls/ioctl.h" #include "libc/calls/pledge.h" @@ -37,8 +34,10 @@ #include "libc/errno.h" #include "libc/fmt/conv.h" #include "libc/fmt/itoa.h" -#include "libc/intrin/kprintf.h" +#include "libc/intrin/atomic.h" +#include "libc/intrin/likely.h" #include "libc/intrin/nomultics.internal.h" +#include "libc/intrin/safemacros.internal.h" #include "libc/intrin/spinlock.h" #include "libc/log/check.h" #include "libc/log/log.h" @@ -54,7 +53,6 @@ #include "libc/nexgen32e/x86feature.h" #include "libc/nt/enum/fileflagandattributes.h" #include "libc/nt/thread.h" -#include "libc/stdio/rand.h" #include "libc/runtime/clktck.h" #include "libc/runtime/gc.h" #include "libc/runtime/gc.internal.h" @@ -66,6 +64,7 @@ #include "libc/sock/struct/pollfd.h" #include "libc/stdio/append.internal.h" #include "libc/stdio/hex.internal.h" +#include "libc/stdio/rand.h" #include "libc/stdio/stdio.h" #include "libc/str/slice.h" #include "libc/sysv/consts/af.h"