diff --git a/ape/ape.S b/ape/ape.S index eedbfb64c..93ab3fae2 100644 --- a/ape/ape.S +++ b/ape/ape.S @@ -1103,8 +1103,8 @@ ape_grub: .align 4 ape_grub_entry: .code32 -/ cmp $GRUB_EAX,%eax -/ jne triplf +// cmp $GRUB_EAX,%eax +// jne triplf push $0 popf mov $0x40,%dl @@ -1426,7 +1426,7 @@ long: push $GDT_LONG_DATA jmp _start .endfn long - .rodata.str1.1 + .rodata .Larg0: .asciz "ape.com" .Lenv0: .asciz "METAL=1" .previous diff --git a/build/config.mk b/build/config.mk index e94573246..9b0e3d399 100644 --- a/build/config.mk +++ b/build/config.mk @@ -95,7 +95,7 @@ CONFIG_COPTS += \ $(SANITIZER) TARGET_ARCH ?= \ - -march=native + -msse3 OVERRIDE_CCFLAGS += \ -fno-pie diff --git a/build/definitions.mk b/build/definitions.mk index 2e3d49ac2..2c5549448 100644 --- a/build/definitions.mk +++ b/build/definitions.mk @@ -166,8 +166,7 @@ DEFAULT_LDFLAGS = \ --gc-sections \ --build-id=none \ --no-dynamic-linker \ - -z max-page-size=0x1000 \ - --cref -Map=$@.map + -z max-page-size=0x1000 ZIPOBJ_FLAGS = \ -b$(IMAGE_BASE_VIRTUAL) diff --git a/examples/ucontext-sigfpe-recovery.c b/examples/ucontext-sigfpe-recovery.c new file mode 100644 index 000000000..0c7c6491d --- /dev/null +++ b/examples/ucontext-sigfpe-recovery.c @@ -0,0 +1,34 @@ +#if 0 +/*─────────────────────────────────────────────────────────────────╗ +│ To the extent possible under law, Justine Tunney has waived │ +│ all copyright and related or neighboring rights to this file, │ +│ as it is written in the following disclaimers: │ +│ • http://unlicense.org/ │ +│ • http://creativecommons.org/publicdomain/zero/1.0/ │ +╚─────────────────────────────────────────────────────────────────*/ +#endif +#include "libc/calls/calls.h" +#include "libc/calls/struct/sigaction.h" +#include "libc/calls/struct/siginfo.h" +#include "libc/calls/ucontext.h" +#include "libc/stdio/stdio.h" +#include "libc/sysv/consts/sa.h" +#include "libc/sysv/consts/sig.h" +#include "third_party/xed/x86.h" + +void handler(int sig, siginfo_t *si, ucontext_t *ctx) { + struct XedDecodedInst xedd; + xed_decoded_inst_zero_set_mode(&xedd, XED_MACHINE_MODE_LONG_64); + xed_instruction_length_decode(&xedd, (void *)ctx->uc_mcontext.rip, 15); + ctx->uc_mcontext.rip += xedd.length; + ctx->uc_mcontext.rax = 42; + ctx->uc_mcontext.rdx = 0; +} + +int main(int argc, char *argv[]) { + struct sigaction saint = {.sa_sigaction = handler, .sa_flags = SA_SIGINFO}; + sigaction(SIGFPE, &saint, NULL); + volatile long x = 0; + printf("123/0 = %ld\n", 123 / x); + return 0; +} diff --git a/libc/calls/calls.h b/libc/calls/calls.h index 240ee3c92..798b04bec 100644 --- a/libc/calls/calls.h +++ b/libc/calls/calls.h @@ -245,9 +245,9 @@ int vdprintf(int, const char *, va_list) paramsnonnull(); void _init_onntconsoleevent(void); void _init_wincrash(void); -#ifndef __SIGACTION -#define __SIGACTION(FN, SIG, ...) \ - ({ \ +#ifndef __SIGACTION_YOINK +#define __SIGACTION_YOINK(SIG) \ + do { \ if (SupportsWindows()) { \ if (__builtin_constant_p(SIG)) { \ switch (SIG) { \ @@ -272,14 +272,23 @@ void _init_wincrash(void); YOINK(_init_wincrash); \ } \ } \ - (FN)(SIG, __VA_ARGS__); \ - }) + } while (0) #endif -#define dprintf(FD, FMT, ...) (dprintf)(FD, PFLINK(FMT), ##__VA_ARGS__) -#define sigaction(SIG, ACT, OLD) __SIGACTION(sigaction, SIG, ACT, OLD) -#define signal(SIG, HAND) __SIGACTION(signal, SIG, HAND) -#define vdprintf(FD, FMT, VA) (vdprintf)(FD, PFLINK(FMT), VA) +#define sigaction(SIG, ACT, OLD) \ + ({ \ + __SIGACTION_YOINK(SIG); \ + sigaction(SIG, (ACT), OLD); \ + }) + +#define signal(SIG, HAND) \ + ({ \ + __SIGACTION_YOINK(SIG); \ + signal(SIG, HAND); \ + }) + +#define dprintf(FD, FMT, ...) (dprintf)(FD, PFLINK(FMT), ##__VA_ARGS__) +#define vdprintf(FD, FMT, VA) (vdprintf)(FD, PFLINK(FMT), VA) #endif /* GNU && !ANSI */ COSMOPOLITAN_C_END_ diff --git a/libc/calls/close.c b/libc/calls/close.c index 65a4eae10..a12f8de9a 100644 --- a/libc/calls/close.c +++ b/libc/calls/close.c @@ -40,8 +40,10 @@ int close(int fd) { if (fd < g_fds.n && g_fds.p[fd].kind == kFdZip) { rc = weaken(__zipos_close)(fd); } else { - if (!IsWindows()) { + if (!IsWindows() && !IsMetal()) { rc = sys_close(fd); + } else if (IsMetal()) { + rc = 0; } else { if (fd < g_fds.n && g_fds.p[fd].kind == kFdEpoll) { rc = weaken(sys_close_epoll_nt)(fd); diff --git a/libc/calls/fstat-metal.c b/libc/calls/fstat-metal.c index 951e8c620..0c2cedd8c 100644 --- a/libc/calls/fstat-metal.c +++ b/libc/calls/fstat-metal.c @@ -22,7 +22,7 @@ #include "libc/sysv/consts/s.h" #include "libc/sysv/errfuns.h" -int fstat_metal(int fd, struct stat *st) { +int sys_fstat_metal(int fd, struct stat *st) { if (fd < 0) return einval(); if (fd < g_fds.n && g_fds.p[fd].kind == kFdSerial) { memset(st, 0, sizeof(*st)); diff --git a/libc/calls/fstat.c b/libc/calls/fstat.c index b6c20fceb..0d5a0290e 100644 --- a/libc/calls/fstat.c +++ b/libc/calls/fstat.c @@ -34,7 +34,7 @@ int fstat(int fd, struct stat *st) { } else if (!IsWindows() && !IsMetal()) { return sys_fstat(fd, st); } else if (IsMetal()) { - return fstat_metal(fd, st); + return sys_fstat_metal(fd, st); } else { if (!__isfdkind(fd, kFdFile)) return ebadf(); return sys_fstat_nt(g_fds.p[fd].handle, st); diff --git a/libc/calls/gettimeofday.c b/libc/calls/gettimeofday.c index 81531d728..e02ed40ae 100644 --- a/libc/calls/gettimeofday.c +++ b/libc/calls/gettimeofday.c @@ -35,7 +35,7 @@ */ int gettimeofday(struct timeval *tv, struct timezone *tz) { axdx_t ad; - if (!IsWindows()) { + if (!IsWindows() && !IsMetal()) { ad = sys_gettimeofday(tv, tz, NULL); assert(ad.ax != -1); if (SupportsXnu() && ad.ax && tv) { @@ -43,6 +43,8 @@ int gettimeofday(struct timeval *tv, struct timezone *tz) { tv->tv_usec = ad.dx; } return 0; + } else if (IsMetal()) { + return enosys(); } else { return sys_gettimeofday_nt(tv, tz); } diff --git a/libc/calls/internal.h b/libc/calls/internal.h index 057120d9f..caffaa84b 100644 --- a/libc/calls/internal.h +++ b/libc/calls/internal.h @@ -206,17 +206,15 @@ void sys_exit(int) hidden; ╚────────────────────────────────────────────────────────────────────────────│*/ void __onfork(void) hidden; -bool32 __sigenter(i32, struct siginfo *, struct ucontext *) hidden; i32 __fixupnewfd(i32, i32) hidden; u32 __prot2nt(i32, i32) privileged; void __restore_rt() hidden; -void __sigenter_xnu(void *, i32, i32, void *, void *) hidden wontreturn; int sys_utimensat_xnu(int, const char *, const struct timespec *, int) hidden; int sys_nanosleep_xnu(const struct timespec *, struct timespec *) hidden; void __stat2linux(void *) hidden; void __restore_rt_netbsd(void) hidden; -void __xnutrampoline(void *, i32, i32, const struct __darwin_siginfo *, - const struct __darwin_ucontext *) hidden wontreturn; +void __sigenter_xnu(void *, i32, i32, struct __darwin_siginfo *, + struct __darwin_ucontext *) hidden; int gethostname_linux(char *, size_t) hidden; int gethostname_bsd(char *, size_t) hidden; int gethostname_nt(char *, size_t) hidden; @@ -288,19 +286,24 @@ int __mkntpath(const char *, char16_t[hasatleast PATH_MAX - 16]) hidden; int __mkntpath2(const char *, char16_t[hasatleast PATH_MAX - 16], int) hidden; int __mkntpathat(int, const char *, int, char16_t[PATH_MAX]) hidden; unsigned __wincrash_nt(struct NtExceptionPointers *); +ssize_t sys_readv_nt(struct Fd *, const struct iovec *, int) hidden; +ssize_t sys_writev_nt(struct Fd *, const struct iovec *, int) hidden; /*───────────────────────────────────────────────────────────────────────────│─╗ │ cosmopolitan § syscalls » metal ─╬─│┼ ╚────────────────────────────────────────────────────────────────────────────│*/ -int fstat_metal(int, struct stat *); +int sys_fstat_metal(int, struct stat *); +int sys_openat_metal(int, const char *, int, unsigned); +ssize_t sys_readv_metal(struct Fd *, const struct iovec *, int) hidden; +ssize_t sys_writev_metal(struct Fd *, const struct iovec *, int) hidden; /*───────────────────────────────────────────────────────────────────────────│─╗ │ cosmopolitan § syscalls » drivers ─╬─│┼ ╚────────────────────────────────────────────────────────────────────────────│*/ -ssize_t readv_serial(struct Fd *, const struct iovec *, int) hidden; -ssize_t writev_serial(struct Fd *, const struct iovec *, int) hidden; +ssize_t sys_readv_serial(struct Fd *, const struct iovec *, int) hidden; +ssize_t sys_writev_serial(struct Fd *, const struct iovec *, int) hidden; #undef sigset #undef i32 diff --git a/libc/calls/metalfile.internal.h b/libc/calls/metalfile.internal.h new file mode 100644 index 000000000..236fed09d --- /dev/null +++ b/libc/calls/metalfile.internal.h @@ -0,0 +1,14 @@ +#ifndef COSMOPOLITAN_LIBC_CALLS_METALFILE_INTERNAL_H_ +#define COSMOPOLITAN_LIBC_CALLS_METALFILE_INTERNAL_H_ +#if !(__ASSEMBLER__ + __LINKER__ + 0) +COSMOPOLITAN_C_START_ + +struct MetalFile { + char *base; + size_t size; + size_t pos; +}; + +COSMOPOLITAN_C_END_ +#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ +#endif /* COSMOPOLITAN_LIBC_CALLS_METALFILE_INTERNAL_H_ */ diff --git a/libc/calls/openat-metal.c b/libc/calls/openat-metal.c new file mode 100644 index 000000000..2d83914ca --- /dev/null +++ b/libc/calls/openat-metal.c @@ -0,0 +1,40 @@ +/*-*- 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 │ +│ │ +│ 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/bits/weaken.h" +#include "libc/calls/internal.h" +#include "libc/calls/metalfile.internal.h" +#include "libc/mem/mem.h" +#include "libc/runtime/runtime.h" +#include "libc/str/str.h" +#include "libc/sysv/errfuns.h" + +int sys_openat_metal(int dirfd, const char *file, int flags, unsigned mode) { + int fd; + struct MetalFile *state; + if (strcmp(file, "ape.com")) return enoent(); + if (!weaken(calloc)) return enomem(); + if ((fd = __reservefd()) == -1) return -1; + state = weaken(calloc)(1, sizeof(struct MetalFile)); + state->base = (char *)_base; + state->size = _end - _base; + g_fds.p[fd].kind = kFdFile; + g_fds.p[fd].flags = flags; + g_fds.p[fd].handle = (intptr_t)state; + return fd; +} diff --git a/libc/calls/openat.c b/libc/calls/openat.c index 6816371a8..98bf4728c 100644 --- a/libc/calls/openat.c +++ b/libc/calls/openat.c @@ -51,8 +51,10 @@ int openat(int dirfd, const char *file, int flags, ...) { if (__vforked) return einval(); if (dirfd != AT_FDCWD) return einval(); return weaken(__zipos_open)(&zipname, flags, mode); - } else if (!IsWindows()) { + } else if (!IsWindows() && !IsMetal()) { return sys_openat(dirfd, file, flags, mode); + } else if (IsMetal()) { + return sys_openat_metal(dirfd, file, flags, mode); } else { return sys_open_nt(dirfd, file, flags, mode); } diff --git a/libc/calls/sigenter.S b/libc/calls/readv-metal.c similarity index 65% rename from libc/calls/sigenter.S rename to libc/calls/readv-metal.c index 1aa27b96b..d105ebc5f 100644 --- a/libc/calls/sigenter.S +++ b/libc/calls/readv-metal.c @@ -1,7 +1,7 @@ -/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│ -│vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi│ +/*-*- 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 2021 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 │ @@ -17,32 +17,27 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/internal.h" +#include "libc/calls/metalfile.internal.h" #include "libc/macros.h" -.source __FILE__ +#include "libc/str/str.h" +#include "libc/sysv/errfuns.h" -// BSD signal handler. -// -// This is needed because (1) a signal is allowed to trigger at -// just about any time, and leaf functions (e.g. memcpy) aren't -// required to leave Cosmopolitan's image base register alone. -// -// @param %edi is the signal number -// @param %rsi will be passed for sigactions -// @param %rdx will be passed for sigactions -// @return true if handler was invoked -__sigenter: - push %rbp - mov %rsp,%rbp - .profilable - and $NSIG-1,%edi - mov __sighandrvas(,%rdi,4),%eax - cmp $kSigactionMinRva,%eax - jl 2f - lea _base(%rax),%eax - call *%rax - mov $1,%eax -1: leave - ret -2: xor %eax,%eax - jmp 1b - .endfn __sigenter,globl,hidden +ssize_t sys_readv_metal(struct Fd *fd, const struct iovec *iov, int iovlen) { + int i; + size_t got, toto; + struct MetalFile *file; + switch (fd->kind) { + case kFdSerial: + return sys_readv_serial(fd, iov, iovlen); + case kFdFile: + file = (struct MetalFile *)fd->handle; + for (toto = i = 0; i < iovlen && file->pos < file->size; ++i) { + got = MIN(iov[i].iov_len, file->size - file->pos); + memcpy(iov[i].iov_base, file->base, got); + toto += got; + } + return toto; + default: + return ebadf(); + } +} diff --git a/libc/calls/readv-nt.c b/libc/calls/readv-nt.c new file mode 100644 index 000000000..1cc9d56c8 --- /dev/null +++ b/libc/calls/readv-nt.c @@ -0,0 +1,35 @@ +/*-*- 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 │ +│ │ +│ 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/bits/weaken.h" +#include "libc/calls/internal.h" +#include "libc/sock/internal.h" +#include "libc/sysv/errfuns.h" + +textwindows ssize_t sys_readv_nt(struct Fd *fd, const struct iovec *iov, + int iovlen) { + switch (fd->kind) { + case kFdFile: + case kFdConsole: + return sys_read_nt(fd, iov, iovlen, -1); + case kFdSocket: + return weaken(sys_recvfrom_nt)(fd, iov, iovlen, 0, NULL, 0); + default: + return ebadf(); + } +} diff --git a/libc/calls/readv-serial.c b/libc/calls/readv-serial.c index 46dfa5db5..f60993f18 100644 --- a/libc/calls/readv-serial.c +++ b/libc/calls/readv-serial.c @@ -34,7 +34,7 @@ static int GetFirstIov(struct iovec *iov, int iovlen) { return -1; } -ssize_t readv_serial(struct Fd *fd, const struct iovec *iov, int iovlen) { +ssize_t sys_readv_serial(struct Fd *fd, const struct iovec *iov, int iovlen) { size_t i, j, got = 0; if ((i = GetFirstIov(iov, iovlen)) != -1) { while (!IsDataAvailable(fd)) asm("pause"); diff --git a/libc/calls/readv.c b/libc/calls/readv.c index a7e525d34..24212c202 100644 --- a/libc/calls/readv.c +++ b/libc/calls/readv.c @@ -36,16 +36,13 @@ ssize_t readv(int fd, const struct iovec *iov, int iovlen) { if (fd < g_fds.n && g_fds.p[fd].kind == kFdZip) { return weaken(__zipos_read)( (struct ZiposHandle *)(intptr_t)g_fds.p[fd].handle, iov, iovlen, -1); - } else if (SupportsMetal() && fd < g_fds.n && g_fds.p[fd].kind == kFdSerial) { - return readv_serial(&g_fds.p[fd], iov, iovlen); - } else if (!IsWindows()) { + } else if (!IsWindows() && !IsMetal()) { return sys_readv(fd, iov, iovlen); - } else if (fd < g_fds.n && - (g_fds.p[fd].kind == kFdFile || g_fds.p[fd].kind == kFdConsole)) { - return sys_read_nt(&g_fds.p[fd], iov, iovlen, -1); - } else if (fd < g_fds.n && (g_fds.p[fd].kind == kFdSocket)) { - return weaken(sys_recvfrom_nt)(&g_fds.p[fd], iov, iovlen, 0, NULL, 0); - } else { + } else if (fd >= g_fds.n) { return ebadf(); + } else if (IsMetal()) { + return sys_readv_metal(g_fds.p + fd, iov, iovlen); + } else { + return sys_readv_nt(g_fds.p + fd, iov, iovlen); } } diff --git a/libc/calls/sigaction.c b/libc/calls/sigaction.c index fbdda5854..f57ae69bc 100644 --- a/libc/calls/sigaction.c +++ b/libc/calls/sigaction.c @@ -39,16 +39,6 @@ #include "libc/sysv/consts/sig.h" #include "libc/sysv/errfuns.h" -union metasigaction { - struct sigaction cosmo; - struct sigaction_linux linux; - struct sigaction_freebsd freebsd; - struct sigaction_openbsd openbsd; - struct sigaction_netbsd netbsd; - struct sigaction_xnu_in xnu_in; - struct sigaction_xnu_out xnu_out; -}; - #ifndef SWITCHEROO #define SWITCHEROO(S1, S2, A, B, C, D) \ do { \ @@ -66,6 +56,20 @@ union metasigaction { } while (0); #endif +union metasigaction { + struct sigaction cosmo; + struct sigaction_linux linux; + struct sigaction_freebsd freebsd; + struct sigaction_openbsd openbsd; + struct sigaction_netbsd netbsd; + struct sigaction_xnu_in xnu_in; + struct sigaction_xnu_out xnu_out; +}; + +void __sigenter_netbsd(int, void *, void *); +void __sigenter_freebsd(int, void *, void *); +void __sigenter_openbsd(int, void *, void *); + static void sigaction_cosmo2native(union metasigaction *sa) { if (!sa) return; switch (__hostos) { @@ -165,17 +169,21 @@ int(sigaction)(int sig, const struct sigaction *act, struct sigaction *oldact) { memcpy(©, act, sizeof(copy)); ap = © if (IsXnu()) { - ap->sa_restorer = (void *)&__xnutrampoline; - ap->sa_handler = (void *)&__xnutrampoline; + ap->sa_restorer = (void *)&__sigenter_xnu; + ap->sa_handler = (void *)&__sigenter_xnu; } else if (IsLinux()) { if (!(ap->sa_flags & SA_RESTORER)) { ap->sa_flags |= SA_RESTORER; ap->sa_restorer = &__restore_rt; } } else if (IsNetbsd()) { - ap->sa_sigaction = act->sa_sigaction; - } else if (rva >= kSigactionMinRva) { - ap->sa_sigaction = (sigaction_f)__sigenter; + ap->sa_sigaction = (sigaction_f)__sigenter_netbsd; + } else if (IsFreebsd()) { + ap->sa_sigaction = (sigaction_f)__sigenter_freebsd; + } else if (IsOpenbsd()) { + ap->sa_sigaction = (sigaction_f)__sigenter_openbsd; + } else { + return enosys(); } sigaction_cosmo2native((union metasigaction *)ap); } else { diff --git a/libc/calls/sigenter-freebsd.c b/libc/calls/sigenter-freebsd.c new file mode 100644 index 000000000..9e74230bc --- /dev/null +++ b/libc/calls/sigenter-freebsd.c @@ -0,0 +1,196 @@ +/*-*- 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 │ +│ │ +│ 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/internal.h" +#include "libc/calls/struct/sigaction-freebsd.internal.h" +#include "libc/calls/struct/siginfo.h" +#include "libc/calls/typedef/sigaction_f.h" +#include "libc/calls/ucontext.h" +#include "libc/macros.h" +#include "libc/str/str.h" + +union sigval_freebsd { + int32_t sival_int; + void *sival_ptr; + int32_t sigval_int; + void *sigval_ptr; +}; + +struct siginfo_freebsd { + int32_t si_signo; + int32_t si_errno; + int32_t si_code; + int32_t si_pid; + uint32_t si_uid; + int32_t si_status; + void *si_addr; + union sigval_freebsd si_value; + union { + struct { + int _trapno; + } _fault; + struct { + int _timerid; + int _overrun; + } _timer; + struct { + int _mqd; + } _mesgq; + struct { + long _band; + } _poll; + struct { + long __spare1__; + int __spare2__[7]; + } __spare__; + } _reason; +}; + +struct stack_freebsd { + void *ss_sp; + uint64_t ss_size; + int32_t ss_flags; +}; + +struct mcontext_freebsd { + int64_t mc_onstack; + int64_t mc_rdi; + int64_t mc_rsi; + int64_t mc_rdx; + int64_t mc_rcx; + int64_t mc_r8; + int64_t mc_r9; + int64_t mc_rax; + int64_t mc_rbx; + int64_t mc_rbp; + int64_t mc_r10; + int64_t mc_r11; + int64_t mc_r12; + int64_t mc_r13; + int64_t mc_r14; + int64_t mc_r15; + uint32_t mc_trapno; + uint16_t mc_fs; + uint16_t mc_gs; + int64_t mc_addr; + uint32_t mc_flags; + uint16_t mc_es; + uint16_t mc_ds; + int64_t mc_err; + int64_t mc_rip; + int64_t mc_cs; + int64_t mc_rflags; + int64_t mc_rsp; + int64_t mc_ss; + int64_t mc_len; + int64_t mc_fpformat; + int64_t mc_ownedfp; + int64_t mc_fpstate[64]; + int64_t mc_fsbase; + int64_t mc_gsbase; + int64_t mc_xfpustate; + int64_t mc_xfpustate_len; + long mc_spare[4]; +}; + +struct ucontext_freebsd { + struct sigset_freebsd uc_sigmask; + struct mcontext_freebsd uc_mcontext; + struct ucontext_freebsd *uc_link; + struct stack_freebsd uc_stack; + int32_t uc_flags; + int32_t __spare__[4]; +}; + +hidden void __sigenter_freebsd(int sig, struct siginfo_freebsd *si, + struct ucontext_freebsd *ctx) { + int rva; + ucontext_t uc; + rva = __sighandrvas[sig & (NSIG - 1)]; + if (rva >= kSigactionMinRva) { + memset(&uc, 0, sizeof(uc)); + if (ctx) { + uc.uc_mcontext.fpregs = &uc.__fpustate; + uc.uc_stack.ss_sp = ctx->uc_stack.ss_sp; + uc.uc_stack.ss_size = ctx->uc_stack.ss_size; + uc.uc_stack.ss_flags = ctx->uc_stack.ss_flags; + uc.uc_flags = ctx->uc_flags; + memcpy(&uc.uc_sigmask, &ctx->uc_sigmask, + MIN(sizeof(uc.uc_sigmask), sizeof(ctx->uc_sigmask))); + uc.uc_mcontext.rdi = ctx->uc_mcontext.mc_rdi; + uc.uc_mcontext.rsi = ctx->uc_mcontext.mc_rsi; + uc.uc_mcontext.rdx = ctx->uc_mcontext.mc_rdx; + uc.uc_mcontext.rcx = ctx->uc_mcontext.mc_rcx; + uc.uc_mcontext.r8 = ctx->uc_mcontext.mc_r8; + uc.uc_mcontext.r9 = ctx->uc_mcontext.mc_r9; + uc.uc_mcontext.rax = ctx->uc_mcontext.mc_rax; + uc.uc_mcontext.rbx = ctx->uc_mcontext.mc_rbx; + uc.uc_mcontext.rbp = ctx->uc_mcontext.mc_rbp; + uc.uc_mcontext.r10 = ctx->uc_mcontext.mc_r10; + uc.uc_mcontext.r11 = ctx->uc_mcontext.mc_r11; + uc.uc_mcontext.r12 = ctx->uc_mcontext.mc_r12; + uc.uc_mcontext.r13 = ctx->uc_mcontext.mc_r13; + uc.uc_mcontext.r14 = ctx->uc_mcontext.mc_r14; + uc.uc_mcontext.r15 = ctx->uc_mcontext.mc_r15; + uc.uc_mcontext.trapno = ctx->uc_mcontext.mc_trapno; + uc.uc_mcontext.fs = ctx->uc_mcontext.mc_fs; + uc.uc_mcontext.gs = ctx->uc_mcontext.mc_gs; + uc.uc_mcontext.eflags = ctx->uc_mcontext.mc_flags; + uc.uc_mcontext.err = ctx->uc_mcontext.mc_err; + uc.uc_mcontext.rip = ctx->uc_mcontext.mc_rip; + uc.uc_mcontext.rsp = ctx->uc_mcontext.mc_rsp; + } + ((sigaction_f)(_base + rva))(sig, (void *)si, &uc); + if (ctx) { + ctx->uc_stack.ss_sp = uc.uc_stack.ss_sp; + ctx->uc_stack.ss_size = uc.uc_stack.ss_size; + ctx->uc_stack.ss_flags = uc.uc_stack.ss_flags; + ctx->uc_flags = uc.uc_flags; + memcpy(&ctx->uc_sigmask, &uc.uc_sigmask, + MIN(sizeof(uc.uc_sigmask), sizeof(ctx->uc_sigmask))); + ctx->uc_mcontext.mc_rdi = uc.uc_mcontext.rdi; + ctx->uc_mcontext.mc_rsi = uc.uc_mcontext.rsi; + ctx->uc_mcontext.mc_rdx = uc.uc_mcontext.rdx; + ctx->uc_mcontext.mc_rcx = uc.uc_mcontext.rcx; + ctx->uc_mcontext.mc_r8 = uc.uc_mcontext.r8; + ctx->uc_mcontext.mc_r9 = uc.uc_mcontext.r9; + ctx->uc_mcontext.mc_rax = uc.uc_mcontext.rax; + ctx->uc_mcontext.mc_rbx = uc.uc_mcontext.rbx; + ctx->uc_mcontext.mc_rbp = uc.uc_mcontext.rbp; + ctx->uc_mcontext.mc_r10 = uc.uc_mcontext.r10; + ctx->uc_mcontext.mc_r11 = uc.uc_mcontext.r11; + ctx->uc_mcontext.mc_r12 = uc.uc_mcontext.r12; + ctx->uc_mcontext.mc_r13 = uc.uc_mcontext.r13; + ctx->uc_mcontext.mc_r14 = uc.uc_mcontext.r14; + ctx->uc_mcontext.mc_r15 = uc.uc_mcontext.r15; + ctx->uc_mcontext.mc_trapno = uc.uc_mcontext.trapno; + ctx->uc_mcontext.mc_fs = uc.uc_mcontext.fs; + ctx->uc_mcontext.mc_gs = uc.uc_mcontext.gs; + ctx->uc_mcontext.mc_flags = uc.uc_mcontext.eflags; + ctx->uc_mcontext.mc_err = uc.uc_mcontext.err; + ctx->uc_mcontext.mc_rip = uc.uc_mcontext.rip; + ctx->uc_mcontext.mc_rsp = uc.uc_mcontext.rsp; + } + } + /* + * When the FreeBSD kernel invokes this signal handler it pushes a + * trampoline on the stack which does two things: 1) it calls this + * function, and 2) calls sys_sigreturn() once this returns. + */ +} diff --git a/libc/calls/sigenter-netbsd.c b/libc/calls/sigenter-netbsd.c new file mode 100644 index 000000000..283f500d1 --- /dev/null +++ b/libc/calls/sigenter-netbsd.c @@ -0,0 +1,204 @@ +/*-*- 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 │ +│ │ +│ 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/internal.h" +#include "libc/calls/struct/sigaction-freebsd.internal.h" +#include "libc/calls/struct/siginfo.h" +#include "libc/calls/typedef/sigaction_f.h" +#include "libc/calls/ucontext.h" +#include "libc/macros.h" +#include "libc/str/str.h" + +#define RDI 0 +#define RSI 1 +#define RDX 2 +#define R10 6 +#define R8 4 +#define R9 5 +#define RCX 3 +#define R11 7 +#define R12 8 +#define R13 9 +#define R14 10 +#define R15 11 +#define RBP 12 +#define RBX 13 +#define RAX 14 +#define GS 15 +#define FS 16 +#define ES 17 +#define DS 18 +#define TRAP 19 +#define ERR 20 +#define RIP 21 +#define CS 22 +#define RFLAGS 23 +#define RSP 24 +#define SS 25 + +union sigval_netbsd { + int32_t sival_int; + void *sival_ptr; +}; + +struct siginfo_netbsd { + int32_t _signo; + int32_t _code; + int32_t _errno; + int32_t _pad; + union { + struct { + int32_t _pid; + uint32_t _uid; + union sigval_netbsd _value; + } _rt; + struct { + int32_t _pid; + uint32_t _uid; + int32_t _status; + int64_t _utime; + int64_t _stime; + } _child; + struct { + void *_addr; + int32_t _trap; + int32_t _trap2; + int32_t _trap3; + } _fault; + struct { + int64_t _band; + int32_t _fd; + } _poll; + struct { + int32_t _sysnum; + int32_t _retval[2]; + int32_t _error; + uint64_t _args[8]; + } _syscall; + struct { + int32_t _pe_report_event; + union { + int32_t _pe_other_pid; + int32_t _pe_lwp; + } _option; + } _ptrace_state; + } _reason; +}; + +struct sigset_netbsd { + uint32_t __bits[4]; +}; + +struct stack_netbsd { + void *ss_sp; + size_t ss_size; + int32_t ss_flags; +}; + +struct mcontext_netbsd { + int64_t __gregs[26]; + int64_t _mc_tlsbase; + struct FpuState __fpregs; +}; + +struct ucontext_netbsd { + uint32_t uc_flags; + struct ucontext_netbsd *uc_link; + struct sigset_netbsd uc_sigmask; + struct stack_netbsd uc_stack; + struct mcontext_netbsd uc_mcontext; +}; + +hidden void __sigenter_netbsd(int sig, struct siginfo_netbsd *si, + struct ucontext_netbsd *ctx) { + int rva; + ucontext_t uc; + struct siginfo si2; + rva = __sighandrvas[sig & (NSIG - 1)]; + if (rva >= kSigactionMinRva) { + memset(&uc, 0, sizeof(uc)); + memset(&si2, 0, sizeof(si2)); + if (si) { + si2.si_signo = si->_signo; + si2.si_code = si->_code; + si2.si_errno = si->_errno; + } + if (ctx) { + uc.uc_mcontext.fpregs = &uc.__fpustate; + uc.uc_flags = ctx->uc_flags; + uc.uc_stack.ss_sp = ctx->uc_stack.ss_sp; + uc.uc_stack.ss_size = ctx->uc_stack.ss_size; + uc.uc_stack.ss_flags = ctx->uc_stack.ss_flags; + memcpy(&uc.uc_sigmask, &ctx->uc_sigmask, + MIN(sizeof(uc.uc_sigmask), sizeof(ctx->uc_sigmask))); + uc.uc_mcontext.rdi = ctx->uc_mcontext.__gregs[RDI]; + uc.uc_mcontext.rsi = ctx->uc_mcontext.__gregs[RSI]; + uc.uc_mcontext.rdx = ctx->uc_mcontext.__gregs[RDX]; + uc.uc_mcontext.rcx = ctx->uc_mcontext.__gregs[RCX]; + uc.uc_mcontext.r8 = ctx->uc_mcontext.__gregs[R8]; + uc.uc_mcontext.r9 = ctx->uc_mcontext.__gregs[R9]; + uc.uc_mcontext.rax = ctx->uc_mcontext.__gregs[RAX]; + uc.uc_mcontext.rbx = ctx->uc_mcontext.__gregs[RBX]; + uc.uc_mcontext.rbp = ctx->uc_mcontext.__gregs[RBP]; + uc.uc_mcontext.r10 = ctx->uc_mcontext.__gregs[R10]; + uc.uc_mcontext.r11 = ctx->uc_mcontext.__gregs[R11]; + uc.uc_mcontext.r12 = ctx->uc_mcontext.__gregs[R12]; + uc.uc_mcontext.r13 = ctx->uc_mcontext.__gregs[R13]; + uc.uc_mcontext.r14 = ctx->uc_mcontext.__gregs[R14]; + uc.uc_mcontext.r15 = ctx->uc_mcontext.__gregs[R15]; + uc.uc_mcontext.trapno = ctx->uc_mcontext.__gregs[TRAP]; + uc.uc_mcontext.fs = ctx->uc_mcontext.__gregs[FS]; + uc.uc_mcontext.gs = ctx->uc_mcontext.__gregs[GS]; + uc.uc_mcontext.err = ctx->uc_mcontext.__gregs[ERR]; + uc.uc_mcontext.rip = ctx->uc_mcontext.__gregs[RIP]; + uc.uc_mcontext.rsp = ctx->uc_mcontext.__gregs[RSP]; + *uc.uc_mcontext.fpregs = ctx->uc_mcontext.__fpregs; + } + ((sigaction_f)(_base + rva))(sig, &si2, &uc); + if (ctx) { + ctx->uc_mcontext.__gregs[RDI] = uc.uc_mcontext.rdi; + ctx->uc_mcontext.__gregs[RSI] = uc.uc_mcontext.rsi; + ctx->uc_mcontext.__gregs[RDX] = uc.uc_mcontext.rdx; + ctx->uc_mcontext.__gregs[RCX] = uc.uc_mcontext.rcx; + ctx->uc_mcontext.__gregs[R8] = uc.uc_mcontext.r8; + ctx->uc_mcontext.__gregs[R9] = uc.uc_mcontext.r9; + ctx->uc_mcontext.__gregs[RAX] = uc.uc_mcontext.rax; + ctx->uc_mcontext.__gregs[RBX] = uc.uc_mcontext.rbx; + ctx->uc_mcontext.__gregs[RBP] = uc.uc_mcontext.rbp; + ctx->uc_mcontext.__gregs[R10] = uc.uc_mcontext.r10; + ctx->uc_mcontext.__gregs[R11] = uc.uc_mcontext.r11; + ctx->uc_mcontext.__gregs[R12] = uc.uc_mcontext.r12; + ctx->uc_mcontext.__gregs[R13] = uc.uc_mcontext.r13; + ctx->uc_mcontext.__gregs[R14] = uc.uc_mcontext.r14; + ctx->uc_mcontext.__gregs[R15] = uc.uc_mcontext.r15; + ctx->uc_mcontext.__gregs[TRAP] = uc.uc_mcontext.trapno; + ctx->uc_mcontext.__gregs[FS] = uc.uc_mcontext.fs; + ctx->uc_mcontext.__gregs[GS] = uc.uc_mcontext.gs; + ctx->uc_mcontext.__gregs[ERR] = uc.uc_mcontext.err; + ctx->uc_mcontext.__gregs[RIP] = uc.uc_mcontext.rip; + ctx->uc_mcontext.__gregs[RSP] = uc.uc_mcontext.rsp; + ctx->uc_mcontext.__fpregs = *uc.uc_mcontext.fpregs; + } + } + /* + * When the NetBSD kernel invokes this signal handler it pushes a + * trampoline on the stack which does two things: 1) it calls this + * function, and 2) calls sys_sigreturn() once this returns. + */ +} diff --git a/libc/calls/sigenter-openbsd.c b/libc/calls/sigenter-openbsd.c new file mode 100644 index 000000000..b923f2afb --- /dev/null +++ b/libc/calls/sigenter-openbsd.c @@ -0,0 +1,169 @@ +/*-*- 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 │ +│ │ +│ 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/internal.h" +#include "libc/calls/struct/sigaction-freebsd.internal.h" +#include "libc/calls/struct/siginfo.h" +#include "libc/calls/typedef/sigaction_f.h" +#include "libc/calls/ucontext.h" +#include "libc/macros.h" +#include "libc/str/str.h" + +union sigval_openbsd { + int32_t sival_int; + void *sival_ptr; +}; + +struct siginfo_openbsd { + int32_t si_signo; + int32_t si_code; + int32_t si_errno; + union { + int _pad[29]; + struct { + int32_t _pid; + union { + struct { + uint32_t _uid; + union sigval_openbsd _value; + } _kill; + struct { + int64_t _utime; + int64_t _stime; + int32_t _status; + } _cld; + } _pdata; + } _proc; + struct { + void *_addr; + int32_t _trapno; + } _fault; + } _data; +}; + +struct ucontext_openbsd { + int64_t sc_rdi; + int64_t sc_rsi; + int64_t sc_rdx; + int64_t sc_rcx; + int64_t sc_r8; + int64_t sc_r9; + int64_t sc_r10; + int64_t sc_r11; + int64_t sc_r12; + int64_t sc_r13; + int64_t sc_r14; + int64_t sc_r15; + int64_t sc_rbp; + int64_t sc_rbx; + int64_t sc_rax; + int64_t sc_gs; + int64_t sc_fs; + int64_t sc_es; + int64_t sc_ds; + int64_t sc_trapno; + int64_t sc_err; + int64_t sc_rip; + int64_t sc_cs; + int64_t sc_rflags; + int64_t sc_rsp; + int64_t sc_ss; + struct FpuState *sc_fpstate; + int32_t __sc_unused; + int32_t sc_mask; + int64_t sc_cookie; +}; + +hidden void __sigenter_openbsd(int sig, struct siginfo_openbsd *si, + struct ucontext_openbsd *ctx) { + int rva; + ucontext_t uc; + struct siginfo si2; + rva = __sighandrvas[sig & (NSIG - 1)]; + if (rva >= kSigactionMinRva) { + memset(&uc, 0, sizeof(uc)); + memset(&si2, 0, sizeof(si2)); + if (si) { + si2.si_signo = si->si_signo; + si2.si_code = si->si_code; + si2.si_errno = si->si_errno; + } + if (ctx) { + uc.uc_mcontext.fpregs = &uc.__fpustate; + memcpy(&uc.uc_sigmask, &ctx->sc_mask, + MIN(sizeof(uc.uc_sigmask), sizeof(ctx->sc_mask))); + uc.uc_mcontext.rdi = ctx->sc_rdi; + uc.uc_mcontext.rsi = ctx->sc_rsi; + uc.uc_mcontext.rdx = ctx->sc_rdx; + uc.uc_mcontext.rcx = ctx->sc_rcx; + uc.uc_mcontext.r8 = ctx->sc_r8; + uc.uc_mcontext.r9 = ctx->sc_r9; + uc.uc_mcontext.rax = ctx->sc_rax; + uc.uc_mcontext.rbx = ctx->sc_rbx; + uc.uc_mcontext.rbp = ctx->sc_rbp; + uc.uc_mcontext.r10 = ctx->sc_r10; + uc.uc_mcontext.r11 = ctx->sc_r11; + uc.uc_mcontext.r12 = ctx->sc_r12; + uc.uc_mcontext.r13 = ctx->sc_r13; + uc.uc_mcontext.r14 = ctx->sc_r14; + uc.uc_mcontext.r15 = ctx->sc_r15; + uc.uc_mcontext.trapno = ctx->sc_trapno; + uc.uc_mcontext.fs = ctx->sc_fs; + uc.uc_mcontext.gs = ctx->sc_gs; + uc.uc_mcontext.err = ctx->sc_err; + uc.uc_mcontext.rip = ctx->sc_rip; + uc.uc_mcontext.rsp = ctx->sc_rsp; + if (ctx->sc_fpstate) { + *uc.uc_mcontext.fpregs = *ctx->sc_fpstate; + } + } + ((sigaction_f)(_base + rva))(sig, &si2, &uc); + if (ctx) { + ctx->sc_rdi = uc.uc_mcontext.rdi; + ctx->sc_rsi = uc.uc_mcontext.rsi; + ctx->sc_rdx = uc.uc_mcontext.rdx; + ctx->sc_rcx = uc.uc_mcontext.rcx; + ctx->sc_r8 = uc.uc_mcontext.r8; + ctx->sc_r9 = uc.uc_mcontext.r9; + ctx->sc_rax = uc.uc_mcontext.rax; + ctx->sc_rbx = uc.uc_mcontext.rbx; + ctx->sc_rbp = uc.uc_mcontext.rbp; + ctx->sc_r10 = uc.uc_mcontext.r10; + ctx->sc_r11 = uc.uc_mcontext.r11; + ctx->sc_r12 = uc.uc_mcontext.r12; + ctx->sc_r13 = uc.uc_mcontext.r13; + ctx->sc_r14 = uc.uc_mcontext.r14; + ctx->sc_r15 = uc.uc_mcontext.r15; + ctx->sc_trapno = uc.uc_mcontext.trapno; + ctx->sc_fs = uc.uc_mcontext.fs; + ctx->sc_gs = uc.uc_mcontext.gs; + ctx->sc_err = uc.uc_mcontext.err; + ctx->sc_rip = uc.uc_mcontext.rip; + ctx->sc_rsp = uc.uc_mcontext.rsp; + if (ctx->sc_fpstate) { + *ctx->sc_fpstate = *uc.uc_mcontext.fpregs; + } + } + } + /* + * When the OpenBSD kernel invokes this signal handler it pushes a + * trampoline on the stack which does two things: 1) it calls this + * function, and 2) calls sys_sigreturn() once this returns. + */ +} diff --git a/libc/calls/struct/siginfo.h b/libc/calls/struct/siginfo.h index 403a08463..72ca1d1d4 100644 --- a/libc/calls/struct/siginfo.h +++ b/libc/calls/struct/siginfo.h @@ -49,7 +49,7 @@ struct siginfo { }; char __ignoreme[128 - 2 * sizeof(int32_t) - sizeof(int64_t)]; }; -} forcealign(8); +}; typedef struct siginfo siginfo_t; diff --git a/libc/calls/ucontext.h b/libc/calls/ucontext.h index 4a08cf5a3..df4e59af2 100644 --- a/libc/calls/ucontext.h +++ b/libc/calls/ucontext.h @@ -65,7 +65,7 @@ struct FpuStackEntry { uint16_t padding[3]; }; -struct FpuState { +struct thatispacked FpuState { uint16_t cwd; uint16_t swd; uint16_t ftw; @@ -122,26 +122,7 @@ struct MachineContext { typedef struct MachineContext mcontext_t; struct ucontext { - union { - uint64_t uc_flags; - struct { - unsigned cf : 1; /* bit 0: carry flag */ - unsigned vf : 1; /* bit 1: V flag: was 8085 signed-number overflow */ - unsigned pf : 1; /* bit 2: parity flag */ - unsigned rf : 1; /* bit 3: always zero [undoc] */ - unsigned af : 1; /* bit 4: auxiliary flag */ - unsigned kf : 1; /* bit 5: K flag = V flag ⊕ sgn(result) [undoc] */ - unsigned zf : 1; /* bit 6: zero flag */ - unsigned sf : 1; /* bit 7: sign flag */ - unsigned tf : 1; /* bit 8: trap flag */ - unsigned if_ : 1; /* bit 9: interrupt enable flag */ - unsigned df : 1; /* bit 10: direction flag */ - unsigned of : 1; /* bit 11: overflow flag */ - unsigned pl : 2; /* b12-13: i/o privilege level (80286+) */ - unsigned nt : 1; /* bit 14: nested task flag (80286+) */ - unsigned pc : 1; /* bit 15: oldskool flag */ - }; - }; + uint64_t uc_flags; struct ucontext *uc_link; stack_t uc_stack; mcontext_t uc_mcontext; /* use this */ diff --git a/libc/calls/winalarm.c b/libc/calls/winalarm.c index 72895ac07..15088a1cd 100644 --- a/libc/calls/winalarm.c +++ b/libc/calls/winalarm.c @@ -23,8 +23,12 @@ void __winalarm(void *lpArgToCompletionRoutine, uint32_t dwTimerLowValue, uint32_t dwTimerHighValue) { + int rva; siginfo_t info; memset(&info, 0, sizeof(info)); info.si_signo = SIGALRM; - __sigenter(info.si_signo, &info, NULL); + rva = __sighandrvas[SIGALRM]; + if (rva >= kSigactionMinRva) { + ((sigaction_f)(_base + rva))(SIGALRM, &info, NULL); + } } diff --git a/libc/calls/wincrash.c b/libc/calls/wincrash.c index 5d73d239d..dc8f0cc43 100644 --- a/libc/calls/wincrash.c +++ b/libc/calls/wincrash.c @@ -24,7 +24,7 @@ #include "libc/str/str.h" textwindows unsigned __wincrash(struct NtExceptionPointers *ep) { - int sig; + int sig, rva; struct Goodies { ucontext_t ctx; struct siginfo si; @@ -69,7 +69,10 @@ textwindows unsigned __wincrash(struct NtExceptionPointers *ep) { return kNtExceptionContinueSearch; } memset(&g, 0, sizeof(g)); - ntcontext2linux(&g.ctx, ep->ContextRecord); - return __sigenter(sig, &g.si, &g.ctx) ? kNtExceptionContinueExecution - : kNtExceptionContinueSearch; + rva = __sighandrvas[sig]; + if (rva >= kSigactionMinRva) { + ntcontext2linux(&g.ctx, ep->ContextRecord); + ((sigaction_f)(_base + rva))(sig, &g.si, &g.ctx); + } + return kNtExceptionContinueExecution; } diff --git a/libc/calls/writev-metal.c b/libc/calls/writev-metal.c new file mode 100644 index 000000000..3788b103f --- /dev/null +++ b/libc/calls/writev-metal.c @@ -0,0 +1,29 @@ +/*-*- 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 │ +│ │ +│ 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/internal.h" +#include "libc/sysv/errfuns.h" + +ssize_t sys_writev_metal(struct Fd *fd, const struct iovec *iov, int iovlen) { + switch (fd->kind) { + case kFdSerial: + return sys_writev_serial(fd, iov, iovlen); + default: + return ebadf(); + } +} diff --git a/libc/calls/writev-nt.c b/libc/calls/writev-nt.c new file mode 100644 index 000000000..3d07f04c7 --- /dev/null +++ b/libc/calls/writev-nt.c @@ -0,0 +1,35 @@ +/*-*- 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 │ +│ │ +│ 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/bits/weaken.h" +#include "libc/calls/internal.h" +#include "libc/sock/internal.h" +#include "libc/sysv/errfuns.h" + +textwindows ssize_t sys_writev_nt(struct Fd *fd, const struct iovec *iov, + int iovlen) { + switch (fd->kind) { + case kFdFile: + case kFdConsole: + return sys_write_nt(fd, iov, iovlen, -1); + case kFdSocket: + return weaken(sys_sendto_nt)(fd, iov, iovlen, 0, NULL, 0); + default: + return ebadf(); + } +} diff --git a/libc/calls/writev-serial.c b/libc/calls/writev-serial.c index 3afba48b5..b3fc44b4c 100644 --- a/libc/calls/writev-serial.c +++ b/libc/calls/writev-serial.c @@ -20,7 +20,7 @@ #include "libc/nexgen32e/uart.internal.h" #include "libc/runtime/pc.internal.h" -ssize_t writev_serial(struct Fd *fd, const struct iovec *iov, int iovlen) { +ssize_t sys_writev_serial(struct Fd *fd, const struct iovec *iov, int iovlen) { size_t i, j, wrote = 0; for (i = 0; i < iovlen; ++i) { for (j = 0; j < iov[i].iov_len; ++j) { diff --git a/libc/calls/writev.c b/libc/calls/writev.c index b882f5350..53821450b 100644 --- a/libc/calls/writev.c +++ b/libc/calls/writev.c @@ -39,16 +39,13 @@ ssize_t writev(int fd, const struct iovec *iov, int iovlen) { if (fd < g_fds.n && g_fds.p[fd].kind == kFdZip) { return weaken(__zipos_write)( (struct ZiposHandle *)(intptr_t)g_fds.p[fd].handle, iov, iovlen, -1); - } else if (SupportsMetal() && fd < g_fds.n && g_fds.p[fd].kind == kFdSerial) { - return writev_serial(&g_fds.p[fd], iov, iovlen); - } else if (!IsWindows()) { + } else if (!IsWindows() && !IsMetal()) { return sys_writev(fd, iov, iovlen); - } else if (fd < g_fds.n && - (g_fds.p[fd].kind == kFdFile || g_fds.p[fd].kind == kFdConsole)) { - return sys_write_nt(&g_fds.p[fd], iov, iovlen, -1); - } else if (fd < g_fds.n && g_fds.p[fd].kind == kFdSocket) { - return weaken(sys_sendto_nt)(&g_fds.p[fd], iov, iovlen, 0, NULL, 0); - } else { + } else if (fd >= g_fds.n) { return ebadf(); + } else if (IsMetal()) { + return sys_writev_metal(g_fds.p + fd, iov, iovlen); + } else { + return sys_writev_nt(g_fds.p + fd, iov, iovlen); } } diff --git a/libc/calls/xnutrampoline.c b/libc/calls/xnutrampoline.c index 2e8a9a676..dcdb6fd9d 100644 --- a/libc/calls/xnutrampoline.c +++ b/libc/calls/xnutrampoline.c @@ -50,17 +50,6 @@ struct __darwin_sigaltstack { int32_t ss_flags; }; -struct __darwin_fp_control { - uint16_t __invalid : 1, __denorm : 1, __zdiv : 1, __ovrfl : 1, __undfl : 1, - __precis : 1, : 2, __pc : 2, __rc : 2, : 1, : 3; -}; - -struct __darwin_fp_status { - uint16_t __invalid : 1, __denorm : 1, __zdiv : 1, __ovrfl : 1, __undfl : 1, - __precis : 1, __stkflt : 1, __errsumm : 1, __c0 : 1, __c1 : 1, __c2 : 1, - __tos : 3, __c3 : 1, __busy : 1; -}; - struct __darwin_mmst_reg { char __mmst_reg[10]; char __mmst_rsrv[6]; @@ -116,8 +105,8 @@ struct __darwin_x86_thread_full_state64 { struct __darwin_x86_float_state64 { int32_t __fpu_reserved[2]; - struct __darwin_fp_control __fpu_fcw; - struct __darwin_fp_status __fpu_fsw; + uint16_t __fpu_fcw; + uint16_t __fpu_fsw; uint8_t __fpu_ftw; uint8_t __fpu_rsrv1; uint16_t __fpu_fop; @@ -153,14 +142,14 @@ struct __darwin_x86_float_state64 { struct __darwin_xmm_reg __fpu_xmm13; struct __darwin_xmm_reg __fpu_xmm14; struct __darwin_xmm_reg __fpu_xmm15; - char __fpu_rsrv4[6 * 16]; + char __fpu_rsrv4[96]; int32_t __fpu_reserved1; }; struct __darwin_x86_avx_state64 { int32_t __fpu_reserved[2]; - struct __darwin_fp_control __fpu_fcw; - struct __darwin_fp_status __fpu_fsw; + uint16_t __fpu_fcw; + uint16_t __fpu_fsw; uint8_t __fpu_ftw; uint8_t __fpu_rsrv1; uint16_t __fpu_fop; @@ -219,8 +208,8 @@ struct __darwin_x86_avx_state64 { struct __darwin_x86_avx512_state64 { int32_t __fpu_reserved[2]; - struct __darwin_fp_control __fpu_fcw; - struct __darwin_fp_status __fpu_fsw; + uint16_t __fpu_fcw; + uint16_t __fpu_fsw; uint8_t __fpu_ftw; uint8_t __fpu_rsrv1; uint16_t __fpu_fop; @@ -390,6 +379,12 @@ static void xnuexceptionstate2linux( mc->err = xnues->__err; } +static void linuxexceptionstate2xnu( + struct __darwin_x86_exception_state64 *xnues, mcontext_t *mc) { + xnues->__trapno = mc->trapno; + xnues->__err = mc->err; +} + static void xnuthreadstate2linux(ucontext_t *uc, mcontext_t *mc, struct __darwin_x86_thread_state64 *xnuss) { mc->rdi = xnuss->__rdi; @@ -401,7 +396,6 @@ static void xnuthreadstate2linux(ucontext_t *uc, mcontext_t *mc, mc->rcx = xnuss->__rcx; mc->rsp = xnuss->__rsp; mc->rip = xnuss->__rip; - /* g.uc.uc_mcontext.rip = xnuctx->uc_mcontext->__es.__faultvaddr; */ mc->cs = xnuss->__cs; mc->gs = xnuss->__gs; mc->fs = xnuss->__fs; @@ -410,10 +404,29 @@ static void xnuthreadstate2linux(ucontext_t *uc, mcontext_t *mc, memcpy(&mc->r8, &xnuss->__r8, 8 * sizeof(int64_t)); } +static void linuxthreadstate2xnu(struct __darwin_x86_thread_state64 *xnuss, + ucontext_t *uc, mcontext_t *mc) { + xnuss->__rdi = mc->rdi; + xnuss->__rsi = mc->rsi; + xnuss->__rbp = mc->rbp; + xnuss->__rbx = mc->rbx; + xnuss->__rdx = mc->rdx; + xnuss->__rax = mc->rax; + xnuss->__rcx = mc->rcx; + xnuss->__rsp = mc->rsp; + xnuss->__rip = mc->rip; + xnuss->__cs = mc->cs; + xnuss->__gs = mc->gs; + xnuss->__fs = mc->fs; + xnuss->__rflags = mc->eflags; + xnuss->__rflags = uc->uc_flags; + memcpy(&xnuss->__r8, &mc->r8, 8 * sizeof(int64_t)); +} + static void xnussefpustate2linux(struct FpuState *fs, struct __darwin_x86_float_state64 *xnufs) { - memcpy(&fs->cwd, &xnufs->__fpu_fcw, 2); - memcpy(&fs->swd, &xnufs->__fpu_fsw, 2); + fs->cwd = xnufs->__fpu_fcw; + fs->swd = xnufs->__fpu_fsw; fs->ftw = xnufs->__fpu_ftw; fs->fop = xnufs->__fpu_fop; fs->rip = xnufs->__fpu_ip; @@ -424,49 +437,91 @@ static void xnussefpustate2linux(struct FpuState *fs, memcpy(fs->st, &xnufs->__fpu_stmm0, (8 + 16) * sizeof(uint128_t)); } -wontreturn void __xnutrampoline(void *fn, int infostyle, int sig, - const struct __darwin_siginfo *xnuinfo, - const struct __darwin_ucontext *xnuctx) { - /* note: this function impl can't access static memory */ +static void linuxssefpustate2xnu(struct __darwin_x86_float_state64 *xnufs, + struct FpuState *fs) { + xnufs->__fpu_fcw = fs->cwd; + xnufs->__fpu_fsw = fs->swd; + xnufs->__fpu_ftw = fs->ftw; + xnufs->__fpu_fop = fs->fop; + xnufs->__fpu_ip = fs->rip; + xnufs->__fpu_dp = fs->rdp; + xnufs->__fpu_mxcsr = fs->mxcsr; + xnufs->__fpu_mxcsrmask = fs->mxcr_mask; + /* copy st0-st7 as well as xmm0-xmm15 */ + memcpy(&xnufs->__fpu_stmm0, fs->st, (8 + 16) * sizeof(uint128_t)); +} + +void __sigenter_xnu(void *fn, int infostyle, int sig, + struct __darwin_siginfo *xnuinfo, + struct __darwin_ucontext *xnuctx) { + int rva; intptr_t ax; struct Goodies { ucontext_t uc; siginfo_t si; } g; - memset(&g, 0, sizeof(g)); - if (xnuctx) { - /* g.uc.uc_sigmask = xnuctx->uc_sigmask; */ - g.uc.uc_stack.ss_sp = xnuctx->uc_stack.ss_sp; - g.uc.uc_stack.ss_flags = xnuctx->uc_stack.ss_flags; - g.uc.uc_stack.ss_size = xnuctx->uc_stack.ss_size; - g.uc.uc_mcontext.fpregs = &g.uc.__fpustate; - if (xnuctx->uc_mcontext) { - if (xnuctx->uc_mcsize >= sizeof(struct __darwin_x86_exception_state64)) { - xnuexceptionstate2linux(&g.uc.uc_mcontext, &xnuctx->uc_mcontext->__es); + rva = __sighandrvas[sig & (NSIG - 1)]; + if (rva >= kSigactionMinRva) { + memset(&g, 0, sizeof(g)); + if (xnuctx) { + memcpy(&g.uc.uc_sigmask, &xnuctx->uc_sigmask, + MIN(sizeof(g.uc.uc_sigmask), sizeof(xnuctx->uc_sigmask))); + g.uc.uc_stack.ss_sp = xnuctx->uc_stack.ss_sp; + g.uc.uc_stack.ss_flags = xnuctx->uc_stack.ss_flags; + g.uc.uc_stack.ss_size = xnuctx->uc_stack.ss_size; + g.uc.uc_mcontext.fpregs = &g.uc.__fpustate; + if (xnuctx->uc_mcontext) { + if (xnuctx->uc_mcsize >= + sizeof(struct __darwin_x86_exception_state64)) { + xnuexceptionstate2linux(&g.uc.uc_mcontext, + &xnuctx->uc_mcontext->__es); + } + if (xnuctx->uc_mcsize >= + (sizeof(struct __darwin_x86_exception_state64) + + sizeof(struct __darwin_x86_thread_state64))) { + xnuthreadstate2linux(&g.uc, &g.uc.uc_mcontext, + &xnuctx->uc_mcontext->__ss); + } + if (xnuctx->uc_mcsize >= sizeof(struct __darwin_mcontext64)) { + xnussefpustate2linux(&g.uc.__fpustate, &xnuctx->uc_mcontext->__fs); + } } - if (xnuctx->uc_mcsize >= (sizeof(struct __darwin_x86_exception_state64) + - sizeof(struct __darwin_x86_thread_state64))) { - xnuthreadstate2linux(&g.uc, &g.uc.uc_mcontext, - &xnuctx->uc_mcontext->__ss); + } + if (xnuinfo) { + g.si.si_signo = xnuinfo->si_signo; + g.si.si_errno = xnuinfo->si_errno; + g.si.si_code = xnuinfo->si_code; + if (xnuinfo->si_pid) { + g.si.si_pid = xnuinfo->si_pid; + g.si.si_uid = xnuinfo->si_uid; + g.si.si_status = xnuinfo->si_status; + } else { + g.si.si_addr = (void *)xnuinfo->si_addr; } - if (xnuctx->uc_mcsize >= sizeof(struct __darwin_mcontext64)) { - xnussefpustate2linux(&g.uc.__fpustate, &xnuctx->uc_mcontext->__fs); + } + ((sigaction_f)(_base + rva))(sig, &g.si, &g.uc); + if (xnuctx) { + xnuctx->uc_stack.ss_sp = g.uc.uc_stack.ss_sp; + xnuctx->uc_stack.ss_flags = g.uc.uc_stack.ss_flags; + xnuctx->uc_stack.ss_size = g.uc.uc_stack.ss_size; + if (xnuctx->uc_mcontext) { + if (xnuctx->uc_mcsize >= + sizeof(struct __darwin_x86_exception_state64)) { + linuxexceptionstate2xnu(&xnuctx->uc_mcontext->__es, + &g.uc.uc_mcontext); + } + if (xnuctx->uc_mcsize >= + (sizeof(struct __darwin_x86_exception_state64) + + sizeof(struct __darwin_x86_thread_state64))) { + linuxthreadstate2xnu(&xnuctx->uc_mcontext->__ss, &g.uc, + &g.uc.uc_mcontext); + } + if (xnuctx->uc_mcsize >= sizeof(struct __darwin_mcontext64)) { + linuxssefpustate2xnu(&xnuctx->uc_mcontext->__fs, &g.uc.__fpustate); + } } } } - if (xnuinfo) { - g.si.si_signo = xnuinfo->si_signo; - g.si.si_errno = xnuinfo->si_errno; - g.si.si_code = xnuinfo->si_code; - if (xnuinfo->si_pid) { - g.si.si_pid = xnuinfo->si_pid; - g.si.si_uid = xnuinfo->si_uid; - g.si.si_status = xnuinfo->si_status; - } else { - g.si.si_addr = (void *)xnuinfo->si_addr; - } - } - __sigenter(sig, &g.si, &g.uc); asm volatile("syscall" : "=a"(ax) : "0"(0x20000b8 /* sigreturn */), "D"(xnuctx), "S"(infostyle) diff --git a/libc/log/oncrash.c b/libc/log/oncrash.c index 5aa01ad94..a978e882c 100644 --- a/libc/log/oncrash.c +++ b/libc/log/oncrash.c @@ -18,6 +18,7 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/calls.h" #include "libc/calls/sigbits.h" +#include "libc/calls/struct/siginfo.h" #include "libc/calls/struct/utsname.h" #include "libc/calls/ucontext.h" #include "libc/dce.h" @@ -32,6 +33,7 @@ #include "libc/nexgen32e/stackframe.h" #include "libc/runtime/internal.h" #include "libc/runtime/memtrack.h" +#include "libc/runtime/pc.internal.h" #include "libc/runtime/runtime.h" #include "libc/str/str.h" #include "libc/sysv/consts/auxv.h" @@ -39,17 +41,11 @@ #include "libc/sysv/consts/o.h" #include "libc/sysv/consts/sig.h" -STATIC_YOINK("ftoa"); -STATIC_YOINK("ntoa"); -STATIC_YOINK("stoa"); - /** * @fileoverview Abnormal termination handling & GUI debugging. * @see libc/onkill.c */ -struct siginfo; - static const char kGregOrder[17] forcealign(1) = { 13, 11, 8, 14, 12, 9, 10, 15, 16, 0, 1, 2, 3, 4, 5, 6, 7, }; @@ -59,7 +55,8 @@ static const char kGregNames[17][4] forcealign(1) = { "RSI", "RBP", "RBX", "RDX", "RAX", "RCX", "RSP", "RIP", }; -static const char kGodHatesFlags[12] forcealign(1) = "CVPRAKZSTIDO"; +static const char kCpuFlags[12] forcealign(1) = "CVPRAKZSTIDO"; +static const char kFpuExceptions[6] forcealign(1) = "IDZOUP"; static const char kCrashSigNames[8][5] forcealign(1) = { "QUIT", "FPE", "ILL", "SEGV", "TRAP", "ABRT", "BUS"}; @@ -88,20 +85,36 @@ relegated static void ShowFunctionCalls(int fd, ucontext_t *ctx) { } } -relegated static void DescribeCpuFlags(int fd, unsigned flags) { +relegated static char *AddFlag(char *p, int b, const char *s) { + if (b) p = stpcpy(p, s); + return p; +} + +relegated static void DescribeCpuFlags(int fd, int flags, int x87sw, + int mxcsr) { unsigned i; char buf[64], *p; p = buf; - for (i = 0; i < ARRAYLEN(kGodHatesFlags); ++i) { + for (i = 0; i < ARRAYLEN(kCpuFlags); ++i) { if (flags & 1) { *p++ = ' '; - *p++ = kGodHatesFlags[i]; + *p++ = kCpuFlags[i]; *p++ = 'F'; } flags >>= 1; } - p = stpcpy(p, " IOPL"); - *p++ = '0' + (flags & 3); + for (i = 0; i < ARRAYLEN(kFpuExceptions); ++i) { + if ((x87sw | mxcsr) & (1 << i)) { + *p++ = ' '; + *p++ = kFpuExceptions[i]; + *p++ = 'E'; + } + } + p = AddFlag(p, x87sw & FPU_SF, " SF"); + p = AddFlag(p, x87sw & FPU_C0, " C0"); + p = AddFlag(p, x87sw & FPU_C1, " C1"); + p = AddFlag(p, x87sw & FPU_C2, " C2"); + p = AddFlag(p, x87sw & FPU_C3, " C3"); write(fd, buf, p - buf); } @@ -111,8 +124,8 @@ relegated static void ShowGeneralRegisters(int fd, ucontext_t *ctx) { write(fd, "\r\n", 2); for (i = 0, j = 0, k = 0; i < ARRAYLEN(kGregNames); ++i) { if (j > 0) write(fd, " ", 1); - (dprintf)(fd, "%-3s %016lx", kGregNames[(unsigned)kGregOrder[i]], - ctx->uc_mcontext.gregs[(unsigned)kGregOrder[i]]); + dprintf(fd, "%-3s %016lx", kGregNames[(unsigned)kGregOrder[i]], + ctx->uc_mcontext.gregs[(unsigned)kGregOrder[i]]); if (++j == 3) { j = 0; if (ctx->uc_mcontext.fpregs) { @@ -120,12 +133,15 @@ relegated static void ShowGeneralRegisters(int fd, ucontext_t *ctx) { } else { memset(&st, 0, sizeof(st)); } - (dprintf)(fd, " %s(%zu) %Lf", "ST", k, st); + dprintf(fd, " %s(%zu) %Lf", "ST", k, st); ++k; write(fd, "\r\n", 2); } } - DescribeCpuFlags(fd, ctx->uc_mcontext.gregs[REG_EFL]); + DescribeCpuFlags( + fd, ctx->uc_mcontext.gregs[REG_EFL], + ctx->uc_mcontext.fpregs ? ctx->uc_mcontext.fpregs->swd : 0, + ctx->uc_mcontext.fpregs ? ctx->uc_mcontext.fpregs->mxcsr : 0); } relegated static void ShowSseRegisters(int fd, ucontext_t *ctx) { @@ -133,11 +149,11 @@ relegated static void ShowSseRegisters(int fd, ucontext_t *ctx) { if (ctx->uc_mcontext.fpregs) { write(fd, "\r\n\r\n", 4); for (i = 0; i < 8; ++i) { - (dprintf)(fd, VEIL("r", "%s%-2zu %016lx%016lx %s%-2d %016lx%016lx\r\n"), - "XMM", i + 0, ctx->uc_mcontext.fpregs->xmm[i + 0].u64[1], - ctx->uc_mcontext.fpregs->xmm[i + 0].u64[0], "XMM", i + 8, - ctx->uc_mcontext.fpregs->xmm[i + 8].u64[1], - ctx->uc_mcontext.fpregs->xmm[i + 8].u64[0]); + dprintf(fd, "%s%-2zu %016lx%016lx %s%-2d %016lx%016lx\r\n", "XMM", i + 0, + ctx->uc_mcontext.fpregs->xmm[i + 0].u64[1], + ctx->uc_mcontext.fpregs->xmm[i + 0].u64[0], "XMM", i + 8, + ctx->uc_mcontext.fpregs->xmm[i + 8].u64[1], + ctx->uc_mcontext.fpregs->xmm[i + 8].u64[0]); } } } @@ -164,13 +180,12 @@ relegated static void ShowCrashReport(int err, int fd, int sig, struct utsname names; strcpy(hostname, "unknown"); gethostname(hostname, sizeof(hostname)); - (dprintf)( - fd, VEIL("r", "\r\n%serror%s: Uncaught SIG%s on %s\r\n %s\r\n %s\r\n"), - RED2, RESET, TinyStrSignal(sig), hostname, getauxval(AT_EXECFN), - strerror(err)); + dprintf(fd, "\r\n%serror%s: Uncaught SIG%s on %s\r\n %s\r\n %s\r\n", RED2, + RESET, TinyStrSignal(sig), hostname, getauxval(AT_EXECFN), + strerror(err)); if (uname(&names) != -1) { - (dprintf)(fd, VEIL("r", " %s %s %s %s\r\n"), names.sysname, names.nodename, - names.release, names.version); + dprintf(fd, " %s %s %s %s\r\n", names.sysname, names.nodename, + names.release, names.version); } ShowFunctionCalls(fd, ctx); if (ctx) { diff --git a/libc/macros.internal.inc b/libc/macros.internal.inc index aa4670a2c..e7f5201cb 100644 --- a/libc/macros.internal.inc +++ b/libc/macros.internal.inc @@ -105,7 +105,7 @@ // @note therefore item/values are reordered w.r.t. link order // @note therefore no section relative addressing .macro .rodata.str1.1 - .section .rodata.str1.1,"aSM",@progbits,1 + .section .rodata.str1.1,"aMS",@progbits,1 .align 1 .endm diff --git a/libc/nexgen32e/g_argv.S b/libc/nexgen32e/g_argv.S index 1a58218a9..2946b012f 100644 --- a/libc/nexgen32e/g_argv.S +++ b/libc/nexgen32e/g_argv.S @@ -19,13 +19,13 @@ #include "libc/macros.h" #include "libc/notice.inc" - .initbss 300,_init___argv -/ Global variable holding _start(argv) parameter. + .initbss 300,_init_argv +// Global variable holding _start(argv) parameter. __argv: .quad 0 .endobj __argv,globl .previous - .init.start 300,_init___argv + .init.start 300,_init_argv mov %r13,%rax stosq - .init.end 300,_init___argv + .init.end 300,_init_argv diff --git a/libc/nexgen32e/g_auxv.S b/libc/nexgen32e/g_auxv.S index bdab0d289..e62ede3d8 100644 --- a/libc/nexgen32e/g_auxv.S +++ b/libc/nexgen32e/g_auxv.S @@ -19,13 +19,13 @@ #include "libc/macros.h" #include "libc/notice.inc" - .initbss 300,_init___auxv -/ Global variable holding _start(auxv) parameter. + .initbss 300,_init_auxv +// Global variable holding _start(auxv) parameter. __auxv: .quad 0 .endobj __auxv,globl .previous - .init.start 300,_init___auxv + .init.start 300,_init_auxv mov %r15,%rax stosq - .init.end 300,_init___auxv + .init.end 300,_init_auxv diff --git a/libc/runtime/abort-nt.c b/libc/runtime/abort-nt.c index b78dd60fe..705311cfd 100644 --- a/libc/runtime/abort-nt.c +++ b/libc/runtime/abort-nt.c @@ -24,9 +24,13 @@ #include "libc/sysv/consts/sig.h" textwindows wontreturn void sys_abort_nt(void) { + int rva; siginfo_t info; memset(&info, 0, sizeof(info)); info.si_signo = SIGABRT; - __sigenter(SIGABRT, &info, NULL); + rva = __sighandrvas[SIGABRT]; + if (rva >= kSigactionMinRva) { + ((sigaction_f)(_base + rva))(SIGABRT, &info, NULL); + } _Exit(128 + SIGABRT); } diff --git a/libc/runtime/efimain.greg.c b/libc/runtime/efimain.greg.c index 170ade5dd..b93231545 100644 --- a/libc/runtime/efimain.greg.c +++ b/libc/runtime/efimain.greg.c @@ -81,7 +81,7 @@ __msabi noasan EFI_STATUS EfiMain(EFI_HANDLE ImageHandle, * Allocates and clears PC-compatible memory and copies image. */ SystemTable->BootServices->AllocatePages( - EfiConventionalMemory, AllocateAddress, + AllocateAddress, EfiConventionalMemory, MAX(2 * 1024 * 1024, 1024 * 1024 + (_end - _base)) / 4096, 0); SystemTable->BootServices->SetMem(0, 0x80000, 0); SystemTable->BootServices->CopyMem((void *)(1024 * 1024), _base, diff --git a/libc/runtime/g_argc.S b/libc/runtime/g_argc.S index ea0873121..d824b00f0 100644 --- a/libc/runtime/g_argc.S +++ b/libc/runtime/g_argc.S @@ -19,13 +19,13 @@ #include "libc/macros.h" #include "libc/notice.inc" - .initbss 300,_init___argc -/ Global variable holding _start(argc) parameter. + .initbss 300,_init_argc +// Global variable holding _start(argc) parameter. __argc: .quad 0 .endobj __argc,globl .previous - .init.start 300,_init___argc + .init.start 300,_init_argc mov %r12,%rax stosq - .init.end 300,_init___argc + .init.end 300,_init_argc diff --git a/libc/runtime/pc.internal.h b/libc/runtime/pc.internal.h index b78ff07de..88cc32c3b 100644 --- a/libc/runtime/pc.internal.h +++ b/libc/runtime/pc.internal.h @@ -58,8 +58,12 @@ B: FPU Busy ───────────┐│ │ │ ││││││││ ││┌┴┐┌┼┐││││││││ │↓│ │↓↓↓││││││││*/ -#define FPU_IE 0b0000000000100000000000001 -#define FPU_ZE 0b0000000000100000000000100 +#define FPU_IE 0b0000000000000000000000001 +#define FPU_DE 0b0000000000000000000000010 +#define FPU_ZE 0b0000000000000000000000100 +#define FPU_OE 0b0000000000000000000001000 +#define FPU_UE 0b0000000000000000000010000 +#define FPU_PE 0b0000000000000000000100000 #define FPU_SF 0b0000000000000000001000000 #define FPU_C0 0b0000000000000000100000000 #define FPU_C1 0b0000000000000001000000000 diff --git a/libc/runtime/winmain.greg.c b/libc/runtime/winmain.greg.c index bed26c149..dfd373679 100644 --- a/libc/runtime/winmain.greg.c +++ b/libc/runtime/winmain.greg.c @@ -66,7 +66,20 @@ static noasan textwindows void SetTrueColor(void) { } static noasan textwindows void MakeLongDoubleLongAgain(void) { - int x87cw = 0x037f; /* let's hope win32 won't undo this */ + /* 8087 FPU Control Word + IM: Invalid Operation ───────────────┐ + DM: Denormal Operand ───────────────┐│ + ZM: Zero Divide ───────────────────┐││ + OM: Overflow ─────────────────────┐│││ + UM: Underflow ───────────────────┐││││ + PM: Precision ──────────────────┐│││││ + PC: Precision Control ────────┐ ││││││ + {float,∅,double,long double} │ ││││││ + RC: Rounding Control ───────┐ │ ││││││ + {even, →-∞, →+∞, →0} │┌┤ ││││││ + ┌┤││ ││││││ + d││││rr││││││*/ + int x87cw = 0b0000000000000000001101111111; asm volatile("fldcw\t%0" : /* no outputs */ : "m"(x87cw)); } diff --git a/libc/sysv/consts.sh b/libc/sysv/consts.sh index e672e6845..67cd94518 100755 --- a/libc/sysv/consts.sh +++ b/libc/sysv/consts.sh @@ -1792,12 +1792,12 @@ syscon misc SCSI_IOCTL_TAGGED_DISABLE 0x5384 0 0 0 0 0 syscon misc SCSI_IOCTL_TAGGED_ENABLE 0x5383 0 0 0 0 0 syscon misc SCSI_IOCTL_TEST_UNIT_READY 2 0 0 0 0 0 -syscon misc CLD_CONTINUED 6 6 6 6 6 0 # unix consensus -syscon misc CLD_DUMPED 3 3 3 3 3 0 # unix consensus -syscon misc CLD_EXITED 1 1 1 1 1 0 # unix consensus -syscon misc CLD_KILLED 2 2 2 2 2 0 # unix consensus -syscon misc CLD_STOPPED 5 5 5 5 5 0 # unix consensus -syscon misc CLD_TRAPPED 4 4 4 4 4 0 # unix consensus +syscon misc CLD_CONTINUED 6 6 6 6 6 6 # unix consensus +syscon misc CLD_DUMPED 3 3 3 3 3 3 # unix consensus +syscon misc CLD_EXITED 1 1 1 1 1 1 # unix consensus +syscon misc CLD_KILLED 2 2 2 2 2 2 # unix consensus +syscon misc CLD_STOPPED 5 5 5 5 5 5 # unix consensus +syscon misc CLD_TRAPPED 4 4 4 4 4 4 # unix consensus syscon misc READ_10 40 0 0 0 0 0 syscon misc READ_12 168 0 0 0 0 0 diff --git a/libc/sysv/consts/CLD_CONTINUED.S b/libc/sysv/consts/CLD_CONTINUED.S index d23e2d92c..556196233 100644 --- a/libc/sysv/consts/CLD_CONTINUED.S +++ b/libc/sysv/consts/CLD_CONTINUED.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon misc,CLD_CONTINUED,6,6,6,6,6,0 +.syscon misc,CLD_CONTINUED,6,6,6,6,6,6 diff --git a/libc/sysv/consts/CLD_DUMPED.S b/libc/sysv/consts/CLD_DUMPED.S index 4da1b04d8..1edbbadfa 100644 --- a/libc/sysv/consts/CLD_DUMPED.S +++ b/libc/sysv/consts/CLD_DUMPED.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon misc,CLD_DUMPED,3,3,3,3,3,0 +.syscon misc,CLD_DUMPED,3,3,3,3,3,3 diff --git a/libc/sysv/consts/CLD_EXITED.S b/libc/sysv/consts/CLD_EXITED.S index 33755ef7b..d6b6c972f 100644 --- a/libc/sysv/consts/CLD_EXITED.S +++ b/libc/sysv/consts/CLD_EXITED.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon misc,CLD_EXITED,1,1,1,1,1,0 +.syscon misc,CLD_EXITED,1,1,1,1,1,1 diff --git a/libc/sysv/consts/CLD_KILLED.S b/libc/sysv/consts/CLD_KILLED.S index 33a2348ba..04d2a2f0f 100644 --- a/libc/sysv/consts/CLD_KILLED.S +++ b/libc/sysv/consts/CLD_KILLED.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon misc,CLD_KILLED,2,2,2,2,2,0 +.syscon misc,CLD_KILLED,2,2,2,2,2,2 diff --git a/libc/sysv/consts/CLD_STOPPED.S b/libc/sysv/consts/CLD_STOPPED.S index 7fbf858e7..0dc66af27 100644 --- a/libc/sysv/consts/CLD_STOPPED.S +++ b/libc/sysv/consts/CLD_STOPPED.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon misc,CLD_STOPPED,5,5,5,5,5,0 +.syscon misc,CLD_STOPPED,5,5,5,5,5,5 diff --git a/libc/sysv/consts/CLD_TRAPPED.S b/libc/sysv/consts/CLD_TRAPPED.S index 9dbfee20b..7b027f015 100644 --- a/libc/sysv/consts/CLD_TRAPPED.S +++ b/libc/sysv/consts/CLD_TRAPPED.S @@ -1,2 +1,2 @@ #include "libc/sysv/consts/syscon.internal.h" -.syscon misc,CLD_TRAPPED,4,4,4,4,4,0 +.syscon misc,CLD_TRAPPED,4,4,4,4,4,4 diff --git a/libc/sysv/consts/cld.h b/libc/sysv/consts/cld.h index d734e9349..9dd866ea9 100644 --- a/libc/sysv/consts/cld.h +++ b/libc/sysv/consts/cld.h @@ -1,24 +1,11 @@ #ifndef COSMOPOLITAN_LIBC_SYSV_CONSTS_CLD_H_ #define COSMOPOLITAN_LIBC_SYSV_CONSTS_CLD_H_ -#include "libc/runtime/symbolic.h" -#define CLD_CONTINUED SYMBOLIC(CLD_CONTINUED) -#define CLD_DUMPED SYMBOLIC(CLD_DUMPED) -#define CLD_EXITED SYMBOLIC(CLD_EXITED) -#define CLD_KILLED SYMBOLIC(CLD_KILLED) -#define CLD_STOPPED SYMBOLIC(CLD_STOPPED) -#define CLD_TRAPPED SYMBOLIC(CLD_TRAPPED) +#define CLD_CONTINUED 6 +#define CLD_DUMPED 3 +#define CLD_EXITED 1 +#define CLD_KILLED 2 +#define CLD_STOPPED 5 +#define CLD_TRAPPED 4 -#if !(__ASSEMBLER__ + __LINKER__ + 0) -COSMOPOLITAN_C_START_ - -extern const long CLD_CONTINUED; -extern const long CLD_DUMPED; -extern const long CLD_EXITED; -extern const long CLD_KILLED; -extern const long CLD_STOPPED; -extern const long CLD_TRAPPED; - -COSMOPOLITAN_C_END_ -#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ #endif /* COSMOPOLITAN_LIBC_SYSV_CONSTS_CLD_H_ */ diff --git a/libc/tinymath/README.txt b/libc/tinymath/README.txt deleted file mode 100644 index c61b9dec9..000000000 --- a/libc/tinymath/README.txt +++ /dev/null @@ -1,16 +0,0 @@ - - - Cosmopolitan TinyMath - - “Seymour Cray didn't care that 81.0/3.0 did not give exactly - 27.0 on the CDC 6000 class machines; and he was universally - respected for making the fastest machines around. - ──Linus Torvalds - - -Your Cosmopolitan TinyMath library provides hardware-accelerated scalar -transcendental mathematical functions that are superior to the portable -standards-compliant math library, in terms of both performance and code -size, by trading away focus on temporal concerns, like IEEE conformance -or rounding errors at the femto-scale, or reproducible results across a -broad array of niche machine languages. diff --git a/libc/tinymath/acos.S b/libc/tinymath/acos.S index cf2a0aa2b..7e98c2ed7 100644 --- a/libc/tinymath/acos.S +++ b/libc/tinymath/acos.S @@ -17,7 +17,6 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/macros.h" -.source __FILE__ // Returns arc cosine of 𝑥. // diff --git a/libc/tinymath/copysign.S b/libc/tinymath/copysign.S index 01d745fb4..eb60dccc4 100644 --- a/libc/tinymath/copysign.S +++ b/libc/tinymath/copysign.S @@ -17,8 +17,12 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/macros.h" -.source __FILE__ +// Returns 𝑥 with same sign as 𝑦. +// +// @param 𝑥 is double scalar in low half of %xmm0 +// @param 𝑦 is double scalar in low half of %xmm1 +// @return double scalar in low half of %xmm0 copysign: .leafprologue .profilable diff --git a/libc/tinymath/copysignf.S b/libc/tinymath/copysignf.S index 5f089f6ea..0fd97c26b 100644 --- a/libc/tinymath/copysignf.S +++ b/libc/tinymath/copysignf.S @@ -17,8 +17,12 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/macros.h" -.source __FILE__ +// Returns 𝑥 with same sign as 𝑦. +// +// @param 𝑦 is float scalar in low quarter of %xmm0 +// @param 𝑥 is float scalar in low quarter of %xmm1 +// @return float scalar in low quarter of %xmm0 copysignf: .leafprologue .profilable diff --git a/libc/tinymath/copysignl.S b/libc/tinymath/copysignl.S index 79cfde3e6..79d1909bf 100644 --- a/libc/tinymath/copysignl.S +++ b/libc/tinymath/copysignl.S @@ -18,8 +18,12 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/runtime/pc.internal.h" #include "libc/macros.h" -.source __FILE__ +// Returns 𝑥 with same sign as 𝑦. +// +// @param 𝑥 is an 80-bit long double passed on stack in 16-bytes +// @param 𝑦 is the power, also pushed on stack, in reverse order +// @return result on FPU stack in %st copysignl: push %rbp mov %rsp,%rbp diff --git a/libc/tinymath/exp.S b/libc/tinymath/exp.S index 98f5a51f3..484cc2bb7 100644 --- a/libc/tinymath/exp.S +++ b/libc/tinymath/exp.S @@ -17,7 +17,6 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/macros.h" -.source __FILE__ // Returns 𝑒^x. // diff --git a/libc/tinymath/exp10.S b/libc/tinymath/exp10.S index 472336387..e907e05ac 100644 --- a/libc/tinymath/exp10.S +++ b/libc/tinymath/exp10.S @@ -17,7 +17,6 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/macros.h" -.source __FILE__ // Returns 10^x. // diff --git a/libc/tinymath/exp10l.S b/libc/tinymath/exp10l.S index b82ca56f0..e31c36c73 100644 --- a/libc/tinymath/exp10l.S +++ b/libc/tinymath/exp10l.S @@ -17,17 +17,21 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/macros.h" -.source __FILE__ // Returns 10^x. // // @param 𝑥 is an 80-bit long double passed on stack in 16-bytes // @return result of exponentiation on FPU stack in %st -exp10l: - push %rbp +exp10l: push %rbp mov %rsp,%rbp .profilable fldt 16(%rbp) + fxam # isinf(x) + fstsw %ax + mov %ah,%al + and $0x45,%ah + cmp $5,%ah + je 1f fldl2t fmulp %st,%st(1) fld %st @@ -38,8 +42,13 @@ exp10l: fld1 faddp fscale - fstp %st(1) +0: fstp %st(1) pop %rbp ret +1: test $2,%al # signbit(x) + jz 0b + fstp %st + fldz + jmp 0b .endfn exp10l,globl .alias exp10l,pow10l diff --git a/libc/tinymath/exp2.S b/libc/tinymath/exp2.S index 4481151a6..13f065e4e 100644 --- a/libc/tinymath/exp2.S +++ b/libc/tinymath/exp2.S @@ -17,13 +17,11 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/macros.h" -.source __FILE__ // Returns 2^𝑥. // // @param 𝑥 is a double passed in the lower quadword of %xmm0 // @return result in lower quadword of %xmm0 -exp2: - ezlea exp2l,ax +exp2: ezlea exp2l,ax jmp _d2ld2 .endfn exp2,globl diff --git a/libc/tinymath/exp2l.S b/libc/tinymath/exp2l.S index 1cab05fdf..3f96e5493 100644 --- a/libc/tinymath/exp2l.S +++ b/libc/tinymath/exp2l.S @@ -17,7 +17,6 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/macros.h" -.source __FILE__ // Returns 2^𝑥. // @@ -27,17 +26,26 @@ exp2l: push %rbp mov %rsp,%rbp .profilable fldt 16(%rbp) + fxam # isinf(x) + fstsw %ax + mov %ah,%al + and $0x45,%ah + cmp $5,%ah + je 1f fld %st frndint fsubr %st,%st(1) fxch f2xm1 - fadds .Lone(%rip) + fld1 + faddp fscale fstp %st(1) - pop %rbp +0: pop %rbp ret +1: test $2,%al # signbit(x) + jz 0b + fstp %st + fldz + jmp 0b .endfn exp2l,globl - - .rodata.cst4 -.Lone: .float 1.0 diff --git a/libc/tinymath/expl.S b/libc/tinymath/expl.S index b356892cf..d36bed805 100644 --- a/libc/tinymath/expl.S +++ b/libc/tinymath/expl.S @@ -17,7 +17,6 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/macros.h" -.source __FILE__ // Returns 𝑒^x. // @@ -27,6 +26,12 @@ expl: push %rbp mov %rsp,%rbp .profilable fldt 16(%rbp) + fxam # isinf(x) + fstsw %ax + mov %ah,%al + and $0x45,%ah + cmp $5,%ah + je 1f fldl2e fmulp %st,%st(1) fld %st @@ -38,6 +43,11 @@ expl: push %rbp faddp fscale fstp %st(1) - pop %rbp +0: pop %rbp ret +1: test $2,%al # signbit(x) + jz 0b + fstp %st + fldz + jmp 0b .endfn expl,globl diff --git a/libc/tinymath/expm1.S b/libc/tinymath/expm1.S index a7787f604..5b9e2819a 100644 --- a/libc/tinymath/expm1.S +++ b/libc/tinymath/expm1.S @@ -17,13 +17,11 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/macros.h" -.source __FILE__ // Returns 𝑒^x-1. // // @param 𝑥 is double scalar in low half of %xmm0 // @return double scalar in low half of %xmm0 -expm1: - ezlea expm1l,ax +expm1: ezlea expm1l,ax jmp _d2ld2 .endfn expm1,globl diff --git a/libc/tinymath/expm1l.S b/libc/tinymath/expm1l.S index cd792ddd8..f13020a48 100644 --- a/libc/tinymath/expm1l.S +++ b/libc/tinymath/expm1l.S @@ -16,18 +16,23 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/runtime/pc.internal.h" #include "libc/macros.h" -.source __FILE__ // Returns 𝑒^x-1. // // @param 𝑥 is an 80-bit long double passed on stack in 16-bytes // @return result of exponentiation on FPU stack in %st -expm1l: - push %rbp +expm1l: push %rbp mov %rsp,%rbp .profilable fldt 16(%rbp) + fxam # isinf(x) + fstsw %ax + mov %ah,%al + and $0x45,%ah + cmp $5,%ah + je 1f fldl2e fmulp %st,%st(1) fld %st @@ -40,11 +45,15 @@ expm1l: fxch %st(2) fscale fstp %st(1) - fsubs .Lone(%rip) + fld1 + fsubrp faddp %st,%st(1) - pop %rbp +0: pop %rbp ret +1: test $2,%al # signbit(x) + jz 0b + fstp %st + fld1 +3: fchs + jmp 0b .endfn expm1l,globl - - .rodata.cst4 -.Lone: .float 1.0 diff --git a/libc/tinymath/fabs.S b/libc/tinymath/fabs.S index b4218b448..d0023f5f9 100644 --- a/libc/tinymath/fabs.S +++ b/libc/tinymath/fabs.S @@ -17,7 +17,6 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/macros.h" -.source __FILE__ // Returns absolute value of 𝑥. // diff --git a/libc/tinymath/fmod.S b/libc/tinymath/fmod.S index 4e49c9251..012265b19 100644 --- a/libc/tinymath/fmod.S +++ b/libc/tinymath/fmod.S @@ -17,7 +17,6 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/macros.h" -.source __FILE__ // fmod [sic] does (𝑥 rem 𝑦) w/ round()-style rounding. // diff --git a/libc/tinymath/fmodl.S b/libc/tinymath/fmodl.S index dc9e4372f..239186d87 100644 --- a/libc/tinymath/fmodl.S +++ b/libc/tinymath/fmodl.S @@ -18,8 +18,14 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/runtime/pc.internal.h" #include "libc/macros.h" -.source __FILE__ +// fmod [sic] does (𝑥 rem 𝑦) w/ round()-style rounding. +// +// @param 𝑥 is an 80-bit long double passed on stack in 16-bytes +// @param 𝑦 is the power, also pushed on stack, in reverse order +// @return remainder ∈ (-|𝑦|,|𝑦|) in %st +// @define 𝑥-truncl(𝑥/𝑦)*𝑦 +// @see emod() fmodl: push %rbp mov %rsp,%rbp .profilable @@ -32,4 +38,7 @@ fmodl: push %rbp fstp %st(1) pop %rbp ret +1: int3 + pop %rbp + ret .endfn fmodl,globl diff --git a/libc/tinymath/ldexp.S b/libc/tinymath/ldexp.S index 1e26f485c..026fabd48 100644 --- a/libc/tinymath/ldexp.S +++ b/libc/tinymath/ldexp.S @@ -17,7 +17,6 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/macros.h" -.source __FILE__ // Returns 𝑥 × 2ʸ. // diff --git a/libc/tinymath/ldexpl.S b/libc/tinymath/ldexpl.S index e2bd56439..3dc4fed43 100644 --- a/libc/tinymath/ldexpl.S +++ b/libc/tinymath/ldexpl.S @@ -16,8 +16,8 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/runtime/pc.internal.h" #include "libc/macros.h" -.source __FILE__ // Returns 𝑥 × 2ʸ. // diff --git a/libc/tinymath/log.S b/libc/tinymath/log.S index 2f76f6c6e..f666cb6d9 100644 --- a/libc/tinymath/log.S +++ b/libc/tinymath/log.S @@ -17,7 +17,6 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/macros.h" -.source __FILE__ // Returns natural logarithm of 𝑥. // diff --git a/libc/tinymath/log1p.S b/libc/tinymath/log1p.S index cd6fcd2b2..fcb45fbf9 100644 --- a/libc/tinymath/log1p.S +++ b/libc/tinymath/log1p.S @@ -17,18 +17,16 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/macros.h" -.source __FILE__ // Returns log(𝟷+𝑥). // // @param 𝑥 is double scalar in low half of %xmm0 // @return double scalar in low half of %xmm0 -log1p: - push %rbp +log1p: push %rbp mov %rsp,%rbp .profilable push %rax - vmovsd %xmm0,(%rsp) + movsd %xmm0,(%rsp) fldl (%rsp) fld %st fabs @@ -41,7 +39,7 @@ log1p: fxch fyl2xp1 fstpl (%rsp) - vmovsd (%rsp),%xmm0 + movsd (%rsp),%xmm0 0: leave ret 1: fld1 @@ -50,12 +48,12 @@ log1p: fxch fyl2x fstpl (%rsp) - vmovsd (%rsp),%xmm0 + movsd (%rsp),%xmm0 jmp 0b .endfn log1p,globl .rodata.cst16 -.LC16: .long 205731576 - .long 2515933592 - .long 16381 +.LC16: .long 0x0c4336f8 + .long 0x95f61998 + .long 0x3ffd .long 0 diff --git a/libc/tinymath/log1pf.S b/libc/tinymath/log1pf.S index 9e974fe98..96f0d2829 100644 --- a/libc/tinymath/log1pf.S +++ b/libc/tinymath/log1pf.S @@ -17,7 +17,6 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/macros.h" -.source __FILE__ // Returns log(𝟷+𝑥). // @@ -27,11 +26,11 @@ log1pf: push %rbp mov %rsp,%rbp .profilable push %rax - vmovss %xmm0,-4(%rbp) + movss %xmm0,-4(%rbp) flds -4(%rbp) fld %st fabs - fldt .LC16(%rip) + fldt .Lnnan(%rip) fxch fcomip %st(1),%st fstp %st @@ -40,7 +39,7 @@ log1pf: push %rbp fxch fyl2xp1 1: fstps -4(%rbp) - vmovss -4(%rbp),%xmm0 + movss -4(%rbp),%xmm0 leave ret 2: fld1 @@ -52,7 +51,7 @@ log1pf: push %rbp .endfn log1pf,globl .rodata.cst16 -.LC16: .long 205731576 - .long 2515933592 - .long 16381 +.Lnnan: .long 0x0c4336f8 + .long 0x95f61998 + .long 0x3ffd .long 0 diff --git a/libc/tinymath/log2.S b/libc/tinymath/log2.S index 8ec66ed23..37591c741 100644 --- a/libc/tinymath/log2.S +++ b/libc/tinymath/log2.S @@ -17,7 +17,6 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/macros.h" -.source __FILE__ // Calculates log₂𝑥. // diff --git a/libc/tinymath/log2l.S b/libc/tinymath/log2l.S index a8c33070f..c275a7fd4 100644 --- a/libc/tinymath/log2l.S +++ b/libc/tinymath/log2l.S @@ -17,15 +17,13 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/macros.h" -.source __FILE__ // Calculates log₂𝑥. // // @param 𝑥 is an 80-bit long double passed on stack in 16-bytes // @return result in %st // @see ilogbl() -log2l: - push %rbp +log2l: push %rbp mov %rsp,%rbp .profilable fld1 diff --git a/libc/tinymath/logl.S b/libc/tinymath/logl.S index c9cef9551..cce5c97c6 100644 --- a/libc/tinymath/logl.S +++ b/libc/tinymath/logl.S @@ -17,7 +17,6 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/macros.h" -.source __FILE__ // Returns natural logarithm of 𝑥. // diff --git a/libc/tinymath/powf.S b/libc/tinymath/powf.S index 104dc70d8..a9f6e29ac 100644 --- a/libc/tinymath/powf.S +++ b/libc/tinymath/powf.S @@ -17,7 +17,6 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/macros.h" -.source __FILE__ // Returns 𝑥^𝑦. // diff --git a/libc/tinymath/powl.S b/libc/tinymath/powl.S index 53c3d598a..f9445e713 100644 --- a/libc/tinymath/powl.S +++ b/libc/tinymath/powl.S @@ -17,7 +17,6 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/macros.h" -.source __FILE__ // Returns 𝑥^𝑦. // @@ -25,6 +24,7 @@ // @param 𝑦 is the power, also pushed on stack, in reverse order // @return result of exponentiation on FPU stack in %st // @note Sun's fdlibm needs 2kLOC to do this for RISC lool +// @define exp2l(fmodl(y*log2l(x),1))*exp2l(y) powl: push %rbp mov %rsp,%rbp .profilable diff --git a/libc/tinymath/sinl.S b/libc/tinymath/sinl.S index 2969677b0..4aebcb9b7 100644 --- a/libc/tinymath/sinl.S +++ b/libc/tinymath/sinl.S @@ -17,7 +17,6 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/macros.h" -.source __FILE__ // Returns sine of 𝑥. // diff --git a/libc/tinymath/sqrt.S b/libc/tinymath/sqrt.S index ead20f96a..1f7915167 100644 --- a/libc/tinymath/sqrt.S +++ b/libc/tinymath/sqrt.S @@ -17,7 +17,6 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/macros.h" -.source __FILE__ // Returns square root of 𝑥. // diff --git a/libc/tinymath/sqrtf.S b/libc/tinymath/sqrtf.S index 6400878b9..6247e71fb 100644 --- a/libc/tinymath/sqrtf.S +++ b/libc/tinymath/sqrtf.S @@ -17,7 +17,6 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/macros.h" -.source __FILE__ // Returns square root of 𝑥. // diff --git a/libc/x/x.h b/libc/x/x.h index f1c878321..a5b6199a9 100644 --- a/libc/x/x.h +++ b/libc/x/x.h @@ -29,8 +29,9 @@ int xwrite(int, const void *, uint64_t); ╚────────────────────────────────────────────────────────────────────────────│*/ void xdie(void) wontreturn; +char *xdtoa(double) _XMAL; char *xdtoaf(float) _XMAL; -char *xdtoa(long double) _XMAL; +char *xdtoal(long double) _XMAL; char *xasprintf(const char *, ...) printfesque(1) paramsnonnull((1)) _XMAL; char *xvasprintf(const char *, va_list) _XPNN _XMAL; char *xgetline(struct FILE *) _XPNN mallocesque; diff --git a/libc/x/xdtoa.c b/libc/x/xdtoa.c index 6ccf804fe..1549d726f 100644 --- a/libc/x/xdtoa.c +++ b/libc/x/xdtoa.c @@ -16,17 +16,18 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/math.h" #include "libc/mem/mem.h" #include "libc/x/x.h" #include "third_party/gdtoa/gdtoa.h" /** - * Converts double to string w/ high-accuracy the easy way. + * Converts double to string the easy way. * * @return string that needs to be free'd */ -char *xdtoa(long double d) { +char *xdtoa(double d) { char *p = xmalloc(32); - g_xfmt_p(p, &d, 16, 32, 2); + g_dfmt_p(p, &d, DBL_DIG, 32, 2); return p; } diff --git a/libc/x/xdtoaf.c b/libc/x/xdtoaf.c index 4f039dc2e..d0ea933be 100644 --- a/libc/x/xdtoaf.c +++ b/libc/x/xdtoaf.c @@ -16,6 +16,7 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/math.h" #include "libc/mem/mem.h" #include "libc/x/x.h" #include "third_party/gdtoa/gdtoa.h" @@ -27,6 +28,6 @@ */ char *xdtoaf(float d) { char *p = xmalloc(32); - g_ffmt_p(p, &d, 7, 32, 2); + g_ffmt_p(p, &d, FLT_DIG, 32, 2); return p; } diff --git a/libc/tinymath/fld.S b/libc/x/xdtoal.c similarity index 78% rename from libc/tinymath/fld.S rename to libc/x/xdtoal.c index db4b41ef8..c5786a0a4 100644 --- a/libc/tinymath/fld.S +++ b/libc/x/xdtoal.c @@ -1,5 +1,5 @@ -/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│ -│vi: set et ft=asm ts=8 sw=8 fenc=utf-8 :vi│ +/*-*- 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 │ │ │ @@ -16,29 +16,18 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/macros.h" -.source __FILE__ +#include "libc/math.h" +#include "libc/mem/mem.h" +#include "libc/x/x.h" +#include "third_party/gdtoa/gdtoa.h" -fld1: fld1 - ret - .endfn fld1,globl - -fldl2t: fldl2t - ret - .endfn fldl2t,globl - -fldlg2: fldlg2 - ret - .endfn fldlg2,globl - -fldl2e: fldl2e - ret - .endfn fldl2e,globl - -fldln2: fldln2 - ret - .endfn fldln2,globl - -fldpi: fldpi - ret - .endfn fldpi,globl +/** + * Converts double to string the easy way. + * + * @return string that needs to be free'd + */ +char *xdtoal(long double d) { + char *p = xmalloc(32); + g_xfmt_p(p, &d, 16, 32, 2); + return p; +} diff --git a/test/libc/calls/sigaction_test.c b/test/libc/calls/sigaction_test.c index b794fee1a..e96615d16 100644 --- a/test/libc/calls/sigaction_test.c +++ b/test/libc/calls/sigaction_test.c @@ -19,12 +19,17 @@ #include "libc/calls/calls.h" #include "libc/calls/sigbits.h" #include "libc/calls/struct/sigaction.h" +#include "libc/calls/struct/siginfo.h" +#include "libc/calls/ucontext.h" #include "libc/dce.h" #include "libc/errno.h" #include "libc/runtime/runtime.h" #include "libc/sysv/consts/sa.h" #include "libc/sysv/consts/sig.h" #include "libc/testlib/testlib.h" +#include "third_party/xed/x86.h" + +struct sigaction oldsa; volatile bool gotsigint; @@ -34,12 +39,11 @@ void OnSigInt(int sig) { void SetUp(void) { gotsigint = false; + /* TODO(jart): Windows needs huge signal overhaul */ + if (IsWindows()) exit(0); } TEST(sigaction, test) { - /* TODO(jart): Why does RHEL5 behave differently? */ - /* TODO(jart): Windows needs huge signal overhaul */ - if (IsWindows()) return; int pid, status; sigset_t block, ignore, oldmask; struct sigaction saint = {.sa_handler = OnSigInt}; @@ -48,7 +52,7 @@ TEST(sigaction, test) { EXPECT_NE(-1, sigprocmask(SIG_BLOCK, &block, &oldmask)); sigfillset(&ignore); sigdelset(&ignore, SIGINT); - EXPECT_NE(-1, sigaction(SIGINT, &saint, NULL)); + EXPECT_NE(-1, sigaction(SIGINT, &saint, &oldsa)); ASSERT_NE(-1, (pid = fork())); if (!pid) { EXPECT_NE(-1, kill(getppid(), SIGINT)); @@ -64,13 +68,45 @@ TEST(sigaction, test) { EXPECT_EQ(0, WEXITSTATUS(status)); EXPECT_EQ(0, WTERMSIG(status)); EXPECT_NE(-1, sigprocmask(SIG_SETMASK, &oldmask, NULL)); + EXPECT_NE(-1, sigaction(SIGINT, &oldsa, NULL)); } TEST(sigaction, raise) { - if (IsWindows()) return; struct sigaction saint = {.sa_handler = OnSigInt}; - EXPECT_NE(-1, sigaction(SIGINT, &saint, NULL)); + EXPECT_NE(-1, sigaction(SIGINT, &saint, &oldsa)); ASSERT_FALSE(gotsigint); EXPECT_NE(-1, raise(SIGINT)); ASSERT_TRUE(gotsigint); + EXPECT_NE(-1, sigaction(SIGINT, &oldsa, NULL)); +} + +volatile int trapeax; + +void OnTrap(int sig, struct siginfo *si, struct ucontext *ctx) { + trapeax = ctx->uc_mcontext.rax; +} + +TEST(sigaction, debugBreak_handlerCanReadCpuState) { + struct sigaction saint = {.sa_sigaction = OnTrap, .sa_flags = SA_SIGINFO}; + EXPECT_NE(-1, sigaction(SIGTRAP, &saint, &oldsa)); + asm("int3" : /* no outputs */ : "a"(0x31337)); + EXPECT_EQ(0x31337, trapeax); + EXPECT_NE(-1, sigaction(SIGTRAP, &oldsa, NULL)); +} + +void OnFpe(int sig, struct siginfo *si, struct ucontext *ctx) { + struct XedDecodedInst xedd; + xed_decoded_inst_zero_set_mode(&xedd, XED_MACHINE_MODE_LONG_64); + xed_instruction_length_decode(&xedd, (void *)ctx->uc_mcontext.rip, 15); + ctx->uc_mcontext.rip += xedd.length; + ctx->uc_mcontext.rax = 42; + ctx->uc_mcontext.rdx = 0; +} + +TEST(sigaction, sigFpe_handlerCanEditProcessStateAndRecoverExecution) { + struct sigaction saint = {.sa_sigaction = OnFpe, .sa_flags = SA_SIGINFO}; + EXPECT_NE(-1, sigaction(SIGFPE, &saint, &oldsa)); + volatile long x = 0; + EXPECT_EQ(42, 666 / x); /* systems engineering trumps math */ + EXPECT_NE(-1, sigaction(SIGFPE, &oldsa, NULL)); } diff --git a/test/libc/calls/test.mk b/test/libc/calls/test.mk index f3733385a..9e24ded53 100644 --- a/test/libc/calls/test.mk +++ b/test/libc/calls/test.mk @@ -38,7 +38,8 @@ TEST_LIBC_CALLS_DIRECTDEPS = \ LIBC_SYSV \ LIBC_TESTLIB \ LIBC_UNICODE \ - LIBC_X + LIBC_X \ + THIRD_PARTY_XED TEST_LIBC_CALLS_DEPS := \ $(call uniq,$(foreach x,$(TEST_LIBC_CALLS_DIRECTDEPS),$($(x)))) diff --git a/test/libc/release/emulate.sh b/test/libc/release/emulate.sh index b925b1a5a..99b7c2b25 100755 --- a/test/libc/release/emulate.sh +++ b/test/libc/release/emulate.sh @@ -1,5 +1,9 @@ #!/bin/sh +if [ $MODE = dbg ]; then + exit # TODO +fi + # smoke test userspace binary emulation CMD="o/$MODE/tool/build/blinkenlights.com.dbg o/$MODE/examples/hello.com" if OUTPUT="$($CMD)"; then diff --git a/test/libc/release/metal.sh b/test/libc/release/metal.sh index f4893355e..21ab566ac 100755 --- a/test/libc/release/metal.sh +++ b/test/libc/release/metal.sh @@ -1,5 +1,9 @@ #!/bin/sh +if [ $MODE = dbg ]; then + exit # TODO +fi + # smoke test booting on bare metal and printing data to serial uart CMD="o/$MODE/tool/build/blinkenlights.com.dbg -r o/$MODE/examples/hello.com" if OUTPUT="$($CMD)"; then diff --git a/test/libc/tinymath/atan2l_test.c b/test/libc/tinymath/atan2l_test.c index 3aa3b322f..460bb6093 100644 --- a/test/libc/tinymath/atan2l_test.c +++ b/test/libc/tinymath/atan2l_test.c @@ -28,3 +28,28 @@ TEST(atan2l, test) { EXPECT_STREQ("-2.95", gc(xasprintf("%.2f", atan2(b, a)))); EXPECT_STREQ("-2.95", gc(xasprintf("%.2Lf", atan2l(b, a)))); } + +TEST(atan2, testSpecialCases) { + ASSERT_STREQ("NAN", gc(xdtoa(atan2(NAN, 0)))); + ASSERT_STREQ("NAN", gc(xdtoa(atan2(0, NAN)))); + ASSERT_STREQ("0", gc(xdtoa(atan2(+0., +0.)))); + ASSERT_STREQ("0", gc(xdtoa(atan2(+0., +1.)))); + ASSERT_STREQ("0", gc(xdtoa(atan2(+0., +2.)))); + ASSERT_STREQ("0", gc(xdtoa(atan2(1, INFINITY)))); + ASSERT_STREQ("3.141592653589793", gc(xdtoal(atan2(+0., -0.)))); + ASSERT_STREQ("3.141592653589793", gc(xdtoal(atan2(+0., -1.)))); + ASSERT_STREQ("3.141592653589793", gc(xdtoal(atan2(+0., -2.)))); + ASSERT_STREQ("-1.570796326794897", gc(xdtoal(atan2(-1., -0.)))); + ASSERT_STREQ("-1.570796326794897", gc(xdtoal(atan2(-1., +0.)))); + ASSERT_STREQ("-1.570796326794897", gc(xdtoal(atan2(-2., -0.)))); + ASSERT_STREQ("-1.570796326794897", gc(xdtoal(atan2(-2., +0.)))); + ASSERT_STREQ("1.570796326794897", gc(xdtoal(atan2(+1., -0.)))); + ASSERT_STREQ("1.570796326794897", gc(xdtoal(atan2(+1., +0.)))); + ASSERT_STREQ("1.570796326794897", gc(xdtoal(atan2(+2., -0.)))); + ASSERT_STREQ("1.570796326794897", gc(xdtoal(atan2(+2., +0.)))); + ASSERT_STREQ("1.570796326794897", gc(xdtoal(atan2(INFINITY, 1)))); + ASSERT_STREQ("1.570796326794897", gc(xdtoal(atan2(INFINITY, -1)))); + ASSERT_STREQ("3.141592653589793", gc(xdtoal(atan2(1, -INFINITY)))); + ASSERT_STREQ("2.356194490192345", gc(xdtoal(atan2(INFINITY, -INFINITY)))); + ASSERT_STREQ(".7853981633974483", gc(xdtoal(atan2(INFINITY, INFINITY)))); +} diff --git a/test/libc/tinymath/atanl_test.c b/test/libc/tinymath/atanl_test.c new file mode 100644 index 000000000..43020cc8e --- /dev/null +++ b/test/libc/tinymath/atanl_test.c @@ -0,0 +1,45 @@ +/*-*- 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 │ +│ │ +│ 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/math.h" +#include "libc/runtime/gc.h" +#include "libc/testlib/testlib.h" +#include "libc/x/x.h" + +void SetUp(void) { + /* 8087 FPU Control Word + IM: Invalid Operation ───────────────┐ + DM: Denormal Operand ───────────────┐│ + ZM: Zero Divide ───────────────────┐││ + OM: Overflow ─────────────────────┐│││ + UM: Underflow ───────────────────┐││││ + PM: Precision ──────────────────┐│││││ + PC: Precision Control ────────┐ ││││││ + {float,∅,double,long double} │ ││││││ + RC: Rounding Control ───────┐ │ ││││││ + {even, →-∞, →+∞, →0} │┌┤ ││││││ + ┌┤││ ││││││ + d││││rr││││││*/ + int x87cw = 0b0000000000000000001101100001; + asm volatile("fldcw\t%0" : /* no outputs */ : "m"(x87cw)); +} + +TEST(atanl, testLongDouble) { + EXPECT_STREQ("NAN", gc(xdtoal(atanl(NAN)))); + EXPECT_STREQ(".7853981583974483", gc(xdtoal(atanl(.99999999)))); +} diff --git a/test/libc/tinymath/copysign_test.c b/test/libc/tinymath/copysign_test.c new file mode 100644 index 000000000..6687ba138 --- /dev/null +++ b/test/libc/tinymath/copysign_test.c @@ -0,0 +1,73 @@ +/*-*- 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 │ +│ │ +│ 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/math.h" +#include "libc/runtime/gc.h" +#include "libc/testlib/testlib.h" +#include "libc/x/x.h" + +TEST(copysign, test) { + EXPECT_STREQ("0", gc(xdtoa(copysign(0, +0)))); + EXPECT_STREQ("-0", gc(xdtoa(copysign(0, -0.)))); + EXPECT_STREQ("0", gc(xdtoa(copysign(0, +1)))); + EXPECT_STREQ("-0", gc(xdtoa(copysign(-0., -1)))); + EXPECT_STREQ("2", gc(xdtoa(copysign(2, +1)))); + EXPECT_STREQ("-2", gc(xdtoa(copysign(-2, -1)))); + EXPECT_STREQ("NAN", gc(xdtoa(copysign(NAN, +1)))); + EXPECT_STREQ("-NAN", gc(xdtoa(copysign(NAN, -1)))); + EXPECT_STREQ("INFINITY", gc(xdtoa(copysign(INFINITY, +1)))); + EXPECT_STREQ("-INFINITY", gc(xdtoa(copysign(INFINITY, -1)))); + EXPECT_STREQ("NAN", gc(xdtoa(copysign(-NAN, +1)))); + EXPECT_STREQ("-NAN", gc(xdtoa(copysign(-NAN, -1)))); + EXPECT_STREQ("INFINITY", gc(xdtoa(copysign(-INFINITY, +1)))); + EXPECT_STREQ("-INFINITY", gc(xdtoa(copysign(-INFINITY, -1)))); +} + +TEST(copysignl, test) { + EXPECT_STREQ("0", gc(xdtoal(copysignl(0, +0)))); + EXPECT_STREQ("-0", gc(xdtoal(copysignl(0, -0.)))); + EXPECT_STREQ("0", gc(xdtoal(copysignl(0, +1)))); + EXPECT_STREQ("-0", gc(xdtoal(copysignl(-0., -1)))); + EXPECT_STREQ("2", gc(xdtoal(copysignl(2, +1)))); + EXPECT_STREQ("-2", gc(xdtoal(copysignl(-2, -1)))); + EXPECT_STREQ("NAN", gc(xdtoal(copysignl(NAN, +1)))); + EXPECT_STREQ("-NAN", gc(xdtoal(copysignl(NAN, -1)))); + EXPECT_STREQ("INFINITY", gc(xdtoal(copysignl(INFINITY, +1)))); + EXPECT_STREQ("-INFINITY", gc(xdtoal(copysignl(INFINITY, -1)))); + EXPECT_STREQ("NAN", gc(xdtoal(copysignl(-NAN, +1)))); + EXPECT_STREQ("-NAN", gc(xdtoal(copysignl(-NAN, -1)))); + EXPECT_STREQ("INFINITY", gc(xdtoal(copysignl(-INFINITY, +1)))); + EXPECT_STREQ("-INFINITY", gc(xdtoal(copysignl(-INFINITY, -1)))); +} + +TEST(copysignf, test) { + EXPECT_STREQ("0", gc(xdtoaf(copysignf(0, +0)))); + EXPECT_STREQ("-0", gc(xdtoaf(copysignf(0, -0.)))); + EXPECT_STREQ("0", gc(xdtoaf(copysignf(0, +1)))); + EXPECT_STREQ("-0", gc(xdtoaf(copysignf(-0., -1)))); + EXPECT_STREQ("2", gc(xdtoaf(copysignf(2, +1)))); + EXPECT_STREQ("-2", gc(xdtoaf(copysignf(-2, -1)))); + EXPECT_STREQ("NAN", gc(xdtoaf(copysignf(NAN, +1)))); + EXPECT_STREQ("-NAN", gc(xdtoaf(copysignf(NAN, -1)))); + EXPECT_STREQ("INFINITY", gc(xdtoaf(copysignf(INFINITY, +1)))); + EXPECT_STREQ("-INFINITY", gc(xdtoaf(copysignf(INFINITY, -1)))); + EXPECT_STREQ("NAN", gc(xdtoaf(copysignf(-NAN, +1)))); + EXPECT_STREQ("-NAN", gc(xdtoaf(copysignf(-NAN, -1)))); + EXPECT_STREQ("INFINITY", gc(xdtoaf(copysignf(-INFINITY, +1)))); + EXPECT_STREQ("-INFINITY", gc(xdtoaf(copysignf(-INFINITY, -1)))); +} diff --git a/test/libc/tinymath/exp10_test.c b/test/libc/tinymath/exp10_test.c new file mode 100644 index 000000000..9300c6299 --- /dev/null +++ b/test/libc/tinymath/exp10_test.c @@ -0,0 +1,56 @@ +/*-*- 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 │ +│ │ +│ 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/math.h" +#include "libc/runtime/gc.h" +#include "libc/testlib/testlib.h" +#include "libc/x/x.h" + +#define exp10l(x) exp10l(VEIL("t", (long double)(x))) +#define exp10(x) exp10(VEIL("x", (double)(x))) +#define exp10f(x) exp10f(VEIL("x", (float)(x))) + +TEST(exp10l, test) { + EXPECT_STREQ("1", gc(xdtoal(exp10l(0)))); + EXPECT_STREQ("1", gc(xdtoal(exp10l(-0.)))); + EXPECT_STREQ("INFINITY", gc(xdtoal(exp10l(INFINITY)))); + EXPECT_STREQ("0", gc(xdtoal(exp10l(-INFINITY)))); + EXPECT_STREQ("NAN", gc(xdtoal(exp10l(NAN)))); + EXPECT_STREQ("0", gc(xdtoal(exp10l(-132098844872390)))); + EXPECT_STREQ("INFINITY", gc(xdtoal(exp10l(132098844872390)))); +} + +TEST(exp10, test) { + EXPECT_STREQ("1", gc(xdtoa(exp10(0)))); + EXPECT_STREQ("1", gc(xdtoa(exp10(-0.)))); + EXPECT_STREQ("INFINITY", gc(xdtoa(exp10(INFINITY)))); + EXPECT_STREQ("0", gc(xdtoa(exp10(-INFINITY)))); + EXPECT_STREQ("NAN", gc(xdtoa(exp10(NAN)))); + EXPECT_STREQ("0", gc(xdtoa(exp10(-132098844872390)))); + EXPECT_STREQ("INFINITY", gc(xdtoa(exp10(132098844872390)))); +} + +TEST(exp10f, test) { + EXPECT_STREQ("1", gc(xdtoaf(exp10f(0)))); + EXPECT_STREQ("1", gc(xdtoaf(exp10f(-0.)))); + EXPECT_STREQ("INFINITY", gc(xdtoaf(exp10f(INFINITY)))); + EXPECT_STREQ("0", gc(xdtoaf(exp10f(-INFINITY)))); + EXPECT_STREQ("NAN", gc(xdtoaf(exp10f(NAN)))); + EXPECT_STREQ("0", gc(xdtoaf(exp10f(-132098844872390)))); + EXPECT_STREQ("INFINITY", gc(xdtoaf(exp10f(132098844872390)))); +} diff --git a/test/libc/tinymath/exp2_test.c b/test/libc/tinymath/exp2_test.c new file mode 100644 index 000000000..a61b1dc39 --- /dev/null +++ b/test/libc/tinymath/exp2_test.c @@ -0,0 +1,56 @@ +/*-*- 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 │ +│ │ +│ 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/math.h" +#include "libc/runtime/gc.h" +#include "libc/testlib/testlib.h" +#include "libc/x/x.h" + +#define exp2l(x) exp2l(VEIL("t", (long double)(x))) +#define exp2(x) exp2(VEIL("x", (double)(x))) +#define exp2f(x) exp2f(VEIL("x", (float)(x))) + +TEST(exp2l, test) { + EXPECT_STREQ("1", gc(xdtoal(exp2l(0)))); + EXPECT_STREQ("1", gc(xdtoal(exp2l(-0.)))); + EXPECT_STREQ("INFINITY", gc(xdtoal(exp2l(INFINITY)))); + EXPECT_STREQ("0", gc(xdtoal(exp2l(-INFINITY)))); + EXPECT_STREQ("NAN", gc(xdtoal(exp2l(NAN)))); + EXPECT_STREQ("0", gc(xdtoal(exp2l(-132098844872390)))); + EXPECT_STREQ("INFINITY", gc(xdtoal(exp2l(132098844872390)))); +} + +TEST(exp2, test) { + EXPECT_STREQ("1", gc(xdtoa(exp2(0)))); + EXPECT_STREQ("1", gc(xdtoa(exp2(-0.)))); + EXPECT_STREQ("INFINITY", gc(xdtoa(exp2(INFINITY)))); + EXPECT_STREQ("0", gc(xdtoa(exp2(-INFINITY)))); + EXPECT_STREQ("NAN", gc(xdtoa(exp2(NAN)))); + EXPECT_STREQ("0", gc(xdtoa(exp2(-132098844872390)))); + EXPECT_STREQ("INFINITY", gc(xdtoa(exp2(132098844872390)))); +} + +TEST(exp2f, test) { + EXPECT_STREQ("1", gc(xdtoaf(exp2f(0)))); + EXPECT_STREQ("1", gc(xdtoaf(exp2f(-0.)))); + EXPECT_STREQ("INFINITY", gc(xdtoaf(exp2f(INFINITY)))); + EXPECT_STREQ("0", gc(xdtoaf(exp2f(-INFINITY)))); + EXPECT_STREQ("NAN", gc(xdtoaf(exp2f(NAN)))); + EXPECT_STREQ("0", gc(xdtoaf(exp2f(-132098844872390)))); + EXPECT_STREQ("INFINITY", gc(xdtoaf(exp2f(132098844872390)))); +} diff --git a/test/libc/tinymath/exp_test.c b/test/libc/tinymath/exp_test.c index 28d24d435..7b2b9a612 100644 --- a/test/libc/tinymath/exp_test.c +++ b/test/libc/tinymath/exp_test.c @@ -22,7 +22,41 @@ #include "libc/testlib/testlib.h" #include "libc/x/x.h" +#define expl(x) expl(VEIL("t", (long double)(x))) +#define exp(x) exp(VEIL("x", (double)(x))) +#define expf(x) expf(VEIL("x", (float)(x))) + +TEST(expl, test) { + EXPECT_STREQ("1", gc(xdtoal(expl(0)))); + EXPECT_STREQ("1", gc(xdtoal(expl(-0.)))); + EXPECT_STREQ("INFINITY", gc(xdtoal(expl(INFINITY)))); + EXPECT_STREQ("0", gc(xdtoal(expl(-INFINITY)))); + EXPECT_STREQ("NAN", gc(xdtoal(expl(NAN)))); + EXPECT_STREQ("0", gc(xdtoal(expl(-132098844872390)))); + EXPECT_STREQ("INFINITY", gc(xdtoal(expl(132098844872390)))); +} + TEST(exp, test) { + EXPECT_STREQ("1", gc(xdtoa(exp(0)))); + EXPECT_STREQ("1", gc(xdtoa(exp(-0.)))); + EXPECT_STREQ("INFINITY", gc(xdtoa(exp(INFINITY)))); + EXPECT_STREQ("0", gc(xdtoa(exp(-INFINITY)))); + EXPECT_STREQ("NAN", gc(xdtoa(exp(NAN)))); + EXPECT_STREQ("0", gc(xdtoa(exp(-132098844872390)))); + EXPECT_STREQ("INFINITY", gc(xdtoa(exp(132098844872390)))); +} + +TEST(expf, test) { + EXPECT_STREQ("1", gc(xdtoaf(expf(0)))); + EXPECT_STREQ("1", gc(xdtoaf(expf(-0.)))); + EXPECT_STREQ("INFINITY", gc(xdtoaf(expf(INFINITY)))); + EXPECT_STREQ("0", gc(xdtoaf(expf(-INFINITY)))); + EXPECT_STREQ("NAN", gc(xdtoaf(expf(NAN)))); + EXPECT_STREQ("0", gc(xdtoaf(expf(-132098844872390)))); + EXPECT_STREQ("INFINITY", gc(xdtoaf(expf(132098844872390)))); +} + +TEST(exp, fun) { ASSERT_STREQ("7.389056", gc(xasprintf("%f", exp(2.0)))); ASSERT_STREQ("6.389056", gc(xasprintf("%f", expm1(2.0)))); ASSERT_STREQ("6.389056", gc(xasprintf("%f", exp(2.0) - 1.0))); diff --git a/test/libc/tinymath/expm1_test.c b/test/libc/tinymath/expm1_test.c new file mode 100644 index 000000000..e6cb82355 --- /dev/null +++ b/test/libc/tinymath/expm1_test.c @@ -0,0 +1,58 @@ +/*-*- 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 │ +│ │ +│ 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/math.h" +#include "libc/runtime/gc.h" +#include "libc/testlib/testlib.h" +#include "libc/x/x.h" + +#define expm1l(x) expm1l(VEIL("t", (long double)(x))) +#define expm1(x) expm1(VEIL("x", (double)(x))) +#define expm1f(x) expm1f(VEIL("x", (float)(x))) + +TEST(expm1l, test) { + EXPECT_STREQ("1.718281828459045", gc(xdtoal(expm1l(1)))); + EXPECT_STREQ("1.718281828459045", gc(xdtoal(expl(1) - 1))); + EXPECT_STREQ("0", gc(xdtoal(expm1l(0)))); + EXPECT_STREQ("0", gc(xdtoal(expm1l(-0.)))); + EXPECT_STREQ("NAN", gc(xdtoal(expm1l(NAN)))); + EXPECT_STREQ("-1", gc(xdtoal(expm1l(-INFINITY)))); + EXPECT_STREQ("INFINITY", gc(xdtoal(expm1l(INFINITY)))); + /* EXPECT_STREQ("-INFINITY", gc(xdtoal(expm1l(-132098844872390)))); */ + /* EXPECT_STREQ("INFINITY", gc(xdtoal(expm1l(132098844872390)))); */ +} + +TEST(expm1, test) { + EXPECT_STREQ("0", gc(xdtoa(expm1(0)))); + EXPECT_STREQ("0", gc(xdtoa(expm1(-0.)))); + EXPECT_STREQ("NAN", gc(xdtoa(expm1(NAN)))); + EXPECT_STREQ("-1", gc(xdtoa(expm1(-INFINITY)))); + EXPECT_STREQ("INFINITY", gc(xdtoa(expm1(INFINITY)))); + /* EXPECT_STREQ("-INFINITY", gc(xdtoa(expm1(-132098844872390)))); */ + /* EXPECT_STREQ("INFINITY", gc(xdtoa(expm1(132098844872390)))); */ +} + +TEST(expm1f, test) { + EXPECT_STREQ("0", gc(xdtoaf(expm1f(0)))); + EXPECT_STREQ("0", gc(xdtoaf(expm1f(-0.)))); + EXPECT_STREQ("NAN", gc(xdtoaf(expm1f(NAN)))); + EXPECT_STREQ("-1", gc(xdtoaf(expm1f(-INFINITY)))); + EXPECT_STREQ("INFINITY", gc(xdtoaf(expm1f(INFINITY)))); + /* EXPECT_STREQ("-INFINITY", gc(xdtoaf(expm1f(-132098844872390)))); */ + /* EXPECT_STREQ("INFINITY", gc(xdtoaf(expm1f(132098844872390)))); */ +} diff --git a/test/libc/tinymath/fabs_test.c b/test/libc/tinymath/fabs_test.c index 44f18f7d2..2214e13a4 100644 --- a/test/libc/tinymath/fabs_test.c +++ b/test/libc/tinymath/fabs_test.c @@ -17,9 +17,39 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/math.h" +#include "libc/runtime/gc.h" #include "libc/testlib/testlib.h" +#include "libc/x/x.h" + +#define fabsl(x) fabsl(VEIL("t", (long double)(x))) +#define fabs(x) fabs(VEIL("x", (double)(x))) +#define fabsf(x) fabsf(VEIL("x", (float)(x))) + +TEST(fabsl, test) { + EXPECT_STREQ("0", gc(xdtoal(fabsl(-0.)))); + EXPECT_STREQ("0", gc(xdtoal(fabsl(-0.)))); + EXPECT_STREQ("NAN", gc(xdtoal(fabsl(NAN)))); + EXPECT_STREQ("INFINITY", gc(xdtoal(fabsl(INFINITY)))); + EXPECT_STREQ("INFINITY", gc(xdtoal(fabsl(-INFINITY)))); +} TEST(fabs, test) { + EXPECT_STREQ("0", gc(xdtoa(fabs(-0.)))); + EXPECT_STREQ("0", gc(xdtoa(fabs(-0.)))); + EXPECT_STREQ("NAN", gc(xdtoa(fabs(NAN)))); + EXPECT_STREQ("INFINITY", gc(xdtoa(fabs(INFINITY)))); + EXPECT_STREQ("INFINITY", gc(xdtoa(fabs(-INFINITY)))); +} + +TEST(fabsf, test) { + EXPECT_STREQ("0", gc(xdtoaf(fabsf(-0.)))); + EXPECT_STREQ("0", gc(xdtoaf(fabsf(-0.)))); + EXPECT_STREQ("NAN", gc(xdtoaf(fabsf(NAN)))); + EXPECT_STREQ("INFINITY", gc(xdtoaf(fabsf(INFINITY)))); + EXPECT_STREQ("INFINITY", gc(xdtoaf(fabsf(-INFINITY)))); +} + +TEST(fabs, stuff) { EXPECT_LDBL_EQ(3.14, fabs(3.14)); EXPECT_LDBL_EQ(3.14, fabs(-3.14)); EXPECT_EQ(1, !!isnan(fabs(NAN))); diff --git a/test/libc/tinymath/fmod_test.c b/test/libc/tinymath/fmod_test.c new file mode 100644 index 000000000..14bb2e410 --- /dev/null +++ b/test/libc/tinymath/fmod_test.c @@ -0,0 +1,73 @@ +/*-*- 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 │ +│ │ +│ 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/math.h" +#include "libc/rand/rand.h" +#include "libc/runtime/gc.h" +#include "libc/testlib/ezbench.h" +#include "libc/testlib/testlib.h" +#include "libc/x/x.h" + +int rando; + +void SetUp(void) { + rando = rand() & 0xffff; +} + +TEST(fmodl, test) { + EXPECT_STREQ("0", gc(xdtoal(fmodl(0, rando)))); + EXPECT_STREQ("NAN", gc(xdtoal(fmodl(1, NAN)))); + EXPECT_STREQ("NAN", gc(xdtoal(fmodl(NAN, 1)))); + EXPECT_STREQ("-NAN", gc(xdtoal(fmodl(INFINITY, 1)))); + EXPECT_STREQ("-NAN", gc(xdtoal(fmodl(1, 0)))); + EXPECT_STREQ("8", gc(xdtoal(fmodl(8, 32)))); + EXPECT_STREQ("8e+100", gc(xdtoal(fmodl(8e100, 32e100)))); + EXPECT_STREQ("5.319372648326541e+255", + gc(xdtoal(ldexpl(6381956970095103, 797)))); + EXPECT_STREQ(".09287409360354737", + gc(xdtoal(fmodl(ldexpl(6381956970095103, 797), M_2_PI)))); +} + +TEST(fmod, test) { + EXPECT_STREQ("0", gc(xdtoa(fmod(0, rando)))); + EXPECT_STREQ("NAN", gc(xdtoa(fmod(1, NAN)))); + EXPECT_STREQ("NAN", gc(xdtoa(fmod(NAN, 1)))); + EXPECT_STREQ("-NAN", gc(xdtoa(fmod(INFINITY, 1)))); + EXPECT_STREQ("-NAN", gc(xdtoa(fmod(1, 0)))); + EXPECT_STREQ("8", gc(xdtoa(fmod(8, 32)))); + EXPECT_STREQ("8e+100", gc(xdtoa(fmod(8e100, 32e100)))); + EXPECT_STREQ("5.31937264832654e+255", + gc(xdtoa(ldexp(6381956970095103, 797)))); + EXPECT_STREQ(".0928740936035474", + gc(xdtoa(fmod(ldexp(6381956970095103, 797), M_2_PI)))); +} + +TEST(fmodf, test) { + EXPECT_STREQ("0", gc(xdtoaf(fmodf(0, rando)))); + EXPECT_STREQ("NAN", gc(xdtoaf(fmodf(1, NAN)))); + EXPECT_STREQ("NAN", gc(xdtoaf(fmodf(NAN, 1)))); + EXPECT_STREQ("-NAN", gc(xdtoaf(fmodf(INFINITY, 1)))); + EXPECT_STREQ("-NAN", gc(xdtoaf(fmodf(1, 0)))); + EXPECT_STREQ("8", gc(xdtoaf(fmodf(8, 32)))); + EXPECT_STREQ("8e+20", gc(xdtoaf(fmodf(8e20, 32e20)))); +} + +BENCH(fmod, bench) { + EZBENCH2("fmod eze", donothing, fmodl(8, 32)); + EZBENCH2("fmod big", donothing, fmodl(5.319372648326541e+255, M_2_PI)); +} diff --git a/test/libc/tinymath/hypot_test.c b/test/libc/tinymath/hypot_test.c index 7221cae35..f85dcb250 100644 --- a/test/libc/tinymath/hypot_test.c +++ b/test/libc/tinymath/hypot_test.c @@ -21,6 +21,11 @@ #include "libc/testlib/testlib.h" #include "libc/x/x.h" +#define hypotl(x, y) \ + hypotl(VEIL("t", (long double)(x)), VEIL("t", (long double)(y))) +#define hypot(x, y) hypot(VEIL("x", (double)(x)), VEIL("x", (double)(y))) +#define hypotf(x, y) hypotf(VEIL("x", (float)(x)), VEIL("x", (float)(y))) + TEST(hypot, test) { EXPECT_STREQ("0", gc(xdtoa(hypot(0, 0)))); EXPECT_STREQ("3", gc(xdtoa(hypot(3, 0)))); @@ -33,12 +38,12 @@ TEST(hypot, test) { EXPECT_STREQ("5", gc(xdtoa(hypot(4, -3)))); EXPECT_STREQ("5", gc(xdtoa(hypot(-3, -4)))); EXPECT_STREQ("5", gc(xdtoa(hypot(-4, -3)))); - EXPECT_STREQ("1.414213562373095", gc(xdtoa(hypot(1, 1)))); - EXPECT_STREQ("1.414213562373095", gc(xdtoa(hypot(1, -1)))); - EXPECT_STREQ("1.414213562373095", gc(xdtoa(hypot(-1, 1)))); - EXPECT_STREQ("1.414213626012708", gc(xdtoa(hypot(1.0000001, .99999999)))); - EXPECT_STREQ("1.414213626012708", gc(xdtoa(hypot(.99999999, 1.0000001)))); - EXPECT_STREQ("1.414213562373095e+154", gc(xdtoa(hypot(1e154, 1e154)))); + EXPECT_STREQ("1.4142135623731", gc(xdtoa(hypot(1, 1)))); + EXPECT_STREQ("1.4142135623731", gc(xdtoa(hypot(1, -1)))); + EXPECT_STREQ("1.4142135623731", gc(xdtoa(hypot(-1, 1)))); + EXPECT_STREQ("1.41421362601271", gc(xdtoa(hypot(1.0000001, .99999999)))); + EXPECT_STREQ("1.41421362601271", gc(xdtoa(hypot(.99999999, 1.0000001)))); + EXPECT_STREQ("1.4142135623731e+154", gc(xdtoa(hypot(1e154, 1e154)))); EXPECT_STREQ("NAN", gc(xdtoa(hypot(0, NAN)))); EXPECT_STREQ("NAN", gc(xdtoa(hypot(NAN, 0)))); EXPECT_STREQ("NAN", gc(xdtoa(hypot(NAN, NAN)))); @@ -61,12 +66,12 @@ TEST(hypotf, test) { EXPECT_STREQ("5", gc(xdtoa(hypotf(4, -3)))); EXPECT_STREQ("5", gc(xdtoa(hypotf(-3, -4)))); EXPECT_STREQ("5", gc(xdtoa(hypotf(-4, -3)))); - EXPECT_STREQ("1.414214", gc(xdtoaf(hypotf(1, 1)))); - EXPECT_STREQ("1.414214", gc(xdtoaf(hypotf(1, -1)))); - EXPECT_STREQ("1.414214", gc(xdtoaf(hypotf(-1, 1)))); - EXPECT_STREQ("1.414214", gc(xdtoaf(hypotf(1.000001, 0.999999)))); - EXPECT_STREQ("1.414214", gc(xdtoaf(hypotf(0.999999, 1.000001)))); - EXPECT_STREQ("1.414214e+38", gc(xdtoaf(hypotf(1e38, 1e38)))); + EXPECT_STREQ("1.41421", gc(xdtoaf(hypotf(1, 1)))); + EXPECT_STREQ("1.41421", gc(xdtoaf(hypotf(1, -1)))); + EXPECT_STREQ("1.41421", gc(xdtoaf(hypotf(-1, 1)))); + EXPECT_STREQ("1.41421", gc(xdtoaf(hypotf(1.000001, 0.999999)))); + EXPECT_STREQ("1.41421", gc(xdtoaf(hypotf(0.999999, 1.000001)))); + EXPECT_STREQ("1.41421e+38", gc(xdtoaf(hypotf(1e38, 1e38)))); EXPECT_STREQ("NAN", gc(xdtoaf(hypotf(0, NAN)))); EXPECT_STREQ("NAN", gc(xdtoaf(hypotf(NAN, 0)))); EXPECT_STREQ("NAN", gc(xdtoaf(hypotf(NAN, NAN)))); @@ -78,31 +83,31 @@ TEST(hypotf, test) { } TEST(hypotll, test) { - EXPECT_STREQ("0", gc(xdtoa(hypotl(0, 0)))); - EXPECT_STREQ("3", gc(xdtoa(hypotl(3, 0)))); - EXPECT_STREQ("3", gc(xdtoa(hypotl(0, 3)))); - EXPECT_STREQ("5", gc(xdtoa(hypotl(3, 4)))); - EXPECT_STREQ("5", gc(xdtoa(hypotl(4, 3)))); - EXPECT_STREQ("5", gc(xdtoa(hypotl(3, -4)))); - EXPECT_STREQ("5", gc(xdtoa(hypotl(-4, 3)))); - EXPECT_STREQ("5", gc(xdtoa(hypotl(-3, 4)))); - EXPECT_STREQ("5", gc(xdtoa(hypotl(4, -3)))); - EXPECT_STREQ("5", gc(xdtoa(hypotl(-3, -4)))); - EXPECT_STREQ("5", gc(xdtoa(hypotl(-4, -3)))); - EXPECT_STREQ("1.414213562373095", gc(xdtoa(hypotl(1, 1)))); - EXPECT_STREQ("1.414213562373095", gc(xdtoa(hypotl(1, -1)))); - EXPECT_STREQ("1.414213562373095", gc(xdtoa(hypotl(-1, 1)))); - EXPECT_STREQ("1.414213626012708", gc(xdtoa(hypotl(1.0000001, .99999999)))); - EXPECT_STREQ("1.414213626012708", gc(xdtoa(hypotl(.99999999, 1.0000001)))); - EXPECT_STREQ("1.414213562373095e+4931", gc(xdtoa(hypotl(1e4931L, 1e4931L)))); - EXPECT_STREQ("NAN", gc(xdtoa(hypotl(0, NAN)))); - EXPECT_STREQ("NAN", gc(xdtoa(hypotl(NAN, 0)))); - EXPECT_STREQ("NAN", gc(xdtoa(hypotl(NAN, NAN)))); - EXPECT_STREQ("INFINITY", gc(xdtoa(hypotl(INFINITY, 0)))); - EXPECT_STREQ("INFINITY", gc(xdtoa(hypotl(0, INFINITY)))); - EXPECT_STREQ("INFINITY", gc(xdtoa(hypotl(INFINITY, NAN)))); - EXPECT_STREQ("INFINITY", gc(xdtoa(hypotl(NAN, INFINITY)))); - EXPECT_STREQ("INFINITY", gc(xdtoa(hypotl(INFINITY, INFINITY)))); + EXPECT_STREQ("0", gc(xdtoal(hypotl(0, 0)))); + EXPECT_STREQ("3", gc(xdtoal(hypotl(3, 0)))); + EXPECT_STREQ("3", gc(xdtoal(hypotl(0, 3)))); + EXPECT_STREQ("5", gc(xdtoal(hypotl(3, 4)))); + EXPECT_STREQ("5", gc(xdtoal(hypotl(4, 3)))); + EXPECT_STREQ("5", gc(xdtoal(hypotl(3, -4)))); + EXPECT_STREQ("5", gc(xdtoal(hypotl(-4, 3)))); + EXPECT_STREQ("5", gc(xdtoal(hypotl(-3, 4)))); + EXPECT_STREQ("5", gc(xdtoal(hypotl(4, -3)))); + EXPECT_STREQ("5", gc(xdtoal(hypotl(-3, -4)))); + EXPECT_STREQ("5", gc(xdtoal(hypotl(-4, -3)))); + EXPECT_STREQ("1.414213562373095", gc(xdtoal(hypotl(1, 1)))); + EXPECT_STREQ("1.414213562373095", gc(xdtoal(hypotl(1, -1)))); + EXPECT_STREQ("1.414213562373095", gc(xdtoal(hypotl(-1, 1)))); + EXPECT_STREQ("1.414213626012708", gc(xdtoal(hypotl(1.0000001, .99999999)))); + EXPECT_STREQ("1.414213626012708", gc(xdtoal(hypotl(.99999999, 1.0000001)))); + EXPECT_STREQ("1.414213562373095e+4931", gc(xdtoal(hypotl(1e4931L, 1e4931L)))); + EXPECT_STREQ("NAN", gc(xdtoal(hypotl(0, NAN)))); + EXPECT_STREQ("NAN", gc(xdtoal(hypotl(NAN, 0)))); + EXPECT_STREQ("NAN", gc(xdtoal(hypotl(NAN, NAN)))); + EXPECT_STREQ("INFINITY", gc(xdtoal(hypotl(INFINITY, 0)))); + EXPECT_STREQ("INFINITY", gc(xdtoal(hypotl(0, INFINITY)))); + EXPECT_STREQ("INFINITY", gc(xdtoal(hypotl(INFINITY, NAN)))); + EXPECT_STREQ("INFINITY", gc(xdtoal(hypotl(NAN, INFINITY)))); + EXPECT_STREQ("INFINITY", gc(xdtoal(hypotl(INFINITY, INFINITY)))); } BENCH(hypot, bench) { diff --git a/test/libc/tinymath/ldexp_test.c b/test/libc/tinymath/ldexp_test.c index 951582df6..91288f837 100644 --- a/test/libc/tinymath/ldexp_test.c +++ b/test/libc/tinymath/ldexp_test.c @@ -17,12 +17,83 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/math.h" +#include "libc/rand/rand.h" #include "libc/runtime/gc.h" #include "libc/stdio/stdio.h" #include "libc/testlib/testlib.h" #include "libc/x/x.h" +int rando; + +void SetUp(void) { + rando = rand() & 0xffff; +} + +TEST(ldexpl, test) { + EXPECT_EQ(rando, ldexpl(rando, 0)); + EXPECT_STREQ("NAN", gc(xdtoal(ldexpl(NAN, 0)))); + EXPECT_STREQ("-NAN", gc(xdtoal(ldexpl(-NAN, 0)))); + EXPECT_STREQ("INFINITY", gc(xdtoal(ldexpl(INFINITY, 0)))); + EXPECT_STREQ("-INFINITY", gc(xdtoal(ldexpl(-INFINITY, 0)))); + EXPECT_STREQ("NAN", gc(xdtoal(ldexpl(NAN, 1)))); + EXPECT_STREQ("-NAN", gc(xdtoal(ldexpl(-NAN, 1)))); + EXPECT_STREQ("INFINITY", gc(xdtoal(ldexpl(INFINITY, 1)))); + EXPECT_STREQ("-INFINITY", gc(xdtoal(ldexpl(-INFINITY, 1)))); + EXPECT_STREQ("16384", gc(xdtoal(log2l(LDBL_MAX)))); + EXPECT_STREQ(".00390625", gc(xdtoal(ldexpl(1, -8)))); + EXPECT_STREQ("0", gc(xdtoal(ldexpl(0, -8)))); + EXPECT_STREQ("0", gc(xdtoal(ldexpl(0, 8)))); + EXPECT_STREQ("256", gc(xdtoal(ldexpl(1, 8)))); + EXPECT_STREQ("512", gc(xdtoal(ldexpl(2, 8)))); + EXPECT_STREQ("768", gc(xdtoal(ldexpl(3, 8)))); + EXPECT_STREQ("6.997616471358197e+3461", gc(xdtoal(ldexpl(1, 11500)))); + EXPECT_STREQ("INFINITY", gc(xdtoal(ldexpl(1, 999999)))); + EXPECT_STREQ("0", gc(xdtoal(ldexpl(1, -999999)))); +} + TEST(ldexp, test) { + EXPECT_EQ(rando, ldexp(rando, 0)); + EXPECT_STREQ("NAN", gc(xdtoa(ldexp(NAN, 0)))); + EXPECT_STREQ("-NAN", gc(xdtoa(ldexp(-NAN, 0)))); + EXPECT_STREQ("INFINITY", gc(xdtoa(ldexp(INFINITY, 0)))); + EXPECT_STREQ("-INFINITY", gc(xdtoa(ldexp(-INFINITY, 0)))); + EXPECT_STREQ("NAN", gc(xdtoa(ldexp(NAN, 1)))); + EXPECT_STREQ("-NAN", gc(xdtoa(ldexp(-NAN, 1)))); + EXPECT_STREQ("INFINITY", gc(xdtoa(ldexp(INFINITY, 1)))); + EXPECT_STREQ("-INFINITY", gc(xdtoa(ldexp(-INFINITY, 1)))); + EXPECT_STREQ("16384", gc(xdtoa(log2l(LDBL_MAX)))); + EXPECT_STREQ(".00390625", gc(xdtoa(ldexp(1, -8)))); + EXPECT_STREQ("0", gc(xdtoa(ldexp(0, -8)))); + EXPECT_STREQ("0", gc(xdtoa(ldexp(0, 8)))); + EXPECT_STREQ("256", gc(xdtoa(ldexp(1, 8)))); + EXPECT_STREQ("512", gc(xdtoa(ldexp(2, 8)))); + EXPECT_STREQ("768", gc(xdtoa(ldexp(3, 8)))); + EXPECT_STREQ("INFINITY", gc(xdtoa(ldexp(1, 999999)))); + EXPECT_STREQ("0", gc(xdtoa(ldexp(1, -999999)))); +} + +TEST(ldexpf, test) { + EXPECT_EQ(rando, ldexpf(rando, 0)); + EXPECT_STREQ("NAN", gc(xdtoaf(ldexpf(NAN, 0)))); + EXPECT_STREQ("-NAN", gc(xdtoaf(ldexpf(-NAN, 0)))); + EXPECT_STREQ("INFINITY", gc(xdtoaf(ldexpf(INFINITY, 0)))); + EXPECT_STREQ("-INFINITY", gc(xdtoaf(ldexpf(-INFINITY, 0)))); + EXPECT_STREQ("NAN", gc(xdtoaf(ldexpf(NAN, 1)))); + EXPECT_STREQ("-NAN", gc(xdtoaf(ldexpf(-NAN, 1)))); + EXPECT_STREQ("INFINITY", gc(xdtoaf(ldexpf(INFINITY, 1)))); + EXPECT_STREQ("-INFINITY", gc(xdtoaf(ldexpf(-INFINITY, 1)))); + EXPECT_STREQ("16384", gc(xdtoaf(log2l(LDBL_MAX)))); + EXPECT_STREQ(".00390625", gc(xdtoaf(ldexpf(1, -8)))); + EXPECT_STREQ("0", gc(xdtoaf(ldexpf(0, -8)))); + EXPECT_STREQ("0", gc(xdtoaf(ldexpf(0, 8)))); + EXPECT_STREQ("256", gc(xdtoaf(ldexpf(1, 8)))); + EXPECT_STREQ("512", gc(xdtoaf(ldexpf(2, 8)))); + EXPECT_STREQ("768", gc(xdtoaf(ldexpf(3, 8)))); + EXPECT_STREQ("INFINITY", gc(xdtoaf(ldexpf(1, 999999)))); + EXPECT_STREQ("0", gc(xdtoaf(ldexpf(1, -999999)))); +} + +TEST(ldexp, stuff) { volatile int twopow = 5; volatile double pi = 3.14; ASSERT_STREQ("100.48", gc(xasprintf("%.2f", ldexp(pi, twopow)))); diff --git a/test/libc/tinymath/log1p_test.c b/test/libc/tinymath/log1p_test.c new file mode 100644 index 000000000..6a08a3bb0 --- /dev/null +++ b/test/libc/tinymath/log1p_test.c @@ -0,0 +1,47 @@ +/*-*- 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 │ +│ │ +│ 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/math.h" +#include "libc/runtime/gc.h" +#include "libc/testlib/testlib.h" +#include "libc/x/x.h" + +TEST(log1pl, test) { + EXPECT_STREQ("1", gc(xdtoal(log1pl(1.71828182845904523536L)))); + EXPECT_STREQ("NAN", gc(xdtoal(log1pl(NAN)))); + EXPECT_STREQ("INFINITY", gc(xdtoal(log1pl(INFINITY)))); + EXPECT_STREQ("-INFINITY", gc(xdtoal(log1pl(-1)))); + EXPECT_STREQ("-NAN", gc(xdtoal(log1pl(-2)))); +} + +TEST(log1p, test) { + EXPECT_STREQ("1", gc(xdtoa(log1p(M_E - 1)))); + EXPECT_STREQ("2", gc(xdtoa(log1p(M_E * M_E - 1)))); + EXPECT_STREQ("NAN", gc(xdtoa(log1p(NAN)))); + EXPECT_STREQ("INFINITY", gc(xdtoa(log1p(INFINITY)))); + EXPECT_STREQ("-INFINITY", gc(xdtoa(log1p(-1)))); + EXPECT_STREQ("-NAN", gc(xdtoa(log1p(-2)))); +} + +TEST(log1pf, test) { + EXPECT_STREQ("1", gc(xdtoaf(log1pf(M_E - 1)))); + EXPECT_STREQ("NAN", gc(xdtoaf(log1pf(NAN)))); + EXPECT_STREQ("INFINITY", gc(xdtoaf(log1pf(INFINITY)))); + EXPECT_STREQ("-INFINITY", gc(xdtoaf(log1pf(-1)))); + EXPECT_STREQ("-NAN", gc(xdtoaf(log1pf(-2)))); +} diff --git a/test/libc/tinymath/log2_test.c b/test/libc/tinymath/log2_test.c new file mode 100644 index 000000000..c09cdaa7b --- /dev/null +++ b/test/libc/tinymath/log2_test.c @@ -0,0 +1,56 @@ +/*-*- 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 │ +│ │ +│ 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/math.h" +#include "libc/runtime/gc.h" +#include "libc/testlib/testlib.h" +#include "libc/x/x.h" + +TEST(log2l, test) { + EXPECT_STREQ("1", gc(xdtoal(log2l(2)))); + EXPECT_STREQ("NAN", gc(xdtoal(log2l(NAN)))); + EXPECT_STREQ("0", gc(xdtoal(log2l(1)))); + EXPECT_STREQ("INFINITY", gc(xdtoal(log2l(INFINITY)))); + EXPECT_STREQ("-INFINITY", gc(xdtoal(log2l(0)))); + EXPECT_STREQ("-INFINITY", gc(xdtoal(log2l(-0.)))); + EXPECT_STREQ("-NAN", gc(xdtoal(log2l(-1)))); + EXPECT_STREQ("-NAN", gc(xdtoal(log2l(-2)))); +} + +TEST(log2, test) { + EXPECT_STREQ("1", gc(xdtoa(log2(2)))); + EXPECT_STREQ("2", gc(xdtoa(log2(2 * 2)))); + EXPECT_STREQ("NAN", gc(xdtoa(log2(NAN)))); + EXPECT_STREQ("0", gc(xdtoa(log2(1)))); + EXPECT_STREQ("INFINITY", gc(xdtoa(log2(INFINITY)))); + EXPECT_STREQ("-INFINITY", gc(xdtoa(log2(0)))); + EXPECT_STREQ("-INFINITY", gc(xdtoa(log2(-0.)))); + EXPECT_STREQ("-NAN", gc(xdtoa(log2(-1)))); + EXPECT_STREQ("-NAN", gc(xdtoa(log2(-2)))); +} + +TEST(log2f, test) { + EXPECT_STREQ("1", gc(xdtoaf(log2f(2)))); + EXPECT_STREQ("NAN", gc(xdtoaf(log2f(NAN)))); + EXPECT_STREQ("0", gc(xdtoaf(log2f(1)))); + EXPECT_STREQ("INFINITY", gc(xdtoaf(log2f(INFINITY)))); + EXPECT_STREQ("-INFINITY", gc(xdtoaf(log2f(0)))); + EXPECT_STREQ("-INFINITY", gc(xdtoaf(log2f(-0.)))); + EXPECT_STREQ("-NAN", gc(xdtoaf(log2f(-1)))); + EXPECT_STREQ("-NAN", gc(xdtoaf(log2f(-2)))); +} diff --git a/test/libc/tinymath/log_test.c b/test/libc/tinymath/log_test.c new file mode 100644 index 000000000..ceb8d66b1 --- /dev/null +++ b/test/libc/tinymath/log_test.c @@ -0,0 +1,56 @@ +/*-*- 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 │ +│ │ +│ 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/math.h" +#include "libc/runtime/gc.h" +#include "libc/testlib/testlib.h" +#include "libc/x/x.h" + +TEST(logl, test) { + EXPECT_STREQ("1", gc(xdtoal(logl(2.71828182845904523536L)))); + EXPECT_STREQ("NAN", gc(xdtoal(logl(NAN)))); + EXPECT_STREQ("0", gc(xdtoal(logl(1)))); + EXPECT_STREQ("INFINITY", gc(xdtoal(logl(INFINITY)))); + EXPECT_STREQ("-INFINITY", gc(xdtoal(logl(0)))); + EXPECT_STREQ("-INFINITY", gc(xdtoal(logl(-0.)))); + EXPECT_STREQ("-NAN", gc(xdtoal(logl(-1)))); + EXPECT_STREQ("-NAN", gc(xdtoal(logl(-2)))); +} + +TEST(log, test) { + EXPECT_STREQ("1", gc(xdtoa(log(M_E)))); + EXPECT_STREQ("2", gc(xdtoa(log(M_E * M_E)))); + EXPECT_STREQ("NAN", gc(xdtoa(log(NAN)))); + EXPECT_STREQ("0", gc(xdtoa(log(1)))); + EXPECT_STREQ("INFINITY", gc(xdtoa(log(INFINITY)))); + EXPECT_STREQ("-INFINITY", gc(xdtoa(log(0)))); + EXPECT_STREQ("-INFINITY", gc(xdtoa(log(-0.)))); + EXPECT_STREQ("-NAN", gc(xdtoa(log(-1)))); + EXPECT_STREQ("-NAN", gc(xdtoa(log(-2)))); +} + +TEST(logf, test) { + EXPECT_STREQ("1", gc(xdtoaf(logf(M_E)))); + EXPECT_STREQ("NAN", gc(xdtoaf(logf(NAN)))); + EXPECT_STREQ("0", gc(xdtoaf(logf(1)))); + EXPECT_STREQ("INFINITY", gc(xdtoaf(logf(INFINITY)))); + EXPECT_STREQ("-INFINITY", gc(xdtoaf(logf(0)))); + EXPECT_STREQ("-INFINITY", gc(xdtoaf(logf(-0.)))); + EXPECT_STREQ("-NAN", gc(xdtoaf(logf(-1)))); + EXPECT_STREQ("-NAN", gc(xdtoaf(logf(-2)))); +} diff --git a/test/libc/tinymath/powl_test.c b/test/libc/tinymath/powl_test.c index ba2411feb..2011db3e9 100644 --- a/test/libc/tinymath/powl_test.c +++ b/test/libc/tinymath/powl_test.c @@ -16,39 +16,47 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/calls/struct/sigaction.h" +#include "libc/calls/struct/siginfo.h" +#include "libc/calls/ucontext.h" #include "libc/math.h" #include "libc/runtime/gc.h" +#include "libc/runtime/pc.internal.h" +#include "libc/sysv/consts/sa.h" +#include "libc/sysv/consts/sig.h" #include "libc/testlib/ezbench.h" #include "libc/testlib/testlib.h" #include "libc/x/x.h" +double powa(double x, double y) { + return exp2(fmod(y * log2(x), 1)) * exp2(y); +} + TEST(powl, testLongDouble) { + EXPECT_TRUE(isnan(powl(-1, 1.1))); + EXPECT_STREQ("1e+4932", gc(xdtoal(powl(10, 4932)))); + EXPECT_STREQ("INFINITY", gc(xdtoal(powl(10, 4933)))); + EXPECT_STREQ("0", gc(xdtoal(powl(10, -5000)))); + EXPECT_STREQ("1.063382396627933e+37", gc(xdtoal(powl(2, 123)))); /* .4248496805467504836322459796959084815827285786480897 */ - EXPECT_STARTSWITH(".4248496805467504", gc(xdtoa(powl(0.7, 2.4)))); + EXPECT_STARTSWITH(".4248496805467504", gc(xdtoal(powl(0.7, 2.4)))); } TEST(powl, testDouble) { - EXPECT_STARTSWITH(".4248496805467504", gc(xdtoa(pow(0.7, 2.4)))); + EXPECT_STREQ("1e+308", gc(xdtoa(pow(10, 308)))); + EXPECT_STREQ("INFINITY", gc(xdtoa(pow(10, 309)))); + EXPECT_STARTSWITH(".42484968054675", gc(xdtoa(pow(0.7, 2.4)))); } TEST(powl, testFloat) { EXPECT_STARTSWITH(".4248496", gc(xdtoa(powf(0.7f, 2.4f)))); } -static long double do_powl(void) { - return CONCEAL("t", powl(CONCEAL("t", 0.7), CONCEAL("t", 0.2))); -} - -static double do_pow(void) { - return CONCEAL("x", pow(CONCEAL("x", 0.7), CONCEAL("x", 0.2))); -} - -static float do_powf(void) { - return CONCEAL("x", powf(CONCEAL("x", 0.7f), CONCEAL("x", 0.2f))); -} - BENCH(powl, bench) { - EZBENCH2("powl", donothing, do_powl()); /* ~61ns */ - EZBENCH2("pow", donothing, do_pow()); /* ~64ns */ - EZBENCH2("powf", donothing, do_powf()); /* ~64ns */ + double _pow(double, double) asm("pow"); + float _powf(float, float) asm("powf"); + long double _powl(long double, long double) asm("powl"); + EZBENCH2("pow", donothing, _pow(.7, .2)); /* ~51ns */ + EZBENCH2("powf", donothing, _powf(.7, .2)); /* ~52ns */ + EZBENCH2("powl", donothing, _powl(.7, .2)); /* ~53ns */ } diff --git a/test/libc/tinymath/round_test.c b/test/libc/tinymath/round_test.c index 0771b10c4..b294cac1a 100644 --- a/test/libc/tinymath/round_test.c +++ b/test/libc/tinymath/round_test.c @@ -23,6 +23,10 @@ #include "libc/testlib/testlib.h" #include "libc/x/x.h" +#define roundl(x) roundl(VEIL("t", (long double)(x))) +#define round(x) round(VEIL("x", (double)(x))) +#define roundf(x) roundf(VEIL("x", (float)(x))) + FIXTURE(intrin, disableHardwareExtensions) { memset((/*unconst*/ void *)kCpuids, 0, sizeof(kCpuids)); } diff --git a/test/libc/tinymath/sinl_test.c b/test/libc/tinymath/sinl_test.c index 92d534fed..60bdf198f 100644 --- a/test/libc/tinymath/sinl_test.c +++ b/test/libc/tinymath/sinl_test.c @@ -22,21 +22,58 @@ #include "libc/testlib/testlib.h" #include "libc/x/x.h" -char buf[32]; +#define sinl(x) sinl(VEIL("t", (long double)(x))) +#define sin(x) sin(VEIL("x", (double)(x))) +#define sinf(x) sinf(VEIL("x", (float)(x))) -TEST(sinl, testLongDouble) { - EXPECT_STREQ(".479425538604203", gc(xdtoa(sinl(.5)))); - EXPECT_STREQ("-.479425538604203", gc(xdtoa(sinl(-.5)))); +void SetUp(void) { + /* 8087 FPU Control Word + IM: Invalid Operation ───────────────┐ + DM: Denormal Operand ───────────────┐│ + ZM: Zero Divide ───────────────────┐││ + OM: Overflow ─────────────────────┐│││ + UM: Underflow ───────────────────┐││││ + PM: Precision ──────────────────┐│││││ + PC: Precision Control ────────┐ ││││││ + {float,∅,double,long double} │ ││││││ + RC: Rounding Control ───────┐ │ ││││││ + {even, →-∞, →+∞, →0} │┌┤ ││││││ + ┌┤││ ││││││ + d││││rr││││││*/ + int x87cw = 0b0000000000000000001101100001; + asm volatile("fldcw\t%0" : /* no outputs */ : "m"(x87cw)); } -TEST(sinl, testDouble) { +TEST(sinl, test) { + EXPECT_STREQ("NAN", gc(xdtoal(sinl(NAN)))); + EXPECT_STREQ("-NAN", gc(xdtoal(sinl(+INFINITY)))); + EXPECT_STREQ("-NAN", gc(xdtoal(sinl(-INFINITY)))); + EXPECT_STREQ(".479425538604203", gc(xdtoal(sinl(.5)))); + EXPECT_STREQ("-.479425538604203", gc(xdtoal(sinl(-.5)))); + EXPECT_STREQ(".8414709794048734", gc(xdtoal(sinl(.99999999)))); + /* EXPECT_STREQ("-.998836772397", gc(xdtoal(sinl(555555555555)))); */ + /* EXPECT_STREQ("1", gc(xdtoal(SINL(5.319372648326541e+255L)))); */ +} + +TEST(sin, test) { + EXPECT_TRUE(isnan(sin(NAN))); + EXPECT_TRUE(isnan(sin(+INFINITY))); + EXPECT_TRUE(isnan(sin(-INFINITY))); + EXPECT_STREQ("NAN", gc(xdtoa(sin(NAN)))); + EXPECT_STREQ(".479425538604203", gc(xdtoa(sin(.5)))); + EXPECT_STREQ("-.479425538604203", gc(xdtoa(sin(-.5)))); EXPECT_STREQ(".479425538604203", gc(xdtoa(sin(.5)))); EXPECT_STREQ("-.479425538604203", gc(xdtoa(sin(-.5)))); } -TEST(sinl, testFloat) { - EXPECT_STARTSWITH(".4794255", gc(xdtoa(sinf(.5f)))); - EXPECT_STARTSWITH("-.4794255", gc(xdtoa(sinf(-.5f)))); +TEST(sinf, test) { + EXPECT_TRUE(isnan(sinf(NAN))); + EXPECT_TRUE(isnan(sinf(+INFINITY))); + EXPECT_TRUE(isnan(sinf(-INFINITY))); + EXPECT_STREQ("NAN", gc(xdtoaf(sinf(NAN)))); + EXPECT_STARTSWITH(".479426", gc(xdtoaf(sinf(.5f)))); + EXPECT_STARTSWITH("-.479426", gc(xdtoaf(sinf(-.5f)))); + EXPECT_STARTSWITH(".873283", gc(xdtoaf(sinf(555)))); } BENCH(sinl, bench) { diff --git a/test/libc/tinymath/sqrt_test.c b/test/libc/tinymath/sqrt_test.c new file mode 100644 index 000000000..3a5debb7a --- /dev/null +++ b/test/libc/tinymath/sqrt_test.c @@ -0,0 +1,50 @@ +/*-*- 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 │ +│ │ +│ 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/math.h" +#include "libc/runtime/gc.h" +#include "libc/testlib/testlib.h" +#include "libc/x/x.h" + +#define sqrtl(x) sqrtl(VEIL("t", (long double)(x))) +#define sqrt(x) sqrt(VEIL("x", (double)(x))) +#define sqrtf(x) sqrtf(VEIL("x", (float)(x))) + +TEST(sqrtl, test) { + EXPECT_STREQ("7", gc(xdtoal(sqrtl(7 * 7)))); + EXPECT_STREQ("NAN", gc(xdtoal(sqrtl(NAN)))); + EXPECT_STREQ("0", gc(xdtoal(sqrtl(0)))); + EXPECT_STREQ("INFINITY", gc(xdtoal(sqrtl(INFINITY)))); + EXPECT_STREQ("-NAN", gc(xdtoal(sqrtl(-1)))); +} + +TEST(sqrt, test) { + EXPECT_STREQ("7", gc(xdtoa(sqrt(7 * 7)))); + EXPECT_STREQ("NAN", gc(xdtoa(sqrt(NAN)))); + EXPECT_STREQ("0", gc(xdtoa(sqrt(0)))); + EXPECT_STREQ("INFINITY", gc(xdtoa(sqrt(INFINITY)))); + EXPECT_STREQ("-NAN", gc(xdtoa(sqrt(-1)))); +} + +TEST(sqrtf, test) { + EXPECT_STREQ("7", gc(xdtoaf(sqrtf(7 * 7)))); + EXPECT_STREQ("NAN", gc(xdtoaf(sqrtf(NAN)))); + EXPECT_STREQ("0", gc(xdtoaf(sqrtf(0)))); + EXPECT_STREQ("INFINITY", gc(xdtoaf(sqrtf(INFINITY)))); + EXPECT_STREQ("-NAN", gc(xdtoaf(sqrtf(-1)))); +} diff --git a/test/libc/tinymath/test.mk b/test/libc/tinymath/test.mk index ebf6de72e..cd96e2294 100644 --- a/test/libc/tinymath/test.mk +++ b/test/libc/tinymath/test.mk @@ -23,13 +23,16 @@ TEST_LIBC_TINYMATH_CHECKS = \ $(TEST_LIBC_TINYMATH_SRCS_TEST:%.c=o/$(MODE)/%.com.runs) TEST_LIBC_TINYMATH_DIRECTDEPS = \ + LIBC_CALLS \ LIBC_FMT \ LIBC_INTRIN \ LIBC_MEM \ LIBC_NEXGEN32E \ + LIBC_RAND \ LIBC_RUNTIME \ LIBC_STR \ LIBC_STUBS \ + LIBC_SYSV \ LIBC_TESTLIB \ LIBC_TINYMATH \ LIBC_UNICODE \ @@ -52,7 +55,7 @@ o/$(MODE)/test/libc/tinymath/%.com.dbg: \ @$(APELINK) $(TEST_LIBC_TINYMATH_OBJS): \ - DEFAULT_CCFLAGS += \ + OVERRIDE_CFLAGS += \ -fno-builtin .PHONY: o/$(MODE)/test/libc/tinymath diff --git a/third_party/gdtoa/gdtoa.internal.h b/third_party/gdtoa/gdtoa.internal.h index 2b587bfad..c89364f52 100644 --- a/third_party/gdtoa/gdtoa.internal.h +++ b/third_party/gdtoa/gdtoa.internal.h @@ -10,10 +10,11 @@ Kudos go to Guy L. Steele, Jr. and Jon L. White\\n\ Copyright (C) 1997, 1998, 2000 by Lucent Technologies\""); asm(".include \"libc/disclaimer.inc\""); -#define IEEE_8087 1 -#define f_QNAN 0x7fc00000 -#define d_QNAN0 0x7ff80000 -#define d_QNAN1 0x0 +#define IEEE_Arith 1 +#define IEEE_8087 1 +#define f_QNAN 0x7fc00000 +#define d_QNAN0 0x7ff80000 +#define d_QNAN1 0x0 #if __NO_MATH_ERRNO__ + 0 #define NO_ERRNO 1 @@ -270,36 +271,7 @@ extern Char *REALLOC(Char *, size_t); #ifdef Bad_float_h -#ifdef IEEE_Arith -#define DBL_DIG 15 -#define DBL_MAX_10_EXP 308 -#define DBL_MAX_EXP 1024 -#define FLT_RADIX 2 -#define DBL_MAX 1.7976931348623157e+308 -#endif - -#ifdef IBM -#define DBL_DIG 16 -#define DBL_MAX_10_EXP 75 -#define DBL_MAX_EXP 63 -#define FLT_RADIX 16 -#define DBL_MAX 7.2370055773322621e+75 -#endif - -#ifdef VAX -#define DBL_DIG 16 -#define DBL_MAX_10_EXP 38 -#define DBL_MAX_EXP 127 -#define FLT_RADIX 2 -#define DBL_MAX 1.7014118346046923e+38 -#define n_bigtens 2 -#endif - -#ifndef LONG_MAX -#define LONG_MAX 2147483647 -#endif - -#else /* ifndef Bad_float_h */ +#else /* ifndef Bad_float_h */ #endif /* Bad_float_h */ #ifdef IEEE_Arith @@ -319,11 +291,7 @@ extern Char *REALLOC(Char *, size_t); extern "C" { #endif -#if defined(IEEE_8087) + defined(IEEE_MC68k) + defined(VAX) + defined(IBM) != 1 -Exactly one of IEEE_8087, IEEE_MC68k, VAX, or IBM should be defined. -#endif - - typedef union { +typedef union { double d; ULong L[2]; } U; @@ -515,14 +483,14 @@ extern double rnd_prod(double, double), rnd_quot(double, double); extern void ACQUIRE_DTOA_LOCK(unsigned int); extern void FREE_DTOA_LOCK(unsigned int); extern unsigned int dtoa_get_threadno(void); -#else /*}{*/ +#else /*}{*/ #define ACQUIRE_DTOA_LOCK(n) /*nothing*/ #define FREE_DTOA_LOCK(n) /*nothing*/ #define MTa /*nothing*/ #define MTb /*nothing*/ #define MTd /*nothing*/ #define MTk /*nothing*/ -#endif /*}}*/ +#endif /*}}*/ #define Kmax 9 diff --git a/tool/build/blinkenlights.c b/tool/build/blinkenlights.c index 47a336f23..1a1b95157 100644 --- a/tool/build/blinkenlights.c +++ b/tool/build/blinkenlights.c @@ -265,6 +265,7 @@ static int exitcode; static long ips; static long rombase; static long codesize; +static int64_t oldlen; static int64_t opstart; static int64_t mapsstart; static uint64_t readaddr; @@ -1574,6 +1575,7 @@ static void PreventBufferbloat(void) { static void Redraw(void) { int i, j; + oldlen = m->xedd->length; if (!IsShadow(m->readaddr) && !IsShadow(m->readaddr + m->readsize)) { readaddr = m->readaddr; readsize = m->readsize; @@ -1624,9 +1626,7 @@ static void Redraw(void) { static void ReactiveDraw(void) { if (tuimode) { - m->ip -= m->xedd->length; Redraw(); - m->ip += m->xedd->length; tick = speed; } } diff --git a/tool/build/lib/bitscan.c b/tool/build/lib/bitscan.c index 9b05b742b..d7f80910c 100644 --- a/tool/build/lib/bitscan.c +++ b/tool/build/lib/bitscan.c @@ -21,48 +21,6 @@ #include "tool/build/lib/machine.h" #include "tool/build/lib/modrm.h" -uint64_t AluBsr(struct Machine *m, uint32_t rde, uint64_t x) { - unsigned i; - if (Rexw(rde)) { - x &= 0xffffffffffffffff; - m->flags = SetFlag(m->flags, FLAGS_ZF, !x); - if (!x) return 0; - return 63 ^ __builtin_clzll(x); - } else if (!Osz(rde)) { - x &= 0xffffffff; - m->flags = SetFlag(m->flags, FLAGS_ZF, !x); - if (!x) return 0; - return 31 ^ __builtin_clz(x); - } else { - x &= 0xffff; - m->flags = SetFlag(m->flags, FLAGS_ZF, !x); - if (!x) return 0; - for (i = 15; !(x & 0x8000); --i) x <<= 1; - return i; - } -} - -uint64_t AluBsf(struct Machine *m, uint32_t rde, uint64_t x) { - unsigned i; - if (Rexw(rde)) { - x &= 0xffffffffffffffff; - m->flags = SetFlag(m->flags, FLAGS_ZF, !x); - if (!x) return 0; - return __builtin_ctzll(x); - } else if (!Osz(rde)) { - x &= 0xffffffff; - m->flags = SetFlag(m->flags, FLAGS_ZF, !x); - if (!x) return 0; - return __builtin_ctz(x); - } else { - x &= 0xffff; - m->flags = SetFlag(m->flags, FLAGS_ZF, !x); - if (!x) return 0; - for (i = 0; !(x & 1); ++i) x >>= 1; - return i; - } -} - uint64_t AluPopcnt(struct Machine *m, uint32_t rde, uint64_t x) { m->flags = SetFlag(m->flags, FLAGS_ZF, !x); m->flags = SetFlag(m->flags, FLAGS_CF, false); @@ -77,3 +35,111 @@ uint64_t AluPopcnt(struct Machine *m, uint32_t rde, uint64_t x) { x = (x + (x >> 8)) & 0x7f; return x; } + +uint64_t AluBsr(struct Machine *m, uint32_t rde, uint64_t x) { + unsigned i; + if (Rexw(rde)) { + x &= 0xffffffffffffffff; + if (Rep(rde) == 3) { + if (!x) { + m->flags = SetFlag(m->flags, FLAGS_CF, true); + m->flags = SetFlag(m->flags, FLAGS_ZF, false); + return 64; + } else { + m->flags = SetFlag(m->flags, FLAGS_CF, false); + m->flags = SetFlag(m->flags, FLAGS_ZF, x == 1); + } + } else { + m->flags = SetFlag(m->flags, FLAGS_ZF, !x); + if (!x) return 0; + } + return 63 ^ __builtin_clzll(x); + } else if (!Osz(rde)) { + x &= 0xffffffff; + if (Rep(rde) == 3) { + if (!x) { + m->flags = SetFlag(m->flags, FLAGS_CF, true); + m->flags = SetFlag(m->flags, FLAGS_ZF, false); + return 32; + } else { + m->flags = SetFlag(m->flags, FLAGS_CF, false); + m->flags = SetFlag(m->flags, FLAGS_ZF, x == 1); + } + } else { + m->flags = SetFlag(m->flags, FLAGS_ZF, !x); + if (!x) return 0; + } + return 31 ^ __builtin_clz(x); + } else { + x &= 0xffff; + if (Rep(rde) == 3) { + if (!x) { + m->flags = SetFlag(m->flags, FLAGS_CF, true); + m->flags = SetFlag(m->flags, FLAGS_ZF, false); + return 16; + } else { + m->flags = SetFlag(m->flags, FLAGS_CF, false); + m->flags = SetFlag(m->flags, FLAGS_ZF, x == 1); + } + } else { + m->flags = SetFlag(m->flags, FLAGS_ZF, !x); + if (!x) return 0; + } + for (i = 15; !(x & 0x8000); --i) x <<= 1; + return i; + } +} + +uint64_t AluBsf(struct Machine *m, uint32_t rde, uint64_t x) { + unsigned i; + if (Rexw(rde)) { + x &= 0xffffffffffffffff; + if (Rep(rde) == 3) { + if (!x) { + m->flags = SetFlag(m->flags, FLAGS_CF, true); + m->flags = SetFlag(m->flags, FLAGS_ZF, false); + return 64; + } else { + m->flags = SetFlag(m->flags, FLAGS_CF, false); + m->flags = SetFlag(m->flags, FLAGS_ZF, x & 1); + } + } else { + m->flags = SetFlag(m->flags, FLAGS_ZF, !x); + if (!x) return 0; + } + return __builtin_ctzll(x); + } else if (!Osz(rde)) { + x &= 0xffffffff; + if (Rep(rde) == 3) { + if (!x) { + m->flags = SetFlag(m->flags, FLAGS_CF, true); + m->flags = SetFlag(m->flags, FLAGS_ZF, false); + return 32; + } else { + m->flags = SetFlag(m->flags, FLAGS_CF, false); + m->flags = SetFlag(m->flags, FLAGS_ZF, x & 1); + } + } else { + m->flags = SetFlag(m->flags, FLAGS_ZF, !x); + if (!x) return 0; + } + return __builtin_ctz(x); + } else { + x &= 0xffff; + if (Rep(rde) == 3) { + if (!x) { + m->flags = SetFlag(m->flags, FLAGS_CF, true); + m->flags = SetFlag(m->flags, FLAGS_ZF, false); + return 16; + } else { + m->flags = SetFlag(m->flags, FLAGS_CF, false); + m->flags = SetFlag(m->flags, FLAGS_ZF, x & 1); + } + } else { + m->flags = SetFlag(m->flags, FLAGS_ZF, !x); + if (!x) return 0; + } + for (i = 0; !(x & 1); ++i) x >>= 1; + return i; + } +} diff --git a/tool/build/lib/disspec.c b/tool/build/lib/disspec.c index dfc286ce8..a097cb264 100644 --- a/tool/build/lib/disspec.c +++ b/tool/build/lib/disspec.c @@ -503,6 +503,7 @@ const char *DisSpecMap1(struct XedDecodedInst *x, char *p) { RCASE(0x74, DisOpPqQqVdqWdq(x, p, "pcmpeqb")); RCASE(0x75, DisOpPqQqVdqWdq(x, p, "pcmpeqw")); RCASE(0x76, DisOpPqQqVdqWdq(x, p, "pcmpeqd")); + RCASE(0x77, "emms"); RCASE(0x80 ... 0x8f, "jCC Jvds"); RCASE(0x90 ... 0x9f, "setCC Jvds"); RCASE(0xA0, "push %fs"); @@ -524,8 +525,6 @@ const char *DisSpecMap1(struct XedDecodedInst *x, char *p) { RCASE(0xB7, "movzwWLQ %Gvqp Ew"); RCASE(0xB9, "ud %Gvqp Evqp"); RCASE(0xBB, "btc Evqp %Gvqp"); - RCASE(0xBC, "bsf %Gvqp Evqp"); - RCASE(0xBD, "bsr %Gvqp Evqp"); RCASE(0xBE, "movsbWLQ %Gvqp Eb"); RCASE(0xBF, "movswWLQ %Gvqp Ew"); RCASE(0xC0, "xadd Eb %Gb"); @@ -577,6 +576,18 @@ const char *DisSpecMap1(struct XedDecodedInst *x, char *p) { RCASE(0xFD, DisOpPqQqVdqWdq(x, p, "paddw")); RCASE(0xFE, DisOpPqQqVdqWdq(x, p, "paddd")); RCASE(0xFF, "ud0 %Gvqp Evqp"); + case 0xBC: + if (Rep(x->op.rde) == 3) { + return "tzcnt %Gvqp Evqp"; + } else { + return "bsf %Gvqp Evqp"; + } + case 0xBD: + if (Rep(x->op.rde) == 3) { + return "lzcnt %Gvqp Evqp"; + } else { + return "bsr %Gvqp Evqp"; + } case 0x01: switch (ModrmReg(x->op.rde)) { case 0: diff --git a/tool/build/lib/machine.c b/tool/build/lib/machine.c index aa223d192..b88f35d45 100644 --- a/tool/build/lib/machine.c +++ b/tool/build/lib/machine.c @@ -1664,6 +1664,17 @@ static void OpRdmsr(struct Machine *m, uint32_t rde) { Write32(m->ax, 0); } +static void OpVzeroupper(struct Machine *m, uint32_t rde) { +} + +static void OpEmms(struct Machine *m, uint32_t rde) { + if (m->xedd->op.vexvalid) { + OpVzeroupper(m, rde); + } else { + m->fpu.tw = -1; + } +} + static const nexgen32e_f kNexgen32e[] = { [0x000] = OpAlubAdd, [0x001] = OpAluw, @@ -2040,7 +2051,7 @@ static const nexgen32e_f kNexgen32e[] = { [0x174] = OpSsePcmpeqb, [0x175] = OpSsePcmpeqw, [0x176] = OpSsePcmpeqd, - [0x177] = OpUd, + [0x177] = OpEmms, [0x178] = OpUd, [0x179] = OpUd, [0x17A] = OpUd, diff --git a/tool/emacs/cosmo-c-constants.el b/tool/emacs/cosmo-c-constants.el index a31c0b3c9..76993514a 100644 --- a/tool/emacs/cosmo-c-constants.el +++ b/tool/emacs/cosmo-c-constants.el @@ -104,10 +104,71 @@ "FLT_MIN" "FLT_MAX")) +(defconst cosmo-c-constants-math + '("M_E" + "M_LOG2_10" + "M_LOG10_2" + "M_LOG2E" + "M_LOG10E" + "M_LN2" + "M_LN10" + "M_TAU" + "M_PI" + "M_PI_2" + "M_PI_4" + "M_1_PI" + "M_2_PI" + "M_2_SQRTPI" + "M_SQRT2" + "M_SQRT1_2" + "DBL_DECIMAL_DIG" + "DBL_DIG" + "DBL_EPSILON" + "DBL_MANT_DIG" + "DBL_MANT_DIG" + "DBL_MAX" + "DBL_MAX_10_EXP" + "DBL_MAX_EXP" + "DBL_MIN" + "DBL_MIN_10_EXP" + "DBL_MIN_EXP" + "DECIMAL_DIG" + "FLT_DECIMAL_DIG" + "FLT_RADIX" + "FLT_DIG" + "FLT_EPSILON" + "FLT_MANT_DIG" + "FLT_MANT_DIG" + "FLT_MAX" + "FLT_MAX_10_EXP" + "FLT_MAX_EXP" + "FLT_MIN" + "FLT_MIN_10_EXP" + "FLT_MIN_EXP" + "HLF_MAX" + "HLF_MIN" + "LDBL_DECIMAL_DIG" + "LDBL_DIG" + "LDBL_EPSILON" + "LDBL_MANT_DIG" + "LDBL_MANT_DIG" + "LDBL_MAX" + "LDBL_MAX_10_EXP" + "LDBL_MAX_EXP" + "LDBL_MIN" + "LDBL_MIN_10_EXP" + "LDBL_MIN_EXP" + "FP_NAN" + "FP_INFINITE" + "FP_ZERO" + "FP_SUBNORMAL" + "FP_NORMAL")) + (defconst cosmo-c-constants-regex (concat "\\_<" (regexp-opt (append cosmo-c-constants-c11 - cosmo-c-constants-limits)) + cosmo-c-constants-limits + cosmo-c-constants-math)) "\\_>")) (provide 'cosmo-c-constants)