mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-02-07 06:53:33 +00:00
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.
This commit is contained in:
parent
8a0a2c0c36
commit
7cf66bc161
48 changed files with 4924 additions and 2046 deletions
|
@ -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) $<
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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, //
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
|
|
|
@ -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_
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
|
|
57
libc/intrin/describeptrace.c
Normal file
57
libc/intrin/describeptrace.c
Normal file
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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)) {
|
||||
|
|
|
@ -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;
|
||||
|
|
348
libc/sock/nointernet.c
Normal file
348
libc/sock/nointernet.c
Normal file
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
2
libc/sysv/calls/__sys_ptrace.s
Normal file
2
libc/sysv/calls/__sys_ptrace.s
Normal file
|
@ -0,0 +1,2 @@
|
|||
.include "o/libc/sysv/macros.internal.inc"
|
||||
.scall __sys_ptrace,0x01a01a01a201a065,globl,hidden
|
|
@ -1,2 +0,0 @@
|
|||
.include "o/libc/sysv/macros.internal.inc"
|
||||
.scall sys_ptrace,0x01a01a01a201a065,globl,hidden
|
|
@ -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
|
||||
|
|
0
test/libc/calls/ptrace_test.c
Normal file
0
test/libc/calls/ptrace_test.c
Normal file
0
test/libc/calls/sys_ptrace_test.c
Normal file
0
test/libc/calls/sys_ptrace_test.c
Normal file
85
test/libc/sock/nointernet_test.c
Normal file
85
test/libc/sock/nointernet_test.c
Normal file
|
@ -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));
|
||||
}
|
|
@ -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"
|
||||
|
|
|
@ -34,6 +34,7 @@ TEST_LIBC_SOCK_DIRECTDEPS = \
|
|||
LIBC_STR \
|
||||
LIBC_STUBS \
|
||||
LIBC_SYSV \
|
||||
LIBC_SYSV_CALLS \
|
||||
LIBC_TESTLIB \
|
||||
LIBC_X \
|
||||
TOOL_DECODE_LIB
|
||||
|
|
|
@ -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) {
|
||||
|
|
1
third_party/make/job.c
vendored
1
third_party/make/job.c
vendored
|
@ -67,6 +67,7 @@ this program. If not, see <http://www.gnu.org/licenses/>. */
|
|||
#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 \
|
||||
|
|
27
third_party/make/main.c
vendored
27
third_party/make/main.c
vendored
|
@ -30,6 +30,21 @@ this program. If not, see <http://www.gnu.org/licenses/>. */
|
|||
#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");
|
||||
|
|
1
third_party/make/make.mk
vendored
1
third_party/make/make.mk
vendored
|
@ -119,6 +119,7 @@ THIRD_PARTY_MAKE_DIRECTDEPS = \
|
|||
LIBC_RUNTIME \
|
||||
LIBC_STDIO \
|
||||
LIBC_STR \
|
||||
LIBC_SOCK \
|
||||
LIBC_SYSV \
|
||||
LIBC_SYSV_CALLS \
|
||||
LIBC_TIME \
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
166
tool/build/lib/bits.h
Executable file
166
tool/build/lib/bits.h
Executable file
|
@ -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_ */
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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) */
|
||||
|
|
49
tool/build/lib/ldbl.c
Normal file
49
tool/build/lib/ldbl.c
Normal file
|
@ -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;
|
||||
}
|
11
tool/build/lib/ldbl.h
Normal file
11
tool/build/lib/ldbl.h
Normal file
|
@ -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_ */
|
|
@ -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;
|
||||
|
|
28
tool/build/lib/pun.h
Normal file
28
tool/build/lib/pun.h
Normal file
|
@ -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_ */
|
165
tool/build/lib/signal.c
Normal file
165
tool/build/lib/signal.c
Normal file
|
@ -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);
|
||||
}
|
||||
}
|
15
tool/build/lib/signal.h
Normal file
15
tool/build/lib/signal.h
Normal file
|
@ -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_ */
|
2213
tool/build/lib/sse.c
2213
tool/build/lib/sse.c
File diff suppressed because it is too large
Load diff
|
@ -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);
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load diff
1002
tool/build/lib/xlat.c
Normal file
1002
tool/build/lib/xlat.c
Normal file
File diff suppressed because it is too large
Load diff
53
tool/build/lib/xlat.h
Normal file
53
tool/build/lib/xlat.h
Normal file
|
@ -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_ */
|
10
tool/build/lib/xlaterrno.h
Normal file → Executable file
10
tool/build/lib/xlaterrno.h
Normal file → Executable file
|
@ -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_ */
|
|
@ -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"
|
||||
|
|
Loading…
Reference in a new issue