From 416fd866768aa68aa38c16ab84f6b0399dad4be9 Mon Sep 17 00:00:00 2001 From: Justine Tunney Date: Sun, 6 Sep 2020 21:39:00 -0700 Subject: [PATCH] Make improvements MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Emulator can now test the αcτµαlly pδrταblε εxεcµταblε bootloader - Whipped up a webserver named redbean. It services 150k requests per second on a single core. Bundling assets inside zip enables extremely fast serving for two reasons. The first is that zip central directory lookups go faster than stat() system calls. The second is that both zip and gzip content-encoding use DEFLATE, therefore, compressed responses can be served via the sendfile() system call which does an in-kernel copy directly from the zip executable structure. Also note that red bean zip executables can be deployed easily to all platforms, since these native executables work on Linux, Mac, BSD, and Windows. - Address sanitizer now works very well --- ape/ape.S | 25 +- ape/config.h | 2 +- dsp/core/core.mk | 6 + dsp/scale/gyarados.c | 14 +- dsp/tty/tty.mk | 6 + examples/fld.c | 6 +- examples/ls.c | 82 + examples/tiny-raw-linux-tutorial.S | 3 + libc/calls/hefty/dirstream.c | 107 +- libc/calls/internal.h | 13 +- libc/calls/stat.c | 2 + libc/calls/struct/dirent.h | 6 +- libc/conv/conv.mk | 6 +- libc/conv/itoa64fixed16.greg.c | 22 +- libc/conv/itoa64radix16.greg.c | 16 +- libc/crt/crt.S | 2 +- libc/elf/elf.h | 8 +- .../elf/iself64binary.c | 10 +- libc/fmt/palandftoa.c | 20 +- libc/fmt/palandprintf.h | 2 +- libc/integral/c.inc | 132 +- libc/integral/normalize.inc | 2 +- libc/intrin/mpsadbw.c | 45 + libc/intrin/mpsadbw.h | 41 + .../kcrc32tab.S => intrin/mpsadbws.S} | 33 +- libc/intrin/repstosb.h | 2 +- libc/log/asan.c | 319 +- libc/log/asan.h | 25 +- libc/log/backtrace3.c | 51 +- libc/log/checkfail_ndebug.c | 19 +- libc/log/commandvenv.c | 5 +- libc/log/malloc_stats.c | 2 +- libc/log/somanyasan.S | 64 +- libc/log/startfatal_ndebug.c | 10 +- libc/log/ubsan.c | 23 +- libc/math.h | 24 - libc/nexgen32e/crc32.h | 2 - libc/nexgen32e/crc32init.S | 1 - libc/nexgen32e/crc32z.c | 13 + libc/nt/struct/win32finddata.h | 5 +- libc/runtime/destruct.S | 45 + libc/runtime/exit.S | 1 + libc/runtime/missioncritical.h | 3 +- libc/runtime/print.greg.c | 9 +- libc/sock/accept4.c | 2 + libc/sock/bind.c | 1 + libc/sock/connect.c | 1 + libc/sock/internal.h | 2 +- libc/sock/sendto-nt.c | 7 +- libc/sock/sendto.c | 2 +- libc/sock/setsockopt.c | 3 +- libc/sock/sock.h | 10 +- libc/str/stpcpy.c | 16 +- libc/str/str.h | 17 - libc/str/str.mk | 4 - libc/sysv/calls/getdents.s | 2 +- libc/sysv/consts.sh | 29 +- libc/sysv/consts/DT_BLK.s | 2 +- libc/sysv/consts/DT_CHR.s | 2 +- libc/sysv/consts/DT_DIR.s | 2 +- libc/sysv/consts/DT_FIFO.s | 2 +- libc/sysv/consts/DT_LNK.s | 2 +- libc/sysv/consts/DT_REG.s | 2 +- libc/sysv/consts/DT_SOCK.s | 2 +- libc/sysv/consts/DT_UNKNOWN.s | 2 +- libc/sysv/consts/SOL_ICMPV6.s | 2 +- libc/sysv/consts/SOL_IPV6.s | 2 +- libc/sysv/consts/SOL_TCP.s | 2 +- libc/sysv/consts/SOL_UDP.s | 2 +- libc/sysv/consts/TIOCOUTQ.s | 2 +- libc/sysv/consts/dt.h | 28 +- libc/sysv/syscalls.sh | 2 +- libc/testlib/formatbinaryasglyphs.c | 2 +- libc/time/asctime_r.c | 2 +- libc/time/ctime_r.c | 2 +- libc/time/gettimeofday.c | 2 + libc/time/localtime.c | 350 +- libc/time/strftime.c | 161 +- libc/time/time.h | 12 +- libc/time/time.mk | 3 +- libc/tinymath/copysignl.S | 3 +- libc/tinymath/lroundl.S | 12 +- libc/tinymath/round.S | 2 +- libc/tinymath/roundl.S | 10 +- net/http/gethttpheader.c | 8 +- net/http/gethttpheader.gperf | 102 +- net/http/gethttpheader.inc | 365 +- .../{clearhttprequest.c => gethttpmethod.c} | 20 +- net/http/gethttpmethod.gperf | 36 + net/http/gethttpmethod.inc | 206 ++ net/http/http.h | 153 +- net/http/method.gperf | 24 - net/http/negotiatehttprequest.c | 2 +- net/http/parsehttprequest.c | 111 +- test/ape/lib/test.mk | 5 + test/dsp/core/getintegercoefficients8_test.c | 4 +- test/dsp/core/test.mk | 8 + test/dsp/scale/scale_test.c | 32 +- test/libc/conv/itoa64radix16_test.c | 4 + test/libc/fmt/palandprintf_test.c | 8 +- test/libc/intrin/intrin_test.c | 19 +- test/libc/intrin/test.mk | 4 + test/libc/nexgen32e/memmove_test.c | 34 + test/libc/str/memcpy_test.c | 14 + test/libc/str/str_test.c | 16 +- test/libc/str/strlen_test.c | 4 +- test/libc/tinymath/ldexp_test.c | 5 + test/libc/tinymath/round_test.c | 75 +- test/libc/tinymath/test.mk | 1 + test/libc/xed/x86ild_lib.c | 2 +- test/net/http/parsehttprequest_test.c | 68 +- test/net/http/test.mk | 4 + test/tool/build/lib/alu_test.c | 14 + test/tool/build/lib/bitscan_test.c | 14 +- test/tool/build/lib/bsu_test.c | 99 + test/tool/build/lib/disinst_test.c | 138 +- test/tool/build/lib/divmul_test.c | 4 +- test/tool/build/lib/machine_test.c | 33 +- test/tool/build/lib/modrm_test.c | 8 +- third_party/dlmalloc/bulk_free.c | 20 +- third_party/dlmalloc/dlcalloc.c | 11 + third_party/dlmalloc/dlindependent_calloc.c | 4 +- third_party/dlmalloc/dlmalloc-debug.c | 4 +- third_party/dlmalloc/dlmalloc.c | 301 +- third_party/dlmalloc/dlmalloc.h | 59 +- .../dlmalloc/dlmalloc_try_realloc_chunk.c | 105 + third_party/dlmalloc/dlmemalign.c | 2 +- third_party/dlmalloc/dlposix_memalign.c | 2 +- third_party/dlmalloc/dlpvalloc.c | 2 +- third_party/dlmalloc/dlrealloc.c | 42 + third_party/dlmalloc/dlrealloc_in_place.c | 2 +- third_party/dlmalloc/dlvalloc.c | 2 +- third_party/dlmalloc/mallinfo.c | 24 +- third_party/dlmalloc/malloc_footprint.c | 6 +- third_party/dlmalloc/malloc_footprint_limit.c | 2 +- third_party/dlmalloc/malloc_inspect_all.c | 6 +- third_party/dlmalloc/malloc_max_footprint.c | 6 +- .../dlmalloc/malloc_set_footprint_limit.c | 2 +- third_party/dlmalloc/malloc_trim.c | 6 +- third_party/dlmalloc/mallopt.c | 8 +- third_party/f2c/f2c.mk | 2 +- third_party/xed/x86.h | 157 +- third_party/xed/x86ild.greg.c | 190 +- tool/build/build.mk | 13 +- tool/build/emubin/emubin.mk | 9 + tool/build/emubin/mips.c | 2 +- tool/build/emubin/real/spiral.c | 128 + tool/build/emubin/real/spiral.lds | 37 + tool/build/emulator.c | 466 ++- tool/build/lib/{x87.c => address.c} | 99 +- tool/build/lib/address.h | 28 + tool/build/lib/alu.c | 803 +++- tool/build/lib/alu.h | 113 +- tool/build/lib/bcd.c | 78 + tool/build/lib/bcd.h | 15 + tool/build/lib/bitscan.c | 6 +- tool/build/lib/bitscan.h | 8 +- tool/build/lib/bsu.c | 167 - tool/build/lib/buildlib.mk | 12 +- .../lib/x87_test.c => tool/build/lib/cga.c | 38 +- tool/build/lib/cga.h | 11 + tool/build/lib/cond.h | 50 - tool/build/lib/cpuid.c | 2 +- tool/build/lib/cpuid.h | 4 +- tool/build/lib/cvt.c | 35 +- tool/build/lib/cvt.h | 14 +- tool/build/lib/dis.c | 149 +- tool/build/lib/dis.h | 7 +- tool/build/lib/disarg.c | 455 ++- tool/build/lib/diself.c | 22 +- tool/build/lib/disinst.c | 48 +- tool/build/lib/disspec.c | 48 +- tool/build/lib/elfwriter.c | 28 +- tool/build/lib/fds.h | 1 + tool/build/lib/flags.h | 2 +- tool/build/lib/fpu.c | 84 +- tool/build/lib/fpu.h | 4 +- tool/build/lib/init.c | 26 - tool/build/lib/instruction.c | 74 +- tool/build/lib/interner.c | 9 +- tool/build/lib/loader.c | 68 +- tool/build/lib/loader.h | 2 + tool/build/lib/machine.c | 3227 ++++++++--------- tool/build/lib/machine.h | 26 +- .../freehttprequest.c => tool/build/lib/mda.c | 26 +- tool/build/lib/mda.h | 11 + tool/build/lib/memory.c | 3 +- tool/build/lib/memory.h | 5 +- tool/build/lib/memorymalloc.c | 1 + tool/build/lib/modrm.c | 101 +- tool/build/lib/modrm.h | 70 +- tool/build/lib/pml4tfmt.c | 4 +- tool/build/lib/pty.c | 48 +- tool/build/lib/pty.h | 3 +- tool/build/lib/sse.c | 683 +++- tool/build/lib/sse.h | 150 +- tool/build/lib/ssefloat.c | 571 +++ tool/build/lib/ssefloat.h | 37 + tool/build/lib/ssemov.c | 522 +++ tool/build/lib/ssemov.h | 30 + tool/build/lib/stack.c | 324 +- tool/build/lib/stack.h | 24 +- tool/build/lib/string.c | 290 +- tool/build/lib/string.h | 8 +- tool/build/lib/syscall.c | 443 ++- tool/build/lib/syscall.h | 2 +- tool/build/lib/throw.c | 12 +- tool/build/lib/throw.h | 5 +- tool/build/lib/time.c | 16 +- tool/build/lib/time.h | 4 +- tool/build/lib/x87.h | 15 - tool/build/refactor.c | 4 +- tool/build/tinyemu.c | 7 + tool/decode/decode.mk | 1 + tool/decode/getdents.c | 50 + tool/decode/x86opinfo.c | 1 - tool/emacs/cosmo-c-builtins.el | 4 + tool/emacs/cosmo-cpp-constants.el | 24 +- tool/emacs/cosmo-format.el | 1 + tool/net/net.mk | 15 +- tool/net/redbean.c | 217 ++ tool/net/redbean.html | 6 + tool/net/redbean.ico | Bin 0 -> 16958 bytes tool/net/redbean.png | Bin 0 -> 5073 bytes tool/viz/deathstar.c | 14 +- tool/viz/lib/vizlib.mk | 6 + tool/viz/printimage.c | 2 +- tool/viz/printvideo.c | 2 +- tool/viz/viz.mk | 6 + tool/viz/xterm256info.c | 775 ++-- 230 files changed, 9835 insertions(+), 5682 deletions(-) create mode 100644 examples/ls.c rename test/ape/lib/flattenhighmemory_test.c => libc/elf/iself64binary.c (86%) create mode 100644 libc/intrin/mpsadbw.c create mode 100644 libc/intrin/mpsadbw.h rename libc/{nexgen32e/kcrc32tab.S => intrin/mpsadbws.S} (81%) create mode 100644 libc/runtime/destruct.S rename net/http/{clearhttprequest.c => gethttpmethod.c} (87%) create mode 100644 net/http/gethttpmethod.gperf create mode 100644 net/http/gethttpmethod.inc delete mode 100644 net/http/method.gperf create mode 100644 third_party/dlmalloc/dlcalloc.c create mode 100644 third_party/dlmalloc/dlmalloc_try_realloc_chunk.c create mode 100644 third_party/dlmalloc/dlrealloc.c create mode 100644 tool/build/emubin/real/spiral.c create mode 100644 tool/build/emubin/real/spiral.lds rename tool/build/lib/{x87.c => address.c} (56%) create mode 100644 tool/build/lib/address.h create mode 100644 tool/build/lib/bcd.c create mode 100644 tool/build/lib/bcd.h delete mode 100644 tool/build/lib/bsu.c rename test/tool/build/lib/x87_test.c => tool/build/lib/cga.c (72%) create mode 100644 tool/build/lib/cga.h delete mode 100644 tool/build/lib/cond.h rename net/http/freehttprequest.c => tool/build/lib/mda.c (81%) create mode 100644 tool/build/lib/mda.h create mode 100644 tool/build/lib/ssefloat.c create mode 100644 tool/build/lib/ssefloat.h create mode 100644 tool/build/lib/ssemov.c create mode 100644 tool/build/lib/ssemov.h delete mode 100644 tool/build/lib/x87.h create mode 100644 tool/decode/getdents.c create mode 100644 tool/net/redbean.c create mode 100644 tool/net/redbean.html create mode 100644 tool/net/redbean.ico create mode 100644 tool/net/redbean.png diff --git a/ape/ape.S b/ape/ape.S index 3f4e49eb..dc0fe792 100644 --- a/ape/ape.S +++ b/ape/ape.S @@ -236,9 +236,6 @@ pc: cld ljmp $0,$REAL(realmodeloader) .endfn pc,globl,hidden -/ Be gentler on Unix line buffer impls. - .byte 0x0a - / Determines disk geometry. / / We use imperial measurements for storage systems so the software @@ -1055,9 +1052,9 @@ realmodeloader: call rlinit call sinit4 mov $VIDYA_MODE,%di + call vinit mov %es,XLM(VIDEO_POSITION_FAR_POINTER) mov %ax,XLM(VIDEO_POSITION_FAR_POINTER)+2 - call vinit mov $REAL(.Lstr.ape),%di call rvputs .optfn _start16 @@ -1370,8 +1367,8 @@ vtput: push %bp mov %di,%dx bband VIDYA_REWIND,%dh,%dl bbadd VIDYA_SIZE,%dh,%dl - bbmov VIDYA_COLUMNS*2,%bx,%bh,%bl -0: cmp %di,%dx + bbmov VIDYA_COLUMNS*2-2,%bx,%bh,%bl +0: cmp %dx,%di je 6f ja 3f lodsb # todo: utf8 → cp437 @@ -1523,12 +1520,12 @@ longmodeloader: / Long Mode Hardware Check lcheck: push %bp mov %sp,%bp - pushfw # check for i8086 / i8088 / i80186 + pushf # check for i8086 / i8088 / i80186 pop %ax - and $0b111<<12,%ax # see intel manual volume 1 §19.1.2 - jnz 9f - pushfl # now check for later model of 80486 - pop %eax # test ability to *change* cpuid bit + test $0x80,%ah # see intel manual volume 1 20.1.2 + jnz 9f # we now assume 32bit is supported + pushfl # now check for i386 or early i486 + pop %eax # test ability to change cpuid bit mov %eax,%ecx mov $1<<21,%ebx xor %ebx,%eax @@ -1537,8 +1534,8 @@ lcheck: push %bp pushfl pop %eax cmp %eax,%ecx - je 12f - and %ebx,%eax # puts cpuid bit in the on position + je 12f # we assume cpuid inst is available + or %ebx,%eax # puts cpuid bit in the on position push %eax popfl mov $0x80000000,%edi # get amd ext cpuid thingy length @@ -1549,7 +1546,7 @@ lcheck: push %bp jl 10f mov %edi,%eax cpuid - mov $1<<29/*LM*/,%edi # check for nexgen32e support + mov $1<<29,%edi # need nexgen32e long mode support and %edi,%edx cmp %edi,%edx jne 10f diff --git a/ape/config.h b/ape/config.h index 12e0eb5c..bdf0a307 100644 --- a/ape/config.h +++ b/ape/config.h @@ -41,7 +41,7 @@ * @see ape/lib/vidya.h */ #ifndef VIDYA_MODE -#define VIDYA_MODE VIDYA_MODE_MDA +#define VIDYA_MODE VIDYA_MODE_CGA #endif /* FPU Control Word (x87) Exception Masks diff --git a/dsp/core/core.mk b/dsp/core/core.mk index 10872e75..a3ea303e 100644 --- a/dsp/core/core.mk +++ b/dsp/core/core.mk @@ -58,6 +58,12 @@ o/$(MODE)/dsp/core/det3.o: \ OVERRIDE_CFLAGS += \ -ffast-math +ifeq (,$(MODE)) +$(DSP_CORE_OBJS): \ + OVERRIDE_CFLAGS += \ + -fsanitize=address +endif + DSP_CORE_LIBS = $(foreach x,$(DSP_CORE_ARTIFACTS),$($(x))) DSP_CORE_SRCS = $(foreach x,$(DSP_CORE_ARTIFACTS),$($(x)_SRCS)) DSP_CORE_HDRS = $(foreach x,$(DSP_CORE_ARTIFACTS),$($(x)_HDRS)) diff --git a/dsp/scale/gyarados.c b/dsp/scale/gyarados.c index edb57f0c..36a208eb 100644 --- a/dsp/scale/gyarados.c +++ b/dsp/scale/gyarados.c @@ -102,7 +102,7 @@ struct SamplingSolution *ComputeSamplingSolution(long dn, long sn, double dar, if (!dar) dar = sn, dar /= dn; if (!off) off = (dar - 1) / 2; f = dar < 1 ? 1 / dar : dar; - s = 3 * f + 1; + s = 3 * f + 4; fweights = gc(xcalloc(s, sizeof(double))); res = NewSamplingSolution(dn, s); weights = res->weights; @@ -147,9 +147,9 @@ static int Sharpen(int ax, int bx, int cx) { static void GyaradosImpl(long dyw, long dxw, int dst[dyw][dxw], long syw, long sxw, const int src[syw][sxw], long dyn, long dxn, - long syn, long sxn, short tmp0[restrict dyn][sxn], - short tmp1[restrict dyn][sxn], - short tmp2[restrict dyn][dxn], long yfn, long xfn, + long syn, long sxn, int tmp0[restrict dyn][sxn], + int tmp1[restrict dyn][sxn], + int tmp2[restrict dyn][dxn], long yfn, long xfn, const short fyi[dyn][yfn], const short fyw[dyn][yfn], const short fxi[dxn][xfn], const short fxw[dxn][xfn], bool sharpen) { @@ -216,9 +216,9 @@ void *Gyarados(long dyw, long dxw, int dst[dyw][dxw], long syw, long sxw, CHECK_LE(syn, 0x7fff); CHECK_LE(sxn, 0x7fff); GyaradosImpl(dyw, dxw, dst, syw, sxw, src, dyn, dxn, syn, sxn, - gc(xmemalign(64, sizeof(short) * dyn * sxn)), - gc(xmemalign(64, sizeof(short) * dyn * sxn)), - gc(xmemalign(64, sizeof(short) * dyn * dxn)), cy->s, cx->s, + gc(xmemalign(64, sizeof(int) * dyn * sxn)), + gc(xmemalign(64, sizeof(int) * dyn * sxn)), + gc(xmemalign(64, sizeof(int) * dyn * dxn)), cy->s, cx->s, cy->indices, cy->weights, cx->indices, cx->weights, sharpen); } else { ZeroMatrix(dyw, dxw, dst, dyn, dxn); diff --git a/dsp/tty/tty.mk b/dsp/tty/tty.mk index 4c9478f6..85344fa6 100644 --- a/dsp/tty/tty.mk +++ b/dsp/tty/tty.mk @@ -59,6 +59,12 @@ o/$(MODE)/dsp/tty/ttyraster.o: \ OVERRIDE_CFLAGS += \ $(MATHEMATICAL) +ifeq (,$(MODE)) +$(DSP_TTY_OBJS): \ + OVERRIDE_CFLAGS += \ + -fsanitize=address +endif + DSP_TTY_LIBS = $(foreach x,$(DSP_TTY_ARTIFACTS),$($(x))) DSP_TTY_SRCS = $(foreach x,$(DSP_TTY_ARTIFACTS),$($(x)_SRCS)) DSP_TTY_HDRS = $(foreach x,$(DSP_TTY_ARTIFACTS),$($(x)_HDRS)) diff --git a/examples/fld.c b/examples/fld.c index 2d753c95..f18c1452 100644 --- a/examples/fld.c +++ b/examples/fld.c @@ -35,7 +35,7 @@ void dobin(const char *op, long double x, FILE *f) { memcpy(buf, &x, sizeof(x)); memcpy(&lo, &buf[0], sizeof(lo)); memcpy(&hi, &buf[8], sizeof(hi)); - fprintf(f, "/\t%016" PRIb16 "%064" PRIb64 " %-8s % 19.19Lf\n", hi, lo, op, x); + fprintf(f, "/\t%016" PRIb16 "%064" PRIb64 " %-8s % 17.14Lf\n", hi, lo, op, x); } void dohex(const char *op, long double x, FILE *f) { @@ -45,7 +45,7 @@ void dohex(const char *op, long double x, FILE *f) { memcpy(buf, &x, sizeof(x)); memcpy(&lo, &buf[0], sizeof(lo)); memcpy(&hi, &buf[8], sizeof(hi)); - fprintf(f, "/\t%04" PRIx16 "%016" PRIx64 " %-8s % 19.19Lf\n", hi, lo, op, x); + fprintf(f, "/\t%04" PRIx16 "%016" PRIx64 " %-8s % 17.14Lf\n", hi, lo, op, x); } #define DOBIN(OP) \ @@ -65,7 +65,6 @@ int main(int argc, char *argv[]) { DOBIN(fldlg2); DOBIN(fldln2); DOBIN(fldl2e); - DOBIN(finit); fputc('\n', stdout); fputs(kHeaderHex, stdout); DOHEX(fldz); @@ -75,7 +74,6 @@ int main(int argc, char *argv[]) { DOHEX(fldlg2); DOHEX(fldln2); DOHEX(fldl2e); - DOHEX(finit); return 0; } diff --git a/examples/ls.c b/examples/ls.c new file mode 100644 index 00000000..a25a08b0 --- /dev/null +++ b/examples/ls.c @@ -0,0 +1,82 @@ +#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/dirent.h" +#include "libc/calls/struct/stat.h" +#include "libc/log/check.h" +#include "libc/runtime/gc.h" +#include "libc/stdio/stdio.h" +#include "libc/str/str.h" +#include "libc/sysv/consts/dt.h" +#include "libc/x/x.h" + +struct stat st; + +const char *TypeToString(uint8_t type) { + switch (type) { + case DT_UNKNOWN: + return "DT_UNKNOWN"; + case DT_FIFO: + return "DT_FIFO"; + case DT_CHR: + return "DT_CHR"; + case DT_DIR: + return "DT_DIR"; + case DT_BLK: + return "DT_BLK"; + case DT_REG: + return "DT_REG"; + case DT_LNK: + return "DT_LNK"; + case DT_SOCK: + return "DT_SOCK"; + default: + return "UNKNOWN"; + } +} + +void List(const char *path) { + DIR *d; + struct dirent *e; + const char *vpath; + if (strcmp(path, ".") == 0) { + vpath = ""; + } else if (!endswith(path, "/")) { + vpath = gc(xasprintf("%s/", path)); + } else { + vpath = path; + } + if (stat(path, &st) != -1) { + if (S_ISDIR(st.st_mode)) { + CHECK((d = opendir(path))); + while ((e = readdir(d))) { + printf("0x%016x 0x%016x %-10s %s%s\n", e->d_ino, e->d_off, + TypeToString(e->d_type), vpath, e->d_name); + } + closedir(d); + } else { + printf("%s\n", path); + } + } else { + fprintf(stderr, "not found: %s\n", path); + } +} + +int main(int argc, char *argv[]) { + int i; + if (argc == 1) { + List("."); + } else { + for (i = 1; i < argc; ++i) { + List(argv[i]); + } + } + return 0; +} diff --git a/examples/tiny-raw-linux-tutorial.S b/examples/tiny-raw-linux-tutorial.S index 81801c40..d8dc6e9d 100644 --- a/examples/tiny-raw-linux-tutorial.S +++ b/examples/tiny-raw-linux-tutorial.S @@ -58,3 +58,6 @@ _start: mov $12,%rdx # arg no. 3 is length jmp 0b .endfn _start,globl .source __FILE__ + + .rodata.cst4 +1: .float -1.5 diff --git a/libc/calls/hefty/dirstream.c b/libc/calls/hefty/dirstream.c index 7da1a786..57f46f15 100644 --- a/libc/calls/hefty/dirstream.c +++ b/libc/calls/hefty/dirstream.c @@ -23,6 +23,8 @@ #include "libc/calls/struct/dirent.h" #include "libc/dce.h" #include "libc/mem/mem.h" +#include "libc/nt/enum/fileflagandattributes.h" +#include "libc/nt/enum/filetype.h" #include "libc/nt/files.h" #include "libc/nt/runtime.h" #include "libc/nt/struct/win32finddata.h" @@ -31,9 +33,18 @@ #include "libc/sysv/consts/o.h" #include "libc/sysv/errfuns.h" +struct dirent$freebsd { + uint32_t d_fileno; + uint16_t d_reclen; + uint8_t d_type; + uint8_t d_namlen; + char d_name[256]; +}; + struct dirstream { int64_t tell; int64_t fd; + struct dirent ent; union { struct { unsigned buf_pos; @@ -41,8 +52,6 @@ struct dirstream { char buf[BUFSIZ]; }; struct { - struct dirent winent; - char __d_name[PATH_MAX]; bool isdone; struct NtWin32FindData windata; }; @@ -71,17 +80,60 @@ static textwindows noinline DIR *opendir$nt(const char *name) { } } +static textwindows noinline struct dirent *readdir$nt(DIR *dir) { + if (!dir->isdone) { + memset(&dir->ent, 0, sizeof(dir->ent)); + dir->ent.d_ino = 0; + dir->ent.d_off = dir->tell++; + dir->ent.d_reclen = sizeof(dir->ent) + + tprecode16to8(dir->ent.d_name, sizeof(dir->ent.d_name), + dir->windata.cFileName) + + 1; + switch (dir->windata.dwFileType) { + case kNtFileTypeDisk: + dir->ent.d_type = DT_BLK; + break; + case kNtFileTypeChar: + dir->ent.d_type = DT_CHR; + break; + case kNtFileTypePipe: + dir->ent.d_type = DT_FIFO; + break; + default: + if (dir->windata.dwFileAttributes & kNtFileAttributeDirectory) { + dir->ent.d_type = DT_DIR; + } else { + dir->ent.d_type = DT_REG; + } + break; + } + dir->isdone = !FindNextFile(dir->fd, &dir->windata); + return &dir->ent; + } else { + return NULL; + } +} + /** - * Opens directory so readdir() and closedir() may be called. + * Opens directory, e.g. + * + * DIR *d; + * struct dirent *e; + * CHECK((d = opendir(path))); + * while ((e = readdir(d))) { + * printf("%s/%s\n", path, e->d_name); + * } + * LOGIFNEG1(closedir(d)); * * @returns newly allocated DIR object, or NULL w/ errno * @errors ENOENT, ENOTDIR, EACCES, EMFILE, ENFILE, ENOMEM * @see glob() */ DIR *opendir(const char *name) { + int fd; + DIR *res; if (!IsWindows() && !IsXnu()) { - int fd; - DIR *res = NULL; + res = NULL; if ((fd = open(name, O_RDONLY | O_DIRECTORY | O_CLOEXEC, 0)) != -1) { if (!(res = fdopendir(fd))) close(fd); } @@ -103,8 +155,8 @@ DIR *opendir(const char *name) { * @errors ENOMEM and fd is closed */ DIR *fdopendir(int fd) { + DIR *dir; if (!IsWindows() && !IsXnu()) { - DIR *dir; if ((dir = calloc(1, sizeof(*dir)))) { dir->fd = fd; return dir; @@ -125,35 +177,36 @@ DIR *fdopendir(int fd) { * differentiated by setting errno to 0 beforehand */ struct dirent *readdir(DIR *dir) { + int rc; + struct dirent *ent; + struct dirent$freebsd *freebsd; if (!IsWindows()) { if (dir->buf_pos >= dir->buf_end) { - int rc; - if (!(rc = getdents(dir->fd, dir->buf, BUFSIZ)) || rc == -1) { + if (!(rc = getdents(dir->fd, dir->buf, + sizeof(dir->buf) - sizeof(dir->ent.d_name))) || + rc == -1) { return NULL; } dir->buf_pos = 0; dir->buf_end = rc; } - /* TODO(jart): Check FreeBSD and OpenBSD again regarding this */ - char *record = dir->buf + dir->buf_pos; - char *name = record + 8 + 8 + 2; - size_t namelen = strlen(name); - unsigned char dtype = name[namelen + 1]; - memmove(name + 1, name, namelen + 1); /* shove forward one byte */ - *name = dtype; /* is dirent d_type field */ - struct dirent *ent = (void *)record; - dir->buf_pos += ent->d_reclen; - dir->tell = ent->d_off; + if (IsLinux()) { + ent = (struct dirent *)(dir->buf + dir->buf_pos); + dir->buf_pos += ent->d_reclen; + dir->tell = ent->d_off; + } else { + freebsd = (struct dirent$freebsd *)(dir->buf + dir->buf_pos); + dir->buf_pos += freebsd->d_reclen; + ent = &dir->ent; + ent->d_ino = freebsd->d_fileno; + ent->d_off = dir->tell++; + ent->d_reclen = freebsd->d_reclen; + ent->d_type = freebsd->d_type; + memcpy(ent->d_name, freebsd->d_name, freebsd->d_namlen + 1); + } return ent; } else { - if (dir->isdone) return NULL; - struct dirent *ent = &dir->winent; - memset(ent, 0, sizeof(*ent)); - ent->d_reclen = - sizeof(*ent) + - tprecode16to8(ent->d_name, PATH_MAX, dir->windata.cFileName) + 1; - dir->isdone = FindNextFile(dir->fd, &dir->windata); - return ent; + return readdir$nt(dir); } } @@ -177,7 +230,7 @@ int closedir(DIR *dir) { } /** - * Returns current byte offset into directory data. + * Returns offset into directory data. */ long telldir(DIR *dir) { return dir->tell; diff --git a/libc/calls/internal.h b/libc/calls/internal.h index 665c2a1a..f12fe19a 100644 --- a/libc/calls/internal.h +++ b/libc/calls/internal.h @@ -21,6 +21,9 @@ #define COSMOPOLITAN_LIBC_CALLS_INTERNAL_H_ #ifndef __STRICT_ANSI__ #include "libc/calls/calls.h" +#include "libc/calls/struct/itimerval.h" +#include "libc/calls/struct/timespec.h" +#include "libc/calls/struct/timeval.h" #include "libc/dce.h" #include "libc/limits.h" #include "libc/macros.h" @@ -28,6 +31,8 @@ #include "libc/nt/struct/startupinfo.h" #include "libc/nt/struct/systeminfo.h" #include "libc/runtime/runtime.h" +#include "libc/time/struct/timezone.h" +#include "libc/time/struct/utimbuf.h" #define kSigactionMinRva 8 /* >SIG_{ERR,DFL,IGN,...} */ @@ -41,14 +46,6 @@ struct NtWin32FileAttributeData; struct ZiposHandle; struct __darwin_siginfo; struct __darwin_ucontext; -struct itimerval; -struct rlimit; -struct rusage; -struct sigset; -struct sysinfo; -struct timeval; -struct timezone; -struct utimbuf; struct IoctlPtmGet { int theduxfd; diff --git a/libc/calls/stat.c b/libc/calls/stat.c index be4019b5..a05987c2 100644 --- a/libc/calls/stat.c +++ b/libc/calls/stat.c @@ -28,6 +28,8 @@ /** * Returns information about thing. + * + * @see S_ISDIR(st.st_mode), S_ISREG(), etc. * @asyncsignalsafe */ int stat(const char *pathname, struct stat *st) { diff --git a/libc/calls/struct/dirent.h b/libc/calls/struct/dirent.h index 8df45380..c19c825c 100644 --- a/libc/calls/struct/dirent.h +++ b/libc/calls/struct/dirent.h @@ -2,12 +2,12 @@ #define COSMOPOLITAN_LIBC_CALLS_STRUCT_DIRENT_H_ #if !(__ASSEMBLER__ + __LINKER__ + 0) -struct dirent { +struct dirent { /* linux getdents64 abi */ uint64_t d_ino; /* inode number */ int64_t d_off; /* implementation-dependent location number */ uint16_t d_reclen; /* byte length of this whole struct and string */ - uint8_t d_type; /* DT_UNKNOWN, DT_BLK, DT_DIR, etc. it's flaky */ - char d_name[1]; /* NUL-terminated basename */ + uint8_t d_type; /* DT_UNKNOWN, DT_BLK, DT_DIR, etc. */ + char d_name[256]; /* NUL-terminated basename */ }; #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ diff --git a/libc/conv/conv.mk b/libc/conv/conv.mk index 5365f94e..1ee2d1b0 100644 --- a/libc/conv/conv.mk +++ b/libc/conv/conv.mk @@ -58,9 +58,13 @@ o/$(MODE)/libc/conv/filetimetotime.o \ o/$(MODE)/libc/conv/timespectofiletime.o \ o/$(MODE)/libc/conv/filetimetotimespec.o \ o/$(MODE)/libc/conv/filetimetotimeval.o: \ - OVERRIDE_COPTS += \ + OVERRIDE_CFLAGS += \ -O3 +$(LIBC_CONV_A_OBJS): \ + OVERRIDE_CFLAGS += \ + $(NO_MAGIC) + LIBC_CONV_LIBS = $(foreach x,$(LIBC_CONV_ARTIFACTS),$($(x))) LIBC_CONV_SRCS = $(foreach x,$(LIBC_CONV_ARTIFACTS),$($(x)_SRCS)) LIBC_CONV_HDRS = $(foreach x,$(LIBC_CONV_ARTIFACTS),$($(x)_HDRS)) diff --git a/libc/conv/itoa64fixed16.greg.c b/libc/conv/itoa64fixed16.greg.c index f88b25ac..00601c50 100644 --- a/libc/conv/itoa64fixed16.greg.c +++ b/libc/conv/itoa64fixed16.greg.c @@ -17,22 +17,14 @@ │ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │ │ 02110-1301 USA │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/alg/reverse.h" #include "libc/assert.h" #include "libc/conv/itoa.h" -size_t uint64toarray_fixed16(uint64_t i, char a[hasatleast 17], uint8_t b) { - size_t j; - assert(b <= 64); - assert(b % 4 == 0); - j = 0; - if (b) { - do { - a[j++] = "0123456789abcdef"[i & 15]; - i >>= 4; - } while (b -= 4); - } - a[j] = '\0'; - reverse(a, j); - return j; +size_t uint64toarray_fixed16(uint64_t x, char b[hasatleast 17], uint8_t k) { + int i; + char *p; + assert(k <= 64 && !(k & 3)); + for (p = b; k > 0;) *p++ = "0123456789abcdef"[(x >> (k -= 4)) & 15]; + *p = '\0'; + return p - b; } diff --git a/libc/conv/itoa64radix16.greg.c b/libc/conv/itoa64radix16.greg.c index a01d5919..36157db2 100644 --- a/libc/conv/itoa64radix16.greg.c +++ b/libc/conv/itoa64radix16.greg.c @@ -17,17 +17,11 @@ │ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │ │ 02110-1301 USA │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/alg/reverse.h" #include "libc/conv/conv.h" +#include "libc/conv/itoa.h" +#include "libc/macros.h" +#include "libc/nexgen32e/bsr.h" -size_t uint64toarray_radix16(uint64_t i, char a[hasatleast 17]) { - size_t j; - j = 0; - do { - a[j++] = "0123456789abcdef"[i % 16]; - i /= 16; - } while (i > 0); - a[j] = '\0'; - reverse(a, j); - return j; +size_t uint64toarray_radix16(uint64_t x, char b[hasatleast 17]) { + return uint64toarray_fixed16(x, b, ROUNDUP(x ? bsrl(x) + 1 : 1, 4)); } diff --git a/libc/crt/crt.S b/libc/crt/crt.S index 6f490515..233030a4 100644 --- a/libc/crt/crt.S +++ b/libc/crt/crt.S @@ -39,7 +39,7 @@ _start: test %rdi,%rdi lea 8(%rsp),%rsi # argv lea 24(%rsp,%rbx,8),%rdx # envp .frame0 - bofram 9f +/ bofram 9f .weak idata.iat,idata.iatend ezlea missingno,ax # make win32 imps noop ezlea idata.iat,di diff --git a/libc/elf/elf.h b/libc/elf/elf.h index f897a43d..2a5da336 100644 --- a/libc/elf/elf.h +++ b/libc/elf/elf.h @@ -23,6 +23,7 @@ Elf64_Ehdr *mapelfread(const char *, struct MappedFile *); char *getelfstringtable(const Elf64_Ehdr *, size_t); Elf64_Sym *getelfsymboltable(const Elf64_Ehdr *, size_t, Elf64_Xword *); Elf64_Shdr *getelfsectionbyaddress(const Elf64_Ehdr *, size_t, void *); +bool iself64binary(const Elf64_Ehdr *, size_t); forceinline void checkelfaddress(const Elf64_Ehdr *elf, size_t mapsize, intptr_t addr, size_t addrsize) { @@ -33,13 +34,6 @@ forceinline void checkelfaddress(const Elf64_Ehdr *elf, size_t mapsize, #endif } -static inline bool iself64binary(const Elf64_Ehdr *elf, size_t mapsize) { - return mapsize >= sizeof(Elf64_Ehdr) && - memcmp(elf->e_ident, ELFMAG, 4) == 0 && - (elf->e_ident[EI_CLASS] == ELFCLASSNONE || - elf->e_ident[EI_CLASS] == ELFCLASS64); -} - static inline bool iselfsymbolcontent(const Elf64_Sym *sym) { return sym->st_size > 0 && (ELF64_ST_TYPE(sym->st_info) == STT_FUNC || ELF64_ST_TYPE(sym->st_info) == STT_OBJECT); diff --git a/test/ape/lib/flattenhighmemory_test.c b/libc/elf/iself64binary.c similarity index 86% rename from test/ape/lib/flattenhighmemory_test.c rename to libc/elf/iself64binary.c index 6da4846a..5c61f4eb 100644 --- a/test/ape/lib/flattenhighmemory_test.c +++ b/libc/elf/iself64binary.c @@ -17,9 +17,11 @@ │ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │ │ 02110-1301 USA │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/testlib/testlib.h" +#include "libc/elf/elf.h" -TEST(flattenhighmemory, test) { - /* EXPECT_EQ(0, flattenhighmemory()); */ - /* EXPECT_STREQ("", flattenhighmemory()); */ +bool iself64binary(const Elf64_Ehdr *elf, size_t mapsize) { + if (mapsize < sizeof(Elf64_Ehdr)) return false; + if (memcmp(elf->e_ident, ELFMAG, 4)) return false; + return (elf->e_ident[EI_CLASS] == ELFCLASSNONE || + elf->e_ident[EI_CLASS] == ELFCLASS64); } diff --git a/libc/fmt/palandftoa.c b/libc/fmt/palandftoa.c index 238f7e5c..8b11bc6e 100644 --- a/libc/fmt/palandftoa.c +++ b/libc/fmt/palandftoa.c @@ -34,16 +34,13 @@ #include "libc/fmt/palandprintf.h" #include "libc/math.h" -static const int kPow10[] = {1, 10, 100, 1000, 10000, - 100000, 1000000, 10000000, 100000000, 1000000000}; - /** * Formats floating point number. * * @see xdtoa() for higher precision at the cost of bloat * @see palandprintf() which is intended caller */ -int ftoa(int out(int, void *), void *arg, long double value, unsigned long prec, +int ftoa(int out(int, void *), void *arg, long double value, int prec, unsigned long width, unsigned long flags) { long whole, frac; long double tmp, diff; @@ -72,32 +69,31 @@ int ftoa(int out(int, void *), void *arg, long double value, unsigned long prec, prec = 6; } - /* limit precision to 9, cause a prec >= 10 can lead to overflow errors */ - while (len < PRINTF_FTOA_BUFFER_SIZE && prec > 9) { + while (len < PRINTF_FTOA_BUFFER_SIZE && prec > 14) { buf[len++] = '0'; prec--; } whole = truncl(fabsl(value)); - tmp = (fabsl(value) - whole) * kPow10[prec]; + tmp = (fabsl(value) - whole) * exp10l(prec); frac = tmp; diff = tmp - frac; - if (diff > 0.5) { + if (diff > .5) { ++frac; /* handle rollover, e.g. case 0.99 with prec 1 is 1.0 */ - if (frac >= kPow10[prec]) { + if (frac >= exp10l(prec)) { frac = 0; ++whole; } - } else if (diff < 0.5) { + } else if (diff < .5) { } else if (!frac || (frac & 1)) { ++frac; /* if halfway, round up if odd OR if last digit is 0 */ } if (!prec) { diff = fabsl(value) - whole; - if ((!(diff < 0.5) || (diff > 0.5)) && (whole & 1)) { - /* exactly 0.5 and ODD, then round up */ + if ((!(diff < .5) || (diff > .5)) && (whole & 1)) { + /* exactly .5 and ODD, then round up */ /* 1.5 -> 2, but 2.5 -> 2 */ ++whole; } diff --git a/libc/fmt/palandprintf.h b/libc/fmt/palandprintf.h index 7c65f304..c9a65459 100644 --- a/libc/fmt/palandprintf.h +++ b/libc/fmt/palandprintf.h @@ -8,7 +8,7 @@ COSMOPOLITAN_C_START_ int spacepad(int(int, void *), void *, unsigned long) hidden; -int ftoa(int(int, void *), void *, long double, unsigned long, unsigned long, +int ftoa(int(int, void *), void *, long double, int, unsigned long, unsigned long) hidden; int stoa(int(int, void *), void *, void *, unsigned long, unsigned long, unsigned long, unsigned char, unsigned char) hidden; diff --git a/libc/integral/c.inc b/libc/integral/c.inc index 3955c208..34da759e 100644 --- a/libc/integral/c.inc +++ b/libc/integral/c.inc @@ -179,7 +179,7 @@ typedef struct axdx_t { #undef __SIZEOF_INTMAX__ #endif #if !defined(__STRICT_ANSI__) && __SIZEOF_POINTER__ == 8 && \ - (__GNUC__ * 100 + __GNUC_MINOR__ >= 406 || defined(__llvm__)) + ((__GNUC__ + 0) * 100 + (__GNUC_MINOR__ + 0) >= 406 || defined(__llvm__)) #define __SIZEOF_INTMAX__ 16 #else #define __SIZEOF_INTMAX__ __SIZEOF_POINTER__ @@ -279,7 +279,7 @@ typedef uint64_t uintmax_t; #ifndef noinstrument #if !defined(__STRICT_ANSI__) && \ (__has_attribute(__no_instrument_function__) || \ - __GNUC__ * 100 + __GNUC_MINOR__ >= 204) + (__GNUC__ + 0) * 100 + (__GNUC_MINOR__ + 0) >= 204) #define noinstrument __attribute__((__no_instrument_function__)) #else #define noinstrument @@ -287,8 +287,9 @@ typedef uint64_t uintmax_t; #endif #ifndef noreturn -#if !defined(__STRICT_ANSI__) && \ - (__has_attribute(__noreturn__) || __GNUC__ * 100 + __GNUC_MINOR__ >= 208) +#if !defined(__STRICT_ANSI__) && \ + (__has_attribute(__noreturn__) || \ + (__GNUC__ + 0) * 100 + (__GNUC_MINOR__ + 0) >= 208) #define noreturn __attribute__((__noreturn__)) #else #define noreturn @@ -301,8 +302,9 @@ typedef uint64_t uintmax_t; * @see pureconst */ #ifndef nosideeffect -#if !defined(__STRICT_ANSI__) && \ - (__has_attribute(__pure__) || __GNUC__ * 100 + __GNUC_MINOR__ >= 296) +#if !defined(__STRICT_ANSI__) && \ + (__has_attribute(__pure__) || \ + (__GNUC__ + 0) * 100 + (__GNUC_MINOR__ + 0) >= 296) #define nosideeffect __attribute__((__pure__)) #else #define nosideeffect @@ -310,8 +312,9 @@ typedef uint64_t uintmax_t; #endif #ifndef noinline -#if !defined(__STRICT_ANSI__) && \ - (__has_attribute(__noinline__) || __GNUC__ * 100 + __GNUC_MINOR__ >= 301) +#if !defined(__STRICT_ANSI__) && \ + (__has_attribute(__noinline__) || \ + (__GNUC__ + 0) * 100 + (__GNUC_MINOR__ + 0) >= 301) #define noinline __attribute__((__noinline__)) #else #define noinline @@ -319,8 +322,9 @@ typedef uint64_t uintmax_t; #endif #ifndef noclone -#if !defined(__STRICT_ANSI__) && \ - (__has_attribute(__noclone__) || __GNUC__ * 100 + __GNUC_MINOR__ >= 405) +#if !defined(__STRICT_ANSI__) && \ + (__has_attribute(__noclone__) || \ + (__GNUC__ + 0) * 100 + (__GNUC_MINOR__ + 0) >= 405) #define noclone __attribute__((__noclone__)) #else #define noclone @@ -343,9 +347,11 @@ typedef uint64_t uintmax_t; #ifdef __cplusplus #define forceinline inline #else -#if !defined(__STRICT_ANSI__) && __GNUC__ * 100 + __GNUC_MINOR__ >= 302 -#if __GNUC__ * 100 + __GNUC_MINOR__ >= 403 || !defined(__cplusplus) || \ - (defined(__clang__) && \ +#if !defined(__STRICT_ANSI__) && \ + (__GNUC__ + 0) * 100 + (__GNUC_MINOR__ + 0) >= 302 +#if (__GNUC__ + 0) * 100 + (__GNUC_MINOR__ + 0) >= 403 || \ + !defined(__cplusplus) || \ + (defined(__clang__) && \ (defined(__GNUC_STDC_INLINE__) || defined(__GNUC_GNU_INLINE__))) #if defined(__GNUC_STDC_INLINE__) || defined(__cplusplus) #define forceinline \ @@ -379,8 +385,9 @@ typedef uint64_t uintmax_t; * @see unsigned char */ #ifndef mayalias -#if !defined(__STRICT_ANSI__) && \ - (__has_attribute(__may_alias__) || __GNUC__ * 100 + __GNUC_MINOR__ >= 303) +#if !defined(__STRICT_ANSI__) && \ + (__has_attribute(__may_alias__) || \ + (__GNUC__ + 0) * 100 + (__GNUC_MINOR__ + 0) >= 303) #define mayalias __attribute__((__may_alias__)) #else #define mayalias @@ -393,8 +400,9 @@ typedef uint64_t uintmax_t; * @see gc(), free(), close(), etc. */ #ifndef nodiscard -#if !defined(__STRICT_ANSI__) && (__GNUC__ * 100 + __GNUC_MINOR__ >= 304 || \ - __has_attribute(__warn_unused_result__)) +#if !defined(__STRICT_ANSI__) && \ + ((__GNUC__ + 0) * 100 + (__GNUC_MINOR__ + 0) >= 304 || \ + __has_attribute(__warn_unused_result__)) #define nodiscard __attribute__((__warn_unused_result__)) #else #define nodiscard @@ -416,7 +424,7 @@ typedef uint64_t uintmax_t; #ifndef flattenout #if __has_attribute(__flatten__) || \ - (__GNUC__ * 100 + __GNUC_MINOR__ >= 401 && !defined(__llvm__)) + ((__GNUC__ + 0) * 100 + (__GNUC_MINOR__ + 0) >= 401 && !defined(__llvm__)) #define flattenout __attribute__((__flatten__)) #else #define flattenout @@ -424,9 +432,10 @@ typedef uint64_t uintmax_t; #endif #ifndef externinline -#if !defined(__STRICT_ANSI__) && \ - (!defined(__cplusplus) || __GNUC__ * 100 + __GNUC_MINOR__ >= 403 || \ - (defined(__clang__) && \ +#if !defined(__STRICT_ANSI__) && \ + (!defined(__cplusplus) || \ + (__GNUC__ + 0) * 100 + (__GNUC_MINOR__ + 0) >= 403 || \ + (defined(__clang__) && \ (defined(__GNUC_STDC_INLINE__) || defined(__GNUC_GNU_INLINE__)))) #if defined(__GNUC_STDC_INLINE__) || defined(__cplusplus) #define externinline extern __inline __attribute__((__gnu_inline__)) @@ -443,16 +452,18 @@ typedef uint64_t uintmax_t; * @note can be used to minimize page-faults and improve locality */ #ifndef relegated -#if !defined(__STRICT_ANSI__) && \ - (__has_attribute(__cold__) || __GNUC__ * 100 + __GNUC_MINOR__ >= 403) +#if !defined(__STRICT_ANSI__) && \ + (__has_attribute(__cold__) || \ + (__GNUC__ + 0) * 100 + (__GNUC_MINOR__ + 0) >= 403) #define relegated __attribute__((__cold__)) #else #define relegated #endif #endif -#if !defined(__STRICT_ANSI__) && \ - (__has_attribute(__warning__) || __GNUC__ * 100 + __GNUC_MINOR__ >= 403) +#if !defined(__STRICT_ANSI__) && \ + (__has_attribute(__warning__) || \ + (__GNUC__ + 0) * 100 + (__GNUC_MINOR__ + 0) >= 403) #define warnifused(s) __attribute__((__warning__(s))) #else #define warnifused(s) @@ -465,7 +476,8 @@ typedef uint64_t uintmax_t; */ #ifndef firstclass #if !defined(__STRICT_ANSI__) && \ - (__has_attribute(__hot__) || __GNUC__ * 100 + __GNUC_MINOR__ >= 403) + (__has_attribute(__hot__) || \ + (__GNUC__ + 0) * 100 + (__GNUC_MINOR__ + 0) >= 403) #define firstclass __attribute__((__hot__)) #else #define firstclass @@ -479,8 +491,9 @@ typedef uint64_t uintmax_t; * runtime too (only in MODE=dbg mode) by synthetic Ubsan code. */ #ifndef paramsnonnull -#if !defined(__STRICT_ANSI__) && \ - (__has_attribute(__nonnull__) || __GNUC__ * 100 + __GNUC_MINOR__ >= 403) +#if !defined(__STRICT_ANSI__) && \ + (__has_attribute(__nonnull__) || \ + (__GNUC__ + 0) * 100 + (__GNUC_MINOR__ + 0) >= 403) #define paramsnonnull(opt_1idxs) __attribute__((__nonnull__ opt_1idxs)) #else #define paramsnonnull(opt_1idxs) @@ -505,7 +518,7 @@ typedef uint64_t uintmax_t; */ #if __STDC_VERSION__ + 0 < 199901L && !defined(restrict) #if !defined(__STRICT_ANSI__) && !defined(__cplusplus) && \ - (__GNUC__ * 100 + __GNUC_MINOR__ >= 301 || defined(_MSC_VER)) + ((__GNUC__ + 0) * 100 + (__GNUC_MINOR__ + 0) >= 301 || defined(_MSC_VER)) #define restrict __restrict__ #else #define restrict @@ -520,7 +533,8 @@ typedef uint64_t uintmax_t; #ifndef nocallback #if !defined(__STRICT_ANSI__) && \ (__has_attribute(__leaf__) || \ - (!defined(__llvm__) && __GNUC__ * 100 + __GNUC_MINOR__ >= 406)) + (!defined(__llvm__) && \ + (__GNUC__ + 0) * 100 + (__GNUC_MINOR__ + 0) >= 406)) #define nocallback __attribute__((__leaf__)) #else #define nocallback @@ -529,7 +543,8 @@ typedef uint64_t uintmax_t; #ifndef nothrow #if defined(__cplusplus) && !defined(__STRICT_ANSI__) && \ - (__has_attribute(nothrow) || __GNUC__ * 100 + __GNUC_MINOR__ >= 303) + (__has_attribute(nothrow) || \ + (__GNUC__ + 0) * 100 + (__GNUC_MINOR__ + 0) >= 303) #define nothrow __attribute__((__nothrow__)) #elif defined(_MSC_VER) #define nothrow __declspec(nothrow) @@ -545,7 +560,8 @@ typedef uint64_t uintmax_t; */ #ifndef nooptimize #ifndef __STRICT_ANSI__ -#if __GNUC__ * 100 + __GNUC_MINOR__ >= 407 || __has_attribute(__optimize__) +#if (__GNUC__ + 0) * 100 + (__GNUC_MINOR__ + 0) >= 407 || \ + __has_attribute(__optimize__) #define nooptimize __attribute__((__optimize__(1))) #elif defined(__llvm__) || __has_attribute(__optnone__) #define nooptimize __attribute__((__optnone__)) @@ -564,7 +580,8 @@ typedef uint64_t uintmax_t; */ #ifndef optimizesize #ifndef __STRICT_ANSI__ -#if __GNUC__ * 100 + __GNUC_MINOR__ >= 407 || __has_attribute(__optimize__) +#if (__GNUC__ + 0) * 100 + (__GNUC_MINOR__ + 0) >= 407 || \ + __has_attribute(__optimize__) #define optimizesize __attribute__((__optimize__("s"))) #elif defined(__llvm__) || __has_attribute(__optnone__) #define optimizesize __attribute__((__optnone__)) @@ -584,8 +601,9 @@ typedef uint64_t uintmax_t; * @todo this is dangerous delete? */ #ifndef optimizespeed -#if !defined(__STRICT_ANSI__) && \ - (__GNUC__ * 100 + __GNUC_MINOR__ >= 407 || __has_attribute(__optimize__)) +#if !defined(__STRICT_ANSI__) && \ + ((__GNUC__ + 0) * 100 + (__GNUC_MINOR__ + 0) >= 407 || \ + __has_attribute(__optimize__)) #define optimizespeed __attribute__((__optimize__(3))) #else #define optimizespeed @@ -596,8 +614,9 @@ typedef uint64_t uintmax_t; * Declares prototype that behaves similar to setjmp() or vfork(). */ #ifndef returnstwice -#if !defined(__STRICT_ANSI__) && (__has_attribute(__returns_twice__) || \ - __GNUC__ * 100 + __GNUC_MINOR__ >= 402) +#if !defined(__STRICT_ANSI__) && \ + (__has_attribute(__returns_twice__) || \ + (__GNUC__ + 0) * 100 + (__GNUC_MINOR__ + 0) >= 402) #define returnstwice __attribute__((__returns_twice__)) #else #define returnstwice @@ -622,8 +641,9 @@ typedef uint64_t uintmax_t; * @see nodebuginfo */ #ifndef artificial -#if !defined(__STRICT_ANSI__) && (__has_attribute(__artificial__) || \ - __GNUC__ * 100 + __GNUC_MINOR__ >= 403) +#if !defined(__STRICT_ANSI__) && \ + (__has_attribute(__artificial__) || \ + (__GNUC__ + 0) * 100 + (__GNUC_MINOR__ + 0) >= 403) #define artificial __attribute__((__artificial__)) #else #define artificial @@ -636,8 +656,9 @@ typedef uint64_t uintmax_t; * @see libc/dce.h */ #ifndef microarchitecture -#if !defined(__STRICT_ANSI__) && \ - (__has_attribute(__target__) || __GNUC__ * 100 + __GNUC_MINOR__ >= 404) +#if !defined(__STRICT_ANSI__) && \ + (__has_attribute(__target__) || \ + (__GNUC__ + 0) * 100 + (__GNUC_MINOR__ + 0) >= 404) #define microarchitecture(march) __attribute__((__target__(march))) #else #define microarchitecture(march) @@ -661,7 +682,7 @@ typedef uint64_t uintmax_t; * Defines function with prologue that fixes misaligned stack. * @see nocallersavedregisters and consider assembly */ -#if __GNUC__ * 100 + __GNUC_MINOR__ >= 408 || \ +#if (__GNUC__ + 0) * 100 + (__GNUC_MINOR__ + 0) >= 408 || \ __has_attribute(__force_align_arg_pointer__) #define forcealignargpointer __attribute__((__force_align_arg_pointer__)) #else @@ -675,8 +696,9 @@ typedef uint64_t uintmax_t; * runtime too by synthetic code, only in MODE=dbg mode. */ #ifndef returnsnonnull -#if !defined(__STRICT_ANSI__) && (__has_attribute(__returns_nonnull__) || \ - __GNUC__ * 100 + __GNUC_MINOR__ >= 409) +#if !defined(__STRICT_ANSI__) && \ + (__has_attribute(__returns_nonnull__) || \ + (__GNUC__ + 0) * 100 + (__GNUC_MINOR__ + 0) >= 409) #define returnsnonnull __attribute__((__returns_nonnull__)) #else #define returnsnonnull @@ -690,8 +712,9 @@ typedef uint64_t uintmax_t; * @param (alignment, misalignment) * @see attributeallocalign(), returnspointerwithnoaliases, mallocesque */ -#if !defined(__STRICT_ANSI__) && (__has_attribute(__assume_aligned__) || \ - __GNUC__ * 100 + __GNUC_MINOR__ >= 409) +#if !defined(__STRICT_ANSI__) && \ + (__has_attribute(__assume_aligned__) || \ + (__GNUC__ + 0) * 100 + (__GNUC_MINOR__ + 0) >= 409) #define returnsaligned(x) __attribute__((__assume_aligned__ x)) #else #define returnsaligned(x) @@ -702,8 +725,9 @@ typedef uint64_t uintmax_t; * @see attributeallocsize(), attributeallocalign() */ #ifndef returnspointerwithnoaliases -#if !defined(__STRICT_ANSI__) && \ - (__has_attribute(__malloc__) || __GNUC__ * 100 + __GNUC_MINOR__ >= 409) +#if !defined(__STRICT_ANSI__) && \ + (__has_attribute(__malloc__) || \ + (__GNUC__ + 0) * 100 + (__GNUC_MINOR__ + 0) >= 409) #define returnspointerwithnoaliases __attribute__((__malloc__)) #elif defined(_MSC_VER) #define returnspointerwithnoaliases __declspec(allocator) @@ -713,8 +737,9 @@ typedef uint64_t uintmax_t; #endif #ifndef attributeallocsize -#if !defined(__STRICT_ANSI__) && (__has_attribute(__alloc_size__) || \ - __GNUC__ * 100 + __GNUC_MINOR__ >= 409) +#if !defined(__STRICT_ANSI__) && \ + (__has_attribute(__alloc_size__) || \ + (__GNUC__ + 0) * 100 + (__GNUC_MINOR__ + 0) >= 409) #define attributeallocsize(x) __attribute__((__alloc_size__ x)) #else #define attributeallocsize(x) @@ -722,8 +747,9 @@ typedef uint64_t uintmax_t; #endif #ifndef attributeallocalign -#if !defined(__STRICT_ANSI__) && (__has_attribute(__alloc_align__) || \ - __GNUC__ * 100 + __GNUC_MINOR__ >= 409) +#if !defined(__STRICT_ANSI__) && \ + (__has_attribute(__alloc_align__) || \ + (__GNUC__ + 0) * 100 + (__GNUC_MINOR__ + 0) >= 409) #define attributeallocalign(x) __attribute__((__alloc_align__ x)) #else #define attributeallocalign(x) @@ -747,7 +773,7 @@ typedef uint64_t uintmax_t; #if __cplusplus + 0 >= 201103L #define autotype(x) auto #elif (__has_builtin(auto_type) || defined(__llvm__) || \ - __GNUC__ * 100 + __GNUC_MINOR__ >= 409) + (__GNUC__ + 0) * 100 + (__GNUC_MINOR__ + 0) >= 409) #define autotype(x) __auto_type #else #define autotype(x) typeof(x) diff --git a/libc/integral/normalize.inc b/libc/integral/normalize.inc index 29802cf2..f6784ebb 100644 --- a/libc/integral/normalize.inc +++ b/libc/integral/normalize.inc @@ -75,7 +75,7 @@ #define ENV_MAX 0x7fff /* b/c windows */ #define ARG_MAX 0x3fff /* b/c windows */ #define CMD_MAX 0x4000 /* b/c windows */ -#define PATH_MAX 248 /* b/c windows */ +#define PATH_MAX 248 /* b/c win32 apis limit ~248..260 */ #define NAME_MAX 63 /* b/c dns */ #define CHILD_MAX 25 /* only if malloc isn't linked */ #define OPEN_MAX 16 /* only if malloc isn't linked */ diff --git a/libc/intrin/mpsadbw.c b/libc/intrin/mpsadbw.c new file mode 100644 index 00000000..29edf261 --- /dev/null +++ b/libc/intrin/mpsadbw.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 2020 Justine Alexandra Roberts Tunney │ +│ │ +│ This program is free software; you can redistribute it and/or modify │ +│ it under the terms of the GNU General Public License as published by │ +│ the Free Software Foundation; version 2 of the License. │ +│ │ +│ This program is distributed in the hope that it will be useful, but │ +│ WITHOUT ANY WARRANTY; without even the implied warranty of │ +│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │ +│ General Public License for more details. │ +│ │ +│ You should have received a copy of the GNU General Public License │ +│ along with this program; if not, write to the Free Software │ +│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │ +│ 02110-1301 USA │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/intrin/mpsadbw.h" +#include "libc/macros.h" +#include "libc/str/str.h" + +/** + * Computes multiple sum of absolute differences. + * + * This appears to be intended for video encoding motion estimation. It + * can be combined with phminposuw. That allows us to search for an int + * overlapping inside 𝑏 that's nearest to an aligned int in 𝑎. + * + * @note goes fast w/ sse4 cf. core c. 2006 cf. bulldozer c. 2011 + * @mayalias + */ +void(mpsadbw)(uint16_t c[8], const uint8_t b[16], const uint8_t a[16], + uint8_t control) { + unsigned i, j; + uint16_t r[8]; + for (i = 0; i < 8; ++i) { + r[i] = 0; + for (j = 0; j < 4; ++j) { + r[i] += ABS(b[(control & 4) + i + j] - a[(control & 3) * 4 + j]); + } + } + memcpy(c, r, 16); +} diff --git a/libc/intrin/mpsadbw.h b/libc/intrin/mpsadbw.h new file mode 100644 index 00000000..f26034e4 --- /dev/null +++ b/libc/intrin/mpsadbw.h @@ -0,0 +1,41 @@ +#ifndef COSMOPOLITAN_LIBC_INTRIN_MPSADBW_H_ +#define COSMOPOLITAN_LIBC_INTRIN_MPSADBW_H_ +#include "libc/intrin/macros.h" +#if !(__ASSEMBLER__ + __LINKER__ + 0) +COSMOPOLITAN_C_START_ + +void mpsadbw(uint16_t[8], const uint8_t[16], const uint8_t[16], uint8_t); + +#ifndef __STRICT_ANSI__ +__intrin_xmm_t __mpsadbws(__intrin_xmm_t, __intrin_xmm_t); +#define mpsadbw(C, B, A, I) \ + do { \ + if (likely(!IsModeDbg() && X86_NEED(SSE) && X86_HAVE(SSE4_1))) { \ + __intrin_xmm_t *Xmm0 = (void *)(C); \ + const __intrin_xmm_t *Xmm1 = (const __intrin_xmm_t *)(B); \ + const __intrin_xmm_t *Xmm2 = (const __intrin_xmm_t *)(A); \ + if (isconstant(I)) { \ + if (!X86_NEED(AVX)) { \ + asm("mpsadbw\t%2,%1,%0" \ + : "=x"(*Xmm0) \ + : "x"(*Xmm2), "i"(I), "0"(*Xmm1)); \ + } else { \ + asm("vmpsadbw\t%3,%2,%1,%0" \ + : "=x"(*Xmm0) \ + : "x"(*Xmm1), "x"(*Xmm2), "i"(I)); \ + } \ + } else { \ + unsigned long Vimm = (I); \ + typeof(__mpsadbws) *Fn; \ + Fn = (typeof(__mpsadbws) *)((uintptr_t)&__mpsadbws + (Vimm & 7) * 8); \ + *Xmm0 = Fn(*Xmm1, *Xmm2); \ + } \ + } else { \ + mpsadbw(C, B, A, I); \ + } \ + } while (0) +#endif + +COSMOPOLITAN_C_END_ +#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ +#endif /* COSMOPOLITAN_LIBC_INTRIN_MPSADBW_H_ */ diff --git a/libc/nexgen32e/kcrc32tab.S b/libc/intrin/mpsadbws.S similarity index 81% rename from libc/nexgen32e/kcrc32tab.S rename to libc/intrin/mpsadbws.S index 36cb48c4..f7f2153e 100644 --- a/libc/nexgen32e/kcrc32tab.S +++ b/libc/intrin/mpsadbws.S @@ -19,24 +19,17 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/macros.h" -/ Phil Katz CRC-32 Polynomial -/ x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x+1 -/ 0b100000100110000010001110110110111 -/ bitreverse32(0x104c11db7) -#define kZipCrc32Polynomial 0xedb88320 - - .initbss 300,_init_kCrc32Tab -kCrc32Tab: - .rept 256 - .long 0 +/ Jump table for mpsadbw() with non-constexpr immediate parameter. +/ +/ @note needs sse4 cf. core c. 2006 cf. bulldozer c. 2011 +/ @see mpsadbw() + .align 8 +__mpsadbws: + i = 0 + .rept 8 + mpsadbw $i,%xmm1,%xmm0 + ret + nop + i = i + 1 .endr - .endobj kCrc32Tab,globl,hidden - .previous - - .init.start 300,_init_kCrc32Tab - push %rsi - mov $kZipCrc32Polynomial,%esi - call crc32init - pop %rsi - .init.end 300,_init_kCrc32Tab - .source __FILE__ + .endfn __mpsadbws,globl diff --git a/libc/intrin/repstosb.h b/libc/intrin/repstosb.h index e733a6f0..554682da 100644 --- a/libc/intrin/repstosb.h +++ b/libc/intrin/repstosb.h @@ -14,7 +14,7 @@ forceinline void *repstosb(void *dest, unsigned char al, size_t cx) { void *Di = (DI); \ size_t Cx = (CX); \ unsigned char Al = (AL); \ - asm("rep stosb" \ + asm("rep stosb %b5,(%0)" \ : "=D"(Di), "=c"(Cx), "=m"(*(char(*)[Cx])Di) \ : "0"(Di), "1"(Cx), "a"(Al)); \ Di; \ diff --git a/libc/log/asan.c b/libc/log/asan.c index 0c7f54b1..08b8758d 100644 --- a/libc/log/asan.c +++ b/libc/log/asan.c @@ -102,6 +102,111 @@ struct AsanGlobal { char *odr_indicator; }; +struct AsanMorgue { + unsigned i; + void *p[16]; +}; + +static struct AsanMorgue __asan_morgue; + +static const char *__asan_dscribe_free_poison(int c) { + switch (c) { + case kAsanHeapFree: + return "heap double free"; + case kAsanRelocated: + return "free after relocate"; + case kAsanStackFree: + return "stack double free"; + default: + return "invalid pointer"; + } +} + +static const char *__asan_describe_access_poison(int c) { + switch (c) { + case kAsanHeapFree: + return "heap use after free"; + case kAsanStackFree: + return "stack use after release"; + case kAsanRelocated: + return "heap use after relocate"; + case kAsanHeapUnderrun: + return "heap underrun"; + case kAsanHeapOverrun: + return "heap overrun"; + case kAsanGlobalOverrun: + return "global overrun"; + case kAsanGlobalUnregistered: + return "global unregistered"; + case kAsanStackUnderrun: + return "stack underflow"; + case kAsanStackOverrun: + return "stack overflow"; + case kAsanAllocaOverrun: + return "alloca overflow"; + case kAsanUnscoped: + return "unscoped"; + default: + return "poisoned"; + } +} + +static noreturn void __asan_die(const char *msg, size_t size) { + __print(msg, size); + PrintBacktraceUsingSymbols(stderr, __builtin_frame_address(0), + getsymboltable()); + DebugBreak(); + _Exit(66); +} + +static noreturn void __asan_report_deallocate_fault(void *addr, int c) { + char *p, ibuf[21], buf[256]; + p = buf; + p = stpcpy(p, "error: "); + p = stpcpy(p, __asan_dscribe_free_poison(c)); + p = stpcpy(p, " "); + p = mempcpy(p, ibuf, int64toarray_radix10(c, ibuf)); + p = stpcpy(p, " at 0x"); + p = mempcpy(p, ibuf, uint64toarray_fixed16((intptr_t)addr, ibuf, 48)); + p = stpcpy(p, "\n"); + __asan_die(buf, p - buf); +} + +static noreturn void __asan_report_memory_fault(uint8_t *addr, int size, + const char *kind) { + char *p, ibuf[21], buf[256]; + p = buf; + p = stpcpy(p, "error: "); + p = stpcpy(p, __asan_describe_access_poison(*(char *)SHADOW((intptr_t)addr))); + p = stpcpy(p, " "); + p = mempcpy(p, ibuf, uint64toarray_radix10(size, ibuf)); + p = stpcpy(p, "-byte "); + p = stpcpy(p, kind); + p = stpcpy(p, " at 0x"); + p = mempcpy(p, ibuf, uint64toarray_fixed16((intptr_t)addr, ibuf, 48)); + p = stpcpy(p, "\n"); + __asan_die(buf, p - buf); +} + +static const void *__asan_morgue_add(void *p) { + void *r; + r = __asan_morgue.p[__asan_morgue.i]; + __asan_morgue.p[__asan_morgue.i] = p; + __asan_morgue.i += 1; + __asan_morgue.i &= ARRAYLEN(__asan_morgue.p) - 1; + return r; +} + +static void __asan_morgue_flush(void) { + void *p; + unsigned i; + for (i = 0; i < ARRAYLEN(__asan_morgue.p); ++i) { + p = __asan_morgue.p[i]; + __asan_morgue.p[i] = NULL; + dlfree(p); + } +} + static bool __asan_is_mapped(void *p) { int x, i; x = (intptr_t)p >> 16; @@ -109,41 +214,8 @@ static bool __asan_is_mapped(void *p) { return i < _mmi.i && x >= _mmi.p[i].x && x <= _mmi.p[i].y; } -void __asan_map_shadow(void *addr, size_t size) { - int i, n, x; - char *a, *b; - struct DirectMap sm; - a = (char *)ROUNDDOWN(SHADOW((intptr_t)addr), FRAMESIZE); - b = (char *)ROUNDDOWN(SHADOW((intptr_t)addr + size - 1), FRAMESIZE); - for (; a <= b; a += FRAMESIZE) { - if (!__asan_is_mapped(a)) { - sm = DirectMap(a, FRAMESIZE, PROT_READ | PROT_WRITE, - MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, 0); - if (sm.addr == MAP_FAILED || - TrackMemoryInterval(&_mmi, (intptr_t)a >> 16, (intptr_t)a >> 16, - sm.maphandle) == -1) { - abort(); - } - } - } -} - -size_t __asan_malloc_usable_size(const void *vp) { - char *s; - size_t n; - for (n = 0, s = (char *)SHADOW((intptr_t)vp);; ++s) { - if (!*s) { - n += 8; - } else if (*s > 0) { - n += *s & 7; - } else { - break; - } - } - return n; -} - -void *__asan_allocate(size_t align, size_t size, int underrun, int overrun) { +static void *__asan_allocate(size_t align, size_t size, int underrun, + int overrun) { char *p, *s; size_t q, r, i; if (!(p = dlmemalign(align, ROUNDUP(size, 8) + 16))) return NULL; @@ -160,29 +232,59 @@ void *__asan_allocate(size_t align, size_t size, int underrun, int overrun) { return p; } -void __asan_deallocate(char *p, int kind) { +static void __asan_deallocate(char *p, int kind) { + char *s; + s = (char *)SHADOW((intptr_t)p); + if ((*s < 0 && *s != kAsanHeapOverrun) || *s >= 8) { + __asan_report_deallocate_fault(p, *s); + } + for (; *s >= 0; ++s) *s = kind; + dlfree(__asan_morgue_add(p)); +} + +static void __asan_poison_redzone(intptr_t addr, size_t size, size_t redsize, + int kind) { + char *s; + intptr_t p; + size_t a, b, w; + w = (intptr_t)addr & 7; + p = (intptr_t)addr - w; + a = w + size; + b = w + redsize; + s = (char *)SHADOW(p + a); + if (a & 7) *s++ = a & 7; + memset(s, kind, (b - ROUNDUP(a, 8)) >> 3); +} + +static size_t __asan_malloc_usable_size(const void *vp) { char *s; size_t n; - s = (char *)SHADOW((intptr_t)p); - n = dlmalloc_usable_size(p); - n /= 8; - memset(s, kind, n); - dlfree(p); + for (n = 0, s = (char *)SHADOW((intptr_t)vp);; ++s) { + if (!*s) { + n += 8; + } else if (*s > 0) { + n += *s & 7; + } else { + break; + } + } + return n; } -void __asan_free(void *vp) { - __asan_deallocate(vp, kAsanHeapFree); +static void __asan_free(void *p) { + if (!p) return; + __asan_deallocate(p, kAsanHeapFree); } -void *__asan_memalign(size_t align, size_t size) { +static void *__asan_memalign(size_t align, size_t size) { return __asan_allocate(align, size, kAsanHeapUnderrun, kAsanHeapOverrun); } -void *__asan_malloc(size_t size) { +static void *__asan_malloc(size_t size) { return __asan_memalign(16, size); } -void *__asan_calloc(size_t n, size_t m) { +static void *__asan_calloc(size_t n, size_t m) { char *p; size_t size; if (__builtin_mul_overflow(n, m, &size)) size = -1; @@ -190,7 +292,7 @@ void *__asan_calloc(size_t n, size_t m) { return p; } -void *__asan_realloc(void *p, size_t n) { +static void *__asan_realloc(void *p, size_t n) { char *p2; if (p) { if (n) { @@ -208,86 +310,32 @@ void *__asan_realloc(void *p, size_t n) { return p2; } -void *__asan_valloc(size_t n) { +static void *__asan_valloc(size_t n) { return __asan_memalign(PAGESIZE, n); } -void *__asan_pvalloc(size_t n) { +static void *__asan_pvalloc(size_t n) { return __asan_valloc(ROUNDUP(n, PAGESIZE)); } -void __asan_poison(intptr_t addr, size_t size, size_t redsize, int kind) { - char *s; - intptr_t p; - size_t a, b, w; - w = (intptr_t)addr & 7; - p = (intptr_t)addr - w; - a = w + size; - b = w + redsize; - s = (char *)SHADOW(p + a); - if (a & 7) *s++ = a & 7; - memset(s, kind, (b - ROUNDUP(a, 8)) >> 3); -} - void __asan_register_globals(struct AsanGlobal g[], int n) { - size_t i; + unsigned i; for (i = 0; i < n; ++i) { - __asan_poison((intptr_t)g[i].addr, g[i].size, g[i].size_with_redzone, - kAsanGlobalOverrun); + __asan_poison_redzone((intptr_t)g[i].addr, g[i].size, + g[i].size_with_redzone, kAsanGlobalOverrun); } } -void __asan_report_memory_fault(uint8_t *addr, int size, const char *kind) { - char *p, *s, ibuf[21], buf[256]; - switch (*(char *)SHADOW((intptr_t)addr)) { - case kAsanStackFree: - s = "stack use after release"; - break; - case kAsanHeapFree: - s = "heap use after free"; - break; - case kAsanRelocated: - s = "heap use after relocate"; - break; - case kAsanHeapUnderrun: - s = "heap underrun"; - break; - case kAsanHeapOverrun: - s = "heap overrun"; - break; - case kAsanStackUnderrun: - s = "stack underflow"; - break; - case kAsanStackOverrun: - s = "stack overflow"; - break; - case kAsanAllocaOverrun: - s = "alloca overflow"; - break; - case kAsanUnscoped: - s = "unscoped"; - break; - default: - s = "poisoned"; - break; +void __asan_unregister_globals(struct AsanGlobal g[], int n) { + unsigned i; + intptr_t a, b; + for (i = 0; i < n; ++i) { + a = ROUNDUP((intptr_t)g[i].addr, 8); + b = ROUNDDOWN((intptr_t)g[i].addr + g[i].size_with_redzone, 8); + if (b > a) { + memset((char *)SHADOW(a), kAsanGlobalUnregistered, (b - a) >> 3); + } } - p = buf; - p = stpcpy(p, "error: "); - p = stpcpy(p, s); - p = stpcpy(p, " "); - uint64toarray_radix10(size, ibuf); - p = stpcpy(p, ibuf); - p = stpcpy(p, "-byte "); - p = stpcpy(p, kind); - p = stpcpy(p, " at 0x"); - uint64toarray_fixed16((intptr_t)addr, ibuf, 48); - p = stpcpy(p, ibuf); - p = stpcpy(p, "\n"); - __print(buf, p - buf); - PrintBacktraceUsingSymbols(stderr, __builtin_frame_address(0), - getsymboltable()); - DebugBreak(); - _Exit(66); } void *__asan_stack_malloc(size_t size, int classid) { @@ -295,7 +343,7 @@ void *__asan_stack_malloc(size_t size, int classid) { } void __asan_stack_free(char *p, size_t size, int classid) { - return __asan_deallocate(p, kAsanStackFree); + dlfree(p); } void __asan_report_load_n(uint8_t *addr, int size) { @@ -316,16 +364,8 @@ void __asan_unpoison_stack_memory(uintptr_t p, size_t n) { if (n & 7) *(char *)SHADOW(p + n) = n & 7; } -void __asan_loadN(intptr_t ptr, size_t size) { - DebugBreak(); -} - -void __asan_storeN(intptr_t ptr, size_t size) { - DebugBreak(); -} - void __asan_alloca_poison(intptr_t addr, size_t size) { - __asan_poison(addr, size, size + 32, kAsanAllocaOverrun); + __asan_poison_redzone(addr, size, size + 32, kAsanAllocaOverrun); } void __asan_allocas_unpoison(uintptr_t top, uintptr_t bottom) { @@ -352,7 +392,27 @@ void __asan_install_malloc_hooks(void) { HOOK(hook$malloc_usable_size, __asan_malloc_usable_size); } -void __asan_init(int argc, char *argv[], char **envp, intptr_t *auxv) { +void __asan_map_shadow(void *addr, size_t size) { + int i, n, x; + char *a, *b; + struct DirectMap sm; + a = (char *)ROUNDDOWN(SHADOW((intptr_t)addr), FRAMESIZE); + b = (char *)ROUNDDOWN(SHADOW((intptr_t)addr + size - 1), FRAMESIZE); + for (; a <= b; a += FRAMESIZE) { + if (!__asan_is_mapped(a)) { + sm = DirectMap(a, FRAMESIZE, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, 0); + if (sm.addr == MAP_FAILED || + TrackMemoryInterval(&_mmi, (intptr_t)a >> 16, (intptr_t)a >> 16, + sm.maphandle) == -1) { + abort(); + } + } + } +} + +textstartup void __asan_init(int argc, char *argv[], char **envp, + intptr_t *auxv) { int i; static bool once; register intptr_t rsp asm("rsp"); @@ -367,4 +427,9 @@ void __asan_init(int argc, char *argv[], char **envp, intptr_t *auxv) { } } -const void *const g_asan_ctor[] initarray = {getsymboltable}; +static textstartup void __asan_ctor(void) { + /* __cxa_atexit(__asan_morgue_flush, NULL, NULL); */ + getsymboltable(); +} + +const void *const g_asan_ctor[] initarray = {__asan_ctor}; diff --git a/libc/log/asan.h b/libc/log/asan.h index ca15d460..6bfc4110 100644 --- a/libc/log/asan.h +++ b/libc/log/asan.h @@ -1,18 +1,19 @@ #ifndef COSMOPOLITAN_LIBC_LOG_ASAN_H_ #define COSMOPOLITAN_LIBC_LOG_ASAN_H_ -#define kAsanScale 3 -#define kAsanMagic 0x7fff8000 -#define kAsanHeapFree -1 -#define kAsanStackFree -2 -#define kAsanRelocated -3 -#define kAsanHeapUnderrun -4 -#define kAsanHeapOverrun -5 -#define kAsanGlobalOverrun -6 -#define kAsanStackUnderrun -7 -#define kAsanStackOverrun -8 -#define kAsanAllocaOverrun -9 -#define kAsanUnscoped -10 +#define kAsanScale 3 +#define kAsanMagic 0x7fff8000 +#define kAsanHeapFree -1 +#define kAsanStackFree -2 +#define kAsanRelocated -3 +#define kAsanHeapUnderrun -4 +#define kAsanHeapOverrun -5 +#define kAsanGlobalOverrun -6 +#define kAsanGlobalUnregistered -7 +#define kAsanStackUnderrun -8 +#define kAsanStackOverrun -9 +#define kAsanAllocaOverrun -10 +#define kAsanUnscoped -11 #define SHADOW(x) (((x) >> kAsanScale) + kAsanMagic) diff --git a/libc/log/backtrace3.c b/libc/log/backtrace3.c index 03f09ecf..1ba6c8cf 100644 --- a/libc/log/backtrace3.c +++ b/libc/log/backtrace3.c @@ -18,41 +18,29 @@ │ 02110-1301 USA │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/alg/bisectcarleft.h" +#include "libc/assert.h" #include "libc/bits/weaken.h" +#include "libc/conv/itoa.h" #include "libc/fmt/fmt.h" #include "libc/log/backtrace.h" #include "libc/macros.h" #include "libc/nexgen32e/gc.h" #include "libc/nexgen32e/stackframe.h" +#include "libc/runtime/missioncritical.h" #include "libc/runtime/symbols.h" #include "libc/stdio/stdio.h" - -static char *FormatAddress(FILE *f, const struct SymbolTable *st, intptr_t addr, - char *out, unsigned size, bool symbolic) { - int64_t addend; - const char *name; - const struct Symbol *symbol; - if (st->count && ((intptr_t)addr >= (intptr_t)&_base && - (intptr_t)addr <= (intptr_t)&_end && symbolic)) { - symbol = &st->symbols[bisectcarleft((const int32_t(*)[2])st->symbols, - st->count, addr - st->addr_base - 1)]; - addend = addr - st->addr_base - symbol->addr_rva; - name = &st->name_base[symbol->name_rva]; - snprintf(out, size, "%s%c%#x", name, addend >= 0 ? '+' : '-', ABS(addend)); - } else { - snprintf(out, size, "%p", addr); - } - return out; -} +#include "libc/str/str.h" int PrintBacktraceUsingSymbols(FILE *f, const struct StackFrame *bp, - struct SymbolTable *symbols) { + struct SymbolTable *st) { size_t gi; - char buf[256]; intptr_t addr; + int64_t addend; struct Garbages *garbage; + char *p, buf[256], ibuf[21]; + const struct Symbol *symbol; const struct StackFrame *frame; - if (!symbols) return -1; + if (!st) return -1; garbage = weaken(g_garbage); gi = garbage ? garbage->i : 0; for (frame = bp; frame; frame = frame->next) { @@ -62,8 +50,25 @@ int PrintBacktraceUsingSymbols(FILE *f, const struct StackFrame *bp, --gi; } while ((addr = garbage->p[gi].ret) == weakaddr("CollectGarbage")); } - fprintf(f, "%p %p %s\n", frame, addr, - FormatAddress(f, symbols, addr, buf, sizeof(buf), true)); + p = buf; + p = mempcpy(p, ibuf, uint64toarray_fixed16((intptr_t)frame, ibuf, 48)); + *p++ = ' '; + p = mempcpy(p, ibuf, uint64toarray_fixed16(addr, ibuf, 48)); + *p++ = ' '; + if (st->count && ((intptr_t)addr >= (intptr_t)&_base && + (intptr_t)addr <= (intptr_t)&_end)) { + symbol = &st->symbols[bisectcarleft((const int32_t(*)[2])st->symbols, + st->count, addr - st->addr_base - 1)]; + p = stpcpy(p, &st->name_base[symbol->name_rva]); + addend = addr - st->addr_base - symbol->addr_rva; + *p++ = addend >= 0 ? '+' : '-'; + if (addend) *p++ = '0', *p++ = 'x'; + p = mempcpy(p, ibuf, uint64toarray_radix16(ABS(addend), ibuf)); + } else { + p = stpcpy(p, "UNKNOWN"); + } + *p++ = '\n'; + __print(buf, p - buf); } return 0; } diff --git a/libc/log/checkfail_ndebug.c b/libc/log/checkfail_ndebug.c index 2897c504..21c88cc4 100644 --- a/libc/log/checkfail_ndebug.c +++ b/libc/log/checkfail_ndebug.c @@ -17,11 +17,11 @@ │ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │ │ 02110-1301 USA │ ╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/conv/itoa.h" #include "libc/errno.h" -#include "libc/fmt/fmt.h" #include "libc/log/internal.h" #include "libc/log/log.h" -#include "libc/stdio/stdio.h" +#include "libc/runtime/missioncritical.h" /** * Handles failure of CHECK_xx() macros in -DNDEBUG mode. @@ -35,8 +35,17 @@ */ relegated void ___check_fail_ndebug(uint64_t want, uint64_t got, const char *opchar) { - int lasterr = errno; + char bx[21]; + int lasterr; + lasterr = errno; startfatal_ndebug(); - fprintf(stderr, "%s: %#lx %s %#lx (%s)\n", "check failed", want, opchar, got, - strerror(lasterr)); + __print_string("check failed: 0x"); + __print(bx, uint64toarray_radix16(want, bx)); + __print_string(" "); + __print_string(opchar); + __print_string(" 0x"); + __print(bx, uint64toarray_radix16(got, bx)); + __print_string(" ("); + __print(bx, int64toarray_radix10(lasterr, bx)); + __print_string(")\n"); } diff --git a/libc/log/commandvenv.c b/libc/log/commandvenv.c index 4aded14e..538c91f7 100644 --- a/libc/log/commandvenv.c +++ b/libc/log/commandvenv.c @@ -20,6 +20,7 @@ #include "libc/bits/safemacros.h" #include "libc/calls/calls.h" #include "libc/log/log.h" +#include "libc/mem/mem.h" #include "libc/runtime/runtime.h" #include "libc/sysv/consts/ok.h" @@ -31,12 +32,12 @@ nodiscard char *commandvenv(const char *var, const char *cmd) { char pathbuf[PATH_MAX]; if ((exepath = getenv(var))) { if (!isempty(exepath) && access(exepath, X_OK) != -1) { - return exepath; + return strdup(exepath); } else { return NULL; } } else if ((exepath = commandv(cmd, pathbuf))) { - return exepath; + return strdup(exepath); } else { return NULL; } diff --git a/libc/log/malloc_stats.c b/libc/log/malloc_stats.c index 886a3e1a..262ad8f4 100644 --- a/libc/log/malloc_stats.c +++ b/libc/log/malloc_stats.c @@ -24,7 +24,7 @@ STATIC_YOINK("ntoa"); void malloc_stats(void) { - struct MallocStats res = dlmalloc_stats(gm); + struct MallocStats res = dlmalloc_stats(g_dlmalloc); (fprintf)(stderr, "max system bytes = %'10zu\n", res.maxfp); (fprintf)(stderr, "system bytes = %'10zu\n", res.fp); (fprintf)(stderr, "in use bytes = %'10zu\n", res.used); diff --git a/libc/log/somanyasan.S b/libc/log/somanyasan.S index c4772f6f..a1888d5a 100644 --- a/libc/log/somanyasan.S +++ b/libc/log/somanyasan.S @@ -27,64 +27,6 @@ / since ASAN has the same stylistic hugeness as UBSAN. / We also guard all the functions, against reentrancy. -__asan_load1: - push $1 - jmp OnLoad - .endfn __asan_load1,globl -__asan_load2: - push $2 - jmp OnLoad - .endfn __asan_load2,globl -__asan_load4: - push $4 - jmp OnLoad - .endfn __asan_load4,globl -__asan_load8: - push $8 - jmp OnLoad - .endfn __asan_load8,globl -__asan_load16: - push $16 - jmp OnLoad - .endfn __asan_load16,globl -__asan_load32: - push $32 -/ 𝑠𝑙𝑖𝑑𝑒 - .endfn __asan_load32,globl -OnLoad: pop %rsi - ezlea __asan_loadN,ax - jmp __asan_report_noreentry - .endfn OnStore - -__asan_store1: - push $1 - jmp OnStore - .endfn __asan_store1,globl -__asan_store2: - push $2 - jmp OnStore - .endfn __asan_store2,globl -__asan_store4: - push $4 - jmp OnStore - .endfn __asan_store4,globl -__asan_store8: - push $8 - jmp OnStore - .endfn __asan_store8,globl -__asan_store16: - push $16 - jmp OnStore - .endfn __asan_store16,globl -__asan_store32: - push $32 -/ 𝑠𝑙𝑖𝑑𝑒 - .endfn __asan_store32,globl -OnStore:pop %rsi - ezlea __asan_storeN,ax - jmp __asan_report_noreentry - .endfn OnStore - __asan_report_load1: push $1 jmp OnReportLoad @@ -264,10 +206,6 @@ __asan_after_dynamic_init: ret .endfn __asan_after_dynamic_init,globl -__asan_unregister_globals: - ret - .endfn __asan_unregister_globals,globl - __asan_version_mismatch_check_v8: ret .endfn __asan_version_mismatch_check_v8,globl @@ -287,7 +225,7 @@ __asan_version_mismatch_check_v8: .rodata.cst4 __asan_option_detect_stack_use_after_return: - .long 1 + .long 0 .endobj __asan_option_detect_stack_use_after_return,globl .previous diff --git a/libc/log/startfatal_ndebug.c b/libc/log/startfatal_ndebug.c index cb5eac71..c4ac1535 100644 --- a/libc/log/startfatal_ndebug.c +++ b/libc/log/startfatal_ndebug.c @@ -17,10 +17,8 @@ │ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │ │ 02110-1301 USA │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/log/internal.h" -#include "libc/runtime/runtime.h" +#include "libc/runtime/missioncritical.h" #include "libc/stdio/stdio.h" -#include "libc/calls/calls.h" /** * Prints initial part of fatal message. @@ -31,7 +29,7 @@ relegated void startfatal_ndebug(void) { fflush(stdout); fflush(stderr); - stderr->bufmode = _IOFBF; - fprintf(stderr, "%s%s%s:%s%s: ", RED, "error", BLUE1, program_invocation_name, - RESET); + __print_string("error:"); + __print_string(program_invocation_name); + __print_string(": "); } diff --git a/libc/log/ubsan.c b/libc/log/ubsan.c index bd5849fe..67773ce9 100644 --- a/libc/log/ubsan.c +++ b/libc/log/ubsan.c @@ -32,17 +32,18 @@ static char __ubsan_buf[256]; -static const char kUbsanTypeCheckKinds[] = "load of\0" - "store to\0" - "reference binding to\0" - "member access within\0" - "member call on\0" - "constructor call on\0" - "downcast of\0" - "downcast of\0" - "upcast of\0" - "cast to virtual base of\0" - "\0"; +static const char kUbsanTypeCheckKinds[] = "\ +load of\0\ +store to\0\ +reference binding to\0\ +member access within\0\ +member call on\0\ +constructor call on\0\ +downcast of\0\ +downcast of\0\ +upcast of\0\ +cast to virtual base of\0\ +\0"; void __ubsan_abort(const struct UbsanSourceLocation *loc, const char *description) { diff --git a/libc/math.h b/libc/math.h index 66952089..041647d8 100644 --- a/libc/math.h +++ b/libc/math.h @@ -312,30 +312,6 @@ void sincosl(long double, long double *, long double *); #define __X87_CONST(OP, VALUE) VALUE #endif -#define fnstsw() __X87_FPU_STATUS("fnstsw") -#define fstsw() __X87_FPU_STATUS("fstsw") -#define __X87_FPU_STATUS(OP) \ - ({ \ - unsigned short fpsr; \ - asm volatile(OP "\t%0" : "=am"(fpsr)); \ - fpsr; \ - }) - -#define finit() __X87_INIT("finit") -#define fninit() __X87_INIT("fninit") -#define __X87_INIT(OP) \ - ({ \ - long double st0, stm; \ - asm volatile(OP \ - : "=t"(st0) \ - : /* no inputs */ \ - : "st(1)", "st(2)", "st(3)", "st(4)", "st(5)", "st(6)", \ - "st(7)", "fpsr"); \ - /* assume(!fpsr && fpcr == FPU_DEFAULT); */ \ - asm("fst\t%0" : "=m"(stm) : "t"(st0)); \ - st0; \ - }) - COSMOPOLITAN_C_END_ #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ #endif /* COSMOPOLITAN_LIBC_MATH_H_ */ diff --git a/libc/nexgen32e/crc32.h b/libc/nexgen32e/crc32.h index f01610d4..186eeb2f 100644 --- a/libc/nexgen32e/crc32.h +++ b/libc/nexgen32e/crc32.h @@ -3,8 +3,6 @@ #if !(__ASSEMBLER__ + __LINKER__ + 0) COSMOPOLITAN_C_START_ -extern const uint32_t kCrc32Tab[256]; - void crc32init(uint32_t[hasatleast 256], uint32_t); uint32_t crc32_z(uint32_t, const void *, size_t); extern uint32_t (*const crc32c)(uint32_t, const void *, size_t) paramsnonnull(); diff --git a/libc/nexgen32e/crc32init.S b/libc/nexgen32e/crc32init.S index 9af6fb9d..435caa00 100644 --- a/libc/nexgen32e/crc32init.S +++ b/libc/nexgen32e/crc32init.S @@ -18,7 +18,6 @@ │ 02110-1301 USA │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/macros.h" -.text.startup / Generates lookup table for computing CRC-32 byte-by-byte. / diff --git a/libc/nexgen32e/crc32z.c b/libc/nexgen32e/crc32z.c index 94280ab2..d6e62b63 100644 --- a/libc/nexgen32e/crc32z.c +++ b/libc/nexgen32e/crc32z.c @@ -21,12 +21,25 @@ #include "libc/nexgen32e/crc32.h" #include "libc/nexgen32e/x86feature.h" +static uint32_t kCrc32Tab[256]; + /** * Computes Phil Katz CRC-32 used by zip/zlib/gzip/etc. + * + * x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x+1 + * 0b100000100110000010001110110110111 + * bitreverse32(0x104c11db7) + * + * @param h is initial value */ uint32_t crc32_z(uint32_t h, const void *data, size_t size) { const unsigned char *p, *pe; + static bool once; size_t skip; + if (!once) { + crc32init(kCrc32Tab, 0xedb88320); + once = true; + } if (data) { h ^= 0xffffffff; if (size >= 64 && X86_HAVE(PCLMUL)) { diff --git a/libc/nt/struct/win32finddata.h b/libc/nt/struct/win32finddata.h index 02842b45..7ed71233 100644 --- a/libc/nt/struct/win32finddata.h +++ b/libc/nt/struct/win32finddata.h @@ -12,8 +12,11 @@ struct NtWin32FindData { uint32_t nFileSizeLow; uint32_t dwReserved0; uint32_t dwReserved1; - char16_t cFileName[PATH_MAX]; + char16_t cFileName[260]; char16_t cAlternateFileName[14]; + uint32_t dwFileType; + uint32_t dwCreatorType; + uint16_t wFinderFlags; }; #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ diff --git a/libc/runtime/destruct.S b/libc/runtime/destruct.S new file mode 100644 index 00000000..befeeccd --- /dev/null +++ b/libc/runtime/destruct.S @@ -0,0 +1,45 @@ +/*-*- 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│ +╞══════════════════════════════════════════════════════════════════════════════╡ +│ Copyright 2020 Justine Alexandra Roberts Tunney │ +│ │ +│ This program is free software; you can redistribute it and/or modify │ +│ it under the terms of the GNU General Public License as published by │ +│ the Free Software Foundation; version 2 of the License. │ +│ │ +│ This program is distributed in the hope that it will be useful, but │ +│ WITHOUT ANY WARRANTY; without even the implied warranty of │ +│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │ +│ General Public License for more details. │ +│ │ +│ You should have received a copy of the GNU General Public License │ +│ along with this program; if not, write to the Free Software │ +│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │ +│ 02110-1301 USA │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/macros.h" +.text.exit +.source __FILE__ + +/ Calls linker registered finalization functions. +/ @note functions are called in reverse order +_destruct: + push %rbp + mov %rsp,%rbp + ezlea __fini_array_start,cx + .weak __fini_array_start + ezlea __fini_array_end,ax + .weak __fini_array_end + cmp %rax,%rcx + je 2f +1: sub $8,%rax + push %rax + push %rcx + call *(%rax) + pop %rcx + pop %rax + cmp %rax,%rcx + jne 1b +2: pop %rbp + ret + .endfn _destruct,globl diff --git a/libc/runtime/exit.S b/libc/runtime/exit.S index 31bc9988..9b91fe19 100644 --- a/libc/runtime/exit.S +++ b/libc/runtime/exit.S @@ -31,6 +31,7 @@ exit: push %rbp push %rdi xor %edi,%edi call __cxa_finalize + call _destruct pop %rdi pop %rdi call _Exit diff --git a/libc/runtime/missioncritical.h b/libc/runtime/missioncritical.h index fe437a70..18ae3ae0 100644 --- a/libc/runtime/missioncritical.h +++ b/libc/runtime/missioncritical.h @@ -136,7 +136,8 @@ } \ while (0) -interruptfn void __print(const void *, size_t); +void __print(const void *, size_t); +void __print_string(const char *); #define LOAD_DEFAULT_RBX() /* disabled for now b/c clang */ #define RESTORE_RBX() /* disabled for now b/c clang */ diff --git a/libc/runtime/print.greg.c b/libc/runtime/print.greg.c index c6d80841..fb29738e 100644 --- a/libc/runtime/print.greg.c +++ b/libc/runtime/print.greg.c @@ -49,9 +49,8 @@ static privileged void __print$nt(const void *data, size_t len) { * @clob nothing except flags * @see PRINT() */ -privileged interruptfn void __print(const void *data, size_t len) { +privileged void __print(const void *data, size_t len) { int64_t ax, ordinal; - LOAD_DEFAULT_RBX(); if (NT_HAVE_IMPORT(__imp_WriteFile)) { __print$nt(data, len); } else { @@ -69,3 +68,9 @@ privileged interruptfn void __print(const void *data, size_t len) { } RESTORE_RBX(); } + +privileged void __print_string(const char *s) { + size_t n = 0; + while (s[n]) ++n; + __print(s, n); +} diff --git a/libc/sock/accept4.c b/libc/sock/accept4.c index a428ba3e..71a54952 100644 --- a/libc/sock/accept4.c +++ b/libc/sock/accept4.c @@ -34,6 +34,8 @@ * @return client fd which needs close(), or -1 w/ errno */ int accept4(int fd, void *out_addr, uint32_t *inout_addrsize, int flags) { + if (!out_addr) return efault(); + if (!inout_addrsize) return efault(); if (!IsWindows()) { return accept4$sysv(fd, out_addr, inout_addrsize, flags); } else if (isfdkind(fd, kFdSocket)) { diff --git a/libc/sock/bind.c b/libc/sock/bind.c index 8fa42a76..a5390433 100644 --- a/libc/sock/bind.c +++ b/libc/sock/bind.c @@ -35,6 +35,7 @@ * @asyncsignalsafe */ int bind(int fd, const void *addr, uint32_t addrsize) { + if (!addr) return efault(); if (addrsize == sizeof(struct sockaddr_in)) { if (!IsWindows()) { if (!IsBsd()) { diff --git a/libc/sock/connect.c b/libc/sock/connect.c index 1c3a6bf3..8a4e7c88 100644 --- a/libc/sock/connect.c +++ b/libc/sock/connect.c @@ -34,6 +34,7 @@ * @asyncsignalsafe */ int connect(int fd, const void *addr, uint32_t addrsize) { + if (!addr) return efault(); if (!IsWindows()) { return connect$sysv(fd, addr, addrsize); } else if (isfdkind(fd, kFdSocket)) { diff --git a/libc/sock/internal.h b/libc/sock/internal.h index d0174d9f..0f4af900 100644 --- a/libc/sock/internal.h +++ b/libc/sock/internal.h @@ -108,7 +108,7 @@ int socket$nt(int, int, int) hidden; size_t iovec2nt(struct iovec$nt[hasatleast 16], const struct iovec *, size_t) hidden; ssize_t sendto$nt(struct Fd *, const struct iovec *, size_t, uint32_t, void *, - uint32_t *) hidden; + uint32_t) hidden; ssize_t recvfrom$nt(struct Fd *, const struct iovec *, size_t, uint32_t, void *, uint32_t *) hidden; diff --git a/libc/sock/sendto-nt.c b/libc/sock/sendto-nt.c index 540e2cc2..99325f05 100644 --- a/libc/sock/sendto-nt.c +++ b/libc/sock/sendto-nt.c @@ -18,8 +18,11 @@ │ 02110-1301 USA │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/assert.h" +#include "libc/calls/calls.h" #include "libc/calls/internal.h" +#include "libc/nt/winsock.h" #include "libc/sock/internal.h" +#include "libc/sysv/consts/fileno.h" /** * Performs send(), sendto(), or writev() on Windows NT. @@ -29,11 +32,11 @@ */ textwindows ssize_t sendto$nt(struct Fd *fd, const struct iovec *iov, size_t iovlen, uint32_t flags, void *opt_in_addr, - uint32_t *in_addrsize) { + uint32_t in_addrsize) { uint32_t sent; struct iovec$nt iovnt[16]; if (WSASendTo(fd->handle, iovnt, iovec2nt(iovnt, iov, iovlen), &sent, flags, - opt_in_addr, *in_addrsize, NULL, NULL) != -1) { + opt_in_addr, in_addrsize, NULL, NULL) != -1) { return sent; } else { return winsockerr(); diff --git a/libc/sock/sendto.c b/libc/sock/sendto.c index 0a75bb5c..561702d2 100644 --- a/libc/sock/sendto.c +++ b/libc/sock/sendto.c @@ -60,7 +60,7 @@ ssize_t sendto(int fd, const void *buf, size_t size, uint32_t flags, } } else if (isfdkind(fd, kFdSocket)) { return sendto$nt(&g_fds.p[fd], (struct iovec[]){{buf, size}}, 1, flags, - opt_addr, &addrsize); + opt_addr, addrsize); } else { return ebadf(); } diff --git a/libc/sock/setsockopt.c b/libc/sock/setsockopt.c index d09bc1c6..424fc51e 100644 --- a/libc/sock/setsockopt.c +++ b/libc/sock/setsockopt.c @@ -51,7 +51,7 @@ static textwindows int setsockopt$nt(struct Fd *fd, int level, int optname, * int yes = 1; * setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &yes, sizeof(yes)); * - * @param level can be SOL_SOCKET, IPPROTO_TCP, etc. + * @param level can be SOL_SOCKET, SOL_IP, SOL_TCP, etc. * @param optname can be SO_{REUSE{PORT,ADDR},KEEPALIVE,etc.} etc. * @return 0 on success, or -1 w/ errno * @error ENOPROTOOPT for unknown (level,optname) @@ -60,6 +60,7 @@ static textwindows int setsockopt$nt(struct Fd *fd, int level, int optname, */ int setsockopt(int fd, int level, int optname, const void *optval, uint32_t optlen) { + if (!optval) return efault(); if (!level || !optname) return enoprotoopt(); /* our sysvconsts definition */ if (optname == -1) return 0; /* our sysvconsts definition */ if (!IsWindows()) { diff --git a/libc/sock/sock.h b/libc/sock/sock.h index 086975e5..eaa62538 100644 --- a/libc/sock/sock.h +++ b/libc/sock/sock.h @@ -61,10 +61,10 @@ int inet_pton(int af, const char *, void *); int parseport(const char *); int socket(int, int, int) nodiscard; -int accept(int, void *, uint32_t *) paramsnonnull() nodiscard; -int accept4(int, void *, uint32_t *, int) paramsnonnull() nodiscard; -int bind(int, const void *, uint32_t) paramsnonnull(); -int connect(int, const void *, uint32_t) paramsnonnull(); +int accept(int, void *, uint32_t *) nodiscard; +int accept4(int, void *, uint32_t *, int) nodiscard; +int bind(int, const void *, uint32_t); +int connect(int, const void *, uint32_t); int socketconnect(const struct addrinfo *, int); int listen(int, int); int shutdown(int, int); @@ -79,7 +79,7 @@ ssize_t readv(int, const struct iovec *, int); ssize_t writev(int, const struct iovec *, int); ssize_t sendfile(int, int, int64_t *, size_t); int getsockopt(int, int, int, void *, uint32_t *) paramsnonnull((5)); -int setsockopt(int, int, int, const void *, uint32_t) paramsnonnull(); +int setsockopt(int, int, int, const void *, uint32_t); int socketpair(int, int, int, int64_t[2]) paramsnonnull(); int poll(struct pollfd *, uint64_t, int32_t) paramsnonnull(); int ppoll(struct pollfd *, uint64_t, const struct timespec *, diff --git a/libc/str/stpcpy.c b/libc/str/stpcpy.c index 1596aeef..ab9dff15 100644 --- a/libc/str/stpcpy.c +++ b/libc/str/stpcpy.c @@ -17,16 +17,20 @@ │ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │ │ 02110-1301 USA │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/limits.h" #include "libc/str/str.h" /** - * Copies string, returning pointer to where copying ended. - * - * @see strcpy(), mempcpy() + * Copies string and advances destination pointer. * @asyncsignalsafe */ char *stpcpy(char *dst, const char *src) { - dst = memccpy(dst, src, '\0', SIZE_MAX); - return dst - 1; + char c; + for (;;) { + c = *src; + *dst = c; + if (!c) break; + ++src; + ++dst; + } + return dst; } diff --git a/libc/str/str.h b/libc/str/str.h index 25987c72..757cc4a4 100644 --- a/libc/str/str.h +++ b/libc/str/str.h @@ -471,8 +471,6 @@ char *_strncpy(char *, const char *, size_t) asm("strncpy") memcpyesque; #else /* hosted/sse2/unbloat */ -#define memmove(DEST, SRC, SIZE) __memcpy((DEST), (SRC), (SIZE)) - #define mempcpy(DEST, SRC, SIZE) \ ({ \ void *Rdi, *Dest = (DEST); \ @@ -513,21 +511,6 @@ char *_strncpy(char *, const char *, size_t) asm("strncpy") memcpyesque; #endif /* hosted/sse2/unbloat */ -#if __STDC_VERSION__ + 0 >= 201112 -#define strlen(s) \ - chooseexpr((typescompatible(typeof(s), const char[]) && \ - isconstant(((const char *)(s))[0])), \ - sizeof(s) - 1, \ - _Generic(*(s), wchar_t \ - : wcslen, char16_t \ - : strlen16, default \ - : _strlen)(s)) -#else -#define strlen(s) \ - chooseexpr(isconstant(s) && typescompatible(typeof(s), const char[]), \ - __builtin_strlen(s), _strlen(s)) -#endif /* C11+ */ - #define pututf16(BUF, SIZE, CH, AWESOME) __pututf16(BUF, SIZE, CH, AWESOME) #define getutf16(BUF, CHPTR) __getutf16(BUF, CHPTR) size_t _strlen(const char *s) asm("strlen") strlenesque; diff --git a/libc/str/str.mk b/libc/str/str.mk index 835edfa3..498c44e0 100644 --- a/libc/str/str.mk +++ b/libc/str/str.mk @@ -42,10 +42,6 @@ $(LIBC_STR_A).pkg: \ $(LIBC_STR_A_OBJS) \ $(foreach x,$(LIBC_STR_A_DIRECTDEPS),$($(x)_A).pkg) -o/$(MODE)/libc/str/lz4cpy.o: \ - OVERRIDE_CFLAGS += \ - $(NO_MAGIC) - LIBC_STR_LIBS = $(foreach x,$(LIBC_STR_ARTIFACTS),$($(x))) LIBC_STR_SRCS = $(foreach x,$(LIBC_STR_ARTIFACTS),$($(x)_SRCS)) LIBC_STR_HDRS = $(foreach x,$(LIBC_STR_ARTIFACTS),$($(x)_HDRS)) diff --git a/libc/sysv/calls/getdents.s b/libc/sysv/calls/getdents.s index 84ca32e9..5f4d5948 100644 --- a/libc/sysv/calls/getdents.s +++ b/libc/sysv/calls/getdents.s @@ -1,2 +1,2 @@ .include "o/libc/sysv/macros.inc" -.scall getdents 0x00630110ffff004e globl hidden +.scall getdents 0x00630110ffff00d9 globl hidden diff --git a/libc/sysv/consts.sh b/libc/sysv/consts.sh index eb319daa..45f209a2 100755 --- a/libc/sysv/consts.sh +++ b/libc/sysv/consts.sh @@ -1313,6 +1313,18 @@ syscon ex EX_CONFIG 78 78 78 78 78 # unix consensus & force NT syscon ex EX__BASE 64 64 64 64 64 # unix consensus & force NT syscon ex EX__MAX 78 78 78 78 78 # unix consensus & force NT +# getdents() constants +# +# group name GNU/Systemd XNU's Not UNIX FreeBSD OpenBSD XENIX Commentary +syscon dt DT_UNKNOWN 0 0 0 0 0 # consensus +syscon dt DT_FIFO 1 1 1 1 1 # unix consensus & faked nt +syscon dt DT_CHR 2 2 2 2 2 # unix consensus & faked nt +syscon dt DT_DIR 4 4 4 4 4 # unix consensus & faked nt +syscon dt DT_BLK 6 6 6 6 6 # unix consensus & faked nt +syscon dt DT_REG 8 8 8 8 8 # unix consensus & faked nt +syscon dt DT_LNK 10 10 10 10 10 # unix consensus & faked nt +syscon dt DT_SOCK 12 12 12 12 12 # unix consensus & faked nt + # msync() flags # # group name GNU/Systemd XNU's Not UNIX FreeBSD OpenBSD XENIX Commentary @@ -1382,6 +1394,10 @@ syscon msg MSG_SYN 0x0400 0 0 0 0 syscon sol SOL_IP 0 0 0 0 0 # consensus syscon sol SOL_SOCKET 1 0xffff 0xffff 0xffff 0xffff # bsd+nt consensus +syscon sol SOL_TCP 6 6 6 6 6 +syscon sol SOL_UDP 17 17 17 17 17 +syscon sol SOL_IPV6 41 41 41 41 41 +syscon sol SOL_ICMPV6 58 58 58 58 0 syscon sol SOL_AAL 265 0 0 0 0 syscon sol SOL_ALG 279 0 0 0 0 syscon sol SOL_ATM 264 0 0 0 0 @@ -1389,8 +1405,6 @@ syscon sol SOL_BLUETOOTH 274 0 0 0 0 syscon sol SOL_CAIF 278 0 0 0 0 syscon sol SOL_DCCP 269 0 0 0 0 syscon sol SOL_DECNET 261 0 0 0 0 -syscon sol SOL_ICMPV6 58 0 0 0 0 -syscon sol SOL_IPV6 41 0 0 0 0 syscon sol SOL_IRDA 266 0 0 0 0 syscon sol SOL_IUCV 277 0 0 0 0 syscon sol SOL_KCM 281 0 0 0 0 @@ -1404,9 +1418,7 @@ syscon sol SOL_PPPOL2TP 273 0 0 0 0 syscon sol SOL_RAW 255 0 0 0 0 syscon sol SOL_RDS 276 0 0 0 0 syscon sol SOL_RXRPC 272 0 0 0 0 -syscon sol SOL_TCP 6 0 0 0 0 syscon sol SOL_TIPC 271 0 0 0 0 -syscon sol SOL_UDP 17 0 0 0 0 syscon sol SOL_X25 262 0 0 0 0 syscon in IN_LOOPBACKNET 127 127 127 127 0 # unix consensus @@ -1656,15 +1668,6 @@ syscon misc BLKSECTGET 0x1267 0 0 0 0 syscon misc BLKSECTSET 0x1266 0 0 0 0 syscon misc BLKSSZGET 0x1268 0 0 0 0 -syscon misc DT_UNKNOWN 0 0 0 0 0 # consensus -syscon misc DT_BLK 6 6 6 6 0 # unix consensus -syscon misc DT_CHR 2 2 2 2 0 # unix consensus -syscon misc DT_DIR 4 4 4 4 0 # unix consensus -syscon misc DT_FIFO 1 1 1 1 0 # unix consensus -syscon misc DT_LNK 10 10 10 10 0 # unix consensus -syscon misc DT_REG 8 8 8 8 0 # unix consensus -syscon misc DT_SOCK 12 12 12 12 0 # unix consensus - syscon misc TH_FIN 1 1 1 1 1 # consensus syscon misc TH_SYN 2 2 2 2 2 # consensus syscon misc TH_RST 4 4 4 4 4 # consensus diff --git a/libc/sysv/consts/DT_BLK.s b/libc/sysv/consts/DT_BLK.s index 9c10b60e..e2d0378f 100644 --- a/libc/sysv/consts/DT_BLK.s +++ b/libc/sysv/consts/DT_BLK.s @@ -1,2 +1,2 @@ .include "libc/sysv/consts/syscon.inc" -.syscon misc DT_BLK 6 6 6 6 0 +.syscon dt DT_BLK 6 6 6 6 6 diff --git a/libc/sysv/consts/DT_CHR.s b/libc/sysv/consts/DT_CHR.s index 3c277524..93f9dafb 100644 --- a/libc/sysv/consts/DT_CHR.s +++ b/libc/sysv/consts/DT_CHR.s @@ -1,2 +1,2 @@ .include "libc/sysv/consts/syscon.inc" -.syscon misc DT_CHR 2 2 2 2 0 +.syscon dt DT_CHR 2 2 2 2 2 diff --git a/libc/sysv/consts/DT_DIR.s b/libc/sysv/consts/DT_DIR.s index 4b34a24a..ae21ce71 100644 --- a/libc/sysv/consts/DT_DIR.s +++ b/libc/sysv/consts/DT_DIR.s @@ -1,2 +1,2 @@ .include "libc/sysv/consts/syscon.inc" -.syscon misc DT_DIR 4 4 4 4 0 +.syscon dt DT_DIR 4 4 4 4 4 diff --git a/libc/sysv/consts/DT_FIFO.s b/libc/sysv/consts/DT_FIFO.s index abb5616f..82b75be5 100644 --- a/libc/sysv/consts/DT_FIFO.s +++ b/libc/sysv/consts/DT_FIFO.s @@ -1,2 +1,2 @@ .include "libc/sysv/consts/syscon.inc" -.syscon misc DT_FIFO 1 1 1 1 0 +.syscon dt DT_FIFO 1 1 1 1 1 diff --git a/libc/sysv/consts/DT_LNK.s b/libc/sysv/consts/DT_LNK.s index caf63f84..4fd62bf1 100644 --- a/libc/sysv/consts/DT_LNK.s +++ b/libc/sysv/consts/DT_LNK.s @@ -1,2 +1,2 @@ .include "libc/sysv/consts/syscon.inc" -.syscon misc DT_LNK 10 10 10 10 0 +.syscon dt DT_LNK 10 10 10 10 10 diff --git a/libc/sysv/consts/DT_REG.s b/libc/sysv/consts/DT_REG.s index 5d9c25aa..98f40415 100644 --- a/libc/sysv/consts/DT_REG.s +++ b/libc/sysv/consts/DT_REG.s @@ -1,2 +1,2 @@ .include "libc/sysv/consts/syscon.inc" -.syscon misc DT_REG 8 8 8 8 0 +.syscon dt DT_REG 8 8 8 8 8 diff --git a/libc/sysv/consts/DT_SOCK.s b/libc/sysv/consts/DT_SOCK.s index fe48b611..e57a7986 100644 --- a/libc/sysv/consts/DT_SOCK.s +++ b/libc/sysv/consts/DT_SOCK.s @@ -1,2 +1,2 @@ .include "libc/sysv/consts/syscon.inc" -.syscon misc DT_SOCK 12 12 12 12 0 +.syscon dt DT_SOCK 12 12 12 12 12 diff --git a/libc/sysv/consts/DT_UNKNOWN.s b/libc/sysv/consts/DT_UNKNOWN.s index 479505d5..4d7374d1 100644 --- a/libc/sysv/consts/DT_UNKNOWN.s +++ b/libc/sysv/consts/DT_UNKNOWN.s @@ -1,2 +1,2 @@ .include "libc/sysv/consts/syscon.inc" -.syscon misc DT_UNKNOWN 0 0 0 0 0 +.syscon dt DT_UNKNOWN 0 0 0 0 0 diff --git a/libc/sysv/consts/SOL_ICMPV6.s b/libc/sysv/consts/SOL_ICMPV6.s index 0d516de3..ca8b9982 100644 --- a/libc/sysv/consts/SOL_ICMPV6.s +++ b/libc/sysv/consts/SOL_ICMPV6.s @@ -1,2 +1,2 @@ .include "libc/sysv/consts/syscon.inc" -.syscon sol SOL_ICMPV6 58 0 0 0 0 +.syscon sol SOL_ICMPV6 58 58 58 58 0 diff --git a/libc/sysv/consts/SOL_IPV6.s b/libc/sysv/consts/SOL_IPV6.s index a464ad56..c9419ceb 100644 --- a/libc/sysv/consts/SOL_IPV6.s +++ b/libc/sysv/consts/SOL_IPV6.s @@ -1,2 +1,2 @@ .include "libc/sysv/consts/syscon.inc" -.syscon sol SOL_IPV6 41 0 0 0 0 +.syscon sol SOL_IPV6 41 41 41 41 41 diff --git a/libc/sysv/consts/SOL_TCP.s b/libc/sysv/consts/SOL_TCP.s index fc721924..db5f02d2 100644 --- a/libc/sysv/consts/SOL_TCP.s +++ b/libc/sysv/consts/SOL_TCP.s @@ -1,2 +1,2 @@ .include "libc/sysv/consts/syscon.inc" -.syscon sol SOL_TCP 6 0 0 0 0 +.syscon sol SOL_TCP 6 6 6 6 6 diff --git a/libc/sysv/consts/SOL_UDP.s b/libc/sysv/consts/SOL_UDP.s index 0c321632..c2d5350d 100644 --- a/libc/sysv/consts/SOL_UDP.s +++ b/libc/sysv/consts/SOL_UDP.s @@ -1,2 +1,2 @@ .include "libc/sysv/consts/syscon.inc" -.syscon sol SOL_UDP 17 0 0 0 0 +.syscon sol SOL_UDP 17 17 17 17 17 diff --git a/libc/sysv/consts/TIOCOUTQ.s b/libc/sysv/consts/TIOCOUTQ.s index 2dffa16a..9fd4d600 100644 --- a/libc/sysv/consts/TIOCOUTQ.s +++ b/libc/sysv/consts/TIOCOUTQ.s @@ -1,2 +1,2 @@ .include "libc/sysv/consts/syscon.inc" -.syscon ioctl TIOCOUTQ 0x5411 0x40047473 0x40047473 0x40047473 -1 +.syscon termios TIOCOUTQ 0x5411 0x40047473 0x40047473 0x40047473 -1 diff --git a/libc/sysv/consts/dt.h b/libc/sysv/consts/dt.h index 8eb049d5..ca40eb74 100644 --- a/libc/sysv/consts/dt.h +++ b/libc/sysv/consts/dt.h @@ -1,28 +1,28 @@ #ifndef COSMOPOLITAN_LIBC_SYSV_CONSTS_DT_H_ #define COSMOPOLITAN_LIBC_SYSV_CONSTS_DT_H_ #include "libc/runtime/symbolic.h" - -#define DT_BLK SYMBOLIC(DT_BLK) -#define DT_CHR SYMBOLIC(DT_CHR) -#define DT_DIR SYMBOLIC(DT_DIR) -#define DT_FIFO SYMBOLIC(DT_FIFO) -#define DT_LNK SYMBOLIC(DT_LNK) -#define DT_REG SYMBOLIC(DT_REG) -#define DT_SOCK SYMBOLIC(DT_SOCK) -#define DT_UNKNOWN SYMBOLIC(DT_UNKNOWN) - #if !(__ASSEMBLER__ + __LINKER__ + 0) COSMOPOLITAN_C_START_ -hidden extern const long DT_BLK; +hidden extern const long DT_UNKNOWN; +hidden extern const long DT_FIFO; hidden extern const long DT_CHR; hidden extern const long DT_DIR; -hidden extern const long DT_FIFO; -hidden extern const long DT_LNK; +hidden extern const long DT_BLK; hidden extern const long DT_REG; +hidden extern const long DT_LNK; hidden extern const long DT_SOCK; -hidden extern const long DT_UNKNOWN; COSMOPOLITAN_C_END_ #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ + +#define DT_UNKNOWN LITERALLY(0) +#define DT_FIFO LITERALLY(1) +#define DT_CHR LITERALLY(2) +#define DT_DIR LITERALLY(4) +#define DT_BLK LITERALLY(6) +#define DT_REG LITERALLY(8) +#define DT_LNK LITERALLY(10) +#define DT_SOCK LITERALLY(12) + #endif /* COSMOPOLITAN_LIBC_SYSV_CONSTS_DT_H_ */ diff --git a/libc/sysv/syscalls.sh b/libc/sysv/syscalls.sh index e6a9c116..16bf9312 100755 --- a/libc/sysv/syscalls.sh +++ b/libc/sysv/syscalls.sh @@ -243,7 +243,7 @@ scall lookup_dcookie 0xffffffffffff00d4 globl scall epoll_create 0xffffffffffff00d5 globl scall epoll_wait 0xffffffffffff00e8 globl scall epoll_ctl 0xffffffffffff00e9 globl -scall getdents 0x00630110ffff004e globl hidden +scall getdents 0x00630110ffff00d9 globl hidden # getdents64 on linux scall set_tid_address 0xffffffffffff00da globl scall restart_syscall 0xffffffffffff00db globl scall semtimedop 0xffffffffffff00dc globl diff --git a/libc/testlib/formatbinaryasglyphs.c b/libc/testlib/formatbinaryasglyphs.c index 076b2ae7..b8b5139e 100644 --- a/libc/testlib/formatbinaryasglyphs.c +++ b/libc/testlib/formatbinaryasglyphs.c @@ -24,7 +24,7 @@ testonly void testlib_formatbinaryasglyphs(const char16_t *want, const void *got, size_t n, char **out_v1, char **out_v2) { - if (n == -1ul) n = strlen(want); + if (n == -1ul) n = strlen16(want); *out_v1 = xasprintf("%`#.*hs", n, want); *out_v2 = xasprintf(" %`'#.*s", n, got); } diff --git a/libc/time/asctime_r.c b/libc/time/asctime_r.c index 047a2045..d67a9ec7 100644 --- a/libc/time/asctime_r.c +++ b/libc/time/asctime_r.c @@ -28,7 +28,7 @@ static unsigned clip(unsigned index, unsigned count) { return index < count ? index : 0; } -char *asctime_r(const struct tm *date, char *buf /*[64]*/) { +char *asctime_r(const struct tm *date, char buf[hasatleast 64]) { (snprintf)(buf, 64, "%.3s %.3s%3d %.2d:%.2d:%.2d %d\n", kWeekdayNameShort[clip(date->tm_wday, 7)], kMonthNameShort[clip(date->tm_mon, 12)], date->tm_mday, diff --git a/libc/time/ctime_r.c b/libc/time/ctime_r.c index 1b543bee..d952e915 100644 --- a/libc/time/ctime_r.c +++ b/libc/time/ctime_r.c @@ -20,7 +20,7 @@ #include "libc/time/struct/tm.h" #include "libc/time/time.h" -char *ctime_r(const int64_t *timep, char *buf /*[64]*/) { +char *ctime_r(const int64_t *timep, char buf[hasatleast 64]) { struct tm date[1]; return asctime_r(localtime_r(timep, date), buf); } diff --git a/libc/time/gettimeofday.c b/libc/time/gettimeofday.c index 6cf9ca64..2c4a4b89 100644 --- a/libc/time/gettimeofday.c +++ b/libc/time/gettimeofday.c @@ -18,7 +18,9 @@ │ 02110-1301 USA │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/internal.h" +#include "libc/calls/struct/timeval.h" #include "libc/dce.h" +#include "libc/time/struct/timezone.h" #include "libc/time/time.h" /** diff --git a/libc/time/localtime.c b/libc/time/localtime.c index 12ee429e..1c98e4b8 100644 --- a/libc/time/localtime.c +++ b/libc/time/localtime.c @@ -1,3 +1,6 @@ +/*-*- mode:c; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│ +│vi: set et ft=c ts=8 tw=8 fenc=utf-8 :vi│ +╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/bits/initializer.h" #include "libc/calls/calls.h" #include "libc/macros.h" @@ -13,7 +16,6 @@ #define ALL_STATE -#define P(x) x #define time_t int64_t #define int_fast64_t int64_t #define int_fast32_t int32_t @@ -25,13 +27,6 @@ #define YEARSPERREPEAT 400 /* years before a Gregorian repeat */ #define TM_ZONE tm_zone #define INITIALIZE(x) x = 0 -static int is_digit(int c) { - return isdigit(c); -} - -asm(".ident\t\"\\n\\n\ -localtime (Public Domain)\\n\ -Credit: Arthur David Olson\""); STATIC_YOINK("usr/share/zoneinfo/GST"); @@ -157,48 +152,37 @@ struct rule { ** Prototypes for static functions. */ -static int32_t detzcode P((const char * codep)); -static time_t detzcode64 P((const char * codep)); -static int differ_by_repeat P((time_t t1, time_t t0)); -static const char * getzname P((const char * strp)); -static const char * getqzname P((const char * strp, const int delim)); -static const char * getnum P((const char * strp, int * nump, int min, - int max)); -static const char * getsecs P((const char * strp, int32_t * secsp)); -static const char * getoffset P((const char * strp, int32_t * offsetp)); -static const char * getrule P((const char * strp, struct rule * rulep)); -static void gmtload P((struct state * sp)); -static struct tm * gmtsub P((const time_t * timep, int32_t offset, - struct tm * tmp)); -static struct tm * localsub P((const time_t * timep, int32_t offset, - struct tm * tmp)); -static int increment_overflow P((int * number, int delta)); -static int leaps_thru_end_of P((int y)); -static int normalize_overflow P((int * tensptr, int * unitsptr, - int base)); -static void settzname P((void)); -static time_t time1 P((struct tm * tmp, - struct tm * (*funcp) P((const time_t *, - int32_t, struct tm *)), - int32_t offset)); -static time_t time2 P((struct tm *tmp, - struct tm * (*funcp) P((const time_t *, - int32_t, struct tm*)), - int32_t offset, int * okayp)); -static time_t time2sub P((struct tm *tmp, - struct tm * (*funcp) P((const time_t *, - int32_t, struct tm*)), - int32_t offset, int * okayp, int do_norm_secs)); -static struct tm * timesub P((const time_t * timep, int32_t offset, - const struct state * sp, struct tm * tmp)); -static int tmcomp P((const struct tm * atmp, - const struct tm * btmp)); -static time_t transtime P((time_t janfirst, int year, - const struct rule * rulep, int32_t offset)); -static int tzload P((const char * name, struct state * sp, - int doextend)); -static int tzparse P((const char * name, struct state * sp, - int lastditch)); +static int32_t detzcode(const char *); +static time_t detzcode64(const char *); +static int differ_by_repeat(time_t, time_t); +static const char * getzname(const char *); +static const char * getqzname(const char *, const int); +static const char * getnum(const char *, int *, int, int); +static const char * getsecs(const char *, int32_t *); +static const char * getoffset(const char *, int32_t *); +static const char * getrule(const char *, struct rule *); +static void gmtload(struct state *); +static struct tm * gmtsub(const time_t *, int32_t, struct tm *); +static struct tm * localsub(const time_t *, int32_t, struct tm *); +static int increment_overflow(int *, int); +static int leaps_thru_end_of(int); +static int normalize_overflow(int *, int *, int); +static void settzname(void); +static time_t time1(struct tm *, struct tm * (*)(const time_t *, + int32_t, struct tm *), + int32_t); +static time_t time2(struct tm *, struct tm *(*)(const time_t *, + int32_t, struct tm *), + int32_t, int *); +static time_t time2sub(struct tm *, struct tm *(*)(const time_t *, + int32_t, struct tm*), + int32_t, int *, int); +static struct tm * timesub(const time_t *, int32_t, + const struct state *, struct tm *); +static int tmcomp(const struct tm *, const struct tm *); +static time_t transtime(time_t, int, const struct rule *, int32_t); +static int tzload(const char *, struct state *, int); +static int tzparse(const char *, struct state *, int); #ifdef ALL_STATE static struct state * lclptr; @@ -242,21 +226,20 @@ INITIALIZER(400, _init_localtime, { static struct tm tm; #ifdef USG_COMPAT -time_t timezone = 0; -int daylight = 0; +time_t timezone; +int daylight; #endif /* defined USG_COMPAT */ #ifdef ALTZONE -time_t altzone = 0; +time_t altzone; #endif /* defined ALTZONE */ static int32_t detzcode(codep) -const char * const codep; + const char * const codep; { register int32_t result; - register int i; - + register int i; result = (codep[0] & 0x80) ? ~0L : 0; for (i = 0; i < 4; ++i) result = ((unsigned)result << 8) | (codep[i] & 0xff); @@ -265,11 +248,10 @@ const char * const codep; static time_t detzcode64(codep) -const char * const codep; + const char * const codep; { - register time_t result; - register int i; - + register time_t result; + register int i; result = (codep[0] & 0x80) ? (~(int_fast64_t) 0) : 0; for (i = 0; i < 8; ++i) result = result * 256 + (codep[i] & 0xff); @@ -277,11 +259,11 @@ const char * const codep; } static void -settzname P((void)) +settzname(void) { - register struct state * const sp = lclptr; - register int i; - + register struct state * sp; + register int i; + sp = lclptr; tzname[0] = wildabbr2; tzname[1] = wildabbr2; #ifdef USG_COMPAT @@ -299,7 +281,6 @@ settzname P((void)) #endif /* defined ALL_STATE */ for (i = 0; i < sp->typecnt; ++i) { register const struct ttinfo * const ttisp = &sp->ttis[i]; - tzname[ttisp->tt_isdst] = &sp->chars[ttisp->tt_abbrind]; #ifdef USG_COMPAT @@ -320,7 +301,6 @@ settzname P((void)) register const struct ttinfo * const ttisp = &sp->ttis[ sp->types[i]]; - tzname[ttisp->tt_isdst] = &sp->chars[ttisp->tt_abbrind]; } @@ -337,7 +317,6 @@ settzname P((void)) for (i = 0; i < sp->typecnt; ++i) { register const struct ttinfo * const ttisp = &sp->ttis[i]; register char * cp = &sp->chars[ttisp->tt_abbrind]; - if (strlen(cp) > TZ_ABBR_MAX_LEN && strcmp(cp, GRANDPARENTED) != 0) *(cp + TZ_ABBR_MAX_LEN) = '\0'; @@ -346,8 +325,8 @@ settzname P((void)) forceinline int differ_by_repeat(t1, t0) -const time_t t1; -const time_t t0; + const time_t t1; + const time_t t0; { if (TYPE_INTEGRAL(time_t) && TYPE_BIT(time_t) - TYPE_SIGNED(time_t) < SECSPERREPEAT_BITS) @@ -355,14 +334,19 @@ const time_t t0; return (t1 - t0) == SECSPERREPEAT; } -/* static int toint(unsigned char *s) { */ -/* return (s[0] << 24) | (s[1] << 16) | (s[2] << 8) | s[3]; */ -/* } */ +forceinline int +cmpstr(l, r) + const char *l, *r; +{ + size_t i = 0; + while (l[i] == r[i] && r[i]) ++i; + return (l[i] & 0xff) - (r[i] & 0xff); +} static int typesequiv(sp, a, b) - int a, b; - const struct state *sp; + int a, b; + const struct state *sp; { int result; if (sp == NULL || @@ -376,7 +360,7 @@ typesequiv(sp, a, b) ap->tt_isdst == bp->tt_isdst && ap->tt_ttisstd == bp->tt_ttisstd && ap->tt_ttisgmt == bp->tt_ttisgmt && - strcmp(&sp->chars[ap->tt_abbrind], + cmpstr(&sp->chars[ap->tt_abbrind], &sp->chars[bp->tt_abbrind]) == 0; } return result; @@ -384,9 +368,9 @@ typesequiv(sp, a, b) static int tzload(name, sp, doextend) -register const char * name; -register struct state * const sp; -register const int doextend; + register const char * name; + register struct state * const sp; + register const int doextend; { register const char * p; register int i; @@ -612,12 +596,12 @@ oops: return -1; } -static const int mon_lengths[2][MONSPERYEAR] = { +static const unsigned char kMonthLengths[2][MONSPERYEAR] = { { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }, { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 } }; -static const int year_lengths[2] = { +static const int kYearLengths[2] = { DAYSPERNYEAR, DAYSPERLYEAR }; @@ -629,13 +613,13 @@ static const int year_lengths[2] = { static const char * getzname(strp) -register const char * strp; + const char * strp; { - register char c; - - while ((c = *strp) != '\0' && !is_digit(c) && c != ',' && c != '-' && - c != '+') - ++strp; + char c; + while ((c = *strp) != '\0' && !isdigit(c) && c != ',' && c != '-' && + c != '+') { + ++strp; + } return strp; } @@ -649,9 +633,11 @@ register const char * strp; */ static const char * -getqzname(register const char *strp, const int delim) +getqzname(strp, delim) + register const char * strp; + const int delim; { - register int c; + register int c; while ((c = *strp) != '\0' && c != delim) ++strp; @@ -667,15 +653,15 @@ getqzname(register const char *strp, const int delim) static const char * getnum(strp, nump, min, max) -register const char * strp; -int * const nump; -const int min; -const int max; + register const char * strp; + int * const nump; + const int min; + const int max; { - register char c; - register int num; + register char c; + register int num; - if (strp == NULL || !is_digit(c = *strp)) + if (strp == NULL || !isdigit(c = *strp)) return NULL; num = 0; do { @@ -683,7 +669,7 @@ const int max; if (num > max) return NULL; /* illegal value */ c = *++strp; - } while (is_digit(c)); + } while (isdigit(c)); if (num < min) return NULL; /* illegal value */ *nump = num; @@ -700,11 +686,10 @@ const int max; static const char * getsecs(strp, secsp) -register const char * strp; -int32_t * const secsp; + register const char * strp; + int32_t * const secsp; { - int num; - + int num; /* ** `HOURSPERDAY * DAYSPERWEEK - 1' allows quasi-Posix rules like ** "M10.4.6/26", which does not conform to Posix, @@ -742,11 +727,10 @@ int32_t * const secsp; static const char * getoffset(strp, offsetp) -register const char * strp; -int32_t * const offsetp; + register const char * strp; + int32_t * const offsetp; { - register int neg = 0; - + register int neg = 0; if (*strp == '-') { neg = 1; ++strp; @@ -769,8 +753,8 @@ int32_t * const offsetp; static const char * getrule(strp, rulep) -const char * strp; -register struct rule * const rulep; + const char * strp; + register struct rule * const rulep; { if (*strp == 'J') { /* @@ -796,7 +780,7 @@ register struct rule * const rulep; if (*strp++ != '.') return NULL; strp = getnum(strp, &rulep->r_day, 0, DAYSPERWEEK - 1); - } else if (is_digit(*strp)) { + } else if (isdigit(*strp)) { /* ** Day of year. */ @@ -865,7 +849,7 @@ const int32_t offset; */ value = janfirst; for (i = 0; i < rulep->r_mon - 1; ++i) - value += mon_lengths[leapyear][i] * SECSPERDAY; + value += kMonthLengths[leapyear][i] * SECSPERDAY; /* ** Use Zeller's Congruence to get day-of-week of first day of @@ -890,7 +874,7 @@ const int32_t offset; d += DAYSPERWEEK; for (i = 1; i < rulep->r_week; ++i) { if (d + DAYSPERWEEK >= - mon_lengths[leapyear][rulep->r_mon - 1]) + kMonthLengths[leapyear][rulep->r_mon - 1]) break; d += DAYSPERWEEK; } @@ -1036,7 +1020,7 @@ tzparse(name, sp, lastditch) } sp->timecnt += 2; newfirst = janfirst; - newfirst += year_lengths[isleap(year)] * + newfirst += kYearLengths[isleap(year)] * SECSPERDAY; if (newfirst <= janfirst) break; @@ -1153,7 +1137,7 @@ tzparse(name, sp, lastditch) static void gmtload(sp) -struct state * const sp; + struct state * const sp; { if (tzload(gmt, sp, TRUE) != 0) (void) tzparse(gmt, sp, TRUE); @@ -1167,7 +1151,7 @@ struct state * const sp; static #endif /* !defined STD_INSPIRED */ void -tzsetwall P((void)) +tzsetwall(void) { if (lcl_is_set < 0) return; @@ -1188,7 +1172,7 @@ tzsetwall P((void)) } void -tzset P((void)) +tzset(void) { register const char * name = NULL; /* static char buf[PROP_VALUE_MAX]; */ @@ -1248,9 +1232,9 @@ tzset P((void)) /*ARGSUSED*/ static struct tm * localsub(timep, offset, tmp) -const time_t * const timep; -const int32_t offset; -struct tm * const tmp; + const time_t * const timep; + const int32_t offset; + struct tm * const tmp; { register struct state * sp; register const struct ttinfo * ttisp; @@ -1340,7 +1324,7 @@ struct tm * const tmp; struct tm * localtime(timep) -const time_t * const timep; + const time_t * const timep; { tzset(); return localsub(timep, 0L, &tm); @@ -1352,8 +1336,8 @@ const time_t * const timep; struct tm * localtime_r(timep, tmp) -const time_t * const timep; -struct tm * tmp; + const time_t * const timep; + struct tm * tmp; { tzset(); return localsub(timep, 0L, tmp); @@ -1365,12 +1349,11 @@ struct tm * tmp; static struct tm * gmtsub(timep, offset, tmp) -const time_t * const timep; -const int32_t offset; -struct tm * const tmp; + const time_t * const timep; + const int32_t offset; + struct tm * const tmp; { register struct tm * result; - if (!gmt_is_set) { gmt_is_set = TRUE; #ifdef ALL_STATE @@ -1404,7 +1387,7 @@ struct tm * const tmp; struct tm * gmtime(timep) -const time_t * const timep; + const time_t * const timep; { return gmtsub(timep, 0L, &tm); } @@ -1415,8 +1398,8 @@ const time_t * const timep; struct tm * gmtime_r(timep, tmp) -const time_t * const timep; -struct tm * tmp; + const time_t * const timep; + struct tm * tmp; { return gmtsub(timep, 0L, tmp); } @@ -1425,8 +1408,8 @@ struct tm * tmp; struct tm * offtime(timep, offset) -const time_t * const timep; -const int32_t offset; + const time_t * const timep; + const int32_t offset; { return gmtsub(timep, offset, &tm); } @@ -1440,7 +1423,7 @@ const int32_t offset; pureconst static int leaps_thru_end_of(y) -register const int y; + register const int y; { return (y >= 0) ? (y / 4 - div100int64(y) + y / 400) : -(leaps_thru_end_of(-(y + 1)) + 1); @@ -1448,20 +1431,20 @@ register const int y; static struct tm * timesub(timep, offset, sp, tmp) -const time_t * const timep; -const int32_t offset; -register const struct state * const sp; -register struct tm * const tmp; + const time_t * const timep; + const int32_t offset; + const struct state * const sp; + struct tm * const tmp; { - register const struct lsinfo * lp; - register time_t tdays; - register int idays; /* unsigned would be so 2003 */ - register long rem; /* ^wut */ + const struct lsinfo * lp; + time_t tdays; + int idays; /* unsigned would be so 2003 */ + long rem; /* ^wut */ int y; - register const int * ip; - register long corr; - register int hit; - register int i; + int leap; + long corr; + int hit; + int i; corr = 0; hit = 0; @@ -1494,7 +1477,7 @@ register struct tm * const tmp; y = EPOCH_YEAR; tdays = *timep / SECSPERDAY; rem = *timep - tdays * SECSPERDAY; - while (tdays < 0 || tdays >= year_lengths[isleap(y)]) { + while (tdays < 0 || tdays >= kYearLengths[isleap(y)]) { int newy; register time_t tdelta; register int idelta; @@ -1538,10 +1521,10 @@ register struct tm * const tmp; while (idays < 0) { if (increment_overflow(&y, -1)) return NULL; - idays += year_lengths[isleap(y)]; + idays += kYearLengths[isleap(y)]; } - while (idays >= year_lengths[isleap(y)]) { - idays -= year_lengths[isleap(y)]; + while (idays >= kYearLengths[isleap(y)]) { + idays -= kYearLengths[isleap(y)]; if (increment_overflow(&y, 1)) return NULL; } @@ -1569,9 +1552,12 @@ register struct tm * const tmp; ** representation. This uses "... ??:59:60" et seq. */ tmp->tm_sec = (int) (rem % SECSPERMIN) + hit; - ip = mon_lengths[isleap(y)]; - for (tmp->tm_mon = 0; idays >= ip[tmp->tm_mon]; ++(tmp->tm_mon)) - idays -= ip[tmp->tm_mon]; + leap = isleap(y); + for (tmp->tm_mon = 0; + idays >= kMonthLengths[leap][tmp->tm_mon]; + ++(tmp->tm_mon)) { + idays -= kMonthLengths[leap][tmp->tm_mon]; + } tmp->tm_mday = (int) (idays + 1); tmp->tm_isdst = 0; #ifdef TM_GMTOFF @@ -1621,11 +1607,10 @@ register struct tm * const tmp; static int increment_overflow(number, delta) -int * number; -int delta; + int * number; + int delta; { int number0; - number0 = *number; *number += delta; return (*number < number0) != (delta < 0); @@ -1633,12 +1618,11 @@ int delta; static int normalize_overflow(tensptr, unitsptr, base) -int * const tensptr; -int * const unitsptr; -const int base; + int * const tensptr; + int * const unitsptr; + const int base; { register int tensdelta; - tensdelta = (*unitsptr >= 0) ? (*unitsptr / base) : (-1 - (-1 - *unitsptr) / base); @@ -1648,11 +1632,10 @@ const int base; static int tmcomp(atmp, btmp) -register const struct tm * const atmp; -register const struct tm * const btmp; + register const struct tm * const atmp; + register const struct tm * const btmp; { register int result; - if ((result = (atmp->tm_year - btmp->tm_year)) == 0 && (result = (atmp->tm_mon - btmp->tm_mon)) == 0 && (result = (atmp->tm_mday - btmp->tm_mday)) == 0 && @@ -1664,11 +1647,11 @@ register const struct tm * const btmp; static time_t time2sub(tmp, funcp, offset, okayp, do_norm_secs) -struct tm * const tmp; -struct tm * (* const funcp) P((const time_t*, int32_t, struct tm*)); -const int32_t offset; -int * const okayp; -const int do_norm_secs; + struct tm * const tmp; + struct tm * (* const funcp)(const time_t*, int32_t, struct tm*); + const int32_t offset; + int * const okayp; + const int do_norm_secs; { register const struct state * sp; register int dir; @@ -1681,7 +1664,6 @@ const int do_norm_secs; time_t newt; time_t t; struct tm yourtm, mytm; - *okayp = FALSE; yourtm = *tmp; if (do_norm_secs) { @@ -1706,16 +1688,16 @@ const int do_norm_secs; if (increment_overflow(&y, -1)) return WRONG; li = y + (1 < yourtm.tm_mon); - yourtm.tm_mday += year_lengths[isleap(li)]; + yourtm.tm_mday += kYearLengths[isleap(li)]; } while (yourtm.tm_mday > DAYSPERLYEAR) { li = y + (1 < yourtm.tm_mon); - yourtm.tm_mday -= year_lengths[isleap(li)]; + yourtm.tm_mday -= kYearLengths[isleap(li)]; if (increment_overflow(&y, 1)) return WRONG; } for ( ; ; ) { - i = mon_lengths[isleap(y)][yourtm.tm_mon]; + i = kMonthLengths[isleap(y)][yourtm.tm_mon]; if (yourtm.tm_mday <= i) break; yourtm.tm_mday -= i; @@ -1852,13 +1834,12 @@ label: static time_t time2(tmp, funcp, offset, okayp) -struct tm * const tmp; -struct tm * (* const funcp) P((const time_t*, int32_t, struct tm*)); -const int32_t offset; -int * const okayp; + struct tm * const tmp; + struct tm * (* const funcp)(const time_t*, int32_t, struct tm*); + const int32_t offset; + int * const okayp; { - time_t t; - + time_t t; /* ** First try without normalization of seconds ** (in case tm_sec contains a value associated with a leap second). @@ -1870,9 +1851,9 @@ int * const okayp; static time_t time1(tmp, funcp, offset) -struct tm * const tmp; -struct tm * (* const funcp) P((const time_t *, int32_t, struct tm *)); -const int32_t offset; + struct tm * const tmp; + struct tm * (* const funcp)(const time_t *, int32_t, struct tm *); + const int32_t offset; { register time_t t; register const struct state * sp; @@ -1883,7 +1864,6 @@ const int32_t offset; int seen[TZ_MAX_TYPES]; int types[TZ_MAX_TYPES]; int okay; - if (tmp->tm_isdst > 1) tmp->tm_isdst = 1; t = time2(tmp, funcp, offset, &okay); @@ -1947,7 +1927,7 @@ const int32_t offset; time_t mktime(tmp) -struct tm * const tmp; + struct tm * const tmp; { tzset(); return time1(tmp, localsub, 0L); @@ -1955,7 +1935,7 @@ struct tm * const tmp; time_t timelocal(tmp) -struct tm * const tmp; + struct tm * const tmp; { tmp->tm_isdst = -1; /* in case it wasn't initialized */ return mktime(tmp); @@ -1963,7 +1943,7 @@ struct tm * const tmp; time_t timegm(tmp) -struct tm * const tmp; + struct tm * const tmp; { tmp->tm_isdst = 0; return time1(tmp, gmtsub, 0L); @@ -1971,8 +1951,8 @@ struct tm * const tmp; time_t timeoff(tmp, offset) -struct tm * const tmp; -const long offset; + struct tm * const tmp; + const long offset; { tmp->tm_isdst = 0; return time1(tmp, gmtsub, offset); @@ -1988,7 +1968,7 @@ const long offset; static long leapcorr(timep) -time_t * timep; + time_t * timep; { register struct state * sp; register struct lsinfo * lp; @@ -2006,7 +1986,7 @@ time_t * timep; pureconst time_t time2posix(t) -time_t t; + time_t t; { tzset(); return t - leapcorr(&t); @@ -2014,7 +1994,7 @@ time_t t; pureconst time_t posix2time(t) -time_t t; + time_t t; { time_t x; time_t y; diff --git a/libc/time/strftime.c b/libc/time/strftime.c index 4cfe17ce..21d43ad1 100644 --- a/libc/time/strftime.c +++ b/libc/time/strftime.c @@ -31,29 +31,28 @@ strftime (BSD-3)\\n\ Copyright 1989 The Regents of the University of California\""); asm(".include \"libc/disclaimer.inc\""); -static char *strftime_add(char *pt, const char *ptlim, const char *str) { - while (pt < ptlim && (*pt = *str++) != '\0') ++pt; - return pt; +static char *strftime_add(char *p, const char *pe, const char *str) { + while (p < pe && (*p = *str++) != '\0') ++p; + return p; } -static char *strftime_conv(char *pt, const char *ptlim, int n, - const char *format) { +static char *strftime_conv(char *p, const char *pe, int n, const char *format) { char buf[INT_STRLEN_MAXIMUM(int) + 1]; (snprintf)(buf, sizeof(buf), format, n); - return strftime_add(pt, ptlim, buf); + return strftime_add(p, pe, buf); } -static char *strftime_secs(char *pt, const char *ptlim, const struct tm *t) { +static char *strftime_secs(char *p, const char *pe, const struct tm *t) { static char buf[INT_STRLEN_MAXIMUM(int) + 1]; struct tm tmp; int64_t s; tmp = *t; /* Make a copy, mktime(3) modifies the tm struct. */ s = mktime(&tmp); (snprintf)(buf, sizeof(buf), "%ld", s); - return strftime_add(pt, ptlim, buf); + return strftime_add(p, pe, buf); } -static char *strftime_timefmt(char *pt, const char *ptlim, const char *format, +static char *strftime_timefmt(char *p, const char *pe, const char *format, const struct tm *t) { int i; long diff; @@ -67,31 +66,31 @@ static char *strftime_timefmt(char *pt, const char *ptlim, const char *format, --format; break; case 'A': - pt = strftime_add(pt, ptlim, - (t->tm_wday < 0 || t->tm_wday > 6) - ? "?" - : kWeekdayName[t->tm_wday]); + p = strftime_add(p, pe, + (t->tm_wday < 0 || t->tm_wday > 6) + ? "?" + : kWeekdayName[t->tm_wday]); continue; case 'a': - pt = strftime_add(pt, ptlim, - (t->tm_wday < 0 || t->tm_wday > 6) - ? "?" - : kWeekdayNameShort[t->tm_wday]); + p = strftime_add(p, pe, + (t->tm_wday < 0 || t->tm_wday > 6) + ? "?" + : kWeekdayNameShort[t->tm_wday]); continue; case 'B': - pt = strftime_add( - pt, ptlim, + p = strftime_add( + p, pe, (t->tm_mon < 0 || t->tm_mon > 11) ? "?" : kMonthName[t->tm_mon]); continue; case 'b': case 'h': - pt = strftime_add(pt, ptlim, - (t->tm_mon < 0 || t->tm_mon > 11) - ? "?" - : kMonthNameShort[t->tm_mon]); + p = strftime_add(p, pe, + (t->tm_mon < 0 || t->tm_mon > 11) + ? "?" + : kMonthNameShort[t->tm_mon]); continue; case 'c': - pt = strftime_timefmt(pt, ptlim, "%D %X", t); + p = strftime_timefmt(p, pe, "%D %X", t); continue; case 'C': /* @@ -101,11 +100,11 @@ static char *strftime_timefmt(char *pt, const char *ptlim, const char *format, ** something completely different. ** (ado, 5/24/93) */ - pt = strftime_conv(pt, ptlim, div100int64(t->tm_year + TM_YEAR_BASE), - "%02d"); + p = strftime_conv(p, pe, div100int64(t->tm_year + TM_YEAR_BASE), + "%02d"); continue; case 'D': - pt = strftime_timefmt(pt, ptlim, "%m/%d/%y", t); + p = strftime_timefmt(p, pe, "%m/%d/%y", t); continue; case 'x': /* @@ -125,10 +124,10 @@ static char *strftime_timefmt(char *pt, const char *ptlim, const char *format, ** ftp.uni-erlangen.de. ** (ado, 5/30/93) */ - pt = strftime_timefmt(pt, ptlim, "%m/%d/%y", t); + p = strftime_timefmt(p, pe, "%m/%d/%y", t); continue; case 'd': - pt = strftime_conv(pt, ptlim, t->tm_mday, "%02d"); + p = strftime_conv(p, pe, t->tm_mday, "%02d"); continue; case 'E': case 'O': @@ -145,17 +144,17 @@ static char *strftime_timefmt(char *pt, const char *ptlim, const char *format, */ goto label; case 'e': - pt = strftime_conv(pt, ptlim, t->tm_mday, "%2d"); + p = strftime_conv(p, pe, t->tm_mday, "%2d"); continue; case 'H': - pt = strftime_conv(pt, ptlim, t->tm_hour, "%02d"); + p = strftime_conv(p, pe, t->tm_hour, "%02d"); continue; case 'I': - pt = strftime_conv( - pt, ptlim, (t->tm_hour % 12) ? (t->tm_hour % 12) : 12, "%02d"); + p = strftime_conv(p, pe, (t->tm_hour % 12) ? (t->tm_hour % 12) : 12, + "%02d"); continue; case 'j': - pt = strftime_conv(pt, ptlim, t->tm_yday + 1, "%03d"); + p = strftime_conv(p, pe, t->tm_yday + 1, "%03d"); continue; case 'k': /* @@ -168,14 +167,14 @@ static char *strftime_timefmt(char *pt, const char *ptlim, const char *format, ** "%l" have been swapped. ** (ado, 5/24/93) */ - pt = strftime_conv(pt, ptlim, t->tm_hour, "%2d"); + p = strftime_conv(p, pe, t->tm_hour, "%2d"); continue; #ifdef KITCHEN_SINK case 'K': /* ** After all this time, still unclaimed! */ - pt = strftime_add(pt, ptlim, "kitchen sink"); + p = strftime_add(p, pe, "kitchen sink"); continue; #endif /* defined KITCHEN_SINK */ case 'l': @@ -188,43 +187,42 @@ static char *strftime_timefmt(char *pt, const char *ptlim, const char *format, ** "%l" have been swapped. ** (ado, 5/24/93) */ - pt = strftime_conv(pt, ptlim, - (t->tm_hour % 12) ? (t->tm_hour % 12) : 12, "%2d"); + p = strftime_conv(p, pe, (t->tm_hour % 12) ? (t->tm_hour % 12) : 12, + "%2d"); continue; case 'M': - pt = strftime_conv(pt, ptlim, t->tm_min, "%02d"); + p = strftime_conv(p, pe, t->tm_min, "%02d"); continue; case 'm': - pt = strftime_conv(pt, ptlim, t->tm_mon + 1, "%02d"); + p = strftime_conv(p, pe, t->tm_mon + 1, "%02d"); continue; case 'n': - pt = strftime_add(pt, ptlim, "\n"); + p = strftime_add(p, pe, "\n"); continue; case 'p': - pt = strftime_add(pt, ptlim, t->tm_hour >= 12 ? "PM" : "AM"); + p = strftime_add(p, pe, t->tm_hour >= 12 ? "PM" : "AM"); continue; case 'R': - pt = strftime_timefmt(pt, ptlim, "%H:%M", t); + p = strftime_timefmt(p, pe, "%H:%M", t); continue; case 'r': - pt = strftime_timefmt(pt, ptlim, "%I:%M:%S %p", t); + p = strftime_timefmt(p, pe, "%I:%M:%S %p", t); continue; case 'S': - pt = strftime_conv(pt, ptlim, t->tm_sec, "%02d"); + p = strftime_conv(p, pe, t->tm_sec, "%02d"); continue; case 's': - pt = strftime_secs(pt, ptlim, t); + p = strftime_secs(p, pe, t); continue; case 'T': case 'X': - pt = strftime_timefmt(pt, ptlim, "%H:%M:%S", t); + p = strftime_timefmt(p, pe, "%H:%M:%S", t); continue; case 't': - pt = strftime_add(pt, ptlim, "\t"); + p = strftime_add(p, pe, "\t"); continue; case 'U': - pt = strftime_conv(pt, ptlim, (t->tm_yday + 7 - t->tm_wday) / 7, - "%02d"); + p = strftime_conv(p, pe, (t->tm_yday + 7 - t->tm_wday) / 7, "%02d"); continue; case 'u': /* @@ -233,8 +231,7 @@ static char *strftime_timefmt(char *pt, const char *ptlim, const char *format, ** [1 (Monday) - 7]" ** (ado, 5/24/93) */ - pt = strftime_conv(pt, ptlim, (t->tm_wday == 0) ? 7 : t->tm_wday, - "%d"); + p = strftime_conv(p, pe, (t->tm_wday == 0) ? 7 : t->tm_wday, "%d"); continue; case 'V': /* @@ -289,7 +286,7 @@ static char *strftime_timefmt(char *pt, const char *ptlim, const char *format, i = 53; #endif /* defined XPG4_1994_04_09 */ } - pt = strftime_conv(pt, ptlim, i, "%02d"); + p = strftime_conv(p, pe, i, "%02d"); continue; case 'v': /* @@ -297,32 +294,30 @@ static char *strftime_timefmt(char *pt, const char *ptlim, const char *format, ** "date as dd-bbb-YYYY" ** (ado, 5/24/93) */ - pt = strftime_timefmt(pt, ptlim, "%e-%b-%Y", t); + p = strftime_timefmt(p, pe, "%e-%b-%Y", t); continue; case 'W': - pt = strftime_conv( - pt, ptlim, - (t->tm_yday + 7 - (t->tm_wday ? (t->tm_wday - 1) : 6)) / 7, + p = strftime_conv( + p, pe, (t->tm_yday + 7 - (t->tm_wday ? (t->tm_wday - 1) : 6)) / 7, "%02d"); continue; case 'w': - pt = strftime_conv(pt, ptlim, t->tm_wday, "%d"); + p = strftime_conv(p, pe, t->tm_wday, "%d"); continue; case 'y': - pt = strftime_conv(pt, ptlim, (t->tm_year + TM_YEAR_BASE) % 100, - "%02d"); + p = strftime_conv(p, pe, (t->tm_year + TM_YEAR_BASE) % 100, "%02d"); continue; case 'Y': - pt = strftime_conv(pt, ptlim, t->tm_year + TM_YEAR_BASE, "%04d"); + p = strftime_conv(p, pe, t->tm_year + TM_YEAR_BASE, "%04d"); continue; case 'Z': if (t->tm_zone) { - pt = strftime_add(pt, ptlim, t->tm_zone); + p = strftime_add(p, pe, t->tm_zone); } else { if (t->tm_isdst == 0 || t->tm_isdst == 1) { - pt = strftime_add(pt, ptlim, tzname[t->tm_isdst]); + p = strftime_add(p, pe, tzname[t->tm_isdst]); } else { - pt = strftime_add(pt, ptlim, "?"); + p = strftime_add(p, pe, "?"); } } continue; @@ -350,10 +345,10 @@ static char *strftime_timefmt(char *pt, const char *ptlim, const char *format, } else { sign = "+"; } - pt = strftime_add(pt, ptlim, sign); + p = strftime_add(p, pe, sign); diff /= SECSPERMIN; diff = (diff / MINSPERHOUR) * 100 + (diff % MINSPERHOUR); - pt = strftime_conv(pt, ptlim, diff, "%04d"); + p = strftime_conv(p, pe, diff, "%04d"); continue; case '%': /* @@ -365,17 +360,33 @@ static char *strftime_timefmt(char *pt, const char *ptlim, const char *format, break; } } - if (pt == ptlim) break; - *pt++ = *format; + if (p >= pe) break; + *p++ = *format; } - return pt; + return p; } -size_t strftime(char *s, size_t maxsize, const char *format, - const struct tm *t) { +/** + * Converts time to string, e.g. + * + * char b[64]; + * int64_t sec; + * struct tm tm; + * time(&sec); + * localtime_r(&sec, &tm); + * strftime(b, sizeof(b), "%Y-%m-%dT%H:%M:%S%z", &tm); // ISO8601 + * strftime(b, sizeof(b), "%a, %d %b %Y %H:%M:%S %Z", &tm); // RFC1123 + * + * @return bytes copied excluding nul, or 0 on error + */ +size_t strftime(char *s, size_t size, const char *f, const struct tm *t) { char *p; - p = strftime_timefmt(s, s + maxsize, format, t); - if (p == s + maxsize) return 0; - *p = '\0'; - return p - s; + p = strftime_timefmt(s, s + size, f, t); + if (p < s + size) { + *p = '\0'; + return p - s; + } else { + s[size - 1] = '\0'; + return 0; + } } diff --git a/libc/time/time.h b/libc/time/time.h index f5092149..6542918e 100644 --- a/libc/time/time.h +++ b/libc/time/time.h @@ -1,15 +1,13 @@ #ifndef COSMOPOLITAN_LIBC_TIME_TIME_H_ #define COSMOPOLITAN_LIBC_TIME_TIME_H_ +#include "libc/calls/struct/itimerval.h" #include "libc/calls/struct/timespec.h" #include "libc/calls/struct/timeval.h" +#include "libc/time/struct/timezone.h" +#include "libc/time/struct/utimbuf.h" #if !(__ASSEMBLER__ + __LINKER__ + 0) COSMOPOLITAN_C_START_ -struct itimerval; -struct timezone; -struct tm; -struct utimbuf; - extern const char kWeekdayNameShort[7][4]; extern const char kWeekdayName[7][10]; extern const char kMonthNameShort[12][4]; @@ -48,9 +46,9 @@ char *strptime(const char *, const char *, struct tm *); size_t strftime(char *, size_t, const char *, const struct tm *) strftimeesque(3); char *asctime(const struct tm *); -char *asctime_r(const struct tm *, char * /*[64]*/); char *ctime(const int64_t *); -char *ctime_r(const int64_t *, char * /*[64]*/); +char *ctime_r(const int64_t *, char[hasatleast 64]); +char *asctime_r(const struct tm *, char[hasatleast 64]); int futimens(int, const struct timespec[2]); int utimensat(int, const char *, const struct timespec[2], int); diff --git a/libc/time/time.mk b/libc/time/time.mk index 6f403d91..ba1d8daf 100644 --- a/libc/time/time.mk +++ b/libc/time/time.mk @@ -25,8 +25,7 @@ LIBC_TIME_A = o/$(MODE)/libc/time/time.a LIBC_TIME_A_FILES := \ $(wildcard libc/time/struct/*) \ $(wildcard libc/time/*) -LIBC_TIME_A_FILES := $(wildcard libc/time/*) -LIBC_TIME_A_HDRS = $(filter %.h,$(LIBC_TIME_A_FILES)) +LIBC_TIME_A_HDRS := $(filter %.h,$(LIBC_TIME_A_FILES)) LIBC_TIME_A_SRCS_S = $(filter %.S,$(LIBC_TIME_A_FILES)) LIBC_TIME_A_SRCS_C = $(filter %.c,$(LIBC_TIME_A_FILES)) diff --git a/libc/tinymath/copysignl.S b/libc/tinymath/copysignl.S index 44e36582..0c2f69b3 100644 --- a/libc/tinymath/copysignl.S +++ b/libc/tinymath/copysignl.S @@ -17,6 +17,7 @@ │ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │ │ 02110-1301 USA │ ╚─────────────────────────────────────────────────────────────────────────────*/ +#include "ape/lib/pc.h" #include "libc/macros.h" .source __FILE__ @@ -29,7 +30,7 @@ tinymath_copysignl: fnstsw fstp %st fldt 16(%rbp) - testb $2,%ah + test $FPU_C1>>8,%ah fabs je 1f fchs diff --git a/libc/tinymath/lroundl.S b/libc/tinymath/lroundl.S index baa2d0bf..f275adc1 100644 --- a/libc/tinymath/lroundl.S +++ b/libc/tinymath/lroundl.S @@ -26,22 +26,14 @@ tinymath_lroundl: mov %rsp,%rbp .profilable push %rax - push %rax fldt 16(%rbp) - fnstcw -8(%rbp) - movzwl -8(%rbp),%edx - and $0b11110011,%dh # RC (Rounding Control) - or $0b00000100,%dh # →-∞ - mov %dx,-4(%rbp) fxam fnstsw fabs test $FPU_C1>>8,%ah fadds .Lhalf(%rip) - fldcw -4(%rbp) - fistpq -16(%rbp) - fldcw -8(%rbp) - mov -16(%rbp),%rax + fisttpq -8(%rbp) + mov -8(%rbp),%rax je 1f neg %rax 1: leave diff --git a/libc/tinymath/round.S b/libc/tinymath/round.S index ca3e7739..4abfe836 100644 --- a/libc/tinymath/round.S +++ b/libc/tinymath/round.S @@ -26,7 +26,7 @@ / / @param 𝑥 is double scalar in low half of %xmm0 / @return double scalar in low half of %xmm0 -/ @define round(𝑥) = copysign(floor(fabs(𝑥)+.5),𝑥) +/ @define round(𝑥) = copysign(trunc(fabs(𝑥)+.5),𝑥) / round(𝑥) = trunc(𝑥+copysign(.5,𝑥)) tinymath_round: #if !X86_NEED(SSE4_2) diff --git a/libc/tinymath/roundl.S b/libc/tinymath/roundl.S index 4f4413da..faaf8e12 100644 --- a/libc/tinymath/roundl.S +++ b/libc/tinymath/roundl.S @@ -30,19 +30,17 @@ tinymath_roundl: .profilable push %rax fldt 16(%rbp) + fnstcw -6(%rbp) fnstcw -8(%rbp) - movzwl -8(%rbp),%edx - and $0b11110011,%dh # RC (Rounding Control) - or $0b00000100,%dh # →-∞ a.k.a. floor() - mov %dx,-4(%rbp) + orb $0b00001100,-7(%rbp) # RC = →0 fxam # C1 is set to sign bit fnstsw fabs test $FPU_C1>>8,%ah fadds .Lhalf(%rip) - fldcw -4(%rbp) - frndint fldcw -8(%rbp) + frndint + fldcw -6(%rbp) je 1f fchs 1: leave diff --git a/net/http/gethttpheader.c b/net/http/gethttpheader.c index 882f89b8..7f7e9829 100644 --- a/net/http/gethttpheader.c +++ b/net/http/gethttpheader.c @@ -21,13 +21,13 @@ #include "net/http/http.h" /** - * Returns small number for HTTP header, or 0 if not found. + * Returns small number for HTTP header, or -1 if not found. */ -enum HttpHeader gethttpheader(const char *str, unsigned int len) { +int GetHttpHeader(const char *str, size_t len) { const struct HttpHeaderSlot *slot; - if ((slot = in_word_set(str, len))) { + if ((slot = LookupHttpHeader(str, len))) { return slot->code; } else { - return 0; + return -1; } } diff --git a/net/http/gethttpheader.gperf b/net/http/gethttpheader.gperf index e60bb2ba..b2d504d5 100644 --- a/net/http/gethttpheader.gperf +++ b/net/http/gethttpheader.gperf @@ -6,57 +6,57 @@ %compare-strncmp %ignore-case %language=ANSI-C -%pic %readonly-tables %struct-type -struct HttpHeaderSlot { unsigned char name; unsigned char code; }; +%define lookup-function-name LookupHttpHeader +struct HttpHeaderSlot { char *name; char code; }; %% -Accept, kHttpAccept -Accept-Charset, kHttpAcceptCharset -Accept-Encoding, kHttpAcceptEncoding -Accept-Language, kHttpAcceptLanguage -Age, kHttpAge -Allow, kHttpAllow -Authorization, kHttpAuthorization -Cache-Control, kHttpCacheControl -Chunked, kHttpChunked -Close, kHttpClose -Connection, kHttpConnection -Content-Base, kHttpContentBase -Content-Encoding, kHttpContentEncoding -Content-Language, kHttpContentLanguage -Content-Length, kHttpContentLength -Content-Location, kHttpContentLocation -Content-Md5, kHttpContentMd5 -Content-Range, kHttpContentRange -Content-Type, kHttpContentType -Date, kHttpDate -Etag, kHttpEtag -Expires, kHttpExpires -From, kHttpFrom -Host, kHttpHost -If-Match, kHttpIfMatch -If-Modified-Since, kHttpIfModifiedSince -If-None-Match, kHttpIfNoneMatch -If-Range, kHttpIfRange -If-Unmodified-Since, kHttpIfUnmodifiedSince -Keep-Alive, kHttpKeepAlive -Max-Forwards, kHttpMaxForwards -Pragma, kHttpPragma -Proxy-Authenticate, kHttpProxyAuthenticate -Proxy-Authorization, kHttpProxyAuthorization -Proxy-Connection, kHttpProxyConnection -Range, kHttpRange -Referer, kHttpReferer -Transfer-Encoding, kHttpTransferEncoding -Upgrade, kHttpUpgrade -User-Agent, kHttpUserAgent -Via, kHttpVia -Location, kHttpLocation -Public, kHttpPublic -Retry-After, kHttpRetryAfter -Server, kHttpServer -Vary, kHttpVary -Warning, kHttpWarning -WWW-Authenticate, kHttpWwwAuthenticate -Last-Modified, kHttpLastModified +Accept, kHttpAccept +Accept-Charset, kHttpAcceptCharset +Accept-Encoding, kHttpAcceptEncoding +Accept-Language, kHttpAcceptLanguage +Age, kHttpAge +Allow, kHttpAllow +Authorization, kHttpAuthorization +Cache-Control, kHttpCacheControl +Chunked, kHttpChunked +Close, kHttpClose +Connection, kHttpConnection +Content-Base, kHttpContentBase +Content-Encoding, kHttpContentEncoding +Content-Language, kHttpContentLanguage +Content-Length, kHttpContentLength +Content-Location, kHttpContentLocation +Content-Md5, kHttpContentMd5 +Content-Range, kHttpContentRange +Content-Type, kHttpContentType +Date, kHttpDate +Etag, kHttpEtag +Expires, kHttpExpires +From, kHttpFrom +Host, kHttpHost +If-Match, kHttpIfMatch +If-Modified-Since, kHttpIfModifiedSince +If-None-Match, kHttpIfNoneMatch +If-Range, kHttpIfRange +If-Unmodified-Since, kHttpIfUnmodifiedSince +Keep-Alive, kHttpKeepAlive +Max-Forwards, kHttpMaxForwards +Pragma, kHttpPragma +Proxy-Authenticate, kHttpProxyAuthenticate +Proxy-Authorization, kHttpProxyAuthorization +Proxy-Connection, kHttpProxyConnection +Range, kHttpRange +Referer, kHttpReferer +Transfer-Encoding, kHttpTransferEncoding +Upgrade, kHttpUpgrade +User-Agent, kHttpUserAgent +Via, kHttpVia +Location, kHttpLocation +Public, kHttpPublic +Retry-After, kHttpRetryAfter +Server, kHttpServer +Vary, kHttpVary +Warning, kHttpWarning +WWW-Authenticate, kHttpWwwAuthenticate +Last-Modified, kHttpLastModified diff --git a/net/http/gethttpheader.inc b/net/http/gethttpheader.inc index b55752b6..890efdfe 100644 --- a/net/http/gethttpheader.inc +++ b/net/http/gethttpheader.inc @@ -1,5 +1,5 @@ -/* ANSI-C code produced by gperf version 3.0.4 */ -/* Command-line: gperf net/http/gethttpheader.gperf */ +/* ANSI-C code produced by gperf version 3.1 */ +/* Command-line: gperf gethttpheader.gperf */ /* Computed positions: -k'1,9,$' */ #if !((' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \ @@ -26,16 +26,16 @@ && ('w' == 119) && ('x' == 120) && ('y' == 121) && ('z' == 122) \ && ('{' == 123) && ('|' == 124) && ('}' == 125) && ('~' == 126)) /* The character set is not based on ISO-646. */ -#error "gperf generated tables don't work with this execution character set. Please report a bug to ." +#error "gperf generated tables don't work with this execution character set. Please report a bug to ." #endif -#line 1 "net/http/gethttpheader.gperf" +#line 1 "gethttpheader.gperf" #include "libc/str/str.h" #include "net/http/http.h" #define GPERF_DOWNCASE -#line 12 "net/http/gethttpheader.gperf" -struct HttpHeaderSlot { unsigned char name; unsigned char code; }; +#line 12 "gethttpheader.gperf" +struct HttpHeaderSlot { char *name; char code; }; #define TOTAL_KEYWORDS 49 #define MIN_WORD_LENGTH 3 @@ -72,7 +72,7 @@ static unsigned char gperf_downcase[256] = #ifndef GPERF_CASE_STRNCMP #define GPERF_CASE_STRNCMP 1 static int -gperf_case_strncmp (register const char *s1, register const char *s2, register unsigned int n) +gperf_case_strncmp (register const char *s1, register const char *s2, register size_t n) { for (; n > 0;) { @@ -97,7 +97,7 @@ inline #endif #endif static unsigned int -hash (register const char *str, register unsigned int len) +hash (register const char *str, register size_t len) { static const unsigned char asso_values[] = { @@ -128,7 +128,7 @@ hash (register const char *str, register unsigned int len) 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73 }; - register int hval = len; + register unsigned int hval = len; switch (hval) { @@ -149,248 +149,133 @@ hash (register const char *str, register unsigned int len) return hval + asso_values[(unsigned char)str[len - 1]]; } -struct stringpool_t - { - char stringpool_str5[sizeof("Close")]; - char stringpool_str7[sizeof("Upgrade")]; - char stringpool_str8[sizeof("Age")]; - char stringpool_str9[sizeof("From")]; - char stringpool_str10[sizeof("Range")]; - char stringpool_str11[sizeof("Accept")]; - char stringpool_str12[sizeof("Content-Type")]; - char stringpool_str13[sizeof("If-Range")]; - char stringpool_str15[sizeof("User-Agent")]; - char stringpool_str16[sizeof("Content-Md5")]; - char stringpool_str17[sizeof("Referer")]; - char stringpool_str18[sizeof("Content-Range")]; - char stringpool_str19[sizeof("Date")]; - char stringpool_str20[sizeof("Connection")]; - char stringpool_str21[sizeof("Retry-After")]; - char stringpool_str22[sizeof("Chunked")]; - char stringpool_str23[sizeof("Via")]; - char stringpool_str24[sizeof("Host")]; - char stringpool_str25[sizeof("Accept-Language")]; - char stringpool_str26[sizeof("Public")]; - char stringpool_str27[sizeof("If-Modified-Since")]; - char stringpool_str28[sizeof("Authorization")]; - char stringpool_str29[sizeof("If-Unmodified-Since")]; - char stringpool_str30[sizeof("Allow")]; - char stringpool_str31[sizeof("Pragma")]; - char stringpool_str32[sizeof("Content-Base")]; - char stringpool_str33[sizeof("If-Match")]; - char stringpool_str34[sizeof("Vary")]; - char stringpool_str35[sizeof("Keep-Alive")]; - char stringpool_str36[sizeof("WWW-Authenticate")]; - char stringpool_str37[sizeof("Expires")]; - char stringpool_str38[sizeof("Proxy-Authenticate")]; - char stringpool_str39[sizeof("Accept-Charset")]; - char stringpool_str41[sizeof("Server")]; - char stringpool_str43[sizeof("If-None-Match")]; - char stringpool_str44[sizeof("Proxy-Authorization")]; - char stringpool_str46[sizeof("Proxy-Connection")]; - char stringpool_str48[sizeof("Location")]; - char stringpool_str49[sizeof("Etag")]; - char stringpool_str51[sizeof("Content-Language")]; - char stringpool_str52[sizeof("Max-Forwards")]; - char stringpool_str53[sizeof("Cache-Control")]; - char stringpool_str56[sizeof("Content-Location")]; - char stringpool_str61[sizeof("Content-Encoding")]; - char stringpool_str62[sizeof("Transfer-Encoding")]; - char stringpool_str68[sizeof("Last-Modified")]; - char stringpool_str69[sizeof("Content-Length")]; - char stringpool_str70[sizeof("Accept-Encoding")]; - char stringpool_str72[sizeof("Warning")]; - }; -static const struct stringpool_t stringpool_contents = - { - "Close", - "Upgrade", - "Age", - "From", - "Range", - "Accept", - "Content-Type", - "If-Range", - "User-Agent", - "Content-Md5", - "Referer", - "Content-Range", - "Date", - "Connection", - "Retry-After", - "Chunked", - "Via", - "Host", - "Accept-Language", - "Public", - "If-Modified-Since", - "Authorization", - "If-Unmodified-Since", - "Allow", - "Pragma", - "Content-Base", - "If-Match", - "Vary", - "Keep-Alive", - "WWW-Authenticate", - "Expires", - "Proxy-Authenticate", - "Accept-Charset", - "Server", - "If-None-Match", - "Proxy-Authorization", - "Proxy-Connection", - "Location", - "Etag", - "Content-Language", - "Max-Forwards", - "Cache-Control", - "Content-Location", - "Content-Encoding", - "Transfer-Encoding", - "Last-Modified", - "Content-Length", - "Accept-Encoding", - "Warning" - }; -#define stringpool ((const char *) &stringpool_contents) -#ifdef __GNUC__ -__inline -#if defined __GNUC_STDC_INLINE__ || defined __GNUC_GNU_INLINE__ -__attribute__ ((__gnu_inline__)) -#endif -#endif const struct HttpHeaderSlot * -in_word_set (register const char *str, register unsigned int len) +LookupHttpHeader (register const char *str, register size_t len) { static const struct HttpHeaderSlot wordlist[] = { - {-1}, {-1}, {-1}, {-1}, {-1}, -#line 23 "net/http/gethttpheader.gperf" - {(int)(long)&((struct stringpool_t *)0)->stringpool_str5, kHttpClose }, - {-1}, -#line 52 "net/http/gethttpheader.gperf" - {(int)(long)&((struct stringpool_t *)0)->stringpool_str7, kHttpUpgrade }, -#line 18 "net/http/gethttpheader.gperf" - {(int)(long)&((struct stringpool_t *)0)->stringpool_str8, kHttpAge }, -#line 36 "net/http/gethttpheader.gperf" - {(int)(long)&((struct stringpool_t *)0)->stringpool_str9, kHttpFrom }, -#line 49 "net/http/gethttpheader.gperf" - {(int)(long)&((struct stringpool_t *)0)->stringpool_str10, kHttpRange }, -#line 14 "net/http/gethttpheader.gperf" - {(int)(long)&((struct stringpool_t *)0)->stringpool_str11, kHttpAccept }, -#line 32 "net/http/gethttpheader.gperf" - {(int)(long)&((struct stringpool_t *)0)->stringpool_str12, kHttpContentType }, -#line 41 "net/http/gethttpheader.gperf" - {(int)(long)&((struct stringpool_t *)0)->stringpool_str13, kHttpIfRange }, - {-1}, -#line 53 "net/http/gethttpheader.gperf" - {(int)(long)&((struct stringpool_t *)0)->stringpool_str15, kHttpUserAgent }, -#line 30 "net/http/gethttpheader.gperf" - {(int)(long)&((struct stringpool_t *)0)->stringpool_str16, kHttpContentMd5 }, -#line 50 "net/http/gethttpheader.gperf" - {(int)(long)&((struct stringpool_t *)0)->stringpool_str17, kHttpReferer }, -#line 31 "net/http/gethttpheader.gperf" - {(int)(long)&((struct stringpool_t *)0)->stringpool_str18, kHttpContentRange }, -#line 33 "net/http/gethttpheader.gperf" - {(int)(long)&((struct stringpool_t *)0)->stringpool_str19, kHttpDate }, -#line 24 "net/http/gethttpheader.gperf" - {(int)(long)&((struct stringpool_t *)0)->stringpool_str20, kHttpConnection }, -#line 57 "net/http/gethttpheader.gperf" - {(int)(long)&((struct stringpool_t *)0)->stringpool_str21, kHttpRetryAfter }, -#line 22 "net/http/gethttpheader.gperf" - {(int)(long)&((struct stringpool_t *)0)->stringpool_str22, kHttpChunked }, -#line 54 "net/http/gethttpheader.gperf" - {(int)(long)&((struct stringpool_t *)0)->stringpool_str23, kHttpVia }, -#line 37 "net/http/gethttpheader.gperf" - {(int)(long)&((struct stringpool_t *)0)->stringpool_str24, kHttpHost }, -#line 17 "net/http/gethttpheader.gperf" - {(int)(long)&((struct stringpool_t *)0)->stringpool_str25, kHttpAcceptLanguage }, -#line 56 "net/http/gethttpheader.gperf" - {(int)(long)&((struct stringpool_t *)0)->stringpool_str26, kHttpPublic }, -#line 39 "net/http/gethttpheader.gperf" - {(int)(long)&((struct stringpool_t *)0)->stringpool_str27, kHttpIfModifiedSince }, -#line 20 "net/http/gethttpheader.gperf" - {(int)(long)&((struct stringpool_t *)0)->stringpool_str28, kHttpAuthorization }, -#line 42 "net/http/gethttpheader.gperf" - {(int)(long)&((struct stringpool_t *)0)->stringpool_str29, kHttpIfUnmodifiedSince }, -#line 19 "net/http/gethttpheader.gperf" - {(int)(long)&((struct stringpool_t *)0)->stringpool_str30, kHttpAllow }, -#line 45 "net/http/gethttpheader.gperf" - {(int)(long)&((struct stringpool_t *)0)->stringpool_str31, kHttpPragma }, -#line 25 "net/http/gethttpheader.gperf" - {(int)(long)&((struct stringpool_t *)0)->stringpool_str32, kHttpContentBase }, -#line 38 "net/http/gethttpheader.gperf" - {(int)(long)&((struct stringpool_t *)0)->stringpool_str33, kHttpIfMatch }, -#line 59 "net/http/gethttpheader.gperf" - {(int)(long)&((struct stringpool_t *)0)->stringpool_str34, kHttpVary }, -#line 43 "net/http/gethttpheader.gperf" - {(int)(long)&((struct stringpool_t *)0)->stringpool_str35, kHttpKeepAlive }, -#line 61 "net/http/gethttpheader.gperf" - {(int)(long)&((struct stringpool_t *)0)->stringpool_str36, kHttpWwwAuthenticate }, -#line 35 "net/http/gethttpheader.gperf" - {(int)(long)&((struct stringpool_t *)0)->stringpool_str37, kHttpExpires }, -#line 46 "net/http/gethttpheader.gperf" - {(int)(long)&((struct stringpool_t *)0)->stringpool_str38, kHttpProxyAuthenticate }, -#line 15 "net/http/gethttpheader.gperf" - {(int)(long)&((struct stringpool_t *)0)->stringpool_str39, kHttpAcceptCharset }, - {-1}, -#line 58 "net/http/gethttpheader.gperf" - {(int)(long)&((struct stringpool_t *)0)->stringpool_str41, kHttpServer }, - {-1}, -#line 40 "net/http/gethttpheader.gperf" - {(int)(long)&((struct stringpool_t *)0)->stringpool_str43, kHttpIfNoneMatch }, -#line 47 "net/http/gethttpheader.gperf" - {(int)(long)&((struct stringpool_t *)0)->stringpool_str44, kHttpProxyAuthorization }, - {-1}, -#line 48 "net/http/gethttpheader.gperf" - {(int)(long)&((struct stringpool_t *)0)->stringpool_str46, kHttpProxyConnection }, - {-1}, -#line 55 "net/http/gethttpheader.gperf" - {(int)(long)&((struct stringpool_t *)0)->stringpool_str48, kHttpLocation }, -#line 34 "net/http/gethttpheader.gperf" - {(int)(long)&((struct stringpool_t *)0)->stringpool_str49, kHttpEtag }, - {-1}, -#line 27 "net/http/gethttpheader.gperf" - {(int)(long)&((struct stringpool_t *)0)->stringpool_str51, kHttpContentLanguage }, -#line 44 "net/http/gethttpheader.gperf" - {(int)(long)&((struct stringpool_t *)0)->stringpool_str52, kHttpMaxForwards }, -#line 21 "net/http/gethttpheader.gperf" - {(int)(long)&((struct stringpool_t *)0)->stringpool_str53, kHttpCacheControl }, - {-1}, {-1}, -#line 29 "net/http/gethttpheader.gperf" - {(int)(long)&((struct stringpool_t *)0)->stringpool_str56, kHttpContentLocation }, - {-1}, {-1}, {-1}, {-1}, -#line 26 "net/http/gethttpheader.gperf" - {(int)(long)&((struct stringpool_t *)0)->stringpool_str61, kHttpContentEncoding }, -#line 51 "net/http/gethttpheader.gperf" - {(int)(long)&((struct stringpool_t *)0)->stringpool_str62, kHttpTransferEncoding }, - {-1}, {-1}, {-1}, {-1}, {-1}, -#line 62 "net/http/gethttpheader.gperf" - {(int)(long)&((struct stringpool_t *)0)->stringpool_str68, kHttpLastModified }, -#line 28 "net/http/gethttpheader.gperf" - {(int)(long)&((struct stringpool_t *)0)->stringpool_str69, kHttpContentLength }, -#line 16 "net/http/gethttpheader.gperf" - {(int)(long)&((struct stringpool_t *)0)->stringpool_str70, kHttpAcceptEncoding }, - {-1}, -#line 60 "net/http/gethttpheader.gperf" - {(int)(long)&((struct stringpool_t *)0)->stringpool_str72, kHttpWarning } + {""}, {""}, {""}, {""}, {""}, +#line 23 "gethttpheader.gperf" + {"Close", kHttpClose}, + {""}, +#line 52 "gethttpheader.gperf" + {"Upgrade", kHttpUpgrade}, +#line 18 "gethttpheader.gperf" + {"Age", kHttpAge}, +#line 36 "gethttpheader.gperf" + {"From", kHttpFrom}, +#line 49 "gethttpheader.gperf" + {"Range", kHttpRange}, +#line 14 "gethttpheader.gperf" + {"Accept", kHttpAccept}, +#line 32 "gethttpheader.gperf" + {"Content-Type", kHttpContentType}, +#line 41 "gethttpheader.gperf" + {"If-Range", kHttpIfRange}, + {""}, +#line 53 "gethttpheader.gperf" + {"User-Agent", kHttpUserAgent}, +#line 30 "gethttpheader.gperf" + {"Content-Md5", kHttpContentMd5}, +#line 50 "gethttpheader.gperf" + {"Referer", kHttpReferer}, +#line 31 "gethttpheader.gperf" + {"Content-Range", kHttpContentRange}, +#line 33 "gethttpheader.gperf" + {"Date", kHttpDate}, +#line 24 "gethttpheader.gperf" + {"Connection", kHttpConnection}, +#line 57 "gethttpheader.gperf" + {"Retry-After", kHttpRetryAfter}, +#line 22 "gethttpheader.gperf" + {"Chunked", kHttpChunked}, +#line 54 "gethttpheader.gperf" + {"Via", kHttpVia}, +#line 37 "gethttpheader.gperf" + {"Host", kHttpHost}, +#line 17 "gethttpheader.gperf" + {"Accept-Language", kHttpAcceptLanguage}, +#line 56 "gethttpheader.gperf" + {"Public", kHttpPublic}, +#line 39 "gethttpheader.gperf" + {"If-Modified-Since", kHttpIfModifiedSince}, +#line 20 "gethttpheader.gperf" + {"Authorization", kHttpAuthorization}, +#line 42 "gethttpheader.gperf" + {"If-Unmodified-Since", kHttpIfUnmodifiedSince}, +#line 19 "gethttpheader.gperf" + {"Allow", kHttpAllow}, +#line 45 "gethttpheader.gperf" + {"Pragma", kHttpPragma}, +#line 25 "gethttpheader.gperf" + {"Content-Base", kHttpContentBase}, +#line 38 "gethttpheader.gperf" + {"If-Match", kHttpIfMatch}, +#line 59 "gethttpheader.gperf" + {"Vary", kHttpVary}, +#line 43 "gethttpheader.gperf" + {"Keep-Alive", kHttpKeepAlive}, +#line 61 "gethttpheader.gperf" + {"WWW-Authenticate", kHttpWwwAuthenticate}, +#line 35 "gethttpheader.gperf" + {"Expires", kHttpExpires}, +#line 46 "gethttpheader.gperf" + {"Proxy-Authenticate", kHttpProxyAuthenticate}, +#line 15 "gethttpheader.gperf" + {"Accept-Charset", kHttpAcceptCharset}, + {""}, +#line 58 "gethttpheader.gperf" + {"Server", kHttpServer}, + {""}, +#line 40 "gethttpheader.gperf" + {"If-None-Match", kHttpIfNoneMatch}, +#line 47 "gethttpheader.gperf" + {"Proxy-Authorization", kHttpProxyAuthorization}, + {""}, +#line 48 "gethttpheader.gperf" + {"Proxy-Connection", kHttpProxyConnection}, + {""}, +#line 55 "gethttpheader.gperf" + {"Location", kHttpLocation}, +#line 34 "gethttpheader.gperf" + {"Etag", kHttpEtag}, + {""}, +#line 27 "gethttpheader.gperf" + {"Content-Language", kHttpContentLanguage}, +#line 44 "gethttpheader.gperf" + {"Max-Forwards", kHttpMaxForwards}, +#line 21 "gethttpheader.gperf" + {"Cache-Control", kHttpCacheControl}, + {""}, {""}, +#line 29 "gethttpheader.gperf" + {"Content-Location", kHttpContentLocation}, + {""}, {""}, {""}, {""}, +#line 26 "gethttpheader.gperf" + {"Content-Encoding", kHttpContentEncoding}, +#line 51 "gethttpheader.gperf" + {"Transfer-Encoding", kHttpTransferEncoding}, + {""}, {""}, {""}, {""}, {""}, +#line 62 "gethttpheader.gperf" + {"Last-Modified", kHttpLastModified}, +#line 28 "gethttpheader.gperf" + {"Content-Length", kHttpContentLength}, +#line 16 "gethttpheader.gperf" + {"Accept-Encoding", kHttpAcceptEncoding}, + {""}, +#line 60 "gethttpheader.gperf" + {"Warning", kHttpWarning} }; if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH) { - register int key = hash (str, len); + register unsigned int key = hash (str, len); - if (key <= MAX_HASH_VALUE && key >= 0) + if (key <= MAX_HASH_VALUE) { - register int o = wordlist[key].name; - if (o >= 0) - { - register const char *s = o + stringpool; + register const char *s = wordlist[key].name; - if ((((unsigned char)*str ^ (unsigned char)*s) & ~32) == 0 && !gperf_case_strncmp (str, s, len) && s[len] == '\0') - return &wordlist[key]; - } + if ((((unsigned char)*str ^ (unsigned char)*s) & ~32) == 0 && !gperf_case_strncmp (str, s, len) && s[len] == '\0') + return &wordlist[key]; } } return 0; diff --git a/net/http/clearhttprequest.c b/net/http/gethttpmethod.c similarity index 87% rename from net/http/clearhttprequest.c rename to net/http/gethttpmethod.c index 10798e27..318b785a 100644 --- a/net/http/clearhttprequest.c +++ b/net/http/gethttpmethod.c @@ -17,15 +17,17 @@ │ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │ │ 02110-1301 USA │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/alg/alg.h" -#include "libc/bits/bits.h" -#include "libc/bits/pushpop.h" +#include "net/http/gethttpmethod.inc" #include "net/http/http.h" -void clearhttprequest(struct HttpRequest *req) { - req->uri.i = pushpop(0); - req->method.i = pushpop(0); - req->version.i = pushpop(0); - req->scratch.i = pushpop(0); - critbit0_clear(&req->headers); +/** + * Returns small number for HTTP method, or -1 if not found. + */ +int GetHttpMethod(const char *str, size_t len) { + const struct HttpMethodSlot *slot; + if ((slot = LookupHttpMethod(str, len))) { + return slot->code; + } else { + return -1; + } } diff --git a/net/http/gethttpmethod.gperf b/net/http/gethttpmethod.gperf new file mode 100644 index 00000000..2d2caa60 --- /dev/null +++ b/net/http/gethttpmethod.gperf @@ -0,0 +1,36 @@ +%{ +#include "libc/str/str.h" +#include "net/http/http.h" +#define GPERF_DOWNCASE +%} +%compare-strncmp +%ignore-case +%language=ANSI-C +%readonly-tables +%struct-type +%define lookup-function-name LookupHttpMethod +struct HttpMethodSlot { char *name; char code; }; +%% +DELETE, kHttpDelete +GET, kHttpGet +HEAD, kHttpHead +POST, kHttpPost +PUT, kHttpPut +CONNECT, kHttpConnect +OPTIONS, kHttpOptions +TRACE, kHttpTrace +COPY, kHttpCopy +CHECKOUT, kHttpCheckout +LOCK, kHttpLock +MERGE, kHttpMerge +MKACTIVITY, kHttpMkactivity +MKCOL, kHttpMkcol +MOVE, kHttpMove +NOTIFY, kHttpNotify +PATCH, kHttpPatch +PROPFIND, kHttpPropfind +PROPPATCH, kHttpProppatch +REPORT, kHttpReport +SUBSCRIBE, kHttpSubscribe +UNLOCK, kHttpUnlock +UNSUBSCRIBE, kHttpUnsubscribe diff --git a/net/http/gethttpmethod.inc b/net/http/gethttpmethod.inc new file mode 100644 index 00000000..3678aa38 --- /dev/null +++ b/net/http/gethttpmethod.inc @@ -0,0 +1,206 @@ +/* ANSI-C code produced by gperf version 3.1 */ +/* Command-line: gperf gethttpmethod.gperf */ +/* Computed positions: -k'1-2' */ + +#if !((' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \ + && ('%' == 37) && ('&' == 38) && ('\'' == 39) && ('(' == 40) \ + && (')' == 41) && ('*' == 42) && ('+' == 43) && (',' == 44) \ + && ('-' == 45) && ('.' == 46) && ('/' == 47) && ('0' == 48) \ + && ('1' == 49) && ('2' == 50) && ('3' == 51) && ('4' == 52) \ + && ('5' == 53) && ('6' == 54) && ('7' == 55) && ('8' == 56) \ + && ('9' == 57) && (':' == 58) && (';' == 59) && ('<' == 60) \ + && ('=' == 61) && ('>' == 62) && ('?' == 63) && ('A' == 65) \ + && ('B' == 66) && ('C' == 67) && ('D' == 68) && ('E' == 69) \ + && ('F' == 70) && ('G' == 71) && ('H' == 72) && ('I' == 73) \ + && ('J' == 74) && ('K' == 75) && ('L' == 76) && ('M' == 77) \ + && ('N' == 78) && ('O' == 79) && ('P' == 80) && ('Q' == 81) \ + && ('R' == 82) && ('S' == 83) && ('T' == 84) && ('U' == 85) \ + && ('V' == 86) && ('W' == 87) && ('X' == 88) && ('Y' == 89) \ + && ('Z' == 90) && ('[' == 91) && ('\\' == 92) && (']' == 93) \ + && ('^' == 94) && ('_' == 95) && ('a' == 97) && ('b' == 98) \ + && ('c' == 99) && ('d' == 100) && ('e' == 101) && ('f' == 102) \ + && ('g' == 103) && ('h' == 104) && ('i' == 105) && ('j' == 106) \ + && ('k' == 107) && ('l' == 108) && ('m' == 109) && ('n' == 110) \ + && ('o' == 111) && ('p' == 112) && ('q' == 113) && ('r' == 114) \ + && ('s' == 115) && ('t' == 116) && ('u' == 117) && ('v' == 118) \ + && ('w' == 119) && ('x' == 120) && ('y' == 121) && ('z' == 122) \ + && ('{' == 123) && ('|' == 124) && ('}' == 125) && ('~' == 126)) +/* The character set is not based on ISO-646. */ +#error "gperf generated tables don't work with this execution character set. Please report a bug to ." +#endif + +#line 1 "gethttpmethod.gperf" + +#include "libc/str/str.h" +#include "net/http/http.h" +#define GPERF_DOWNCASE +#line 12 "gethttpmethod.gperf" +struct HttpMethodSlot { char *name; char code; }; + +#define TOTAL_KEYWORDS 23 +#define MIN_WORD_LENGTH 3 +#define MAX_WORD_LENGTH 11 +#define MIN_HASH_VALUE 4 +#define MAX_HASH_VALUE 34 +/* maximum key range = 31, duplicates = 0 */ + +#ifndef GPERF_DOWNCASE +#define GPERF_DOWNCASE 1 +static unsigned char gperf_downcase[256] = + { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, + 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, + 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, + 60, 61, 62, 63, 64, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, + 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, + 122, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, + 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, + 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, + 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, + 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, + 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, + 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, + 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, + 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, + 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, + 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, + 255 + }; +#endif + +#ifndef GPERF_CASE_STRNCMP +#define GPERF_CASE_STRNCMP 1 +static int +gperf_case_strncmp (register const char *s1, register const char *s2, register size_t n) +{ + for (; n > 0;) + { + unsigned char c1 = gperf_downcase[(unsigned char)*s1++]; + unsigned char c2 = gperf_downcase[(unsigned char)*s2++]; + if (c1 != 0 && c1 == c2) + { + n--; + continue; + } + return (int)c1 - (int)c2; + } + return 0; +} +#endif + +#ifdef __GNUC__ +__inline +#else +#ifdef __cplusplus +inline +#endif +#endif +static unsigned int +hash (register const char *str, register size_t len) +{ + static const unsigned char asso_values[] = + { + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 0, 35, 5, 10, 10, + 35, 5, 10, 35, 35, 0, 30, 15, 0, 0, + 0, 35, 5, 15, 0, 5, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 0, 35, 5, + 10, 10, 35, 5, 10, 35, 35, 0, 30, 15, + 0, 0, 0, 35, 5, 15, 0, 5, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35 + }; + return len + asso_values[(unsigned char)str[1]] + asso_values[(unsigned char)str[0]]; +} + +const struct HttpMethodSlot * +LookupHttpMethod (register const char *str, register size_t len) +{ + static const struct HttpMethodSlot wordlist[] = + { + {""}, {""}, {""}, {""}, +#line 17 "gethttpmethod.gperf" + {"POST", kHttpPost}, +#line 30 "gethttpmethod.gperf" + {"PATCH", kHttpPatch}, +#line 29 "gethttpmethod.gperf" + {"NOTIFY", kHttpNotify}, +#line 20 "gethttpmethod.gperf" + {"OPTIONS", kHttpOptions}, +#line 18 "gethttpmethod.gperf" + {"PUT", kHttpPut}, +#line 22 "gethttpmethod.gperf" + {"COPY", kHttpCopy}, +#line 21 "gethttpmethod.gperf" + {"TRACE", kHttpTrace}, +#line 35 "gethttpmethod.gperf" + {"UNLOCK", kHttpUnlock}, +#line 19 "gethttpmethod.gperf" + {"CONNECT", kHttpConnect}, +#line 31 "gethttpmethod.gperf" + {"PROPFIND", kHttpPropfind}, +#line 32 "gethttpmethod.gperf" + {"PROPPATCH", kHttpProppatch}, + {""}, +#line 36 "gethttpmethod.gperf" + {"UNSUBSCRIBE", kHttpUnsubscribe}, + {""}, +#line 15 "gethttpmethod.gperf" + {"GET", kHttpGet}, +#line 28 "gethttpmethod.gperf" + {"MOVE", kHttpMove}, +#line 27 "gethttpmethod.gperf" + {"MKCOL", kHttpMkcol}, +#line 33 "gethttpmethod.gperf" + {"REPORT", kHttpReport}, + {""}, +#line 23 "gethttpmethod.gperf" + {"CHECKOUT", kHttpCheckout}, +#line 16 "gethttpmethod.gperf" + {"HEAD", kHttpHead}, +#line 26 "gethttpmethod.gperf" + {"MKACTIVITY", kHttpMkactivity}, +#line 14 "gethttpmethod.gperf" + {"DELETE", kHttpDelete}, + {""}, {""}, +#line 34 "gethttpmethod.gperf" + {"SUBSCRIBE", kHttpSubscribe}, +#line 25 "gethttpmethod.gperf" + {"MERGE", kHttpMerge}, + {""}, {""}, {""}, +#line 24 "gethttpmethod.gperf" + {"LOCK", kHttpLock} + }; + + if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH) + { + register unsigned int key = hash (str, len); + + if (key <= MAX_HASH_VALUE) + { + register const char *s = wordlist[key].name; + + if ((((unsigned char)*str ^ (unsigned char)*s) & ~32) == 0 && !gperf_case_strncmp (str, s, len) && s[len] == '\0') + return &wordlist[key]; + } + } + return 0; +} diff --git a/net/http/http.h b/net/http/http.h index c44983e5..6801183a 100644 --- a/net/http/http.h +++ b/net/http/http.h @@ -1,80 +1,101 @@ #ifndef COSMOPOLITAN_LIBC_HTTP_HTTP_H_ #define COSMOPOLITAN_LIBC_HTTP_HTTP_H_ #include "libc/alg/alg.h" + +#define kHttpGet 0 +#define kHttpHead 1 +#define kHttpPost 2 +#define kHttpPut 3 +#define kHttpDelete 4 +#define kHttpConnect 5 +#define kHttpOptions 6 +#define kHttpTrace 7 +#define kHttpCopy 8 +#define kHttpCheckout 9 +#define kHttpLock 10 +#define kHttpMerge 11 +#define kHttpMkactivity 12 +#define kHttpMkcol 13 +#define kHttpMove 14 +#define kHttpNotify 15 +#define kHttpPatch 16 +#define kHttpPropfind 17 +#define kHttpProppatch 18 +#define kHttpReport 19 +#define kHttpSubscribe 20 +#define kHttpUnlock 21 +#define kHttpUnsubscribe 22 + +#define kHttpAccept 0 +#define kHttpAcceptCharset 1 +#define kHttpAcceptEncoding 2 +#define kHttpAcceptLanguage 3 +#define kHttpAge 4 +#define kHttpAllow 5 +#define kHttpAuthorization 6 +#define kHttpCacheControl 7 +#define kHttpChunked 8 +#define kHttpClose 9 +#define kHttpConnection 10 +#define kHttpContentBase 11 +#define kHttpContentEncoding 12 +#define kHttpContentLanguage 13 +#define kHttpContentLength 14 +#define kHttpContentLocation 15 +#define kHttpContentMd5 16 +#define kHttpContentRange 17 +#define kHttpContentType 18 +#define kHttpDate 19 +#define kHttpEtag 20 +#define kHttpExpires 21 +#define kHttpFrom 22 +#define kHttpHost 23 +#define kHttpIfMatch 24 +#define kHttpIfModifiedSince 25 +#define kHttpIfNoneMatch 26 +#define kHttpIfRange 27 +#define kHttpIfUnmodifiedSince 28 +#define kHttpKeepAlive 29 +#define kHttpMaxForwards 30 +#define kHttpPragma 31 +#define kHttpProxyAuthenticate 32 +#define kHttpProxyAuthorization 33 +#define kHttpProxyConnection 34 +#define kHttpRange 35 +#define kHttpReferer 36 +#define kHttpTransferEncoding 37 +#define kHttpUpgrade 38 +#define kHttpUserAgent 39 +#define kHttpVia 40 +#define kHttpLocation 41 +#define kHttpPublic 42 +#define kHttpRetryAfter 43 +#define kHttpServer 44 +#define kHttpVary 45 +#define kHttpWarning 46 +#define kHttpWwwAuthenticate 47 +#define kHttpLastModified 48 +#define kHttpHeadersMax 49 + #if !(__ASSEMBLER__ + __LINKER__ + 0) COSMOPOLITAN_C_START_ -struct FILE; - -enum HttpHeader { - kHttpAccept = 1, - kHttpAcceptCharset, - kHttpAcceptEncoding, - kHttpAcceptLanguage, - kHttpAge, - kHttpAllow, - kHttpAuthorization, - kHttpCacheControl, - kHttpChunked, - kHttpClose, - kHttpConnection, - kHttpContentBase, - kHttpContentEncoding, - kHttpContentLanguage, - kHttpContentLength, - kHttpContentLocation, - kHttpContentMd5, - kHttpContentRange, - kHttpContentType, - kHttpDate, - kHttpEtag, - kHttpExpires, - kHttpFrom, - kHttpHost, - kHttpIfMatch, - kHttpIfModifiedSince, - kHttpIfNoneMatch, - kHttpIfRange, - kHttpIfUnmodifiedSince, - kHttpKeepAlive, - kHttpMaxForwards, - kHttpPragma, - kHttpProxyAuthenticate, - kHttpProxyAuthorization, - kHttpProxyConnection, - kHttpRange, - kHttpReferer, - kHttpTransferEncoding, - kHttpUpgrade, - kHttpUserAgent, - kHttpVia, - kHttpLocation, - kHttpPublic, - kHttpRetryAfter, - kHttpServer, - kHttpVary, - kHttpWarning, - kHttpWwwAuthenticate, - kHttpLastModified, -}; - -struct HttpStr { - char *p; - size_t i, n; +struct HttpRequestSlice { + short a, b; }; struct HttpRequest { - struct HttpStr uri; /* /foo/bar.html, etc. */ - struct HttpStr method; /* "GET", "POST", etc. */ - struct critbit0 headers; /* TreeMultiMap<"key:value"> (no space delims) */ - struct HttpStr version; /* "HTTP/1.1", etc. */ - struct HttpStr scratch; /* "HTTP/1.1", etc. */ + int method; + struct HttpRequestSlice uri; + struct HttpRequestSlice version; + struct HttpRequestSlice scratch; + struct HttpRequestSlice headers[kHttpHeadersMax]; }; -int parsehttprequest(struct HttpRequest *, struct FILE *) paramsnonnull(); -void clearhttprequest(struct HttpRequest *) paramsnonnull(); -void freehttprequest(struct HttpRequest **) paramsnonnull(); -int negotiatehttprequest(int, const char *, uint32_t *, char *, uint32_t *, +int GetHttpHeader(const char *, size_t); +int GetHttpMethod(const char *, size_t); +int ParseHttpRequest(struct HttpRequest *, const char *, size_t); +int NegotiateHttpRequest(int, const char *, uint32_t *, char *, uint32_t *, uint32_t *, bool, long double); COSMOPOLITAN_C_END_ diff --git a/net/http/method.gperf b/net/http/method.gperf deleted file mode 100644 index 2f319ef7..00000000 --- a/net/http/method.gperf +++ /dev/null @@ -1,24 +0,0 @@ -DELETE -GET -HEAD -POST -PUT -CONNECT -OPTIONS -TRACE -COPY -CHECKOUT -LOCK -M-SEARCH -MERGE -MKACTIVITY -MKCOL -MOVE -NOTIFY -PATCH -PROPFIND -PROPPATCH -REPORT -SUBSCRIBE -UNLOCK -UNSUBSCRIBE diff --git a/net/http/negotiatehttprequest.c b/net/http/negotiatehttprequest.c index 50e9e787..a8bca614 100644 --- a/net/http/negotiatehttprequest.c +++ b/net/http/negotiatehttprequest.c @@ -42,7 +42,7 @@ static pureconst long AsMilliseconds(long double ts) { * @param singleshot should be true w/ connection: close * @return 0 on success, or -1 w/ errno */ -int negotiatehttprequest(int sock, const char *req, uint32_t *inout_reqsize, +int NegotiateHttpRequest(int sock, const char *req, uint32_t *inout_reqsize, char *resp, uint32_t *inout_respsize, uint32_t *out_resphdrsize, bool singleshot, long double timeout) { diff --git a/net/http/parsehttprequest.c b/net/http/parsehttprequest.c index 556189cf..cd44558a 100644 --- a/net/http/parsehttprequest.c +++ b/net/http/parsehttprequest.c @@ -39,95 +39,84 @@ enum ParseHttpRequestState { }; /** - * Parses req line and headers of HTTP req. - * - * This parser is very lax. All decoding is ISO-8859-1. A 1mB upper - * bound on memory is enforced. + * Parses HTTP request header. */ -int parsehttprequest(struct HttpRequest *req, FILE *f) { - enum ParseHttpRequestState state = METHOD; - int toto = 0; - clearhttprequest(req); - while (true) { - char ch; - { - int c = fgetc(f); - if (c == -1) { - if (toto && !ferror(f)) { - return ebadmsg(); /* RFC7230 § 3.4 */ - } - return -1; - } - ch = (unsigned char)c; - } - if (++toto == UINT16_MAX) { - return ebadmsg(); /* RFC7230 § 3.2.5 */ - } - switch (state) { +int ParseHttpRequest(struct HttpRequest *req, const char *p, size_t n) { + int a, h, c, i, x; + enum ParseHttpRequestState t; + memset(req, 0, sizeof(*req)); + a = h = 0; + t = METHOD; + if (n > SHRT_MAX - 1) n = SHRT_MAX - 1; + for (i = 0; i < n; ++i) { + c = p[i] & 0xFF; + switch (t) { case METHOD: - if (ch == '\r' || ch == '\n') break; /* RFC7230 § 3.5 */ - if (ch == ' ') { - if (req->method.i == 0) return ebadmsg(); - state = URI; - } else { - append(&req->method, &ch); + if (c == '\r' || c == '\n') break; /* RFC7230 § 3.5 */ + if (c == ' ') { + if (!i) return ebadmsg(); + if ((x = GetHttpMethod(p, i)) == -1) return ebadmsg(); + req->method = x; + req->uri.a = i + 1; + t = URI; } break; case URI: - if (ch == ' ') { - if (req->uri.i == 0) return ebadmsg(); - state = VERSION; - } else { - append(&req->uri, &ch); + if (c == ' ') { + req->uri.b = i; + req->version.a = i + 1; + if (req->uri.a == req->uri.b) return ebadmsg(); + t = VERSION; } break; case VERSION: - if (ch == '\r' || ch == '\n') { - state = ch == '\r' ? CR1 : LF1; - } else { - append(&req->version, &ch); + if (c == '\r' || c == '\n') { + req->version.b = i; + t = c == '\r' ? CR1 : LF1; } break; case CR1: - if (ch != '\n') return ebadmsg(); - state = LF1; + if (c != '\n') return ebadmsg(); + t = LF1; break; case LF1: - if (ch == '\r') { - state = LF2; + if (c == '\r') { + t = LF2; break; - } else if (ch == '\n') { + } else if (c == '\n') { return 0; - } else if (ch == ' ' || ch == '\t') { /* line folding!!! */ - return eprotonosupport(); /* RFC7230 § 3.2.4 */ + } else if (c == ' ' || c == '\t') { /* line folding!!! */ + return eprotonosupport(); /* RFC7230 § 3.2.4 */ } - state = HKEY; + a = i; + t = HKEY; /* εpsilon transition */ case HKEY: - if (ch == ':') state = HSEP; - ch = tolower(ch); - append(&req->scratch, &ch); + if (c == ':') { + h = GetHttpHeader(p + a, i - a); + t = HSEP; + } break; case HSEP: - if (ch == ' ' || ch == '\t') break; - state = HVAL; + if (c == ' ' || c == '\t') break; + a = i; + t = HVAL; /* εpsilon transition */ case HVAL: - if (ch == '\r' || ch == '\n') { - state = ch == '\r' ? CR1 : LF1; - ch = '\0'; - } - append(&req->scratch, &ch); - if (!ch) { - critbit0_insert(&req->headers, req->scratch.p); - req->scratch.i = 0; + if (c == '\r' || c == '\n') { + if (h != -1) { + req->headers[h].a = a; + req->headers[h].b = i; + } + t = c == '\r' ? CR1 : LF1; } break; case LF2: - if (ch == '\n') return 0; + if (c == '\n') return 0; return ebadmsg(); default: unreachable; } } + return ebadmsg(); } diff --git a/test/ape/lib/test.mk b/test/ape/lib/test.mk index b633a592..58f57e45 100644 --- a/test/ape/lib/test.mk +++ b/test/ape/lib/test.mk @@ -29,6 +29,7 @@ TEST_APE_LIB_DIRECTDEPS = \ LIBC_NEXGEN32E \ LIBC_RUNTIME \ LIBC_STR \ + LIBC_LOG \ LIBC_STUBS \ LIBC_TESTLIB \ LIBC_X @@ -49,6 +50,10 @@ o/$(MODE)/test/ape/lib/%.com.dbg: \ $(APE) @$(APELINK) +$(TEST_APE_LIB_OBJS): \ + OVERRIDE_CFLAGS += \ + -fsanitize=address + .PHONY: o/$(MODE)/test/ape/lib o/$(MODE)/test/ape/lib: $(TEST_APE_LIB_BINS) \ $(TEST_APE_LIB_CHECKS) diff --git a/test/dsp/core/getintegercoefficients8_test.c b/test/dsp/core/getintegercoefficients8_test.c index d789deba..ccdbb691 100644 --- a/test/dsp/core/getintegercoefficients8_test.c +++ b/test/dsp/core/getintegercoefficients8_test.c @@ -19,6 +19,7 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "dsp/core/core.h" #include "dsp/core/q.h" +#include "libc/stdio/stdio.h" #include "libc/str/str.h" #include "libc/testlib/ezbench.h" #include "libc/testlib/testlib.h" @@ -49,7 +50,8 @@ TEST(GetIntegerCoefficients8, testBt601Vectors) { for (i = 0; i < ARRAYLEN(V); ++i) { GetIntegerCoefficients8(got, V[i].r, V[i].m, V[i].L, V[i].H); EXPECT_EQ(0, memcmp(V[i].n, got, sizeof(got)), - "got={%ld,%ld,%ld,%ld,%ld,%ld}, want={%ld,%ld,%ld,%ld,%ld,%ld}", + "got={%ld,%ld,%ld,%ld,%ld,%ld}, want = { % ld, % ld, % ld, % ld, " + "% ld, % ld } ", got[0], got[1], got[2], got[3], got[4], got[5], V[i].n[0], V[i].n[1], V[i].n[2], V[i].n[3], V[i].n[4], V[i].n[5]); } diff --git a/test/dsp/core/test.mk b/test/dsp/core/test.mk index 35a469cf..4fd9dab0 100644 --- a/test/dsp/core/test.mk +++ b/test/dsp/core/test.mk @@ -47,6 +47,14 @@ o/$(MODE)/test/dsp/core/%.com.dbg: \ $(APE) @$(APELINK) +$(TEST_DSP_CORE_OBJS): \ + OVERRIDE_CFLAGS += \ + -fsanitize=address + +o/$(MODE)/test/dsp/core/getintegercoefficients8_test-gcc.asm: \ + OVERRIDE_CFLAGS += \ + -fsanitize=address + .PHONY: o/$(MODE)/test/dsp/core o/$(MODE)/test/dsp/core: \ $(TEST_DSP_CORE_BINS) \ diff --git a/test/dsp/scale/scale_test.c b/test/dsp/scale/scale_test.c index 97806f11..ff6eb952 100644 --- a/test/dsp/scale/scale_test.c +++ b/test/dsp/scale/scale_test.c @@ -347,7 +347,7 @@ TEST(magikarp_vs_gyarados, testHalf) { 61. / 31., 0, 0); Magikarp2xY(32, 61, M[0], 32, 61); Magikarp2xX(32, 61, M[0], 16, 61); - AbsoluteDifference(16, 31, D, 16, 32, G[0], 32, 61, M[0]); + AbsoluteDifference(16, 31, D, 16, 31, G[0], 32, 61, M[0]); EXPECT_STREQ(u"\n\ oppppppppooooooooooooopppppppqp\n\ pppppooonnmmmmmmmmmmmnnoopppppp\n\ @@ -386,21 +386,21 @@ pppppppppoooooooooooooppppppppq", gc(bingblit(16, 31, G[0], 16, 31))); EXPECT_STREQ(u"\n\ ☺       ☺             ☺      ☺ \n\ -    ☺ ☺☺ ☺          ☺          \n\ - ☺☺☺ ☺                ☺☺☺☺☻   ☺\n\ -☻☻☺☻      ☺☺☺  ☺☺☺     ☺☺☻☺☺ ☺☻\n\ -♥☺☺☺ ☺☺☻♥☻♥☻☺ ☺☻☻☻☻☺☺☺ ☺☺☻☻☺ ☺♥\n\ -☻☺ ☺☻♦♣♠♣♦♥☻☺☺☻♥♣♠♣♣♦♥☺☺☺☻☻ ☺☻☻\n\ -☺ ☻♦♠••○•♠♥☻☺♥♦♠•○••♠♥☻ ☻☻☺ ☺☺☻\n\ - ☻♣•◘◙◙◙◙♠♦☺☻♦•○◙◙◙◘•♣☺☺☻☺   ☺☺\n\ -☺♦♠◘◙♂♂◙○♣♦☺♦♠○◙♂♂◙•♠♦ ☺☺    ☺☺\n\ -☻♦•◘○◙◙◘•♦☺☻♦•○◙◙○◘♠♦☺  ☺   ☺☻☺\n\ -☺☻♣♠♠♠♠♠♦☻ ☻♦♠♠♠♠♠♥♥☺ ☻☺☺   ☺☻☻\n\ -☻ ☺♥♥♥☻☻☺☺☺☺☻☻♥♥☻☺ ☺☻♥☻☻☺  ☺☻☻♥\n\ -♥♥☻☻☺         ☺☻☻♥♥♥♥♥☻☻☺☺☻☺♥♥♥\n\ -♥♥♥♥☺☻☺    ☺☺☻☻♥♥♥♥♥♥♥♥☻  ☺☻☻♥♥\n\ -♥♥♥♥♥♥☺☺☺☺☺☻♥♥♥♥♥♥♥♥☻☻☺☺☺ ☺☺☺☺☺\n\ -☻☺☺☺☺☺☺   ☺☺☺☺☺☻oooooppppppppqp", +       ☺               ☺ ☺     \n\ +    ☺ ☺                   ☺☺   \n\ + ☺☺☺☺                      ☺ ☺ \n\ +☺☺              ☺ ☺☺          ☺\n\ +       ☺☺☺           ☺ ☺   ☺ ☺ \n\ +  ☺       ☺☺☺        ☺☺ ☺   ☺  \n\ +         ☺ ☺   ☺      ☺☺☺      \n\ +         ☺ ☺       ☺  ☺☺☺      \n\ +       ☺  ☺        ☺ ☺      ☺☺ \n\ + ☺☺               ☺   ☺      ☺ \n\ +☺  ☺                        ☺ ☺\n\ +                          ☺☺☺  \n\ +   ☺☺☺                  ☺☺ ☺   \n\ +     ☺  ☺             ☺  ☺     \n\ +☺        ☺           ☺       ☺☺", gc(bingblit(16, 31, D, 16, 31))); } diff --git a/test/libc/conv/itoa64radix16_test.c b/test/libc/conv/itoa64radix16_test.c index 931fb48d..046fa1dd 100644 --- a/test/libc/conv/itoa64radix16_test.c +++ b/test/libc/conv/itoa64radix16_test.c @@ -24,6 +24,10 @@ TEST(itoa64radix16, test) { char buf[21]; EXPECT_EQ(5, uint64toarray_radix16(0x31337, buf)); EXPECT_STREQ("31337", buf); + EXPECT_EQ(2, uint64toarray_radix16(0x13, buf)); + EXPECT_STREQ("13", buf); + EXPECT_EQ(3, uint64toarray_radix16(0x113, buf)); + EXPECT_STREQ("113", buf); } TEST(itoa64fixed16, test) { diff --git a/test/libc/fmt/palandprintf_test.c b/test/libc/fmt/palandprintf_test.c index 2a39050e..ad9a26e3 100644 --- a/test/libc/fmt/palandprintf_test.c +++ b/test/libc/fmt/palandprintf_test.c @@ -416,12 +416,8 @@ TEST(sprintf, test_float) { EXPECT_STREQ("42.90", Format("%.2f", 42.8952)); EXPECT_STREQ("42.895200000", Format("%.9f", 42.8952)); EXPECT_STREQ("42.8952230000", Format("%.10f", 42.895223)); - /* this testcase checks, that the precision is truncated to 9 digits. */ - /* a perfect working float should return the whole number */ - EXPECT_STREQ("42.895223123000", Format("%.12f", 42.89522312345678)); - /* this testcase checks, that the precision is truncated AND rounded to 9 */ - /* digits. a perfect working float should return the whole number */ - EXPECT_STREQ("42.895223877000", Format("%.12f", 42.89522387654321)); + EXPECT_STREQ("42.89522312345678", Format("%.14f", 42.89522312345678)); + EXPECT_STREQ("42.89522387654321", Format("%.14f", 42.89522387654321)); EXPECT_STREQ(" 42.90", Format("%6.2f", 42.8952)); EXPECT_STREQ("+42.90", Format("%+6.2f", 42.8952)); EXPECT_STREQ("+42.9", Format("%+5.1f", 42.9252)); diff --git a/test/libc/intrin/intrin_test.c b/test/libc/intrin/intrin_test.c index 58c8cf37..e15d1cc2 100644 --- a/test/libc/intrin/intrin_test.c +++ b/test/libc/intrin/intrin_test.c @@ -18,6 +18,7 @@ │ 02110-1301 USA │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/bits/progn.h" +#include "libc/intrin/mpsadbw.h" #include "libc/intrin/pabsb.h" #include "libc/intrin/pabsd.h" #include "libc/intrin/pabsw.h" @@ -1422,7 +1423,8 @@ TEST(pabsb, fuzz) { RngSet(x, sizeof(x)); pabsb(a, x); (pabsb)(b, x); - ASSERT_EQ(0, memcmp(a, b, 16)); + ASSERT_EQ(0, memcmp(a, b, 16), "%d\n\t%`#.16s\n\t%`#.16s\n\t%`#.16s", i, x, + a, b); } } @@ -1975,6 +1977,21 @@ TEST(pmulhrsw, fuzz) { } } +TEST(mpsadbw, fuzz) { + int i, j; + uint16_t a[8], b[8]; + uint8_t x[16], y[16]; + for (i = 0; i < 100; ++i) { + RngSet(x, sizeof(x)); + RngSet(y, sizeof(y)); + for (j = 0; j < 8; ++j) { + mpsadbw(a, x, y, j); + (mpsadbw)(b, x, y, j); + ASSERT_EQ(0, memcmp(a, b, 16), "%d %d", i, j); + } + } +} + TEST(pmaddubsw, fuzz) { int i, j; int8_t y[16]; diff --git a/test/libc/intrin/test.mk b/test/libc/intrin/test.mk index aad71604..6942926d 100644 --- a/test/libc/intrin/test.mk +++ b/test/libc/intrin/test.mk @@ -52,6 +52,10 @@ o/$(MODE)/test/libc/intrin/%.com.dbg: \ $(APE) @$(APELINK) +$(TEST_LIBC_INTRIN_OBJS): \ + OVERRIDE_CFLAGS += \ + -fsanitize=address + .PHONY: o/$(MODE)/test/libc/intrin o/$(MODE)/test/libc/intrin: \ $(TEST_LIBC_INTRIN_BINS) \ diff --git a/test/libc/nexgen32e/memmove_test.c b/test/libc/nexgen32e/memmove_test.c index 156ba766..33ebbeed 100644 --- a/test/libc/nexgen32e/memmove_test.c +++ b/test/libc/nexgen32e/memmove_test.c @@ -57,3 +57,37 @@ TEST(memmove, overlappingDirect) { } } } + +char *MoveMemory(char *dst, const char *src, size_t n) { + size_t i; + for (i = 0; i < n; ++i) { + dst[i] = src[i]; + } + return dst; +} + +TEST(memmove, overlappingBackwards_isGenerallySafe) { + char buf[32]; + strcpy(buf, "abcdefghijklmnopqrstuvwxyz"); + ASSERT_STREQ("cdefghijklmnopqrstuvwxyzyz", MoveMemory(buf, buf + 2, 24)); + strcpy(buf, "abcdefghijklmnopqrstuvwxyz"); + ASSERT_STREQ("cdefghijklmnopqrstuvwxyzyz", memmove(buf, buf + 2, 24)); + strcpy(buf, "abcdefghijklmnopqrstuvwxyz"); + ASSERT_STREQ("cdefghijklmnopqrstuvwxyzyz", memcpy(buf, buf + 2, 24)); +} + +TEST(memmove, overlappingForwards_avoidsRunLengthDecodeBehavior) { + volatile char buf[32]; + strcpy(buf, "abc"); + MoveMemory(buf + 1, buf, 2); + ASSERT_STREQ("aaa", buf); + strcpy(buf, "abc"); + (memmove)(buf + 1, buf, 2); + ASSERT_STREQ("aab", buf); + strcpy(buf, "abcdefghijklmnopqrstuvwxyz"); + MoveMemory(buf + 2, buf, 24); + ASSERT_STREQ("ababababababababababababab", buf); + strcpy(buf, "abcdefghijklmnopqrstuvwxyz"); + memmove(buf + 2, buf, 24); + ASSERT_STREQ("ababcdefghijklmnopqrstuvwx", buf); +} diff --git a/test/libc/str/memcpy_test.c b/test/libc/str/memcpy_test.c index b74c668a..f2fc631d 100644 --- a/test/libc/str/memcpy_test.c +++ b/test/libc/str/memcpy_test.c @@ -81,3 +81,17 @@ TEST(memcpy, overlapping_isFineIfCopyingBackwards) { tfree(b1); } } + +TEST(stpcpy, test) { + volatile char *p; + volatile char b[16]; + volatile const char *s1 = "hello"; + volatile const char *s2 = "there"; + p = b; + p = stpcpy(p, s1); + EXPECT_EQ((intptr_t)b + 5, (intptr_t)p); + EXPECT_STREQ("hello", b); + p = stpcpy(p, s2); + EXPECT_EQ((intptr_t)b + 10, (intptr_t)p); + EXPECT_STREQ("hellothere", b); +} diff --git a/test/libc/str/str_test.c b/test/libc/str/str_test.c index 266b1f7c..a97601cf 100644 --- a/test/libc/str/str_test.c +++ b/test/libc/str/str_test.c @@ -21,22 +21,26 @@ #include "libc/str/str.h" #include "libc/testlib/testlib.h" -TEST(strlen16, testEmpty) { EXPECT_EQ(0, strlen(u"")); } -TEST(strlen16, testAscii) { EXPECT_EQ(5, strlen(u"hello")); } +TEST(strlen16, testEmpty) { + EXPECT_EQ(0, strlen16(u"")); +} +TEST(strlen16, testAscii) { + EXPECT_EQ(5, strlen16(u"hello")); +} TEST(strlen16, testUnicode) { - EXPECT_EQ(28, strlen(u"αcτµαlly pδrταblε εxεcµταblε")); + EXPECT_EQ(28, strlen16(u"αcτµαlly pδrταblε εxεcµταblε")); } TEST(strclen, testAegeanNumberSupplementaryPlane) { EXPECT_EQ(36, strlen("𐄷𐄸𐄹𐄺𐄻𐄼𐄽𐄾𐄿")); - EXPECT_EQ(18, strlen(u"𐄷𐄸𐄹𐄺𐄻𐄼𐄽𐄾𐄿")); - EXPECT_EQ(9, strlen(L"𐄷𐄸𐄹𐄺𐄻𐄼𐄽𐄾𐄿")); + EXPECT_EQ(18, strlen16(u"𐄷𐄸𐄹𐄺𐄻𐄼𐄽𐄾𐄿")); + EXPECT_EQ(9, wcslen(L"𐄷𐄸𐄹𐄺𐄻𐄼𐄽𐄾𐄿")); EXPECT_EQ(9, strclen("𐄷𐄸𐄹𐄺𐄻𐄼𐄽𐄾𐄿")); EXPECT_EQ(9, strclen(u"𐄷𐄸𐄹𐄺𐄻𐄼𐄽𐄾𐄿")); EXPECT_EQ(9, strclen(L"𐄷𐄸𐄹𐄺𐄻𐄼𐄽𐄾𐄿")); } TEST(strlen16, testCoolKidNulTerminator) { - EXPECT_EQ(2, strlen((const char16_t *)"\x00\xd8\x00\xdc\x00")); + EXPECT_EQ(2, strlen16((const char16_t *)"\x00\xd8\x00\xdc\x00")); } diff --git a/test/libc/str/strlen_test.c b/test/libc/str/strlen_test.c index 75efd04b..a80fac37 100644 --- a/test/libc/str/strlen_test.c +++ b/test/libc/str/strlen_test.c @@ -29,8 +29,8 @@ wchar_t u32[] = L"utf32 ☻"; TEST(strlen, usageExample_c11) { EXPECT_EQ(6 + 3, strlen(u8)); - EXPECT_EQ(7, strlen(u16)); - EXPECT_EQ(7, strlen(u32)); + EXPECT_EQ(7, strlen16(u16)); + EXPECT_EQ(7, wcslen(u32)); } TEST(strlen, usageExample_c99) { diff --git a/test/libc/tinymath/ldexp_test.c b/test/libc/tinymath/ldexp_test.c index 67295a1d..e09ad659 100644 --- a/test/libc/tinymath/ldexp_test.c +++ b/test/libc/tinymath/ldexp_test.c @@ -39,3 +39,8 @@ TEST(ldexp, test) { ASSERT_STREQ("100.48", gc(xasprintf("%.2f", scalblnf(pi, twopow)))); ASSERT_STREQ("100.48", gc(xasprintf("%.2Lf", scalblnl(pi, twopow)))); } + +TEST(exp10, test) { + ASSERT_EQ(100, (int)exp10(2)); + ASSERT_STREQ("100.000000", gc(xasprintf("%Lf", exp10l(2)))); +} diff --git a/test/libc/tinymath/round_test.c b/test/libc/tinymath/round_test.c index 649bbde2..bbb03a69 100644 --- a/test/libc/tinymath/round_test.c +++ b/test/libc/tinymath/round_test.c @@ -20,6 +20,7 @@ #include "libc/math.h" #include "libc/nexgen32e/x86feature.h" #include "libc/runtime/gc.h" +#include "libc/str/str.h" #include "libc/testlib/testlib.h" #include "libc/tinymath/tinymath.h" #include "libc/x/x.h" @@ -27,6 +28,10 @@ float tinymath_roundf$k8(float); double tinymath_round$k8(double); +FIXTURE(intrin, disableHardwareExtensions) { + memset((/*unconst*/ void *)kCpuids, 0, sizeof(kCpuids)); +} + TEST(round, testCornerCases) { EXPECT_STREQ("-0", gc(xdtoa(tinymath_round(-0.0)))); EXPECT_STREQ("nan", gc(xdtoa(tinymath_round(NAN)))); @@ -35,6 +40,14 @@ TEST(round, testCornerCases) { EXPECT_STREQ("-inf", gc(xdtoa(tinymath_round(-INFINITY)))); } +TEST(roundl, testCornerCases) { + EXPECT_STREQ("-0", gc(xdtoa(tinymath_roundl(-0.0)))); + EXPECT_STREQ("nan", gc(xdtoa(tinymath_roundl(NAN)))); + EXPECT_STREQ("-nan", gc(xdtoa(tinymath_roundl(-NAN)))); + EXPECT_STREQ("inf", gc(xdtoa(tinymath_roundl(INFINITY)))); + EXPECT_STREQ("-inf", gc(xdtoa(tinymath_roundl(-INFINITY)))); +} + TEST(round, test) { EXPECT_STREQ("-3", gc(xdtoa(tinymath_round(-2.5)))); EXPECT_STREQ("-2", gc(xdtoa(tinymath_round(-1.5)))); @@ -134,16 +147,6 @@ TEST(rintl, test) { EXPECT_STREQ("2", gc(xdtoa(tinymath_rintl(2.5)))); } -TEST(lround, test) { - EXPECT_EQ(-3, tinymath_lround(-2.5)); - EXPECT_EQ(-2, tinymath_lround(-1.5)); - EXPECT_EQ(-1, tinymath_lround(-.5)); - EXPECT_EQ(0, tinymath_lround(-.0)); - EXPECT_EQ(1, tinymath_lround(.5)); - EXPECT_EQ(2, tinymath_lround(1.5)); - EXPECT_EQ(3, tinymath_lround(2.5)); -} - TEST(roundf, testCornerCases) { EXPECT_STREQ("-0", gc(xdtoa(tinymath_roundf(-0.0)))); EXPECT_STREQ("nan", gc(xdtoa(tinymath_roundf(NAN)))); @@ -162,40 +165,24 @@ TEST(lroundf, test) { EXPECT_EQ(3, tinymath_lroundf(2.5)); } -#if !X86_NEED(SSE4_2) - -TEST(round$k8, test) { - EXPECT_STREQ("-3", gc(xdtoa(tinymath_round$k8(-2.5)))); - EXPECT_STREQ("-2", gc(xdtoa(tinymath_round$k8(-1.5)))); - EXPECT_STREQ("-1", gc(xdtoa(tinymath_round$k8(-.5)))); - EXPECT_STREQ("1", gc(xdtoa(tinymath_round$k8(.5)))); - EXPECT_STREQ("2", gc(xdtoa(tinymath_round$k8(1.5)))); - EXPECT_STREQ("3", gc(xdtoa(tinymath_round$k8(2.5)))); +TEST(lround, test) { + EXPECT_EQ(-3, tinymath_lround(-2.5)); + EXPECT_EQ(-2, tinymath_lround(-1.5)); + EXPECT_EQ(-1, tinymath_lround(-.5)); + EXPECT_EQ(-0, tinymath_lround(-.4)); + EXPECT_EQ(0, tinymath_lround(.4)); + EXPECT_EQ(1, tinymath_lround(.5)); + EXPECT_EQ(2, tinymath_lround(1.5)); + EXPECT_EQ(3, tinymath_lround(2.5)); } -TEST(roundf$k8, test) { - EXPECT_STREQ("-3", gc(xdtoa(tinymath_roundf$k8(-2.5)))); - EXPECT_STREQ("-2", gc(xdtoa(tinymath_roundf$k8(-1.5)))); - EXPECT_STREQ("-1", gc(xdtoa(tinymath_roundf$k8(-.5)))); - EXPECT_STREQ("1", gc(xdtoa(tinymath_roundf$k8(.5)))); - EXPECT_STREQ("2", gc(xdtoa(tinymath_roundf$k8(1.5)))); - EXPECT_STREQ("3", gc(xdtoa(tinymath_roundf$k8(2.5)))); +TEST(lroundl, test) { + EXPECT_EQ(-3, tinymath_lroundl(-2.5)); + EXPECT_EQ(-2, tinymath_lroundl(-1.5)); + EXPECT_EQ(-1, tinymath_lroundl(-.5)); + EXPECT_EQ(-0, tinymath_lroundl(-.4)); + EXPECT_EQ(0, tinymath_lroundl(.4)); + EXPECT_EQ(1, tinymath_lroundl(.5)); + EXPECT_EQ(2, tinymath_lroundl(1.5)); + EXPECT_EQ(3, tinymath_lroundl(2.5)); } - -TEST(round$k8, testCornerCases) { - EXPECT_STREQ("-0", gc(xdtoa(tinymath_round$k8(-0.0)))); - EXPECT_STREQ("nan", gc(xdtoa(tinymath_round$k8(NAN)))); - EXPECT_STREQ("-nan", gc(xdtoa(tinymath_round$k8(-NAN)))); - EXPECT_STREQ("inf", gc(xdtoa(tinymath_round$k8(INFINITY)))); - EXPECT_STREQ("-inf", gc(xdtoa(tinymath_round$k8(-INFINITY)))); -} - -TEST(roundf$k8, testCornerCases) { - EXPECT_STREQ("-0", gc(xdtoa(tinymath_roundf$k8(-0.0)))); - EXPECT_STREQ("nan", gc(xdtoa(tinymath_roundf$k8(NAN)))); - EXPECT_STREQ("-nan", gc(xdtoa(tinymath_roundf$k8(-NAN)))); - EXPECT_STREQ("inf", gc(xdtoa(tinymath_roundf$k8(INFINITY)))); - EXPECT_STREQ("-inf", gc(xdtoa(tinymath_roundf$k8(-INFINITY)))); -} - -#endif diff --git a/test/libc/tinymath/test.mk b/test/libc/tinymath/test.mk index 3cab2a52..787c6516 100644 --- a/test/libc/tinymath/test.mk +++ b/test/libc/tinymath/test.mk @@ -29,6 +29,7 @@ TEST_LIBC_TINYMATH_DIRECTDEPS = \ LIBC_TINYMATH \ LIBC_MEM \ LIBC_RUNTIME \ + LIBC_NEXGEN32E \ LIBC_STUBS \ LIBC_TESTLIB \ LIBC_X \ diff --git a/test/libc/xed/x86ild_lib.c b/test/libc/xed/x86ild_lib.c index 02217553..f015b3e7 100644 --- a/test/libc/xed/x86ild_lib.c +++ b/test/libc/xed/x86ild_lib.c @@ -28,7 +28,7 @@ testonly nodiscard uint8_t *unbingx86op(const char16_t *codez) { size_t len; - len = strlen(codez); + len = strlen16(codez); return unbingbuf(xmalloc(ROUNDUP(len, 16)), len, codez, 0x90); } diff --git a/test/net/http/parsehttprequest_test.c b/test/net/http/parsehttprequest_test.c index 838a87d1..eabcfedd 100644 --- a/test/net/http/parsehttprequest_test.c +++ b/test/net/http/parsehttprequest_test.c @@ -19,52 +19,42 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/bits/bits.h" #include "libc/mem/mem.h" +#include "libc/runtime/gc.h" #include "libc/stdio/stdio.h" #include "libc/str/str.h" #include "libc/testlib/testlib.h" +#include "libc/x/x.h" #include "net/http/http.h" -TEST(parsehttprequest, testEmpty) { - FILE *f = fmemopen(NULL, BUFSIZ, "r+"); - struct HttpRequest *req = calloc(1, sizeof(struct HttpRequest)); - EXPECT_EQ(-1, parsehttprequest(req, f)); - EXPECT_TRUE(feof(f)); - freehttprequest(&req); - fclose(f); +struct HttpRequest req[1]; + +static char *slice(const char *m, struct HttpRequestSlice s) { + return memcpy(xmalloc(s.b - s.a), m + s.a, s.b - s.a); } -TEST(parsehttprequest, testNoHeaders) { - const char kMessage[] = "GET /foo HTTP/1.0\r\n" - "\r\n"; - FILE *f = fmemopen(NULL, BUFSIZ, "r+"); - ASSERT_EQ(1, fwrite(kMessage, strlen(kMessage), 1, f)); - struct HttpRequest *req = calloc(1, sizeof(struct HttpRequest)); - EXPECT_EQ(0, parsehttprequest(req, f)); - EXPECT_STREQN("GET", req->method.p, req->method.i); - EXPECT_STREQN("/foo", req->uri.p, req->uri.i); - EXPECT_STREQN("HTTP/1.0", req->version.p, req->version.i); - EXPECT_EQ(0, req->headers.count); - freehttprequest(&req); - fclose(f); +TEST(ParseHttpRequest, testEmpty) { + EXPECT_EQ(-1, ParseHttpRequest(req, "", 0)); } -TEST(parsehttprequest, testSomeHeaders) { - const char kMessage[] = "GET /foo?bar%20hi HTTP/1.0\r\n" - "Host: foo.example\r\n" - "Content-Length: 0\r\n" - "\r\n"; - FILE *f = fmemopen(NULL, BUFSIZ, "r+"); - ASSERT_EQ(1, fwrite(kMessage, strlen(kMessage), 1, f)); - struct HttpRequest *req = calloc(1, sizeof(struct HttpRequest)); - EXPECT_EQ(0, parsehttprequest(req, f)); - EXPECT_STREQN("GET", req->method.p, req->method.i); - EXPECT_STREQN("/foo?bar%20hi", req->uri.p, req->uri.i); - EXPECT_STREQN("HTTP/1.0", req->version.p, req->version.i); - EXPECT_EQ(2, req->headers.count); - EXPECT_STREQ("host:foo.example", critbit0_get(&req->headers, "host:")); - EXPECT_STREQ("content-length:0", - critbit0_get(&req->headers, "content-length:")); - EXPECT_EQ(NULL, critbit0_get(&req->headers, "content:")); - freehttprequest(&req); - fclose(f); +TEST(ParseHttpRequest, testNoHeaders) { + static const char m[] = "GET /foo HTTP/1.0\r\n\r\n"; + EXPECT_EQ(0, ParseHttpRequest(req, m, strlen(m))); + EXPECT_EQ(kHttpGet, req->method); + EXPECT_STREQ("/foo", gc(slice(m, req->uri))); + EXPECT_STREQ("HTTP/1.0", gc(slice(m, req->version))); +} + +TEST(ParseHttpRequest, testSomeHeaders) { + static const char m[] = "\ +POST /foo?bar%20hi HTTP/1.0\r\n\ +Host: foo.example\r\n\ +Content-Length: 0\r\n\ +\r\n"; + EXPECT_EQ(0, ParseHttpRequest(req, m, strlen(m))); + EXPECT_EQ(kHttpPost, req->method); + EXPECT_STREQ("/foo?bar%20hi", gc(slice(m, req->uri))); + EXPECT_STREQ("HTTP/1.0", gc(slice(m, req->version))); + EXPECT_STREQ("foo.example", gc(slice(m, req->headers[kHttpHost]))); + EXPECT_STREQ("0", gc(slice(m, req->headers[kHttpContentLength]))); + EXPECT_STREQ("", gc(slice(m, req->headers[kHttpEtag]))); } diff --git a/test/net/http/test.mk b/test/net/http/test.mk index ba9c9065..f6669a15 100644 --- a/test/net/http/test.mk +++ b/test/net/http/test.mk @@ -39,6 +39,10 @@ o/$(MODE)/test/net/http/%.com.dbg: \ $(APE) @$(APELINK) +$(TEST_NET_HTTP_OBJS): \ + OVERRIDE_CFLAGS += \ + -fsanitize=address + .PHONY: o/$(MODE)/test/net/http o/$(MODE)/test/net/http: \ $(TEST_NET_HTTP_BINS) \ diff --git a/test/tool/build/lib/alu_test.c b/test/tool/build/lib/alu_test.c index 36fbd73a..8b86eae6 100644 --- a/test/tool/build/lib/alu_test.c +++ b/test/tool/build/lib/alu_test.c @@ -18,14 +18,19 @@ │ 02110-1301 USA │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/assert.h" +#include "libc/bits/progn.h" #include "libc/limits.h" #include "libc/runtime/runtime.h" #include "libc/stdio/stdio.h" +#include "libc/testlib/ezbench.h" #include "libc/testlib/testlib.h" #include "test/tool/build/lib/optest.h" #include "tool/build/lib/alu.h" +#include "tool/build/lib/case.h" #include "tool/build/lib/flags.h" +#define ALU_TEST 8 + #define NATIVE_ALU2(MODE, INSTRUCTION) \ asm("pushf\n\t" \ "andl\t%3,(%%rsp)\n\t" \ @@ -97,6 +102,15 @@ const char *const kAluNames[] = { [ALU_XOR] = "xor", [ALU_CMP] = "cmp", [ALU_AND | ALU_TEST] = "test", }; +int64_t Alu(int w, int h, uint64_t x, uint64_t y, uint32_t *flags) { + if (h < ALU_CMP) { + return kAlu[h][w](x, y, flags); + } else { + kAlu[h & 7][w](x, y, flags); + return x; + } +} + int64_t RunOpTest(char w, int h, uint64_t x, uint64_t y, uint32_t *f) { return Alu(w, h, x, y, f); } diff --git a/test/tool/build/lib/bitscan_test.c b/test/tool/build/lib/bitscan_test.c index f35e7d29..8c1eb592 100644 --- a/test/tool/build/lib/bitscan_test.c +++ b/test/tool/build/lib/bitscan_test.c @@ -24,7 +24,7 @@ #include "tool/build/lib/flags.h" #define OSZ 00000000040 -#define REXW 00000004000 +#define REXW 00000000100 struct Machine m[1]; struct XedDecodedInst xedd[1]; @@ -38,7 +38,7 @@ TEST(bsr64, test) { uint64_t i, w, x, a, b; for (i = 0; i < ARRAYLEN(kNumbers); ++i) { x = kNumbers[i]; - a = AluBsr(m, REXW, 0, x); + a = AluBsr(m, REXW, x); asm("bsrq\t%2,%0" : "=r"(b), "=@ccz"(zf) : "r"(x)); ASSERT_EQ(zf, GetFlag(m->flags, FLAGS_ZF)); if (!zf) ASSERT_EQ(a, b); @@ -50,7 +50,7 @@ TEST(bsr32, test) { uint32_t i, w, x, a, b; for (i = 0; i < ARRAYLEN(kNumbers); ++i) { x = kNumbers[i]; - a = AluBsr(m, 0, 0, x); + a = AluBsr(m, 0, x); asm("bsrl\t%2,%0" : "=r"(b), "=@ccz"(zf) : "r"(x)); ASSERT_EQ(zf, GetFlag(m->flags, FLAGS_ZF)); if (!zf) ASSERT_EQ(a, b); @@ -62,7 +62,7 @@ TEST(bsr16, test) { uint16_t i, w, x, a, b; for (i = 0; i < ARRAYLEN(kNumbers); ++i) { x = kNumbers[i]; - a = AluBsr(m, OSZ, 0, x); + a = AluBsr(m, OSZ, x); asm("bsrw\t%2,%0" : "=r"(b), "=@ccz"(zf) : "r"(x)); ASSERT_EQ(zf, GetFlag(m->flags, FLAGS_ZF)); if (!zf) ASSERT_EQ(a, b); @@ -74,7 +74,7 @@ TEST(bsf64, test) { uint64_t i, w, x, a, b; for (i = 0; i < ARRAYLEN(kNumbers); ++i) { x = kNumbers[i]; - a = AluBsf(m, REXW, 0, x); + a = AluBsf(m, REXW, x); asm("bsfq\t%2,%0" : "=r"(b), "=@ccz"(zf) : "r"(x)); ASSERT_EQ(zf, GetFlag(m->flags, FLAGS_ZF)); if (!zf) ASSERT_EQ(a, b); @@ -86,7 +86,7 @@ TEST(bsf32, test) { uint32_t i, w, x, a, b; for (i = 0; i < ARRAYLEN(kNumbers); ++i) { x = kNumbers[i]; - a = AluBsf(m, 0, 0, x); + a = AluBsf(m, 0, x); asm("bsfl\t%2,%0" : "=r"(b), "=@ccz"(zf) : "r"(x)); ASSERT_EQ(zf, GetFlag(m->flags, FLAGS_ZF)); if (!zf) ASSERT_EQ(a, b); @@ -98,7 +98,7 @@ TEST(bsf16, test) { uint16_t i, w, x, a, b; for (i = 0; i < ARRAYLEN(kNumbers); ++i) { x = kNumbers[i]; - a = AluBsf(m, OSZ, 0, x); + a = AluBsf(m, OSZ, x); asm("bsfw\t%2,%0" : "=r"(b), "=@ccz"(zf) : "r"(x)); ASSERT_EQ(zf, GetFlag(m->flags, FLAGS_ZF)); if (!zf) ASSERT_EQ(a, b, "%#lx", x); diff --git a/test/tool/build/lib/bsu_test.c b/test/tool/build/lib/bsu_test.c index 75245e53..c30939cb 100644 --- a/test/tool/build/lib/bsu_test.c +++ b/test/tool/build/lib/bsu_test.c @@ -58,6 +58,105 @@ abort(); \ } +int64_t Bsu(int w, int h, uint64_t x, uint64_t y, uint32_t *f) { + switch (h & 7) { + case BSU_SHR: + switch (w) { + case 0: + return Shr8(x, y, f); + case 1: + return Shr16(x, y, f); + case 2: + return Shr32(x, y, f); + case 3: + return Shr64(x, y, f); + default: + unreachable; + } + case BSU_SAL: + case BSU_SHL: + switch (w) { + case 0: + return Shl8(x, y, f); + case 1: + return Shl16(x, y, f); + case 2: + return Shl32(x, y, f); + case 3: + return Shl64(x, y, f); + default: + unreachable; + } + case BSU_SAR: + switch (w) { + case 0: + return Sar8(x, y, f); + case 1: + return Sar16(x, y, f); + case 2: + return Sar32(x, y, f); + case 3: + return Sar64(x, y, f); + default: + unreachable; + } + case BSU_ROL: + switch (w) { + case 0: + return Rol8(x, y, f); + case 1: + return Rol16(x, y, f); + case 2: + return Rol32(x, y, f); + case 3: + return Rol64(x, y, f); + default: + unreachable; + } + case BSU_ROR: + switch (w) { + case 0: + return Ror8(x, y, f); + case 1: + return Ror16(x, y, f); + case 2: + return Ror32(x, y, f); + case 3: + return Ror64(x, y, f); + default: + unreachable; + } + case BSU_RCR: + switch (w) { + case 0: + return Rcr8(x, y, f); + case 1: + return Rcr16(x, y, f); + case 2: + return Rcr32(x, y, f); + case 3: + return Rcr64(x, y, f); + default: + unreachable; + } + case BSU_RCL: + switch (w) { + case 0: + return Rcl8(x, y, f); + case 1: + return Rcl16(x, y, f); + case 2: + return Rcl32(x, y, f); + case 3: + return Rcl64(x, y, f); + default: + unreachable; + } + default: + unreachable; + } +} + int64_t RunGolden(char w, int h, uint64_t x, uint64_t y, uint32_t *f) { switch (h & 7) { case BSU_ROR: diff --git a/test/tool/build/lib/disinst_test.c b/test/tool/build/lib/disinst_test.c index d1e647ff..e96fd182 100644 --- a/test/tool/build/lib/disinst_test.c +++ b/test/tool/build/lib/disinst_test.c @@ -19,6 +19,7 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/testlib/testlib.h" #include "tool/build/lib/dis.h" +#include "tool/build/lib/modrm.h" char b1[64]; char b2[64]; @@ -80,9 +81,144 @@ TEST(DisInst, testPuttingOnTheRiz) { } TEST(DisInst, testSibIndexOnly) { - uint8_t op[] = {76, 141, 4, 141, 0, 0, 0, 0}; /* lea 0x0(,%rcx,4),%r8 */ + uint8_t op[] = {76, 141, 4, 141, 0, 0, 0, 0}; xed_decoded_inst_zero_set_mode(d->xedd, XED_MACHINE_MODE_LONG_64); ASSERT_EQ(0, xed_instruction_length_decode(d->xedd, op, sizeof(op))); DisInst(b, b1, DisSpec(d->xedd, b2)); EXPECT_STREQ("lea 0(,%rcx,4),%r8", b1); } + +TEST(DisInst, testRealMode) { + uint8_t op[] = {0x89, 0xe5}; + xed_decoded_inst_zero_set_mode(d->xedd, XED_MACHINE_MODE_REAL); + ASSERT_EQ(0, xed_instruction_length_decode(d->xedd, op, sizeof(op))); + DisInst(b, b1, DisSpec(d->xedd, b2)); + EXPECT_STREQ("mov %sp,%bp", b1); +} + +TEST(DisInst, testNop) { + uint8_t op[] = {0x66, 0x2e, 0x0f, 0x1f, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00}; + xed_decoded_inst_zero_set_mode(d->xedd, XED_MACHINE_MODE_LONG_64); + ASSERT_EQ(0, xed_instruction_length_decode(d->xedd, op, sizeof(op))); + DisInst(b, b1, DisSpec(d->xedd, b2)); + EXPECT_STREQ("nopw %cs:0(%rax,%rax)", b1); +} + +TEST(DisInst, testPush) { + uint8_t op[] = {0x41, 0x5c}; + xed_decoded_inst_zero_set_mode(d->xedd, XED_MACHINE_MODE_LONG_64); + ASSERT_EQ(0, xed_instruction_length_decode(d->xedd, op, sizeof(op))); + EXPECT_EQ(4, ModrmSrm(d->xedd->op.rde)); + EXPECT_EQ(1, Rexb(d->xedd->op.rde)); + DisInst(b, b1, DisSpec(d->xedd, b2)); + EXPECT_STREQ("pop %r12", b1); +} + +TEST(DisInst, testMovb) { + uint8_t op[] = {0x8a, 0x1e, 0x0c, 0x32}; + xed_decoded_inst_zero_set_mode(d->xedd, XED_MACHINE_MODE_LONG_64); + ASSERT_EQ(0, xed_instruction_length_decode(d->xedd, op, sizeof(op))); + DisInst(b, b1, DisSpec(d->xedd, b2)); + EXPECT_STREQ("mov (%rsi),%bl", b1); + xed_decoded_inst_zero_set_mode(d->xedd, XED_MACHINE_MODE_REAL); + ASSERT_EQ(0, xed_instruction_length_decode(d->xedd, op, sizeof(op))); + DisInst(b, b1, DisSpec(d->xedd, b2)); + EXPECT_STREQ("mov 0x320c,%bl", b1); +} + +TEST(DisInst, testLes) { + uint8_t op[] = {0xc4, 0x3e, 0x16, 0x32}; + xed_decoded_inst_zero_set_mode(d->xedd, XED_MACHINE_MODE_REAL); + ASSERT_EQ(0, xed_instruction_length_decode(d->xedd, op, sizeof(op))); + DisInst(b, b1, DisSpec(d->xedd, b2)); + EXPECT_STREQ("les 0x3216,%di", b1); +} + +TEST(DisInst, testStosbLong) { + uint8_t op[] = {0xAA}; + xed_decoded_inst_zero_set_mode(d->xedd, XED_MACHINE_MODE_LONG_64); + ASSERT_EQ(0, xed_instruction_length_decode(d->xedd, op, sizeof(op))); + DisInst(b, b1, DisSpec(d->xedd, b2)); + EXPECT_STREQ("stosb %al,(%rdi)", b1); +} + +TEST(DisInst, testStosbReal) { + uint8_t op[] = {0xAA}; + xed_decoded_inst_zero_set_mode(d->xedd, XED_MACHINE_MODE_REAL); + ASSERT_EQ(0, xed_instruction_length_decode(d->xedd, op, sizeof(op))); + DisInst(b, b1, DisSpec(d->xedd, b2)); + EXPECT_STREQ("stosb %al,(%di)", b1); +} + +TEST(DisInst, testStosbLegacy) { + uint8_t op[] = {0xAA}; + xed_decoded_inst_zero_set_mode(d->xedd, XED_MACHINE_MODE_LEGACY_32); + ASSERT_EQ(0, xed_instruction_length_decode(d->xedd, op, sizeof(op))); + DisInst(b, b1, DisSpec(d->xedd, b2)); + EXPECT_STREQ("stosb %al,(%edi)", b1); +} + +TEST(DisInst, testStosbLongAsz) { + uint8_t op[] = {0x67, 0xAA}; + xed_decoded_inst_zero_set_mode(d->xedd, XED_MACHINE_MODE_LONG_64); + ASSERT_EQ(0, xed_instruction_length_decode(d->xedd, op, sizeof(op))); + DisInst(b, b1, DisSpec(d->xedd, b2)); + EXPECT_STREQ("stosb %al,(%edi)", b1); +} + +TEST(DisInst, testAddLong) { + uint8_t op[] = {0x01, 0xff}; + xed_decoded_inst_zero_set_mode(d->xedd, XED_MACHINE_MODE_LONG_64); + ASSERT_EQ(0, xed_instruction_length_decode(d->xedd, op, sizeof(op))); + DisInst(b, b1, DisSpec(d->xedd, b2)); + EXPECT_STREQ("add %edi,%edi", b1); +} + +TEST(DisInst, testAddLegacy) { + uint8_t op[] = {0x01, 0xff}; + xed_decoded_inst_zero_set_mode(d->xedd, XED_MACHINE_MODE_LEGACY_32); + ASSERT_EQ(0, xed_instruction_length_decode(d->xedd, op, sizeof(op))); + DisInst(b, b1, DisSpec(d->xedd, b2)); + EXPECT_STREQ("add %edi,%edi", b1); +} + +TEST(DisInst, testAddReal) { + uint8_t op[] = {0x01, 0xff}; + xed_decoded_inst_zero_set_mode(d->xedd, XED_MACHINE_MODE_REAL); + ASSERT_EQ(0, xed_instruction_length_decode(d->xedd, op, sizeof(op))); + DisInst(b, b1, DisSpec(d->xedd, b2)); + EXPECT_STREQ("add %di,%di", b1); +} + +TEST(DisInst, testAddLongOsz) { + uint8_t op[] = {0x66, 0x01, 0xff}; + xed_decoded_inst_zero_set_mode(d->xedd, XED_MACHINE_MODE_LONG_64); + ASSERT_EQ(0, xed_instruction_length_decode(d->xedd, op, sizeof(op))); + DisInst(b, b1, DisSpec(d->xedd, b2)); + EXPECT_STREQ("add %di,%di", b1); +} + +TEST(DisInst, testAddLegacyOsz) { + uint8_t op[] = {0x66, 0x01, 0xff}; + xed_decoded_inst_zero_set_mode(d->xedd, XED_MACHINE_MODE_LEGACY_32); + ASSERT_EQ(0, xed_instruction_length_decode(d->xedd, op, sizeof(op))); + DisInst(b, b1, DisSpec(d->xedd, b2)); + EXPECT_STREQ("add %di,%di", b1); +} + +TEST(DisInst, testAddRealOsz) { + uint8_t op[] = {0x66, 0x01, 0xff}; + xed_decoded_inst_zero_set_mode(d->xedd, XED_MACHINE_MODE_REAL); + ASSERT_EQ(0, xed_instruction_length_decode(d->xedd, op, sizeof(op))); + DisInst(b, b1, DisSpec(d->xedd, b2)); + EXPECT_STREQ("add %edi,%edi", b1); +} + +TEST(DisInst, testFxam) { + uint8_t op[] = {0xd9, 0xe5}; + xed_decoded_inst_zero_set_mode(d->xedd, XED_MACHINE_MODE_LONG_64); + ASSERT_EQ(0, xed_instruction_length_decode(d->xedd, op, sizeof(op))); + ASSERT_EQ(4, ModrmReg(d->xedd->op.rde)); + DisInst(b, b1, DisSpec(d->xedd, b2)); + EXPECT_STREQ("fxam ", b1); +} diff --git a/test/tool/build/lib/divmul_test.c b/test/tool/build/lib/divmul_test.c index cce414d7..6f85b542 100644 --- a/test/tool/build/lib/divmul_test.c +++ b/test/tool/build/lib/divmul_test.c @@ -32,8 +32,8 @@ #define CX 1 #define OSZ 00000000040 -#define REXW 00000004000 -#define RM(x) (0000000700 & ((x) << 006)) +#define REXW 00000000100 +#define RM(x) (0000001600 & ((x) << 007)) #define MOD(x) (0060000000 & ((x) << 026)) jmp_buf sigfpejmp; diff --git a/test/tool/build/lib/machine_test.c b/test/tool/build/lib/machine_test.c index 89ec4946..aac04266 100644 --- a/test/tool/build/lib/machine_test.c +++ b/test/tool/build/lib/machine_test.c @@ -106,6 +106,7 @@ struct Machine *m; void SetUp(void) { base = 0; m = NewMachine(); + m->cr3 = MallocPage(); realsize = 0x10000; real = tmemalign(PAGESIZE, ROUNDUP(realsize, PAGESIZE)); RegisterMemory(m, base, real, realsize); @@ -115,6 +116,7 @@ void SetUp(void) { void TearDown(void) { ResetRam(m); + free(m->cr3); tfree(real); free(m); } @@ -294,5 +296,34 @@ BENCH(machine, benchNop) { } TEST(machine, sizeIsReasonable) { - ASSERT_LE(sizeof(struct Machine), 65536 * 2); + ASSERT_LE(sizeof(struct Machine), 65536 * 3); +} + +TEST(x87, fprem1) { + // 1 rem -1.5 + const uint8_t prog[] = { + 0xd9, 0x05, 0x05, 0x00, 0x00, 0x00, // flds + 0xd9, 0xe8, // fld1 + 0xd9, 0xf8, // fprem + 0xf4, // hlt + 0x00, 0x00, 0xc0, 0xbf, // .float -1.5 + }; + memcpy(real, prog, sizeof(prog)); + ASSERT_EQ(kMachineHalt, ExecuteUntilHalt(m)); + ASSERT_LDBL_EQ(1, FpuPop(m)); +} + +TEST(x87, fprem2) { + // 12300000000000000. rem .0000000000000123 + const uint8_t prog[] = { + 0xdd, 0x05, 0x11, 0x00, 0x00, 0x00, // fldl + 0xdd, 0x05, 0x03, 0x00, 0x00, 0x00, // fldl + 0xd9, 0xf8, // fprem + 0xf4, // hlt + 0x00, 0x60, 0x5e, 0x75, 0x64, 0xd9, 0x45, 0x43, // + 0x5b, 0x14, 0xea, 0x9d, 0x77, 0xb2, 0x0b, 0x3d, // + }; + memcpy(real, prog, sizeof(prog)); + ASSERT_EQ(kMachineHalt, ExecuteUntilHalt(m)); + ASSERT_LDBL_EQ(1.1766221079117338e-14, FpuPop(m)); } diff --git a/test/tool/build/lib/modrm_test.c b/test/tool/build/lib/modrm_test.c index 89faba18..eed8c61b 100644 --- a/test/tool/build/lib/modrm_test.c +++ b/test/tool/build/lib/modrm_test.c @@ -88,6 +88,7 @@ TEST(modrm, testPuttingOnTheRiz) { } TEST(modrm, testSibIndexOnly) { + // lea 0x0(,%rcx,4),%r8 // mod = 0b00 (0) // reg = 0b000 (0) // rm = 0b100 (4) @@ -96,11 +97,16 @@ TEST(modrm, testSibIndexOnly) { // base = 0b101 (5) struct Machine *m = gc(NewMachine()); struct XedDecodedInst *xedd = gc(calloc(1, sizeof(struct XedDecodedInst))); - uint8_t op[] = {76, 141, 4, 141, 0, 0, 0, 0}; /* lea 0x0(,%rcx,4),%r8 */ + uint8_t op[] = {0x4c, 0x8d, 0x04, 0x8d, 0, 0, 0, 0}; m->xedd = xedd; Write64(m->bp, 0x123); Write64(m->cx, 0x123); xed_decoded_inst_zero_set_mode(xedd, XED_MACHINE_MODE_LONG_64); ASSERT_EQ(0, xed_instruction_length_decode(xedd, op, sizeof(op))); + EXPECT_TRUE(Rexw(m->xedd->op.rde)); + EXPECT_TRUE(Rexr(m->xedd->op.rde)); + EXPECT_FALSE(Rexb(m->xedd->op.rde)); + EXPECT_EQ(0b000, ModrmReg(m->xedd->op.rde)); + EXPECT_EQ(0b100, ModrmRm(m->xedd->op.rde)); EXPECT_EQ(0x123 * 4, (uint64_t)ComputeAddress(m, m->xedd->op.rde)); } diff --git a/third_party/dlmalloc/bulk_free.c b/third_party/dlmalloc/bulk_free.c index 656f8232..60e0d57b 100644 --- a/third_party/dlmalloc/bulk_free.c +++ b/third_party/dlmalloc/bulk_free.c @@ -18,7 +18,7 @@ size_t bulk_free(void *array[], size_t nelem) { * if allocated with ialloc or the array is sorted. */ size_t unfreed = 0; - if (!PREACTION(gm)) { + if (!PREACTION(g_dlmalloc)) { void **a; void **fence = &(array[nelem]); for (a = array; a != fence; ++a) { @@ -27,30 +27,32 @@ size_t bulk_free(void *array[], size_t nelem) { mchunkptr p = mem2chunk(ADDRESS_DEATH_ACTION(mem)); size_t psize = chunksize(p); #if FOOTERS - if (get_mstate_for(p) != gm) { + if (get_mstate_for(p) != g_dlmalloc) { ++unfreed; continue; } #endif - check_inuse_chunk(gm, p); + check_inuse_chunk(g_dlmalloc, p); *a = 0; - if (RTCHECK(ok_address(gm, p) && ok_inuse(p))) { + if (RTCHECK(ok_address(g_dlmalloc, p) && ok_inuse(p))) { void **b = a + 1; /* try to merge with next chunk */ mchunkptr next = next_chunk(p); if (b != fence && *b == chunk2mem(next)) { size_t newsize = chunksize(next) + psize; - set_inuse(gm, p, newsize); + set_inuse(g_dlmalloc, p, newsize); *b = chunk2mem(p); } else - dlmalloc_dispose_chunk(gm, p, psize); + dlmalloc_dispose_chunk(g_dlmalloc, p, psize); } else { - CORRUPTION_ERROR_ACTION(gm); + CORRUPTION_ERROR_ACTION(g_dlmalloc); break; } } } - if (should_trim(gm, gm->topsize)) dlmalloc_sys_trim(gm, 0); - POSTACTION(gm); + if (should_trim(g_dlmalloc, g_dlmalloc->topsize)) { + dlmalloc_sys_trim(g_dlmalloc, 0); + } + POSTACTION(g_dlmalloc); } return unfreed; } diff --git a/third_party/dlmalloc/dlcalloc.c b/third_party/dlmalloc/dlcalloc.c new file mode 100644 index 00000000..1d61b9d4 --- /dev/null +++ b/third_party/dlmalloc/dlcalloc.c @@ -0,0 +1,11 @@ +#include "libc/str/str.h" +#include "third_party/dlmalloc/dlmalloc.h" + +void *dlcalloc(size_t n_elements, size_t elem_size) { + void *mem; + size_t req; + if (__builtin_mul_overflow(n_elements, elem_size, &req)) req = -1; + mem = dlmalloc(req); + if (mem != 0 && calloc_must_clear(mem2chunk(mem))) memset(mem, 0, req); + return mem; +} diff --git a/third_party/dlmalloc/dlindependent_calloc.c b/third_party/dlmalloc/dlindependent_calloc.c index 56772a04..85fe045a 100644 --- a/third_party/dlmalloc/dlindependent_calloc.c +++ b/third_party/dlmalloc/dlindependent_calloc.c @@ -164,7 +164,7 @@ static void **ialloc(mstate m, size_t n_elements, size_t *sizes, int opts, void **dlindependent_calloc(size_t n_elements, size_t elem_size, void *chunks[]) { size_t sz = elem_size; /* serves as 1-element array */ - return ialloc(gm, n_elements, &sz, 3, chunks); + return ialloc(g_dlmalloc, n_elements, &sz, 3, chunks); } /** @@ -224,5 +224,5 @@ void **dlindependent_calloc(size_t n_elements, size_t elem_size, */ void **dlindependent_comalloc(size_t n_elements, size_t sizes[], void *chunks[]) { - return ialloc(gm, n_elements, sizes, 0, chunks); + return ialloc(g_dlmalloc, n_elements, sizes, 0, chunks); } diff --git a/third_party/dlmalloc/dlmalloc-debug.c b/third_party/dlmalloc/dlmalloc-debug.c index 2b7a1823..6111165f 100644 --- a/third_party/dlmalloc/dlmalloc-debug.c +++ b/third_party/dlmalloc/dlmalloc-debug.c @@ -29,7 +29,7 @@ void do_check_mmapped_chunk(mstate m, mchunkptr p) { assert((is_aligned(chunk2mem(p))) || (p->head == FENCEPOST_HEAD)); assert(ok_address(m, p)); assert(!is_small(sz)); - assert((len & (mparams.page_size - SIZE_T_ONE)) == 0); + assert((len & (g_mparams.page_size - SIZE_T_ONE)) == 0); assert(chunk_plus_offset(p, sz)->head == FENCEPOST_HEAD); assert(chunk_plus_offset(p, sz + SIZE_T_SIZE)->head == 0); } @@ -222,7 +222,7 @@ static size_t traverse_and_check(mstate m) { return sum; } -/* Check all properties of malloc_state. */ +/* Check all properties of MallocState. */ void do_check_malloc_state(mstate m) { bindex_t i; size_t total; diff --git a/third_party/dlmalloc/dlmalloc.c b/third_party/dlmalloc/dlmalloc.c index cb75f6e2..8699b5cd 100644 --- a/third_party/dlmalloc/dlmalloc.c +++ b/third_party/dlmalloc/dlmalloc.c @@ -19,10 +19,10 @@ STATIC_YOINK("_init_dlmalloc"); #define OOM_WARNING "warning: running out of physical memory\n" -#define is_global(M) ((M) == &_gm_) +#define is_global(M) ((M) == g_dlmalloc) -struct malloc_params mparams; -struct malloc_state _gm_; +struct MallocState g_dlmalloc[1]; +struct MallocParams g_mparams; /** * Acquires more system memory for dlmalloc. @@ -63,7 +63,7 @@ static void dlmalloc_init_top(mstate m, mchunkptr p, size_t psize) { p->head = psize | PINUSE_BIT; /* set size of fake trailing chunk holding overhead space only once */ chunk_plus_offset(p, psize)->head = TOP_FOOT_SIZE; - m->trim_check = mparams.trim_threshold; /* reset on each update */ + m->trim_check = g_mparams.trim_threshold; /* reset on each update */ } /* Initialize bins for a new mstate that is otherwise zeroed out */ @@ -184,10 +184,6 @@ static int has_segment_link(mstate m, msegmentptr ss) { /* For sys_alloc, enough padding to ensure can malloc request on success */ #define SYS_ALLOC_PADDING (TOP_FOOT_SIZE + MALLOC_ALIGNMENT) -static size_t mmap_align(size_t s) { - return granularity_align(s); -} - /* Malloc using mmap */ static void *mmap_alloc(mstate m, size_t nb) { size_t mmsize = mmap_align(nb + SIX_SIZE_T_SIZES + CHUNK_ALIGN_MASK); @@ -217,41 +213,10 @@ static void *mmap_alloc(mstate m, size_t nb) { return 0; } -/* Realloc using mmap */ -static mchunkptr mmap_resize(mstate m, mchunkptr oldp, size_t nb, int flags) { - size_t oldsize = chunksize(oldp); - if (is_small(nb)) return 0; /* Can't shrink mmap regions below small size */ - /* Keep old chunk if big enough but not too big */ - if (oldsize >= nb + SIZE_T_SIZE && - (oldsize - nb) <= (mparams.granularity << 1)) { - return oldp; - } else { - size_t offset = oldp->prev_foot; - size_t oldmmsize = oldsize + offset + MMAP_FOOT_PAD; - size_t newmmsize = mmap_align(nb + SIX_SIZE_T_SIZES + CHUNK_ALIGN_MASK); - char *cp = mremap((char *)oldp - offset, oldmmsize, newmmsize, flags, 0); - if (cp != CMFAIL) { - mchunkptr newp = (mchunkptr)(cp + offset); - size_t psize = newmmsize - offset - MMAP_FOOT_PAD; - newp->head = psize; - mark_inuse_foot(m, newp, psize); - chunk_plus_offset(newp, psize)->head = FENCEPOST_HEAD; - chunk_plus_offset(newp, psize + SIZE_T_SIZE)->head = 0; - if (cp < m->least_addr) m->least_addr = cp; - if ((m->footprint += newmmsize - oldmmsize) > m->max_footprint) { - m->max_footprint = m->footprint; - } - check_mmapped_chunk(m, newp); - return newp; - } - } - return 0; -} - /** * Gets memory from system. */ -void *sys_alloc(mstate m, size_t nb) { +static void *dlmalloc_sys_alloc(mstate m, size_t nb) { char *tbase = CMFAIL; size_t tsize = 0; flag_t mmap_flag = 0; @@ -260,7 +225,7 @@ void *sys_alloc(mstate m, size_t nb) { ensure_initialization(); /* Directly map large chunks, but only if already initialized */ - if (use_mmap(m) && nb >= mparams.mmap_threshold && m->topsize != 0) { + if (use_mmap(m) && nb >= g_mparams.mmap_threshold && m->topsize != 0) { void *mem = mmap_alloc(m, nb); if (mem != 0) return mem; } @@ -290,13 +255,13 @@ void *sys_alloc(mstate m, size_t nb) { m->seg.base = tbase; m->seg.size = tsize; m->seg.sflags = mmap_flag; - m->magic = mparams.magic; + m->magic = g_mparams.magic; m->release_checks = MAX_RELEASE_CHECK_RATE; init_bins(m); if (is_global(m)) { dlmalloc_init_top(m, (mchunkptr)tbase, tsize - TOP_FOOT_SIZE); } else { - /* Offset top by embedded malloc_state */ + /* Offset top by embedded MallocState */ mchunkptr mn = next_chunk(mem2chunk(m)); dlmalloc_init_top( m, mn, (size_t)((tbase + tsize) - (char *)mn) - TOP_FOOT_SIZE); @@ -401,7 +366,7 @@ int dlmalloc_sys_trim(mstate m, size_t pad) { pad += TOP_FOOT_SIZE; /* ensure enough room for segment overhead */ if (m->topsize > pad) { /* Shrink top space in granularity-size units, keeping at least one */ - size_t unit = mparams.granularity; + size_t unit = g_mparams.granularity; size_t extra = ((m->topsize - pad + (unit - SIZE_T_ONE)) / unit - SIZE_T_ONE) * unit; msegmentptr sp = segment_holding(m, (char *)m->top); @@ -438,13 +403,13 @@ int dlmalloc_sys_trim(mstate m, size_t pad) { #if LOCK_AT_FORK static void pre_fork(void) { - ACQUIRE_LOCK(&(gm)->mutex); + ACQUIRE_LOCK(&(g_dlmalloc)->mutex); } static void post_fork_parent(void) { - RELEASE_LOCK(&(gm)->mutex); + RELEASE_LOCK(&(g_dlmalloc)->mutex); } static void post_fork_child(void) { - INITIAL_LOCK(&(gm)->mutex); + INITIAL_LOCK(&(g_dlmalloc)->mutex); } #endif /* LOCK_AT_FORK */ @@ -453,7 +418,7 @@ static void post_fork_child(void) { /* Consolidate and bin a chunk. Differs from exported versions of free mainly in that the chunk need not be marked as inuse. */ -hidden void dlmalloc_dispose_chunk(mstate m, mchunkptr p, size_t psize) { +void dlmalloc_dispose_chunk(mstate m, mchunkptr p, size_t psize) { mchunkptr next = chunk_plus_offset(p, psize); if (!pinuse(p)) { mchunkptr prev; @@ -646,7 +611,7 @@ void *dlmalloc(size_t bytes) { ensure_initialization(); /* initialize in sys_alloc if not using locks */ #endif - if (!PREACTION(gm)) { + if (!PREACTION(g_dlmalloc)) { void *mem; size_t nb; if (bytes <= MAX_SMALL_REQUEST) { @@ -654,22 +619,22 @@ void *dlmalloc(size_t bytes) { binmap_t smallbits; nb = (bytes < MIN_REQUEST) ? MIN_CHUNK_SIZE : pad_request(bytes); idx = small_index(nb); - smallbits = gm->smallmap >> idx; + smallbits = g_dlmalloc->smallmap >> idx; if ((smallbits & 0x3U) != 0) { /* Remainderless fit to a smallbin. */ mchunkptr b, p; idx += ~smallbits & 1; /* Uses next bin if idx empty */ - b = smallbin_at(gm, idx); + b = smallbin_at(g_dlmalloc, idx); p = b->fd; assert(chunksize(p) == small_index2size(idx)); - unlink_first_small_chunk(gm, b, p, idx); - set_inuse_and_pinuse(gm, p, small_index2size(idx)); + unlink_first_small_chunk(g_dlmalloc, b, p, idx); + set_inuse_and_pinuse(g_dlmalloc, p, small_index2size(idx)); mem = chunk2mem(p); - check_malloced_chunk(gm, mem, nb); + check_malloced_chunk(g_dlmalloc, mem, nb); goto postaction; } - else if (nb > gm->dvsize) { + else if (nb > g_dlmalloc->dvsize) { if (smallbits != 0) { /* Use chunk in next nonempty smallbin */ mchunkptr b, p, r; size_t rsize; @@ -677,27 +642,28 @@ void *dlmalloc(size_t bytes) { binmap_t leftbits = (smallbits << idx) & left_bits(idx2bit(idx)); binmap_t leastbit = least_bit(leftbits); compute_bit2idx(leastbit, i); - b = smallbin_at(gm, i); + b = smallbin_at(g_dlmalloc, i); p = b->fd; assert(chunksize(p) == small_index2size(i)); - unlink_first_small_chunk(gm, b, p, i); + unlink_first_small_chunk(g_dlmalloc, b, p, i); rsize = small_index2size(i) - nb; /* Fit here cannot be remainderless if 4byte sizes */ if (SIZE_T_SIZE != 4 && rsize < MIN_CHUNK_SIZE) - set_inuse_and_pinuse(gm, p, small_index2size(i)); + set_inuse_and_pinuse(g_dlmalloc, p, small_index2size(i)); else { - set_size_and_pinuse_of_inuse_chunk(gm, p, nb); + set_size_and_pinuse_of_inuse_chunk(g_dlmalloc, p, nb); r = chunk_plus_offset(p, nb); set_size_and_pinuse_of_free_chunk(r, rsize); - replace_dv(gm, r, rsize); + replace_dv(g_dlmalloc, r, rsize); } mem = chunk2mem(p); - check_malloced_chunk(gm, mem, nb); + check_malloced_chunk(g_dlmalloc, mem, nb); goto postaction; } - else if (gm->treemap != 0 && (mem = tmalloc_small(gm, nb)) != 0) { - check_malloced_chunk(gm, mem, nb); + else if (g_dlmalloc->treemap != 0 && + (mem = tmalloc_small(g_dlmalloc, nb)) != 0) { + check_malloced_chunk(g_dlmalloc, mem, nb); goto postaction; } } @@ -705,55 +671,54 @@ void *dlmalloc(size_t bytes) { nb = SIZE_MAX; /* Too big to allocate. Force failure (in sys alloc) */ } else { nb = pad_request(bytes); - if (gm->treemap != 0 && (mem = tmalloc_large(gm, nb)) != 0) { - check_malloced_chunk(gm, mem, nb); + if (g_dlmalloc->treemap != 0 && + (mem = tmalloc_large(g_dlmalloc, nb)) != 0) { + check_malloced_chunk(g_dlmalloc, mem, nb); goto postaction; } } - if (nb <= gm->dvsize) { - size_t rsize = gm->dvsize - nb; - mchunkptr p = gm->dv; + if (nb <= g_dlmalloc->dvsize) { + size_t rsize = g_dlmalloc->dvsize - nb; + mchunkptr p = g_dlmalloc->dv; if (rsize >= MIN_CHUNK_SIZE) { /* split dv */ - mchunkptr r = gm->dv = chunk_plus_offset(p, nb); - gm->dvsize = rsize; + mchunkptr r = g_dlmalloc->dv = chunk_plus_offset(p, nb); + g_dlmalloc->dvsize = rsize; set_size_and_pinuse_of_free_chunk(r, rsize); - set_size_and_pinuse_of_inuse_chunk(gm, p, nb); + set_size_and_pinuse_of_inuse_chunk(g_dlmalloc, p, nb); } else { /* exhaust dv */ - size_t dvs = gm->dvsize; - gm->dvsize = 0; - gm->dv = 0; - set_inuse_and_pinuse(gm, p, dvs); + size_t dvs = g_dlmalloc->dvsize; + g_dlmalloc->dvsize = 0; + g_dlmalloc->dv = 0; + set_inuse_and_pinuse(g_dlmalloc, p, dvs); } mem = chunk2mem(p); - check_malloced_chunk(gm, mem, nb); + check_malloced_chunk(g_dlmalloc, mem, nb); goto postaction; } - else if (nb < gm->topsize) { /* Split top */ - size_t rsize = gm->topsize -= nb; - mchunkptr p = gm->top; - mchunkptr r = gm->top = chunk_plus_offset(p, nb); + else if (nb < g_dlmalloc->topsize) { /* Split top */ + size_t rsize = g_dlmalloc->topsize -= nb; + mchunkptr p = g_dlmalloc->top; + mchunkptr r = g_dlmalloc->top = chunk_plus_offset(p, nb); r->head = rsize | PINUSE_BIT; - set_size_and_pinuse_of_inuse_chunk(gm, p, nb); + set_size_and_pinuse_of_inuse_chunk(g_dlmalloc, p, nb); mem = chunk2mem(p); - check_top_chunk(gm, gm->top); - check_malloced_chunk(gm, mem, nb); + check_top_chunk(g_dlmalloc, g_dlmalloc->top); + check_malloced_chunk(g_dlmalloc, mem, nb); goto postaction; } - mem = sys_alloc(gm, nb); + mem = dlmalloc_sys_alloc(g_dlmalloc, nb); postaction: - POSTACTION(gm); + POSTACTION(g_dlmalloc); return ADDRESS_BIRTH_ACTION(mem); } return 0; } -/* ──────────────────────────── free ─────────────────────────── */ - void dlfree(void *mem) { /* Consolidate freed chunks with preceeding or succeeding bordering @@ -775,7 +740,7 @@ void dlfree(void *mem) { return; } #else /* FOOTERS */ -#define fm gm +#define fm g_dlmalloc #endif /* FOOTERS */ if (!PREACTION(fm)) { @@ -834,8 +799,9 @@ void dlfree(void *mem) { goto postaction; } } - } else + } else { set_free_with_pinuse(p, psize, next); + } if (is_small(psize)) { insert_small_chunk(fm, p, psize); @@ -860,151 +826,12 @@ void dlfree(void *mem) { #endif /* FOOTERS */ } -/** - * Multiplies sizes w/ saturation and overflow detection. - * - * @param count may be 0 to for realloc() → free() behavior - * @param opt_out set to count*itemsize or SIZE_MAX on overflow - * @return true on success or false on overflow - */ -static bool sizemultiply(size_t *opt_out, size_t count, size_t itemsize) { - size_t result; - bool overflowed; - overflowed = __builtin_mul_overflow(count, itemsize, &result); - if (overflowed) result = SIZE_MAX; - if (opt_out) *opt_out = result; - return !overflowed; -} - -void *dlcalloc(size_t n_elements, size_t elem_size) { - void *mem; - size_t req; - sizemultiply(&req, n_elements, elem_size); /* punts error */ - mem = dlmalloc(req); - if (mem != 0 && calloc_must_clear(mem2chunk(mem))) memset(mem, 0, req); - return mem; -} - -/* ──────────── Internal support for realloc, memalign, etc ────────────── */ - -/* Try to realloc; only in-place unless can_move true */ -hidden mchunkptr dlmalloc_try_realloc_chunk(mstate m, mchunkptr p, size_t nb, - int can_move) { - mchunkptr newp = 0; - size_t oldsize = chunksize(p); - mchunkptr next = chunk_plus_offset(p, oldsize); - if (RTCHECK(ok_address(m, p) && ok_inuse(p) && ok_next(p, next) && - ok_pinuse(next))) { - if (is_mmapped(p)) { - newp = mmap_resize(m, p, nb, can_move); - } else if (oldsize >= nb) { /* already big enough */ - size_t rsize = oldsize - nb; - if (rsize >= MIN_CHUNK_SIZE) { /* split off remainder */ - mchunkptr r = chunk_plus_offset(p, nb); - set_inuse(m, p, nb); - set_inuse(m, r, rsize); - dlmalloc_dispose_chunk(m, r, rsize); - } - newp = p; - } else if (next == m->top) { /* extend into top */ - if (oldsize + m->topsize > nb) { - size_t newsize = oldsize + m->topsize; - size_t newtopsize = newsize - nb; - mchunkptr newtop = chunk_plus_offset(p, nb); - set_inuse(m, p, nb); - newtop->head = newtopsize | PINUSE_BIT; - m->top = newtop; - m->topsize = newtopsize; - newp = p; - } - } else if (next == m->dv) { /* extend into dv */ - size_t dvs = m->dvsize; - if (oldsize + dvs >= nb) { - size_t dsize = oldsize + dvs - nb; - if (dsize >= MIN_CHUNK_SIZE) { - mchunkptr r = chunk_plus_offset(p, nb); - mchunkptr n = chunk_plus_offset(r, dsize); - set_inuse(m, p, nb); - set_size_and_pinuse_of_free_chunk(r, dsize); - clear_pinuse(n); - m->dvsize = dsize; - m->dv = r; - } else { /* exhaust dv */ - size_t newsize = oldsize + dvs; - set_inuse(m, p, newsize); - m->dvsize = 0; - m->dv = 0; - } - newp = p; - } - } else if (!cinuse(next)) { /* extend into next free chunk */ - size_t nextsize = chunksize(next); - if (oldsize + nextsize >= nb) { - size_t rsize = oldsize + nextsize - nb; - unlink_chunk(m, next, nextsize); - if (rsize < MIN_CHUNK_SIZE) { - size_t newsize = oldsize + nextsize; - set_inuse(m, p, newsize); - } else { - mchunkptr r = chunk_plus_offset(p, nb); - set_inuse(m, p, nb); - set_inuse(m, r, rsize); - dlmalloc_dispose_chunk(m, r, rsize); - } - newp = p; - } - } - } else { - USAGE_ERROR_ACTION(m, chunk2mem(p)); - } - return newp; -} - -void *dlrealloc(void *oldmem, size_t bytes) { - void *mem = 0; - if (oldmem == 0) { - mem = dlmalloc(bytes); - } else if (bytes >= MAX_REQUEST) { - enomem(); - } else if (bytes == 0) { - dlfree(oldmem); - } else { - size_t nb = request2size(bytes); - mchunkptr oldp = mem2chunk(oldmem); -#if !FOOTERS - mstate m = gm; -#else /* FOOTERS */ - mstate m = get_mstate_for(oldp); - if (!ok_magic(m)) { - USAGE_ERROR_ACTION(m, oldmem); - return 0; - } -#endif /* FOOTERS */ - if (!PREACTION(m)) { - mchunkptr newp = dlmalloc_try_realloc_chunk(m, oldp, nb, 1); - POSTACTION(m); - if (newp != 0) { - check_inuse_chunk(m, newp); - mem = chunk2mem(newp); - } else { - mem = dlmalloc(bytes); - if (mem != 0) { - size_t oc = chunksize(oldp) - overhead_for(oldp); - memcpy(mem, oldmem, (oc < bytes) ? oc : bytes); - dlfree(oldmem); - } - } - } - } - return mem; -} - textstartup void dlmalloc_init(void) { #ifdef NEED_GLOBAL_LOCK_INIT if (malloc_global_mutex_status <= 0) init_malloc_global_mutex(); #endif ACQUIRE_MALLOC_GLOBAL_LOCK(); - if (mparams.magic == 0) { + if (g_mparams.magic == 0) { size_t magic; size_t psize = PAGESIZE; size_t gsize = MAX(g_ntsysteminfo.dwAllocationGranularity, 64 * 1024); @@ -1021,15 +848,15 @@ textstartup void dlmalloc_init(void) { ((gsize & (gsize - SIZE_T_ONE)) != 0) || ((psize & (psize - SIZE_T_ONE)) != 0)) MALLOC_ABORT; - mparams.granularity = gsize; - mparams.page_size = psize; - mparams.mmap_threshold = DEFAULT_MMAP_THRESHOLD; - mparams.trim_threshold = DEFAULT_TRIM_THRESHOLD; - mparams.default_mflags = + g_mparams.granularity = gsize; + g_mparams.page_size = psize; + g_mparams.mmap_threshold = DEFAULT_MMAP_THRESHOLD; + g_mparams.trim_threshold = DEFAULT_TRIM_THRESHOLD; + g_mparams.default_mflags = USE_LOCK_BIT | USE_MMAP_BIT | USE_NONCONTIGUOUS_BIT; /* Set up lock for main malloc area */ - gm->mflags = mparams.default_mflags; - (void)INITIAL_LOCK(&gm->mutex); + g_dlmalloc->mflags = g_mparams.default_mflags; + (void)INITIAL_LOCK(&g_dlmalloc->mutex); #if LOCK_AT_FORK pthread_atfork(&pre_fork, &post_fork_parent, &post_fork_child); #endif @@ -1037,7 +864,7 @@ textstartup void dlmalloc_init(void) { magic |= (size_t)8U; /* ensure nonzero */ magic &= ~(size_t)7U; /* improve chances of fault for bad values */ /* Until memory modes commonly available, use volatile-write */ - (*(volatile size_t *)(&(mparams.magic))) = magic; + (*(volatile size_t *)(&(g_mparams.magic))) = magic; } RELEASE_MALLOC_GLOBAL_LOCK(); } diff --git a/third_party/dlmalloc/dlmalloc.h b/third_party/dlmalloc/dlmalloc.h index bc718a12..b8963288 100644 --- a/third_party/dlmalloc/dlmalloc.h +++ b/third_party/dlmalloc/dlmalloc.h @@ -553,10 +553,10 @@ struct malloc_segment { typedef struct malloc_segment msegment; typedef struct malloc_segment *msegmentptr; -/* ──────────────────────────── malloc_state ───────────────────────────── */ +/* ──────────────────────────── MallocState ───────────────────────────── */ /* - A malloc_state holds all of the bookkeeping for a space. + A MallocState holds all of the bookkeeping for a space. The main fields are: Top @@ -640,7 +640,7 @@ typedef struct malloc_segment *msegmentptr; extensions to this malloc. */ -struct malloc_state { +struct MallocState { binmap_t smallmap; binmap_t treemap; size_t dvsize; @@ -657,22 +657,21 @@ struct malloc_state { size_t max_footprint; size_t footprint_limit; /* zero means no limit */ flag_t mflags; - msegment seg; void *extp; /* Unused but available for extensions */ size_t exts; }; -#define gm (&_gm_) -extern struct malloc_state _gm_; -typedef struct malloc_state *mstate; - struct MallocStats { size_t maxfp; size_t fp; size_t used; }; +typedef struct MallocState *mstate; + +extern struct MallocState g_dlmalloc[1]; + /* ─────────────────────────────── Hooks ──────────────────────────────── */ #ifdef MTRACE /* TODO(jart): Add --mtrace flag for this */ @@ -718,16 +717,16 @@ void *AddressDeathAction(void *); (align_offset(chunk2mem(0)) + pad_request(sizeof(struct malloc_segment)) + \ MIN_CHUNK_SIZE) -/* ───────────── Global malloc_state and malloc_params ─────────────────── */ +/* ───────────── Global MallocState and MallocParams ─────────────────── */ /* - malloc_params holds global properties, including those that can be + MallocParams holds global properties, including those that can be dynamically set using mallopt. There is a single instance, mparams, initialized in init_mparams. Note that the non-zeroness of "magic" also serves as an initialization flag. */ -struct malloc_params { +struct MallocParams { size_t magic; size_t page_size; size_t granularity; @@ -736,18 +735,18 @@ struct malloc_params { flag_t default_mflags; }; -extern struct malloc_params mparams; +extern struct MallocParams g_mparams; #define ensure_initialization() \ /* we use a constructor [jart] */ \ - assert(mparams.magic != 0) -/* (void)(mparams.magic != 0 || init_mparams()) */ + assert(g_mparams.magic != 0) +/* (void)(g_mparams.magic != 0 || init_mparams()) */ #define is_initialized(M) ((M)->top != 0) #define is_page_aligned(S) \ - (((size_t)(S) & (mparams.page_size - SIZE_T_ONE)) == 0) + (((size_t)(S) & (g_mparams.page_size - SIZE_T_ONE)) == 0) #define is_granularity_aligned(S) \ - (((size_t)(S) & (mparams.granularity - SIZE_T_ONE)) == 0) + (((size_t)(S) & (g_mparams.granularity - SIZE_T_ONE)) == 0) /* ────────────────────────── system alloc setup ───────────────────────── */ @@ -777,13 +776,16 @@ extern struct malloc_params mparams; (L) ? ((M)->mflags | USE_LOCK_BIT) : ((M)->mflags & ~USE_LOCK_BIT)) /* page-align a size */ -#define page_align(S) \ - (((S) + (mparams.page_size - SIZE_T_ONE)) & ~(mparams.page_size - SIZE_T_ONE)) +#define page_align(S) \ + (((S) + (g_mparams.page_size - SIZE_T_ONE)) & \ + ~(g_mparams.page_size - SIZE_T_ONE)) /* granularity-align a size */ -#define granularity_align(S) \ - (((S) + (mparams.granularity - SIZE_T_ONE)) & \ - ~(mparams.granularity - SIZE_T_ONE)) +#define granularity_align(S) \ + (((S) + (g_mparams.granularity - SIZE_T_ONE)) & \ + ~(g_mparams.granularity - SIZE_T_ONE)) + +#define mmap_align(s) granularity_align((size_t)(s)) /* ──────────────────────── Operations on bin maps ─────────────────────── */ @@ -849,10 +851,10 @@ extern struct malloc_params mparams; /* For security, the main invariant is that malloc/free/etc never - writes to a static address other than malloc_state, unless static - malloc_state itself has been corrupted, which cannot occur via + writes to a static address other than MallocState, unless static + MallocState itself has been corrupted, which cannot occur via malloc (because of these checks). In essence this means that we - believe all pointers, sizes, maps etc held in malloc_state, but + believe all pointers, sizes, maps etc held in MallocState, but check all of those linked or offsetted from other embedded data structures. These checks are interspersed with main code in a way that tends to minimize their run-time cost. @@ -893,7 +895,7 @@ extern struct malloc_params mparams; #if (FOOTERS && !IsTrustworthy()) /* Check if (alleged) mstate m has expected magic field */ #define ok_magic(M) \ - ((uintptr_t)(M) <= 0x00007ffffffffffful && (M)->magic == mparams.magic) + ((uintptr_t)(M) <= 0x00007ffffffffffful && (M)->magic == g_mparams.magic) #else /* (FOOTERS && !IsTrustworthy()) */ #define ok_magic(M) (1) #endif /* (FOOTERS && !IsTrustworthy()) */ @@ -934,12 +936,13 @@ extern struct malloc_params mparams; #else /* FOOTERS */ /* Set foot of inuse chunk to be xor of mstate and seed */ -#define mark_inuse_foot(M, p, s) \ - (((mchunkptr)((char *)(p) + (s)))->prev_foot = ((size_t)(M) ^ mparams.magic)) +#define mark_inuse_foot(M, p, s) \ + (((mchunkptr)((char *)(p) + (s)))->prev_foot = \ + ((size_t)(M) ^ g_mparams.magic)) #define get_mstate_for(p) \ ((mstate)(((mchunkptr)((char *)(p) + (chunksize(p))))->prev_foot ^ \ - mparams.magic)) + g_mparams.magic)) #define set_inuse(M, p, s) \ ((p)->head = (((p)->head & PINUSE_BIT) | s | CINUSE_BIT), \ diff --git a/third_party/dlmalloc/dlmalloc_try_realloc_chunk.c b/third_party/dlmalloc/dlmalloc_try_realloc_chunk.c new file mode 100644 index 00000000..cfac7f46 --- /dev/null +++ b/third_party/dlmalloc/dlmalloc_try_realloc_chunk.c @@ -0,0 +1,105 @@ +#include "third_party/dlmalloc/dlmalloc.h" + +/* Realloc using mmap */ +static mchunkptr mmap_resize(mstate m, mchunkptr oldp, size_t nb, int flags) { + size_t oldsize = chunksize(oldp); + if (is_small(nb)) return 0; /* Can't shrink mmap regions below small size */ + /* Keep old chunk if big enough but not too big */ + if (oldsize >= nb + SIZE_T_SIZE && + (oldsize - nb) <= (g_mparams.granularity << 1)) { + return oldp; + } else { + size_t offset = oldp->prev_foot; + size_t oldmmsize = oldsize + offset + MMAP_FOOT_PAD; + size_t newmmsize = mmap_align(nb + SIX_SIZE_T_SIZES + CHUNK_ALIGN_MASK); + char *cp = mremap((char *)oldp - offset, oldmmsize, newmmsize, flags, 0); + if (cp != CMFAIL) { + mchunkptr newp = (mchunkptr)(cp + offset); + size_t psize = newmmsize - offset - MMAP_FOOT_PAD; + newp->head = psize; + mark_inuse_foot(m, newp, psize); + chunk_plus_offset(newp, psize)->head = FENCEPOST_HEAD; + chunk_plus_offset(newp, psize + SIZE_T_SIZE)->head = 0; + if (cp < m->least_addr) m->least_addr = cp; + if ((m->footprint += newmmsize - oldmmsize) > m->max_footprint) { + m->max_footprint = m->footprint; + } + check_mmapped_chunk(m, newp); + return newp; + } + } + return 0; +} + +/* Try to realloc; only in-place unless can_move true */ +mchunkptr dlmalloc_try_realloc_chunk(mstate m, mchunkptr p, size_t nb, + int can_move) { + mchunkptr newp = 0; + size_t oldsize = chunksize(p); + mchunkptr next = chunk_plus_offset(p, oldsize); + if (RTCHECK(ok_address(m, p) && ok_inuse(p) && ok_next(p, next) && + ok_pinuse(next))) { + if (is_mmapped(p)) { + newp = mmap_resize(m, p, nb, can_move); + } else if (oldsize >= nb) { /* already big enough */ + size_t rsize = oldsize - nb; + if (rsize >= MIN_CHUNK_SIZE) { /* split off remainder */ + mchunkptr r = chunk_plus_offset(p, nb); + set_inuse(m, p, nb); + set_inuse(m, r, rsize); + dlmalloc_dispose_chunk(m, r, rsize); + } + newp = p; + } else if (next == m->top) { /* extend into top */ + if (oldsize + m->topsize > nb) { + size_t newsize = oldsize + m->topsize; + size_t newtopsize = newsize - nb; + mchunkptr newtop = chunk_plus_offset(p, nb); + set_inuse(m, p, nb); + newtop->head = newtopsize | PINUSE_BIT; + m->top = newtop; + m->topsize = newtopsize; + newp = p; + } + } else if (next == m->dv) { /* extend into dv */ + size_t dvs = m->dvsize; + if (oldsize + dvs >= nb) { + size_t dsize = oldsize + dvs - nb; + if (dsize >= MIN_CHUNK_SIZE) { + mchunkptr r = chunk_plus_offset(p, nb); + mchunkptr n = chunk_plus_offset(r, dsize); + set_inuse(m, p, nb); + set_size_and_pinuse_of_free_chunk(r, dsize); + clear_pinuse(n); + m->dvsize = dsize; + m->dv = r; + } else { /* exhaust dv */ + size_t newsize = oldsize + dvs; + set_inuse(m, p, newsize); + m->dvsize = 0; + m->dv = 0; + } + newp = p; + } + } else if (!cinuse(next)) { /* extend into next free chunk */ + size_t nextsize = chunksize(next); + if (oldsize + nextsize >= nb) { + size_t rsize = oldsize + nextsize - nb; + unlink_chunk(m, next, nextsize); + if (rsize < MIN_CHUNK_SIZE) { + size_t newsize = oldsize + nextsize; + set_inuse(m, p, newsize); + } else { + mchunkptr r = chunk_plus_offset(p, nb); + set_inuse(m, p, nb); + set_inuse(m, r, rsize); + dlmalloc_dispose_chunk(m, r, rsize); + } + newp = p; + } + } + } else { + USAGE_ERROR_ACTION(m, chunk2mem(p)); + } + return newp; +} diff --git a/third_party/dlmalloc/dlmemalign.c b/third_party/dlmalloc/dlmemalign.c index 07bfbefb..dcc6812a 100644 --- a/third_party/dlmalloc/dlmemalign.c +++ b/third_party/dlmalloc/dlmemalign.c @@ -3,5 +3,5 @@ void *dlmemalign(size_t alignment, size_t bytes) { if (alignment <= MALLOC_ALIGNMENT) return dlmalloc(bytes); - return dlmemalign$impl(gm, alignment, bytes); + return dlmemalign$impl(g_dlmalloc, alignment, bytes); } diff --git a/third_party/dlmalloc/dlposix_memalign.c b/third_party/dlmalloc/dlposix_memalign.c index af0839fa..d46d2ad8 100644 --- a/third_party/dlmalloc/dlposix_memalign.c +++ b/third_party/dlmalloc/dlposix_memalign.c @@ -16,7 +16,7 @@ int dlposix_memalign(void** pp, size_t alignment, size_t bytes) { return einval(); } else if (bytes <= MAX_REQUEST - alignment) { if (alignment < MIN_CHUNK_SIZE) alignment = MIN_CHUNK_SIZE; - mem = dlmemalign$impl(gm, alignment, bytes); + mem = dlmemalign$impl(g_dlmalloc, alignment, bytes); } } if (mem == 0) { diff --git a/third_party/dlmalloc/dlpvalloc.c b/third_party/dlmalloc/dlpvalloc.c index f8209649..882ba7ab 100644 --- a/third_party/dlmalloc/dlpvalloc.c +++ b/third_party/dlmalloc/dlpvalloc.c @@ -4,7 +4,7 @@ void *dlpvalloc(size_t bytes) { size_t pagesz; ensure_initialization(); - pagesz = mparams.page_size; + pagesz = g_mparams.page_size; return dlmemalign(pagesz, (bytes + pagesz - SIZE_T_ONE) & ~(pagesz - SIZE_T_ONE)); } diff --git a/third_party/dlmalloc/dlrealloc.c b/third_party/dlmalloc/dlrealloc.c new file mode 100644 index 00000000..0bdb8c3f --- /dev/null +++ b/third_party/dlmalloc/dlrealloc.c @@ -0,0 +1,42 @@ +#include "libc/str/str.h" +#include "libc/sysv/errfuns.h" +#include "third_party/dlmalloc/dlmalloc.h" + +void *dlrealloc(void *oldmem, size_t bytes) { + void *mem = 0; + if (oldmem == 0) { + mem = dlmalloc(bytes); + } else if (bytes >= MAX_REQUEST) { + enomem(); + } else if (bytes == 0) { + dlfree(oldmem); + } else { + size_t nb = request2size(bytes); + mchunkptr oldp = mem2chunk(oldmem); +#if !FOOTERS + mstate m = g_dlmalloc; +#else /* FOOTERS */ + mstate m = get_mstate_for(oldp); + if (!ok_magic(m)) { + USAGE_ERROR_ACTION(m, oldmem); + return 0; + } +#endif /* FOOTERS */ + if (!PREACTION(m)) { + mchunkptr newp = dlmalloc_try_realloc_chunk(m, oldp, nb, 1); + POSTACTION(m); + if (newp != 0) { + check_inuse_chunk(m, newp); + mem = chunk2mem(newp); + } else { + mem = dlmalloc(bytes); + if (mem != 0) { + size_t oc = chunksize(oldp) - overhead_for(oldp); + memcpy(mem, oldmem, (oc < bytes) ? oc : bytes); + dlfree(oldmem); + } + } + } + } + return mem; +} diff --git a/third_party/dlmalloc/dlrealloc_in_place.c b/third_party/dlmalloc/dlrealloc_in_place.c index 9c47c5a2..9ed4020d 100644 --- a/third_party/dlmalloc/dlrealloc_in_place.c +++ b/third_party/dlmalloc/dlrealloc_in_place.c @@ -11,7 +11,7 @@ void *dlrealloc_in_place(void *oldmem, size_t bytes) { size_t nb = request2size(bytes); mchunkptr oldp = mem2chunk(oldmem); #if !FOOTERS - mstate m = gm; + mstate m = g_dlmalloc; #else /* FOOTERS */ mstate m = get_mstate_for(oldp); if (!ok_magic(m)) { diff --git a/third_party/dlmalloc/dlvalloc.c b/third_party/dlmalloc/dlvalloc.c index 26222423..a9cbef80 100644 --- a/third_party/dlmalloc/dlvalloc.c +++ b/third_party/dlmalloc/dlvalloc.c @@ -4,6 +4,6 @@ void *dlvalloc(size_t bytes) { size_t pagesz; ensure_initialization(); - pagesz = mparams.page_size; + pagesz = g_mparams.page_size; return dlmemalign(pagesz, bytes); } diff --git a/third_party/dlmalloc/mallinfo.c b/third_party/dlmalloc/mallinfo.c index 1bdf4c94..56a0afd7 100644 --- a/third_party/dlmalloc/mallinfo.c +++ b/third_party/dlmalloc/mallinfo.c @@ -1,5 +1,5 @@ -#include "third_party/dlmalloc/dlmalloc.h" #include "libc/mem/mem.h" +#include "third_party/dlmalloc/dlmalloc.h" /** * Returns (by copy) a struct containing various summary statistics: @@ -25,16 +25,16 @@ struct mallinfo mallinfo(void) { struct mallinfo nm = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; ensure_initialization(); - if (!PREACTION(gm)) { - check_malloc_state(gm); - if (is_initialized(gm)) { + if (!PREACTION(g_dlmalloc)) { + check_malloc_state(g_dlmalloc); + if (is_initialized(g_dlmalloc)) { size_t nfree = SIZE_T_ONE; /* top always free */ - size_t mfree = gm->topsize + TOP_FOOT_SIZE; + size_t mfree = g_dlmalloc->topsize + TOP_FOOT_SIZE; size_t sum = mfree; - msegmentptr s = &gm->seg; + msegmentptr s = &g_dlmalloc->seg; while (s != 0) { mchunkptr q = align_as_chunk(s->base); - while (segment_holds(s, q) && q != gm->top && + while (segment_holds(s, q) && q != g_dlmalloc->top && q->head != FENCEPOST_HEAD) { size_t sz = chunksize(q); sum += sz; @@ -48,13 +48,13 @@ struct mallinfo mallinfo(void) { } nm.arena = sum; nm.ordblks = nfree; - nm.hblkhd = gm->footprint - sum; - nm.usmblks = gm->max_footprint; - nm.uordblks = gm->footprint - mfree; + nm.hblkhd = g_dlmalloc->footprint - sum; + nm.usmblks = g_dlmalloc->max_footprint; + nm.uordblks = g_dlmalloc->footprint - mfree; nm.fordblks = mfree; - nm.keepcost = gm->topsize; + nm.keepcost = g_dlmalloc->topsize; } - POSTACTION(gm); + POSTACTION(g_dlmalloc); } return nm; } diff --git a/third_party/dlmalloc/malloc_footprint.c b/third_party/dlmalloc/malloc_footprint.c index 541b5926..b340e0d9 100644 --- a/third_party/dlmalloc/malloc_footprint.c +++ b/third_party/dlmalloc/malloc_footprint.c @@ -1,5 +1,5 @@ -#include "third_party/dlmalloc/dlmalloc.h" #include "libc/mem/mem.h" +#include "third_party/dlmalloc/dlmalloc.h" /** * Returns the number of bytes obtained from the system. The total @@ -9,4 +9,6 @@ * Even if locks are otherwise defined, this function does not use them, * so results might not be up to date. */ -size_t malloc_footprint(void) { return gm->footprint; } +size_t malloc_footprint(void) { + return g_dlmalloc->footprint; +} diff --git a/third_party/dlmalloc/malloc_footprint_limit.c b/third_party/dlmalloc/malloc_footprint_limit.c index 24ecf624..295e02b9 100644 --- a/third_party/dlmalloc/malloc_footprint_limit.c +++ b/third_party/dlmalloc/malloc_footprint_limit.c @@ -10,6 +10,6 @@ * this number of bytes can actually be obtained from the system. */ size_t malloc_footprint_limit(void) { - size_t maf = gm->footprint_limit; + size_t maf = g_dlmalloc->footprint_limit; return maf == 0 ? SIZE_MAX : maf; } diff --git a/third_party/dlmalloc/malloc_inspect_all.c b/third_party/dlmalloc/malloc_inspect_all.c index af4280e6..96d336b2 100644 --- a/third_party/dlmalloc/malloc_inspect_all.c +++ b/third_party/dlmalloc/malloc_inspect_all.c @@ -64,8 +64,8 @@ void malloc_inspect_all(void (*handler)(void* start, void* end, size_t used_bytes, void* callback_arg), void* arg) { ensure_initialization(); - if (!PREACTION(gm)) { - internal_inspect_all(gm, handler, arg); - POSTACTION(gm); + if (!PREACTION(g_dlmalloc)) { + internal_inspect_all(g_dlmalloc, handler, arg); + POSTACTION(g_dlmalloc); } } diff --git a/third_party/dlmalloc/malloc_max_footprint.c b/third_party/dlmalloc/malloc_max_footprint.c index b8941c17..68fdaca2 100644 --- a/third_party/dlmalloc/malloc_max_footprint.c +++ b/third_party/dlmalloc/malloc_max_footprint.c @@ -1,5 +1,5 @@ -#include "third_party/dlmalloc/dlmalloc.h" #include "libc/mem/mem.h" +#include "third_party/dlmalloc/dlmalloc.h" /** * Returns the maximum number of bytes obtained from the system. This @@ -11,4 +11,6 @@ * defined, this function does not use them, so results might not be up * to date. */ -size_t malloc_max_footprint(void) { return gm->max_footprint; } +size_t malloc_max_footprint(void) { + return g_dlmalloc->max_footprint; +} diff --git a/third_party/dlmalloc/malloc_set_footprint_limit.c b/third_party/dlmalloc/malloc_set_footprint_limit.c index e50990a3..47c842f8 100644 --- a/third_party/dlmalloc/malloc_set_footprint_limit.c +++ b/third_party/dlmalloc/malloc_set_footprint_limit.c @@ -21,5 +21,5 @@ size_t malloc_set_footprint_limit(size_t bytes) { } else { result = granularity_align(bytes); } - return gm->footprint_limit = result; + return g_dlmalloc->footprint_limit = result; } diff --git a/third_party/dlmalloc/malloc_trim.c b/third_party/dlmalloc/malloc_trim.c index 828b2a12..63a1d1ef 100644 --- a/third_party/dlmalloc/malloc_trim.c +++ b/third_party/dlmalloc/malloc_trim.c @@ -23,9 +23,9 @@ int malloc_trim(size_t pad) { int result = 0; ensure_initialization(); - if (!PREACTION(gm)) { - result = dlmalloc_sys_trim(gm, pad); - POSTACTION(gm); + if (!PREACTION(g_dlmalloc)) { + result = dlmalloc_sys_trim(g_dlmalloc, pad); + POSTACTION(g_dlmalloc); } return result; } diff --git a/third_party/dlmalloc/mallopt.c b/third_party/dlmalloc/mallopt.c index 4ee9e8ca..e8a300da 100644 --- a/third_party/dlmalloc/mallopt.c +++ b/third_party/dlmalloc/mallopt.c @@ -24,17 +24,17 @@ bool32 mallopt(int param_number, int value) { val = (value == -1) ? SIZE_MAX : (size_t)value; switch (param_number) { case M_TRIM_THRESHOLD: - mparams.trim_threshold = val; + g_mparams.trim_threshold = val; return true; case M_GRANULARITY: - if (val >= mparams.page_size && ((val & (val - 1)) == 0)) { - mparams.granularity = val; + if (val >= g_mparams.page_size && ((val & (val - 1)) == 0)) { + g_mparams.granularity = val; return true; } else { return false; } case M_MMAP_THRESHOLD: - mparams.mmap_threshold = val; + g_mparams.mmap_threshold = val; return true; default: return false; diff --git a/third_party/f2c/f2c.mk b/third_party/f2c/f2c.mk index 8d50984f..6fccab6e 100644 --- a/third_party/f2c/f2c.mk +++ b/third_party/f2c/f2c.mk @@ -48,7 +48,7 @@ $(THIRD_PARTY_F2C_A).pkg: \ THIRD_PARTY_F2C_LIBS = $(foreach x,$(THIRD_PARTY_F2C_ARTIFACTS),$($(x))) THIRD_PARTY_F2C_SRCS = $(foreach x,$(THIRD_PARTY_F2C_ARTIFACTS),$($(x)_SRCS)) -THIRD_PARTY_F2C_HDRS = $(foreach x,$(THIRD_PARTY_F2C_ARTIFACTS),$($(x)_HDRS)) +# THIRD_PARTY_F2C_HDRS = $(foreach x,$(THIRD_PARTY_F2C_ARTIFACTS),$($(x)_HDRS)) THIRD_PARTY_F2C_CHECKS = $(foreach x,$(THIRD_PARTY_F2C_ARTIFACTS),$($(x)_CHECKS)) THIRD_PARTY_F2C_OBJS = $(foreach x,$(THIRD_PARTY_F2C_ARTIFACTS),$($(x)_OBJS)) $(THIRD_PARTY_F2C_OBJS): third_party/f2c/f2c.mk diff --git a/third_party/xed/x86.h b/third_party/xed/x86.h index e71a37d1..dd547e8f 100644 --- a/third_party/xed/x86.h +++ b/third_party/xed/x86.h @@ -23,16 +23,9 @@ #define XED_MODE_LEGACY 1 #define XED_MODE_LONG 2 -#define XED_SEG_CS 1 -#define XED_SEG_DS 2 -#define XED_SEG_ES 3 -#define XED_SEG_FS 4 -#define XED_SEG_GS 5 -#define XED_SEG_SS 6 - -#define XED_HINT_NTAKEN 1 -#define XED_HINT_TAKEN 2 -#define XED_HINT_ALTER 3 +#define XED_HINT_NTAKEN 2 +#define XED_HINT_TAKEN 4 +#define XED_HINT_ALTER 6 #define xed_modrm_mod(M) (((M)&0xff) >> 6) #define xed_modrm_reg(M) (((M)&0b00111000) >> 3) @@ -46,15 +39,14 @@ COSMOPOLITAN_C_START_ enum XedMachineMode { - XED_MACHINE_MODE_INVALID, - XED_MACHINE_MODE_LONG_64, - XED_MACHINE_MODE_LONG_COMPAT_32, - XED_MACHINE_MODE_LONG_COMPAT_16, - XED_MACHINE_MODE_LEGACY_32, - XED_MACHINE_MODE_LEGACY_16, - XED_MACHINE_MODE_REAL, - XED_MACHINE_MODE_UNREAL, - XED_MACHINE_MODE_LAST + XED_MACHINE_MODE_REAL = XED_MODE_REAL, + XED_MACHINE_MODE_LEGACY_32 = XED_MODE_LEGACY, + XED_MACHINE_MODE_LONG_64 = XED_MODE_LONG, + XED_MACHINE_MODE_UNREAL = 1 << 2 | XED_MODE_REAL, + XED_MACHINE_MODE_LEGACY_16 = 2 << 2 | XED_MODE_REAL, + XED_MACHINE_MODE_LONG_COMPAT_16 = 3 << 2 | XED_MODE_REAL, + XED_MACHINE_MODE_LONG_COMPAT_32 = 4 << 2 | XED_MODE_LEGACY, + XED_MACHINE_MODE_LAST, }; enum XedError { @@ -319,54 +311,40 @@ struct XedChipFeatures { }; struct XedOperands { /* - ┌rep - │ ┌log₂𝑏 - │ │ ┌rexx - │ │ │┌index - │ │ ││ ┌mod - │ │ ││ │ ┌rexb - │ │ ││ │ │┌base - │ │ ││ │ ││ ┌asz - │ │ ││ │ ││ │┌rex REGISTER - │ │ ││ │ ││ ││┌rexb DISPATCH - │ │ ││ │ ││ │││┌srm ENCODING - │ │ ││ │ ││ ││││ ┌rexw - │ │ ││ │ ││ ││││ │┌rex - │ │ ││ │ ││ ││││ ││┌rexb - │ │ ││ │ ││ ││││ │││┌rm - │ │ ││ │ ││ ││││ ││││ ┌osz - │ │ ││ │ ││ ││││ ││││ │┌rex - │ │ ││ │ ││ ││││ ││││ ││┌rexr - │ │ ││ │ ││ ││││ ││││ │││┌reg - │ │2││ │2││ ││││ ││││ ││││ - │ │8││24│2││18││││12││││ 6││││ 0 - ├┐├┐│├─┐├┐│├─┐│││├─┐│││├─┐│││├─┐ - 0b00000000000000000000000000000000*/ + ┌rep + │ ┌log₂𝑏 + │ │ ┌mode + │ │ │ ┌eamode + │ │ │ │ ┌mod + │ │ │ │ │ + │ │ │ │ │ ┌sego + │ │ │ │ │ │ + │ │ │ │ │ │ ┌rex REGISTER + │ │ │ │ │ │ │┌rexb DISPATCH + │ │ │ │ │ │ ││┌srm ENCODING + │ │ │ │ │ │ │││ ┌rex + │ │ │ │ │ │ │││ │┌rexb + │ │ │ │ │ │ │││ ││┌rm + │ │ │ │ │ │ │││ │││ ┌rexw + │ │ │ │ │ │ │││ │││ │┌osz + │ │ │ │ │ │ │││ │││ ││┌rex + │ │ │ │ │ │ │││ │││ │││┌rexr + │ │ │ │ │ │ │││ │││ ││││┌reg + │3│2│2│2│2 │ │││ │││ │││││ + │0│8│6│4│2 │18 │││12│││ 7│││││ 0 + ├┐├┐├┐├┐├┐ ├─┐ ││├─┐││├─┐││││├─┐ + 00000000000000000000000000000000*/ uint32_t rde; - bool rexw : 1; // rex.w or rex.wb or etc. 64-bit override - bool rexb : 1; // rex.b or rex.wb or etc. see modrm table - bool rexr : 1; // rex.r or rex.wr or etc. see modrm table - bool rex : 1; // any rex prefix including rex - bool rexx : 1; // rex.x or rex.wx or etc. see sib table - bool rexrr : 1; // evex - bool asz : 1; // address size override - bool osz : 1; // operand size override prefix - bool out_of_bytes : 1; - bool is_intel_specific : 1; - bool ild_f2 : 1; - bool ild_f3 : 1; - bool has_modrm : 1; - bool has_sib : 1; - bool realmode : 1; - bool amd3dnow : 1; - uint8_t max_bytes; union { - uint8_t opcode; - uint8_t srm : 3; + struct { + union { + uint8_t opcode; + uint8_t srm : 3; + }; + uint8_t map : 4; // enum XedIldMap + }; + uint16_t dispatch; }; - uint8_t map : 4; // enum XedIldMap - uint8_t rep : 2; // 0, 2 (0xf2 repnz), 3 (0xf3 rep/repe) - uint8_t hint : 2; // static branch prediction union { uint8_t sib; struct { @@ -375,6 +353,24 @@ struct XedOperands { /* uint8_t scale : 2; }; }; + bool osz : 1; // operand size override prefix + bool rexw : 1; // rex.w or rex.wb or etc. 64-bit override + bool rexb : 1; // rex.b or rex.wb or etc. see modrm table + bool rexr : 1; // rex.r or rex.wr or etc. see modrm table + bool rex : 1; // any rex prefix including rex + bool rexx : 1; // rex.x or rex.wx or etc. see sib table + bool rexrr : 1; // evex + bool asz : 1; // address size override + int64_t disp; // displacement(%xxx) sign-extended + uint64_t uimm0; // $immediate sign-extended + bool out_of_bytes : 1; + bool is_intel_specific : 1; + bool ild_f2 : 1; + bool ild_f3 : 1; + bool has_sib : 1; + bool realmode : 1; + bool amd3dnow : 1; + bool lock : 1; union { uint8_t modrm; // selects address register struct { @@ -383,17 +379,17 @@ struct XedOperands { /* uint8_t mod : 2; }; }; + uint8_t max_bytes; + uint8_t rep : 2; // 0, 2 (0xf2 repnz), 3 (0xf3 rep/repe) + uint8_t has_modrm : 2; + bool imm_signed : 1; // internal uint8_t seg_ovd : 3; // XED_SEG_xx uint8_t error : 5; // enum XedError - uint8_t mode : 3; // real,legacy,long - bool lock : 1; // prefix - bool imm_signed : 1; // internal - int64_t disp; // displacement(%xxx) sign-extended - uint64_t uimm0; // $immediate sign-extended + uint8_t mode : 2; // real,legacy,long + uint8_t hint : 3; // static branch prediction uint8_t uimm1; // enter $x,$y uint8_t disp_width; // in bits uint8_t imm_width; // in bits - uint8_t ild_seg; // internal see seg_ovd uint8_t mode_first_prefix; // see xed_set_chip_modes() uint8_t nrexes; uint8_t nprefixes; @@ -419,36 +415,35 @@ struct XedOperands { /* }; struct XedDecodedInst { - struct XedOperands op; - uint8_t bytes[16]; unsigned char length; -} aligned(16); + uint8_t bytes[15]; + struct XedOperands op; +}; forceinline void xed_operands_set_mode(struct XedOperands *p, enum XedMachineMode mmode) { p->realmode = false; switch (mmode) { + default: case XED_MACHINE_MODE_LONG_64: - p->mode = 2; + p->mode = XED_MODE_LONG; return; case XED_MACHINE_MODE_LEGACY_32: case XED_MACHINE_MODE_LONG_COMPAT_32: - p->mode = 1; + p->mode = XED_MODE_LEGACY; break; case XED_MACHINE_MODE_REAL: p->realmode = true; - p->mode = 0; + p->mode = XED_MODE_REAL; break; case XED_MACHINE_MODE_UNREAL: - p->realmode = 1; - p->mode = 1; + p->realmode = true; + p->mode = XED_MODE_LEGACY; break; case XED_MACHINE_MODE_LEGACY_16: case XED_MACHINE_MODE_LONG_COMPAT_16: - p->mode = 0; + p->mode = XED_MODE_REAL; break; - default: - unreachable; } } diff --git a/third_party/xed/x86ild.greg.c b/third_party/xed/x86ild.greg.c index 75d1a394..cdf605f3 100644 --- a/third_party/xed/x86ild.greg.c +++ b/third_party/xed/x86ild.greg.c @@ -18,7 +18,9 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/assert.h" #include "libc/bits/bits.h" +#include "libc/dce.h" #include "libc/macros.h" +#include "libc/nexgen32e/bsr.h" #include "libc/runtime/runtime.h" #include "libc/str/str.h" #include "third_party/xed/avx.h" @@ -109,7 +111,7 @@ extern const uint8_t xed_disp_bits_2d[XED_ILD_MAP2][256] hidden; static const struct XedDenseMagnums { unsigned vex_prefix_recoding[4]; - xed_bits_t eamode_table[2][3]; + xed_bits_t eamode[2][3]; xed_bits_t BRDISPz_BRDISP_WIDTH[4]; xed_bits_t MEMDISPv_DISP_WIDTH[4]; xed_bits_t SIMMz_IMM_WIDTH[4]; @@ -306,11 +308,13 @@ static const struct XedDenseMagnums { [1][1][2] = 0x3, [1][0][2] = 0x3, }, - .eamode_table = + .eamode = { + [0][XED_MODE_REAL] = XED_MODE_REAL, [0][XED_MODE_LEGACY] = XED_MODE_LEGACY, [0][XED_MODE_LONG] = XED_MODE_LONG, [1][XED_MODE_REAL] = XED_MODE_LEGACY, + [1][XED_MODE_LEGACY] = XED_MODE_REAL, [1][XED_MODE_LONG] = XED_MODE_LEGACY, }, }; @@ -511,8 +515,9 @@ privileged static int xed_consume_byte(struct XedDecodedInst *d) { } privileged static void xed_prefix_scanner(struct XedDecodedInst *d) { - xed_bits_t first_f2f3, last_f2f3; + xed_bits_t first_f2f3, last_f2f3, seg; xed_bits_t b, max_bytes, length, nprefixes, nseg_prefixes, nrexes, rex; + seg = 0; length = d->length; max_bytes = d->op.max_bytes; first_f2f3 = last_f2f3 = rex = nrexes = nprefixes = nseg_prefixes = 0; @@ -534,15 +539,13 @@ privileged static void xed_prefix_scanner(struct XedDecodedInst *d) { /* fallthrough */ case 0x26: case 0x36: - if (!xed3_mode_64b(d)) { - d->op.ild_seg = b; - } + if (!xed3_mode_64b(d)) seg = b; nseg_prefixes++; rex = 0; break; case 0x64: case 0x65: - d->op.ild_seg = b; + seg = b; nseg_prefixes++; rex = 0; break; @@ -595,24 +598,24 @@ out: } else { d->op.rep = last_f2f3; } - switch (d->op.ild_seg) { - case 0x2e: - d->op.seg_ovd = 1; + switch (seg) { + case 0x26: /* ES */ + d->op.seg_ovd = 0 + 1; break; - case 0x3e: - d->op.seg_ovd = 2; + case 0x2e: /* CS */ + d->op.seg_ovd = 1 + 1; break; - case 0x26: - d->op.seg_ovd = 3; + case 0x36: /* SS */ + d->op.seg_ovd = 2 + 1; break; - case 0x64: - d->op.seg_ovd = 4; + case 0x3e: /* DS */ + d->op.seg_ovd = 3 + 1; break; - case 0x65: - d->op.seg_ovd = 5; + case 0x64: /* FS */ + d->op.seg_ovd = 4 + 1; break; - case 0x36: - d->op.seg_ovd = 6; + case 0x65: /* GS */ + d->op.seg_ovd = 5 + 1; break; default: break; @@ -630,7 +633,7 @@ privileged static void xed_get_next_as_opcode(struct XedDecodedInst *d) { b = d->bytes[length]; d->op.opcode = b; d->length++; - d->op.srm = xed_modrm_rm(b); + /* d->op.srm = xed_modrm_rm(b); */ } else { xed_too_short(d); } @@ -719,7 +722,7 @@ privileged static void xed_opcode_scanner(struct XedDecodedInst *d) { return; } } - d->op.srm = xed_modrm_rm(d->op.opcode); + /* d->op.srm = xed_modrm_rm(d->op.opcode); */ } privileged static bool xed_is_bound_instruction(struct XedDecodedInst *d) { @@ -784,12 +787,9 @@ privileged static void xed_evex_scanner(struct XedDecodedInst *d) { } privileged static void xed_evex_imm_scanner(struct XedDecodedInst *d) { - bool sex_imm; uint64_t uimm0; - unsigned pos_imm; uint8_t *itext, *imm_ptr; xed_bits_t length, imm_bytes, imm1_bytes, max_bytes; - pos_imm = 0; imm_ptr = 0; itext = d->bytes; xed_set_imm_bytes(d); @@ -829,32 +829,35 @@ privileged static void xed_evex_imm_scanner(struct XedDecodedInst *d) { return; } } - pos_imm = d->op.pos_imm; - imm_ptr = itext + pos_imm; - sex_imm = d->op.imm_signed; - switch (imm_bytes) { - case 0: - uimm0 = 0; - break; - case 1: - uimm0 = *imm_ptr; - if (sex_imm) uimm0 = (int8_t)uimm0; - break; - case 2: - uimm0 = READ16LE(imm_ptr); - if (sex_imm) uimm0 = (int16_t)uimm0; - break; - case 4: - uimm0 = READ32LE(imm_ptr); - if (sex_imm) uimm0 = (int32_t)uimm0; - break; - case 8: - uimm0 = READ64LE(imm_ptr); - break; - default: - unreachable; + imm_ptr = itext + d->op.pos_imm; + if (imm_bytes) { + switch (d->op.imm_signed << 2 | bsr(imm_bytes)) { + case 0b000: + d->op.uimm0 = *imm_ptr; + break; + case 0b100: + d->op.uimm0 = (int8_t)*imm_ptr; + break; + case 0b001: + d->op.uimm0 = READ16LE(imm_ptr); + break; + case 0b101: + d->op.uimm0 = (int16_t)READ16LE(imm_ptr); + break; + case 0b010: + d->op.uimm0 = READ32LE(imm_ptr); + break; + case 0b110: + d->op.uimm0 = (int32_t)READ32LE(imm_ptr); + break; + case 0b011: + case 0b111: + d->op.uimm0 = READ64LE(imm_ptr); + break; + default: + break; + } } - d->op.uimm0 = uimm0; } privileged static void xed_vex_c4_scanner(struct XedDecodedInst *d) { @@ -916,56 +919,6 @@ privileged static void xed_vex_c5_scanner(struct XedDecodedInst *d) { } } -privileged static void xed_xop_scanner(struct XedDecodedInst *d) { - union XedAvxC4Payload1 xop_byte1; - union XedAvxC4Payload2 xop_byte2; - xed_bits_t map, max_bytes, length; - length = d->length; - max_bytes = d->op.max_bytes; - if (length + 1 < max_bytes) { - if (xed_modrm_reg(d->bytes[d->length + 1])) { - length++; - } else { - return; /* not xop it's pop evq lool */ - } - } else { - xed_too_short(d); - return; - } - if (length + 2 < max_bytes) { - xop_byte1.u32 = d->bytes[length]; - xop_byte2.u32 = d->bytes[length + 1]; - map = xop_byte1.s.map; - if (map == 0x9) { - d->op.map = XED_ILD_MAP_XOP9; - d->op.imm_width = 0; - } else if (map == 0x8) { - d->op.map = XED_ILD_MAP_XOP8; - d->op.imm_width = xed_bytes2bits(1); - } else if (map == 0xA) { - d->op.map = XED_ILD_MAP_XOPA; - d->op.imm_width = xed_bytes2bits(4); - } else { - xed_bad_map(d); - } - d->op.rexr = ~xop_byte1.s.r_inv & 1; - d->op.rexx = ~xop_byte1.s.x_inv & 1; - d->op.rexb = (xed3_mode_64b(d) & ~xop_byte1.s.b_inv) & 1; - d->op.rexw = xop_byte2.s.w & 1; - d->op.vexdest3 = xop_byte2.s.v3; - d->op.vexdest210 = xop_byte2.s.vvv210; - d->op.vl = xop_byte2.s.l; - d->op.vex_prefix = kXed.vex_prefix_recoding[xop_byte2.s.pp]; - d->op.vexvalid = 3; - length += 2; - d->length = length; - xed_evex_vex_opcode_scanner(d); - } else { - d->length = length; - xed_too_short(d); - } -} - privileged static void xed_vex_scanner(struct XedDecodedInst *d) { if (!d->op.out_of_bytes) { switch (d->bytes[d->length]) { @@ -975,11 +928,6 @@ privileged static void xed_vex_scanner(struct XedDecodedInst *d) { case 0xC4: xed_vex_c4_scanner(d); break; - case 0x8F: - if (!d->op.is_intel_specific) { - xed_xop_scanner(d); - } - break; default: break; } @@ -1001,8 +949,11 @@ privileged static void xed_bad_ll_check(struct XedDecodedInst *d) { } privileged static void xed_set_has_modrm(struct XedDecodedInst *d) { - d->op.has_modrm = - d->op.map >= XED_ILD_MAP2 || xed_has_modrm_2d[d->op.map][d->op.opcode]; + if (d->op.map < ARRAYLEN(xed_has_modrm_2d)) { + d->op.has_modrm = xed_has_modrm_2d[d->op.map][d->op.opcode]; + } else { + d->op.has_modrm = 1; + } } privileged static void xed_modrm_scanner(struct XedDecodedInst *d) { @@ -1026,7 +977,7 @@ privileged static void xed_modrm_scanner(struct XedDecodedInst *d) { if (has_modrm != XED_ILD_HASMODRM_IGNORE_MOD) { asz = d->op.asz; mode = d->op.mode; - eamode = kXed.eamode_table[asz][mode]; + eamode = kXed.eamode[asz][mode]; d->op.disp_width = xed_bytes2bits(xed_has_disp_regular[eamode][mod][rm]); d->op.has_sib = xed_has_sib_table[eamode][mod][rm]; @@ -1190,16 +1141,14 @@ privileged static void xed_decode_instruction_length( } privileged static void xed_encode_rde(struct XedDecodedInst *x) { - /* fragile examples: addb, cmpxchgb */ - /* fragile counterexamples: btc, bsr, etc. */ const uint8_t kWordLog2[2][2][2] = {{{2, 3}, {1, 3}}, {{0, 0}, {0, 0}}}; - x->op.rde = x->op.rep << 30 | - kWordLog2[~x->op.opcode & 1][x->op.osz][x->op.rexw] << 28 | - x->op.mod << 22 | x->op.rexw << 11 | x->op.osz << 5 | - x->op.asz << 17 | (x->op.rexx << 3 | x->op.index) << 24 | - (x->op.rexb << 3 | x->op.base) << 18 | + uint32_t osz = x->op.osz ^ x->op.realmode; + x->op.rde = kWordLog2[~x->op.opcode & 1][osz][x->op.rexw] << 28 | + x->op.mode << 26 | kXed.eamode[x->op.asz][x->op.mode] << 24 | + x->op.rep << 30 | x->op.mod << 22 | x->op.asz << 17 | + x->op.seg_ovd << 18 | x->op.rexw << 6 | osz << 5 | (x->op.rex << 4 | x->op.rexb << 3 | x->op.srm) << 12 | - (x->op.rex << 4 | x->op.rexb << 3 | x->op.rm) << 6 | + (x->op.rex << 4 | x->op.rexb << 3 | x->op.rm) << 7 | (x->op.rex << 4 | x->op.rexr << 3 | x->op.reg); } @@ -1225,13 +1174,8 @@ privileged struct XedDecodedInst *xed_decoded_inst_zero_set_mode( */ privileged enum XedError xed_instruction_length_decode( struct XedDecodedInst *xedd, const void *itext, size_t bytes) { - if (bytes >= 16) { - __builtin_memcpy(xedd->bytes, itext, 16); - xedd->op.max_bytes = XED_MAX_INSTRUCTION_BYTES; - } else { - __builtin_memcpy(xedd->bytes, itext, bytes); - xedd->op.max_bytes = bytes; - } + __builtin_memcpy(xedd->bytes, itext, MIN(15, bytes)); + xedd->op.max_bytes = MIN(15, bytes); xed_decode_instruction_length(xedd); xed_encode_rde(xedd); if (!xedd->op.out_of_bytes) { diff --git a/tool/build/build.mk b/tool/build/build.mk index 9a35561c..2a5a8edd 100644 --- a/tool/build/build.mk +++ b/tool/build/build.mk @@ -93,9 +93,16 @@ o/$(MODE)/tool/build/emulator.o: \ OVERRIDE_COPTS += \ -fno-sanitize=pointer-overflow -# $(TOOL_BUILD_OBJS): \ -# OVERRIDE_CFLAGS += \ -# -fsanitize=address +o/$(MODE)/tool/build/transpile16.o: \ + OVERRIDE_CFLAGS += \ + -ffixed-r8 \ + -ffixed-r9 \ + -ffixed-r10 \ + -ffixed-r11 \ + -ffixed-r12 \ + -ffixed-r13 \ + -ffixed-r14 \ + -ffixed-r15 .PHONY: o/$(MODE)/tool/build o/$(MODE)/tool/build: \ diff --git a/tool/build/emubin/emubin.mk b/tool/build/emubin/emubin.mk index e182d50a..6fef236d 100644 --- a/tool/build/emubin/emubin.mk +++ b/tool/build/emubin/emubin.mk @@ -49,6 +49,15 @@ o/$(MODE)/tool/build/emubin/%.bin.dbg: \ $(TOOL_BUILD_EMUBIN_A).pkg @$(ELFLINK) -e emucrt -z max-page-size=0x10 +o/$(MODE)/tool/build/emubin/real/spiral.o: tool/build/emubin/real/spiral.c + @$(MKDIR) $(@D) + /opt/cross/bin/i486-linux-musl-gcc -nostdlib -nostdinc -m16 -Os -g -c -o $@ $< + +o/$(MODE)/tool/build/emubin/real/spiral.bin: o/$(MODE)/tool/build/emubin/real/spiral.o + /opt/cross/bin/i486-linux-musl-ld -static -nostdlib --oformat=binary -T tool/build/emubin/real/spiral.lds -o $@ $^ + +o/$(MODE)/tool/build/emubin/hug.o: OVERRIDE_CFLAGS += -ffast-math + .PHONY: o/$(MODE)/tool/build/emubin o/$(MODE)/tool/build/emubin: \ $(TOOL_BUILD_EMUBIN_BINS) \ diff --git a/tool/build/emubin/mips.c b/tool/build/emubin/mips.c index 114dd63e..5abb5cb0 100644 --- a/tool/build/emubin/mips.c +++ b/tool/build/emubin/mips.c @@ -28,7 +28,7 @@ static void Print(uint8_t c) { int main(int argc, char *argv[]) { int i; #ifdef DISINGENUOUS - for (i = 0; i < 100 * 1000 * 1000 / 3; ++i) asm("nop"); + for (i = 0; i < 150 * 1000 * 1000 / 3; ++i) asm("nop"); #else size_t size; struct MetalSha256Ctx ctx; diff --git a/tool/build/emubin/real/spiral.c b/tool/build/emubin/real/spiral.c new file mode 100644 index 00000000..718b42a0 --- /dev/null +++ b/tool/build/emubin/real/spiral.c @@ -0,0 +1,128 @@ +/*-*- 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 │ +│ │ +│ This program is free software; you can redistribute it and/or modify │ +│ it under the terms of the GNU General Public License as published by │ +│ the Free Software Foundation; version 2 of the License. │ +│ │ +│ This program is distributed in the hope that it will be useful, but │ +│ WITHOUT ANY WARRANTY; without even the implied warranty of │ +│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │ +│ General Public License for more details. │ +│ │ +│ You should have received a copy of the GNU General Public License │ +│ along with this program; if not, write to the Free Software │ +│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │ +│ 02110-1301 USA │ +╚─────────────────────────────────────────────────────────────────────────────*/ + +#define signbit(x) __builtin_signbit(x) + +static const unsigned char kBlocks[] = { + [0b1111] = 0xdb, // █ + [0b0110] = 0xdb, // █ + [0b1001] = 0xdb, // █ + [0b0111] = 0xdb, // █ + [0b1011] = 0xdb, // █ + [0b1110] = 0xdb, // █ + [0b1101] = 0xdb, // █ + [0b1100] = 0xdc, // ▄ + [0b0100] = 0xdc, // ▄ + [0b1000] = 0xdc, // ▄ + [0b0101] = 0xdd, // ▌ + [0b1010] = 0xde, // ▐ + [0b0011] = 0xdf, // ▀ + [0b0010] = 0xdf, // ▀ + [0b0001] = 0xdf, // ▀ +}; + +static void *memset(void *di, int al, unsigned long cx) { + asm("rep stosb %%al,(%0)" + : "=D"(di), "=c"(cx), "=m"(*(char(*)[cx])di) + : "0"(di), "1"(cx), "a"(al)); + return di; +} + +static long double pi(void) { + long double x; + asm("fldpi" : "=t"(x)); + return x; +} + +static void sincosl(long double x, long double *sin, long double *cos) { + asm("fsincos" : "=t"(*sin), "=u"(*cos) : "0"(x)); +} + +static long double atan2l(long double x, long double y) { + asm("fpatan" : "+t"(x) : "u"(y) : "st(1)"); + return x; +} + +static long lrintl(long double x) { + long i; + asm("fistp%z0\t%0" : "=m"(i) : "t"(x) : "st"); + return i; +} + +static long double truncl(long double x) { + asm("frndint" : "+t"(x)); + return x; +} + +static long double fabsl(long double x) { + asm("fabs" : "+t"(x)); + return x; +} + +static long lroundl(long double x) { + int s = signbit(x); + x = truncl(fabsl(x) + .5); + if (s) x = -x; + return lrintl(x); +} + +static unsigned short GetFpuControlWord(void) { + unsigned short cw; + asm("fnstcw\t%0" : "=m"(cw)); + return cw; +} + +static void SetFpuControlWord(unsigned short cw) { + asm volatile("fldcw\t%0" : /* no outputs */ : "m"(cw)); +} + +static void SetTruncationRounding(void) { + SetFpuControlWord(GetFpuControlWord() | 0x0c00); +} + +static void spiral(unsigned char p[25][80][2], unsigned char B[25][80]) { + int i, x, y; + long double a, b, u, v, h; + for (a = b = i = 0; i < 1000; ++i) { + sincosl(a, &u, &v); + h = atan2l(u, v); + x = lroundl(80 + u * b); + y = lroundl(25 + v * b * (1. / ((266 / 64.) * (900 / 1600.)))); + B[y >> 1][x >> 1] |= 1 << ((y & 1) << 1 | (x & 1)); + p[y >> 1][x >> 1][0] = kBlocks[B[y >> 1][x >> 1]]; + p[y >> 1][x >> 1][1] = (lrintl((h + pi() * 2) * (8 / (pi() * 2))) & 7) + 8; + a += .05; + b += .05; + } +} + +int main() { + asm(".pushsection .start,\"ax\",@progbits\n\t" + ".globl\t_start\n" + "_start:\n\t" + "callw\tmain\n\t" + ".popsection"); + SetTruncationRounding(); + for (;;) { + memset((void *)0x40000, 0, 25 * 80); + memset((void *)0xb8000, 0, 25 * 80 * 2); + spiral((void *)0xb8000, (void *)0x40000); + } +} diff --git a/tool/build/emubin/real/spiral.lds b/tool/build/emubin/real/spiral.lds new file mode 100644 index 00000000..e7697170 --- /dev/null +++ b/tool/build/emubin/real/spiral.lds @@ -0,0 +1,37 @@ +/*-*- mode: ld-script; indent-tabs-mode: nil; tab-width: 2; coding: utf-8 -*-│ +│vi: set et sts=2 tw=2 fenc=utf-8 :vi│ +╞══════════════════════════════════════════════════════════════════════════════╡ +│ Copyright 2020 Justine Alexandra Roberts Tunney │ +│ │ +│ This program is free software; you can redistribute it and/or modify │ +│ it under the terms of the GNU General Public License as published by │ +│ the Free Software Foundation; version 2 of the License. │ +│ │ +│ This program is distributed in the hope that it will be useful, but │ +│ WITHOUT ANY WARRANTY; without even the implied warranty of │ +│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │ +│ General Public License for more details. │ +│ │ +│ You should have received a copy of the GNU General Public License │ +│ along with this program; if not, write to the Free Software │ +│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │ +│ 02110-1301 USA │ +╚─────────────────────────────────────────────────────────────────────────────*/ + +ENTRY(_start) + +SECTIONS { + + .text 0x7c00 : { + *(.start) + *(.text .text.*) + *(.rodata .rodata.*) + *(.data .data.*) + *(.bss .bss.*) + *(COMMON) + } + + /DISCARD/ : { + *(.*) + } +} diff --git a/tool/build/emulator.c b/tool/build/emulator.c index fd0266df..ebff3dc9 100644 --- a/tool/build/emulator.c +++ b/tool/build/emulator.c @@ -55,12 +55,15 @@ #include "libc/sysv/consts/sa.h" #include "libc/sysv/consts/sig.h" #include "libc/sysv/consts/termios.h" +#include "libc/sysv/errfuns.h" #include "libc/unicode/unicode.h" #include "libc/x/x.h" #include "third_party/dtoa/dtoa.h" #include "third_party/getopt/getopt.h" +#include "tool/build/lib/address.h" #include "tool/build/lib/breakpoint.h" #include "tool/build/lib/case.h" +#include "tool/build/lib/cga.h" #include "tool/build/lib/dis.h" #include "tool/build/lib/endian.h" #include "tool/build/lib/fds.h" @@ -76,24 +79,23 @@ #include "tool/build/lib/stats.h" #include "tool/build/lib/throw.h" -STATIC_YOINK("die"); - #define USAGE \ - " [-?Hhrstv] [ROM] [ARGS...]\n\ + " [-?HhrRstv] [ROM] [ARGS...]\n\ \n\ DESCRIPTION\n\ \n\ - NexGen32e Userspace Emulator w/ Debugger\n\ + x86 Visualizing Emulator\n\ \n\ FLAGS\n\ \n\ -h\n\ -? help\n\ -v verbosity\n\ + -r real mode\n\ -s statistics\n\ -H disable highlight\n\ -t tui debugger mode\n\ - -r reactive tui mode\n\ + -R reactive tui mode\n\ -b ADDR push a breakpoint\n\ -L PATH log file location\n\ \n\ @@ -111,12 +113,14 @@ PERFORMANCE\n\ COMPLETENESS\n\ \n\ Long user mode is supported in addition to SSE3 and SSSE3.\n\ + Real mode and legacy mode are supported with limited APIs.\n\ Integer ops are implemented rigorously with lots of tests.\n\ Floating point instructions are yolo, and tunable more so.\n\ - Loading, virtual memory management, and syscall need work.\n\ + Loading, virtual memory management, and SYSCALL need work.\n\ \n" #define DUMPWIDTH 64 +#define DISPWIDTH 80 #define RESTART 0x001 #define REDRAW 0x002 @@ -143,8 +147,8 @@ struct Panels { struct Panel maps; struct Panel tracehr; struct Panel trace; - struct Panel terminalhr; - struct Panel terminal; + struct Panel displayhr; + struct Panel display; struct Panel registers; struct Panel ssehr; struct Panel sse; @@ -166,9 +170,14 @@ static const char kRegisterNames[16][4] = { "R8", "R9", "R10", "R11", "R12", "R13", "R14", "R15", }; +static const char kSegmentNames[16][4] = { + "ES", "CS", "SS", "DS", "FS", "GS", +}; + static int tyn; static int txn; static int ttyfd; +static bool vidya; static bool react; static bool ssehex; static int exitcode; @@ -216,6 +225,10 @@ static char *FormatDouble(char *b, double x) { return g_fmt(b, x); } +static void SetCarry(bool cf) { + m->flags = SetFlag(m->flags, FLAGS_CF, cf); +} + static bool IsCall(void) { return m->xedd->op.map == XED_ILD_MAP0 && (m->xedd->op.opcode == 0xE8 || @@ -271,6 +284,36 @@ static uint8_t CycleSseWidth(uint8_t w) { } } +static int GetPointerWidth(void) { + return 2 << (m->mode & 3); +} + +static int64_t GetIp(void) { + switch (GetPointerWidth()) { + case 8: + return m->ip; + case 4: + return Read64(m->cs) + (m->ip & 0xffff); + case 2: + return Read64(m->cs) + (m->ip & 0xffff); + default: + abort(); + } +} + +static int64_t GetSp(void) { + switch (GetPointerWidth()) { + case 8: + return Read64(m->sp); + case 4: + return Read64(m->ss) + Read32(m->sp); + case 2: + return Read64(m->ss) + Read16(m->sp); + default: + abort(); + } +} + static void OnBusted(void) { CHECK(onbusted); longjmp(onbusted, 1); @@ -331,6 +374,10 @@ static void OnQ(void) { breakpoints.i = 0; } +static void OnV(void) { + vidya = !vidya; +} + static void OnWinch(void) { LOGF("OnWinch"); action |= WINCHED; @@ -377,13 +424,13 @@ static void LoadSyms(void) { DisLoadElf(dis, elf); } -static void TuiSetup(void) { +void TuiSetup(void) { static bool once; if (!once) { LOGF("loaded program %s\n%s", codepath, gc(FormatPml4t(m->cr3))); LoadSyms(); ResolveBreakpoints(); - Dis(dis, m, elf->base); + Dis(dis, m, elf->base, 100); once = true; } CHECK_NE(-1, (ttyfd = open("/dev/tty", O_RDWR))); @@ -414,7 +461,7 @@ static bool IsXmmNonZero(long start, long end) { long i, j; for (i = start; i < end; ++i) { for (j = 0; j < 16; ++j) { - if (m->xmm[i / 8][i % 8][j]) { + if (m->xmm[i][j]) { return true; } } @@ -422,6 +469,16 @@ static bool IsXmmNonZero(long start, long end) { return false; } +static bool IsSegNonZero(void) { + unsigned i; + for (i = 0; i < 6; ++i) { + if (Read64(GetSegment(m, 0, i))) { + return true; + } + } + return false; +} + static int PickNumberOfXmmRegistersToShow(void) { if (IsXmmNonZero(0, 8) || IsXmmNonZero(8, 16)) { if (IsXmmNonZero(8, 16)) { @@ -446,11 +503,12 @@ static void SetupDraw(void) { } cpuy = 9; + if (IsSegNonZero()) cpuy += 2; ssey = PickNumberOfXmmRegistersToShow(); if (ssey) ++ssey; a = 12 + 1 + DUMPWIDTH; - b = DUMPWIDTH; + b = DISPWIDTH; dx[1] = txn >= a + b ? txn - a : txn; dx[0] = txn >= a + b + b ? txn - a - b : dx[1]; @@ -459,6 +517,10 @@ static void SetupDraw(void) { c2y[0] = a * .7; c2y[1] = a * 2; c2y[2] = a * 2 + b; + if (tyn - c2y[2] > 26) { + c2y[1] -= tyn - c2y[2] - 26; + c2y[2] = tyn - 26; + } a = (tyn - (cpuy + ssey) - 3) / 4; c3y[0] = cpuy; @@ -474,7 +536,7 @@ static void SetupDraw(void) { pan.disassembly.bottom = tyn; pan.disassembly.right = dx[0]; - /* COLUMN #2: BREAKPOINTS, MEMORY MAPS, BACKTRACE, TERMINAL */ + /* COLUMN #2: BREAKPOINTS, MEMORY MAPS, BACKTRACE, DISPLAY */ pan.breakpointshr.top = 0; pan.breakpointshr.left = dx[0]; @@ -506,15 +568,15 @@ static void SetupDraw(void) { pan.trace.bottom = c2y[2]; pan.trace.right = dx[1] - 1; - pan.terminalhr.top = c2y[2]; - pan.terminalhr.left = dx[0]; - pan.terminalhr.bottom = c2y[2] + 1; - pan.terminalhr.right = dx[1] - 1; + pan.displayhr.top = c2y[2]; + pan.displayhr.left = dx[0]; + pan.displayhr.bottom = c2y[2] + 1; + pan.displayhr.right = dx[1] - 1; - pan.terminal.top = c2y[2] + 1; - pan.terminal.left = dx[0]; - pan.terminal.bottom = tyn; - pan.terminal.right = dx[1] - 1; + pan.display.top = c2y[2] + 1; + pan.display.left = dx[0]; + pan.display.bottom = tyn; + pan.display.right = dx[1] - 1; /* COLUMN #3: REGISTERS, VECTORS, CODE, MEMORY READS, MEMORY WRITES, STACK */ @@ -580,20 +642,19 @@ static void SetupDraw(void) { xcalloc(pan.p[i].bottom - pan.p[i].top, sizeof(struct Buffer)); } - if (pty->yn != pan.terminal.bottom - pan.terminal.top || - pty->xn != pan.terminal.right - pan.terminal.left) { - LOGF("MachinePtyNew"); - MachinePtyFree(pty); - pty = MachinePtyNew(pan.terminal.bottom - pan.terminal.top, - pan.terminal.right - pan.terminal.left); + if (pty->yn != pan.display.bottom - pan.display.top || + pty->xn != pan.display.right - pan.display.left) { + LOGF("MachinePtyResize"); + MachinePtyResize(pty, pan.display.bottom - pan.display.top, + pan.display.right - pan.display.left); } } static long GetDisIndex(int64_t addr) { long i; - if ((i = DisFind(dis, m->ip)) == -1) { - Dis(dis, m, m->ip); - CHECK_NE(-1, (i = DisFind(dis, m->ip))); + if ((i = DisFind(dis, GetIp())) == -1) { + Dis(dis, m, GetIp(), pan.disassembly.bottom - pan.disassembly.top * 2); + CHECK_NE(-1, (i = DisFind(dis, GetIp()))); } while (i + 1 < dis->ops.i && !dis->ops.p[i].size) ++i; return i; @@ -605,12 +666,24 @@ static void DrawDisassembly(struct Panel *p) { j = opstart + i; if (0 <= j && j < dis->ops.i) { if (j == opline) AppendPanel(p, i, "\e[7m"); - AppendPanel(p, i, dis->ops.p[j].s); + AppendPanel(p, i, DisGetLine(dis, m, j)); if (j == opline) AppendPanel(p, i, "\e[27m"); } } } +static void DrawHr(struct Panel *p, const char *s) { + long i, wp, ws, wl, wr; + if (p->bottom - p->top < 1) return; + wp = p->right - p->left; + ws = strlen(s); + wl = wp / 4 - ws / 2; + wr = wp - (wl + ws); + for (i = 0; i < wl; ++i) AppendWide(&p->lines[0], u'─'); + AppendStr(&p->lines[0], s); + for (i = 0; i < wr; ++i) AppendWide(&p->lines[0], u'─'); +} + static void DrawTerminal(struct Panel *p) { long y, yn; for (yn = MIN(pty->yn, p->bottom - p->top), y = 0; y < yn; ++y) { @@ -618,8 +691,18 @@ static void DrawTerminal(struct Panel *p) { } } +void DrawDisplay(struct Panel *p) { + if (vidya) { + DrawHr(&pan.displayhr, "COLOR GRAPHICS ADAPTER"); + DrawCga(p, VirtualSend(m, gc(xmalloc(25 * 80 * 2)), 0xb8000, 25 * 80 * 2)); + } else { + DrawHr(&pan.displayhr, "TELETYPEWRITER"); + DrawTerminal(p); + } +} + static void DrawFlag(struct Panel *p, long i, char name, bool value) { - char str[] = " "; + char str[3] = " "; if (value) str[1] = name; AppendPanel(p, i, str); } @@ -639,6 +722,21 @@ static void DrawRegister(struct Panel *p, long i, long r) { AppendPanel(p, i, " "); } +static void DrawSegment(struct Panel *p, long i, long r) { + char buf[32]; + uint64_t value, previous; + value = Read64(GetSegment(m + 0, 0, r)); + previous = Read64(GetSegment(m + 1, 0, r)); + if (value != previous) AppendPanel(p, i, "\e[7m"); + snprintf(buf, sizeof(buf), "%-3s", kSegmentNames[r]); + AppendPanel(p, i, buf); + AppendPanel(p, i, " "); + snprintf(buf, sizeof(buf), "0x%016lx", value); + AppendPanel(p, i, buf); + if (value != previous) AppendPanel(p, i, "\e[27m"); + AppendPanel(p, i, " "); +} + static void DrawSt(struct Panel *p, long i, long r) { char buf[32]; long double value; @@ -656,18 +754,6 @@ static void DrawSt(struct Panel *p, long i, long r) { if (isempty) AppendPanel(p, i, "\e[22m"); } -static void DrawHr(struct Panel *p, const char *s) { - long i, wp, ws, wl, wr; - if (p->bottom - p->top < 1) return; - wp = p->right - p->left; - ws = strlen(s); - wl = wp / 4 - ws / 2; - wr = wp - (wl + ws); - for (i = 0; i < wl; ++i) AppendWide(&p->lines[0], u'─'); - AppendStr(&p->lines[0], s); - for (i = 0; i < wr; ++i) AppendWide(&p->lines[0], u'─'); -} - static void DrawCpu(struct Panel *p) { char buf[48]; DrawRegister(p, 0, 7), DrawRegister(p, 0, 0), DrawSt(p, 0, 0); @@ -701,6 +787,8 @@ static void DrawCpu(struct Panel *p) { if (m->fpu.c1) AppendPanel(p, 8, " C1"); if (m->fpu.c2) AppendPanel(p, 8, " C2"); if (m->fpu.bf) AppendPanel(p, 8, " BF"); + DrawSegment(p, 9, 4), DrawSegment(p, 9, 3), DrawSegment(p, 9, 1); + DrawSegment(p, 10, 5), DrawSegment(p, 10, 0), DrawSegment(p, 10, 2); } static void DrawXmm(struct Panel *p, long i, long r) { @@ -713,8 +801,8 @@ static void DrawXmm(struct Panel *p, long i, long r) { uint8_t xmm[16]; uint64_t ival, itmp; int cells, left, cellwidth, panwidth; - memcpy(xmm, m->xmm[r / 8][r % 8], sizeof(xmm)); - changed = memcmp(xmm, m[1].xmm[r / 8][r % 8], sizeof(xmm)) != 0; + memcpy(xmm, m->xmm[r], sizeof(xmm)); + changed = memcmp(xmm, m[1].xmm[r], sizeof(xmm)) != 0; if (changed) AppendPanel(p, i, "\e[7m"); left = sprintf(buf, "XMM%-2d", r); AppendPanel(p, i, buf); @@ -785,7 +873,7 @@ static void DrawSse(struct Panel *p) { static void ScrollCode(struct Panel *p) { long i, n; n = p->bottom - p->top; - i = m->ip / DUMPWIDTH; + i = GetIp() / DUMPWIDTH; if (!(memstart <= i && i < memstart + n)) { memstart = i; } @@ -812,7 +900,7 @@ static void ScrollWriteData(struct Panel *p) { static void ScrollStack(struct Panel *p) { long i, n; n = p->bottom - p->top; - i = Read64(m->sp) / DUMPWIDTH; + i = GetSp() / DUMPWIDTH; if (!(stackstart <= i && i < stackstart + n)) { stackstart = i; } @@ -877,6 +965,19 @@ static void DrawBreakpoints(struct Panel *p) { } } +static int GetPreferredStackAlignmentMask(void) { + switch (m->mode & 3) { + case XED_MODE_LONG: + return 15; + case XED_MODE_LEGACY: + return 3; + case XED_MODE_REAL: + return 3; + default: + unreachable; + } +} + static void DrawTrace(struct Panel *p) { int i, n; long sym; @@ -888,9 +989,10 @@ static void DrawTrace(struct Panel *p) { bp = Read64(m->bp); sp = Read64(m->sp); for (i = 0; i < p->bottom - p->top;) { + rp += Read64(m->cs); sym = DisFindSym(dis, rp); name = sym != -1 ? dis->syms.stab + dis->syms.p[sym].name : "UNKNOWN"; - snprintf(line, sizeof(line), "%p %p %s", bp, rp, name); + snprintf(line, sizeof(line), "%p %p %s", Read64(m->ss) + bp, rp, name); AppendPanel(p, i, line); if (sym != -1 && rp != dis->syms.p[sym].addr) { snprintf(line, sizeof(line), "+%#lx", rp - dis->syms.p[sym].addr); @@ -903,16 +1005,29 @@ static void DrawTrace(struct Panel *p) { snprintf(line, sizeof(line), " %,ld bytes", bp - sp); AppendPanel(p, i, line); } - if (bp & 15 && i) AppendPanel(p, i, " [MISALIGN]"); + if (bp & GetPreferredStackAlignmentMask() && i) { + AppendPanel(p, i, " [MISALIGN]"); + } ++i; - if ((bp & 0xfff) > 0xff0) break; - if (!(r = FindReal(m, bp))) { + if (((Read64(m->ss) + bp) & 0xfff) > 0xff0) break; + if (!(r = FindReal(m, Read64(m->ss) + bp))) { AppendPanel(p, i, "CORRUPT FRAME POINTER"); break; } sp = bp; - bp = Read64(r + 0); - rp = Read64(r + 8); + switch (m->mode & 3) { + case XED_MODE_LONG: + bp = Read64(r + 0); + rp = Read64(r + 8); + break; + case XED_MODE_REAL: + case XED_MODE_LEGACY: + bp = Read32(r + 0); + rp = Read32(r + 4); + break; + default: + unreachable; + } } } @@ -926,7 +1041,7 @@ static void CheckFramePointerImpl(void) { rp = m->ip; sp = Read64(m->sp); while (bp) { - if (!(r = FindReal(m, bp))) { + if (!(r = FindReal(m, Read64(m->ss) + bp))) { LOGF("corrupt frame: %p", bp); ThrowProtectionFault(m); } @@ -954,7 +1069,7 @@ static void Redraw(void) { } } DrawDisassembly(&pan.disassembly); - DrawTerminal(&pan.terminal); + DrawDisplay(&pan.display); DrawCpu(&pan.registers); DrawSse(&pan.sse); ScrollCode(&pan.code); @@ -964,7 +1079,6 @@ static void Redraw(void) { DrawHr(&pan.breakpointshr, "BREAKPOINTS"); DrawHr(&pan.mapshr, "MAPS"); DrawHr(&pan.tracehr, m->bofram[0] ? "PROTECTED FRAMES" : "FRAMES"); - DrawHr(&pan.terminalhr, "TELETYPEWRITER"); DrawHr(&pan.ssehr, "SSE"); DrawHr(&pan.codehr, "CODE"); DrawHr(&pan.readhr, "READ"); @@ -973,11 +1087,11 @@ static void Redraw(void) { DrawMaps(&pan.maps); DrawTrace(&pan.trace); DrawBreakpoints(&pan.breakpoints); - DrawMemory(&pan.code, memstart, m->ip, m->ip + m->xedd->length); + DrawMemory(&pan.code, memstart, GetIp(), GetIp() + m->xedd->length); DrawMemory(&pan.readdata, readstart, m->readaddr, m->readaddr + m->readsize); DrawMemory(&pan.writedata, writestart, m->writeaddr, m->writeaddr + m->writesize); - DrawMemory(&pan.stack, stackstart, Read64(m->sp), Read64(m->sp) + 8); + DrawMemory(&pan.stack, stackstart, GetSp(), GetSp() + GetPointerWidth()); if (PrintPanels(ttyfd, ARRAYLEN(pan.p), pan.p, tyn, txn) == -1) { LOGF("PrintPanels Interrupted"); CHECK_EQ(EINTR, errno); @@ -1001,10 +1115,22 @@ static ssize_t OnPtyFdWrite(int fd, const void *data, size_t size) { } } +static int OnPtyFdIoctl(int fd, uint64_t request, void *memory) { + if (request == TIOCGWINSZ) { + struct winsize *ws = memory; + ws->ws_row = pan.display.bottom - pan.display.top; + ws->ws_col = pan.display.right - pan.display.left; + return 0; + } else { + return einval(); + } +} + static const struct MachineFdCb kMachineFdCbPty = { .close = OnPtyFdClose, .read = OnPtyFdRead, .write = OnPtyFdWrite, + .ioctl = OnPtyFdIoctl, }; static void LaunchDebuggerReactively(void) { @@ -1070,38 +1196,192 @@ static void OnExit(int rc) { action |= EXIT; } -static void OnHalt(int interrupt) { +static size_t GetLastIndex(size_t size, unsigned unit, int i, unsigned limit) { + unsigned q, r; + if (!size) return 0; + q = size / unit; + r = size % unit; + if (!r) --q; + q += i; + if (q > limit) q = limit; + return q; +} + +static void OnDiskServiceReset(void) { + m->ax[1] = 0x00; + SetCarry(false); +} + +static void OnDiskServiceBadCommand(void) { + m->ax[1] = 0x01; + SetCarry(true); +} + +static void OnDiskServiceGetParams(void) { + size_t lastsector, lasttrack, lasthead; + lasthead = GetLastIndex(elf->mapsize, 512 * 63 * 1024, 0, 255); + lasttrack = GetLastIndex(elf->mapsize, 512 * 63, 0, 1023); + lastsector = GetLastIndex(elf->mapsize, 512, 1, 63); + m->dx[0] = 1; + m->dx[1] = lasthead; + m->cx[0] = lasttrack >> 8 << 6 | lastsector; + m->cx[1] = lasttrack; + m->ax[1] = 0; + Write64(m->es, 0); + Write16(m->di, 0); + SetCarry(false); +} + +static void OnDiskServiceReadSectors(void) { + int64_t drive, head, track, sector, offset, size, addr; + drive = m->dx[0]; + head = m->dx[1]; + track = (m->cx[0] & 0b11000000) << 2 | m->cx[1]; + sector = (m->cx[0] & 0b00111111) - 1; + offset = head * track * sector * 512; + size = m->ax[0] * 512; + offset = sector * 512 + track * 512 * 63 + head * 512 * 63 * 1024; + if (0 <= sector && offset + size <= elf->mapsize) { + addr = Read64(m->es) + Read16(m->bx); + if (addr + size <= 0xffff0 + 0xffff + 1) { + SetWriteAddr(m, addr, size); + VirtualRecv(m, addr, elf->map + offset, size); + m->ax[1] = 0x00; + SetCarry(false); + } else { + m->ax[0] = 0x00; + m->ax[1] = 0x02; + SetCarry(true); + } + } else { + m->ax[0] = 0x00; + m->ax[1] = 0x0d; + SetCarry(true); + } +} + +static void OnDiskService(void) { + switch (m->ax[1]) { + case 0x00: + OnDiskServiceReset(); + break; + case 0x02: + OnDiskServiceReadSectors(); + break; + case 0x08: + OnDiskServiceGetParams(); + break; + default: + OnDiskServiceBadCommand(); + break; + } +} + +static void OnVidyaServiceSetMode(void) { +} + +static void OnVidyaServiceSetCursor(void) { +} + +static void OnVidyaService(void) { + switch (m->ax[1]) { + case 0x00: + OnVidyaServiceSetMode(); + break; + case 0x02: + OnVidyaServiceSetCursor(); + break; + default: + break; + } +} + +static void OnApmService(void) { + if (Read16(m->ax) == 0x5300 && Read16(m->bx) == 0x0000) { + Write16(m->bx, 'P' << 8 | 'M'); + SetCarry(false); + } else if (Read16(m->ax) == 0x5301 && Read16(m->bx) == 0x0000) { + SetCarry(false); + } else if (Read16(m->ax) == 0x5307 && m->bx[0] == 1 && m->cx[0] == 3) { + LOGF("APM SHUTDOWN"); + exit(0); + } else { + SetCarry(true); + } +} + +static void OnE820(void) { + uint8_t p[20]; + if (Read32(m->dx) == 0x534D4150 && Read32(m->cx) == 24) { + if (!Read32(m->bx)) { + Write64(p + 000, 0); + Write64(p + 010, BIGPAGESIZE); + Write32(p + 014, 1); + VirtualRecv(m, Read64(m->es) + Read16(m->di), p, sizeof(p)); + Write32(m->cx, sizeof(p)); + Write32(m->bx, 1); + } else { + Write32(m->bx, 0); + Write32(m->cx, 0); + } + Write32(m->ax, 0x534D4150); + SetCarry(false); + } else { + SetCarry(true); + } +} + +static void OnInt15h(void) { + if (Read32(m->ax) == 0xE820) { + OnE820(); + } else if (m->ax[1] == 0x53) { + OnApmService(); + } else { + SetCarry(true); + } +} + +static bool OnHalt(int interrupt) { switch (interrupt) { case 1: case 3: OnDebug(); - break; + return false; + case 0x13: + OnDiskService(); + return true; + case 0x10: + OnVidyaService(); + return true; + case 0x15: + OnInt15h(); + return true; case kMachineSegmentationFault: OnSegmentationFault(); - break; + return false; case kMachineProtectionFault: OnProtectionFault(); - break; + return false; case kMachineSimdException: OnSimdException(); - break; + return false; case kMachineUndefinedInstruction: OnUndefinedInstruction(); - break; + return false; case kMachineDecodeError: OnDecodeError(); - break; + return false; case kMachineDivideError: OnDivideError(); - break; + return false; case kMachineFpuException: OnFpuException(); - break; + return false; case kMachineExit: case kMachineHalt: default: OnExit(interrupt); - break; + return false; } } @@ -1236,6 +1516,7 @@ static void ReadKeyboard(void) { for (n = rc, i = 0; i < n; ++i) { switch (b[i++]) { CASE('q', OnQ()); + CASE('v', OnV()); CASE('s', OnStep()); CASE('n', OnNext()); CASE('f', OnFinish()); @@ -1370,7 +1651,8 @@ static void Exec(void) { int interrupt; ExecSetup(); if (!(interrupt = setjmp(m->onhalt))) { - if ((bp = IsAtBreakpoint(&breakpoints, m->ip)) != -1) { + if (!(action & CONTINUE) && + (bp = IsAtBreakpoint(&breakpoints, GetIp())) != -1) { LOGF("BREAK %p", breakpoints.p[bp].addr); tuimode = true; LoadInstruction(m); @@ -1378,9 +1660,11 @@ static void Exec(void) { CheckFramePointer(); ops++; } else { + action &= ~CONTINUE; for (;;) { LoadInstruction(m); ExecuteInstruction(m); + KeepGoing: CheckFramePointer(); ops++; if (action || breakpoints.i) { @@ -1397,7 +1681,7 @@ static void Exec(void) { } break; } - if ((bp = IsAtBreakpoint(&breakpoints, m->ip)) != -1) { + if ((bp = IsAtBreakpoint(&breakpoints, GetIp())) != -1) { LOGF("BREAK %p", breakpoints.p[bp].addr); tuimode = true; break; @@ -1406,7 +1690,9 @@ static void Exec(void) { } } } else { - OnHalt(interrupt); + if (OnHalt(interrupt)) { + goto KeepGoing; + } } } @@ -1423,7 +1709,7 @@ static void Tui(void) { if (!(action & FAILURE)) { LoadInstruction(m); } else { - m->xedd = m->icache; + m->xedd = (struct XedDecodedInst *)m->icache[0]; m->xedd->length = 1; m->xedd->bytes[0] = 0xCC; m->xedd->op.opcode = 0xCC; @@ -1449,6 +1735,7 @@ static void Tui(void) { action &= ~(CONTINUE | NEXT | FINISH); } else { tuimode = false; + action |= CONTINUE; break; } } @@ -1470,7 +1757,7 @@ static void Tui(void) { if (IsExecuting()) { op = GetDisIndex(m->ip); ScrollOp(&pan.disassembly, op); - VERBOSEF("%s", dis->ops.p[op].s); + VERBOSEF("%s", DisGetLine(dis, m, op)); memcpy(&m[1], &m[0], sizeof(m[0])); if (!(action & CONTINUE)) { action &= ~STEP; @@ -1498,6 +1785,7 @@ static void Tui(void) { action &= ~FINISH; action &= ~CONTINUE; } + KeepGoing: CheckFramePointer(); ops++; if (!(action & CONTINUE)) { @@ -1516,7 +1804,9 @@ static void Tui(void) { } } } else { - OnHalt(interrupt); + if (OnHalt(interrupt)) { + goto KeepGoing; + } ScrollOp(&pan.disassembly, GetDisIndex(m->ip)); } TuiCleanup(); @@ -1525,14 +1815,18 @@ static void Tui(void) { static void GetOpts(int argc, char *argv[]) { int opt; stpcpy(stpcpy(stpcpy(logpath, kTmpPath), basename(argv[0])), ".log"); - while ((opt = getopt(argc, argv, "?hvtrsb:HL:")) != -1) { + while ((opt = getopt(argc, argv, "?hvtrRsb:HL:")) != -1) { switch (opt) { case 't': tuimode = true; break; - case 'r': + case 'R': react = true; break; + case 'r': + m->mode = XED_MACHINE_MODE_REAL; + vidya = true; + break; case 's': printstats = true; break; @@ -1563,8 +1857,9 @@ int Emulator(int argc, char *argv[]) { void *code; int rc, fd; codepath = argv[optind++]; - pty = MachinePtyNew(20, 80); + pty = MachinePtyNew(); InitMachine(m); + m->cr3 = MallocPage(); m->fds.p = xcalloc((m->fds.n = 8), sizeof(struct MachineFd)); Restart: action = 0; @@ -1590,23 +1885,9 @@ Restart: LeaveScreen(); } if (printstats) { - int i; - extern long opcount[256 * 4]; fprintf(stderr, "taken: %,ld\n", taken); fprintf(stderr, "ntaken: %,ld\n", ntaken); fprintf(stderr, "ops: %,ld\n", ops); - for (i = 0x51; i < 0x58; ++i) opcount[0x50] += opcount[i]; - for (i = 0x51; i < 0x58; ++i) opcount[i] = 0; - for (i = 0x59; i < 0x60; ++i) opcount[0x58] += opcount[i]; - for (i = 0x59; i < 0x60; ++i) opcount[i] = 0; - for (i = 0x91; i < 0x98; ++i) opcount[0x90] += opcount[i]; - for (i = 0x91; i < 0x98; ++i) opcount[i] = 0; - for (i = 0x71; i < 0x80; ++i) opcount[0x70] += opcount[i]; - for (i = 0x71; i < 0x80; ++i) opcount[i] = 0; - for (i = 0; i < ARRAYLEN(opcount); ++i) { - if (!opcount[i]) continue; - fprintf(stderr, "0x%03x %ld\n", i, opcount[i]); - } } munmap(elf->ehdr, elf->size); DisFree(dis); @@ -1621,6 +1902,7 @@ static void OnlyRunOnFirstCpu(void) { int main(int argc, char *argv[]) { int rc; + m->mode = XED_MACHINE_MODE_LONG_64; ssewidth = 2; /* 16-bit is best bit */ if (!NoDebug()) showcrashreports(); // OnlyRunOnFirstCpu(); diff --git a/tool/build/lib/x87.c b/tool/build/lib/address.c similarity index 56% rename from tool/build/lib/x87.c rename to tool/build/lib/address.c index 33e58c5c..76945aba 100644 --- a/tool/build/lib/x87.c +++ b/tool/build/lib/address.c @@ -17,55 +17,70 @@ │ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │ │ 02110-1301 USA │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "ape/lib/pc.h" -#include "libc/math.h" -#include "tool/build/lib/x87.h" +#include "third_party/xed/x86.h" +#include "tool/build/lib/address.h" +#include "tool/build/lib/endian.h" +#include "tool/build/lib/modrm.h" +#include "tool/build/lib/throw.h" -static long ltruncl(long double x) { - return x; +uint8_t *GetSegment(struct Machine *m, uint32_t rde, int s) { + switch (s & 7) { + case 0: + return m->es; + case 1: + return m->cs; + case 2: + return m->ss; + case 3: + return m->ds; + case 4: + return m->fs; + case 5: + return m->gs; + case 6: + case 7: + OpUd(m, rde); + default: + unreachable; + } } -static int ClearC2(int sw) { - return sw & ~FPU_C2; +uint64_t AddSegment(struct Machine *m, uint32_t rde, uint64_t i, uint8_t s[8]) { + if (!Sego(rde)) { + i += Read64(s); + } else { + i += Read64(GetSegment(m, rde, Sego(rde) - 1)); + } + return i; } -static long double x87remainder(long double x, long double y, uint32_t *sw, - long double rem(long double, long double), - long rnd(long double)) { - int s; - long q; - long double r; - s = 0; - r = rem(x, y); - q = rnd(x / y); - s &= ~FPU_C2; /* ty libm */ - if (q & 0b001) s |= FPU_C1; - if (q & 0b010) s |= FPU_C3; - if (q & 0b100) s |= FPU_C0; - if (sw) *sw = s | (*sw & ~(FPU_C0 | FPU_C1 | FPU_C2 | FPU_C3)); - return r; +uint64_t DataSegment(struct Machine *m, uint32_t rde, uint64_t i) { + return AddSegment(m, rde, i, m->ds); } -long double f2xm1(long double x) { - return exp2l(x) - 1; +uint64_t AddressSi(struct Machine *m, uint32_t rde) { + switch (Eamode(rde)) { + case XED_MODE_LONG: + return DataSegment(m, rde, Read64(m->si)); + case XED_MODE_REAL: + return DataSegment(m, rde, Read16(m->si)); + case XED_MODE_LEGACY: + return DataSegment(m, rde, Read32(m->si)); + default: + unreachable; + } } -long double fyl2x(long double x, long double y) { - return y * log2l(x); -} - -long double fyl2xp1(long double x, long double y) { - return y * log2l(x + 1); -} - -long double fscale(long double significand, long double exponent) { - return scalbl(significand, exponent); -} - -long double fprem(long double dividend, long double modulus, uint32_t *sw) { - return x87remainder(dividend, modulus, sw, fmodl, ltruncl); -} - -long double fprem1(long double dividend, long double modulus, uint32_t *sw) { - return x87remainder(dividend, modulus, sw, remainderl, lrintl); +uint64_t AddressDi(struct Machine *m, uint32_t rde) { + uint64_t i = Read64(m->es); + switch (Eamode(rde)) { + case XED_MODE_LONG: + return i + Read64(m->di); + case XED_MODE_REAL: + return i + Read16(m->di); + case XED_MODE_LEGACY: + return i + Read32(m->di); + default: + unreachable; + } } diff --git a/tool/build/lib/address.h b/tool/build/lib/address.h new file mode 100644 index 00000000..b85ffc7b --- /dev/null +++ b/tool/build/lib/address.h @@ -0,0 +1,28 @@ +#ifndef COSMOPOLITAN_TOOL_BUILD_LIB_ADDRESS_H_ +#define COSMOPOLITAN_TOOL_BUILD_LIB_ADDRESS_H_ +#include "libc/assert.h" +#include "third_party/xed/x86.h" +#include "tool/build/lib/machine.h" +#if !(__ASSEMBLER__ + __LINKER__ + 0) +COSMOPOLITAN_C_START_ + +uint64_t AddressDi(struct Machine *, uint32_t); +uint64_t AddressSi(struct Machine *, uint32_t); +uint64_t DataSegment(struct Machine *, uint32_t, uint64_t); +uint64_t AddSegment(struct Machine *, uint32_t, uint64_t, uint8_t[8]); +uint8_t *GetSegment(struct Machine *, uint32_t, int) nosideeffect; + +forceinline uint64_t MaskAddress(uint32_t mode, uint64_t x) { + if (mode != XED_MODE_LONG) { + if (mode == XED_MODE_REAL) { + x &= 0xffff; + } else { + x &= 0xffffffff; + } + } + return x; +} + +COSMOPOLITAN_C_END_ +#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ +#endif /* COSMOPOLITAN_TOOL_BUILD_LIB_ADDRESS_H_ */ diff --git a/tool/build/lib/alu.c b/tool/build/lib/alu.c index be150b16..2db41e7d 100644 --- a/tool/build/lib/alu.c +++ b/tool/build/lib/alu.c @@ -21,68 +21,753 @@ #include "tool/build/lib/alu.h" #include "tool/build/lib/flags.h" -/** - * NexGen32e Arithmetic Unit. - */ -int64_t Alu(int w, int h, uint64_t x, uint64_t y, uint32_t *flags) { - uint64_t t, z, s, m, k; - bool cf, of, zf, sf, af, carry; - assert(w < 4); +const aluop_f kAlu[12][4] = { + {Add8, Add16, Add32, Add64}, {Or8, Or16, Or32, Or64}, + {Adc8, Adc16, Adc32, Adc64}, {Sbb8, Sbb16, Sbb32, Sbb64}, + {And8, And16, And32, And64}, {Sub8, Sub16, Sub32, Sub64}, + {Xor8, Xor16, Xor32, Xor64}, {Sub8, Sub16, Sub32, Sub64}, + {Not8, Not16, Not32, Not64}, {Neg8, Neg16, Neg32, Neg64}, + {Inc8, Inc16, Inc32, Inc64}, {Dec8, Dec16, Dec32, Dec64}, +}; + +const aluop_f kBsu[8][4] = { + {Rol8, Rol16, Rol32, Rol64}, {Ror8, Ror16, Ror32, Ror64}, + {Rcl8, Rcl16, Rcl32, Rcl64}, {Rcr8, Rcr16, Rcr32, Rcr64}, + {Shl8, Shl16, Shl32, Shl64}, {Shr8, Shr16, Shr32, Shr64}, + {Shl8, Shl16, Shl32, Shl64}, {Sar8, Sar16, Sar32, Sar64}, +}; + +int64_t AluFlags(uint64_t x, uint32_t af, uint32_t *f, uint32_t of, uint32_t cf, + uint32_t sf) { + *f &= ~(1u << FLAGS_CF | 1u << FLAGS_ZF | 1u << FLAGS_SF | 1u << FLAGS_OF | + 1u << FLAGS_AF | 0xFF000000u); + *f |= sf << FLAGS_SF | cf << FLAGS_CF | !x << FLAGS_ZF | of << FLAGS_OF | + af << FLAGS_AF | (x & 0xFF) << 24; + return x; +} + +int64_t AluFlags8(uint8_t z, uint32_t af, uint32_t *f, uint32_t of, + uint32_t cf) { + return AluFlags(z, af, f, of, cf, z >> 7); +} + +int64_t AluFlags32(uint32_t z, uint32_t af, uint32_t *f, uint32_t of, + uint32_t cf) { + return AluFlags(z, af, f, of, cf, z >> 31); +} + +int64_t Xor32(uint64_t x, uint64_t y, uint32_t *f) { + return AluFlags32(x ^ y, 0, f, 0, 0); +} + +int64_t Sub32(uint64_t x64, uint64_t y64, uint32_t *f) { + bool cf, of, af; + uint32_t x, y, z; + x = x64; + y = y64; + z = x - y; + cf = x < z; + af = (x & 15) < (z & 15); + of = ((z ^ x) & (x ^ y)) >> 31; + return AluFlags32(z, af, f, of, cf); +} + +int64_t AluFlags64(uint64_t z, uint32_t af, uint32_t *f, uint32_t of, + uint32_t cf) { + return AluFlags(z, af, f, of, cf, z >> 63); +} + +int64_t Sub64(uint64_t x, uint64_t y, uint32_t *f) { + uint64_t z; + bool cf, of, af; + z = x - y; + cf = x < z; + af = (x & 15) < (z & 15); + of = ((z ^ x) & (x ^ y)) >> 63; + return AluFlags64(z, af, f, of, cf); +} + +int64_t Xor8(uint64_t x, uint64_t y, uint32_t *f) { + return AluFlags8(x ^ y, 0, f, 0, 0); +} + +int64_t Xor64(uint64_t x, uint64_t y, uint32_t *f) { + return AluFlags64(x ^ y, 0, f, 0, 0); +} + +int64_t Or8(uint64_t x, uint64_t y, uint32_t *f) { + return AluFlags8(x | y, 0, f, 0, 0); +} + +int64_t Or32(uint64_t x, uint64_t y, uint32_t *f) { + return AluFlags32(x | y, 0, f, 0, 0); +} + +int64_t Or64(uint64_t x, uint64_t y, uint32_t *f) { + return AluFlags64(x | y, 0, f, 0, 0); +} + +int64_t And8(uint64_t x, uint64_t y, uint32_t *f) { + return AluFlags8(x & y, 0, f, 0, 0); +} + +int64_t And32(uint64_t x, uint64_t y, uint32_t *f) { + return AluFlags32(x & y, 0, f, 0, 0); +} + +int64_t And64(uint64_t x, uint64_t y, uint32_t *f) { + return AluFlags64(x & y, 0, f, 0, 0); +} + +int64_t Sub8(uint64_t x64, uint64_t y64, uint32_t *f) { + bool cf, of, af; + uint8_t x, y, z; + x = x64; + y = y64; + z = x - y; + cf = x < z; + af = (x & 15) < (z & 15); + of = ((z ^ x) & (x ^ y)) >> 7; + return AluFlags8(z, af, f, of, cf); +} + +int64_t Add8(uint64_t x64, uint64_t y64, uint32_t *f) { + bool cf, of, af; + uint8_t x, y, z; + x = x64; + y = y64; + z = x + y; + cf = z < y; + af = (z & 15) < (y & 15); + of = ((z ^ x) & (z ^ y)) >> 7; + return AluFlags8(z, af, f, of, cf); +} + +int64_t Add32(uint64_t x64, uint64_t y64, uint32_t *f) { + bool cf, of, af; + uint32_t x, y, z; + x = x64; + y = y64; + z = x + y; + cf = z < y; + af = (z & 15) < (y & 15); + of = ((z ^ x) & (z ^ y)) >> 31; + return AluFlags32(z, af, f, of, cf); +} + +int64_t Add64(uint64_t x, uint64_t y, uint32_t *f) { + uint64_t z; + bool cf, of, af; + z = x + y; + cf = z < y; + af = (z & 15) < (y & 15); + of = ((z ^ x) & (z ^ y)) >> 63; + return AluFlags64(z, af, f, of, cf); +} + +int64_t Adc8(uint64_t x64, uint64_t y64, uint32_t *f) { + bool cf, of, af; + uint8_t x, y, z, t; + x = x64; + y = y64; + t = x + GetFlag(*f, FLAGS_CF); + z = t + y; + cf = (t < x) | (z < y); + of = ((z ^ x) & (z ^ y)) >> 7; + af = ((t & 15) < (x & 15)) | ((z & 15) < (y & 15)); + return AluFlags8(z, af, f, of, cf); +} + +int64_t Adc32(uint64_t x64, uint64_t y64, uint32_t *f) { + bool cf, of, af; + uint32_t x, y, z, t; + x = x64; + y = y64; + t = x + GetFlag(*f, FLAGS_CF); + z = t + y; + cf = (t < x) | (z < y); + of = ((z ^ x) & (z ^ y)) >> 31; + af = ((t & 15) < (x & 15)) | ((z & 15) < (y & 15)); + return AluFlags32(z, af, f, of, cf); +} + +int64_t Adc64(uint64_t x, uint64_t y, uint32_t *f) { + uint64_t z, t; + bool cf, of, af; + t = x + GetFlag(*f, FLAGS_CF); + z = t + y; + cf = (t < x) | (z < y); + of = ((z ^ x) & (z ^ y)) >> 63; + af = ((t & 15) < (x & 15)) | ((z & 15) < (y & 15)); + return AluFlags64(z, af, f, of, cf); +} + +int64_t Sbb8(uint64_t x64, uint64_t y64, uint32_t *f) { + bool cf, of, af; + uint8_t x, y, z, t; + x = x64; + y = y64; + t = x - GetFlag(*f, FLAGS_CF); + z = t - y; + cf = (x < t) | (t < z); + of = ((z ^ x) & (x ^ y)) >> 7; + af = ((x & 15) < (t & 15)) | ((t & 15) < (z & 15)); + return AluFlags8(z, af, f, of, cf); +} + +int64_t Sbb32(uint64_t x64, uint64_t y64, uint32_t *f) { + bool cf, of, af; + uint32_t x, y, z, t; + x = x64; + y = y64; + t = x - GetFlag(*f, FLAGS_CF); + z = t - y; + cf = (x < t) | (t < z); + of = ((z ^ x) & (x ^ y)) >> 31; + af = ((x & 15) < (t & 15)) | ((t & 15) < (z & 15)); + return AluFlags32(z, af, f, of, cf); +} + +int64_t Sbb64(uint64_t x, uint64_t y, uint32_t *f) { + uint64_t z, t; + bool cf, of, af; + t = x - GetFlag(*f, FLAGS_CF); + z = t - y; + cf = (x < t) | (t < z); + of = ((z ^ x) & (x ^ y)) >> 63; + af = ((x & 15) < (t & 15)) | ((t & 15) < (z & 15)); + return AluFlags64(z, af, f, of, cf); +} + +int64_t Not8(uint64_t x, uint64_t y, uint32_t *f) { + return ~x & 0xFF; +} + +int64_t Not32(uint64_t x, uint64_t y, uint32_t *f) { + return ~x & 0xFFFFFFFF; +} + +int64_t Not64(uint64_t x, uint64_t y, uint32_t *f) { + return ~x & 0xFFFFFFFFFFFFFFFF; +} + +int64_t Neg8(uint64_t x64, uint64_t y, uint32_t *f) { + uint8_t x; + bool cf, of, af; + x = x64; + af = cf = !!x; + of = x == 0x80; + x = ~x + 1; + return AluFlags8(x, af, f, of, cf); +} + +int64_t Neg32(uint64_t x64, uint64_t y, uint32_t *f) { + uint32_t x; + bool cf, of, af; + x = x64; + af = cf = !!x; + of = x == 0x80000000; + x = ~x + 1; + return AluFlags32(x, af, f, of, cf); +} + +int64_t Neg64(uint64_t x64, uint64_t y, uint32_t *f) { + uint64_t x; + bool cf, of, af; + x = x64; + af = cf = !!x; + of = x == 0x8000000000000000; + x = ~x + 1; + return AluFlags64(x, af, f, of, cf); +} + +static int64_t BumpFlags(uint64_t x, uint32_t af, uint32_t *f, uint32_t of, + uint32_t sf) { + return AluFlags(x, af, f, of, GetFlag(*f, FLAGS_CF), sf); +} + +int64_t Dec32(uint64_t x64, uint64_t y, uint32_t *f) { + uint32_t x, z, of, sf, af; + x = x64; + z = x - 1; + sf = z >> 31; + af = (x & 15) < (z & 15); + of = ((z ^ x) & (x ^ 1)) >> 31; + return BumpFlags(z, af, f, of, sf); +} + +int64_t Inc32(uint64_t x64, uint64_t y, uint32_t *f) { + uint32_t x, z, of, sf, af; + x = x64; + z = x + 1; + sf = z >> 31; + af = (z & 15) < (y & 15); + of = ((z ^ x) & (z ^ 1)) >> 31; + return BumpFlags(z, af, f, of, sf); +} + +int64_t Inc64(uint64_t x, uint64_t y, uint32_t *f) { + uint64_t z; + uint32_t of, sf, af; + z = x + 1; + sf = z >> 63; + af = (z & 15) < (y & 15); + of = ((z ^ x) & (z ^ 1)) >> 63; + return BumpFlags(z, af, f, of, sf); +} + +int64_t Dec64(uint64_t x, uint64_t y, uint32_t *f) { + uint64_t z; + uint32_t of, sf, af; + z = x - 1; + sf = z >> 63; + af = (x & 15) < (z & 15); + of = ((z ^ x) & (x ^ 1)) >> 63; + return BumpFlags(z, af, f, of, sf); +} + +int64_t Inc8(uint64_t x64, uint64_t y, uint32_t *f) { + uint8_t x, z; + uint32_t of, sf, af; + x = x64; + z = x + 1; + sf = z >> 7; + af = (z & 15) < (y & 15); + of = ((z ^ x) & (z ^ 1)) >> 7; + return BumpFlags(z, af, f, of, sf); +} + +int64_t Dec8(uint64_t x64, uint64_t y, uint32_t *f) { + uint8_t x, z; + uint32_t of, sf, af; + x = x64; + z = x - 1; + sf = z >> 7; + af = (x & 15) < (z & 15); + of = ((z ^ x) & (x ^ 1)) >> 7; + return BumpFlags(z, af, f, of, sf); +} + +int64_t Shr8(uint64_t x64, uint64_t y, uint32_t *f) { + uint32_t x, cf; + x = x64 & 0xff; + if ((y &= 31)) { + cf = (x >> (y - 1)) & 1; + x >>= y; + return AluFlags8(x, 0, f, ((x << 1) ^ x) >> 7, cf); + } else { + return x; + } +} + +int64_t Shr32(uint64_t x64, uint64_t y, uint32_t *f) { + uint32_t cf, x = x64; + if ((y &= 31)) { + cf = (x >> (y - 1)) & 1; + x >>= y; + return AluFlags32(x, 0, f, ((x << 1) ^ x) >> 31, cf); + } else { + return x; + } +} + +int64_t Shr64(uint64_t x, uint64_t y, uint32_t *f) { + uint32_t cf; + if ((y &= 63)) { + cf = (x >> (y - 1)) & 1; + x >>= y; + return AluFlags64(x, 0, f, ((x << 1) ^ x) >> 63, cf); + } else { + return x; + } +} + +int64_t Shl8(uint64_t x64, uint64_t y, uint32_t *f) { + uint32_t x, cf; + x = x64 & 0xff; + if ((y &= 31)) { + cf = (x >> ((8 - y) & 31)) & 1; + x = (x << y) & 0xff; + return AluFlags8(x, 0, f, (x >> 7) ^ cf, cf); + } else { + return x; + } +} + +int64_t Shl32(uint64_t x64, uint64_t y, uint32_t *f) { + uint32_t cf, x = x64; + if ((y &= 31)) { + cf = (x >> (32 - y)) & 1; + x <<= y; + return AluFlags32(x, 0, f, (x >> 31) ^ cf, cf); + } else { + return x; + } +} + +int64_t Shl64(uint64_t x, uint64_t y, uint32_t *f) { + uint32_t cf; + if ((y &= 63)) { + cf = (x >> (64 - y)) & 1; + x <<= y; + return AluFlags64(x, 0, f, (x >> 63) ^ cf, cf); + } else { + return x; + } +} + +int64_t Sar8(uint64_t x64, uint64_t y, uint32_t *f) { + uint32_t x, cf; + x = x64 & 0xff; + if ((y &= 31)) { + cf = ((int32_t)(int8_t)x >> (y - 1)) & 1; + x = ((int32_t)(int8_t)x >> y) & 0xff; + return AluFlags8(x, 0, f, 0, cf); + } else { + return x; + } +} + +int64_t Sar32(uint64_t x64, uint64_t y, uint32_t *f) { + uint32_t cf, x = x64; + if ((y &= 31)) { + cf = ((int32_t)x >> (y - 1)) & 1; + x = (int32_t)x >> y; + return AluFlags32(x, 0, f, 0, cf); + } else { + return x; + } +} + +int64_t Sar64(uint64_t x, uint64_t y, uint32_t *f) { + uint32_t cf; + if ((y &= 63)) { + cf = ((int64_t)x >> (y - 1)) & 1; + x = (int64_t)x >> y; + return AluFlags64(x, 0, f, 0, cf); + } else { + return x; + } +} + +static int64_t RotateFlags(uint64_t x, uint32_t cf, uint32_t *f, uint32_t of) { + *f &= ~(1u << FLAGS_CF | 1u << FLAGS_OF); + *f |= cf << FLAGS_CF | of << FLAGS_OF; + return x; +} + +int64_t Rol32(uint64_t x64, uint64_t y, uint32_t *f) { + uint32_t x = x64; + if ((y &= 31)) { + x = x << y | x >> (32 - y); + return RotateFlags(x, x & 1, f, ((x >> 31) ^ x) & 1); + } else { + return x; + } +} + +int64_t Rol64(uint64_t x, uint64_t y, uint32_t *f) { + if ((y &= 63)) { + x = x << y | x >> (64 - y); + return RotateFlags(x, x & 1, f, ((x >> 63) ^ x) & 1); + } else { + return x; + } +} + +int64_t Ror32(uint64_t x64, uint64_t y, uint32_t *f) { + uint32_t x = x64; + if ((y &= 31)) { + x = x >> y | x << (32 - y); + return RotateFlags(x, x >> 31, f, (x >> 31) ^ (x >> 30) & 1); + } else { + return x; + } +} + +int64_t Ror64(uint64_t x, uint64_t y, uint32_t *f) { + if ((y &= 63)) { + x = x >> y | x << (64 - y); + return RotateFlags(x, x >> 63, f, (x >> 63) ^ (x >> 62) & 1); + } else { + return x; + } +} + +int64_t Rol8(uint64_t x64, uint64_t y, uint32_t *f) { + uint8_t x = x64; + if (y & 31) { + if ((y &= 7)) x = x << y | x >> (8 - y); + return RotateFlags(x, x & 1, f, ((x >> 7) ^ x) & 1); + } else { + return x; + } +} + +int64_t Ror8(uint64_t x64, uint64_t y, uint32_t *f) { + uint8_t x = x64; + if (y & 31) { + if ((y &= 7)) x = x >> y | x << (8 - y); + return RotateFlags(x, x >> 7, f, (x >> 7) ^ (x >> 6) & 1); + } else { + return x; + } +} + +static int64_t Rcr(uint64_t x, uint64_t y, uint32_t *f, uint64_t xm, + uint64_t k) { + uint64_t cf; + uint32_t ct; + x &= xm; + if (y) { + cf = GetFlag(*f, FLAGS_CF); + ct = (x >> (y - 1)) & 1; + if (y == 1) { + x = (x >> 1 | cf << (k - 1)) & xm; + } else { + x = (x >> y | cf << (k - y) | x << (k + 1 - y)) & xm; + } + return RotateFlags(x, ct, f, (((x << 1) ^ x) >> (k - 1)) & 1); + } else { + return x; + } +} + +int64_t Rcr8(uint64_t x, uint64_t y, uint32_t *f) { + return Rcr(x, (y & 31) % 9, f, 0xff, 8); +} + +int64_t Rcr16(uint64_t x, uint64_t y, uint32_t *f) { + return Rcr(x, (y & 31) % 17, f, 0xffff, 16); +} + +int64_t Rcr32(uint64_t x, uint64_t y, uint32_t *f) { + return Rcr(x, y & 31, f, 0xffffffff, 32); +} + +int64_t Rcr64(uint64_t x, uint64_t y, uint32_t *f) { + return Rcr(x, y & 63, f, 0xffffffffffffffff, 64); +} + +static int64_t Rcl(uint64_t x, uint64_t y, uint32_t *f, uint64_t xm, + uint64_t k) { + uint64_t cf; + uint32_t ct; + x &= xm; + if (y) { + cf = GetFlag(*f, FLAGS_CF); + ct = (x >> (k - y)) & 1; + if (y == 1) { + x = (x << 1 | cf) & xm; + } else { + x = (x << y | cf << (y - 1) | x >> (k + 1 - y)) & xm; + } + return RotateFlags(x, ct, f, ct ^ ((x >> (k - 1)) & 1)); + } else { + return x; + } +} + +int64_t Rcl8(uint64_t x, uint64_t y, uint32_t *f) { + return Rcl(x, (y & 31) % 9, f, 0xff, 8); +} + +int64_t Rcl16(uint64_t x, uint64_t y, uint32_t *f) { + return Rcl(x, (y & 31) % 17, f, 0xffff, 16); +} + +int64_t Rcl32(uint64_t x, uint64_t y, uint32_t *f) { + return Rcl(x, y & 31, f, 0xffffffff, 32); +} + +int64_t Rcl64(uint64_t x, uint64_t y, uint32_t *f) { + return Rcl(x, y & 63, f, 0xffffffffffffffff, 64); +} + +uint64_t BsuDoubleShift(int w, uint64_t x, uint64_t y, uint8_t b, bool isright, + uint32_t *f) { + bool cf, of; + uint64_t s, k, m, z; k = 8; k <<= w; s = 1; s <<= k - 1; - m = s; - m |= s - 1; - t = x; - cf = 0; - of = 0; - af = 0; - carry = GetFlag(*flags, FLAGS_CF); - switch (h & 7) { - case ALU_OR: - z = x | y; - break; - case ALU_AND: - z = x & y; - break; - case ALU_XOR: - z = x ^ y; - break; - case ALU_CMP: - h |= 8; - carry = 0; - case ALU_SBB: - t = (x & m) - carry; - cf = (x & m) < (t & m); - af = (x & 15) < (t & 15); - case ALU_SUB: - z = (t & m) - (y & m); - cf |= (t & m) < (z & m); - af |= (t & 15) < (z & 15); - of = !!((z ^ x) & (x ^ y) & s); - break; - case ALU_ADC: - t = (x & m) + carry; - cf = (t & m) < (x & m); - af = (t & 15) < (x & 15); - case ALU_ADD: - z = (t & m) + (y & m); - cf |= (z & m) < (y & m); - af |= (z & 15) < (y & 15); - of = !!((z ^ x) & (z ^ y) & s); - break; - default: - unreachable; + m = s | s - 1; + b &= w == 3 ? 63 : 31; + x &= m; + if (b) { + if (isright) { + z = x >> b | y << (k - b); + cf = (x >> (b - 1)) & 1; + of = b == 1 && (z & s) != (x & s); + } else { + z = x << b | y >> (k - b); + cf = (x >> (k - b)) & 1; + of = b == 1 && (z & s) != (x & s); + } + x = z; + x &= m; + return AluFlags(x, 0, f, of, cf, !!(x & s)); + } else { + return x; + } +} + +int64_t AluFlags16(uint16_t z, uint32_t af, uint32_t *f, uint32_t of, + uint32_t cf) { + return AluFlags(z, af, f, of, cf, z >> 15); +} + +int64_t Xor16(uint64_t x, uint64_t y, uint32_t *f) { + return AluFlags16(x ^ y, 0, f, 0, 0); +} + +int64_t Or16(uint64_t x, uint64_t y, uint32_t *f) { + return AluFlags16(x | y, 0, f, 0, 0); +} + +int64_t And16(uint64_t x, uint64_t y, uint32_t *f) { + return AluFlags16(x & y, 0, f, 0, 0); +} + +int64_t Sub16(uint64_t x64, uint64_t y64, uint32_t *f) { + bool cf, of, af; + uint16_t x, y, z; + x = x64; + y = y64; + z = x - y; + cf = x < z; + af = (x & 15) < (z & 15); + of = ((z ^ x) & (x ^ y)) >> 15; + return AluFlags16(z, af, f, of, cf); +} + +int64_t Add16(uint64_t x64, uint64_t y64, uint32_t *f) { + bool cf, of, af; + uint16_t x, y, z; + x = x64; + y = y64; + z = x + y; + cf = z < y; + af = (z & 15) < (y & 15); + of = ((z ^ x) & (z ^ y)) >> 15; + return AluFlags16(z, af, f, of, cf); +} + +int64_t Adc16(uint64_t x64, uint64_t y64, uint32_t *f) { + bool cf, of, af; + uint16_t x, y, z, t; + x = x64; + y = y64; + t = x + GetFlag(*f, FLAGS_CF); + z = t + y; + cf = (t < x) | (z < y); + of = ((z ^ x) & (z ^ y)) >> 15; + af = ((t & 15) < (x & 15)) | ((z & 15) < (y & 15)); + return AluFlags16(z, af, f, of, cf); +} + +int64_t Sbb16(uint64_t x64, uint64_t y64, uint32_t *f) { + bool cf, of, af; + uint16_t x, y, z, t; + x = x64; + y = y64; + t = x - GetFlag(*f, FLAGS_CF); + z = t - y; + cf = (x < t) | (t < z); + of = ((z ^ x) & (x ^ y)) >> 15; + af = ((x & 15) < (t & 15)) | ((t & 15) < (z & 15)); + return AluFlags16(z, af, f, of, cf); +} + +int64_t Not16(uint64_t x, uint64_t y, uint32_t *f) { + return ~x & 0xFFFF; +} + +int64_t Neg16(uint64_t x64, uint64_t y, uint32_t *f) { + uint16_t x; + bool cf, of, af; + x = x64; + af = cf = !!x; + of = x == 0x8000; + x = ~x + 1; + return AluFlags16(x, af, f, of, cf); +} + +int64_t Inc16(uint64_t x64, uint64_t y, uint32_t *f) { + uint16_t x, z; + uint32_t of, sf, af; + x = x64; + z = x + 1; + sf = z >> 15; + af = (z & 15) < (y & 15); + of = ((z ^ x) & (z ^ 1)) >> 15; + return BumpFlags(z, af, f, of, sf); +} + +int64_t Dec16(uint64_t x64, uint64_t y, uint32_t *f) { + uint16_t x, z; + uint32_t of, sf, af; + x = x64; + z = x - 1; + sf = z >> 15; + af = (x & 15) < (z & 15); + of = ((z ^ x) & (x ^ 1)) >> 15; + return BumpFlags(z, af, f, of, sf); +} + +int64_t Shr16(uint64_t x64, uint64_t y, uint32_t *f) { + uint32_t x, cf; + x = x64 & 0xffff; + if ((y &= 31)) { + cf = (x >> (y - 1)) & 1; + x >>= y; + return AluFlags16(x, 0, f, ((x << 1) ^ x) >> 15, cf); + } else { + return x; + } +} + +int64_t Shl16(uint64_t x64, uint64_t y, uint32_t *f) { + uint32_t x, cf; + x = x64 & 0xffff; + if ((y &= 31)) { + cf = (x >> ((16 - y) & 31)) & 1; + x = (x << y) & 0xffff; + return AluFlags16(x, 0, f, (x >> 15) ^ cf, cf); + } else { + return x; + } +} + +int64_t Sar16(uint64_t x64, uint64_t y, uint32_t *f) { + uint32_t x, cf; + x = x64 & 0xffff; + if ((y &= 31)) { + cf = ((int32_t)(int16_t)x >> (y - 1)) & 1; + x = ((int32_t)(int16_t)x >> y) & 0xffff; + return AluFlags16(x, 0, f, 0, cf); + } else { + return x; + } +} + +int64_t Rol16(uint64_t x64, uint64_t y, uint32_t *f) { + uint16_t x = x64; + if (y & 31) { + if ((y &= 15)) x = x << y | x >> (16 - y); + return RotateFlags(x, x & 1, f, ((x >> 15) ^ x) & 1); + } else { + return x; + } +} + +int64_t Ror16(uint64_t x64, uint64_t y, uint32_t *f) { + uint16_t x = x64; + if (y & 31) { + if ((y &= 15)) x = x >> y | x << (16 - y); + return RotateFlags(x, x >> 15, f, (x >> 15) ^ (x >> 14) & 1); + } else { + return x; } - z &= m; - zf = !z; - sf = !!(z & s); - *flags = (*flags & ~(1 << FLAGS_CF | 1 << FLAGS_ZF | 1 << FLAGS_SF | - 1 << FLAGS_OF | 1 << FLAGS_AF)) | - cf << FLAGS_CF | zf << FLAGS_ZF | sf << FLAGS_SF | of << FLAGS_OF | - af << FLAGS_AF; - *flags = SetLazyParityByte(*flags, x); - if (h & ALU_TEST) z = x; - return z; } diff --git a/tool/build/lib/alu.h b/tool/build/lib/alu.h index 42b08756..aecefc37 100644 --- a/tool/build/lib/alu.h +++ b/tool/build/lib/alu.h @@ -2,15 +2,18 @@ #define COSMOPOLITAN_TOOL_BUILD_LIB_ALU_H_ #include "tool/build/lib/machine.h" -#define ALU_ADD 0 -#define ALU_OR 1 -#define ALU_ADC 2 -#define ALU_SBB 3 -#define ALU_AND 4 -#define ALU_SUB 5 -#define ALU_XOR 6 -#define ALU_CMP 7 -#define ALU_TEST 8 +#define ALU_ADD 0 +#define ALU_OR 1 +#define ALU_ADC 2 +#define ALU_SBB 3 +#define ALU_AND 4 +#define ALU_SUB 5 +#define ALU_XOR 6 +#define ALU_CMP 7 +#define ALU_NOT 8 +#define ALU_NEG 9 +#define ALU_INC 10 +#define ALU_DEC 11 #define BSU_ROL 0 #define BSU_ROR 1 @@ -24,17 +27,93 @@ #if !(__ASSEMBLER__ + __LINKER__ + 0) COSMOPOLITAN_C_START_ -typedef uint64_t (*aluop1_f)(struct Machine *, uint32_t, uint64_t); -typedef uint64_t (*aluop2_f)(struct Machine *, uint32_t, uint64_t, uint64_t); +typedef int64_t (*aluop_f)(uint64_t, uint64_t, uint32_t *); + +extern const aluop_f kAlu[12][4]; +extern const aluop_f kBsu[8][4]; + +int64_t Xor8(uint64_t, uint64_t, uint32_t *); +int64_t Xor16(uint64_t, uint64_t, uint32_t *); +int64_t Xor32(uint64_t, uint64_t, uint32_t *); +int64_t Xor64(uint64_t, uint64_t, uint32_t *); +int64_t Or8(uint64_t, uint64_t, uint32_t *); +int64_t Or16(uint64_t, uint64_t, uint32_t *); +int64_t Or32(uint64_t, uint64_t, uint32_t *); +int64_t Or64(uint64_t, uint64_t, uint32_t *); +int64_t And8(uint64_t, uint64_t, uint32_t *); +int64_t And16(uint64_t, uint64_t, uint32_t *); +int64_t And32(uint64_t, uint64_t, uint32_t *); +int64_t And64(uint64_t, uint64_t, uint32_t *); +int64_t Sub8(uint64_t, uint64_t, uint32_t *); +int64_t Sbb8(uint64_t, uint64_t, uint32_t *); +int64_t Sub16(uint64_t, uint64_t, uint32_t *); +int64_t Sbb16(uint64_t, uint64_t, uint32_t *); +int64_t Sub32(uint64_t, uint64_t, uint32_t *); +int64_t Sbb32(uint64_t, uint64_t, uint32_t *); +int64_t Sub64(uint64_t, uint64_t, uint32_t *); +int64_t Sbb64(uint64_t, uint64_t, uint32_t *); +int64_t Add8(uint64_t, uint64_t, uint32_t *); +int64_t Adc8(uint64_t, uint64_t, uint32_t *); +int64_t Add16(uint64_t, uint64_t, uint32_t *); +int64_t Adc16(uint64_t, uint64_t, uint32_t *); +int64_t Add32(uint64_t, uint64_t, uint32_t *); +int64_t Adc32(uint64_t, uint64_t, uint32_t *); +int64_t Add64(uint64_t, uint64_t, uint32_t *); +int64_t Adc64(uint64_t, uint64_t, uint32_t *); +int64_t Not8(uint64_t, uint64_t, uint32_t *); +int64_t Not16(uint64_t, uint64_t, uint32_t *); +int64_t Not32(uint64_t, uint64_t, uint32_t *); +int64_t Not64(uint64_t, uint64_t, uint32_t *); +int64_t Neg8(uint64_t, uint64_t, uint32_t *); +int64_t Neg16(uint64_t, uint64_t, uint32_t *); +int64_t Neg32(uint64_t, uint64_t, uint32_t *); +int64_t Neg64(uint64_t, uint64_t, uint32_t *); +int64_t Inc8(uint64_t, uint64_t, uint32_t *); +int64_t Inc16(uint64_t, uint64_t, uint32_t *); +int64_t Inc32(uint64_t, uint64_t, uint32_t *); +int64_t Inc64(uint64_t, uint64_t, uint32_t *); +int64_t Dec8(uint64_t, uint64_t, uint32_t *); +int64_t Dec16(uint64_t, uint64_t, uint32_t *); +int64_t Dec32(uint64_t, uint64_t, uint32_t *); +int64_t Dec64(uint64_t, uint64_t, uint32_t *); + +int64_t Shr8(uint64_t, uint64_t, uint32_t *); +int64_t Shr16(uint64_t, uint64_t, uint32_t *); +int64_t Shr32(uint64_t, uint64_t, uint32_t *); +int64_t Shr64(uint64_t, uint64_t, uint32_t *); +int64_t Shl8(uint64_t, uint64_t, uint32_t *); +int64_t Shl16(uint64_t, uint64_t, uint32_t *); +int64_t Shl32(uint64_t, uint64_t, uint32_t *); +int64_t Shl64(uint64_t, uint64_t, uint32_t *); +int64_t Sar8(uint64_t, uint64_t, uint32_t *); +int64_t Sar16(uint64_t, uint64_t, uint32_t *); +int64_t Sar32(uint64_t, uint64_t, uint32_t *); +int64_t Sar64(uint64_t, uint64_t, uint32_t *); +int64_t Rol8(uint64_t, uint64_t, uint32_t *); +int64_t Rol16(uint64_t, uint64_t, uint32_t *); +int64_t Rol32(uint64_t, uint64_t, uint32_t *); +int64_t Rol64(uint64_t, uint64_t, uint32_t *); +int64_t Ror8(uint64_t, uint64_t, uint32_t *); +int64_t Ror16(uint64_t, uint64_t, uint32_t *); +int64_t Ror32(uint64_t, uint64_t, uint32_t *); +int64_t Ror64(uint64_t, uint64_t, uint32_t *); +int64_t Rcr8(uint64_t, uint64_t, uint32_t *); +int64_t Rcr16(uint64_t, uint64_t, uint32_t *); +int64_t Rcr32(uint64_t, uint64_t, uint32_t *); +int64_t Rcr64(uint64_t, uint64_t, uint32_t *); +int64_t Rcl8(uint64_t, uint64_t, uint32_t *); +int64_t Rcl16(uint64_t, uint64_t, uint32_t *); +int64_t Rcl32(uint64_t, uint64_t, uint32_t *); +int64_t Rcl64(uint64_t, uint64_t, uint32_t *); -int64_t Alu(int, int, uint64_t, uint64_t, uint32_t *); -int64_t Bsu(int, int, uint64_t, uint64_t, uint32_t *); -uint64_t AluBt(struct Machine *, uint64_t, uint64_t); -uint64_t AluBtc(struct Machine *, uint64_t, uint64_t); -uint64_t AluBtr(struct Machine *, uint64_t, uint64_t); -uint64_t AluBts(struct Machine *, uint64_t, uint64_t); uint64_t BsuDoubleShift(int, uint64_t, uint64_t, uint8_t, bool, uint32_t *); +int64_t AluFlags(uint64_t, uint32_t, uint32_t *, uint32_t, uint32_t, uint32_t); +int64_t AluFlags8(uint8_t, uint32_t, uint32_t *, uint32_t, uint32_t); +int64_t AluFlags16(uint16_t, uint32_t, uint32_t *, uint32_t, uint32_t); +int64_t AluFlags32(uint32_t, uint32_t, uint32_t *, uint32_t, uint32_t); +int64_t AluFlags64(uint64_t, uint32_t, uint32_t *, uint32_t, uint32_t); + COSMOPOLITAN_C_END_ #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ #endif /* COSMOPOLITAN_TOOL_BUILD_LIB_ALU_H_ */ diff --git a/tool/build/lib/bcd.c b/tool/build/lib/bcd.c new file mode 100644 index 00000000..5dab82a0 --- /dev/null +++ b/tool/build/lib/bcd.c @@ -0,0 +1,78 @@ +/*-*- 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 │ +│ │ +│ This program is free software; you can redistribute it and/or modify │ +│ it under the terms of the GNU General Public License as published by │ +│ the Free Software Foundation; version 2 of the License. │ +│ │ +│ This program is distributed in the hope that it will be useful, but │ +│ WITHOUT ANY WARRANTY; without even the implied warranty of │ +│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │ +│ General Public License for more details. │ +│ │ +│ You should have received a copy of the GNU General Public License │ +│ along with this program; if not, write to the Free Software │ +│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │ +│ 02110-1301 USA │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "tool/build/lib/alu.h" +#include "tool/build/lib/bcd.h" +#include "tool/build/lib/endian.h" +#include "tool/build/lib/flags.h" +#include "tool/build/lib/throw.h" + +void OpDas(struct Machine *m, uint32_t rde) { + uint8_t al, af, cf; + af = cf = 0; + al = m->ax[0]; + if ((al & 0x0f) > 9 || GetFlag(m->flags, FLAGS_AF)) { + cf = m->ax[0] < 6 || GetFlag(m->flags, FLAGS_CF); + m->ax[0] -= 0x06; + af = 1; + } + if (al > 0x99 || GetFlag(m->flags, FLAGS_CF)) { + m->ax[0] -= 0x60; + cf = 1; + } + AluFlags8(m->ax[0], af, &m->flags, 0, cf); +} + +void OpAaa(struct Machine *m, uint32_t rde) { + uint8_t af, cf; + af = cf = 0; + if ((m->ax[0] & 0x0f) > 9 || GetFlag(m->flags, FLAGS_AF)) { + cf = m->ax[0] < 6 || GetFlag(m->flags, FLAGS_CF); + Write16(m->ax, Read16(m->ax) + 0x106); + af = cf = 1; + } + m->ax[0] &= 0x0f; + AluFlags8(m->ax[0], af, &m->flags, 0, cf); +} + +void OpAas(struct Machine *m, uint32_t rde) { + uint8_t af, cf; + af = cf = 0; + if ((m->ax[0] & 0x0f) > 9 || GetFlag(m->flags, FLAGS_AF)) { + cf = m->ax[0] < 6 || GetFlag(m->flags, FLAGS_CF); + Write16(m->ax, Read16(m->ax) - 0x106); + af = cf = 1; + } + m->ax[0] &= 0x0f; + AluFlags8(m->ax[0], af, &m->flags, 0, cf); +} + +void OpAam(struct Machine *m, uint32_t rde) { + uint8_t i = m->xedd->op.uimm0; + if (!i) ThrowDivideError(m); + m->ax[1] = m->ax[0] / i; + m->ax[0] = m->ax[0] % i; + AluFlags8(m->ax[0], 0, &m->flags, 0, 0); +} + +void OpAad(struct Machine *m, uint32_t rde) { + uint8_t i = m->xedd->op.uimm0; + Write16(m->ax, (m->ax[1] * i + m->ax[0]) & 0xff); + AluFlags8(m->ax[0], 0, &m->flags, 0, 0); +} diff --git a/tool/build/lib/bcd.h b/tool/build/lib/bcd.h new file mode 100644 index 00000000..206ec6ef --- /dev/null +++ b/tool/build/lib/bcd.h @@ -0,0 +1,15 @@ +#ifndef COSMOPOLITAN_TOOL_BUILD_LIB_BCD_H_ +#define COSMOPOLITAN_TOOL_BUILD_LIB_BCD_H_ +#include "tool/build/lib/machine.h" +#if !(__ASSEMBLER__ + __LINKER__ + 0) +COSMOPOLITAN_C_START_ + +void OpDas(struct Machine *, uint32_t); +void OpAaa(struct Machine *, uint32_t); +void OpAas(struct Machine *, uint32_t); +void OpAam(struct Machine *, uint32_t); +void OpAad(struct Machine *, uint32_t); + +COSMOPOLITAN_C_END_ +#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ +#endif /* COSMOPOLITAN_TOOL_BUILD_LIB_BCD_H_ */ diff --git a/tool/build/lib/bitscan.c b/tool/build/lib/bitscan.c index 51bbb1d2..f6061e11 100644 --- a/tool/build/lib/bitscan.c +++ b/tool/build/lib/bitscan.c @@ -22,7 +22,7 @@ #include "tool/build/lib/machine.h" #include "tool/build/lib/modrm.h" -uint64_t AluBsr(struct Machine *m, uint32_t rde, uint64_t _, uint64_t x) { +uint64_t AluBsr(struct Machine *m, uint32_t rde, uint64_t x) { unsigned i; if (Rexw(rde)) { x &= 0xffffffffffffffff; @@ -43,7 +43,7 @@ uint64_t AluBsr(struct Machine *m, uint32_t rde, uint64_t _, uint64_t x) { } } -uint64_t AluBsf(struct Machine *m, uint32_t rde, uint64_t _, uint64_t x) { +uint64_t AluBsf(struct Machine *m, uint32_t rde, uint64_t x) { unsigned i; if (Rexw(rde)) { x &= 0xffffffffffffffff; @@ -64,7 +64,7 @@ uint64_t AluBsf(struct Machine *m, uint32_t rde, uint64_t _, uint64_t x) { } } -uint64_t AluPopcnt(struct Machine *m, uint32_t rde, uint64_t _, uint64_t x) { +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); m->flags = SetFlag(m->flags, FLAGS_SF, false); diff --git a/tool/build/lib/bitscan.h b/tool/build/lib/bitscan.h index 95ae962f..26d86574 100644 --- a/tool/build/lib/bitscan.h +++ b/tool/build/lib/bitscan.h @@ -4,9 +4,11 @@ #if !(__ASSEMBLER__ + __LINKER__ + 0) COSMOPOLITAN_C_START_ -uint64_t AluBsr(struct Machine *, uint32_t, uint64_t, uint64_t); -uint64_t AluBsf(struct Machine *, uint32_t, uint64_t, uint64_t); -uint64_t AluPopcnt(struct Machine *, uint32_t, uint64_t, uint64_t); +typedef uint64_t (*bitscan_f)(struct Machine *, uint32_t, uint64_t); + +uint64_t AluBsr(struct Machine *, uint32_t, uint64_t); +uint64_t AluBsf(struct Machine *, uint32_t, uint64_t); +uint64_t AluPopcnt(struct Machine *, uint32_t, uint64_t); COSMOPOLITAN_C_END_ #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ diff --git a/tool/build/lib/bsu.c b/tool/build/lib/bsu.c deleted file mode 100644 index a541edb6..00000000 --- a/tool/build/lib/bsu.c +++ /dev/null @@ -1,167 +0,0 @@ -/*-*- 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 │ -│ │ -│ This program is free software; you can redistribute it and/or modify │ -│ it under the terms of the GNU General Public License as published by │ -│ the Free Software Foundation; version 2 of the License. │ -│ │ -│ This program is distributed in the hope that it will be useful, but │ -│ WITHOUT ANY WARRANTY; without even the implied warranty of │ -│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │ -│ General Public License for more details. │ -│ │ -│ You should have received a copy of the GNU General Public License │ -│ along with this program; if not, write to the Free Software │ -│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │ -│ 02110-1301 USA │ -╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/assert.h" -#include "libc/dce.h" -#include "libc/macros.h" -#include "tool/build/lib/alu.h" -#include "tool/build/lib/endian.h" -#include "tool/build/lib/flags.h" -#include "tool/build/lib/modrm.h" - -/** - * NexGen32e Bit Shift Unit. - */ -int64_t Bsu(int w, int h, uint64_t x, uint64_t y, uint32_t *f) { - bool of; - uint64_t s, k, t, xm, ym, cf; - assert(w < 4); - k = 8; - k <<= w; - s = 1; - s <<= k - 1; - xm = s; - xm |= s - 1; - ym = w == 3 ? 0x3F : 0x1F; - switch (h & 7) { - case BSU_SHR: - x &= xm; - if ((y &= ym)) { - *f = SetFlag(*f, FLAGS_CF, !!(x & (1ull << (y - 1)))); - x = x >> y; - *f = SetLazyParityByte(*f, x); - *f = SetFlag(*f, FLAGS_OF, !!(((x << 1) ^ x) & s)); - *f = SetFlag(*f, FLAGS_ZF, !x); - *f = SetFlag(*f, FLAGS_SF, !!(x & s)); - } - return x; - case BSU_SAL: - case BSU_SHL: - x &= xm; - if ((y &= ym)) { - *f = SetFlag(*f, FLAGS_CF, (cf = !!(x & (1ull << ((k - y) & ym))))); - x = (x << y) & xm; - *f = SetLazyParityByte(*f, x); - *f = SetFlag(*f, FLAGS_OF, !!(x & s) ^ cf); - *f = SetFlag(*f, FLAGS_ZF, !x); - *f = SetFlag(*f, FLAGS_SF, !!(x & s)); - } - return x; - case BSU_SAR: - x &= xm; - if ((y &= ym)) { - x &= xm; - t = !!(x & s); - x >>= (y - 1); - if (t) x |= ~(xm >> (y - 1)); - *f = SetFlag(*f, FLAGS_CF, x & 1); - x >>= 1; - if (t) x = (x | ~(xm >> y)) & xm; - *f = SetLazyParityByte(*f, x); - *f = SetFlag(*f, FLAGS_OF, 0); - *f = SetFlag(*f, FLAGS_ZF, !x); - *f = SetFlag(*f, FLAGS_SF, !!(x & s)); - } - return x; - case BSU_ROL: - x &= xm; - if (y & (k - 1)) { - y &= k - 1; - x = (x << y | x >> (k - y)) & xm; - *f = SetFlag(*f, FLAGS_CF, x & 1); - *f = SetFlag(*f, FLAGS_OF, ((x >> (k - 1)) ^ x) & 1); - } else if (y & 0x1F) { - *f = SetFlag(*f, FLAGS_CF, x & 1); - *f = SetFlag(*f, FLAGS_OF, ((x >> (k - 1)) ^ x) & 1); - } - return x; - case BSU_ROR: - x &= xm; - if (y & (k - 1)) { - y &= k - 1; - x = (x >> y | x << (k - y)) & xm; - *f = SetFlag(*f, FLAGS_CF, (x >> (k - 1)) & 1); - *f = SetFlag(*f, FLAGS_OF, ((x >> (k - 2)) ^ (x >> (k - 1))) & 1); - } else if (y & 0x1F) { - *f = SetFlag(*f, FLAGS_CF, (x >> (k - 1)) & 1); - *f = SetFlag(*f, FLAGS_OF, ((x >> (k - 2)) ^ (x >> (k - 1))) & 1); - } - return x; - case BSU_RCR: - x &= xm; - if ((y = (y & ym) % (k + 1))) { - cf = GetFlag(*f, FLAGS_CF); - *f = SetFlag(*f, FLAGS_CF, (x >> (y - 1)) & 1); - if (y == 1) { - x = (x >> 1 | cf << (k - 1)) & xm; - } else { - x = (x >> y | cf << (k - y) | x << (k + 1 - y)) & xm; - } - *f = SetFlag(*f, FLAGS_OF, (((x << 1) ^ x) >> (k - 1)) & 1); - } - return x; - case BSU_RCL: - x &= xm; - if ((y = (y & ym) % (k + 1))) { - cf = GetFlag(*f, FLAGS_CF); - *f = SetFlag(*f, FLAGS_CF, (t = (x >> (k - y)) & 1)); - if (y == 1) { - x = (x << 1 | cf) & xm; - } else { - x = (x << y | cf << (y - 1) | x >> (k + 1 - y)) & xm; - } - *f = SetFlag(*f, FLAGS_OF, t ^ !!(x & s)); - } - return x; - default: - unreachable; - } -} - -uint64_t BsuDoubleShift(int w, uint64_t x, uint64_t y, uint8_t b, bool isright, - uint32_t *f) { - bool cf, of; - uint64_t s, k, m, z; - k = 8; - k <<= w; - s = 1; - s <<= k - 1; - m = s | s - 1; - b &= w == 3 ? 63 : 31; - x &= m; - if (b) { - if (isright) { - z = x >> b | y << (k - b); - cf = (x >> (b - 1)) & 1; - of = b == 1 && (z & s) != (x & s); - } else { - z = x << b | y >> (k - b); - cf = (x >> (k - b)) & 1; - of = b == 1 && (z & s) != (x & s); - } - x = z; - x &= m; - *f = SetFlag(*f, FLAGS_CF, cf); - *f = SetFlag(*f, FLAGS_OF, of); - *f = SetFlag(*f, FLAGS_ZF, !x); - *f = SetFlag(*f, FLAGS_SF, !!(x & s)); - *f = SetLazyParityByte(*f, x & 0xff); - } - return x; -} diff --git a/tool/build/lib/buildlib.mk b/tool/build/lib/buildlib.mk index 17681816..976935d5 100644 --- a/tool/build/lib/buildlib.mk +++ b/tool/build/lib/buildlib.mk @@ -63,9 +63,15 @@ $(TOOL_BUILD_LIB_A).pkg: \ $(TOOL_BUILD_LIB_A_OBJS) \ $(foreach x,$(TOOL_BUILD_LIB_A_DIRECTDEPS),$($(x)_A).pkg) -# $(TOOL_BUILD_LIB_A_OBJS): \ -# OVERRIDE_CFLAGS += \ -# -fsanitize=address +ifeq (,$(MODE)) +$(TOOL_BUILD_LIB_A_OBJS): \ + OVERRIDE_CFLAGS += \ + -fsanitize=address +endif + +o/$(MODE)/tool/build/lib/ssefloat.o: \ + TARGET_ARCH += \ + -msse3 TOOL_BUILD_LIB_LIBS = $(foreach x,$(TOOL_BUILD_LIB_ARTIFACTS),$($(x))) TOOL_BUILD_LIB_SRCS = $(foreach x,$(TOOL_BUILD_LIB_ARTIFACTS),$($(x)_SRCS)) diff --git a/test/tool/build/lib/x87_test.c b/tool/build/lib/cga.c similarity index 72% rename from test/tool/build/lib/x87_test.c rename to tool/build/lib/cga.c index 672d0975..53b30b70 100644 --- a/test/tool/build/lib/x87_test.c +++ b/tool/build/lib/cga.c @@ -17,23 +17,27 @@ │ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │ │ 02110-1301 USA │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/testlib/testlib.h" -#include "tool/build/lib/x87.h" +#include "libc/macros.h" +#include "libc/str/str.h" +#include "tool/build/lib/buffer.h" +#include "tool/build/lib/cga.h" -TEST(x87, fprem) { - ASSERT_LDBL_EQ(1, fprem(1, -1.5, NULL)); - ASSERT_LDBL_EQ(1.1766221079117338e-14L, - fprem(12300000000000000.L, .0000000000000123L, NULL)); -} +static const uint8_t kCgaToAnsi[] = {30, 34, 32, 36, 31, 35, 33, 37, + 90, 94, 92, 96, 91, 95, 93, 97}; -TEST(x87, fprem1) { - ASSERT_LDBL_EQ(-.5, fprem1(1, -1.5, NULL)); - ASSERT_LDBL_EQ(-5.337789208826618e-16, - fprem1(12300000000000000.L, .0000000000000123L, NULL)); -} - -TEST(x87, fpremFlags) { - uint32_t sw = 0xffff; - ASSERT_LDBL_EQ(1, fprem(1, -1.5, &sw)); - ASSERT_EQ(0b1011100011111111, sw); +void DrawCga(struct Panel *p, uint8_t v[25][80][2]) { + unsigned y, x, n, a; + n = MIN(25, p->bottom - p->top); + for (y = 0; y < n; ++y) { + a = -1; + for (x = 0; x < 80; ++x) { + if (v[y][x][1] != a) { + a = v[y][x][1]; + AppendFmt(&p->lines[y], "\e[%d;%dm", kCgaToAnsi[a & 0x0F], + kCgaToAnsi[(a & 0xF0) >> 4] + 10); + } + AppendWide(&p->lines[y], kCp437[v[y][x][0]]); + } + AppendStr(&p->lines[y], "\e[0m"); + } } diff --git a/tool/build/lib/cga.h b/tool/build/lib/cga.h new file mode 100644 index 00000000..51ec429a --- /dev/null +++ b/tool/build/lib/cga.h @@ -0,0 +1,11 @@ +#ifndef COSMOPOLITAN_TOOL_BUILD_LIB_CGA_H_ +#define COSMOPOLITAN_TOOL_BUILD_LIB_CGA_H_ +#include "tool/build/lib/panel.h" +#if !(__ASSEMBLER__ + __LINKER__ + 0) +COSMOPOLITAN_C_START_ + +void DrawCga(struct Panel *, uint8_t[25][80][2]); + +COSMOPOLITAN_C_END_ +#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ +#endif /* COSMOPOLITAN_TOOL_BUILD_LIB_CGA_H_ */ diff --git a/tool/build/lib/cond.h b/tool/build/lib/cond.h deleted file mode 100644 index e81f4a02..00000000 --- a/tool/build/lib/cond.h +++ /dev/null @@ -1,50 +0,0 @@ -#ifndef COSMOPOLITAN_TOOL_BUILD_LIB_COND_H_ -#define COSMOPOLITAN_TOOL_BUILD_LIB_COND_H_ -#include "tool/build/lib/flags.h" -#include "tool/build/lib/machine.h" -#if !(__ASSEMBLER__ + __LINKER__ + 0) - -forceinline bool GetCond(struct Machine *m, int x) { - uint32_t f = m->flags; - switch (x) { - case 0: - return GetFlag(f, FLAGS_OF); - case 1: - return !GetFlag(f, FLAGS_OF); - case 2: - return GetFlag(f, FLAGS_CF); - case 3: - return !GetFlag(f, FLAGS_CF); - case 4: - return GetFlag(f, FLAGS_ZF); - case 5: - return !GetFlag(f, FLAGS_ZF); - case 6: - return GetFlag(f, FLAGS_CF) || GetFlag(f, FLAGS_ZF); - case 7: - return !GetFlag(f, FLAGS_CF) && !GetFlag(f, FLAGS_ZF); - case 8: - return GetFlag(f, FLAGS_SF); - case 9: - return !GetFlag(f, FLAGS_SF); - case 10: - return GetFlag(f, FLAGS_PF); - case 11: - return !GetFlag(f, FLAGS_PF); - case 12: - return GetFlag(f, FLAGS_SF) != GetFlag(f, FLAGS_OF); - case 13: - return GetFlag(f, FLAGS_SF) == GetFlag(f, FLAGS_OF); - case 14: - return GetFlag(f, FLAGS_ZF) || - GetFlag(f, FLAGS_SF) != GetFlag(f, FLAGS_OF); - case 15: - return !GetFlag(f, FLAGS_ZF) && - GetFlag(f, FLAGS_SF) == GetFlag(f, FLAGS_OF); - default: - unreachable; - } -} - -#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ -#endif /* COSMOPOLITAN_TOOL_BUILD_LIB_COND_H_ */ diff --git a/tool/build/lib/cpuid.c b/tool/build/lib/cpuid.c index 7c9624c0..b1eadfe9 100644 --- a/tool/build/lib/cpuid.c +++ b/tool/build/lib/cpuid.c @@ -20,7 +20,7 @@ #include "tool/build/lib/endian.h" #include "tool/build/lib/machine.h" -void OpCpuid(struct Machine *m) { +void OpCpuid(struct Machine *m, uint32_t rde) { uint32_t ax, bx, cx, dx; ax = 0; bx = 0; diff --git a/tool/build/lib/cpuid.h b/tool/build/lib/cpuid.h index a1c37260..6bc16116 100644 --- a/tool/build/lib/cpuid.h +++ b/tool/build/lib/cpuid.h @@ -1,10 +1,10 @@ #ifndef COSMOPOLITAN_TOOL_BUILD_LIB_CPUID_H_ #define COSMOPOLITAN_TOOL_BUILD_LIB_CPUID_H_ +#include "tool/build/lib/machine.h" #if !(__ASSEMBLER__ + __LINKER__ + 0) COSMOPOLITAN_C_START_ -#include "tool/build/lib/cvt.h" -void OpCpuid(struct Machine *); +void OpCpuid(struct Machine *, uint32_t); COSMOPOLITAN_C_END_ #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ diff --git a/tool/build/lib/cvt.c b/tool/build/lib/cvt.c index a8a7f796..f6273117 100644 --- a/tool/build/lib/cvt.c +++ b/tool/build/lib/cvt.c @@ -26,6 +26,13 @@ #include "tool/build/lib/modrm.h" #include "tool/build/lib/throw.h" +#define kOpCvt0f2a 0 +#define kOpCvtt0f2c 4 +#define kOpCvt0f2d 8 +#define kOpCvt0f5a 12 +#define kOpCvt0f5b 16 +#define kOpCvt0fE6 20 + static double SseRoundDouble(struct Machine *m, double x) { switch (m->sse.rc) { case 0: @@ -285,7 +292,7 @@ static void OpVdqWpdCvtpd2dq(struct Machine *m, uint32_t rde) { memcpy(XmmRexrReg(m, rde), n, 8); } -void OpCvt(struct Machine *m, uint32_t rde, unsigned long op) { +static void OpCvt(struct Machine *m, uint32_t rde, unsigned long op) { switch (op | Rep(rde) | Osz(rde)) { case kOpCvt0f2a + 0: OpVpsQpiCvtpi2ps(m, rde); @@ -354,6 +361,30 @@ void OpCvt(struct Machine *m, uint32_t rde, unsigned long op) { OpVpdWdqCvtdq2pd(m, rde); break; default: - OpUd(m); + OpUd(m, rde); } } + +void OpCvt0f2a(struct Machine *m, uint32_t rde) { + OpCvt(m, rde, kOpCvt0f2a); +} + +void OpCvtt0f2c(struct Machine *m, uint32_t rde) { + OpCvt(m, rde, kOpCvtt0f2c); +} + +void OpCvt0f2d(struct Machine *m, uint32_t rde) { + OpCvt(m, rde, kOpCvt0f2d); +} + +void OpCvt0f5a(struct Machine *m, uint32_t rde) { + OpCvt(m, rde, kOpCvt0f5a); +} + +void OpCvt0f5b(struct Machine *m, uint32_t rde) { + OpCvt(m, rde, kOpCvt0f5b); +} + +void OpCvt0fE6(struct Machine *m, uint32_t rde) { + OpCvt(m, rde, kOpCvt0fE6); +} diff --git a/tool/build/lib/cvt.h b/tool/build/lib/cvt.h index cb306d89..9f5f1eec 100644 --- a/tool/build/lib/cvt.h +++ b/tool/build/lib/cvt.h @@ -4,14 +4,12 @@ #if !(__ASSEMBLER__ + __LINKER__ + 0) COSMOPOLITAN_C_START_ -#define kOpCvt0f2a 0 -#define kOpCvtt0f2c 4 -#define kOpCvt0f2d 8 -#define kOpCvt0f5a 12 -#define kOpCvt0f5b 16 -#define kOpCvt0fE6 20 - -void OpCvt(struct Machine *, uint32_t, unsigned long); +void OpCvt0f2a(struct Machine *, uint32_t); +void OpCvtt0f2c(struct Machine *, uint32_t); +void OpCvt0f2d(struct Machine *, uint32_t); +void OpCvt0f5a(struct Machine *, uint32_t); +void OpCvt0f5b(struct Machine *, uint32_t); +void OpCvt0fE6(struct Machine *, uint32_t); COSMOPOLITAN_C_END_ #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ diff --git a/tool/build/lib/dis.c b/tool/build/lib/dis.c index 9d272483..fd292bc5 100644 --- a/tool/build/lib/dis.c +++ b/tool/build/lib/dis.c @@ -165,83 +165,82 @@ long DisFind(struct Dis *d, int64_t addr) { return -1; } -void Dis(struct Dis *d, struct Machine *m, int64_t addr) { +static long DisOne(struct Dis *d, struct Machine *m, int64_t addr) { + void *r; + unsigned k; + uint8_t b[15]; + struct DisOp op; + long i, n, symbol; + n = 15; + if ((symbol = DisFindSym(d, addr)) != -1) { + if (d->syms.p[symbol].addr <= addr && + addr < d->syms.p[symbol].addr + d->syms.p[symbol].size) { + n = d->syms.p[symbol].size - (addr - d->syms.p[symbol].addr); + } + if (addr == d->syms.p[symbol].addr && d->syms.p[symbol].name) { + op.addr = addr; + op.size = 0; + op.active = true; + DisLabel((struct DisBuilder){d, d->xedd, addr}, d->buf, + d->syms.stab + d->syms.p[symbol].name); + if (!(op.s = strdup(d->buf))) return -1; + APPEND(&d->ops.p, &d->ops.i, &d->ops.n, &op); + } + } + n = MAX(1, MIN(15, n)); + if (!(r = FindReal(m, addr))) return -1; + k = 0x1000 - (addr & 0xfff); + if (n <= k) { + memcpy(b, r, n); + } else { + memcpy(b, r, k); + if ((r = FindReal(m, addr + k))) { + memcpy(b + k, r, n - k); + } else { + n = k; + } + } + xed_decoded_inst_zero_set_mode(d->xedd, m->mode); + xed_instruction_length_decode(d->xedd, b, n); + n = d->xedd->op.error ? 1 : d->xedd->length; + op.addr = addr; + op.size = n; + op.active = true; + op.s = NULL; + APPEND(&d->ops.p, &d->ops.i, &d->ops.n, &op); + return n; +} + +long Dis(struct Dis *d, struct Machine *m, int64_t addr, int lines) { + int64_t i, j, symbol; + DisFreeOps(&d->ops); + if ((symbol = DisFindSym(d, addr)) != -1 && + (d->syms.p[symbol].addr < addr && + addr < d->syms.p[symbol].addr + d->syms.p[symbol].size)) { + for (i = d->syms.p[symbol].addr; i < addr; i += j) { + if ((j = DisOne(d, m, i)) == -1) return -1; + } + } + for (i = 0; i < lines; ++i, addr += j) { + if ((j = DisOne(d, m, addr)) == -1) return -1; + } + return 0; +} + +const char *DisGetLine(struct Dis *d, struct Machine *m, size_t i) { char *p; void *r[2]; - bool iscode; - int64_t unique; - struct DisOp op; - long i, j, n, si, max, toto, symbol; - unique = 0; - max = 999999; - DisFreeOps(&d->ops); - for (i = 0; i < max; ++i) { - xed_decoded_inst_zero_set_mode(d->xedd, XED_MACHINE_MODE_LONG_64); - if ((symbol = DisFindSym(d, addr)) != -1) { - iscode = true; /* d->syms.p[symbol].iscode; */ - n = iscode ? CODELIM : DATALIM; - if (d->syms.p[symbol].size) { - n = MIN(n, d->syms.p[symbol].size); - } else if (symbol + 1 < d->syms.i && - d->syms.p[symbol + 1].addr > d->syms.p[symbol].addr) { - n = MIN(n, d->syms.p[symbol + 1].addr - d->syms.p[symbol].addr); - } - if (addr == d->syms.p[symbol].addr && d->syms.p[symbol].name) { - op.addr = addr; - op.unique = unique++; - op.size = 0; - op.active = true; - DisLabel((struct DisBuilder){d, d->xedd, addr}, d->buf, - d->syms.stab + d->syms.p[symbol].name); - if (!(op.s = strdup(d->buf))) break; - APPEND(&d->ops.p, &d->ops.i, &d->ops.n, &op); - } - } else { - iscode = DisIsText(d, addr); - n = CODELIM; - } - DCHECK_GT(n, 0); - DCHECK_LE(n, ARRAYLEN(d->raw)); - memset(r, 0, sizeof(r)); - if (!(r[0] = FindReal(m, addr))) { - max = MIN(100, max); - n = MIN(DATALIM, 0x1000 - (addr & 0xfff)); - DCHECK_GT(n, 0); - memset(d->raw, 0xCC, DATALIM); - } else if ((addr & 0xfff) + n <= 0x1000) { - memcpy(d->raw, r[0], n); - } else if ((r[1] = FindReal(m, ROUNDUP(addr, 0x1000)))) { - si = 0x1000 - (addr & 0xfff); - memcpy(d->raw, r[0], si); - memcpy(d->raw + si, r[1], n - si); - } else { - n = 0x1000 - (addr & 0xfff); - DCHECK_GT(n, 0); - memcpy(d->raw, r[0], n); - } - if (!NoDebug()) memset(d->buf, 0x55, sizeof(d->buf)); - if (1 || iscode) { - xed_instruction_length_decode(d->xedd, d->raw, n); - DCHECK_GT(n, 0); - p = DisLineCode((struct DisBuilder){d, d->xedd, addr}, d->buf); - CHECK_LT(p - d->buf, sizeof(d->buf)); - n = d->xedd->op.error ? 1 : d->xedd->length; - DCHECK_GT(n, 0); - } else { - p = DisLineData((struct DisBuilder){d, d->xedd, addr}, d->buf, d->raw, n); - CHECK_LT(p - d->buf, sizeof(d->buf)); - } - DCHECK_LT(p, d->buf + sizeof(d->buf)); - DCHECK_LT(strlen(d->buf), sizeof(d->buf)); - op.addr = addr; - op.unique = unique++; - op.size = n; - op.active = true; - if (!(op.s = strdup(d->buf))) break; - APPEND(&d->ops.p, &d->ops.i, &d->ops.n, &op); - addr += n; - n = 0; - } + uint8_t b[15]; + if (i >= d->ops.i) return ""; + if (d->ops.p[i].s) return d->ops.p[i].s; + DCHECK_LE(d->ops.p[i].size, 15); + xed_decoded_inst_zero_set_mode(d->xedd, m->mode); + xed_instruction_length_decode( + d->xedd, AccessRam(m, d->ops.p[i].addr, d->ops.p[i].size, r, b, true), + d->ops.p[i].size); + p = DisLineCode((struct DisBuilder){d, d->xedd, d->ops.p[i].addr}, d->buf); + CHECK_LT(p - d->buf, sizeof(d->buf)); + return d->buf; } void DisFreeOp(struct DisOp *o) { diff --git a/tool/build/lib/dis.h b/tool/build/lib/dis.h index 572b0e1e..08dd9068 100644 --- a/tool/build/lib/dis.h +++ b/tool/build/lib/dis.h @@ -11,8 +11,7 @@ struct Dis { size_t i, n; struct DisOp { int64_t addr; - int unique; - int size; + uint8_t size; bool active; char *s; } * p; @@ -46,7 +45,6 @@ struct Dis { } * p; } edges; struct XedDecodedInst xedd[1]; - uint8_t raw[512]; char buf[512]; }; @@ -66,8 +64,8 @@ struct DisHigh { extern struct DisHigh *g_dis_high; +long Dis(struct Dis *, struct Machine *, int64_t, int); long DisFind(struct Dis *, int64_t); -void Dis(struct Dis *, struct Machine *, int64_t); void DisFree(struct Dis *); void DisFreeOp(struct DisOp *); void DisFreeOps(struct DisOps *); @@ -80,6 +78,7 @@ const char *DisSpec(struct XedDecodedInst *, char *); char *DisInst(struct DisBuilder, char *, const char *); char *DisArg(struct DisBuilder, char *, const char *); char *DisHigh(char *, int); +const char *DisGetLine(struct Dis *, struct Machine *, size_t); COSMOPOLITAN_C_END_ #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ diff --git a/tool/build/lib/disarg.c b/tool/build/lib/disarg.c index 9eda298c..a901398f 100644 --- a/tool/build/lib/disarg.c +++ b/tool/build/lib/disarg.c @@ -17,6 +17,7 @@ │ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │ │ 02110-1301 USA │ ╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/assert.h" #include "libc/bits/bits.h" #include "libc/conv/itoa.h" #include "libc/limits.h" @@ -27,22 +28,15 @@ #include "tool/build/lib/endian.h" #include "tool/build/lib/modrm.h" -#define SSTRCMP8(S1, S2) \ - ({ \ - uint64_t x, y; \ - x = READ64BE(S1); \ - y = READ64BE(S2); \ - x > y ? 1 : x < y ? -1 : 0; \ - }) - static const char kScale[4][4] = {"", ",2", ",4", ",8"}; static const char kSegName[8][3] = {"es", "cs", "ss", "ds", "fs", "gs"}; -static const char kSegOverride[8][3] = {"", "cs", "ds", "es", "fs", "gs", "ss"}; +static const char kPuttingOnTheRiz[2][4] = {"eiz", "riz"}; +static const char kPuttingOnTheRip[2][4] = {"eip", "rip"}; static const char kRegisterName8[2][2][8][5] = { {{"al", "cl", "dl", "bl", "ah", "ch", "dh", "bh"}, {"al", "cl", "dl", "bl", "spl", "bpl", "sil", "dil"}}, - {{"???", "???", "???", "???", "???", "???", "???", "???"}, + {{"wut", "wut", "wut", "wut", "wut", "wut", "wut", "wut"}, {"r8b", "r9b", "r10b", "r11b", "r12b", "r13b", "r14b", "r15b"}}, }; @@ -57,12 +51,18 @@ static const char kRegisterName[2][2][2][8][5] = { {"r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15"}}}, }; +static const char kControlName[8][4] = { + "cr0", "wut", "cr2", "cr3", "cr4", "wut", "wut", "wut", +}; + static int64_t RipRelative(struct DisBuilder b, int64_t d) { return b.addr + b.xedd->length + d; } -static const char *GetAddrReg(struct DisBuilder b, uint8_t x, uint8_t r) { - return kRegisterName[0][!Asz(b.xedd->op.rde)][x & 1][r & 7]; +static const char *GetAddrReg(struct DisBuilder b, uint32_t rde, uint8_t x, + uint8_t r) { + return kRegisterName[Eamode(rde) == XED_MODE_REAL] + [Eamode(rde) == XED_MODE_LONG][x & 1][r & 7]; } static char *DisRegister(char *p, const char *s) { @@ -73,13 +73,6 @@ static char *DisRegister(char *p, const char *s) { return p; } -static char *DisLiteral(char *p, const char *s) { - if (g_dis_high) p = DisHigh(p, g_dis_high->literal); - p = stpcpy(p, s); - if (g_dis_high) p = DisHigh(p, -1); - return p; -} - static char *DisComment(char *p, const char *s) { if (g_dis_high) p = DisHigh(p, g_dis_high->comment); p = stpcpy(p, s); @@ -87,30 +80,14 @@ static char *DisComment(char *p, const char *s) { return p; } -static char *DisRegisterByte(struct DisBuilder b, char *p, bool g, int r) { - return DisRegister(p, kRegisterName8[g][Rex(b.xedd->op.rde)][r]); +static char *DisRegisterByte(struct DisBuilder b, uint32_t rde, char *p, bool g, + int r) { + return DisRegister(p, kRegisterName8[g][Rex(rde)][r]); } -static char *DisRegisterWord(struct DisBuilder b, char *p, bool g, int r) { - return DisRegister( - p, kRegisterName[Osz(b.xedd->op.rde)][Rexw(b.xedd->op.rde)][g][r]); -} - -static char *DisGvqp(struct DisBuilder b, char *p) { - return DisRegisterWord(b, p, Rexr(b.xedd->op.rde), ModrmReg(b.xedd->op.rde)); -} - -static char *DisGdqp(struct DisBuilder b, char *p) { - return DisRegister(p, kRegisterName[0][Rexw(b.xedd->op.rde)][Rexr( - b.xedd->op.rde)][ModrmReg(b.xedd->op.rde)]); -} - -static char *DisGb(struct DisBuilder b, char *p) { - return DisRegisterByte(b, p, Rexr(b.xedd->op.rde), ModrmReg(b.xedd->op.rde)); -} - -static uint8_t DisSeg(struct DisBuilder b) { - return b.xedd->op.seg_ovd ? b.xedd->op.seg_ovd : b.xedd->op.hint; +static char *DisRegisterWord(struct DisBuilder b, uint32_t rde, char *p, bool g, + int r) { + return DisRegister(p, kRegisterName[Osz(rde)][Rexw(rde)][g][r]); } static char *DisInt(char *p, int64_t x) { @@ -147,40 +124,113 @@ static char *DisSym(struct DisBuilder b, char *p, int64_t addr) { } } -static char *DisM(struct DisBuilder b, char *p) { - int64_t disp; - const char *seg, *base, *index, *scale; - base = index = scale = NULL; - seg = kSegOverride[b.xedd->op.seg_ovd ? b.xedd->op.seg_ovd : b.xedd->op.hint]; - if (*seg) { - p = DisRegister(p, seg); +static char *DisSymLiteral(struct DisBuilder b, char *p, uint64_t x) { + *p++ = '$'; + if (g_dis_high) p = DisHigh(p, g_dis_high->literal); + p = DisSym(b, p, x); + if (g_dis_high) p = DisHigh(p, -1); + return p; +} + +static char *DisXmm(struct DisBuilder b, uint32_t rde, char *p, const char *s, + int reg) { + if (g_dis_high) p = DisHigh(p, g_dis_high->reg); + *p++ = '%'; + p = stpcpy(p, s); + p += uint64toarray_radix10(Rexr(rde) << 3 | reg, p); + if (g_dis_high) p = DisHigh(p, -1); + return p; +} + +static char *DisGvqp(struct DisBuilder b, uint32_t rde, char *p) { + return DisRegisterWord(b, rde, p, Rexr(rde), ModrmReg(rde)); +} + +static char *DisGdqp(struct DisBuilder b, uint32_t rde, char *p) { + return DisRegister(p, kRegisterName[0][Rexw(rde)][Rexr(rde)][ModrmReg(rde)]); +} + +static char *DisGb(struct DisBuilder b, uint32_t rde, char *p) { + return DisRegisterByte(b, rde, p, Rexr(rde), ModrmReg(rde)); +} + +static char *DisSego(struct DisBuilder b, uint32_t rde, char *p) { + int seg; + seg = Sego(rde) ? Sego(rde) : b.xedd->op.hint; + if (seg) { + p = DisRegister(p, kSegName[seg - 1]); *p++ = ':'; } - if (ModrmMod(b.xedd->op.rde) == 0b01 || ModrmMod(b.xedd->op.rde) == 0b10 || - IsRipRelative(b.xedd->op.rde) || - (ModrmMod(b.xedd->op.rde) == 0b00 && ModrmRm(b.xedd->op.rde) == 0b100 && - SibBase(b.xedd->op.rde) == 0b101)) { + return p; +} + +static char *DisM(struct DisBuilder b, uint32_t rde, char *p) { + int64_t disp; + const char *base, *index, *scale; + p = DisSego(b, rde, p); + base = index = scale = NULL; + if (ModrmMod(rde) == 0b01 || ModrmMod(rde) == 0b10 || IsRipRelative(rde) || + (Eamode(rde) == XED_MODE_REAL && ModrmRm(rde) == 6 && !ModrmMod(rde)) || + (ModrmMod(rde) == 0b00 && ModrmRm(rde) == 0b100 && + SibBase(b.xedd) == 0b101)) { disp = b.xedd->op.disp; - if (IsRipRelative(b.xedd->op.rde)) disp = RipRelative(b, disp); + if (IsRipRelative(rde)) disp = RipRelative(b, disp); p = DisSym(b, p, disp); } - if (!SibExists(b.xedd->op.rde)) { - DCHECK(!b.xedd->op.has_sib); - if (IsRipRelative(b.xedd->op.rde)) { - base = "rip"; - } else { - base = GetAddrReg(b, Rexb(b.xedd->op.rde), ModrmRm(b.xedd->op.rde)); + if (Eamode(rde) != XED_MODE_REAL) { + if (!SibExists(rde)) { + DCHECK(!b.xedd->op.has_sib); + if (IsRipRelative(rde)) { + if (Mode(rde) == XED_MODE_LONG) { + base = kPuttingOnTheRip[Eamode(rde) == XED_MODE_LONG]; + } + } else { + base = GetAddrReg(b, rde, Rexb(rde), ModrmRm(rde)); + } + } else if (!SibIsAbsolute(b.xedd, rde)) { + if (SibHasBase(b.xedd, rde)) { + base = GetAddrReg(b, rde, Rexb(rde), SibBase(b.xedd)); + } + if (SibHasIndex(b.xedd)) { + index = GetAddrReg(b, rde, Rexx(b.xedd), SibIndex(b.xedd)); + } else if (b.xedd->op.scale) { + index = kPuttingOnTheRiz[Eamode(rde) == XED_MODE_LONG]; + } + scale = kScale[b.xedd->op.scale]; } - } else if (!SibIsAbsolute(b.xedd->op.rde)) { - if (SibHasBase(b.xedd->op.rde)) { - base = GetAddrReg(b, Rexb(b.xedd->op.rde), SibBase(b.xedd->op.rde)); + } else { + switch (ModrmRm(rde)) { + case 0: + base = "bx"; + index = "si"; + break; + case 1: + base = "bx"; + index = "di"; + break; + case 2: + base = "bp"; + index = "si"; + break; + case 3: + base = "bp"; + index = "di"; + break; + case 4: + base = "si"; + break; + case 5: + base = "di"; + break; + case 6: + if (ModrmMod(rde)) base = "bp"; + break; + case 7: + base = "bx"; + break; + default: + unreachable; } - if (SibHasIndex(b.xedd->op.rde)) { - index = GetAddrReg(b, Rexx(b.xedd->op.rde), SibIndex(b.xedd->op.rde)); - } else if (b.xedd->op.scale) { - index = Asz(b.xedd->op.rde) ? "eiz" : "riz"; - } - scale = kScale[b.xedd->op.scale]; } if (base || index) { *p++ = '('; @@ -190,7 +240,9 @@ static char *DisM(struct DisBuilder b, char *p) { if (index) { *p++ = ','; p = DisRegister(p, index); - p = stpcpy(p, scale); + if (scale) { + p = stpcpy(p, scale); + } } *p++ = ')'; } @@ -198,237 +250,245 @@ static char *DisM(struct DisBuilder b, char *p) { return p; } -static char *DisEb(struct DisBuilder b, char *p) { - if (IsModrmRegister(b.xedd->op.rde)) { - return DisRegisterByte(b, p, Rexb(b.xedd->op.rde), ModrmRm(b.xedd->op.rde)); +static char *DisEb(struct DisBuilder b, uint32_t rde, char *p) { + if (IsModrmRegister(rde)) { + return DisRegisterByte(b, rde, p, Rexb(rde), ModrmRm(rde)); } else { - return DisM(b, p); + return DisM(b, rde, p); } } -static char *DisEvqp(struct DisBuilder b, char *p) { - if (IsModrmRegister(b.xedd->op.rde)) { - return DisRegisterWord(b, p, Rexb(b.xedd->op.rde), ModrmRm(b.xedd->op.rde)); +static char *DisEvqp(struct DisBuilder b, uint32_t rde, char *p) { + if (IsModrmRegister(rde)) { + return DisRegisterWord(b, rde, p, Rexb(rde), ModrmRm(rde)); } else { - return DisM(b, p); + return DisM(b, rde, p); } } -static char *DisEdqp(struct DisBuilder b, char *p) { - if (IsModrmRegister(b.xedd->op.rde)) { - return DisRegister(p, kRegisterName[0][Rexw(b.xedd->op.rde)][Rexb( - b.xedd->op.rde)][ModrmRm(b.xedd->op.rde)]); +static char *DisEdqp(struct DisBuilder b, uint32_t rde, char *p) { + if (IsModrmRegister(rde)) { + return DisRegister(p, kRegisterName[0][Rexw(rde)][Rexb(rde)][ModrmRm(rde)]); } else { - return DisM(b, p); + return DisM(b, rde, p); } } -static char *DisEvq(struct DisBuilder b, char *p) { +static char *DisEv(struct DisBuilder b, uint32_t rde, char *p) { const char *s; - if (IsModrmRegister(b.xedd->op.rde)) { - if (Osz(b.xedd->op.rde)) { - s = kRegisterName[1][0][Rexb(b.xedd->op.rde)][ModrmRm(b.xedd->op.rde)]; - } else { - s = kRegisterName[0][1][Rexb(b.xedd->op.rde)][ModrmRm(b.xedd->op.rde)]; - } - return DisRegister(p, s); + if (IsModrmRegister(rde)) { + return DisRegister(p, kRegisterName[Osz(rde)][0][Rexb(rde)][ModrmRm(rde)]); } else { - return DisM(b, p); + return DisM(b, rde, p); } } -static char *DisEd(struct DisBuilder b, char *p) { - if (IsModrmRegister(b.xedd->op.rde)) { - return DisRegister( - p, kRegisterName[0][0][Rexb(b.xedd->op.rde)][ModrmRm(b.xedd->op.rde)]); +static char *DisGvq(struct DisBuilder b, uint32_t rde, char *p, int r) { + const char *s; + if (Mode(rde) == XED_MODE_LONG) { + s = kRegisterName[Osz(rde)][!Osz(rde)][Rexb(rde)][r]; } else { - return DisM(b, p); + s = kRegisterName[Osz(rde)][0][Rexb(rde)][r]; + } + return DisRegister(p, s); +} + +static char *DisZvq(struct DisBuilder b, uint32_t rde, char *p) { + return DisGvq(b, rde, p, ModrmSrm(rde)); +} + +static char *DisEvq(struct DisBuilder b, uint32_t rde, char *p) { + if (IsModrmRegister(rde)) { + return DisGvq(b, rde, p, ModrmRm(rde)); + } else { + return DisM(b, rde, p); } } -static char *DisEq(struct DisBuilder b, char *p) { - if (IsModrmRegister(b.xedd->op.rde)) { - return DisRegister( - p, kRegisterName[0][1][Rexb(b.xedd->op.rde)][ModrmRm(b.xedd->op.rde)]); +static char *DisEd(struct DisBuilder b, uint32_t rde, char *p) { + if (IsModrmRegister(rde)) { + return DisRegister(p, kRegisterName[0][0][Rexb(rde)][ModrmRm(rde)]); } else { - return DisM(b, p); + return DisM(b, rde, p); } } -static char *DisZvq(struct DisBuilder b, char *p) { - if (Osz(b.xedd->op.rde)) { - return DisRegister( - p, kRegisterName[1][0][Rexb(b.xedd->op.rde)][ModrmSrm(b.xedd->op.rde)]); +static char *DisEq(struct DisBuilder b, uint32_t rde, char *p) { + if (IsModrmRegister(rde)) { + return DisRegister(p, kRegisterName[0][1][Rexb(rde)][ModrmRm(rde)]); } else { - return DisRegister( - p, kRegisterName[0][1][Rexb(b.xedd->op.rde)][ModrmSrm(b.xedd->op.rde)]); + return DisM(b, rde, p); } } -static char *DisZvqp(struct DisBuilder b, char *p) { - return DisRegisterWord(b, p, Rexb(b.xedd->op.rde), ModrmSrm(b.xedd->op.rde)); +static char *DisZvqp(struct DisBuilder b, uint32_t rde, char *p) { + return DisRegisterWord(b, rde, p, Rexb(rde), ModrmSrm(rde)); } -static char *DisZb(struct DisBuilder b, char *p) { - return DisRegisterByte(b, p, Rexb(b.xedd->op.rde), ModrmSrm(b.xedd->op.rde)); +static char *DisZb(struct DisBuilder b, uint32_t rde, char *p) { + return DisRegisterByte(b, rde, p, Rexb(rde), ModrmSrm(rde)); } -static char *DisEax(struct DisBuilder b, char *p) { - return DisRegister(p, kRegisterName[Osz(b.xedd->op.rde)][0][0][0]); +static char *DisEax(struct DisBuilder b, uint32_t rde, char *p) { + return DisRegister(p, kRegisterName[Osz(rde)][0][0][0]); } -static char *DisRax(struct DisBuilder b, char *p) { +static char *DisRax(struct DisBuilder b, uint32_t rde, char *p) { + return DisRegister(p, kRegisterName[Osz(rde)][Rexw(rde)][0][0]); +} + +static char *DisRdx(struct DisBuilder b, uint32_t rde, char *p) { + return DisRegister(p, kRegisterName[Osz(rde)][Rexw(rde)][0][2]); +} + +static char *DisCd(struct DisBuilder b, uint32_t rde, char *p) { + return DisRegister(p, kControlName[ModrmReg(rde)]); +} + +static char *DisHd(struct DisBuilder b, uint32_t rde, char *p) { return DisRegister( - p, kRegisterName[Osz(b.xedd->op.rde)][Rexw(b.xedd->op.rde)][0][0]); + p, kRegisterName[0][Mode(rde) == XED_MODE_LONG][0][ModrmRm(rde)]); } -static char *DisRdx(struct DisBuilder b, char *p) { - return DisRegister( - p, kRegisterName[Osz(b.xedd->op.rde)][Rexw(b.xedd->op.rde)][0][2]); +static char *DisImm(struct DisBuilder b, uint32_t rde, char *p) { + return DisSymLiteral(b, p, b.xedd->op.uimm0); } -static char *DisImm(struct DisBuilder b, char *p) { +static char *DisRvds(struct DisBuilder b, uint32_t rde, char *p) { + return DisSymLiteral(b, p, b.xedd->op.disp); +} + +static char *DisKvds(struct DisBuilder b, uint32_t rde, char *p) { *p++ = '$'; if (g_dis_high) p = DisHigh(p, g_dis_high->literal); - p = DisSym(b, p, b.xedd->op.uimm0); + p = DisInt(p, b.xedd->op.uimm0); if (g_dis_high) p = DisHigh(p, -1); return p; } -static char *DisJbs(struct DisBuilder b, char *p) { +static char *DisOne(struct DisBuilder b, uint32_t rde, char *p) { + *p++ = '$'; + if (g_dis_high) p = DisHigh(p, g_dis_high->literal); + p = stpcpy(p, "1"); + if (g_dis_high) p = DisHigh(p, -1); + return p; +} + +static char *DisJbs(struct DisBuilder b, uint32_t rde, char *p) { if (b.xedd->op.disp > 0) *p++ = '+'; p += int64toarray_radix10(b.xedd->op.disp, p); return p; } -static char *DisJb(struct DisBuilder b, char *p) { +static char *DisJb(struct DisBuilder b, uint32_t rde, char *p) { if (b.xedd->op.disp > 0) *p++ = '+'; p += uint64toarray_radix10(b.xedd->op.disp & 0xff, p); return p; } -static char *DisJvds(struct DisBuilder b, char *p) { +static char *DisJvds(struct DisBuilder b, uint32_t rde, char *p) { return DisSym(b, p, RipRelative(b, b.xedd->op.disp)); } -static char *DisAbs(struct DisBuilder b, char *p) { +static char *DisAbs(struct DisBuilder b, uint32_t rde, char *p) { return DisSym(b, p, b.xedd->op.disp); } -static char *DisSw(struct DisBuilder b, char *p) { - if (kSegName[ModrmReg(b.xedd->op.rde)][0]) { - p = DisRegister(p, kSegName[ModrmReg(b.xedd->op.rde)]); - } - *p = '\0'; +static char *DisSw(struct DisBuilder b, uint32_t rde, char *p) { + if (kSegName[ModrmReg(rde)][0]) p = DisRegister(p, kSegName[ModrmReg(rde)]); return p; } -static char *DisY(struct DisBuilder b, char *p) { +static char *DisSpecialAddr(struct DisBuilder b, uint32_t rde, char *p, int r) { *p++ = '('; - p = DisRegister(p, Asz(b.xedd->op.rde) ? "edi" : "rdi"); + p = DisRegister(p, GetAddrReg(b, rde, 0, r)); *p++ = ')'; *p = '\0'; return p; } -static char *DisX(struct DisBuilder b, char *p) { - if (kSegOverride[b.xedd->op.seg_ovd][0]) { - p = DisRegister(p, kSegOverride[b.xedd->op.seg_ovd]); - } - *p++ = '('; - p = DisRegister(p, Asz(b.xedd->op.rde) ? "esi" : "rsi"); - *p++ = ')'; - *p = '\0'; - return p; +static char *DisY(struct DisBuilder b, uint32_t rde, char *p) { + return DisSpecialAddr(b, rde, p, 7); // es:di } -static char *DisBBb(struct DisBuilder b, char *p) { - if (kSegOverride[b.xedd->op.seg_ovd][0]) { - p = DisRegister(p, kSegOverride[b.xedd->op.seg_ovd]); - } - *p++ = '('; - p = DisRegister(p, Asz(b.xedd->op.rde) ? "ebx" : "rbx"); - *p++ = ')'; - *p = '\0'; - return p; +static char *DisX(struct DisBuilder b, uint32_t rde, char *p) { + DisSego(b, rde, p); + return DisSpecialAddr(b, rde, p, 6); // ds:si } -static char *DisXmm(struct DisBuilder b, char *p, const char *s, int reg) { - if (g_dis_high) p = DisHigh(p, g_dis_high->reg); - *p++ = '%'; - p = stpcpy(p, s); - p += uint64toarray_radix10(Rexr(b.xedd->op.rde) << 3 | reg, p); - if (g_dis_high) p = DisHigh(p, -1); - return p; +static char *DisBBb(struct DisBuilder b, uint32_t rde, char *p) { + DisSego(b, rde, p); + return DisSpecialAddr(b, rde, p, 3); // ds:bx } -static char *DisNq(struct DisBuilder b, char *p) { - return DisXmm(b, p, "mm", ModrmRm(b.xedd->op.rde)); +static char *DisNq(struct DisBuilder b, uint32_t rde, char *p) { + return DisXmm(b, rde, p, "mm", ModrmRm(rde)); } -static char *DisUq(struct DisBuilder b, char *p) { - return DisXmm(b, p, "mm", ModrmRm(b.xedd->op.rde)); +static char *DisUq(struct DisBuilder b, uint32_t rde, char *p) { + return DisXmm(b, rde, p, "mm", ModrmRm(rde)); } -static char *DisPq(struct DisBuilder b, char *p) { - return DisXmm(b, p, "mm", ModrmReg(b.xedd->op.rde)); +static char *DisPq(struct DisBuilder b, uint32_t rde, char *p) { + return DisXmm(b, rde, p, "mm", ModrmReg(rde)); } -static char *DisUdq(struct DisBuilder b, char *p) { - return DisXmm(b, p, "xmm", ModrmRm(b.xedd->op.rde)); +static char *DisUdq(struct DisBuilder b, uint32_t rde, char *p) { + return DisXmm(b, rde, p, "xmm", ModrmRm(rde)); } -static char *DisVdq(struct DisBuilder b, char *p) { - return DisXmm(b, p, "xmm", ModrmReg(b.xedd->op.rde)); +static char *DisVdq(struct DisBuilder b, uint32_t rde, char *p) { + return DisXmm(b, rde, p, "xmm", ModrmReg(rde)); } -static char *DisQq(struct DisBuilder b, char *p) { - if (IsModrmRegister(b.xedd->op.rde)) { - return DisNq(b, p); +static char *DisQq(struct DisBuilder b, uint32_t rde, char *p) { + if (IsModrmRegister(rde)) { + return DisNq(b, rde, p); } else { - return DisM(b, p); + return DisM(b, rde, p); } } -static char *DisEst(struct DisBuilder b, char *p) { +static char *DisEst(struct DisBuilder b, uint32_t rde, char *p) { p = DisRegister(p, "st"); - if (ModrmRm(b.xedd->op.rde) != 0) { + if (ModrmRm(rde) != 0) { *p++ = '('; - *p++ = '0' + ModrmRm(b.xedd->op.rde); + *p++ = '0' + ModrmRm(rde); *p++ = ')'; *p = '\0'; } return p; } -static char *DisEst1(struct DisBuilder b, char *p) { - if (ModrmRm(b.xedd->op.rde) != 1) { - p = DisEst(b, p); +static char *DisEst1(struct DisBuilder b, uint32_t rde, char *p) { + if (ModrmRm(rde) != 1) { + p = DisEst(b, rde, p); } else { *p = '\0'; } return p; } -static char *DisEssr(struct DisBuilder b, char *p) { - if (IsModrmRegister(b.xedd->op.rde)) { - return DisEst(b, p); +static char *DisEssr(struct DisBuilder b, uint32_t rde, char *p) { + if (IsModrmRegister(rde)) { + return DisEst(b, rde, p); } else { - return DisM(b, p); + return DisM(b, rde, p); } } -static char *DisWps(struct DisBuilder b, char *p) { - if (IsModrmRegister(b.xedd->op.rde)) { - return DisUdq(b, p); +static char *DisWps(struct DisBuilder b, uint32_t rde, char *p) { + if (IsModrmRegister(rde)) { + return DisUdq(b, rde, p); } else { - return DisM(b, p); + return DisM(b, rde, p); } } #define DisEdr DisM #define DisEqp DisEq #define DisEsr DisM +#define DisGv DisGvqp #define DisIb DisImm #define DisIbs DisImm #define DisIbss DisImm @@ -442,9 +502,11 @@ static char *DisWps(struct DisBuilder b, char *p) { #define DisMdr DisM #define DisMe DisM #define DisMer DisM +#define DisMp DisM #define DisMps DisM #define DisMq DisM #define DisMqi DisM +#define DisMs DisM #define DisMsr DisEssr #define DisMw DisM #define DisMwi DisM @@ -471,14 +533,19 @@ static char *DisWps(struct DisBuilder b, char *p) { #define DisYb DisY #define DisYv DisY #define DisYvqp DisY +#define DisZv DisZvqp static const struct DisArg { char s[8]; - char *(*f)(struct DisBuilder, char *); + char *(*f)(struct DisBuilder, uint32_t, char *); } kDisArgs[] = /* */ { + {"$1", DisOne}, // + {"%Cd", DisCd}, // {"%Gb", DisGb}, // {"%Gdqp", DisGdqp}, // + {"%Gv", DisGv}, // {"%Gvqp", DisGvqp}, // + {"%Hd", DisHd}, // {"%Nq", DisNq}, // {"%Ppi", DisPpi}, // {"%Pq", DisPq}, // @@ -494,6 +561,7 @@ static const struct DisArg { {"%Vsd", DisVsd}, // {"%Vss", DisVss}, // {"%Zb", DisZb}, // + {"%Zv", DisZv}, // {"%Zvq", DisZvq}, // {"%Zvqp", DisZvqp}, // {"%eAX", DisEax}, // @@ -510,7 +578,7 @@ static const struct DisArg { {"Eq", DisEq}, // {"Eqp", DisEqp}, // {"Esr", DisEsr}, // - {"Ev", DisEvqp}, // + {"Ev", DisEv}, // {"Evq", DisEvq}, // {"Evqp", DisEvqp}, // {"Ew", DisEvqp}, // @@ -524,6 +592,7 @@ static const struct DisArg { {"Jb", DisJb}, // {"Jbs", DisJbs}, // {"Jvds", DisJvds}, // + {"Kvds", DisKvds}, // {"M", DisM}, // {"Mdi", DisMdi}, // {"Mdq", DisMdq}, // @@ -531,9 +600,11 @@ static const struct DisArg { {"Mdr", DisMdr}, // {"Me", DisMe}, // {"Mer", DisMer}, // + {"Mp", DisMp}, // {"Mps", DisMps}, // {"Mq", DisMq}, // {"Mqi", DisMqi}, // + {"Ms", DisMs}, // {"Msr", DisMsr}, // {"Mw", DisMw}, // {"Mwi", DisMwi}, // @@ -541,6 +612,7 @@ static const struct DisArg { {"Ovqp", DisOvqp}, // {"Qpi", DisQpi}, // {"Qq", DisQq}, // + {"Rvds", DisRvds}, // {"Wdq", DisWdq}, // {"Wpd", DisWpd}, // {"Wps", DisWps}, // @@ -556,6 +628,13 @@ static const struct DisArg { {"Yvqp", DisYvqp}, // }; +static int CompareString8(const char a[8], const char b[8]) { + uint64_t x, y; + x = READ64BE(a); + y = READ64BE(b); + return x > y ? 1 : x < y ? -1 : 0; +} + char *DisArg(struct DisBuilder b, char *p, const char *s) { char key[8]; int c, m, l, r; @@ -564,13 +643,13 @@ char *DisArg(struct DisBuilder b, char *p, const char *s) { strncpy(key, s, 8); while (l <= r) { m = (l + r) >> 1; - c = SSTRCMP8(kDisArgs[m].s, key); + c = CompareString8(kDisArgs[m].s, key); if (c < 0) { l = m + 1; } else if (c > 0) { r = m - 1; } else { - return kDisArgs[m].f(b, p); + return kDisArgs[m].f(b, b.xedd->op.rde, p); } } if (*s == '%') { diff --git a/tool/build/lib/diself.c b/tool/build/lib/diself.c index 5e9bc0cc..c9ae55e9 100644 --- a/tool/build/lib/diself.c +++ b/tool/build/lib/diself.c @@ -22,6 +22,7 @@ #include "libc/elf/elf.h" #include "libc/elf/struct/sym.h" #include "libc/log/check.h" +#include "libc/macros.h" #include "tool/build/lib/dis.h" static int DisSymCompare(const struct DisSym *a, const struct DisSym *b) { @@ -113,18 +114,29 @@ bool DisIsText(struct Dis *d, int64_t addr) { } long DisFindSym(struct Dis *d, int64_t addr) { - size_t i; + size_t i, l, r, m, n; if (DisIsProg(d, addr)) { - for (i = 0; i < d->syms.i; ++i) { - if (addr == d->syms.p[i].addr) return i; + l = 0; + r = d->syms.i; + while (l < r) { + m = (l + r) >> 1; + if (d->syms.p[m].addr < addr) { + l = m + 1; + } else { + r = m; + } } - for (i = 0; i < d->syms.i; ++i) { + if (d->syms.p[l].addr == addr) { + return l; + } + l = MAX(0, (long)l - 10); + for (n = 0, i = l; i < d->syms.i && n < 20; ++i, ++n) { if (addr >= d->syms.p[i].addr && addr < d->syms.p[i].addr + d->syms.p[i].size) { return i; } } - for (i = 0; i < d->syms.i; ++i) { + for (n = 0, i = l; i < d->syms.i && n < 20; ++i, ++n) { if (addr >= d->syms.p[i].addr && (i + 1 == d->syms.i || addr < d->syms.p[i + 1].addr)) { return i; diff --git a/tool/build/lib/disinst.c b/tool/build/lib/disinst.c index 59f4d461..1e4d5825 100644 --- a/tool/build/lib/disinst.c +++ b/tool/build/lib/disinst.c @@ -23,6 +23,7 @@ #include "tool/build/lib/dis.h" #include "tool/build/lib/modrm.h" +static const char kJcxz[3][6] = {"jcxz", "jecxz", "jrcxz"}; static const char kAluOp[8][4] = {"add", "or", "adc", "sbb", "and", "sub", "xor", "cmp"}; static const char kBitOp[8][4] = {"rol", "ror", "rcl", "rcr", @@ -33,7 +34,7 @@ static bool IsProbablyByteOp(struct XedDecodedInst *x) { } static int IsRepOpcode(struct DisBuilder b) { - switch (b.xedd->op.opcode & ~1u) { + switch (b.xedd->op.opcode & ~1) { case 0x6C: /* INS */ return 1; case 0x6E: /* OUTS */ @@ -86,35 +87,36 @@ static char *DisBranchTaken(struct DisBuilder b, char *p) { static char *DisName(struct DisBuilder b, char *bp, const char *name, bool ambiguous) { char *p, *np; + uint32_t rde; bool notbyte, notlong, wantsuffix, wantsuffixsd; p = bp; + rde = b.xedd->op.rde; if (b.xedd->op.lock) p = stpcpy(p, "lock "); p = DisRepPrefix(b, p); if (tinystrcmp(name, "BIT") == 0) { - p = stpcpy(p, kBitOp[ModrmReg(b.xedd->op.rde)]); + p = stpcpy(p, kBitOp[ModrmReg(rde)]); } else if (tinystrcmp(name, "CALL") == 0) { p = stpcpy(p, "call"); } else if (tinystrcmp(name, "JMP") == 0) { p = stpcpy(p, "jmp"); } else if (tinystrcmp(name, "jcxz") == 0) { - p = stpcpy(p, Asz(b.xedd->op.rde) ? "jecxz" : "jrcxz"); + p = stpcpy(p, kJcxz[Eamode(rde)]); p = DisBranchTaken(b, p); - } else if (tinystrcmp(name, "loop") == 0) { - p = stpcpy(p, Asz(b.xedd->op.rde) ? "loopl" : "loop"); - p = DisBranchTaken(b, p); - } else if (tinystrcmp(name, "loope") == 0) { - p = stpcpy(p, Asz(b.xedd->op.rde) ? "loopel" : "loope"); - p = DisBranchTaken(b, p); - } else if (tinystrcmp(name, "loopne") == 0) { - p = stpcpy(p, Asz(b.xedd->op.rde) ? "loopnel" : "loopne"); + } else if (tinystrcmp(name, "loop") == 0 || tinystrcmp(name, "loope") == 0 || + tinystrcmp(name, "loopne") == 0) { + p = stpcpy(p, name); + if (Eamode(rde) != Mode(rde)) { + *p++ = "wl"[Eamode(rde)]; + *p = '\0'; + } p = DisBranchTaken(b, p); } else if (tinystrcmp(name, "cwtl") == 0) { - if (Osz(b.xedd->op.rde)) name = "cbtw"; - if (Rexw(b.xedd->op.rde)) name = "cltq"; + if (Osz(rde)) name = "cbtw"; + if (Rexw(rde)) name = "cltq"; p = stpcpy(p, name); } else if (tinystrcmp(name, "cltd") == 0) { - if (Osz(b.xedd->op.rde)) name = "cwtd"; - if (Rexw(b.xedd->op.rde)) name = "cqto"; + if (Osz(rde)) name = "cwtd"; + if (Rexw(rde)) name = "cqto"; p = stpcpy(p, name); } else { notbyte = false; @@ -125,13 +127,13 @@ static char *DisName(struct DisBuilder b, char *bp, const char *name, *p++ = *np; } if (tinystrcmp(name, "ALU") == 0) { - p = stpcpy(p, kAluOp[ModrmReg(b.xedd->op.rde)]); + p = stpcpy(p, kAluOp[ModrmReg(rde)]); } else if (tinystrcmp(np, "WLQ") == 0) { notbyte = true; wantsuffix = true; } else if (tinystrcmp(np, "WQ") == 0) { notbyte = true; - notlong = true; + notlong = Eamode(rde) != XED_MODE_REAL; wantsuffix = true; } else if (tinystrcmp(np, "LQ") == 0 || tinystrcmp(np, "WL") == 0) { notbyte = true; @@ -140,21 +142,23 @@ static char *DisName(struct DisBuilder b, char *bp, const char *name, notbyte = true; wantsuffixsd = true; } else if (tinystrcmp(np, "ABS") == 0) { - if (Rexw(b.xedd->op.rde)) p = stpcpy(p, "abs"); + if (Rexw(rde)) p = stpcpy(p, "abs"); } else if (tinystrcmp(np, "BT") == 0) { p = DisBranchTaken(b, p); } if (wantsuffixsd) { - if (Osz(b.xedd->op.rde)) { + if (Osz(rde)) { *p++ = 'd'; } else { *p++ = 's'; } } else if (wantsuffix || (ambiguous && !startswith(name, "f") && !startswith(name, "set"))) { - if (Osz(b.xedd->op.rde)) { - *p++ = 'w'; - } else if (Rexw(b.xedd->op.rde)) { + if (Osz(rde)) { + if (Eamode(rde) != XED_MODE_REAL) { + *p++ = 'w'; + } + } else if (Rexw(rde)) { *p++ = 'q'; } else if (ambiguous && !notbyte && IsProbablyByteOp(b.xedd)) { *p++ = 'b'; diff --git a/tool/build/lib/disspec.c b/tool/build/lib/disspec.c index 5c0684b0..9e363c75 100644 --- a/tool/build/lib/disspec.c +++ b/tool/build/lib/disspec.c @@ -27,7 +27,7 @@ static const char kFpuName[][8][8] = { {"fadd", "fmul", "fcom", "fcomp", "fsub", "fsubr", "fdiv", "fdivr"}, - {"fchs", "fabs", "ftst", "fxam"}, + {"fchs", "fabs", UNKNOWN, UNKNOWN, "ftst", "fxam", UNKNOWN, UNKNOWN}, {"fld1", "fldl2t", "fldl2e", "fldpi", "fldlg2", "fldln2", "fldz"}, {"f2xm1", "fyl2x", "fptan", "fpatan", "fxtract", "fprem1", "fdecstp", "fincstp"}, @@ -90,15 +90,6 @@ char *DisOpVpsWpsVssWssVpdWpdVsdWsd(struct XedDecodedInst *x, char *p, const char *DisSpecMap0(struct XedDecodedInst *x, char *p) { switch (x->op.opcode & 0xff) { - RCASE(0x2F, "das"); - RCASE(0x37, "aaa"); - RCASE(0x3F, "aas"); - RCASE(0xD6, "salc"); - RCASE(0x61, "popa"); - RCASE(0x60, "pusha"); - RCASE(0x62, "bound"); - RCASE(0xD4, "aam Ib"); - RCASE(0xD5, "aad Ib"); RCASE(0x00, "add Eb %Gb"); RCASE(0x01, "add Evqp %Gvqp"); RCASE(0x02, "add %Gb Eb"); @@ -141,6 +132,7 @@ const char *DisSpecMap0(struct XedDecodedInst *x, char *p) { RCASE(0x27, "pop %es"); RCASE(0x28, "sub Eb %Gb"); RCASE(0x29, "sub Evqp %Gvqp"); + RCASE(0x2F, "das"); RCASE(0x2a, "sub %Gb Eb"); RCASE(0x2b, "sub %Gvqp Evqp"); RCASE(0x2c, "sub %al Ib"); @@ -151,14 +143,21 @@ const char *DisSpecMap0(struct XedDecodedInst *x, char *p) { RCASE(0x33, "xor %Gvqp Evqp"); RCASE(0x34, "xor %al Ib"); RCASE(0x35, "xor %rAX Ivds"); + RCASE(0x37, "aaa"); RCASE(0x38, "cmp Eb %Gb"); RCASE(0x39, "cmp Evqp %Gvqp"); RCASE(0x3A, "cmp %Gb Eb"); RCASE(0x3B, "cmp %Gvqp Evqp"); RCASE(0x3C, "cmp %al Ib"); RCASE(0x3D, "cmp %rAX Ivds"); - RCASE(0x50 ... 0x57, "pushWQ %Zvq"); - RCASE(0x58 ... 0x5f, "popWQ %Zvq"); + RCASE(0x3F, "aas"); + RCASE(0x40 ... 0x47, "inc %Zv"); + RCASE(0x48 ... 0x4f, "dec %Zv"); + RCASE(0x50 ... 0x57, "push %Zvq"); + RCASE(0x58 ... 0x5f, "pop %Zvq"); + RCASE(0x60, "pusha"); + RCASE(0x61, "popa"); + RCASE(0x62, "bound"); RCASE(0x63, "movslLQ %Gdqp Ed"); RCASE(0x68, "pushWQ Ivs"); RCASE(0x69, "imul %Gvqp Evqp Ivds"); @@ -230,6 +229,8 @@ const char *DisSpecMap0(struct XedDecodedInst *x, char *p) { RCASE(0xC1, "BIT Evqp Ib"); RCASE(0xC2, "ret Iw"); RCASE(0xC3, "ret"); + RCASE(0xC4, "les %Gv Mp"); + RCASE(0xC5, "lds %Gv Mp"); RCASE(0xC6, "mov Eb Ib"); RCASE(0xC7, "mov Evqp Ivds"); RCASE(0xC9, "leave"); @@ -239,6 +240,9 @@ const char *DisSpecMap0(struct XedDecodedInst *x, char *p) { RCASE(0xD1, "BIT Evqp $1"); RCASE(0xD2, "BIT Evqp %cl"); RCASE(0xD3, "BIT Evqp %cl"); + RCASE(0xD4, x->op.uimm0 == 0x0a ? "aam" : "aam Ib"); + RCASE(0xD5, x->op.uimm0 == 0x0a ? "aad" : "aad Ib"); + RCASE(0xD6, "salc"); RCASE(0xD7, "xlat BBb"); RCASE(0xE0, "loopne Jbs"); RCASE(0xE1, "loope Jbs"); @@ -250,6 +254,7 @@ const char *DisSpecMap0(struct XedDecodedInst *x, char *p) { RCASE(0xE7, "out Ib %eAX"); RCASE(0xE8, "call Jvds"); RCASE(0xE9, "jmp Jvds"); + RCASE(0xEA, "ljmp Rvds Kvds"); RCASE(0xEB, "jmp Jbs"); RCASE(0xEC, "in %al %dx"); RCASE(0xED, "in %eAX %dx"); @@ -577,6 +582,8 @@ const char *DisSpecMap1(struct XedDecodedInst *x, char *p) { RCASE(0x1B, "nop Ev"); RCASE(0x1C, "nop Ev"); RCASE(0x1D, "nop Ev"); + RCASE(0x20, "mov %Hd %Cd"); + RCASE(0x22, "mov %Cd %Hd"); RCASE(0x28, "movapSD %Vps Wps"); RCASE(0x29, "movapSD Wps %Vps"); RCASE(0x2B, "movntpSD Mps %Vps"); @@ -732,8 +739,21 @@ 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 0x01: + if (ModrmMod(x->op.rde) == 0b11 && ModrmReg(x->op.rde) == 0b111 && + ModrmRm(x->op.rde) == 0b001) { + return "rdtscp"; + } else if (!IsModrmRegister(x->op.rde) && ModrmReg(x->op.rde) == 0) { + return "sgdt Ms"; + } else if (!IsModrmRegister(x->op.rde) && ModrmReg(x->op.rde) == 2) { + return "lgdt Ms"; + } else { + return UNKNOWN; + } + break; case 0x1F: - if (x->op.modrm == 0x45) { + if (ModrmMod(x->op.rde) == 1 && ModrmReg(x->op.rde) == 0 && + ModrmRm(x->op.rde) == 0b101) { return "bofram Jb"; } else { return "nop Ev"; @@ -779,7 +799,7 @@ const char *DisSpecMap1(struct XedDecodedInst *x, char *p) { RCASE(5, "lfence"); RCASE(6, "mfence"); case 7: - if (0xf8 <= x->op.modrm && x->op.modrm <= 0xff) { + if (ModrmMod(x->op.rde) == 0b11 && ModrmReg(x->op.rde) == 0b111) { return "sfence"; } else { return "clflush"; diff --git a/tool/build/lib/elfwriter.c b/tool/build/lib/elfwriter.c index 9afd3a0a..817e79e4 100644 --- a/tool/build/lib/elfwriter.c +++ b/tool/build/lib/elfwriter.c @@ -18,6 +18,7 @@ │ 02110-1301 USA │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/alg/arraylist.h" +#include "libc/alg/arraylist2.h" #include "libc/assert.h" #include "libc/bits/safemacros.h" #include "libc/calls/calls.h" @@ -48,7 +49,7 @@ static const Elf64_Ehdr kObjHeader = { static size_t AppendSection(struct ElfWriter *elf, const char *name, int sh_type, int sh_flags) { ssize_t section = - append(elf->shdrs, + APPEND(&elf->shdrs->p, &elf->shdrs->i, &elf->shdrs->n, (&(Elf64_Shdr){.sh_type = sh_type, .sh_flags = sh_flags, .sh_entsize = elf->entsize, @@ -72,12 +73,13 @@ static struct ElfWriterSymRef AppendSymbol(struct ElfWriter *elf, size_t st_size, size_t st_shndx, enum ElfWriterSymOrder slg) { ssize_t sym = - append(elf->syms[slg], (&(Elf64_Sym){.st_info = st_info, - .st_size = st_size, - .st_value = st_value, - .st_other = st_other, - .st_name = intern(elf->strtab, name), - .st_shndx = st_shndx})); + APPEND(&elf->syms[slg]->p, &elf->syms[slg]->i, &elf->syms[slg]->n, + (&(Elf64_Sym){.st_info = st_info, + .st_size = st_size, + .st_value = st_value, + .st_other = st_other, + .st_name = intern(elf->strtab, name), + .st_shndx = st_shndx})); CHECK_NE(-1, sym); return (struct ElfWriterSymRef){.slg = slg, .sym = sym}; } @@ -147,7 +149,7 @@ static void FlushTables(struct ElfWriter *elf) { elf->ehdr->e_shstrndx = FlushStrtab(elf, ".shstrtab", elf->shstrtab); WriteRelaSections(elf, symtab); size = elf->shdrs->i * sizeof(elf->shdrs->p[0]); - elfwriter_align(elf, alignof(elf->shdrs->p[0]), sizeof(elf->shdrs->p[0])); + elfwriter_align(elf, alignof(Elf64_Shdr), sizeof(elf->shdrs->p[0])); elf->ehdr->e_shoff = elf->wrote; elf->ehdr->e_shnum = elf->shdrs->i; elf->shdrs->p[symtab].sh_info = @@ -251,9 +253,9 @@ struct ElfWriterSymRef elfwriter_linksym(struct ElfWriter *elf, void elfwriter_appendrela(struct ElfWriter *elf, uint64_t r_offset, struct ElfWriterSymRef symkey, uint32_t type, int64_t r_addend) { - CHECK_NE(-1, - append(elf->relas, (&(struct ElfWriterRela){.type = type, - .symkey = symkey, - .offset = r_offset, - .addend = r_addend}))); + CHECK_NE(-1, APPEND(&elf->relas->p, &elf->relas->i, &elf->relas->n, + (&(struct ElfWriterRela){.type = type, + .symkey = symkey, + .offset = r_offset, + .addend = r_addend}))); } diff --git a/tool/build/lib/fds.h b/tool/build/lib/fds.h index f31cbbdf..860b3b8b 100644 --- a/tool/build/lib/fds.h +++ b/tool/build/lib/fds.h @@ -11,6 +11,7 @@ struct MachineFds { int (*close)(int); ssize_t (*read)(int, void *, size_t); ssize_t (*write)(int, const void *, size_t); + int (*ioctl)(int, uint64_t, void *); } * cb; } * p; struct MachineFdClosed { diff --git a/tool/build/lib/flags.h b/tool/build/lib/flags.h index 0f1dedca..9ebd47a0 100644 --- a/tool/build/lib/flags.h +++ b/tool/build/lib/flags.h @@ -24,7 +24,7 @@ #define FLAGS_ID 21 #define GetLazyParityBool(f) GetParity((f) >> 24) -#define SetLazyParityByte(f, x) (((f) & ~0xFF000000u) | ((x)&0xFF) << 24) +#define SetLazyParityByte(f, x) (((f) & ~0xFF000000u) | ((x)&0xFFu) << 24) #define GetParity(WORD) \ ({ \ diff --git a/tool/build/lib/fpu.c b/tool/build/lib/fpu.c index afaadfa8..9fd70ae0 100644 --- a/tool/build/lib/fpu.c +++ b/tool/build/lib/fpu.c @@ -31,7 +31,6 @@ #include "tool/build/lib/modrm.h" #include "tool/build/lib/throw.h" #include "tool/build/lib/word.h" -#include "tool/build/lib/x87.h" #define FPUREG 0 #define MEMORY 1 @@ -153,6 +152,57 @@ static void FpuSetMemoryLdbl(struct Machine *m, long double f) { SetMemoryLdbl(m, m->fpu.dp, f); } +static long ltruncl(long double x) { + return x; +} + +static int ClearC2(int sw) { + return sw & ~FPU_C2; +} + +static long double f2xm1(long double x) { + return exp2l(x) - 1; +} + +static long double fyl2x(long double x, long double y) { + return y * log2l(x); +} + +static long double fyl2xp1(long double x, long double y) { + return y * log2l(x + 1); +} + +static long double fscale(long double significand, long double exponent) { + return scalbl(significand, exponent); +} + +static long double x87remainder(long double x, long double y, uint32_t *sw, + long double rem(long double, long double), + long rnd(long double)) { + int s; + long q; + long double r; + s = 0; + r = rem(x, y); + q = rnd(x / y); + s &= ~FPU_C2; /* ty libm */ + if (q & 0b001) s |= FPU_C1; + if (q & 0b010) s |= FPU_C3; + if (q & 0b100) s |= FPU_C0; + if (sw) *sw = s | (*sw & ~(FPU_C0 | FPU_C1 | FPU_C2 | FPU_C3)); + return r; +} + +static long double fprem(long double dividend, long double modulus, + uint32_t *sw) { + return x87remainder(dividend, modulus, sw, fmodl, ltruncl); +} + +static long double fprem1(long double dividend, long double modulus, + uint32_t *sw) { + return x87remainder(dividend, modulus, sw, remainderl, lrintl); +} + static long double FpuAdd(struct Machine *m, long double x, long double y) { if (!isunordered(x, y)) { switch (isinf(y) << 1 | isinf(x)) { @@ -263,7 +313,7 @@ static void FpuCompare(struct Machine *m, long double y) { } } -void OpFxam(struct Machine *m) { +static void OpFxam(struct Machine *m) { long double x; x = *FpuSt(m, 0); m->fpu.c1 = !!signbit(x); @@ -741,7 +791,7 @@ static void OpFldConstant(struct Machine *m) { x = fldz(); break; default: - OpUd(m); + OpUd(m, m->xedd->op.rde); } FpuPush(m, x); } @@ -844,7 +894,7 @@ static void OpFfree(struct Machine *m) { } static void OpFfreep(struct Machine *m) { - OpFfree(m); + if (ModrmRm(m->xedd->op.rde)) OpFfree(m); FpuPop(m); } @@ -932,7 +982,7 @@ void OpFinit(struct Machine *m) { m->fpu.tw = -1; } -void OpFwait(struct Machine *m) { +void OpFwait(struct Machine *m, uint32_t rde) { if ((m->fpu.ie & !m->fpu.im) | (m->fpu.de & !m->fpu.dm) | (m->fpu.ze & !m->fpu.zm) | (m->fpu.oe & !m->fpu.om) | (m->fpu.ue & !m->fpu.um) | (m->fpu.pe & !m->fpu.pm) | @@ -986,15 +1036,15 @@ long double FpuPop(struct Machine *m) { return x; } -void OpFpu(struct Machine *m) { +void OpFpu(struct Machine *m, uint32_t rde) { unsigned op; bool ismemory; op = m->xedd->op.opcode & 0b111; - ismemory = ModrmMod(m->xedd->op.rde) != 0b11; + ismemory = ModrmMod(rde) != 0b11; m->fpu.ip = m->ip - m->xedd->length; - m->fpu.op = op << 8 | m->xedd->op.modrm; - m->fpu.dp = ismemory ? ComputeAddress(m, m->xedd->op.rde) : 0; - switch (DISP(op, ismemory, m->xedd->op.reg)) { + m->fpu.op = op << 8 | ModrmMod(rde) << 6 | ModrmReg(rde) << 3 | ModrmRm(rde); + m->fpu.dp = ismemory ? ComputeAddress(m, rde) : 0; + switch (DISP(op, ismemory, ModrmReg(rde))) { CASE(DISP(0xD8, FPUREG, 0), OpFaddStEst(m)); CASE(DISP(0xD8, FPUREG, 1), OpFmulStEst(m)); CASE(DISP(0xD8, FPUREG, 2), OpFcom(m)); @@ -1106,17 +1156,17 @@ void OpFpu(struct Machine *m) { CASE(DISP(0xDF, MEMORY, 5), OpFildll(m)); CASE(DISP(0xDF, MEMORY, 7), OpFistpll(m)); case DISP(0xD9, FPUREG, 4): - switch (ModrmRm(m->xedd->op.rde)) { + switch (ModrmRm(rde)) { CASE(0, OpFchs(m)); CASE(1, OpFabs(m)); CASE(4, OpFtst(m)); CASE(5, OpFxam(m)); default: - OpUd(m); + OpUd(m, rde); } break; case DISP(0xD9, FPUREG, 6): - switch (ModrmRm(m->xedd->op.rde)) { + switch (ModrmRm(rde)) { CASE(0, OpF2xm1(m)); CASE(1, OpFyl2x(m)); CASE(2, OpFptan(m)); @@ -1130,7 +1180,7 @@ void OpFpu(struct Machine *m) { } break; case DISP(0xD9, FPUREG, 7): - switch (ModrmRm(m->xedd->op.rde)) { + switch (ModrmRm(rde)) { CASE(0, OpFprem(m)); CASE(1, OpFyl2xp1(m)); CASE(2, OpFsqrt(m)); @@ -1144,14 +1194,14 @@ void OpFpu(struct Machine *m) { } break; case DISP(0xDb, FPUREG, 4): - switch (ModrmRm(m->xedd->op.rde)) { + switch (ModrmRm(rde)) { CASE(2, OpFnclex(m)); CASE(3, OpFinit(m)); default: - OpUd(m); + OpUd(m, rde); } break; default: - OpUd(m); + OpUd(m, rde); } } diff --git a/tool/build/lib/fpu.h b/tool/build/lib/fpu.h index 346db037..acfdd924 100644 --- a/tool/build/lib/fpu.h +++ b/tool/build/lib/fpu.h @@ -10,9 +10,9 @@ #if !(__ASSEMBLER__ + __LINKER__ + 0) COSMOPOLITAN_C_START_ -void OpFpu(struct Machine *); +void OpFpu(struct Machine *, uint32_t); void OpFinit(struct Machine *); -void OpFwait(struct Machine *); +void OpFwait(struct Machine *, uint32_t); void FpuPush(struct Machine *, long double); long double FpuPop(struct Machine *); long double *FpuSt(struct Machine *, unsigned); diff --git a/tool/build/lib/init.c b/tool/build/lib/init.c index cb70e471..3170e726 100644 --- a/tool/build/lib/init.c +++ b/tool/build/lib/init.c @@ -19,31 +19,5 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "tool/build/lib/machine.h" -static void InitRegisterBytePointers(struct Machine *m) { - unsigned i, j, k; - for (i = 0; i < 2; ++i) { - for (j = 0; j < 2; ++j) { - for (k = 0; k < 8; ++k) { - if (i) { - m->beg[i << 4 | j << 3 | k] = m->reg[j << 3 | k]; - } else { - m->beg[i << 4 | j << 3 | k] = &m->reg[k & 0b11][(k & 0b100) >> 2]; - } - } - } - } -} - -static void InitRegisterXmmPointers(struct Machine *m) { - unsigned i, j; - for (i = 0; i < 2; ++i) { - for (j = 0; j < 8; ++j) { - m->veg[i << 3 | j] = m->xmm[i][j]; - } - } -} - void InitMachine(struct Machine *m) { - InitRegisterBytePointers(m); - InitRegisterXmmPointers(m); } diff --git a/tool/build/lib/instruction.c b/tool/build/lib/instruction.c index 437a33d1..688895c0 100644 --- a/tool/build/lib/instruction.c +++ b/tool/build/lib/instruction.c @@ -18,64 +18,66 @@ │ 02110-1301 USA │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/macros.h" +#include "libc/nexgen32e/bsf.h" #include "libc/str/str.h" #include "third_party/xed/x86.h" +#include "tool/build/lib/address.h" +#include "tool/build/lib/endian.h" #include "tool/build/lib/machine.h" #include "tool/build/lib/memory.h" #include "tool/build/lib/stats.h" #include "tool/build/lib/throw.h" -static bool IsOpcodeEqual(uint8_t *a, uint8_t b[16], size_t size) { - unsigned i; - if (size) { - i = 0; - do { - if (a[i] != b[i]) { - return false; - } - } while (++i < size); - return true; +static bool IsOpcodeEqual(struct XedDecodedInst *xedd, uint8_t *a) { + uint64_t w; + if (xedd->length) { + if (xedd->length <= 7) { + w = Read64(a) ^ Read64(xedd->bytes); + return !w || bsfl(w) >= (xedd->length << 3); + } else { + return memcmp(a, xedd->bytes, xedd->length) == 0; + } } else { return false; } } +static void DecodeInstruction(struct Machine *m, uint8_t *p, unsigned n) { + struct XedDecodedInst xedd[1]; + xed_decoded_inst_zero_set_mode(xedd, m->mode); + if (!xed_instruction_length_decode(xedd, p, n)) { + memcpy(m->xedd, xedd, sizeof(m->icache[0])); + } else { + HaltMachine(m, kMachineDecodeError); + } +} + void LoadInstruction(struct Machine *m) { - unsigned i; - enum XedError err; + uint64_t ip; + unsigned i, key; uint8_t *addr, *toil, copy[15]; - if ((i = 0x1000 - (m->ip & 0xfff)) >= 15) { - if (ROUNDDOWN(m->ip, 0x1000) == m->codevirt && m->ip) { - addr = m->codereal + (m->ip & 0xfff); + ip = Read64(m->cs) + MaskAddress(m->mode & 3, m->ip); + key = ip & (ARRAYLEN(m->icache) - 1); + m->xedd = (struct XedDecodedInst *)m->icache[key]; + if ((i = 0x1000 - (ip & 0xfff)) >= 15) { + if (ROUNDDOWN(ip, 0x1000) == m->codevirt && ip) { + addr = m->codereal + (ip & 0xfff); } else { - m->codevirt = ROUNDDOWN(m->ip, 0x1000); + m->codevirt = ROUNDDOWN(ip, 0x1000); m->codereal = ResolveAddress(m, m->codevirt); - addr = m->codereal + (m->ip & 0xfff); + addr = m->codereal + (ip & 0xfff); } - m->xedd = m->icache + (m->ip & (ARRAYLEN(m->icache) - 1)); - if (IsOpcodeEqual(addr, m->xedd->bytes, m->xedd->length)) { - taken++; - } else { - ntaken++; - xed_decoded_inst_zero_set_mode(m->xedd, XED_MACHINE_MODE_LONG_64); - if (xed_instruction_length_decode(m->xedd, addr, 15)) { - HaltMachine(m, kMachineDecodeError); - } + if (!IsOpcodeEqual(m->xedd, addr)) { + DecodeInstruction(m, addr, 15); } } else { - m->xedd = m->icache; - xed_decoded_inst_zero_set_mode(m->xedd, XED_MACHINE_MODE_LONG_64); - addr = ResolveAddress(m, m->ip); - if ((toil = FindReal(m, m->ip + i))) { + addr = ResolveAddress(m, ip); + if ((toil = FindReal(m, ip + i))) { memcpy(copy, addr, i); memcpy(copy + i, toil, 15 - i); - if ((err = xed_instruction_length_decode(m->xedd, copy, 15))) { - HaltMachine(m, kMachineDecodeError); - } + DecodeInstruction(m, copy, 15); } else { - if ((err = xed_instruction_length_decode(m->xedd, addr, i))) { - HaltMachine(m, kMachineDecodeError); - } + DecodeInstruction(m, addr, i); } } } diff --git a/tool/build/lib/interner.c b/tool/build/lib/interner.c index e886801b..cd852228 100644 --- a/tool/build/lib/interner.c +++ b/tool/build/lib/interner.c @@ -18,6 +18,7 @@ │ 02110-1301 USA │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/alg/arraylist.h" +#include "libc/alg/arraylist2.h" #include "libc/bits/safemacros.h" #include "libc/mem/mem.h" #include "libc/str/knuthmultiplicativehash.h" @@ -92,12 +93,13 @@ size_t interncount(const struct Interner *t) { * @note use consistent size w/ non-string items */ size_t internobj(struct Interner *t, const void *data, size_t size) { - struct InternerObject *it = (struct InternerObject *)t; + char *item; unsigned hash; size_t i, step; - unsigned char *item; + struct InternerObject *it; step = 0; item = data; + it = (struct InternerObject *)t; hash = max(1, KnuthMultiplicativeHash32(data, size)); do { /* it is written that triangle probe halts iff ip[i].hash); } it->p[i].hash = hash; - return (it->p[i].index = concat(&it->pool, item, size)); + return (it->p[i].index = + CONCAT(&it->pool.p, &it->pool.i, &it->pool.n, item, size)); } /** diff --git a/tool/build/lib/loader.c b/tool/build/lib/loader.c index b3fb8cf8..a39e132b 100644 --- a/tool/build/lib/loader.c +++ b/tool/build/lib/loader.c @@ -112,10 +112,10 @@ static void LoadBin(struct Machine *m, intptr_t base, const char *prog, void LoadProgram(struct Machine *m, const char *prog, char **args, char **vars, struct Elf *elf) { int fd; - char *real; ssize_t rc; + void *stack; struct stat st; - void *code, *stack; + char *real, *memory; size_t i, codesize, mappedsize, extrasize, stacksize; DCHECK_NOTNULL(prog); elf->prog = prog; @@ -125,39 +125,61 @@ void LoadProgram(struct Machine *m, const char *prog, char **args, char **vars, fputs(": not found\n", stderr); exit(1); } - stacksize = STACKSIZE; codesize = st.st_size; - mappedsize = ROUNDDOWN(codesize, FRAMESIZE); - extrasize = codesize - mappedsize; - CHECK_NE(MAP_FAILED, (stack = mmap(NULL, stacksize, PROT_READ | PROT_WRITE, - MAP_ANONYMOUS | MAP_PRIVATE, -1, 0))); - code = real = (char *)0x0000400000000000; - if (mappedsize) { - CHECK_NE(MAP_FAILED, mmap(real, mappedsize, PROT_READ | PROT_WRITE, + elf->mapsize = ROUNDDOWN(codesize, FRAMESIZE); + extrasize = codesize - elf->mapsize; + elf->map = real = (char *)0x0000400000000000; + if (elf->mapsize) { + CHECK_NE(MAP_FAILED, mmap(real, elf->mapsize, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_FIXED, fd, 0)); - real += mappedsize; + real += elf->mapsize; } if (extrasize) { CHECK_NE(MAP_FAILED, mmap(real, ROUNDUP(extrasize, FRAMESIZE), PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED, -1, 0)); for (i = 0; i < extrasize; i += (size_t)rc) { - CHECK_NE(-1, (rc = pread(fd, real + i, extrasize - i, mappedsize + i))); + CHECK_NE(-1, (rc = pread(fd, real + i, extrasize - i, elf->mapsize + i))); } + elf->mapsize += ROUNDUP(extrasize, FRAMESIZE); } CHECK_NE(-1, close(fd)); ResetCpu(m); - Write64(m->sp, 0x0000800000000000); - RegisterMemory(m, 0x0000800000000000 - stacksize, stack, stacksize); - LoadArgv(m, prog, args, vars); - if (memcmp(code, "\177ELF", 4) == 0) { - elf->ehdr = code; - elf->size = codesize; - LoadElf(m, elf); + if (m->mode == XED_MACHINE_MODE_REAL) { + elf->base = 0x7c00; + CHECK_NE(MAP_FAILED, + (memory = mmap(NULL, BIGPAGESIZE, PROT_READ | PROT_WRITE, + MAP_ANONYMOUS | MAP_PRIVATE, -1, 0))); + RegisterMemory(m, 0, memory, BIGPAGESIZE); + m->ip = 0x7c00; + Write64(m->cs, 0); + Write64(m->dx, 0); + memcpy(memory + 0x7c00, elf->map, 512); + if (memcmp(elf->map, "\177ELF", 4) == 0) { + elf->ehdr = (void *)elf->map; + elf->size = codesize; + elf->base = elf->ehdr->e_entry; + } else { + elf->base = 0x7c00; + elf->ehdr = NULL; + elf->size = 0; + } } else { - elf->base = IMAGE_BASE_VIRTUAL; - elf->ehdr = NULL; - elf->size = 0; - LoadBin(m, elf->base, prog, code, codesize); + stacksize = STACKSIZE; + CHECK_NE(MAP_FAILED, (stack = mmap(NULL, stacksize, PROT_READ | PROT_WRITE, + MAP_ANONYMOUS | MAP_PRIVATE, -1, 0))); + Write64(m->sp, 0x0000800000000000); + RegisterMemory(m, 0x0000800000000000 - stacksize, stack, stacksize); + LoadArgv(m, prog, args, vars); + if (memcmp(elf->map, "\177ELF", 4) == 0) { + elf->ehdr = (void *)elf->map; + elf->size = codesize; + LoadElf(m, elf); + } else { + elf->base = IMAGE_BASE_VIRTUAL; + elf->ehdr = NULL; + elf->size = 0; + LoadBin(m, elf->base, prog, elf->map, codesize); + } } } diff --git a/tool/build/lib/loader.h b/tool/build/lib/loader.h index c46bc9b0..80b19026 100644 --- a/tool/build/lib/loader.h +++ b/tool/build/lib/loader.h @@ -10,6 +10,8 @@ struct Elf { Elf64_Ehdr *ehdr; size_t size; int64_t base; + char *map; + size_t mapsize; }; void LoadProgram(struct Machine *, const char *, char **, char **, diff --git a/tool/build/lib/machine.c b/tool/build/lib/machine.c index c0de68e2..a4fe0ffe 100644 --- a/tool/build/lib/machine.c +++ b/tool/build/lib/machine.c @@ -18,26 +18,18 @@ │ 02110-1301 USA │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/assert.h" -#include "libc/bits/popcnt.h" -#include "libc/calls/calls.h" #include "libc/conv/conv.h" #include "libc/dce.h" -#include "libc/intrin/pshufd.h" -#include "libc/intrin/pshufhw.h" -#include "libc/intrin/pshuflw.h" -#include "libc/intrin/pshufw.h" -#include "libc/intrin/shufpd.h" -#include "libc/intrin/shufps.h" #include "libc/log/check.h" #include "libc/log/log.h" #include "libc/macros.h" -#include "libc/math.h" #include "libc/runtime/runtime.h" #include "tool/build/lib/abp.h" +#include "tool/build/lib/address.h" #include "tool/build/lib/alu.h" +#include "tool/build/lib/bcd.h" #include "tool/build/lib/bitscan.h" #include "tool/build/lib/case.h" -#include "tool/build/lib/cond.h" #include "tool/build/lib/cpuid.h" #include "tool/build/lib/cvt.h" #include "tool/build/lib/divmul.h" @@ -49,6 +41,8 @@ #include "tool/build/lib/memory.h" #include "tool/build/lib/modrm.h" #include "tool/build/lib/sse.h" +#include "tool/build/lib/ssefloat.h" +#include "tool/build/lib/ssemov.h" #include "tool/build/lib/stack.h" #include "tool/build/lib/stats.h" #include "tool/build/lib/string.h" @@ -56,65 +50,84 @@ #include "tool/build/lib/throw.h" #include "tool/build/lib/time.h" -#define MUTATING true -#define READONLY false -#define UNCONDITIONAL true -#define BITS (8u << RegLog2(rde)) -#define SIGN (1ull << (BITS - 1)) -#define MASK (SIGN | (SIGN - 1)) -#define SHIFTMASK (BITS - 1) -#define TEST ALU_TEST | ALU_AND +typedef void (*nexgen32e_f)(struct Machine *, uint32_t); -typedef int int_v _Vector_size(16) aligned(16); -typedef long long_v _Vector_size(16) aligned(16); -typedef float float_v _Vector_size(16) aligned(16); -typedef double double_v _Vector_size(16) aligned(16); - -typedef void (*machine_f)(struct Machine *); -typedef void (*map_f)(struct Machine *, uint32_t); -typedef void (*alu_f)(struct Machine *, aluop2_f, bool); -typedef void (*machine_u8p_u8p_f)(struct Machine *, uint8_t *, uint8_t *); - -static uint64_t AluNot(struct Machine *m, uint32_t rde, uint64_t x) { - return ~x & MASK; +static uint64_t ReadMemory(uint32_t rde, uint8_t p[8]) { + if (Rexw(rde)) { + return Read64(p); + } else if (!Osz(rde)) { + return Read32(p); + } else { + return Read16(p); + } } -static uint64_t AluNeg(struct Machine *m, uint32_t rde, uint64_t x) { - m->flags = SetFlag(m->flags, FLAGS_CF, !!(x & MASK)); - m->flags = SetFlag(m->flags, FLAGS_OF, (x & MASK) == SIGN); - x = ~x + 1; - m->flags = SetFlag(m->flags, FLAGS_ZF, !(x & MASK)); - m->flags = SetFlag(m->flags, FLAGS_SF, !!(x & SIGN)); - m->flags = SetLazyParityByte(m->flags, x); - return x & MASK; +static int64_t ReadMemorySigned(uint32_t rde, uint8_t p[8]) { + if (Rexw(rde)) { + return (int64_t)Read64(p); + } else if (!Osz(rde)) { + return (int32_t)Read32(p); + } else { + return (int16_t)Read16(p); + } } -static uint64_t AluInc(struct Machine *m, uint32_t rde, uint64_t a) { - uint64_t c; - uint128_t x, z; - a &= MASK; - x = a; - z = x + 1; - c = z; - m->flags = SetFlag(m->flags, FLAGS_ZF, !(c & MASK)); - m->flags = SetFlag(m->flags, FLAGS_SF, !!(c & SIGN)); - m->flags = SetFlag(m->flags, FLAGS_OF, !!((c ^ a) & (c ^ 1) & SIGN)); - m->flags = SetLazyParityByte(m->flags, x); - return c & MASK; +static void WriteRegister(uint32_t rde, uint8_t p[8], uint64_t x) { + if (Rexw(rde)) { + Write64(p, x); + } else if (!Osz(rde)) { + Write64(p, x & 0xffffffff); + } else { + Write16(p, x); + } } -static uint64_t AluDec(struct Machine *m, uint32_t rde, uint64_t a) { - uint64_t c; - uint128_t x, z; - a &= MASK; - x = a; - z = x - 1; - c = z; - m->flags = SetFlag(m->flags, FLAGS_ZF, !(c & MASK)); - m->flags = SetFlag(m->flags, FLAGS_SF, !!(c & SIGN)); - m->flags = SetFlag(m->flags, FLAGS_OF, !!((c ^ a) & (a ^ 1) & SIGN)); - m->flags = SetLazyParityByte(m->flags, x); - return c & MASK; +static void WriteMemory(uint32_t rde, uint8_t p[8], uint64_t x) { + if (Rexw(rde)) { + Write64(p, x); + } else if (!Osz(rde)) { + Write32(p, x); + } else { + Write16(p, x); + } +} + +static void WriteRegisterOrMemory(uint32_t rde, uint8_t p[8], uint64_t x) { + if (IsModrmRegister(rde)) { + WriteRegister(rde, p, x); + } else { + WriteMemory(rde, p, x); + } +} + +static bool IsParity(struct Machine *m) { + return GetFlag(m->flags, FLAGS_PF); +} + +static bool IsBelowOrEqual(struct Machine *m) { + return GetFlag(m->flags, FLAGS_CF) | GetFlag(m->flags, FLAGS_ZF); +} + +static bool IsAbove(struct Machine *m) { + return !GetFlag(m->flags, FLAGS_CF) && !GetFlag(m->flags, FLAGS_ZF); +} + +static bool IsLess(struct Machine *m) { + return GetFlag(m->flags, FLAGS_SF) != GetFlag(m->flags, FLAGS_OF); +} + +static bool IsGreaterOrEqual(struct Machine *m) { + return GetFlag(m->flags, FLAGS_SF) == GetFlag(m->flags, FLAGS_OF); +} + +static bool IsLessOrEqual(struct Machine *m) { + return GetFlag(m->flags, FLAGS_ZF) | + (GetFlag(m->flags, FLAGS_SF) != GetFlag(m->flags, FLAGS_OF)); +} + +static bool IsGreater(struct Machine *m) { + return !GetFlag(m->flags, FLAGS_ZF) & + (GetFlag(m->flags, FLAGS_SF) == GetFlag(m->flags, FLAGS_OF)); } static void ImportFlags(struct Machine *m, uint64_t flags) { @@ -136,232 +149,165 @@ static void ImportFlags(struct Machine *m, uint64_t flags) { m->flags = SetLazyParityByte(m->flags, !((m->flags >> FLAGS_PF) & 1)); } -forceinline uint64_t ReadMemory(uint32_t rde, uint8_t p[8]) { - if (Rexw(rde)) { - return Read64(p); - } else if (!Osz(rde)) { - return Read32(p); - } else { - return Read16(p); - } +static void OpLfence(struct Machine *m, uint32_t rde) { } -forceinline int64_t ReadMemorySigned(uint32_t rde, uint8_t p[8]) { - if (Rexw(rde)) { - return (int64_t)Read64(p); - } else if (!Osz(rde)) { - return (int32_t)Read32(p); - } else { - return (int16_t)Read16(p); - } +static void OpMfence(struct Machine *m, uint32_t rde) { } -forceinline void WriteRegister(uint32_t rde, uint8_t p[8], uint64_t x) { - if (Rexw(rde)) { - Write64(p, x); - } else if (!Osz(rde)) { - Write64(p, x & 0xffffffff); - } else { - Write16(p, x); - } +static void OpSfence(struct Machine *m, uint32_t rde) { } -forceinline void WriteMemory(uint32_t rde, uint8_t p[8], uint64_t x) { - if (Rexw(rde)) { - Write64(p, x); - } else if (!Osz(rde)) { - Write32(p, x); - } else { - Write16(p, x); - } +static void OpClflush(struct Machine *m, uint32_t rde) { } -forceinline void WriteRegisterOrMemory(uint32_t rde, uint8_t p[8], uint64_t x) { - if (IsModrmRegister(rde)) { - WriteRegister(rde, p, x); - } else { - WriteMemory(rde, p, x); - } +static void OpWutNopEv(struct Machine *m, uint32_t rde) { } -static void OpLfence(struct Machine *m) { -} - -static void OpMfence(struct Machine *m) { -} - -static void OpSfence(struct Machine *m) { -} - -static void OpClflush(struct Machine *m) { -} - -static void OpWutNopEv(struct Machine *m) { -} - -static void OpCmc(struct Machine *m) { +static void OpCmc(struct Machine *m, uint32_t rde) { m->flags = SetFlag(m->flags, FLAGS_CF, !GetFlag(m->flags, FLAGS_CF)); } -static void OpClc(struct Machine *m) { +static void OpClc(struct Machine *m, uint32_t rde) { m->flags = SetFlag(m->flags, FLAGS_CF, false); } -static void OpStc(struct Machine *m) { +static void OpStc(struct Machine *m, uint32_t rde) { m->flags = SetFlag(m->flags, FLAGS_CF, true); } -static void OpCli(struct Machine *m) { +static void OpCli(struct Machine *m, uint32_t rde) { m->flags = SetFlag(m->flags, FLAGS_IF, false); } -static void OpSti(struct Machine *m) { +static void OpSti(struct Machine *m, uint32_t rde) { m->flags = SetFlag(m->flags, FLAGS_IF, true); } -static void OpCld(struct Machine *m) { +static void OpCld(struct Machine *m, uint32_t rde) { m->flags = SetFlag(m->flags, FLAGS_DF, false); } -static void OpStd(struct Machine *m) { +static void OpStd(struct Machine *m, uint32_t rde) { m->flags = SetFlag(m->flags, FLAGS_DF, true); } static void OpPushf(struct Machine *m, uint32_t rde) { - PushOsz(m, rde, ExportFlags(m->flags) & 0xFCFFFF); + Push(m, rde, ExportFlags(m->flags) & 0xFCFFFF); } static void OpPopf(struct Machine *m, uint32_t rde) { if (!Osz(rde)) { - ImportFlags(m, Pop64(m, 0)); + ImportFlags(m, Pop(m, rde, 0)); } else { - ImportFlags(m, (m->flags & ~0xffff) | Pop16(m, 0)); + ImportFlags(m, (m->flags & ~0xffff) | Pop(m, rde, 0)); } } -static void OpLahf(struct Machine *m) { +static void OpLahf(struct Machine *m, uint32_t rde) { Write8(m->ax + 1, ExportFlags(m->flags)); } -static void OpPushFs(struct Machine *m) { - ThrowSegmentationFault(m, m->ip); -} - -static void OpPopFs(struct Machine *m) { - ThrowSegmentationFault(m, m->ip); -} - -static void OpPushGs(struct Machine *m) { - ThrowSegmentationFault(m, m->ip); -} - -static void OpPopGs(struct Machine *m) { - ThrowSegmentationFault(m, m->ip); -} - -static void OpSahf(struct Machine *m) { +static void OpSahf(struct Machine *m, uint32_t rde) { ImportFlags(m, (m->flags & ~0xff) | m->ax[1]); } -static void OpEbSetCc(struct Machine *m, uint32_t rde, bool x) { - Write8(GetModrmRegisterBytePointerWrite(m, rde), x); -} - static void OpLeaGvqpM(struct Machine *m, uint32_t rde) { - Write64(RegRexrReg(m, rde), ComputeAddress(m, rde)); + WriteRegister(rde, RegRexrReg(m, rde), ComputeAddress(m, rde)); } -static void PushVq(struct Machine *m, uint32_t rde, uint8_t *p) { +static void OpPushSeg(struct Machine *m, uint32_t rde) { + uint8_t seg = (m->xedd->op.opcode & 070) >> 3; + Push(m, rde, Read64(GetSegment(m, rde, seg)) >> 4); +} + +static void OpPopSeg(struct Machine *m, uint32_t rde) { + uint8_t seg = (m->xedd->op.opcode & 070) >> 3; + Write64(GetSegment(m, rde, seg), Pop(m, rde, 0) << 4); +} + +static void OpMovEvqpSw(struct Machine *m, uint32_t rde) { + WriteRegisterOrMemory(rde, GetModrmRegisterWordPointerWriteOszRexw(m, rde), + Read64(GetSegment(m, rde, ModrmReg(rde))) >> 4); +} + +static void OpMovSwEvqp(struct Machine *m, uint32_t rde) { + Write64(GetSegment(m, rde, ModrmReg(rde)), + ReadMemory(rde, GetModrmRegisterWordPointerReadOszRexw(m, rde)) << 4); +} + +static void OpJmpf(struct Machine *m, uint32_t rde) { + Write64(m->cs, m->xedd->op.uimm0 << 4); + m->ip = m->xedd->op.disp; +} + +static void WriteEaxAx(struct Machine *m, uint32_t rde, uint32_t x) { if (!Osz(rde)) { - Push64(m, Read64(p)); + Write64(m->ax, x); } else { - Push16(m, Read16(p)); + Write16(m->ax, x); } } -static void PopVq(struct Machine *m, uint32_t rde, uint8_t *p) { +static uint32_t ReadEaxAx(struct Machine *m, uint32_t rde) { if (!Osz(rde)) { - Write64(p, Pop64(m, 0)); + return Read32(m->ax); } else { - Write16(p, Pop16(m, 0)); + return Read16(m->ax); } } -static void OpPushEvq(struct Machine *m, uint32_t rde) { - PushVq(m, rde, GetModrmRegisterWordPointerReadOsz(m, rde)); +static void OpInAlImm(struct Machine *m, uint32_t rde) { + Write8(m->ax, OpIn(m, m->xedd->op.uimm0)); } -static void OpPushZvq(struct Machine *m, uint32_t rde) { - PushVq(m, rde, RegRexbSrm(m, rde)); +static void OpInAxImm(struct Machine *m, uint32_t rde) { + WriteEaxAx(m, rde, OpIn(m, m->xedd->op.uimm0)); } -static void OpPopZvq(struct Machine *m, uint32_t rde) { - PopVq(m, rde, RegRexbSrm(m, rde)); +static void OpInAlDx(struct Machine *m, uint32_t rde) { + Write8(m->ax, OpIn(m, Read16(m->dx))); } -static void OpPopEvq(struct Machine *m, uint32_t rde) { - PopVq(m, rde, GetModrmRegisterWordPointerWriteOsz(m, rde)); +static void OpInAxDx(struct Machine *m, uint32_t rde) { + WriteEaxAx(m, rde, OpIn(m, Read16(m->dx))); } -static void OpJmp(struct Machine *m) { - m->ip += m->xedd->op.disp; +static void OpOutImmAl(struct Machine *m, uint32_t rde) { + OpOut(m, m->xedd->op.uimm0, Read8(m->ax)); } -static void OpJmpEq(struct Machine *m, uint32_t rde) { - m->ip = Read64(GetModrmRegisterWordPointerRead8(m, rde)); +static void OpOutImmAx(struct Machine *m, uint32_t rde) { + OpOut(m, m->xedd->op.uimm0, ReadEaxAx(m, rde)); } -static void OpJcxz(struct Machine *m, uint32_t rde) { - uint64_t count; - count = Read64(m->cx); - if (Asz(rde)) count &= 0xffffffff; - if (!count) OpJmp(m); +static void OpOutDxAl(struct Machine *m, uint32_t rde) { + OpOut(m, Read16(m->dx), Read8(m->ax)); } -static void OpLoop(struct Machine *m, uint32_t rde, bool cond) { - uint64_t count; - count = Read64(m->cx) - 1; - if (Asz(rde)) count &= 0xffffffff; - Write64(m->cx, count); - if (count && cond) m->ip += m->xedd->op.disp; +static void OpOutDxAx(struct Machine *m, uint32_t rde) { + OpOut(m, Read16(m->dx), ReadEaxAx(m, rde)); } -static void OpXlat(struct Machine *m, uint32_t rde) { - int64_t v; - uint8_t al; - v = Read64(m->bx) + Read8(m->ax); - if (Asz(rde)) v &= 0xffffffff; +static void OpXlatAlBbb(struct Machine *m, uint32_t rde) { + uint64_t v; + v = MaskAddress(Eamode(rde), Read64(m->bx) + Read8(m->ax)); + v = DataSegment(m, rde, v); SetReadAddr(m, v, 1); Write8(m->ax, Read8(ResolveAddress(m, v))); } -static void OpEb(struct Machine *m, uint32_t rde, aluop1_f op) { +static void AluEb(struct Machine *m, uint32_t rde, aluop_f op) { uint8_t *p; p = GetModrmRegisterBytePointerWrite(m, rde); - Write8(p, op(m, rde, Read8(p))); + Write8(p, op(Read8(p), 0, &m->flags)); } -static void OpEvqp(struct Machine *m, uint32_t rde, aluop1_f op) { +static void AluEvqp(struct Machine *m, uint32_t rde, aluop_f ops[4]) { uint8_t *p; p = GetModrmRegisterWordPointerWriteOszRexw(m, rde); - WriteRegisterOrMemory(rde, p, op(m, rde, ReadMemory(rde, p))); -} - -static void OpGvqpEvqp(struct Machine *m, uint32_t rde, aluop2_f op, - bool write) { - uint64_t x; - x = op(m, rde, ReadMemory(rde, RegRexrReg(m, rde)), - ReadMemory(rde, GetModrmRegisterWordPointerReadOszRexw(m, rde))); - if (write) WriteRegister(rde, RegRexrReg(m, rde), x); -} - -static void OpEvqpGvqp(struct Machine *m, uint32_t rde, aluop2_f op, - bool write) { - uint8_t *p; - uint64_t x; - p = GetModrmRegisterWordPointerWriteOszRexw(m, rde); - x = op(m, rde, ReadMemory(rde, p), ReadMemory(rde, RegRexrReg(m, rde))); - if (write) WriteRegisterOrMemory(rde, p, x); + WriteRegisterOrMemory(rde, p, + ops[RegLog2(rde)](ReadMemory(rde, p), 0, &m->flags)); } static void OpXchgZvqp(struct Machine *m, uint32_t rde) { @@ -372,24 +318,6 @@ static void OpXchgZvqp(struct Machine *m, uint32_t rde) { WriteRegister(rde, RegRexbSrm(m, rde), x); } -static void OpNopEv(struct Machine *m) { - if (m->xedd->op.modrm == 0x45) { - OpBofram(m); - } -} - -static void OpPause(struct Machine *m) { - sched_yield(); -} - -static void OpNop(struct Machine *m, uint32_t rde) { - if (m->xedd->op.rexb) { - OpXchgZvqp(m, rde); - } else if (Rep(rde) == 3) { - OpPause(m); - } -} - static void OpXchgGbEb(struct Machine *m, uint32_t rde) { uint8_t *p; uint8_t x, y; @@ -417,7 +345,7 @@ static void OpCmpxchgEbAlGb(struct Machine *m, uint32_t rde) { x = Read8(m->ax); y = Read8(p); z = Read8(ByteRexrReg(m, rde)); - Alu(0, ALU_SUB, x, y, &m->flags); + Sub8(x, y, &m->flags); if (GetFlag(m->flags, FLAGS_ZF)) { Write8(p, z); } else { @@ -432,7 +360,7 @@ static void OpCmpxchgEvqpRaxGvqp(struct Machine *m, uint32_t rde) { x = ReadMemory(rde, m->ax); y = ReadMemory(rde, p); z = ReadMemory(rde, RegRexrReg(m, rde)); - Alu(RegLog2(rde), ALU_SUB, x, y, &m->flags); + kAlu[ALU_SUB][RegLog2(rde)](x, y, &m->flags); if (GetFlag(m->flags, FLAGS_ZF)) { WriteRegisterOrMemory(rde, p, z); } else { @@ -488,7 +416,7 @@ static void OpXaddEbGb(struct Machine *m, uint32_t rde) { p = GetModrmRegisterWordPointerWriteOszRexw(m, rde); x = Read8(p); y = Read8(RegRexrReg(m, rde)); - z = Alu(0, ALU_ADD, x, y, &m->flags); + z = Add8(x, y, &m->flags); Write8(p, z); Write8(RegRexrReg(m, rde), x); } @@ -499,29 +427,20 @@ static void OpXaddEvqpGvqp(struct Machine *m, uint32_t rde) { p = GetModrmRegisterWordPointerWriteOszRexw(m, rde); x = ReadMemory(rde, p); y = ReadMemory(rde, RegRexrReg(m, rde)); - z = Alu(RegLog2(rde), ALU_ADD, x, y, &m->flags); + z = kAlu[ALU_ADD][RegLog2(rde)](x, y, &m->flags); WriteRegisterOrMemory(rde, p, z); WriteRegister(rde, RegRexrReg(m, rde), x); } -static uint64_t OpDoubleShift(struct Machine *m, uint32_t rde, uint64_t x, - uint64_t y) { - uint8_t b, w, W[2][2] = {{2, 3}, {1, 3}}; - return BsuDoubleShift( - W[Osz(rde)][Rexw(rde)], x, y, - m->xedd->op.opcode & 1 ? Read8(m->cx) : m->xedd->op.uimm0, - m->xedd->op.opcode & 8, &m->flags); -} - -static uint64_t OpBts(uint64_t x, uint64_t y) { +static uint64_t Bts(uint64_t x, uint64_t y) { return x | y; } -static uint64_t OpBtr(uint64_t x, uint64_t y) { +static uint64_t Btr(uint64_t x, uint64_t y) { return x & ~y; } -static uint64_t OpBtc(uint64_t x, uint64_t y) { +static uint64_t Btc(uint64_t x, uint64_t y) { return (x & ~y) | (~x & y); } @@ -547,8 +466,7 @@ static void OpBit(struct Machine *m, uint32_t rde) { if (IsModrmRegister(rde)) { p = RegRexbRm(m, rde); } else { - v = ComputeAddress(m, rde) + disp; - if (Asz(rde)) v &= 0xffffffff; + v = MaskAddress(Eamode(rde), ComputeAddress(m, rde) + disp); p = ReserveAddress(m, v, 1 << w); if (op == 4) { SetReadAddr(m, v, 1 << w); @@ -563,28 +481,27 @@ static void OpBit(struct Machine *m, uint32_t rde) { case 4: return; case 5: - z = OpBts(x, y); + z = Bts(x, y); break; case 6: - z = OpBtr(x, y); + z = Btr(x, y); break; case 7: - z = OpBtc(x, y); + z = Btc(x, y); break; default: - OpUd(m); + OpUd(m, rde); } WriteRegisterOrMemory(rde, p, z); } static void OpConvert1(struct Machine *m, uint32_t rde) { if (Rexw(rde)) { - Write64(m->ax, Read32(m->ax) | - (Read32(m->ax) & 0x80000000 ? 0xffffffff00000000 : 0)); + Write64(m->ax, (int32_t)Read32(m->ax)); } else if (!Osz(rde)) { - Write64(m->ax, Read16(m->ax) | (Read16(m->ax) & 0x8000 ? 0xffff0000 : 0)); + Write64(m->ax, (uint32_t)(int16_t)Read16(m->ax)); } else { - Write16(m->ax, Read8(m->ax) | (Read8(m->ax) & 0x0080 ? 0xff00 : 0)); + Write16(m->ax, (int8_t)Read8(m->ax)); } } @@ -617,52 +534,32 @@ static void OpBswapZvqp(struct Machine *m, uint32_t rde) { } } -static uint8_t pmovmskb(uint64_t x) { - return (x & 0x0000000000000080) >> 007 | (x & 0x0000000000008000) >> 016 | - (x & 0x0000000000800000) >> 025 | (x & 0x0000000080000000) >> 034 | - (x & 0x0000008000000000) >> 043 | (x & 0x0000800000000000) >> 052 | - (x & 0x0080000000000000) >> 061 | (x & 0x8000000000000000) >> 070; -} - -static void OpPmovmskbGdqpNqUdq(struct Machine *m, uint32_t rde) { - uint64_t bitmask; - if (Osz(rde)) { - bitmask = pmovmskb(Read64(XmmRexbRm(m, rde) + 8)) << 8 | - pmovmskb(Read64(XmmRexbRm(m, rde))); - } else { - bitmask = pmovmskb(Read64(MmRm(m, rde) + 8)) << 8 | - pmovmskb(Read64(MmRm(m, rde))); - } - Write64(RegRexrReg(m, rde), bitmask); -} - -static void OpMovEvqpSw(struct Machine *m) { - ThrowSegmentationFault(m, m->ip); -} - -static void OpMovSwEvqp(struct Machine *m) { - ThrowSegmentationFault(m, m->ip); -} - static void OpMovEbIb(struct Machine *m, uint32_t rde) { Write8(GetModrmRegisterBytePointerWrite(m, rde), m->xedd->op.uimm0); } -static void OpMovAlOb(struct Machine *m) { - memcpy(ResolveAddress(m, m->xedd->op.uimm0), m->ax, 1); +static void OpMovAlOb(struct Machine *m, uint32_t rde) { + SetReadAddr(m, m->xedd->op.disp, 1); + Write8(ResolveAddress(m, m->xedd->op.disp), Read8(m->ax)); } -static void OpMovObAl(struct Machine *m) { - memcpy(m->ax, ResolveAddress(m, m->xedd->op.uimm0), 1); +static void OpMovObAl(struct Machine *m, uint32_t rde) { + SetWriteAddr(m, m->xedd->op.disp, 1); + Write8(m->ax, Read8(ResolveAddress(m, m->xedd->op.disp))); } static void OpMovRaxOvqp(struct Machine *m, uint32_t rde) { - WriteRegister(rde, m->ax, - ReadMemory(rde, ResolveAddress(m, m->xedd->op.uimm0))); + uint64_t v; + v = DataSegment(m, rde, m->xedd->op.disp); + SetReadAddr(m, v, 1 << RegLog2(rde)); + WriteRegister(rde, m->ax, ReadMemory(rde, ResolveAddress(m, v))); } static void OpMovOvqpRax(struct Machine *m, uint32_t rde) { - WriteMemory(rde, ResolveAddress(m, m->xedd->op.uimm0), Read64(m->ax)); + uint64_t v; + v = DataSegment(m, rde, m->xedd->op.disp); + SetWriteAddr(m, v, 1 << RegLog2(rde)); + WriteMemory(rde, ResolveAddress(m, v), Read64(m->ax)); } static void OpMovEbGb(struct Machine *m, uint32_t rde) { @@ -681,22 +578,32 @@ static void OpMovZvqpIvqp(struct Machine *m, uint32_t rde) { WriteRegister(rde, RegRexbSrm(m, rde), m->xedd->op.uimm0); } +static void OpIncZv(struct Machine *m, uint32_t rde) { + if (!Osz(rde)) { + Write32(RegSrm(m, rde), Inc32(Read32(RegSrm(m, rde)), 0, &m->flags)); + } else { + Write16(RegSrm(m, rde), Inc16(Read16(RegSrm(m, rde)), 0, &m->flags)); + } +} + +static void OpDecZv(struct Machine *m, uint32_t rde) { + if (!Osz(rde)) { + Write32(RegSrm(m, rde), Dec32(Read32(RegSrm(m, rde)), 0, &m->flags)); + } else { + Write16(RegSrm(m, rde), Dec16(Read16(RegSrm(m, rde)), 0, &m->flags)); + } +} + static void OpMovEvqpIvds(struct Machine *m, uint32_t rde) { WriteRegisterOrMemory(rde, GetModrmRegisterWordPointerWriteOszRexw(m, rde), m->xedd->op.uimm0); } -noinline void OpMovEvqpGvqp(struct Machine *m, uint32_t rde) { +static void OpMovEvqpGvqp(struct Machine *m, uint32_t rde) { WriteRegisterOrMemory(rde, GetModrmRegisterWordPointerWriteOszRexw(m, rde), ReadMemory(rde, RegRexrReg(m, rde))); } -static void OpMovGvqpEvqp(struct Machine *m, uint32_t rde) { - WriteRegister( - rde, RegRexrReg(m, rde), - ReadMemory(rde, GetModrmRegisterWordPointerReadOszRexw(m, rde))); -} - static void OpMovzbGvqpEb(struct Machine *m, uint32_t rde) { WriteRegister(rde, RegRexrReg(m, rde), Read8(GetModrmRegisterBytePointerRead(m, rde))); @@ -725,1599 +632,1317 @@ static void OpMovsxdGdqpEd(struct Machine *m, uint32_t rde) { Write64(RegRexrReg(m, rde), x); } -static void OpMovdquVdqWdq(struct Machine *m, uint32_t rde) { - memcpy(XmmRexrReg(m, rde), GetModrmRegisterXmmPointerRead16(m, rde), 16); -} - -static void OpMovdquWdqVdq(struct Machine *m, uint32_t rde) { - memcpy(GetModrmRegisterXmmPointerWrite16(m, rde), XmmRexrReg(m, rde), 16); -} - -static void OpMovupsVpsWps(struct Machine *m, uint32_t rde) { - OpMovdquVdqWdq(m, rde); -} - -static void OpMovupsWpsVps(struct Machine *m, uint32_t rde) { - OpMovdquWdqVdq(m, rde); -} - -static void OpMovupdVpsWps(struct Machine *m, uint32_t rde) { - OpMovdquVdqWdq(m, rde); -} - -static void OpMovupdWpsVps(struct Machine *m, uint32_t rde) { - OpMovdquWdqVdq(m, rde); -} - -static void OpLddquVdqMdq(struct Machine *m, uint32_t rde) { - OpMovdquVdqWdq(m, rde); -} - -static void OpMovdqaVdqMdq(struct Machine *m, uint32_t rde) { - int64_t v; - uint8_t *p; - v = ComputeAddress(m, rde); - SetReadAddr(m, v, 16); - if ((v & 15) || !(p = FindReal(m, v))) ThrowSegmentationFault(m, v); - memcpy(XmmRexrReg(m, rde), Abp16(p), 16); -} - -static void OpMovdqaMdqVdq(struct Machine *m, uint32_t rde) { - int64_t v; - uint8_t *p; - v = ComputeAddress(m, rde); - SetWriteAddr(m, v, 16); - if ((v & 15) || !(p = FindReal(m, v))) ThrowSegmentationFault(m, v); - memcpy(Abp16(p), XmmRexrReg(m, rde), 16); -} - -static void OpMovdqaVdqWdq(struct Machine *m, uint32_t rde) { - if (IsModrmRegister(rde)) { - memcpy(XmmRexrReg(m, rde), XmmRexbRm(m, rde), 16); - } else { - OpMovdqaVdqMdq(m, rde); - } -} - -static void OpMovdqaWdqVdq(struct Machine *m, uint32_t rde) { - if (IsModrmRegister(rde)) { - memcpy(XmmRexbRm(m, rde), XmmRexrReg(m, rde), 16); - } else { - OpMovdqaMdqVdq(m, rde); - } -} - -static void OpMovntiMdqpGdqp(struct Machine *m, uint32_t rde) { - int64_t v; - uint8_t *a; - void *p[2]; - uint8_t n, b[8]; - v = ComputeAddress(m, rde); - n = Rexw(rde) ? 8 : 4; - a = BeginStore(m, v, n, p, b); - SetWriteAddr(m, v, n); - memcpy(p, XmmRexrReg(m, rde), n); - EndStore(m, v, n, p, b); -} - -static void OpMovntdqMdqVdq(struct Machine *m, uint32_t rde) { - OpMovdqaMdqVdq(m, rde); -} - -static void OpMovntpsMpsVps(struct Machine *m, uint32_t rde) { - OpMovdqaMdqVdq(m, rde); -} - -static void OpMovntpdMpdVpd(struct Machine *m, uint32_t rde) { - OpMovdqaMdqVdq(m, rde); -} - -static void OpMovntdqaVdqMdq(struct Machine *m, uint32_t rde) { - OpMovdqaVdqMdq(m, rde); -} - -static void OpMovqPqQq(struct Machine *m, uint32_t rde) { - memcpy(MmReg(m, rde), GetModrmRegisterMmPointerRead8(m, rde), 8); -} - -static void OpMovqQqPq(struct Machine *m, uint32_t rde) { - memcpy(GetModrmRegisterMmPointerWrite8(m, rde), MmReg(m, rde), 8); -} - -static void OpMovqVdqEqp(struct Machine *m, uint32_t rde) { - memcpy(XmmRexrReg(m, rde), GetModrmRegisterWordPointerRead8(m, rde), 8); - memset(XmmRexrReg(m, rde) + 8, 0, 8); -} - -static void OpMovdVdqEd(struct Machine *m, uint32_t rde) { - memset(XmmRexrReg(m, rde), 0, 16); - memcpy(XmmRexrReg(m, rde), GetModrmRegisterWordPointerRead4(m, rde), 4); -} - -static void OpMovqPqEqp(struct Machine *m, uint32_t rde) { - memcpy(MmReg(m, rde), GetModrmRegisterWordPointerRead8(m, rde), 8); -} - -static void OpMovdPqEd(struct Machine *m, uint32_t rde) { - memcpy(MmReg(m, rde), GetModrmRegisterWordPointerRead4(m, rde), 4); - memset(MmReg(m, rde) + 4, 0, 4); -} - -static void OpMovdEdVdq(struct Machine *m, uint32_t rde) { - if (IsModrmRegister(rde)) { - Write64(RegRexbRm(m, rde), Read32(XmmRexrReg(m, rde))); - } else { - memcpy(ComputeReserveAddressWrite4(m, rde), XmmRexrReg(m, rde), 4); - } -} - -static void OpMovqEqpVdq(struct Machine *m, uint32_t rde) { - memcpy(GetModrmRegisterWordPointerWrite8(m, rde), XmmRexrReg(m, rde), 8); -} - -static void OpMovdEdPq(struct Machine *m, uint32_t rde) { - if (IsModrmRegister(rde)) { - Write64(RegRexbRm(m, rde), Read32(MmReg(m, rde))); - } else { - memcpy(ComputeReserveAddressWrite4(m, rde), MmReg(m, rde), 4); - } -} - -static void OpMovqEqpPq(struct Machine *m, uint32_t rde) { - memcpy(GetModrmRegisterWordPointerWrite(m, rde, 8), MmReg(m, rde), 8); -} - -static void OpMovntqMqPq(struct Machine *m, uint32_t rde) { - memcpy(ComputeReserveAddressWrite8(m, rde), MmReg(m, rde), 8); -} - -static void OpMovqVqWq(struct Machine *m, uint32_t rde) { - memcpy(XmmRexrReg(m, rde), GetModrmRegisterXmmPointerRead8(m, rde), 8); - memset(XmmRexrReg(m, rde) + 8, 0, 8); -} - -static void OpMovssVpsWps(struct Machine *m, uint32_t rde) { - memcpy(XmmRexrReg(m, rde), GetModrmRegisterXmmPointerRead4(m, rde), 4); -} - -static void OpMovssWpsVps(struct Machine *m, uint32_t rde) { - memcpy(GetModrmRegisterXmmPointerWrite4(m, rde), XmmRexrReg(m, rde), 4); -} - -static void OpMovsdVpsWps(struct Machine *m, uint32_t rde) { - memcpy(XmmRexrReg(m, rde), GetModrmRegisterXmmPointerRead16(m, rde), 8); -} - -static void OpMovsdWpsVps(struct Machine *m, uint32_t rde) { - memcpy(GetModrmRegisterXmmPointerWrite16(m, rde), XmmRexrReg(m, rde), 8); -} - -static void OpMaskMovDiXmmRegXmmRm(struct Machine *m, uint32_t rde) { - void *p[2]; - uint64_t v; - unsigned i, n; - uint8_t *mem, b[16]; - n = Osz(rde) ? 16 : 8; - v = GetSegment() + Read64(m->di); - if (Asz(rde)) v &= 0xffffffff; - mem = BeginStore(m, v, n, p, b); - for (i = 0; i < n; ++i) { - if (XmmRexbRm(m, rde)[i] & 0x80) { - mem[i] = XmmRexrReg(m, rde)[i]; - } - } - EndStore(m, v, n, p, b); -} - -static void OpMovhlpsVqUq(struct Machine *m, uint32_t rde) { - memcpy(XmmRexrReg(m, rde), XmmRexbRm(m, rde) + 8, 8); -} - -static void OpMovlpsVqMq(struct Machine *m, uint32_t rde) { - memcpy(XmmRexrReg(m, rde), ComputeReserveAddressRead8(m, rde), 8); -} - -static void OpMovlpdVqMq(struct Machine *m, uint32_t rde) { - memcpy(XmmRexrReg(m, rde), ComputeReserveAddressRead8(m, rde), 8); -} - -static void OpMovddupVqWq(struct Machine *m, uint32_t rde) { - uint8_t *src; - src = GetModrmRegisterXmmPointerRead8(m, rde); - memcpy(XmmRexrReg(m, rde) + 0, src, 8); - memcpy(XmmRexrReg(m, rde) + 8, src, 8); -} - -static void OpMovsldupVqWq(struct Machine *m, uint32_t rde) { - uint8_t *dst, *src; - dst = XmmRexrReg(m, rde); - src = GetModrmRegisterXmmPointerRead16(m, rde); - memcpy(dst + 0 + 0, src + 0, 4); - memcpy(dst + 0 + 4, src + 0, 4); - memcpy(dst + 8 + 0, src + 8, 4); - memcpy(dst + 8 + 4, src + 8, 4); -} - -static void OpMovlpsMqVq(struct Machine *m, uint32_t rde) { - memcpy(ComputeReserveAddressWrite8(m, rde), XmmRexrReg(m, rde), 8); -} - -static void OpMovlpdMqVq(struct Machine *m, uint32_t rde) { - memcpy(ComputeReserveAddressWrite8(m, rde), XmmRexrReg(m, rde), 8); -} - -static void OpMovlhpsVqUq(struct Machine *m, uint32_t rde) { - memcpy(XmmRexrReg(m, rde) + 8, XmmRexbRm(m, rde), 8); -} - -static void OpMovhpsVqMq(struct Machine *m, uint32_t rde) { - memcpy(XmmRexrReg(m, rde) + 8, ComputeReserveAddressRead8(m, rde), 8); -} - -static void OpMovhpdVqMq(struct Machine *m, uint32_t rde) { - memcpy(XmmRexrReg(m, rde) + 8, ComputeReserveAddressRead8(m, rde), 8); -} - -static void OpMovshdupVqWq(struct Machine *m, uint32_t rde) { - uint8_t *dst, *src; - dst = XmmRexrReg(m, rde); - src = GetModrmRegisterXmmPointerRead16(m, rde); - memcpy(dst + 0 + 0, src + 04, 4); - memcpy(dst + 0 + 4, src + 04, 4); - memcpy(dst + 8 + 0, src + 12, 4); - memcpy(dst + 8 + 4, src + 12, 4); -} - -static void OpMovhpsMqVq(struct Machine *m, uint32_t rde) { - memcpy(ComputeReserveAddressRead8(m, rde), XmmRexrReg(m, rde) + 8, 8); -} - -static void OpMovhpdMqVq(struct Machine *m, uint32_t rde) { - memcpy(ComputeReserveAddressRead8(m, rde), XmmRexrReg(m, rde) + 8, 8); -} - -static void OpMovqWqVq(struct Machine *m, uint32_t rde) { - if (IsModrmRegister(rde)) { - memcpy(XmmRexbRm(m, rde), XmmRexrReg(m, rde), 8); - memset(XmmRexbRm(m, rde) + 8, 0, 8); - } else { - memcpy(ComputeReserveAddressWrite8(m, rde), XmmRexrReg(m, rde), 8); - } -} - -static void OpMovq2dqVdqNq(struct Machine *m, uint32_t rde) { - memcpy(XmmRexrReg(m, rde), MmRm(m, rde), 8); - memset(XmmRexrReg(m, rde) + 8, 0, 8); -} - -static void OpMovdq2qPqUq(struct Machine *m, uint32_t rde) { - memcpy(MmReg(m, rde), XmmRexbRm(m, rde), 8); -} - -static void OpMovapsVpsWps(struct Machine *m, uint32_t rde) { - OpMovdqaVdqWdq(m, rde); -} - -static void OpMovapdVpdWpd(struct Machine *m, uint32_t rde) { - OpMovdqaVdqWdq(m, rde); -} - -static void OpMovapsWpsVps(struct Machine *m, uint32_t rde) { - OpMovdqaWdqVdq(m, rde); -} - -static void OpMovapdWpdVpd(struct Machine *m, uint32_t rde) { - OpMovdqaWdqVdq(m, rde); -} - -static void OpMovWpsVps(struct Machine *m, uint32_t rde) { - uint8_t *p, *r; - switch (Rep(rde) | Osz(rde)) { - case 0: - OpMovupsWpsVps(m, rde); - break; - case 1: - OpMovupdWpsVps(m, rde); - break; - case 2: - OpMovsdWpsVps(m, rde); - break; - case 3: - OpMovssWpsVps(m, rde); - break; - default: - unreachable; - } -} - -static void OpMov0f28(struct Machine *m, uint32_t rde) { - if (!Osz(rde)) { - OpMovapsVpsWps(m, rde); - } else { - OpMovapdVpdWpd(m, rde); - } -} - -static void OpMov0f6e(struct Machine *m, uint32_t rde) { - if (Osz(rde)) { - if (Rexw(rde)) { - OpMovqVdqEqp(m, rde); - } else { - OpMovdVdqEd(m, rde); - } - } else { - if (Rexw(rde)) { - OpMovqPqEqp(m, rde); - } else { - OpMovdPqEd(m, rde); - } - } -} - -static void OpMov0f6f(struct Machine *m, uint32_t rde) { - if (Osz(rde)) { - OpMovdqaVdqWdq(m, rde); - } else if (Rep(rde) == 3) { - OpMovdquVdqWdq(m, rde); - } else { - OpMovqPqQq(m, rde); - } -} - -static void OpMov0fE7(struct Machine *m, uint32_t rde) { - if (!Osz(rde)) { - OpMovntqMqPq(m, rde); - } else { - OpMovntdqMdqVdq(m, rde); - } -} - -static void OpMov0f7e(struct Machine *m, uint32_t rde) { - if (Rep(rde) == 3) { - OpMovqVqWq(m, rde); - } else if (Osz(rde)) { - if (Rexw(rde)) { - OpMovqEqpVdq(m, rde); - } else { - OpMovdEdVdq(m, rde); - } - } else { - if (Rexw(rde)) { - OpMovqEqpPq(m, rde); - } else { - OpMovdEdPq(m, rde); - } - } -} - -static void OpMov0f7f(struct Machine *m, uint32_t rde) { - if (Rep(rde) == 3) { - OpMovdquWdqVdq(m, rde); - } else if (Osz(rde)) { - OpMovdqaWdqVdq(m, rde); - } else { - OpMovqQqPq(m, rde); - } -} - -static void OpMov0f10(struct Machine *m, uint32_t rde) { - uint8_t *p, *r; - switch (Rep(rde) | Osz(rde)) { - case 0: - OpMovupsVpsWps(m, rde); - break; - case 1: - OpMovupdVpsWps(m, rde); - break; - case 2: - OpMovsdVpsWps(m, rde); - break; - case 3: - OpMovssVpsWps(m, rde); - break; - default: - unreachable; - } -} - -static void OpMov0f29(struct Machine *m, uint32_t rde) { - if (!Osz(rde)) { - OpMovapsWpsVps(m, rde); - } else { - OpMovapdWpdVpd(m, rde); - } -} - -static void OpMov0f2b(struct Machine *m, uint32_t rde) { - if (!Osz(rde)) { - OpMovntpsMpsVps(m, rde); - } else { - OpMovntpdMpdVpd(m, rde); - } -} - -static void OpMov0f12(struct Machine *m, uint32_t rde) { - switch (Rep(rde) | Osz(rde)) { - case 0: - if (IsModrmRegister(rde)) { - OpMovhlpsVqUq(m, rde); - } else { - OpMovlpsVqMq(m, rde); - } - break; - case 1: - OpMovlpdVqMq(m, rde); - break; - case 2: - OpMovddupVqWq(m, rde); - break; - case 3: - OpMovsldupVqWq(m, rde); - break; - default: - unreachable; - } -} - -static void OpMov0f13(struct Machine *m, uint32_t rde) { - if (Osz(rde)) { - OpMovlpdMqVq(m, rde); - } else { - OpMovlpsMqVq(m, rde); - } -} - -static void OpMov0f16(struct Machine *m, uint32_t rde) { - switch (Rep(rde) | Osz(rde)) { - case 0: - if (IsModrmRegister(rde)) { - OpMovlhpsVqUq(m, rde); - } else { - OpMovhpsVqMq(m, rde); - } - break; - case 1: - OpMovhpdVqMq(m, rde); - break; - case 3: - OpMovshdupVqWq(m, rde); - break; - default: - OpUd(m); - break; - } -} - -static void OpMov0f17(struct Machine *m, uint32_t rde) { - if (Osz(rde)) { - OpMovhpdMqVq(m, rde); - } else { - OpMovhpsMqVq(m, rde); - } -} - -static void OpMov0fD6(struct Machine *m, uint32_t rde) { - if (Rep(rde) == 3) { - OpMovq2dqVdqNq(m, rde); - } else if (Rep(rde) == 2) { - OpMovdq2qPqUq(m, rde); - } else if (Osz(rde)) { - OpMovqWqVq(m, rde); - } else { - OpUd(m); - } -} - -static void OpUnpcklpsd(struct Machine *m, uint32_t rde) { - uint8_t *a, *b; - a = XmmRexrReg(m, rde); - b = GetModrmRegisterXmmPointerRead8(m, rde); - if (Osz(rde)) { - memcpy(a + 8, b, 8); - } else { - memcpy(a + 4 * 3, b + 4, 4); - memcpy(a + 4 * 2, a + 4, 4); - memcpy(a + 4 * 1, b + 0, 4); - } -} - -static void OpUnpckhpsd(struct Machine *m, uint32_t rde) { - uint8_t *a, *b; - a = XmmRexrReg(m, rde); - b = GetModrmRegisterXmmPointerRead16(m, rde); - if (Osz(rde)) { - memcpy(a + 0, b + 8, 8); - memcpy(a + 8, b + 8, 8); - } else { - memcpy(a + 4 * 0, a + 4 * 2, 4); - memcpy(a + 4 * 1, b + 4 * 2, 4); - memcpy(a + 4 * 2, a + 4 * 3, 4); - memcpy(a + 4 * 3, b + 4 * 3, 4); - } -} - -static void OpPextrwGdqpUdqIb(struct Machine *m, uint32_t rde) { - uint8_t i; - i = m->xedd->op.uimm0; - i &= Osz(rde) ? 7 : 3; - Write16(RegRexrReg(m, rde), Read16(XmmRexbRm(m, rde) + i * 2)); -} - -static void OpPinsrwVdqEwIb(struct Machine *m, uint32_t rde) { - uint8_t i; - i = m->xedd->op.uimm0; - i &= Osz(rde) ? 7 : 3; - Write16(XmmRexrReg(m, rde) + i * 2, - Read16(GetModrmRegisterWordPointerRead2(m, rde))); -} - -static void OpShuffle(struct Machine *m, uint32_t rde) { - int16_t q16[4]; - int16_t x16[8]; - int32_t x32[4]; - switch (Rep(rde) | Osz(rde)) { - case 0: - memcpy(q16, GetModrmRegisterXmmPointerRead8(m, rde), 8); - (pshufw)(q16, q16, m->xedd->op.uimm0); - memcpy(XmmRexrReg(m, rde), q16, 8); - break; - case 1: - memcpy(x32, GetModrmRegisterXmmPointerRead16(m, rde), 16); - (pshufd)(x32, x32, m->xedd->op.uimm0); - memcpy(XmmRexrReg(m, rde), x32, 16); - break; - case 2: - memcpy(x16, GetModrmRegisterXmmPointerRead16(m, rde), 16); - (pshuflw)(x16, x16, m->xedd->op.uimm0); - memcpy(XmmRexrReg(m, rde), x16, 16); - break; - case 3: - memcpy(x16, GetModrmRegisterXmmPointerRead16(m, rde), 16); - (pshufhw)(x16, x16, m->xedd->op.uimm0); - memcpy(XmmRexrReg(m, rde), x16, 16); - break; - default: - unreachable; - } -} - -static void OpShufps(struct Machine *m, uint32_t rde) { - shufps((void *)XmmRexrReg(m, rde), (void *)XmmRexrReg(m, rde), - (void *)GetModrmRegisterXmmPointerRead16(m, rde), m->xedd->op.uimm0); -} - -static void OpShufpd(struct Machine *m, uint32_t rde) { - shufpd((void *)XmmRexrReg(m, rde), (void *)XmmRexrReg(m, rde), - (void *)GetModrmRegisterXmmPointerRead16(m, rde), m->xedd->op.uimm0); -} - -static void OpShufpsd(struct Machine *m, uint32_t rde) { - if (Osz(rde)) { - OpShufpd(m, rde); - } else { - OpShufps(m, rde); - } -} - -static void OpSqrtpsd(struct Machine *m, uint32_t rde) { - long i; - float_v xf; - double_v xd; - switch (Rep(rde) | Osz(rde)) { - case 0: - memcpy(&xf, GetModrmRegisterXmmPointerRead16(m, rde), 16); - for (i = 0; i < 4; ++i) xf[i] = sqrtf(xf[i]); - memcpy(XmmRexrReg(m, rde), &xf, 16); - break; - case 1: - memcpy(&xd, GetModrmRegisterXmmPointerRead16(m, rde), 16); - for (i = 0; i < 2; ++i) xd[i] = sqrt(xd[i]); - memcpy(XmmRexrReg(m, rde), &xd, 16); - break; - case 2: - memcpy(&xd, GetModrmRegisterXmmPointerRead8(m, rde), 8); - xd[0] = sqrt(xd[0]); - memcpy(XmmRexrReg(m, rde), &xd, 8); - break; - case 3: - memcpy(&xf, GetModrmRegisterXmmPointerRead4(m, rde), 4); - xf[0] = sqrtf(xf[0]); - memcpy(XmmRexrReg(m, rde), &xf, 4); - break; - default: - unreachable; - } -} - -static void OpRsqrtps(struct Machine *m, uint32_t rde) { - float_v x; - unsigned i; - if (Rep(rde) != 3) { - memcpy(&x, GetModrmRegisterXmmPointerRead16(m, rde), 16); - for (i = 0; i < 4; ++i) x[i] = 1.f / sqrtf(x[i]); - memcpy(XmmRexrReg(m, rde), &x, 16); - } else { - memcpy(&x, GetModrmRegisterXmmPointerRead4(m, rde), 4); - x[0] = 1.f / sqrtf(x[0]); - memcpy(XmmRexrReg(m, rde), &x, 4); - } -} - -static void OpRcpps(struct Machine *m, uint32_t rde) { - float_v x; - unsigned i; - if (Rep(rde) != 3) { - memcpy(&x, GetModrmRegisterXmmPointerRead16(m, rde), 16); - for (i = 0; i < 4; ++i) x[i] = 1.f / x[i]; - memcpy(XmmRexrReg(m, rde), &x, 16); - } else { - memcpy(&x, GetModrmRegisterXmmPointerRead4(m, rde), 4); - x[0] = 1.f / x[0]; - memcpy(XmmRexrReg(m, rde), &x, 4); - } -} - -static void OpVpsdWpsd(struct Machine *m, uint32_t rde, - float_v opf(struct Machine *, float_v, float_v), - double_v opd(struct Machine *, double_v, double_v), - bool isfloat, bool isdouble) { - float_v xf, yf; - double_v xd, yd; - if (isfloat) { - memcpy(&xf, XmmRexrReg(m, rde), 16); - memcpy(&yf, GetModrmRegisterXmmPointerRead16(m, rde), 16); - xf = opf(m, xf, yf); - memcpy(XmmRexrReg(m, rde), &xf, 16); - } else if (isdouble) { - memcpy(&xd, XmmRexrReg(m, rde), 16); - memcpy(&yd, GetModrmRegisterXmmPointerRead16(m, rde), 16); - xd = opd(m, xd, yd); - memcpy(XmmRexrReg(m, rde), &xd, 16); - } else { - OpUd(m); - } -} - -static void OpVpsdWpsd66(struct Machine *m, uint32_t rde, - float_v opf(struct Machine *, float_v, float_v), - double_v opd(struct Machine *, double_v, double_v)) { - OpVpsdWpsd(m, rde, opf, opd, !Osz(rde), Osz(rde)); -} - -static void OpVpsdWpsd66f2(struct Machine *m, uint32_t rde, - float_v opf(struct Machine *, float_v, float_v), - double_v opd(struct Machine *, double_v, double_v)) { - OpVpsdWpsd(m, rde, opf, opd, Rep(rde) == 2, Osz(rde)); -} - -static void OpVspsdWspsd(struct Machine *m, uint32_t rde, - float_v opf(struct Machine *, float_v, float_v), - double_v opd(struct Machine *, double_v, double_v)) { - float_v xf, yf; - double_v xd, yd; - switch (Rep(rde) | Osz(rde)) { - case 0: - memcpy(&yf, GetModrmRegisterXmmPointerRead16(m, rde), 16); - memcpy(&xf, XmmRexrReg(m, rde), 16); - xf = opf(m, xf, yf); - memcpy(XmmRexrReg(m, rde), &xf, 16); - break; - case 1: - memcpy(&yd, GetModrmRegisterXmmPointerRead16(m, rde), 16); - memcpy(&xd, XmmRexrReg(m, rde), 16); - xd = opd(m, xd, yd); - memcpy(XmmRexrReg(m, rde), &xd, 16); - break; - case 2: - memcpy(&yd, GetModrmRegisterXmmPointerRead8(m, rde), 8); - memcpy(&xd, XmmRexrReg(m, rde), 8); - xd = opd(m, xd, yd); - memcpy(XmmRexrReg(m, rde), &xd, 8); - break; - case 3: - memcpy(&yf, GetModrmRegisterXmmPointerRead4(m, rde), 4); - memcpy(&xf, XmmRexrReg(m, rde), 4); - xf = opf(m, xf, yf); - memcpy(XmmRexrReg(m, rde), &xf, 4); - break; - default: - unreachable; - } -} - -static void OpComissVsWs(struct Machine *m, uint32_t rde) { - float xf, yf; - double xd, yd; - uint8_t zf, cf, pf, ie; - if (!Osz(rde)) { - memcpy(&xf, XmmRexrReg(m, rde), 4); - memcpy(&yf, GetModrmRegisterXmmPointerRead4(m, rde), 4); - if (!isnan(xf) && !isnan(yf)) { - zf = xf == yf; - cf = xf < yf; - pf = false; - ie = false; - } else { - zf = cf = pf = ie = true; - } - } else { - memcpy(&xd, XmmRexrReg(m, rde), 8); - memcpy(&yd, GetModrmRegisterXmmPointerRead8(m, rde), 8); - if (!isnan(xd) && !isnan(yd)) { - zf = xd == yd; - cf = xd < yd; - pf = false; - ie = false; - } else { - zf = cf = pf = ie = true; - } - } - m->flags = SetFlag(m->flags, FLAGS_ZF, zf); - m->flags = SetFlag(m->flags, FLAGS_PF, pf); - m->flags = SetFlag(m->flags, FLAGS_CF, cf); - m->flags = SetFlag(m->flags, FLAGS_SF, false); - m->flags = SetFlag(m->flags, FLAGS_OF, false); - if ((m->xedd->op.opcode & 1) && (m->sse.ie = ie) && !m->sse.im) { - HaltMachine(m, kMachineSimdException); - } -} - -static float_v OpAddps(struct Machine *m, float_v x, float_v y) { - return x + y; -} - -static double_v OpAddpd(struct Machine *m, double_v x, double_v y) { - return x + y; -} - -static float_v OpMulps(struct Machine *m, float_v x, float_v y) { - return x * y; -} - -static double_v OpMulpd(struct Machine *m, double_v x, double_v y) { - return x * y; -} - -static float_v OpSubps(struct Machine *m, float_v x, float_v y) { - return x - y; -} - -static double_v OpSubpd(struct Machine *m, double_v x, double_v y) { - return x - y; -} - -static float_v OpDivps(struct Machine *m, float_v x, float_v y) { - return x / y; -} - -static double_v OpDivpd(struct Machine *m, double_v x, double_v y) { - return x / y; -} - -static float_v OpAndps(struct Machine *m, float_v x, float_v y) { - return (float_v)((int_v)x & (int_v)y); -} - -static double_v OpAndpd(struct Machine *m, double_v x, double_v y) { - return (double_v)((long_v)x & (long_v)y); -} - -static float_v OpAndnps(struct Machine *m, float_v x, float_v y) { - return (float_v)(~(int_v)x & (int_v)y); -} - -static double_v OpAndnpd(struct Machine *m, double_v x, double_v y) { - return (double_v)(~(long_v)x & (long_v)y); -} - -static float_v OpOrps(struct Machine *m, float_v x, float_v y) { - return (float_v)((int_v)x | (int_v)y); -} - -static double_v OpOrpd(struct Machine *m, double_v x, double_v y) { - return (double_v)((long_v)x | (long_v)y); -} - -static float_v OpXorps(struct Machine *m, float_v x, float_v y) { - return (float_v)((int_v)x ^ (int_v)y); -} - -static double_v OpXorpd(struct Machine *m, double_v x, double_v y) { - return (double_v)((long_v)x ^ (long_v)y); -} - -static double_v OpHaddpd(struct Machine *m, double_v x, double_v y) { - return (double_v){x[0] + x[1], y[0] + y[1]}; -} - -static float_v OpHaddps(struct Machine *m, float_v x, float_v y) { - return (float_v){x[0] + x[1], x[2] + x[3], y[0] + y[1], y[2] + y[3]}; -} - -static double_v OpHsubpd(struct Machine *m, double_v x, double_v y) { - return (double_v){x[0] - x[1], y[0] - y[1]}; -} - -static float_v OpHsubps(struct Machine *m, float_v x, float_v y) { - return (float_v){x[0] - x[1], x[2] - x[3], y[0] - y[1], y[2] - y[3]}; -} - -static double_v OpAddsubpd(struct Machine *m, double_v x, double_v y) { - return (double_v){x[0] - y[0], x[1] + y[1]}; -} - -static float_v OpAddsubps(struct Machine *m, float_v x, float_v y) { - return (float_v){x[0] - y[0], x[1] + y[1], x[2] - y[2], x[3] + y[3]}; -} - -static float_v OpMinps(struct Machine *m, float_v x, float_v y) { - unsigned i; - for (i = 0; i < 4; ++i) { - x[i] = MIN(x[i], y[i]); - } - return x; -} - -static double_v OpMinpd(struct Machine *m, double_v x, double_v y) { - unsigned i; - for (i = 0; i < 4; ++i) { - x[i] = MIN(x[i], y[i]); - } - return x; -} - -static float_v OpMaxps(struct Machine *m, float_v x, float_v y) { - unsigned i; - for (i = 0; i < 4; ++i) { - x[i] = MAX(x[i], y[i]); - } - return x; -} - -static double_v OpMaxpd(struct Machine *m, double_v x, double_v y) { - unsigned i; - for (i = 0; i < 4; ++i) { - x[i] = MAX(x[i], y[i]); - } - return x; -} - -static float_v OpCmpps(struct Machine *m, float_v x, float_v y) { - long i; - switch (m->xedd->op.uimm0) { - case 0: - return x == y; - case 1: - return x < y; - case 2: - return x <= y; - case 3: - for (i = 0; i < 4; ++i) { - x[i] = isnan(x[i]) || isnan(y[i]); - } - return x; - case 4: - return x != y; - case 5: - return x >= y; - case 6: - return x > y; - case 7: - for (i = 0; i < 4; ++i) { - x[i] = !(isnan(x[i]) || isnan(y[i])); - } - return x; - default: - OpUd(m); - } -} - -static double_v OpCmppd(struct Machine *m, double_v x, double_v y) { - long i; - switch (m->xedd->op.uimm0) { - case 0: - return x == y; - case 1: - return x < y; - case 2: - return x <= y; - case 3: - for (i = 0; i < 2; ++i) { - x[i] = isnan(x[i]) || isnan(y[i]); - } - return x; - case 4: - return x != y; - case 5: - return x >= y; - case 6: - return x > y; - case 7: - for (i = 0; i < 2; ++i) { - x[i] = !(isnan(x[i]) || isnan(y[i])); - } - return x; - default: - OpUd(m); - } -} - -static void OpAddpsd(struct Machine *m, uint32_t rde) { - OpVspsdWspsd(m, rde, OpAddps, OpAddpd); -} - -static void OpMulpsd(struct Machine *m, uint32_t rde) { - OpVspsdWspsd(m, rde, OpMulps, OpMulpd); -} - -static void OpSubpsd(struct Machine *m, uint32_t rde) { - OpVspsdWspsd(m, rde, OpSubps, OpSubpd); -} - -static void OpDivpsd(struct Machine *m, uint32_t rde) { - OpVspsdWspsd(m, rde, OpDivps, OpDivpd); -} - -static void OpMinpsd(struct Machine *m, uint32_t rde) { - OpVspsdWspsd(m, rde, OpMinps, OpMinpd); -} - -static void OpMaxpsd(struct Machine *m, uint32_t rde) { - OpVspsdWspsd(m, rde, OpMaxps, OpMaxpd); -} - -static void OpCmppsd(struct Machine *m, uint32_t rde) { - OpVspsdWspsd(m, rde, OpCmpps, OpCmppd); -} - -static void OpAndpsd(struct Machine *m, uint32_t rde) { - OpVpsdWpsd66(m, rde, OpAndps, OpAndpd); -} - -static void OpAndnpsd(struct Machine *m, uint32_t rde) { - OpVpsdWpsd66(m, rde, OpAndnps, OpAndnpd); -} - -static void OpOrpsd(struct Machine *m, uint32_t rde) { - OpVpsdWpsd66(m, rde, OpOrps, OpOrpd); -} - -static void OpXorpsd(struct Machine *m, uint32_t rde) { - OpVpsdWpsd66(m, rde, OpXorps, OpXorpd); -} - -static void OpHaddpsd(struct Machine *m, uint32_t rde) { - OpVpsdWpsd66f2(m, rde, OpHaddps, OpHaddpd); -} - -static void OpHsubpsd(struct Machine *m, uint32_t rde) { - OpVpsdWpsd66f2(m, rde, OpHsubps, OpHsubpd); -} - -static void OpAddsubpsd(struct Machine *m, uint32_t rde) { - OpVpsdWpsd66f2(m, rde, OpAddsubps, OpAddsubpd); -} - -static void OpAlub(struct Machine *m, uint32_t rde, int h) { +static void OpAlub(struct Machine *m, uint32_t rde) { uint8_t *a; a = GetModrmRegisterBytePointerWrite(m, rde); - Write8(a, Alu(0, h, Read8(a), Read8(ByteRexrReg(m, rde)), &m->flags)); + Write8(a, kAlu[(m->xedd->op.opcode & 070) >> 3][0]( + Read8(a), Read8(ByteRexrReg(m, rde)), &m->flags)); } -static void OpAlubRo(struct Machine *m, uint32_t rde, int h) { - Alu(0, h, Read8(GetModrmRegisterBytePointerWrite(m, rde)), - Read8(ByteRexrReg(m, rde)), &m->flags); +static void AlubRo(struct Machine *m, uint32_t rde, aluop_f op) { + op(Read8(GetModrmRegisterBytePointerRead(m, rde)), Read8(ByteRexrReg(m, rde)), + &m->flags); } -static void OpAlubFlip(struct Machine *m, uint32_t rde, int h) { +static void OpAlubCmp(struct Machine *m, uint32_t rde) { + AlubRo(m, rde, Sub8); +} + +static void OpAlubTest(struct Machine *m, uint32_t rde) { + AlubRo(m, rde, And8); +} + +static void OpAlubFlip(struct Machine *m, uint32_t rde) { Write8(ByteRexrReg(m, rde), - Alu(0, h, Read8(ByteRexrReg(m, rde)), + kAlu[(m->xedd->op.opcode & 070) >> 3][0]( + Read8(ByteRexrReg(m, rde)), Read8(GetModrmRegisterBytePointerRead(m, rde)), &m->flags)); } -static void OpAlubFlipRo(struct Machine *m, uint32_t rde, int h) { - Alu(0, h, Read8(ByteRexrReg(m, rde)), - Read8(GetModrmRegisterBytePointerRead(m, rde)), &m->flags); +static void AlubFlipRo(struct Machine *m, uint32_t rde, aluop_f op) { + op(Read8(ByteRexrReg(m, rde)), Read8(GetModrmRegisterBytePointerRead(m, rde)), + &m->flags); } -static void OpAlubi(struct Machine *m, uint32_t rde, int h) { +static void OpAlubFlipCmp(struct Machine *m, uint32_t rde) { + AlubFlipRo(m, rde, Sub8); +} + +static void OpAlubFlipTest(struct Machine *m, uint32_t rde) { + AlubFlipRo(m, rde, And8); +} + +static void Alubi(struct Machine *m, uint32_t rde, aluop_f op) { uint8_t *a, x; a = GetModrmRegisterBytePointerWrite(m, rde); - x = Alu(0, h, Read8(a), m->xedd->op.uimm0, &m->flags); - if (h != ALU_CMP) Write8(a, x); + Write8(a, op(Read8(a), m->xedd->op.uimm0, &m->flags)); } -static void OpAlubiRo(struct Machine *m, uint32_t rde, int h) { - Alu(0, h, Read8(GetModrmRegisterBytePointerWrite(m, rde)), m->xedd->op.uimm0, - &m->flags); +static void AlubiRo(struct Machine *m, uint32_t rde, aluop_f op) { + op(Read8(GetModrmRegisterBytePointerRead(m, rde)), m->xedd->op.uimm0, + &m->flags); } -static void OpAluw(struct Machine *m, uint32_t rde, int h) { +static void OpAlubiTest(struct Machine *m, uint32_t rde) { + AlubiRo(m, rde, And8); +} + +static void OpAlubiReg(struct Machine *m, uint32_t rde) { + if (ModrmReg(rde) == ALU_CMP) { + AlubiRo(m, rde, kAlu[ModrmReg(rde)][0]); + } else { + Alubi(m, rde, kAlu[ModrmReg(rde)][0]); + } +} + +static void OpAluw(struct Machine *m, uint32_t rde) { uint8_t *a; a = GetModrmRegisterWordPointerWriteOszRexw(m, rde); - WriteRegisterOrMemory(rde, a, - Alu(RegLog2(rde), h, ReadMemory(rde, a), - Read64(RegRexrReg(m, rde)), &m->flags)); + WriteRegisterOrMemory( + rde, a, + kAlu[(m->xedd->op.opcode & 070) >> 3][RegLog2(rde)]( + ReadMemory(rde, a), Read64(RegRexrReg(m, rde)), &m->flags)); } -static void OpAluwRo(struct Machine *m, uint32_t rde, int h) { - Alu(RegLog2(rde), h, - ReadMemory(rde, GetModrmRegisterWordPointerWriteOszRexw(m, rde)), +static void AluwRo(struct Machine *m, uint32_t rde, aluop_f ops[4]) { + ops[RegLog2(rde)]( + ReadMemory(rde, GetModrmRegisterWordPointerReadOszRexw(m, rde)), Read64(RegRexrReg(m, rde)), &m->flags); } -static void OpAluwFlip(struct Machine *m, uint32_t rde, int h) { +static void OpAluwCmp(struct Machine *m, uint32_t rde) { + AluwRo(m, rde, kAlu[ALU_SUB]); +} + +static void OpAluwTest(struct Machine *m, uint32_t rde) { + AluwRo(m, rde, kAlu[ALU_AND]); +} + +static void OpAluwFlip(struct Machine *m, uint32_t rde) { WriteRegister( rde, RegRexrReg(m, rde), - Alu(RegLog2(rde), h, Read64(RegRexrReg(m, rde)), + kAlu[(m->xedd->op.opcode & 070) >> 3][RegLog2(rde)]( + Read64(RegRexrReg(m, rde)), ReadMemory(rde, GetModrmRegisterWordPointerReadOszRexw(m, rde)), &m->flags)); } -static void OpAluwFlipRo(struct Machine *m, uint32_t rde, int h) { - Alu(RegLog2(rde), h, Read64(RegRexrReg(m, rde)), +static void AluwFlipRo(struct Machine *m, uint32_t rde, aluop_f ops[4]) { + ops[RegLog2(rde)]( + Read64(RegRexrReg(m, rde)), ReadMemory(rde, GetModrmRegisterWordPointerReadOszRexw(m, rde)), &m->flags); } -static void OpAluwi(struct Machine *m, uint32_t rde, int h) { +static void OpAluwFlipCmp(struct Machine *m, uint32_t rde) { + AluwFlipRo(m, rde, kAlu[ALU_SUB]); +} + +static void OpAluwFlipTest(struct Machine *m, uint32_t rde) { + AluwFlipRo(m, rde, kAlu[ALU_AND]); +} + +static void Aluwi(struct Machine *m, uint32_t rde, aluop_f ops[4]) { uint8_t *a; uint64_t x; a = GetModrmRegisterWordPointerWriteOszRexw(m, rde); - x = Alu(RegLog2(rde), h, ReadMemory(rde, a), m->xedd->op.uimm0, &m->flags); - if (h != ALU_CMP) WriteRegisterOrMemory(rde, a, x); + WriteRegisterOrMemory( + rde, a, + ops[RegLog2(rde)](ReadMemory(rde, a), m->xedd->op.uimm0, &m->flags)); } -static void OpAluwiRo(struct Machine *m, uint32_t rde, int h) { - Alu(RegLog2(rde), h, - ReadMemory(rde, GetModrmRegisterWordPointerWriteOszRexw(m, rde)), +static void AluwiRo(struct Machine *m, uint32_t rde, aluop_f ops[4]) { + ops[RegLog2(rde)]( + ReadMemory(rde, GetModrmRegisterWordPointerReadOszRexw(m, rde)), m->xedd->op.uimm0, &m->flags); } -static void OpBsuwi(struct Machine *m, uint32_t rde, int h, uint64_t yimm) { - int64_t v; - void *p[2]; - uint8_t w, *a, split[8]; - w = RegLog2(rde); - if (IsModrmRegister(rde)) { - v = 0; - a = RegRexbRm(m, rde); +static void OpAluwiReg(struct Machine *m, uint32_t rde) { + if (ModrmReg(rde) == ALU_CMP) { + AluwiRo(m, rde, kAlu[ModrmReg(rde)]); } else { - v = ComputeAddress(m, rde); - a = BeginLoadStore(m, v, 1 << w, p, split); + Aluwi(m, rde, kAlu[ModrmReg(rde)]); } - WriteRegisterOrMemory(rde, a, Bsu(w, h, Read64(a), yimm, &m->flags)); - EndStore(m, v, 1 << w, p, split); } -static void OpBsubi(struct Machine *m, uint32_t rde, int h, uint64_t yimm) { - uint8_t *a; - a = GetModrmRegisterBytePointerWrite(m, rde); - Write8(a, Bsu(0, h, Read8(a), yimm, &m->flags)); +static void OpAluAlIb(struct Machine *m, uint32_t rde) { + Write8(m->ax, kAlu[(m->xedd->op.opcode & 070) >> 3][0]( + Read8(m->ax), m->xedd->op.uimm0, &m->flags)); } -static void OpAluAlIb(struct Machine *m, int h) { - Write8(m->ax, Alu(0, h, Read8(m->ax), m->xedd->op.uimm0, &m->flags)); -} - -static void OpAluRaxIvds(struct Machine *m, uint32_t rde, int h) { +static void OpAluRaxIvds(struct Machine *m, uint32_t rde) { WriteRegister(rde, m->ax, - Alu(RegLog2(rde), h, ReadMemory(rde, m->ax), m->xedd->op.uimm0, - &m->flags)); + kAlu[(m->xedd->op.opcode & 070) >> 3][RegLog2(rde)]( + ReadMemory(rde, m->ax), m->xedd->op.uimm0, &m->flags)); } -static void OpCmpAlIb(struct Machine *m) { - Alu(0, ALU_SUB, Read8(m->ax), m->xedd->op.uimm0, &m->flags); +static void OpCmpAlIb(struct Machine *m, uint32_t rde) { + Sub8(Read8(m->ax), m->xedd->op.uimm0, &m->flags); } static void OpCmpRaxIvds(struct Machine *m, uint32_t rde) { - Alu(RegLog2(rde), ALU_SUB, ReadMemory(rde, m->ax), m->xedd->op.uimm0, - &m->flags); + kAlu[ALU_SUB][RegLog2(rde)](ReadMemory(rde, m->ax), m->xedd->op.uimm0, + &m->flags); } -static void OpTestAlIb(struct Machine *m) { - Alu(0, ALU_AND, Read8(m->ax), m->xedd->op.uimm0, &m->flags); +static void OpTestAlIb(struct Machine *m, uint32_t rde) { + And8(Read8(m->ax), m->xedd->op.uimm0, &m->flags); } static void OpTestRaxIvds(struct Machine *m, uint32_t rde) { - Alu(RegLog2(rde), ALU_AND, ReadMemory(rde, m->ax), m->xedd->op.uimm0, - &m->flags); + kAlu[ALU_AND][RegLog2(rde)](ReadMemory(rde, m->ax), m->xedd->op.uimm0, + &m->flags); } -long opcount[256 * 4]; +static void Bsuwi(struct Machine *m, uint32_t rde, uint64_t y) { + uint8_t *p; + p = GetModrmRegisterWordPointerWriteOszRexw(m, rde); + WriteRegisterOrMemory( + rde, p, + kBsu[ModrmReg(rde)][RegLog2(rde)](ReadMemory(rde, p), y, &m->flags)); +} -void ExecuteInstruction(struct Machine *m) { - uint32_t rde; - m->ip += m->xedd->length; - rde = m->xedd->op.rde; - opcount[m->xedd->op.map << 8 | m->xedd->op.opcode]++; - switch (m->xedd->op.map << 8 | m->xedd->op.opcode) { - CASE(0x089, OpMovEvqpGvqp(m, rde)); - CASE(0x083, OpAluwi(m, rde, ModrmReg(rde))); - CASR(0x070, if (GetCond(m, 0x0)) OpJmp(m)); - CASR(0x071, if (GetCond(m, 0x1)) OpJmp(m)); - CASR(0x072, if (GetCond(m, 0x2)) OpJmp(m)); - CASR(0x073, if (GetCond(m, 0x3)) OpJmp(m)); - CASR(0x074, if (GetCond(m, 0x4)) OpJmp(m)); - CASR(0x075, if (GetCond(m, 0x5)) OpJmp(m)); - CASR(0x076, if (GetCond(m, 0x6)) OpJmp(m)); - CASR(0x077, if (GetCond(m, 0x7)) OpJmp(m)); - CASR(0x078, if (GetCond(m, 0x8)) OpJmp(m)); - CASR(0x079, if (GetCond(m, 0x9)) OpJmp(m)); - CASR(0x07A, if (GetCond(m, 0xa)) OpJmp(m)); - CASR(0x07B, if (GetCond(m, 0xb)) OpJmp(m)); - CASR(0x07C, if (GetCond(m, 0xc)) OpJmp(m)); - CASR(0x07D, if (GetCond(m, 0xd)) OpJmp(m)); - CASR(0x07E, if (GetCond(m, 0xe)) OpJmp(m)); - CASR(0x07F, if (GetCond(m, 0xf)) OpJmp(m)); - CASR(0x0B0 ... 0x0B7, OpMovZbIb(m, rde)); - CASR(0x0B8 ... 0x0BF, OpMovZvqpIvqp(m, rde)); - CASR(0x050 ... 0x057, OpPushZvq(m, rde)); - CASR(0x058 ... 0x05F, OpPopZvq(m, rde)); - CASR(0x091 ... 0x097, OpXchgZvqp(m, rde)); - CASR(0x1C8 ... 0x1CF, OpBswapZvqp(m, rde)); - CASR(0x000, OpAlub(m, rde, ALU_ADD)); - CASE(0x001, OpAluw(m, rde, ALU_ADD)); - CASR(0x002, OpAlubFlip(m, rde, ALU_ADD)); - CASE(0x003, OpAluwFlip(m, rde, ALU_ADD)); - CASR(0x004, OpAluAlIb(m, ALU_ADD)); - CASR(0x005, OpAluRaxIvds(m, rde, ALU_ADD)); - CASR(0x008, OpAlub(m, rde, ALU_OR)); - CASE(0x009, OpAluw(m, rde, ALU_OR)); - CASR(0x00A, OpAlubFlip(m, rde, ALU_OR)); - CASE(0x00B, OpAluwFlip(m, rde, ALU_OR)); - CASR(0x00C, OpAluAlIb(m, ALU_OR)); - CASR(0x00D, OpAluRaxIvds(m, rde, ALU_OR)); - CASR(0x010, OpAlub(m, rde, ALU_ADC)); - CASE(0x011, OpAluw(m, rde, ALU_ADC)); - CASR(0x012, OpAlubFlip(m, rde, ALU_ADC)); - CASE(0x013, OpAluwFlip(m, rde, ALU_ADC)); - CASR(0x014, OpAluAlIb(m, ALU_ADC)); - CASR(0x015, OpAluRaxIvds(m, rde, ALU_ADC)); - CASR(0x018, OpAlub(m, rde, ALU_SBB)); - CASE(0x019, OpAluw(m, rde, ALU_SBB)); - CASR(0x01A, OpAlubFlip(m, rde, ALU_SBB)); - CASE(0x01B, OpAluwFlip(m, rde, ALU_SBB)); - CASR(0x01C, OpAluAlIb(m, ALU_SBB)); - CASR(0x01D, OpAluRaxIvds(m, rde, ALU_SBB)); - CASR(0x020, OpAlub(m, rde, ALU_AND)); - CASE(0x021, OpAluw(m, rde, ALU_AND)); - CASR(0x022, OpAlubFlip(m, rde, ALU_AND)); - CASE(0x023, OpAluwFlip(m, rde, ALU_AND)); - CASR(0x024, OpAluAlIb(m, ALU_AND)); - CASR(0x025, OpAluRaxIvds(m, rde, ALU_AND)); - CASR(0x028, OpAlub(m, rde, ALU_SUB)); - CASE(0x029, OpAluw(m, rde, ALU_SUB)); - CASR(0x02A, OpAlubFlip(m, rde, ALU_SUB)); - CASE(0x02B, OpAluwFlip(m, rde, ALU_SUB)); - CASR(0x02C, OpAluAlIb(m, ALU_SUB)); - CASR(0x02D, OpAluRaxIvds(m, rde, ALU_SUB)); - CASR(0x030, OpAlub(m, rde, ALU_XOR)); - CASE(0x031, OpAluw(m, rde, ALU_XOR)); - CASR(0x032, OpAlubFlip(m, rde, ALU_XOR)); - CASE(0x033, OpAluwFlip(m, rde, ALU_XOR)); - CASR(0x034, OpAluAlIb(m, ALU_XOR)); - CASR(0x035, OpAluRaxIvds(m, rde, ALU_XOR)); - CASR(0x038, OpAlubRo(m, rde, ALU_CMP)); - CASE(0x039, OpAluwRo(m, rde, ALU_CMP)); - CASR(0x03A, OpAlubFlipRo(m, rde, ALU_CMP)); - CASE(0x03B, OpAluwFlipRo(m, rde, ALU_CMP)); - CASR(0x03C, OpCmpAlIb(m)); - CASR(0x03D, OpCmpRaxIvds(m, rde)); - CASE(0x063, OpMovsxdGdqpEd(m, rde)); - CASE(0x068, PushOsz(m, rde, m->xedd->op.uimm0)); - CASE(0x069, OpImulGvqpEvqpImm(m, rde)); - CASE(0x06A, PushOsz(m, rde, m->xedd->op.uimm0)); - CASE(0x06B, OpImulGvqpEvqpImm(m, rde)); - CASE(0x06C, OpString(m, rde, STRING_INS)); - CASE(0x06D, OpString(m, rde, STRING_INS)); - CASE(0x06E, OpString(m, rde, STRING_OUTS)); - CASE(0x06F, OpString(m, rde, STRING_OUTS)); - CASR(0x080, OpAlubi(m, rde, ModrmReg(rde))); - CASE(0x081, OpAluwi(m, rde, ModrmReg(rde))); - CASR(0x082, OpAlubi(m, rde, ModrmReg(rde))); - CASR(0x084, OpAlubRo(m, rde, TEST)); - CASE(0x085, OpAluwRo(m, rde, TEST)); - CASE(0x086, OpXchgGbEb(m, rde)); - CASE(0x087, OpXchgGvqpEvqp(m, rde)); - CASE(0x088, OpMovEbGb(m, rde)); - CASE(0x08A, OpMovGbEb(m, rde)); - CASE(0x08B, OpMovGvqpEvqp(m, rde)); - CASE(0x08C, OpMovEvqpSw(m)); - CASE(0x08D, OpLeaGvqpM(m, rde)); - CASE(0x08E, OpMovSwEvqp(m)); - CASE(0x08F, OpPopEvq(m, rde)); - CASE(0x090, OpNop(m, rde)); - CASE(0x098, OpConvert1(m, rde)); - CASE(0x099, OpConvert2(m, rde)); - CASE(0x09C, OpPushf(m, rde)); - CASE(0x09D, OpPopf(m, rde)); - CASE(0x09E, OpSahf(m)); - CASE(0x09F, OpLahf(m)); - CASE(0x09B, OpFwait(m)); - CASE(0x0A0, OpMovAlOb(m)); - CASE(0x0A1, OpMovRaxOvqp(m, rde)); - CASE(0x0A2, OpMovObAl(m)); - CASE(0x0A3, OpMovOvqpRax(m, rde)); - CASE(0x0A4, OpMovsb(m, rde)); - CASE(0x0A5, OpString(m, rde, STRING_MOVS)); - CASE(0x0A6, OpString(m, rde, STRING_CMPS)); - CASE(0x0A7, OpString(m, rde, STRING_CMPS)); - CASE(0x0A8, OpTestAlIb(m)); - CASE(0x0A9, OpTestRaxIvds(m, rde)); - CASE(0x0AA, OpStosb(m, rde)); - CASE(0x0AB, OpString(m, rde, STRING_STOS)); - CASE(0x0AC, OpString(m, rde, STRING_LODS)); - CASE(0x0AD, OpString(m, rde, STRING_LODS)); - CASE(0x0AE, OpString(m, rde, STRING_SCAS)); - CASE(0x0AF, OpString(m, rde, STRING_SCAS)); - CASR(0x0C0, OpBsubi(m, rde, ModrmReg(rde), m->xedd->op.uimm0)); - CASR(0x0C1, OpBsuwi(m, rde, ModrmReg(rde), m->xedd->op.uimm0)); - CASE(0x0C2, OpRet(m, m->xedd->op.uimm0)); - CASE(0x0C3, OpRet(m, 0)); - CASE(0x0C6, OpMovEbIb(m, rde)); - CASE(0x0C7, OpMovEvqpIvds(m, rde)); - CASE(0x0C9, OpLeave(m)); - CASE(0x0CC, OpInterrupt(m, 3)); - CASE(0x0CD, OpInterrupt(m, m->xedd->op.uimm0)); - CASR(0x0D0, OpBsubi(m, rde, ModrmReg(rde), 1)); - CASR(0x0D1, OpBsuwi(m, rde, ModrmReg(rde), 1)); - CASR(0x0D2, OpBsubi(m, rde, ModrmReg(rde), m->cx[0])); - CASR(0x0D3, OpBsuwi(m, rde, ModrmReg(rde), m->cx[0])); - CASE(0x0D7, OpXlat(m, rde)); - CASE(0x0E0, OpLoop(m, rde, !GetFlag(m->flags, FLAGS_ZF))); - CASE(0x0E1, OpLoop(m, rde, GetFlag(m->flags, FLAGS_ZF))); - CASE(0x0E2, OpLoop(m, rde, 1)); - CASE(0x0E3, OpJcxz(m, rde)); - CASE(0x0E4, Write8(m->ax, OpIn(m, m->xedd->op.uimm0))); - CASE(0x0E5, Write32(m->ax, OpIn(m, m->xedd->op.uimm0))); - CASE(0x0E6, OpOut(m, m->xedd->op.uimm0, Read8(m->ax))); - CASE(0x0E7, OpOut(m, m->xedd->op.uimm0, Read32(m->ax))); - CASE(0x0E8, OpCallJvds(m)); - CASE(0x0E9, OpJmp(m)); - CASE(0x0EB, OpJmp(m)); - CASE(0x0EC, Write8(m->ax, OpIn(m, Read16(m->dx)))); - CASE(0x0ED, Write32(m->ax, OpIn(m, Read16(m->dx)))); - CASE(0x0EE, OpOut(m, Read16(m->dx), Read8(m->ax))); - CASE(0x0EF, OpOut(m, Read16(m->dx), Read32(m->ax))); - CASE(0x0F1, OpInterrupt(m, 1)); - CASE(0x0F4, OpHlt(m)); - CASE(0x0F5, OpCmc(m)); - CASE(0x0F8, OpClc(m)); - CASE(0x0F9, OpStc(m)); - CASE(0x0FA, OpCli(m)); - CASE(0x0FB, OpSti(m)); - CASE(0x0FC, OpCld(m)); - CASE(0x0FD, OpStd(m)); - CASE(0x105, OpSyscall(m)); - CASE(0x110, OpMov0f10(m, rde)); - CASE(0x111, OpMovWpsVps(m, rde)); - CASE(0x112, OpMov0f12(m, rde)); - CASE(0x113, OpMov0f13(m, rde)); - CASE(0x114, OpUnpcklpsd(m, rde)); - CASE(0x115, OpUnpckhpsd(m, rde)); - CASE(0x116, OpMov0f16(m, rde)); - CASE(0x117, OpMov0f17(m, rde)); - CASE(0x128, OpMov0f28(m, rde)); - CASE(0x129, OpMovWpsVps(m, rde)); - CASE(0x12A, OpCvt(m, rde, kOpCvt0f2a)); - CASE(0x12B, OpMov0f2b(m, rde)); - CASE(0x12C, OpCvt(m, rde, kOpCvtt0f2c)); - CASE(0x12D, OpCvt(m, rde, kOpCvt0f2d)); - CASE(0x12E, OpComissVsWs(m, rde)); - CASE(0x12F, OpComissVsWs(m, rde)); - CASE(0x131, OpRdtsc(m)); - CASE(0x140, if (GetCond(m, 0x0)) OpMovGvqpEvqp(m, rde)); - CASE(0x141, if (GetCond(m, 0x1)) OpMovGvqpEvqp(m, rde)); - CASE(0x142, if (GetCond(m, 0x2)) OpMovGvqpEvqp(m, rde)); - CASE(0x143, if (GetCond(m, 0x3)) OpMovGvqpEvqp(m, rde)); - CASE(0x144, if (GetCond(m, 0x4)) OpMovGvqpEvqp(m, rde)); - CASE(0x145, if (GetCond(m, 0x5)) OpMovGvqpEvqp(m, rde)); - CASE(0x146, if (GetCond(m, 0x6)) OpMovGvqpEvqp(m, rde)); - CASE(0x147, if (GetCond(m, 0x7)) OpMovGvqpEvqp(m, rde)); - CASE(0x148, if (GetCond(m, 0x8)) OpMovGvqpEvqp(m, rde)); - CASE(0x149, if (GetCond(m, 0x9)) OpMovGvqpEvqp(m, rde)); - CASE(0x14A, if (GetCond(m, 0xa)) OpMovGvqpEvqp(m, rde)); - CASE(0x14B, if (GetCond(m, 0xb)) OpMovGvqpEvqp(m, rde)); - CASE(0x14C, if (GetCond(m, 0xc)) OpMovGvqpEvqp(m, rde)); - CASE(0x14D, if (GetCond(m, 0xd)) OpMovGvqpEvqp(m, rde)); - CASE(0x14E, if (GetCond(m, 0xe)) OpMovGvqpEvqp(m, rde)); - CASE(0x14F, if (GetCond(m, 0xf)) OpMovGvqpEvqp(m, rde)); - CASE(0x151, OpSqrtpsd(m, rde)); - CASE(0x152, OpRsqrtps(m, rde)); - CASE(0x153, OpRcpps(m, rde)); - CASE(0x154, OpAndpsd(m, rde)); - CASE(0x155, OpAndnpsd(m, rde)); - CASE(0x156, OpOrpsd(m, rde)); - CASE(0x157, OpXorpsd(m, rde)); - CASE(0x158, OpAddpsd(m, rde)); - CASE(0x159, OpMulpsd(m, rde)); - CASE(0x15A, OpCvt(m, rde, kOpCvt0f5a)); - CASE(0x15B, OpCvt(m, rde, kOpCvt0f5b)); - CASE(0x15C, OpSubpsd(m, rde)); - CASE(0x15D, OpMinpsd(m, rde)); - CASE(0x15E, OpDivpsd(m, rde)); - CASE(0x15F, OpMaxpsd(m, rde)); - CASR(0x160, OpSse(m, rde, kOpSsePunpcklbw)); - CASR(0x161, OpSse(m, rde, kOpSsePunpcklwd)); - CASR(0x162, OpSse(m, rde, kOpSsePunpckldq)); - CASR(0x163, OpSse(m, rde, kOpSsePacksswb)); - CASR(0x164, OpSse(m, rde, kOpSsePcmpgtb)); - CASR(0x165, OpSse(m, rde, kOpSsePcmpgtw)); - CASR(0x166, OpSse(m, rde, kOpSsePcmpgtd)); - CASR(0x167, OpSse(m, rde, kOpSsePackuswb)); - CASR(0x168, OpSse(m, rde, kOpSsePunpckhbw)); - CASR(0x169, OpSse(m, rde, kOpSsePunpckhwd)); - CASR(0x16A, OpSse(m, rde, kOpSsePunpckhdq)); - CASR(0x16B, OpSse(m, rde, kOpSsePackssdw)); - CASR(0x16C, OpSse(m, rde, kOpSsePunpcklqdq)); - CASR(0x16D, OpSse(m, rde, kOpSsePunpckhqdq)); - CASE(0x16E, OpMov0f6e(m, rde)); - CASE(0x16F, OpMov0f6f(m, rde)); - CASE(0x170, OpShuffle(m, rde)); - CASR(0x174, OpSse(m, rde, kOpSsePcmpeqb)); - CASR(0x175, OpSse(m, rde, kOpSsePcmpeqw)); - CASR(0x176, OpSse(m, rde, kOpSsePcmpeqd)); - CASE(0x17C, OpHaddpsd(m, rde)); - CASE(0x17D, OpHsubpsd(m, rde)); - CASE(0x17E, OpMov0f7e(m, rde)); - CASE(0x17F, OpMov0f7f(m, rde)); - CASE(0x180, if (GetCond(m, 0x0)) OpJmp(m)); - CASE(0x181, if (GetCond(m, 0x1)) OpJmp(m)); - CASE(0x182, if (GetCond(m, 0x2)) OpJmp(m)); - CASE(0x183, if (GetCond(m, 0x3)) OpJmp(m)); - CASE(0x184, if (GetCond(m, 0x4)) OpJmp(m)); - CASE(0x185, if (GetCond(m, 0x5)) OpJmp(m)); - CASE(0x186, if (GetCond(m, 0x6)) OpJmp(m)); - CASE(0x187, if (GetCond(m, 0x7)) OpJmp(m)); - CASE(0x188, if (GetCond(m, 0x8)) OpJmp(m)); - CASE(0x189, if (GetCond(m, 0x9)) OpJmp(m)); - CASE(0x18A, if (GetCond(m, 0xa)) OpJmp(m)); - CASE(0x18B, if (GetCond(m, 0xb)) OpJmp(m)); - CASE(0x18C, if (GetCond(m, 0xc)) OpJmp(m)); - CASE(0x18D, if (GetCond(m, 0xd)) OpJmp(m)); - CASE(0x18E, if (GetCond(m, 0xe)) OpJmp(m)); - CASE(0x18F, if (GetCond(m, 0xf)) OpJmp(m)); - CASE(0x190, OpEbSetCc(m, rde, GetCond(m, 0x0))); - CASE(0x191, OpEbSetCc(m, rde, GetCond(m, 0x1))); - CASE(0x192, OpEbSetCc(m, rde, GetCond(m, 0x2))); - CASE(0x193, OpEbSetCc(m, rde, GetCond(m, 0x3))); - CASE(0x194, OpEbSetCc(m, rde, GetCond(m, 0x4))); - CASE(0x195, OpEbSetCc(m, rde, GetCond(m, 0x5))); - CASE(0x196, OpEbSetCc(m, rde, GetCond(m, 0x6))); - CASE(0x197, OpEbSetCc(m, rde, GetCond(m, 0x7))); - CASE(0x198, OpEbSetCc(m, rde, GetCond(m, 0x8))); - CASE(0x199, OpEbSetCc(m, rde, GetCond(m, 0x9))); - CASE(0x19A, OpEbSetCc(m, rde, GetCond(m, 0xa))); - CASE(0x19B, OpEbSetCc(m, rde, GetCond(m, 0xb))); - CASE(0x19C, OpEbSetCc(m, rde, GetCond(m, 0xc))); - CASE(0x19D, OpEbSetCc(m, rde, GetCond(m, 0xd))); - CASE(0x19E, OpEbSetCc(m, rde, GetCond(m, 0xe))); - CASE(0x19F, OpEbSetCc(m, rde, GetCond(m, 0xf))); - CASE(0x1A0, OpPushFs(m)); - CASE(0x1A1, OpPopFs(m)); - CASE(0x1A2, OpCpuid(m)); - CASE(0x1A3, OpBit(m, rde)); - CASE(0x1A8, OpPushGs(m)); - CASE(0x1A9, OpPopGs(m)); - CASE(0x1AB, OpBit(m, rde)); - CASE(0x1AF, OpImulGvqpEvqp(m, rde)); - CASE(0x1B0, OpCmpxchgEbAlGb(m, rde)); - CASE(0x1B1, OpCmpxchgEvqpRaxGvqp(m, rde)); - CASE(0x1B3, OpBit(m, rde)); - CASE(0x1B6, OpMovzbGvqpEb(m, rde)); - CASE(0x1B7, OpMovzwGvqpEw(m, rde)); - CASE(0x1BA, OpBit(m, rde)); - CASE(0x1BB, OpBit(m, rde)); - CASE(0x1BC, OpGvqpEvqp(m, rde, AluBsf, MUTATING)); - CASE(0x1BD, OpGvqpEvqp(m, rde, AluBsr, MUTATING)); - CASE(0x1BE, OpMovsbGvqpEb(m, rde)); - CASE(0x1BF, OpMovswGvqpEw(m, rde)); - CASE(0x1C0, OpXaddEbGb(m, rde)); - CASE(0x1C1, OpXaddEvqpGvqp(m, rde)); - CASE(0x1C2, OpCmppsd(m, rde)); - CASE(0x1C3, OpMovntiMdqpGdqp(m, rde)); - CASE(0x1C4, OpPinsrwVdqEwIb(m, rde)); - CASE(0x1C5, OpPextrwGdqpUdqIb(m, rde)); - CASE(0x1C6, OpShufpsd(m, rde)); - CASE(0x1C7, OpCmpxchgDxAx(m, rde)); - CASE(0x1D0, OpAddsubpsd(m, rde)); - CASR(0x1D1, OpSse(m, rde, kOpSsePsrlwv)); - CASR(0x1D2, OpSse(m, rde, kOpSsePsrldv)); - CASR(0x1D3, OpSse(m, rde, kOpSsePsrlqv)); - CASR(0x1D4, OpSse(m, rde, kOpSsePaddq)); - CASR(0x1D5, OpSse(m, rde, kOpSsePmullw)); - CASE(0x1D6, OpMov0fD6(m, rde)); - CASE(0x1D7, OpPmovmskbGdqpNqUdq(m, rde)); - CASR(0x1D8, OpSse(m, rde, kOpSsePsubusb)); - CASR(0x1D9, OpSse(m, rde, kOpSsePsubusw)); - CASR(0x1DA, OpSse(m, rde, kOpSsePminub)); - CASR(0x1DB, OpSse(m, rde, kOpSsePand)); - CASR(0x1DC, OpSse(m, rde, kOpSsePaddusb)); - CASR(0x1DD, OpSse(m, rde, kOpSsePaddusw)); - CASR(0x1DE, OpSse(m, rde, kOpSsePmaxub)); - CASR(0x1DF, OpSse(m, rde, kOpSsePandn)); - CASR(0x1E0, OpSse(m, rde, kOpSsePavgb)); - CASR(0x1E1, OpSse(m, rde, kOpSsePsrawv)); - CASR(0x1E2, OpSse(m, rde, kOpSsePsradv)); - CASR(0x1E3, OpSse(m, rde, kOpSsePavgw)); - CASR(0x1E4, OpSse(m, rde, kOpSsePmulhuw)); - CASR(0x1E5, OpSse(m, rde, kOpSsePmulhw)); - CASE(0x1E6, OpCvt(m, rde, kOpCvt0fE6)); - CASE(0x1E7, OpMov0fE7(m, rde)); - CASR(0x1E8, OpSse(m, rde, kOpSsePsubsb)); - CASR(0x1E9, OpSse(m, rde, kOpSsePsubsw)); - CASR(0x1EA, OpSse(m, rde, kOpSsePminsw)); - CASR(0x1EB, OpSse(m, rde, kOpSsePor)); - CASR(0x1EC, OpSse(m, rde, kOpSsePaddsb)); - CASR(0x1ED, OpSse(m, rde, kOpSsePaddsw)); - CASR(0x1EE, OpSse(m, rde, kOpSsePmaxsw)); - CASR(0x1EF, OpSse(m, rde, kOpSsePxor)); - CASE(0x1F0, OpLddquVdqMdq(m, rde)); - CASR(0x1F1, OpSse(m, rde, kOpSsePsllwv)); - CASR(0x1F2, OpSse(m, rde, kOpSsePslldv)); - CASR(0x1F3, OpSse(m, rde, kOpSsePsllqv)); - CASR(0x1F4, OpSse(m, rde, kOpSsePmuludq)); - CASR(0x1F5, OpSse(m, rde, kOpSsePmaddwd)); - CASR(0x1F6, OpSse(m, rde, kOpSsePsadbw)); - CASE(0x1F7, OpMaskMovDiXmmRegXmmRm(m, rde)); - CASR(0x1F8, OpSse(m, rde, kOpSsePsubb)); - CASR(0x1F9, OpSse(m, rde, kOpSsePsubw)); - CASR(0x1FA, OpSse(m, rde, kOpSsePsubd)); - CASR(0x1FB, OpSse(m, rde, kOpSsePsubq)); - CASR(0x1FC, OpSse(m, rde, kOpSsePaddb)); - CASR(0x1FD, OpSse(m, rde, kOpSsePaddw)); - CASR(0x1FE, OpSse(m, rde, kOpSsePaddd)); - CASR(0x200, OpSse(m, rde, kOpSsePshufb)); - CASR(0x201, OpSse(m, rde, kOpSsePhaddw)); - CASR(0x202, OpSse(m, rde, kOpSsePhaddd)); - CASR(0x203, OpSse(m, rde, kOpSsePhaddsw)); - CASR(0x204, OpSse(m, rde, kOpSsePmaddubsw)); - CASR(0x205, OpSse(m, rde, kOpSsePhsubw)); - CASR(0x206, OpSse(m, rde, kOpSsePhsubd)); - CASR(0x207, OpSse(m, rde, kOpSsePhsubsw)); - CASR(0x208, OpSse(m, rde, kOpSsePsignb)); - CASR(0x209, OpSse(m, rde, kOpSsePsignw)); - CASR(0x20A, OpSse(m, rde, kOpSsePsignd)); - CASR(0x20B, OpSse(m, rde, kOpSsePmulhrsw)); - CASR(0x21C, OpSse(m, rde, kOpSsePabsb)); - CASR(0x21D, OpSse(m, rde, kOpSsePabsw)); - CASR(0x21E, OpSse(m, rde, kOpSsePabsd)); - CASE(0x22A, OpMovntdqaVdqMdq(m, rde)); - CASR(0x240, OpSse(m, rde, kOpSsePmulld)); - CASE(0x30F, OpSsePalignr(m, rde)); - case 0xD8: - case 0xD9: - case 0xDA: - case 0xDB: - case 0xDC: - case 0xDD: - case 0xDE: - case 0xDF: - OpFpu(m); +static void OpBsuwi1(struct Machine *m, uint32_t rde) { + Bsuwi(m, rde, 1); +} + +static void OpBsuwiCl(struct Machine *m, uint32_t rde) { + Bsuwi(m, rde, Read8(m->cx)); +} + +static void OpBsuwiImm(struct Machine *m, uint32_t rde) { + Bsuwi(m, rde, m->xedd->op.uimm0); +} + +static void Bsubi(struct Machine *m, uint32_t rde, uint64_t y) { + uint8_t *a = GetModrmRegisterBytePointerWrite(m, rde); + Write8(a, kBsu[ModrmReg(rde)][RegLog2(rde)](Read8(a), y, &m->flags)); +} + +static void OpBsubi1(struct Machine *m, uint32_t rde) { + Bsubi(m, rde, 1); +} + +static void OpBsubiCl(struct Machine *m, uint32_t rde) { + Bsubi(m, rde, Read8(m->cx)); +} + +static void OpBsubiImm(struct Machine *m, uint32_t rde) { + Bsubi(m, rde, m->xedd->op.uimm0); +} + +static void LoadFarPointer(struct Machine *m, uint32_t rde, uint8_t seg[8]) { + uint32_t fp; + fp = Read32(ComputeReserveAddressRead4(m, rde)); + Write64(seg, (fp & 0x0000ffff) << 4); + Write16(RegRexrReg(m, rde), fp >> 16); +} + +static void OpLes(struct Machine *m, uint32_t rde) { + LoadFarPointer(m, rde, m->es); +} + +static void OpLds(struct Machine *m, uint32_t rde) { + LoadFarPointer(m, rde, m->ds); +} + +static void OpLgdtMs(struct Machine *m, uint32_t rde) { +} + +static void OpPushImm(struct Machine *m, uint32_t rde) { + Push(m, rde, m->xedd->op.uimm0); +} + +static void OpRet0(struct Machine *m, uint32_t rde) { + OpRet(m, rde, 0); +} + +static void OpRetImm(struct Machine *m, uint32_t rde) { + OpRet(m, rde, m->xedd->op.uimm0); +} + +static void Interrupt(struct Machine *m, uint32_t rde, int i) { + HaltMachine(m, i); +} + +static void OpInterruptImm(struct Machine *m, uint32_t rde) { + Interrupt(m, rde, m->xedd->op.uimm0); +} + +static void OpInterrupt1(struct Machine *m, uint32_t rde) { + Interrupt(m, rde, 1); +} + +static void OpInterrupt3(struct Machine *m, uint32_t rde) { + Interrupt(m, rde, 3); +} + +static void OpJmp(struct Machine *m, uint32_t rde) { + m->ip += m->xedd->op.disp; +} + +static void OpJe(struct Machine *m, uint32_t rde) { + if (GetFlag(m->flags, FLAGS_ZF)) { + OpJmp(m, rde); + } +} + +static void OpJne(struct Machine *m, uint32_t rde) { + if (!GetFlag(m->flags, FLAGS_ZF)) { + OpJmp(m, rde); + } +} + +static void OpJb(struct Machine *m, uint32_t rde) { + if (GetFlag(m->flags, FLAGS_CF)) { + OpJmp(m, rde); + } +} + +static void OpJbe(struct Machine *m, uint32_t rde) { + if (IsBelowOrEqual(m)) { + OpJmp(m, rde); + } +} + +static void OpJo(struct Machine *m, uint32_t rde) { + if (GetFlag(m->flags, FLAGS_OF)) { + OpJmp(m, rde); + } +} + +static void OpJno(struct Machine *m, uint32_t rde) { + if (!GetFlag(m->flags, FLAGS_OF)) { + OpJmp(m, rde); + } +} + +static void OpJae(struct Machine *m, uint32_t rde) { + if (!GetFlag(m->flags, FLAGS_CF)) { + OpJmp(m, rde); + } +} + +static void OpJa(struct Machine *m, uint32_t rde) { + if (IsAbove(m)) { + OpJmp(m, rde); + } +} + +static void OpJs(struct Machine *m, uint32_t rde) { + if (GetFlag(m->flags, FLAGS_SF)) { + OpJmp(m, rde); + } +} + +static void OpJns(struct Machine *m, uint32_t rde) { + if (!GetFlag(m->flags, FLAGS_SF)) { + OpJmp(m, rde); + } +} + +static void OpJp(struct Machine *m, uint32_t rde) { + if (IsParity(m)) { + OpJmp(m, rde); + } +} + +static void OpJnp(struct Machine *m, uint32_t rde) { + if (!IsParity(m)) { + OpJmp(m, rde); + } +} + +static void OpJl(struct Machine *m, uint32_t rde) { + if (IsLess(m)) { + OpJmp(m, rde); + } +} + +static void OpJge(struct Machine *m, uint32_t rde) { + if (IsGreaterOrEqual(m)) { + OpJmp(m, rde); + } +} + +static void OpJle(struct Machine *m, uint32_t rde) { + if (IsLessOrEqual(m)) { + OpJmp(m, rde); + } +} + +static void OpJg(struct Machine *m, uint32_t rde) { + if (IsGreater(m)) { + OpJmp(m, rde); + } +} + +static void OpMovGvqpEvqp(struct Machine *m, uint32_t rde) { + WriteRegister( + rde, RegRexrReg(m, rde), + ReadMemory(rde, GetModrmRegisterWordPointerReadOszRexw(m, rde))); +} + +static void OpCmovo(struct Machine *m, uint32_t rde) { + if (GetFlag(m->flags, FLAGS_OF)) { + OpMovGvqpEvqp(m, rde); + } +} + +static void OpCmovno(struct Machine *m, uint32_t rde) { + if (!GetFlag(m->flags, FLAGS_OF)) { + OpMovGvqpEvqp(m, rde); + } +} + +static void OpCmovb(struct Machine *m, uint32_t rde) { + if (GetFlag(m->flags, FLAGS_CF)) { + OpMovGvqpEvqp(m, rde); + } +} + +static void OpCmovae(struct Machine *m, uint32_t rde) { + if (!GetFlag(m->flags, FLAGS_CF)) { + OpMovGvqpEvqp(m, rde); + } +} + +static void OpCmove(struct Machine *m, uint32_t rde) { + if (GetFlag(m->flags, FLAGS_ZF)) { + OpMovGvqpEvqp(m, rde); + } +} + +static void OpCmovne(struct Machine *m, uint32_t rde) { + if (!GetFlag(m->flags, FLAGS_ZF)) { + OpMovGvqpEvqp(m, rde); + } +} + +static void OpCmovbe(struct Machine *m, uint32_t rde) { + if (IsBelowOrEqual(m)) { + OpMovGvqpEvqp(m, rde); + } +} + +static void OpCmova(struct Machine *m, uint32_t rde) { + if (IsAbove(m)) { + OpMovGvqpEvqp(m, rde); + } +} + +static void OpCmovs(struct Machine *m, uint32_t rde) { + if (GetFlag(m->flags, FLAGS_SF)) { + OpMovGvqpEvqp(m, rde); + } +} + +static void OpCmovns(struct Machine *m, uint32_t rde) { + if (!GetFlag(m->flags, FLAGS_SF)) { + OpMovGvqpEvqp(m, rde); + } +} + +static void OpCmovp(struct Machine *m, uint32_t rde) { + if (IsParity(m)) { + OpMovGvqpEvqp(m, rde); + } +} + +static void OpCmovnp(struct Machine *m, uint32_t rde) { + if (!IsParity(m)) { + OpMovGvqpEvqp(m, rde); + } +} + +static void OpCmovl(struct Machine *m, uint32_t rde) { + if (IsLess(m)) { + OpMovGvqpEvqp(m, rde); + } +} + +static void OpCmovge(struct Machine *m, uint32_t rde) { + if (IsGreaterOrEqual(m)) { + OpMovGvqpEvqp(m, rde); + } +} + +static void OpCmovle(struct Machine *m, uint32_t rde) { + if (IsLessOrEqual(m)) { + OpMovGvqpEvqp(m, rde); + } +} + +static void OpCmovg(struct Machine *m, uint32_t rde) { + if (IsGreater(m)) { + OpMovGvqpEvqp(m, rde); + } +} + +static void SetEb(struct Machine *m, uint32_t rde, bool x) { + Write8(GetModrmRegisterBytePointerWrite(m, rde), x); +} + +static void OpSeto(struct Machine *m, uint32_t rde) { + SetEb(m, rde, GetFlag(m->flags, FLAGS_OF)); +} + +static void OpSetno(struct Machine *m, uint32_t rde) { + SetEb(m, rde, !GetFlag(m->flags, FLAGS_OF)); +} + +static void OpSetb(struct Machine *m, uint32_t rde) { + SetEb(m, rde, GetFlag(m->flags, FLAGS_CF)); +} + +static void OpSetae(struct Machine *m, uint32_t rde) { + SetEb(m, rde, !GetFlag(m->flags, FLAGS_CF)); +} + +static void OpSete(struct Machine *m, uint32_t rde) { + SetEb(m, rde, GetFlag(m->flags, FLAGS_ZF)); +} + +static void OpSetne(struct Machine *m, uint32_t rde) { + SetEb(m, rde, !GetFlag(m->flags, FLAGS_ZF)); +} + +static void OpSetbe(struct Machine *m, uint32_t rde) { + SetEb(m, rde, IsBelowOrEqual(m)); +} + +static void OpSeta(struct Machine *m, uint32_t rde) { + SetEb(m, rde, IsAbove(m)); +} + +static void OpSets(struct Machine *m, uint32_t rde) { + SetEb(m, rde, GetFlag(m->flags, FLAGS_SF)); +} + +static void OpSetns(struct Machine *m, uint32_t rde) { + SetEb(m, rde, !GetFlag(m->flags, FLAGS_SF)); +} + +static void OpSetp(struct Machine *m, uint32_t rde) { + SetEb(m, rde, IsParity(m)); +} + +static void OpSetnp(struct Machine *m, uint32_t rde) { + SetEb(m, rde, !IsParity(m)); +} + +static void OpSetl(struct Machine *m, uint32_t rde) { + SetEb(m, rde, IsLess(m)); +} + +static void OpSetge(struct Machine *m, uint32_t rde) { + SetEb(m, rde, IsGreaterOrEqual(m)); +} + +static void OpSetle(struct Machine *m, uint32_t rde) { + SetEb(m, rde, IsLessOrEqual(m)); +} + +static void OpSetg(struct Machine *m, uint32_t rde) { + SetEb(m, rde, IsGreater(m)); +} + +static void OpJcxz(struct Machine *m, uint32_t rde) { + if (!MaskAddress(Eamode(rde), Read64(m->cx))) { + OpJmp(m, rde); + } +} + +static void Loop(struct Machine *m, uint32_t rde, bool cond) { + uint64_t cx; + cx = Read64(m->cx) - 1; + if (Eamode(rde) != XED_MODE_REAL) { + if (Eamode(rde) == XED_MODE_LEGACY) { + cx &= 0xffffffff; + } + Write64(m->cx, cx); + } else { + cx &= 0xffff; + Write16(m->cx, cx); + } + if (cx && cond) { + OpJmp(m, rde); + } +} + +static void OpLoope(struct Machine *m, uint32_t rde) { + Loop(m, rde, GetFlag(m->flags, FLAGS_ZF)); +} + +static void OpLoopne(struct Machine *m, uint32_t rde) { + Loop(m, rde, !GetFlag(m->flags, FLAGS_ZF)); +} + +static void OpLoop1(struct Machine *m, uint32_t rde) { + Loop(m, rde, true); +} + +static void Bitscan(struct Machine *m, uint32_t rde, bitscan_f op) { + WriteRegister( + rde, RegRexrReg(m, rde), + op(m, rde, + ReadMemory(rde, GetModrmRegisterWordPointerReadOszRexw(m, rde)))); +} + +static void OpBsf(struct Machine *m, uint32_t rde) { + Bitscan(m, rde, AluBsf); +} + +static void OpBsr(struct Machine *m, uint32_t rde) { + Bitscan(m, rde, AluBsr); +} + +static void Op1b8(struct Machine *m, uint32_t rde) { + if (Rep(rde) == 3) { + Bitscan(m, rde, AluPopcnt); + } else { + OpUd(m, rde); + } +} + +static void OpNotEb(struct Machine *m, uint32_t rde) { + AluEb(m, rde, Not8); +} + +static void OpNegEb(struct Machine *m, uint32_t rde) { + AluEb(m, rde, Neg8); +} + +static void Op0f6(struct Machine *m, uint32_t rde) { + static const nexgen32e_f kOp0f6[] = { + OpAlubiTest, + OpAlubiTest, + OpNotEb, + OpNegEb, + OpMulAxAlEbUnsigned, + OpMulAxAlEbSigned, + OpDivAlAhAxEbUnsigned, + OpDivAlAhAxEbSigned, + }; + kOp0f6[ModrmReg(rde)](m, rde); +} + +static void OpTestEvqpIvds(struct Machine *m, uint32_t rde) { + AluwiRo(m, rde, kAlu[ALU_AND]); +} + +static void OpNotEvqp(struct Machine *m, uint32_t rde) { + AluEvqp(m, rde, kAlu[ALU_NOT]); +} + +static void OpNegEvqp(struct Machine *m, uint32_t rde) { + AluEvqp(m, rde, kAlu[ALU_NEG]); +} + +static void Op0f7(struct Machine *m, uint32_t rde) { + static const nexgen32e_f kOp0f7[] = { + OpTestEvqpIvds, + OpTestEvqpIvds, + OpNotEvqp, + OpNegEvqp, + OpMulRdxRaxEvqpUnsigned, + OpMulRdxRaxEvqpSigned, + OpDivRdxRaxEvqpUnsigned, + OpDivRdxRaxEvqpSigned, + }; + kOp0f7[ModrmReg(rde)](m, rde); +} + +static void Op0fe(struct Machine *m, uint32_t rde) { + switch (ModrmReg(rde)) { + case 0: + AluEb(m, rde, Inc8); break; - case 0xF6: - switch (ModrmReg(rde)) { - CASR(0, OpAlubiRo(m, rde, TEST)); - CASR(1, OpAlubiRo(m, rde, TEST)); - CASR(2, OpEb(m, rde, AluNot)); - CASR(3, OpEb(m, rde, AluNeg)); - CASE(4, OpMulAxAlEbUnsigned(m, rde)); - CASE(5, OpMulAxAlEbSigned(m, rde)); - CASE(6, OpDivAlAhAxEbUnsigned(m, rde)); - CASE(7, OpDivAlAhAxEbSigned(m, rde)); - default: - unreachable; - } + case 1: + AluEb(m, rde, Dec8); break; - case 0xF7: - switch (ModrmReg(rde)) { - CASE(0, OpAluwiRo(m, rde, TEST)); - CASE(1, OpAluwiRo(m, rde, TEST)); - CASE(2, OpEvqp(m, rde, AluNot)); - CASE(3, OpEvqp(m, rde, AluNeg)); - CASE(4, OpMulRdxRaxEvqpUnsigned(m, rde)); - CASE(5, OpMulRdxRaxEvqpSigned(m, rde)); - CASE(6, OpDivRdxRaxEvqpUnsigned(m, rde)); - CASE(7, OpDivRdxRaxEvqpSigned(m, rde)); - default: - unreachable; - } + default: + OpUd(m, rde); + } +} + +static void OpIncEvqp(struct Machine *m, uint32_t rde) { + AluEvqp(m, rde, kAlu[ALU_INC]); +} + +static void OpDecEvqp(struct Machine *m, uint32_t rde) { + AluEvqp(m, rde, kAlu[ALU_DEC]); +} + +static void Op0ff(struct Machine *m, uint32_t rde) { + static const nexgen32e_f kOp0ff[] = {OpIncEvqp, OpDecEvqp, OpCallEq, OpUd, + OpJmpEq, OpUd, OpPushEvq, OpUd}; + kOp0ff[ModrmReg(rde)](m, rde); +} + +static void Op101(struct Machine *m, uint32_t rde) { + if (IsModrmRegister(rde)) { + if (ModrmReg(rde) == 0b111 && ModrmRm(rde) == 0b001) { + OpRdtscp(m, rde); + return; + } + } else { + if (ModrmReg(rde) == 2) { + OpLgdtMs(m, rde); + return; + } + } + OpUd(m, rde); +} + +static void Op171(struct Machine *m, uint32_t rde) { + switch (ModrmReg(rde)) { + case 2: + OpSseUdqIb(m, rde, kOpSseUdqIbPsrlw); break; - case 0xFE: - switch (ModrmReg(rde)) { - CASE(0b000, OpEb(m, rde, AluInc)); - CASE(0b001, OpEb(m, rde, AluDec)); - default: - OpUd(m); - } + case 4: + OpSseUdqIb(m, rde, kOpSseUdqIbPsraw); break; - case 0xFF: - switch (ModrmReg(rde)) { - CASE(0, OpEvqp(m, rde, AluInc)); - CASE(1, OpEvqp(m, rde, AluDec)); - CASE(2, OpCallEq(m, rde)); - CASE(4, OpJmpEq(m, rde)); - CASE(6, OpPushEvq(m, rde)); - default: - OpUd(m); - } + case 6: + OpSseUdqIb(m, rde, kOpSseUdqIbPsllw); break; - case 0x10B: - case 0x1B9: - case 0x1FF: - OpUd(m); + default: + OpUd(m, rde); + } +} + +static void Op172(struct Machine *m, uint32_t rde) { + switch (ModrmReg(rde)) { + case 2: + OpSseUdqIb(m, rde, kOpSseUdqIbPsrld); break; - case 0x10D: - case 0x118: - case 0x119: - case 0x11A: - case 0x11B: - case 0x11C: - case 0x11D: - OpWutNopEv(m); + case 4: + OpSseUdqIb(m, rde, kOpSseUdqIbPsrad); break; - case 0x11F: - OpNopEv(m); + case 6: + OpSseUdqIb(m, rde, kOpSseUdqIbPslld); break; - case 0x171: - switch (ModrmReg(rde)) { - CASE(2, OpSseUdqIb(m, rde, kOpSseUdqIbPsrlw)); - CASE(4, OpSseUdqIb(m, rde, kOpSseUdqIbPsraw)); - CASE(6, OpSseUdqIb(m, rde, kOpSseUdqIbPsllw)); - default: - OpUd(m); - } + default: + OpUd(m, rde); + } +} + +static void Op173(struct Machine *m, uint32_t rde) { + switch (ModrmReg(rde)) { + case 2: + OpSseUdqIb(m, rde, kOpSseUdqIbPsrlq); break; - case 0x172: - switch (ModrmReg(rde)) { - CASE(2, OpSseUdqIb(m, rde, kOpSseUdqIbPsrld)); - CASE(4, OpSseUdqIb(m, rde, kOpSseUdqIbPsrad)); - CASE(6, OpSseUdqIb(m, rde, kOpSseUdqIbPslld)); - default: - OpUd(m); - } + case 3: + OpSseUdqIb(m, rde, kOpSseUdqIbPsrldq); break; - case 0x173: - switch (ModrmReg(rde)) { - CASE(2, OpSseUdqIb(m, rde, kOpSseUdqIbPsrlq)); - CASE(3, OpSseUdqIb(m, rde, kOpSseUdqIbPsrldq)); - CASE(6, OpSseUdqIb(m, rde, kOpSseUdqIbPsllq)); - CASE(7, OpSseUdqIb(m, rde, kOpSseUdqIbPslldq)); - default: - OpUd(m); - } + case 6: + OpSseUdqIb(m, rde, kOpSseUdqIbPsllq); break; - case 0x1A4: - case 0x1A5: - case 0x1AC: - case 0x1AD: - OpEvqpGvqp(m, rde, OpDoubleShift, MUTATING); + case 7: + OpSseUdqIb(m, rde, kOpSseUdqIbPslldq); break; - case 0x1AE: - switch (ModrmReg(rde)) { - CASE(5, OpLfence(m)); - CASE(6, OpMfence(m)); - case 7: - if (0xf8 <= m->xedd->op.modrm && m->xedd->op.modrm <= 0xff) { - OpSfence(m); - } else { - OpClflush(m); - } - break; - default: - OpUd(m); - } + default: + OpUd(m, rde); + } +} + +static void OpDoubleShift(struct Machine *m, uint32_t rde) { + uint8_t *p; + uint64_t x; + uint8_t W[2][2] = {{2, 3}, {1, 3}}; + p = GetModrmRegisterWordPointerWriteOszRexw(m, rde); + WriteRegisterOrMemory( + rde, p, + BsuDoubleShift(W[Osz(rde)][Rexw(rde)], ReadMemory(rde, p), + ReadMemory(rde, RegRexrReg(m, rde)), + m->xedd->op.opcode & 1 ? Read8(m->cx) : m->xedd->op.uimm0, + m->xedd->op.opcode & 8, &m->flags)); +} + +static void Op1ae(struct Machine *m, uint32_t rde) { + switch (ModrmReg(rde)) { + case 5: + OpLfence(m, rde); break; - case 0x1B8: - if (Rep(rde) == 3) { - OpGvqpEvqp(m, rde, AluPopcnt, MUTATING); + case 6: + OpMfence(m, rde); + break; + case 7: + if (ModrmMod(rde) == 0b11 && ModrmReg(rde) == 0b111) { + OpSfence(m, rde); } else { - OpUd(m); + OpClflush(m, rde); } break; default: - OpUd(m); + OpUd(m, rde); + } +} + +static void OpSalc(struct Machine *m, uint32_t rde) { + Write8(m->ax, GetFlag(m->flags, FLAGS_CF)); +} + +static void OpNopEv(struct Machine *m, uint32_t rde) { + if (ModrmMod(rde) == 0b01 && ModrmReg(rde) == 0 && ModrmRm(rde) == 0b101) { + OpBofram(m, rde); + } +} + +static void OpNop(struct Machine *m, uint32_t rde) { + if (Rexb(rde)) { + OpXchgZvqp(m, rde); + } else if (Rep(rde) == 3) { + OpPause(m, rde); + } +} + +static const nexgen32e_f kNexgen32e[] = { + [0x000] = OpAlub, + [0x001] = OpAluw, + [0x002] = OpAlubFlip, + [0x003] = OpAluwFlip, + [0x004] = OpAluAlIb, + [0x005] = OpAluRaxIvds, + [0x006] = OpPushSeg, + [0x007] = OpPopSeg, + [0x008] = OpAlub, + [0x009] = OpAluw, + [0x00A] = OpAlubFlip, + [0x00B] = OpAluwFlip, + [0x00C] = OpAluAlIb, + [0x00D] = OpAluRaxIvds, + [0x00E] = OpPushSeg, + [0x00F] = OpPopSeg, + [0x010] = OpAlub, + [0x011] = OpAluw, + [0x012] = OpAlubFlip, + [0x013] = OpAluwFlip, + [0x014] = OpAluAlIb, + [0x015] = OpAluRaxIvds, + [0x016] = OpPushSeg, + [0x017] = OpPopSeg, + [0x018] = OpAlub, + [0x019] = OpAluw, + [0x01A] = OpAlubFlip, + [0x01B] = OpAluwFlip, + [0x01C] = OpAluAlIb, + [0x01D] = OpAluRaxIvds, + [0x01E] = OpPushSeg, + [0x01F] = OpPopSeg, + [0x020] = OpAlub, + [0x021] = OpAluw, + [0x022] = OpAlubFlip, + [0x023] = OpAluwFlip, + [0x024] = OpAluAlIb, + [0x025] = OpAluRaxIvds, + [0x026] = OpPushSeg, + [0x027] = OpPopSeg, + [0x028] = OpAlub, + [0x029] = OpAluw, + [0x02A] = OpAlubFlip, + [0x02B] = OpAluwFlip, + [0x02C] = OpAluAlIb, + [0x02D] = OpAluRaxIvds, + [0x02E] = OpUd, + [0x02F] = OpDas, + [0x030] = OpAlub, + [0x031] = OpAluw, + [0x032] = OpAlubFlip, + [0x033] = OpAluwFlip, + [0x034] = OpAluAlIb, + [0x035] = OpAluRaxIvds, + [0x036] = OpUd, + [0x037] = OpAaa, + [0x038] = OpAlubCmp, + [0x039] = OpAluwCmp, + [0x03A] = OpAlubFlipCmp, + [0x03B] = OpAluwFlipCmp, + [0x03C] = OpCmpAlIb, + [0x03D] = OpCmpRaxIvds, + [0x03E] = OpUd, + [0x03F] = OpAas, + [0x040] = OpIncZv, + [0x041] = OpIncZv, + [0x042] = OpIncZv, + [0x043] = OpIncZv, + [0x044] = OpIncZv, + [0x045] = OpIncZv, + [0x046] = OpIncZv, + [0x047] = OpIncZv, + [0x048] = OpDecZv, + [0x049] = OpDecZv, + [0x04A] = OpDecZv, + [0x04B] = OpDecZv, + [0x04C] = OpDecZv, + [0x04D] = OpDecZv, + [0x04E] = OpDecZv, + [0x04F] = OpDecZv, + [0x050] = OpPushZvq, + [0x051] = OpPushZvq, + [0x052] = OpPushZvq, + [0x053] = OpPushZvq, + [0x054] = OpPushZvq, + [0x055] = OpPushZvq, + [0x056] = OpPushZvq, + [0x057] = OpPushZvq, + [0x058] = OpPopZvq, + [0x059] = OpPopZvq, + [0x05A] = OpPopZvq, + [0x05B] = OpPopZvq, + [0x05C] = OpPopZvq, + [0x05D] = OpPopZvq, + [0x05E] = OpPopZvq, + [0x05F] = OpPopZvq, + [0x060] = OpPusha, + [0x061] = OpPopa, + [0x062] = OpUd, + [0x063] = OpMovsxdGdqpEd, + [0x064] = OpUd, + [0x065] = OpUd, + [0x066] = OpUd, + [0x067] = OpUd, + [0x068] = OpPushImm, + [0x069] = OpImulGvqpEvqpImm, + [0x06A] = OpPushImm, + [0x06B] = OpImulGvqpEvqpImm, + [0x06C] = OpIns, + [0x06D] = OpIns, + [0x06E] = OpOuts, + [0x06F] = OpOuts, + [0x070] = OpJo, + [0x071] = OpJno, + [0x072] = OpJb, + [0x073] = OpJae, + [0x074] = OpJe, + [0x075] = OpJne, + [0x076] = OpJbe, + [0x077] = OpJa, + [0x078] = OpJs, + [0x079] = OpJns, + [0x07A] = OpJp, + [0x07B] = OpJnp, + [0x07C] = OpJl, + [0x07D] = OpJge, + [0x07E] = OpJle, + [0x07F] = OpJg, + [0x080] = OpAlubiReg, + [0x081] = OpAluwiReg, + [0x082] = OpAlubiReg, + [0x083] = OpAluwiReg, + [0x084] = OpAlubTest, + [0x085] = OpAluwTest, + [0x086] = OpXchgGbEb, + [0x087] = OpXchgGvqpEvqp, + [0x088] = OpMovEbGb, + [0x089] = OpMovEvqpGvqp, + [0x08A] = OpMovGbEb, + [0x08B] = OpMovGvqpEvqp, + [0x08C] = OpMovEvqpSw, + [0x08D] = OpLeaGvqpM, + [0x08E] = OpMovSwEvqp, + [0x08F] = OpPopEvq, + [0x090] = OpNop, + [0x091] = OpXchgZvqp, + [0x092] = OpXchgZvqp, + [0x093] = OpXchgZvqp, + [0x094] = OpXchgZvqp, + [0x095] = OpXchgZvqp, + [0x096] = OpXchgZvqp, + [0x097] = OpXchgZvqp, + [0x098] = OpConvert1, + [0x099] = OpConvert2, + [0x09A] = OpUd, + [0x09B] = OpFwait, + [0x09C] = OpPushf, + [0x09D] = OpPopf, + [0x09E] = OpSahf, + [0x09F] = OpLahf, + [0x0A0] = OpMovAlOb, + [0x0A1] = OpMovRaxOvqp, + [0x0A2] = OpMovObAl, + [0x0A3] = OpMovOvqpRax, + [0x0A4] = OpMovsb, + [0x0A5] = OpMovs, + [0x0A6] = OpCmps, + [0x0A7] = OpCmps, + [0x0A8] = OpTestAlIb, + [0x0A9] = OpTestRaxIvds, + [0x0AA] = OpStosb, + [0x0AB] = OpStos, + [0x0AC] = OpLods, + [0x0AD] = OpLods, + [0x0AE] = OpScas, + [0x0AF] = OpScas, + [0x0B0] = OpMovZbIb, + [0x0B1] = OpMovZbIb, + [0x0B2] = OpMovZbIb, + [0x0B3] = OpMovZbIb, + [0x0B4] = OpMovZbIb, + [0x0B5] = OpMovZbIb, + [0x0B6] = OpMovZbIb, + [0x0B7] = OpMovZbIb, + [0x0B8] = OpMovZvqpIvqp, + [0x0B9] = OpMovZvqpIvqp, + [0x0BA] = OpMovZvqpIvqp, + [0x0BB] = OpMovZvqpIvqp, + [0x0BC] = OpMovZvqpIvqp, + [0x0BD] = OpMovZvqpIvqp, + [0x0BE] = OpMovZvqpIvqp, + [0x0BF] = OpMovZvqpIvqp, + [0x0C0] = OpBsubiImm, + [0x0C1] = OpBsuwiImm, + [0x0C2] = OpRetImm, + [0x0C3] = OpRet0, + [0x0C4] = OpLes, + [0x0C5] = OpLds, + [0x0C6] = OpMovEbIb, + [0x0C7] = OpMovEvqpIvds, + [0x0C8] = OpUd, + [0x0C9] = OpLeave, + [0x0CA] = OpUd, + [0x0CB] = OpUd, + [0x0CC] = OpInterrupt3, + [0x0CD] = OpInterruptImm, + [0x0CE] = OpUd, + [0x0CF] = OpUd, + [0x0D0] = OpBsubi1, + [0x0D1] = OpBsuwi1, + [0x0D2] = OpBsubiCl, + [0x0D3] = OpBsuwiCl, + [0x0D4] = OpAam, + [0x0D5] = OpAad, + [0x0D6] = OpSalc, + [0x0D7] = OpXlatAlBbb, + [0x0D8] = OpFpu, + [0x0D9] = OpFpu, + [0x0DA] = OpFpu, + [0x0DB] = OpFpu, + [0x0DC] = OpFpu, + [0x0DD] = OpFpu, + [0x0DE] = OpFpu, + [0x0DF] = OpFpu, + [0x0E0] = OpLoopne, + [0x0E1] = OpLoope, + [0x0E2] = OpLoop1, + [0x0E3] = OpJcxz, + [0x0E4] = OpInAlImm, + [0x0E5] = OpInAxImm, + [0x0E6] = OpOutImmAl, + [0x0E7] = OpOutImmAx, + [0x0E8] = OpCallJvds, + [0x0E9] = OpJmp, + [0x0EA] = OpJmpf, + [0x0EB] = OpJmp, + [0x0EC] = OpInAlDx, + [0x0ED] = OpInAxDx, + [0x0EE] = OpOutDxAl, + [0x0EF] = OpOutDxAx, + [0x0F0] = OpUd, + [0x0F1] = OpInterrupt1, + [0x0F2] = OpUd, + [0x0F3] = OpUd, + [0x0F4] = OpHlt, + [0x0F5] = OpCmc, + [0x0F6] = Op0f6, + [0x0F7] = Op0f7, + [0x0F8] = OpClc, + [0x0F9] = OpStc, + [0x0FA] = OpCli, + [0x0FB] = OpSti, + [0x0FC] = OpCld, + [0x0FD] = OpStd, + [0x0FE] = Op0fe, + [0x0FF] = Op0ff, + [0x100] = OpUd, + [0x101] = Op101, + [0x102] = OpUd, + [0x103] = OpUd, + [0x104] = OpUd, + [0x105] = OpSyscall, + [0x106] = OpUd, + [0x107] = OpUd, + [0x108] = OpUd, + [0x109] = OpUd, + [0x10A] = OpUd, + [0x10B] = OpUd, + [0x10C] = OpUd, + [0x10D] = OpWutNopEv, + [0x10E] = OpUd, + [0x10F] = OpUd, + [0x110] = OpMov0f10, + [0x111] = OpMovWpsVps, + [0x112] = OpMov0f12, + [0x113] = OpMov0f13, + [0x114] = OpUnpcklpsd, + [0x115] = OpUnpckhpsd, + [0x116] = OpMov0f16, + [0x117] = OpMov0f17, + [0x118] = OpWutNopEv, + [0x119] = OpWutNopEv, + [0x11A] = OpWutNopEv, + [0x11B] = OpWutNopEv, + [0x11C] = OpWutNopEv, + [0x11D] = OpWutNopEv, + [0x11E] = OpUd, + [0x11F] = OpNopEv, + [0x120] = OpUd, + [0x121] = OpUd, + [0x122] = OpUd, + [0x123] = OpUd, + [0x124] = OpUd, + [0x125] = OpUd, + [0x126] = OpUd, + [0x127] = OpUd, + [0x128] = OpMov0f28, + [0x129] = OpMovWpsVps, + [0x12A] = OpCvt0f2a, + [0x12B] = OpMov0f2b, + [0x12C] = OpCvtt0f2c, + [0x12D] = OpCvt0f2d, + [0x12E] = OpComissVsWs, + [0x12F] = OpComissVsWs, + [0x130] = OpUd, + [0x131] = OpRdtsc, + [0x132] = OpUd, + [0x133] = OpUd, + [0x134] = OpUd, + [0x135] = OpUd, + [0x136] = OpUd, + [0x137] = OpUd, + [0x138] = OpUd, + [0x139] = OpUd, + [0x13A] = OpUd, + [0x13B] = OpUd, + [0x13C] = OpUd, + [0x13D] = OpUd, + [0x13E] = OpUd, + [0x13F] = OpUd, + [0x140] = OpCmovo, + [0x141] = OpCmovno, + [0x142] = OpCmovb, + [0x143] = OpCmovae, + [0x144] = OpCmove, + [0x145] = OpCmovne, + [0x146] = OpCmovbe, + [0x147] = OpCmova, + [0x148] = OpCmovs, + [0x149] = OpCmovns, + [0x14A] = OpCmovp, + [0x14B] = OpCmovnp, + [0x14C] = OpCmovl, + [0x14D] = OpCmovge, + [0x14E] = OpCmovle, + [0x14F] = OpCmovg, + [0x150] = OpUd, + [0x151] = OpSqrtpsd, + [0x152] = OpRsqrtps, + [0x153] = OpRcpps, + [0x154] = OpAndpsd, + [0x155] = OpAndnpsd, + [0x156] = OpOrpsd, + [0x157] = OpXorpsd, + [0x158] = OpAddpsd, + [0x159] = OpMulpsd, + [0x15A] = OpCvt0f5a, + [0x15B] = OpCvt0f5b, + [0x15C] = OpSubpsd, + [0x15D] = OpMinpsd, + [0x15E] = OpDivpsd, + [0x15F] = OpMaxpsd, + [0x160] = OpSsePunpcklbw, + [0x161] = OpSsePunpcklwd, + [0x162] = OpSsePunpckldq, + [0x163] = OpSsePacksswb, + [0x164] = OpSsePcmpgtb, + [0x165] = OpSsePcmpgtw, + [0x166] = OpSsePcmpgtd, + [0x167] = OpSsePackuswb, + [0x168] = OpSsePunpckhbw, + [0x169] = OpSsePunpckhwd, + [0x16A] = OpSsePunpckhdq, + [0x16B] = OpSsePackssdw, + [0x16C] = OpSsePunpcklqdq, + [0x16D] = OpSsePunpckhqdq, + [0x16E] = OpMov0f6e, + [0x16F] = OpMov0f6f, + [0x170] = OpShuffle, + [0x171] = Op171, + [0x172] = Op172, + [0x173] = Op173, + [0x174] = OpSsePcmpeqb, + [0x175] = OpSsePcmpeqw, + [0x176] = OpSsePcmpeqd, + [0x177] = OpUd, + [0x178] = OpUd, + [0x179] = OpUd, + [0x17A] = OpUd, + [0x17B] = OpUd, + [0x17C] = OpHaddpsd, + [0x17D] = OpHsubpsd, + [0x17E] = OpMov0f7e, + [0x17F] = OpMov0f7f, + [0x180] = OpJo, + [0x181] = OpJno, + [0x182] = OpJb, + [0x183] = OpJae, + [0x184] = OpJe, + [0x185] = OpJne, + [0x186] = OpJbe, + [0x187] = OpJa, + [0x188] = OpJs, + [0x189] = OpJns, + [0x18A] = OpJp, + [0x18B] = OpJnp, + [0x18C] = OpJl, + [0x18D] = OpJge, + [0x18E] = OpJle, + [0x18F] = OpJg, + [0x190] = OpSeto, + [0x191] = OpSetno, + [0x192] = OpSetb, + [0x193] = OpSetae, + [0x194] = OpSete, + [0x195] = OpSetne, + [0x196] = OpSetbe, + [0x197] = OpSeta, + [0x198] = OpSets, + [0x199] = OpSetns, + [0x19A] = OpSetp, + [0x19B] = OpSetnp, + [0x19C] = OpSetl, + [0x19D] = OpSetge, + [0x19E] = OpSetle, + [0x19F] = OpSetg, + [0x1A0] = OpPushSeg, + [0x1A1] = OpPopSeg, + [0x1A2] = OpCpuid, + [0x1A3] = OpBit, + [0x1A4] = OpDoubleShift, + [0x1A5] = OpDoubleShift, + [0x1A6] = OpUd, + [0x1A7] = OpUd, + [0x1A8] = OpPushSeg, + [0x1A9] = OpPopSeg, + [0x1AA] = OpUd, + [0x1AB] = OpBit, + [0x1AC] = OpDoubleShift, + [0x1AD] = OpDoubleShift, + [0x1AE] = Op1ae, + [0x1AF] = OpImulGvqpEvqp, + [0x1B0] = OpCmpxchgEbAlGb, + [0x1B1] = OpCmpxchgEvqpRaxGvqp, + [0x1B2] = OpUd, + [0x1B3] = OpBit, + [0x1B4] = OpUd, + [0x1B5] = OpUd, + [0x1B6] = OpMovzbGvqpEb, + [0x1B7] = OpMovzwGvqpEw, + [0x1B8] = Op1b8, + [0x1B9] = OpUd, + [0x1BA] = OpBit, + [0x1BB] = OpBit, + [0x1BC] = OpBsf, + [0x1BD] = OpBsr, + [0x1BE] = OpMovsbGvqpEb, + [0x1BF] = OpMovswGvqpEw, + [0x1C0] = OpXaddEbGb, + [0x1C1] = OpXaddEvqpGvqp, + [0x1C2] = OpCmppsd, + [0x1C3] = OpMovntiMdqpGdqp, + [0x1C4] = OpPinsrwVdqEwIb, + [0x1C5] = OpPextrwGdqpUdqIb, + [0x1C6] = OpShufpsd, + [0x1C7] = OpCmpxchgDxAx, + [0x1C8] = OpBswapZvqp, + [0x1C9] = OpBswapZvqp, + [0x1CA] = OpBswapZvqp, + [0x1CB] = OpBswapZvqp, + [0x1CC] = OpBswapZvqp, + [0x1CD] = OpBswapZvqp, + [0x1CE] = OpBswapZvqp, + [0x1CF] = OpBswapZvqp, + [0x1D0] = OpAddsubpsd, + [0x1D1] = OpSsePsrlwv, + [0x1D2] = OpSsePsrldv, + [0x1D3] = OpSsePsrlqv, + [0x1D4] = OpSsePaddq, + [0x1D5] = OpSsePmullw, + [0x1D6] = OpMov0fD6, + [0x1D7] = OpPmovmskbGdqpNqUdq, + [0x1D8] = OpSsePsubusb, + [0x1D9] = OpSsePsubusw, + [0x1DA] = OpSsePminub, + [0x1DB] = OpSsePand, + [0x1DC] = OpSsePaddusb, + [0x1DD] = OpSsePaddusw, + [0x1DE] = OpSsePmaxub, + [0x1DF] = OpSsePandn, + [0x1E0] = OpSsePavgb, + [0x1E1] = OpSsePsrawv, + [0x1E2] = OpSsePsradv, + [0x1E3] = OpSsePavgw, + [0x1E4] = OpSsePmulhuw, + [0x1E5] = OpSsePmulhw, + [0x1E6] = OpCvt0fE6, + [0x1E7] = OpMov0fE7, + [0x1E8] = OpSsePsubsb, + [0x1E9] = OpSsePsubsw, + [0x1EA] = OpSsePminsw, + [0x1EB] = OpSsePor, + [0x1EC] = OpSsePaddsb, + [0x1ED] = OpSsePaddsw, + [0x1EE] = OpSsePmaxsw, + [0x1EF] = OpSsePxor, + [0x1F0] = OpLddquVdqMdq, + [0x1F1] = OpSsePsllwv, + [0x1F2] = OpSsePslldv, + [0x1F3] = OpSsePsllqv, + [0x1F4] = OpSsePmuludq, + [0x1F5] = OpSsePmaddwd, + [0x1F6] = OpSsePsadbw, + [0x1F7] = OpMaskMovDiXmmRegXmmRm, + [0x1F8] = OpSsePsubb, + [0x1F9] = OpSsePsubw, + [0x1FA] = OpSsePsubd, + [0x1FB] = OpSsePsubq, + [0x1FC] = OpSsePaddb, + [0x1FD] = OpSsePaddw, + [0x1FE] = OpSsePaddd, + [0x1FF] = OpUd, + [0x200] = OpSsePshufb, + [0x201] = OpSsePhaddw, + [0x202] = OpSsePhaddd, + [0x203] = OpSsePhaddsw, + [0x204] = OpSsePmaddubsw, + [0x205] = OpSsePhsubw, + [0x206] = OpSsePhsubd, + [0x207] = OpSsePhsubsw, + [0x208] = OpSsePsignb, + [0x209] = OpSsePsignw, + [0x20A] = OpSsePsignd, + [0x20B] = OpSsePmulhrsw, +}; + +void ExecuteSparseInstruction(struct Machine *m, uint32_t rde, uint32_t d) { + switch (d) { + CASE(0x21c, OpSsePabsb(m, rde)); + CASE(0x21d, OpSsePabsw(m, rde)); + CASE(0x21e, OpSsePabsd(m, rde)); + CASE(0x22a, OpMovntdqaVdqMdq(m, rde)); + CASE(0x240, OpSsePmulld(m, rde)); + CASE(0x30f, OpSsePalignr(m, rde)); + default: + OpUd(m, rde); + } +} + +void ExecuteInstruction(struct Machine *m) { + m->ip += m->xedd->length; + if (m->xedd->op.dispatch < ARRAYLEN(kNexgen32e)) { + kNexgen32e[m->xedd->op.dispatch](m, m->xedd->op.rde); + } else { + ExecuteSparseInstruction(m, m->xedd->op.rde, m->xedd->op.dispatch); } if (m->stashaddr) { VirtualRecv(m, m->stashaddr, m->stash, m->stashsize); diff --git a/tool/build/lib/machine.h b/tool/build/lib/machine.h index 0f8fee5b..565a6454 100644 --- a/tool/build/lib/machine.h +++ b/tool/build/lib/machine.h @@ -1,6 +1,5 @@ #ifndef COSMOPOLITAN_TOOL_BUILD_LIB_MACHINE_H_ #define COSMOPOLITAN_TOOL_BUILD_LIB_MACHINE_H_ -#include "libc/elf/struct/ehdr.h" #include "libc/runtime/runtime.h" #include "third_party/xed/x86.h" #include "tool/build/lib/fds.h" @@ -26,9 +25,13 @@ COSMOPOLITAN_C_START_ struct Machine { struct XedDecodedInst *xedd; uint64_t ip; + uint8_t cs[8]; + uint8_t ss[8]; uint64_t codevirt; uint8_t *codereal; + uint32_t mode; uint32_t flags; + uint32_t tlbindex; uint32_t stashsize; int64_t stashaddr; int64_t readaddr; @@ -36,7 +39,7 @@ struct Machine { uint32_t readsize; uint32_t writesize; union { - uint8_t reg[2 * 8][8]; + uint8_t reg[16][8]; struct { uint8_t ax[8]; uint8_t cx[8]; @@ -55,14 +58,19 @@ struct Machine { uint8_t r14[8]; uint8_t r15[8]; }; - } aligned(8); - uint32_t tlbindex; + }; + uint8_t *real; + uint64_t realsize; + uint64_t *cr3; struct TlbEntry { int64_t v; void *r; } tlb[16]; - uint8_t *veg[2 * 8]; - uint8_t *beg[2 * 2 * 8]; + uint8_t xmm[16][16] aligned(16); + uint8_t es[8]; + uint8_t ds[8]; + uint8_t fs[8]; + uint8_t gs[8]; struct MachineFpu { long double st[8]; union { @@ -129,16 +137,14 @@ struct Machine { uint32_t i; void *p[6]; } freelist; - pml4t_t cr3; - uint8_t xmm[2][8][16] aligned(16); int64_t bofram[2]; jmp_buf onhalt; int64_t faultaddr; uint8_t stash[4096]; uint8_t xmmtype[2][8]; - struct XedDecodedInst icache[1024]; + uint8_t icache[2048][40] aligned(8); struct MachineFds fds; -}; +} aligned(64); void ResetCpu(struct Machine *); void LoadInstruction(struct Machine *); diff --git a/net/http/freehttprequest.c b/tool/build/lib/mda.c similarity index 81% rename from net/http/freehttprequest.c rename to tool/build/lib/mda.c index eb47efa5..84d530c3 100644 --- a/net/http/freehttprequest.c +++ b/tool/build/lib/mda.c @@ -17,17 +17,21 @@ │ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │ │ 02110-1301 USA │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/alg/alg.h" -#include "libc/runtime/runtime.h" -#include "net/http/http.h" +#include "libc/macros.h" +#include "libc/str/str.h" +#include "tool/build/lib/buffer.h" +#include "tool/build/lib/mda.h" -void freehttprequest(struct HttpRequest **req) { - if (*req) { - critbit0_clear(&(*req)->headers); - free_s(&(*req)->method.p); - free_s(&(*req)->scratch.p); - free_s(&(*req)->uri.p); - free_s(&(*req)->version.p); - free_s(req); +void DrawMda(struct Panel *p, uint8_t v[25][80][2]) { + unsigned y, x, n; + n = MIN(25, p->bottom - p->top); + for (y = 0; y < n; ++y) { + for (x = 0; x < 80; ++x) { + if (v[y][x][1]) { + AppendWide(&p->lines[y], kCp437[v[y][x][0]]); + } else { + AppendChar(&p->lines[y], ' '); + } + } } } diff --git a/tool/build/lib/mda.h b/tool/build/lib/mda.h new file mode 100644 index 00000000..84eb7c46 --- /dev/null +++ b/tool/build/lib/mda.h @@ -0,0 +1,11 @@ +#ifndef COSMOPOLITAN_TOOL_BUILD_LIB_MDA_H_ +#define COSMOPOLITAN_TOOL_BUILD_LIB_MDA_H_ +#include "tool/build/lib/panel.h" +#if !(__ASSEMBLER__ + __LINKER__ + 0) +COSMOPOLITAN_C_START_ + +void DrawMda(struct Panel *, uint8_t[25][80][2]); + +COSMOPOLITAN_C_END_ +#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ +#endif /* COSMOPOLITAN_TOOL_BUILD_LIB_MDA_H_ */ diff --git a/tool/build/lib/memory.c b/tool/build/lib/memory.c index daa274c2..58d911b8 100644 --- a/tool/build/lib/memory.c +++ b/tool/build/lib/memory.c @@ -105,8 +105,9 @@ void VirtualCopy(struct Machine *m, int64_t v, char *r, uint64_t n, bool d) { } } -void VirtualSend(struct Machine *m, void *dst, int64_t src, uint64_t n) { +void *VirtualSend(struct Machine *m, void *dst, int64_t src, uint64_t n) { VirtualCopy(m, src, dst, n, true); + return dst; } void VirtualRecv(struct Machine *m, int64_t dst, void *src, uint64_t n) { diff --git a/tool/build/lib/memory.h b/tool/build/lib/memory.h index 32269014..c563095c 100644 --- a/tool/build/lib/memory.h +++ b/tool/build/lib/memory.h @@ -4,8 +4,6 @@ #if !(__ASSEMBLER__ + __LINKER__ + 0) COSMOPOLITAN_C_START_ -#define GetSegment(m) 0 - int RegisterMemory(struct Machine *, int64_t, void *, size_t); void *AccessRam(struct Machine *, int64_t, size_t, void *[2], uint8_t *, bool); void *BeginLoadStore(struct Machine *, int64_t, size_t, void *[2], uint8_t *); @@ -24,8 +22,9 @@ void ResetRam(struct Machine *); void SetReadAddr(struct Machine *, int64_t, uint32_t); void SetWriteAddr(struct Machine *, int64_t, uint32_t); void VirtualRecv(struct Machine *, int64_t, void *, uint64_t); -void VirtualSend(struct Machine *, void *, int64_t, uint64_t); +void *VirtualSend(struct Machine *, void *, int64_t, uint64_t); void VirtualSet(struct Machine *, int64_t, char, uint64_t); +void *RealAddress(struct Machine *, int64_t); COSMOPOLITAN_C_END_ #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ diff --git a/tool/build/lib/memorymalloc.c b/tool/build/lib/memorymalloc.c index ea38bb6d..1d9fdbf6 100644 --- a/tool/build/lib/memorymalloc.c +++ b/tool/build/lib/memorymalloc.c @@ -45,6 +45,7 @@ struct Machine *NewMachine(void) { struct Machine *m; m = memalign(alignof(struct Machine), sizeof(struct Machine)); memset(m, 0, sizeof(struct Machine)); + m->mode = XED_MACHINE_MODE_LONG_64; InitMachine(m); return m; } diff --git a/tool/build/lib/modrm.c b/tool/build/lib/modrm.c index 2bd2b3b5..18a2e394 100644 --- a/tool/build/lib/modrm.c +++ b/tool/build/lib/modrm.c @@ -18,37 +18,104 @@ │ 02110-1301 USA │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/log/check.h" +#include "third_party/xed/x86.h" +#include "tool/build/lib/address.h" #include "tool/build/lib/endian.h" #include "tool/build/lib/machine.h" #include "tool/build/lib/memory.h" #include "tool/build/lib/modrm.h" +#include "tool/build/lib/throw.h" /** - * Computes virtual address based on modrm and sib bytes. + * Byte register offsets. + * + * for (i = 0; i < 2; ++i) { // rex + * for (j = 0; j < 2; ++j) { // rexb, or rexr + * for (k = 0; k < 8; ++k) { // reg, rm, or srm + * kByteReg[i << 4 | j << 3 | k] = + * i ? (j << 3 | k) * 8 : (k & 0b11) * 8 + ((k & 0b100) >> 2); + * } + * } + * } */ +const uint8_t kByteReg[32] = {0x00, 0x08, 0x10, 0x18, 0x01, 0x09, 0x11, 0x19, + 0x00, 0x08, 0x10, 0x18, 0x01, 0x09, 0x11, 0x19, + 0x00, 0x08, 0x10, 0x18, 0x20, 0x28, 0x30, 0x38, + 0x40, 0x48, 0x50, 0x58, 0x60, 0x68, 0x70, 0x78}; + int64_t ComputeAddress(const struct Machine *m, uint32_t rde) { uint64_t i; - DCHECK(m->xedd->op.has_modrm); + uint8_t *s; DCHECK(!IsModrmRegister(rde)); + s = m->ds; i = m->xedd->op.disp; - if (!SibExists(rde)) { - if (IsRipRelative(rde)) { - i += m->ip; + if (Eamode(rde) != XED_MODE_REAL) { + if (!SibExists(rde)) { + if (IsRipRelative(rde)) { + if (Mode(rde) == XED_MODE_LONG) { + i += m->ip; + } + } else { + i += Read64(RegRexbRm(m, rde)); + if (RexbRm(rde) == 4 || RexbRm(rde) == 5) { + s = m->ss; + } + } } else { - i += Read64(RegRexbRm(m, rde)); + if (SibHasBase(m->xedd, rde)) { + i += Read64(RegRexbBase(m, rde)); + if (RexbBase(m, rde) == 4 || RexbBase(m, rde) == 5) { + s = m->ss; + } + } + if (SibHasIndex(m->xedd)) { + i += Read64(RegRexxIndex(m)) << m->xedd->op.scale; + } + } + if (Eamode(rde) == XED_MODE_LEGACY) { + i &= 0xffffffff; } } else { - DCHECK(m->xedd->op.has_sib); - if (SibHasBase(rde)) { - i += Read64(RegRexbBase(m, rde)); - } - if (SibHasIndex(rde)) { - i += Read64(RegRexxIndex(m, rde)) << m->xedd->op.scale; + switch (ModrmRm(rde)) { + case 0: + i += Read16(m->bx); + i += Read16(m->si); + break; + case 1: + i += Read16(m->bx); + i += Read16(m->di); + break; + case 2: + s = m->ss; + i += Read16(m->bp); + i += Read16(m->si); + break; + case 3: + s = m->ss; + i += Read16(m->bp); + i += Read16(m->di); + break; + case 4: + i += Read16(m->si); + break; + case 5: + i += Read16(m->di); + break; + case 6: + if (ModrmMod(rde)) { + s = m->ss; + i += Read16(m->bp); + } + break; + case 7: + i += Read16(m->bx); + break; + default: + unreachable; } + i &= 0xffff; } - i += GetSegment(m); - if (Asz(rde)) i &= 0xffffffff; - return i; + return AddSegment(m, rde, i, s); } void *ComputeReserveAddressRead(struct Machine *m, uint32_t rde, size_t n) { @@ -62,6 +129,10 @@ void *ComputeReserveAddressRead1(struct Machine *m, uint32_t rde) { return ComputeReserveAddressRead(m, rde, 1); } +void *ComputeReserveAddressRead4(struct Machine *m, uint32_t rde) { + return ComputeReserveAddressRead(m, rde, 4); +} + void *ComputeReserveAddressRead8(struct Machine *m, uint32_t rde) { return ComputeReserveAddressRead(m, rde, 8); } diff --git a/tool/build/lib/modrm.h b/tool/build/lib/modrm.h index 3a29c403..3c327334 100644 --- a/tool/build/lib/modrm.h +++ b/tool/build/lib/modrm.h @@ -5,46 +5,56 @@ #if !(__ASSEMBLER__ + __LINKER__ + 0) COSMOPOLITAN_C_START_ -#define SibBase(x) ((x & 000007000000) >> 022) -#define SibIndex(x) ((x & 000700000000) >> 030) -#define ModrmRm(x) ((x & 000000000700) >> 006) -#define ModrmReg(x) ((x & 000000000007) >> 000) -#define ModrmSrm(x) ((x & 000000070000) >> 014) -#define ModrmMod(x) ((x & 000060000000) >> 026) -#define RegLog2(x) ((x & 006000000000) >> 034) -#define Rexx(x) ((x & 001000000000) >> 033) -#define Asz(x) ((x & 000000400000) >> 021) -#define Rexw(x) ((x & 000000004000) >> 013) -#define Rexr(x) ((x & 000000000010) >> 003) -#define Rexb(x) ((x & 000010000000) >> 025) #define Rex(x) ((x & 000000000020) >> 004) #define Osz(x) ((x & 000000000040) >> 005) #define Rep(x) ((x & 030000000000) >> 036) +#define Rexr(x) ((x & 000000000010) >> 003) +#define Rexw(x) ((x & 000000000100) >> 006) +#define Rexb(x) ((x & 000000002000) >> 012) +#define Sego(x) ((x & 000007000000) >> 022) +#define Mode(x) ((x & 001400000000) >> 032) +#define Eamode(x) ((x & 000300000000) >> 030) +#define RexbRm(x) ((x & 000000003600) >> 007) +#define RexrReg(x) ((x & 000000000017) >> 000) +#define RegLog2(x) ((x & 006000000000) >> 034) +#define ModrmRm(x) ((x & 000000001600) >> 007) +#define ModrmReg(x) ((x & 000000000007) >> 000) +#define ModrmSrm(x) ((x & 000000070000) >> 014) +#define ModrmMod(x) ((x & 000060000000) >> 026) -#define IsModrmRegister(x) (ModrmMod(x) == 3) -#define SibExists(x) (ModrmRm(x) == 4) -#define SibHasIndex(x) (SibIndex(x) != 4 || Rexx(x)) -#define SibHasBase(x) (SibBase(x) != 5 || ModrmMod(x)) -#define SibIsAbsolute(x) (!SibHasBase(x) && !SibHasIndex(x)) -#define IsRipRelative(x) (ModrmRm(x) == 5 && !ModrmMod(x)) +#define AddrByteReg(m, k) ((uint8_t *)m->reg + kByteReg[k]) +#define ByteRexrReg(m, x) AddrByteReg(m, (x & 00000000037) >> 0) +#define ByteRexbRm(m, x) AddrByteReg(m, (x & 00000007600) >> 7) +#define ByteRexbSrm(m, x) AddrByteReg(m, (x & 00000370000) >> 12) +#define RexbBase(m, x) (Rexb(x) << 3 | m->xedd->op.base) +#define RegSrm(m, x) Abp8(m->reg[(x & 00000070000) >> 12]) +#define RegRexbRm(m, x) Abp8(m->reg[RexbRm(x)]) +#define RegRexbSrm(m, x) Abp8(m->reg[(x & 00000170000) >> 12]) +#define RegRexrReg(m, x) Abp8(m->reg[RexrReg(x)]) +#define RegRexbBase(m, x) Abp8(m->reg[RexbBase(m, x)]) +#define RegRexxIndex(m) Abp8(m->reg[m->xedd->op.rexx << 3 | m->xedd->op.index]) +#define MmRm(m, x) Abp16(m->xmm[(x & 00000001600) >> 7]) +#define MmReg(m, x) Abp16(m->xmm[(x & 00000000007) >> 0]) +#define XmmRexbRm(m, x) Abp16(m->xmm[RexbRm(x)]) +#define XmmRexrReg(m, x) Abp16(m->xmm[RexrReg(x)]) -#define ByteRexrReg(m, x) m->beg[(x & 00000000037) >> 0] -#define ByteRexbRm(m, x) m->beg[(x & 00000003700) >> 6] -#define ByteRexbSrm(m, x) m->beg[(x & 00000370000) >> 12] -#define RegRexbSrm(m, x) Abp8(m->reg[(x & 00000170000) >> 12]) -#define RegRexrReg(m, x) Abp8(m->reg[(x & 00000000017) >> 0]) -#define RegRexbRm(m, x) Abp8(m->reg[(x & 00000001700) >> 6]) -#define RegRexbBase(m, x) Abp8(m->reg[(x & 00017000000) >> 18]) -#define RegRexxIndex(m, x) Abp8(m->reg[(x & 01700000000) >> 24]) -#define XmmRexrReg(m, x) Abp16(m->veg[(x & 00000000017) >> 0]) -#define XmmRexbRm(m, x) Abp16(m->veg[(x & 00000001700) >> 6]) -#define MmReg(m, x) Abp16(m->veg[(x & 00000000007) >> 0]) -#define MmRm(m, x) Abp16(m->veg[(x & 00000000700) >> 6]) +#define Rexx(m) m->op.rexx +#define SibBase(m) m->op.base +#define SibIndex(m) m->op.index +#define SibExists(x) (ModrmRm(x) == 4) +#define IsModrmRegister(x) (ModrmMod(x) == 3) +#define SibHasIndex(x) (SibIndex(x) != 4 || Rexx(x)) +#define SibHasBase(x, r) (SibBase(x) != 5 || ModrmMod(r)) +#define SibIsAbsolute(x, r) (!SibHasBase(x, r) && !SibHasIndex(x)) +#define IsRipRelative(x) (ModrmRm(x) == 5 && !ModrmMod(x)) + +extern const uint8_t kByteReg[32]; int64_t ComputeAddress(const struct Machine *, uint32_t) nosideeffect; void *ComputeReserveAddressRead(struct Machine *, uint32_t, size_t); void *ComputeReserveAddressRead1(struct Machine *, uint32_t); +void *ComputeReserveAddressRead4(struct Machine *, uint32_t); void *ComputeReserveAddressRead8(struct Machine *, uint32_t); void *ComputeReserveAddressWrite(struct Machine *, uint32_t, size_t); void *ComputeReserveAddressWrite1(struct Machine *, uint32_t); diff --git a/tool/build/lib/pml4tfmt.c b/tool/build/lib/pml4tfmt.c index d8eafa26..18c72a65 100644 --- a/tool/build/lib/pml4tfmt.c +++ b/tool/build/lib/pml4tfmt.c @@ -19,6 +19,7 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/macros.h" #include "libc/mem/mem.h" +#include "libc/x/x.h" #include "tool/build/lib/buffer.h" #include "tool/build/lib/memory.h" #include "tool/build/lib/pml4t.h" @@ -104,8 +105,7 @@ char *FormatPml4t(uint64_t pml4t[512]) { FormatEndPage(&pp, 0x800000000000); } if (pp.b.p) { - realloc(pp.b.p, pp.b.i + 1); - return pp.b.p; + return xrealloc(pp.b.p, pp.b.i + 1); } else { return strdup(""); } diff --git a/tool/build/lib/pty.c b/tool/build/lib/pty.c index 2409d21f..74ab21ef 100644 --- a/tool/build/lib/pty.c +++ b/tool/build/lib/pty.c @@ -31,18 +31,39 @@ #include "libc/x/x.h" #include "tool/build/lib/pty.h" -struct MachinePty *MachinePtyNew(unsigned yn, unsigned xn) { - struct MachinePty *pty; - DCHECK_GT(yn, 0); - DCHECK_GT(xn, 0); - pty = xcalloc(1, sizeof(struct MachinePty)); +struct MachinePty *MachinePtyNew(void) { + return xcalloc(1, sizeof(struct MachinePty)); +} + +void MachinePtyResize(struct MachinePty *pty, int yn, int xn) { + unsigned y, ym, xm, y0; + uint32_t *wcs, *fgs, *bgs, *prs; + if (yn <= 0 || xn <= 0) return; + wcs = xcalloc(yn * xn, 4); + fgs = xcalloc(yn * xn, 4); + bgs = xcalloc(yn * xn, 4); + prs = xcalloc(yn * xn, 4); + y0 = yn > pty->y + 1 ? 0 : pty->y + 1 - yn; + ym = MIN(yn, pty->yn) + y0; + xm = MIN(xn, pty->xn); + for (y = y0; y < ym; ++y) { + memcpy(wcs + y * xn, pty->wcs + y * pty->xn, xm * 4); + memcpy(fgs + y * xn, pty->fgs + y * pty->xn, xm * 4); + memcpy(bgs + y * xn, pty->bgs + y * pty->xn, xm * 4); + memcpy(prs + y * xn, pty->prs + y * pty->xn, xm * 4); + } + free(pty->wcs); + free(pty->fgs); + free(pty->bgs); + free(pty->prs); + pty->wcs = wcs; + pty->fgs = fgs; + pty->bgs = bgs; + pty->prs = prs; + pty->y = MIN(pty->y, yn - 1); + pty->x = MIN(pty->x, xn - 1); pty->yn = yn; pty->xn = xn; - pty->wcs = xcalloc(yn * xn, sizeof(pty->wcs[0])); - pty->fgs = xcalloc(yn * xn, sizeof(pty->fgs[0])); - pty->bgs = xcalloc(yn * xn, sizeof(pty->bgs[0])); - pty->prs = xcalloc(yn * xn, sizeof(pty->prs[0])); - return pty; } void MachinePtyFree(struct MachinePty *pty) { @@ -234,7 +255,7 @@ static void MachinePtySelectGraphicsRendition(struct MachinePty *pty) { t = kSgrFg; break; case 39: - pty->pr &= kMachinePtyFg; + pty->pr &= ~kMachinePtyFg; break; case 100 ... 107: code[0] -= 100 - 40; @@ -248,7 +269,7 @@ static void MachinePtySelectGraphicsRendition(struct MachinePty *pty) { t = kSgrBg; break; case 49: - pty->pr &= kMachinePtyBg; + pty->pr &= ~kMachinePtyBg; break; default: break; @@ -368,6 +389,7 @@ static void MachinePtyEscAppend(struct MachinePty *pty, char c) { ssize_t MachinePtyWrite(struct MachinePty *pty, const void *data, size_t n) { int i; const uint8_t *p; + if (!pty->yn || !pty->xn) return 0; for (p = data, i = 0; i < n; ++i) { switch (pty->state) { case kMachinePtyAscii: @@ -464,7 +486,7 @@ ssize_t MachinePtyWrite(struct MachinePty *pty, const void *data, size_t n) { void MachinePtyAppendLine(struct MachinePty *pty, struct Buffer *buf, unsigned y) { uint32_t x, i, fg, bg, pr, wc, w; - CHECK_LT(y, pty->yn); + if (y >= pty->yn) return; for (fg = bg = pr = x = 0; x < pty->xn; x += w) { i = y * pty->xn + x; wc = pty->wcs[i]; diff --git a/tool/build/lib/pty.h b/tool/build/lib/pty.h index 1cbeb73f..fd72299d 100644 --- a/tool/build/lib/pty.h +++ b/tool/build/lib/pty.h @@ -40,8 +40,9 @@ struct MachinePty { } esc; }; -struct MachinePty *MachinePtyNew(unsigned, unsigned) nodiscard; void MachinePtyFree(struct MachinePty *); +struct MachinePty *MachinePtyNew(void) nodiscard; +void MachinePtyResize(struct MachinePty *, int, int); ssize_t MachinePtyWrite(struct MachinePty *, const void *, size_t); void MachinePtyAppendLine(struct MachinePty *, struct Buffer *, unsigned); diff --git a/tool/build/lib/sse.c b/tool/build/lib/sse.c index 039933ac..8ce233e5 100644 --- a/tool/build/lib/sse.c +++ b/tool/build/lib/sse.c @@ -114,102 +114,603 @@ union MachineVector { uint64_t u64[2]; }; -void OpSse(struct Machine *m, uint32_t rde, enum OpSseKernel kernel) { - int i; - uint8_t *p; - union MachineVector x, y; - p = GetModrmRegisterXmmPointerRead16(m, rde); +static void SsePsubb(void *b, const void *a) { + psubb(b, b, a); +} + +static void SsePaddb(void *b, const void *a) { + paddb(b, b, a); +} + +static void SsePsubw(void *b, const void *a) { + psubw(b, b, a); +} + +static void SsePaddw(void *b, const void *a) { + paddw(b, b, a); +} + +static void SsePsubd(void *b, const void *a) { + psubd(b, b, a); +} + +static void SsePaddd(void *b, const void *a) { + paddd(b, b, a); +} + +static void SsePaddq(void *b, const void *a) { + paddq(b, b, a); +} + +static void SsePsubq(void *b, const void *a) { + psubq(b, b, a); +} + +static void SsePsubsb(void *b, const void *a) { + psubsb(b, b, a); +} + +static void SsePsubsw(void *b, const void *a) { + psubsw(b, b, a); +} + +static void SsePaddsb(void *b, const void *a) { + paddsb(b, b, a); +} + +static void SsePaddsw(void *b, const void *a) { + paddsw(b, b, a); +} + +static void SsePaddusb(void *b, const void *a) { + paddusb(b, b, a); +} + +static void SsePaddusw(void *b, const void *a) { + paddusw(b, b, a); +} + +static void SsePor(void *b, const void *a) { + por(b, b, a); +} + +static void SsePxor(void *b, const void *a) { + pxor(b, b, a); +} + +static void SsePand(void *b, const void *a) { + pand(b, b, a); +} + +static void SsePandn(void *b, const void *a) { + pandn(b, b, a); +} + +static void SsePsubusb(void *b, const void *a) { + psubusb(b, b, a); +} + +static void SsePsubusw(void *b, const void *a) { + psubusw(b, b, a); +} + +static void SsePminub(void *b, const void *a) { + pminub(b, b, a); +} + +static void SsePmaxub(void *b, const void *a) { + pmaxub(b, b, a); +} + +static void SsePminsw(void *b, const void *a) { + pminsw(b, b, a); +} + +static void SsePmaxsw(void *b, const void *a) { + pmaxsw(b, b, a); +} + +static void SsePunpcklbw(void *b, const void *a) { + punpcklbw(b, b, a); +} + +static void SsePunpckhbw(void *b, const void *a) { + punpckhbw(b, b, a); +} + +static void SsePunpcklwd(void *b, const void *a) { + punpcklwd(b, b, a); +} + +static void SsePunpckldq(void *b, const void *a) { + punpckldq(b, b, a); +} + +static void SsePunpckhwd(void *b, const void *a) { + punpckhwd(b, b, a); +} + +static void SsePunpckhdq(void *b, const void *a) { + punpckhdq(b, b, a); +} + +static void SsePunpcklqdq(void *b, const void *a) { + punpcklqdq(b, b, a); +} + +static void SsePunpckhqdq(void *b, const void *a) { + punpckhqdq(b, b, a); +} + +static void SsePacksswb(void *b, const void *a) { + packsswb(b, b, a); +} + +static void SsePackuswb(void *b, const void *a) { + packuswb(b, b, a); +} + +static void SsePackssdw(void *b, const void *a) { + packssdw(b, b, a); +} + +static void SsePcmpgtb(void *b, const void *a) { + pcmpgtb(b, b, a); +} + +static void SsePcmpgtw(void *b, const void *a) { + pcmpgtw(b, b, a); +} + +static void SsePcmpgtd(void *b, const void *a) { + pcmpgtd(b, b, a); +} + +static void SsePcmpeqb(void *b, const void *a) { + pcmpeqb(b, b, a); +} + +static void SsePcmpeqw(void *b, const void *a) { + pcmpeqw(b, b, a); +} + +static void SsePcmpeqd(void *b, const void *a) { + pcmpeqd(b, b, a); +} + +static void SsePsrawv(void *b, const void *a) { + psrawv(b, b, a); +} + +static void SsePsrlwv(void *b, const void *a) { + psrlwv(b, b, a); +} + +static void SsePsllwv(void *b, const void *a) { + psllwv(b, b, a); +} + +static void SsePsradv(void *b, const void *a) { + psradv(b, b, a); +} + +static void SsePsrldv(void *b, const void *a) { + psrldv(b, b, a); +} + +static void SsePslldv(void *b, const void *a) { + pslldv(b, b, a); +} + +static void SsePsrlqv(void *b, const void *a) { + psrlqv(b, b, a); +} + +static void SsePsllqv(void *b, const void *a) { + psllqv(b, b, a); +} + +static void SsePavgb(void *b, const void *a) { + pavgb(b, b, a); +} + +static void SsePavgw(void *b, const void *a) { + pavgw(b, b, a); +} + +static void SsePsadbw(void *b, const void *a) { + psadbw(b, b, a); +} + +static void SsePmaddwd(void *b, const void *a) { + pmaddwd(b, b, a); +} + +static void SsePmulhuw(void *b, const void *a) { + pmulhuw(b, b, a); +} + +static void SsePmulhw(void *b, const void *a) { + pmulhw(b, b, a); +} + +static void SsePmuludq(void *b, const void *a) { + pmuludq(b, b, a); +} + +static void SsePmullw(void *b, const void *a) { + pmullw(b, b, a); +} + +static void SsePmulld(void *b, const void *a) { + pmulld(b, b, a); +} + +static void SsePshufb(void *b, const void *a) { + pshufb(b, b, a); +} + +static void SsePhaddw(void *b, const void *a) { + phaddw(b, b, a); +} + +static void SsePhaddd(void *b, const void *a) { + phaddd(b, b, a); +} + +static void SsePhaddsw(void *b, const void *a) { + phaddsw(b, b, a); +} + +static void SsePmaddubsw(void *b, const void *a) { + pmaddubsw(b, b, a); +} + +static void SsePhsubw(void *b, const void *a) { + phsubw(b, b, a); +} + +static void SsePhsubd(void *b, const void *a) { + phsubd(b, b, a); +} + +static void SsePhsubsw(void *b, const void *a) { + phsubsw(b, b, a); +} + +static void SsePsignb(void *b, const void *a) { + psignb(b, b, a); +} + +static void SsePsignw(void *b, const void *a) { + psignw(b, b, a); +} + +static void SsePsignd(void *b, const void *a) { + psignd(b, b, a); +} + +static void SsePmulhrsw(void *b, const void *a) { + pmulhrsw(b, b, a); +} + +static void SsePabsb(void *b, const void *a) { + pabsb(b, a); +} + +static void SsePabsw(void *b, const void *a) { + pabsw(b, a); +} + +static void SsePabsd(void *b, const void *a) { + pabsd(b, a); +} + +static void OpSse(struct Machine *m, uint32_t rde, + void kernel(void *, const void *)) { + char x[16], y[16]; if (Osz(rde)) { - memcpy(&y, p, 16); + kernel(XmmRexrReg(m, rde), GetModrmRegisterXmmPointerRead16(m, rde)); } else { - memset(&y, 0, 16); - memcpy(&y, p, 8); - } - memcpy(&x, XmmRexrReg(m, rde), 16); - switch (kernel) { - CASE(kOpSsePsubb, psubb(x.i8, x.i8, y.i8)); - CASE(kOpSsePaddb, paddb(x.i8, x.i8, y.i8)); - CASE(kOpSsePsubw, psubw(x.i16, x.i16, y.i16)); - CASE(kOpSsePaddw, paddw(x.i16, x.i16, y.i16)); - CASE(kOpSsePsubd, psubd(x.i32, x.i32, y.i32)); - CASE(kOpSsePaddd, paddd(x.i32, x.i32, y.i32)); - CASE(kOpSsePaddq, paddq(x.i64, x.i64, y.i64)); - CASE(kOpSsePsubq, psubq(x.i64, x.i64, y.i64)); - CASE(kOpSsePsubsb, psubsb(x.i8, x.i8, y.i8)); - CASE(kOpSsePsubsw, psubsw(x.i16, x.i16, y.i16)); - CASE(kOpSsePaddsb, paddsb(x.i8, x.i8, y.i8)); - CASE(kOpSsePaddsw, paddsw(x.i16, x.i16, y.i16)); - CASE(kOpSsePaddusb, paddusb(x.u8, x.u8, y.u8)); - CASE(kOpSsePaddusw, paddusw(x.u16, x.u16, y.u16)); - CASE(kOpSsePor, por(x.u64, x.u64, y.u64)); - CASE(kOpSsePxor, pxor(x.u64, x.u64, y.u64)); - CASE(kOpSsePand, pand(x.u64, x.u64, y.u64)); - CASE(kOpSsePandn, pandn(x.u64, x.u64, y.u64)); - CASE(kOpSsePsubusb, psubusb(x.u8, x.u8, y.u8)); - CASE(kOpSsePsubusw, psubusw(x.u16, x.u16, y.u16)); - CASE(kOpSsePminub, pminub(x.u8, x.u8, y.u8)); - CASE(kOpSsePmaxub, pmaxub(x.u8, x.u8, y.u8)); - CASE(kOpSsePminsw, pminsw(x.i16, x.i16, y.i16)); - CASE(kOpSsePmaxsw, pmaxsw(x.i16, x.i16, y.i16)); - CASE(kOpSsePunpcklbw, punpcklbw(x.u8, x.u8, y.u8)); - CASE(kOpSsePunpckhbw, punpckhbw(x.u8, x.u8, y.u8)); - CASE(kOpSsePunpcklwd, punpcklwd(x.u16, x.u16, y.u16)); - CASE(kOpSsePunpckldq, punpckldq(x.u32, x.u32, y.u32)); - CASE(kOpSsePunpckhwd, punpckhwd(x.u16, x.u16, y.u16)); - CASE(kOpSsePunpckhdq, punpckhdq(x.u32, x.u32, y.u32)); - CASE(kOpSsePunpcklqdq, punpcklqdq(x.u64, x.u64, y.u64)); - CASE(kOpSsePunpckhqdq, punpckhqdq(x.u64, x.u64, y.u64)); - CASE(kOpSsePacksswb, packsswb(x.i8, x.i16, y.i16)); - CASE(kOpSsePackuswb, packuswb(x.u8, x.i16, y.i16)); - CASE(kOpSsePackssdw, packssdw(x.i16, x.i32, y.i32)); - CASE(kOpSsePcmpgtb, pcmpgtb(x.i8, x.i8, y.i8)); - CASE(kOpSsePcmpgtw, pcmpgtw(x.i16, x.i16, y.i16)); - CASE(kOpSsePcmpgtd, pcmpgtd(x.i32, x.i32, y.i32)); - CASE(kOpSsePcmpeqb, pcmpeqb(x.u8, x.u8, y.u8)); - CASE(kOpSsePcmpeqw, pcmpeqw(x.i16, x.i16, y.i16)); - CASE(kOpSsePcmpeqd, pcmpeqd(x.i32, x.i32, y.i32)); - CASE(kOpSsePsrawv, psrawv(x.i16, x.i16, y.u64)); - CASE(kOpSsePsrlwv, psrlwv(x.u16, x.u16, y.u64)); - CASE(kOpSsePsllwv, psllwv(x.u16, x.u16, y.u64)); - CASE(kOpSsePsradv, psradv(x.i32, x.i32, y.u64)); - CASE(kOpSsePsrldv, psrldv(x.u32, x.u32, y.u64)); - CASE(kOpSsePslldv, pslldv(x.u32, x.u32, y.u64)); - CASE(kOpSsePsrlqv, psrlqv(x.u64, x.u64, y.u64)); - CASE(kOpSsePsllqv, psllqv(x.u64, x.u64, y.u64)); - CASE(kOpSsePavgb, pavgb(x.u8, x.u8, y.u8)); - CASE(kOpSsePavgw, pavgw(x.u16, x.u16, y.u16)); - CASE(kOpSsePsadbw, psadbw(x.u64, x.u8, y.u8)); - CASE(kOpSsePmaddwd, pmaddwd(x.i32, x.i16, y.i16)); - CASE(kOpSsePmulhuw, pmulhuw(x.u16, x.u16, y.u16)); - CASE(kOpSsePmulhw, pmulhw(x.i16, x.i16, y.i16)); - CASE(kOpSsePmuludq, pmuludq(x.u64, x.u32, y.u32)); - CASE(kOpSsePmullw, pmullw(x.i16, x.i16, y.i16)); - CASE(kOpSsePmulld, pmulld(x.i32, x.i32, y.i32)); - CASE(kOpSsePshufb, pshufb(x.u8, x.u8, y.u8)); - CASE(kOpSsePhaddw, phaddw(x.i16, x.i16, y.i16)); - CASE(kOpSsePhaddd, phaddd(x.i32, x.i32, y.i32)); - CASE(kOpSsePhaddsw, phaddsw(x.i16, x.i16, y.i16)); - CASE(kOpSsePmaddubsw, pmaddubsw(x.i16, x.u8, y.i8)); - CASE(kOpSsePhsubw, phsubw(x.i16, x.i16, y.i16)); - CASE(kOpSsePhsubd, phsubd(x.i32, x.i32, y.i32)); - CASE(kOpSsePhsubsw, phsubsw(x.i16, x.i16, y.i16)); - CASE(kOpSsePsignb, psignb(x.i8, x.i8, y.i8)); - CASE(kOpSsePsignw, psignw(x.i16, x.i16, y.i16)); - CASE(kOpSsePsignd, psignd(x.i32, x.i32, y.i32)); - CASE(kOpSsePmulhrsw, pmulhrsw(x.i16, x.i16, y.i16)); - CASE(kOpSsePabsb, pabsb(x.u8, x.i8)); - CASE(kOpSsePabsw, pabsw(x.u16, x.i16)); - CASE(kOpSsePabsd, pabsd(x.u32, x.i32)); - default: - unreachable; - } - if (Osz(rde)) { - memcpy(XmmRexrReg(m, rde), &x, 16); - } else { - memcpy(XmmRexrReg(m, rde), &x, 8); + memcpy(x, XmmRexrReg(m, rde), 8); + memcpy(y, GetModrmRegisterXmmPointerRead16(m, rde), 8); + kernel(x, y); + memcpy(XmmRexrReg(m, rde), x, 8); } } +void OpSsePunpcklbw(struct Machine *m, uint32_t rde) { + OpSse(m, rde, SsePunpcklbw); +} + +void OpSsePunpcklwd(struct Machine *m, uint32_t rde) { + OpSse(m, rde, SsePunpcklwd); +} + +void OpSsePunpckldq(struct Machine *m, uint32_t rde) { + OpSse(m, rde, SsePunpckldq); +} + +void OpSsePacksswb(struct Machine *m, uint32_t rde) { + OpSse(m, rde, SsePacksswb); +} + +void OpSsePcmpgtb(struct Machine *m, uint32_t rde) { + OpSse(m, rde, SsePcmpgtb); +} + +void OpSsePcmpgtw(struct Machine *m, uint32_t rde) { + OpSse(m, rde, SsePcmpgtw); +} + +void OpSsePcmpgtd(struct Machine *m, uint32_t rde) { + OpSse(m, rde, SsePcmpgtd); +} + +void OpSsePackuswb(struct Machine *m, uint32_t rde) { + OpSse(m, rde, SsePackuswb); +} + +void OpSsePunpckhbw(struct Machine *m, uint32_t rde) { + OpSse(m, rde, SsePunpckhbw); +} + +void OpSsePunpckhwd(struct Machine *m, uint32_t rde) { + OpSse(m, rde, SsePunpckhwd); +} + +void OpSsePunpckhdq(struct Machine *m, uint32_t rde) { + OpSse(m, rde, SsePunpckhdq); +} + +void OpSsePackssdw(struct Machine *m, uint32_t rde) { + OpSse(m, rde, SsePackssdw); +} + +void OpSsePunpcklqdq(struct Machine *m, uint32_t rde) { + OpSse(m, rde, SsePunpcklqdq); +} + +void OpSsePunpckhqdq(struct Machine *m, uint32_t rde) { + OpSse(m, rde, SsePunpckhqdq); +} + +void OpSsePcmpeqb(struct Machine *m, uint32_t rde) { + OpSse(m, rde, SsePcmpeqb); +} + +void OpSsePcmpeqw(struct Machine *m, uint32_t rde) { + OpSse(m, rde, SsePcmpeqw); +} + +void OpSsePcmpeqd(struct Machine *m, uint32_t rde) { + OpSse(m, rde, SsePcmpeqd); +} + +void OpSsePsrlwv(struct Machine *m, uint32_t rde) { + OpSse(m, rde, SsePsrlwv); +} + +void OpSsePsrldv(struct Machine *m, uint32_t rde) { + OpSse(m, rde, SsePsrldv); +} + +void OpSsePsrlqv(struct Machine *m, uint32_t rde) { + OpSse(m, rde, SsePsrlqv); +} + +void OpSsePaddq(struct Machine *m, uint32_t rde) { + OpSse(m, rde, SsePaddq); +} + +void OpSsePmullw(struct Machine *m, uint32_t rde) { + OpSse(m, rde, SsePmullw); +} + +void OpSsePsubusb(struct Machine *m, uint32_t rde) { + OpSse(m, rde, SsePsubusb); +} + +void OpSsePsubusw(struct Machine *m, uint32_t rde) { + OpSse(m, rde, SsePsubusw); +} + +void OpSsePminub(struct Machine *m, uint32_t rde) { + OpSse(m, rde, SsePminub); +} + +void OpSsePand(struct Machine *m, uint32_t rde) { + OpSse(m, rde, SsePand); +} + +void OpSsePaddusb(struct Machine *m, uint32_t rde) { + OpSse(m, rde, SsePaddusb); +} + +void OpSsePaddusw(struct Machine *m, uint32_t rde) { + OpSse(m, rde, SsePaddusw); +} + +void OpSsePmaxub(struct Machine *m, uint32_t rde) { + OpSse(m, rde, SsePmaxub); +} + +void OpSsePandn(struct Machine *m, uint32_t rde) { + OpSse(m, rde, SsePandn); +} + +void OpSsePavgb(struct Machine *m, uint32_t rde) { + OpSse(m, rde, SsePavgb); +} + +void OpSsePsrawv(struct Machine *m, uint32_t rde) { + OpSse(m, rde, SsePsrawv); +} + +void OpSsePsradv(struct Machine *m, uint32_t rde) { + OpSse(m, rde, SsePsradv); +} + +void OpSsePavgw(struct Machine *m, uint32_t rde) { + OpSse(m, rde, SsePavgw); +} + +void OpSsePmulhuw(struct Machine *m, uint32_t rde) { + OpSse(m, rde, SsePmulhuw); +} + +void OpSsePmulhw(struct Machine *m, uint32_t rde) { + OpSse(m, rde, SsePmulhw); +} + +void OpSsePsubsb(struct Machine *m, uint32_t rde) { + OpSse(m, rde, SsePsubsb); +} + +void OpSsePsubsw(struct Machine *m, uint32_t rde) { + OpSse(m, rde, SsePsubsw); +} + +void OpSsePminsw(struct Machine *m, uint32_t rde) { + OpSse(m, rde, SsePminsw); +} + +void OpSsePor(struct Machine *m, uint32_t rde) { + OpSse(m, rde, SsePor); +} + +void OpSsePaddsb(struct Machine *m, uint32_t rde) { + OpSse(m, rde, SsePaddsb); +} + +void OpSsePaddsw(struct Machine *m, uint32_t rde) { + OpSse(m, rde, SsePaddsw); +} + +void OpSsePmaxsw(struct Machine *m, uint32_t rde) { + OpSse(m, rde, SsePmaxsw); +} + +void OpSsePxor(struct Machine *m, uint32_t rde) { + OpSse(m, rde, SsePxor); +} + +void OpSsePsllwv(struct Machine *m, uint32_t rde) { + OpSse(m, rde, SsePsllwv); +} + +void OpSsePslldv(struct Machine *m, uint32_t rde) { + OpSse(m, rde, SsePslldv); +} + +void OpSsePsllqv(struct Machine *m, uint32_t rde) { + OpSse(m, rde, SsePsllqv); +} + +void OpSsePmuludq(struct Machine *m, uint32_t rde) { + OpSse(m, rde, SsePmuludq); +} + +void OpSsePmaddwd(struct Machine *m, uint32_t rde) { + OpSse(m, rde, SsePmaddwd); +} + +void OpSsePsadbw(struct Machine *m, uint32_t rde) { + OpSse(m, rde, SsePsadbw); +} + +void OpSsePsubb(struct Machine *m, uint32_t rde) { + OpSse(m, rde, SsePsubb); +} + +void OpSsePsubw(struct Machine *m, uint32_t rde) { + OpSse(m, rde, SsePsubw); +} + +void OpSsePsubd(struct Machine *m, uint32_t rde) { + OpSse(m, rde, SsePsubd); +} + +void OpSsePsubq(struct Machine *m, uint32_t rde) { + OpSse(m, rde, SsePsubq); +} + +void OpSsePaddb(struct Machine *m, uint32_t rde) { + OpSse(m, rde, SsePaddb); +} + +void OpSsePaddw(struct Machine *m, uint32_t rde) { + OpSse(m, rde, SsePaddw); +} + +void OpSsePaddd(struct Machine *m, uint32_t rde) { + OpSse(m, rde, SsePaddd); +} + +void OpSsePshufb(struct Machine *m, uint32_t rde) { + OpSse(m, rde, SsePshufb); +} + +void OpSsePhaddw(struct Machine *m, uint32_t rde) { + OpSse(m, rde, SsePhaddw); +} + +void OpSsePhaddd(struct Machine *m, uint32_t rde) { + OpSse(m, rde, SsePhaddd); +} + +void OpSsePhaddsw(struct Machine *m, uint32_t rde) { + OpSse(m, rde, SsePhaddsw); +} + +void OpSsePmaddubsw(struct Machine *m, uint32_t rde) { + OpSse(m, rde, SsePmaddubsw); +} + +void OpSsePhsubw(struct Machine *m, uint32_t rde) { + OpSse(m, rde, SsePhsubw); +} + +void OpSsePhsubd(struct Machine *m, uint32_t rde) { + OpSse(m, rde, SsePhsubd); +} + +void OpSsePhsubsw(struct Machine *m, uint32_t rde) { + OpSse(m, rde, SsePhsubsw); +} + +void OpSsePsignb(struct Machine *m, uint32_t rde) { + OpSse(m, rde, SsePsignb); +} + +void OpSsePsignw(struct Machine *m, uint32_t rde) { + OpSse(m, rde, SsePsignw); +} + +void OpSsePsignd(struct Machine *m, uint32_t rde) { + OpSse(m, rde, SsePsignd); +} + +void OpSsePmulhrsw(struct Machine *m, uint32_t rde) { + OpSse(m, rde, SsePmulhrsw); +} + +void OpSsePabsb(struct Machine *m, uint32_t rde) { + OpSse(m, rde, SsePabsb); +} + +void OpSsePabsw(struct Machine *m, uint32_t rde) { + OpSse(m, rde, SsePabsw); +} + +void OpSsePabsd(struct Machine *m, uint32_t rde) { + OpSse(m, rde, SsePabsd); +} + +void OpSsePmulld(struct Machine *m, uint32_t rde) { + OpSse(m, rde, SsePmulld); +} + void OpSseUdqIb(struct Machine *m, uint32_t rde, enum OpSseUdqIbKernel kernel) { uint8_t i; union MachineVector x; diff --git a/tool/build/lib/sse.h b/tool/build/lib/sse.h index 78c40ccf..2fd84dcf 100644 --- a/tool/build/lib/sse.h +++ b/tool/build/lib/sse.h @@ -4,81 +4,7 @@ #if !(__ASSEMBLER__ + __LINKER__ + 0) COSMOPOLITAN_C_START_ -enum OpSseKernel { - kOpSsePaddb, - kOpSsePaddw, - kOpSsePaddd, - kOpSsePaddq, - kOpSsePsubb, - kOpSsePsubw, - kOpSsePsubd, - kOpSsePsubq, - kOpSsePaddsb, - kOpSsePaddsw, - kOpSsePaddusb, - kOpSsePaddusw, - kOpSsePsubsb, - kOpSsePsubsw, - kOpSsePor, - kOpSsePxor, - kOpSsePand, - kOpSsePandn, - kOpSsePsubusb, - kOpSsePsubusw, - kOpSsePminub, - kOpSsePmaxub, - kOpSsePminsw, - kOpSsePmaxsw, - kOpSsePunpcklbw, - kOpSsePunpckhbw, - kOpSsePunpcklwd, - kOpSsePunpckldq, - kOpSsePunpckhwd, - kOpSsePunpckhdq, - kOpSsePunpcklqdq, - kOpSsePunpckhqdq, - kOpSsePacksswb, - kOpSsePackuswb, - kOpSsePackssdw, - kOpSsePcmpgtb, - kOpSsePcmpgtw, - kOpSsePcmpgtd, - kOpSsePcmpeqb, - kOpSsePcmpeqw, - kOpSsePcmpeqd, - kOpSsePsrawv, - kOpSsePsradv, - kOpSsePsrlwv, - kOpSsePsrldv, - kOpSsePsrlqv, - kOpSsePsllwv, - kOpSsePslldv, - kOpSsePsllqv, - kOpSsePavgb, - kOpSsePavgw, - kOpSsePmulhuw, - kOpSsePmulhw, - kOpSsePmuludq, - kOpSsePmaddwd, - kOpSsePmullw, - kOpSsePmulld, - kOpSsePsadbw, - kOpSsePshufb, - kOpSsePhaddw, - kOpSsePhaddd, - kOpSsePhaddsw, - kOpSsePmaddubsw, - kOpSsePhsubw, - kOpSsePhsubd, - kOpSsePhsubsw, - kOpSsePsignb, - kOpSsePsignw, - kOpSsePsignd, - kOpSsePmulhrsw, - kOpSsePabsb, - kOpSsePabsw, - kOpSsePabsd, -}; +typedef void (*sse_f)(void *, void *, void *); enum OpSseUdqIbKernel { kOpSseUdqIbPsrlw, @@ -93,9 +19,81 @@ enum OpSseUdqIbKernel { kOpSseUdqIbPslldq, }; -void OpSse(struct Machine *, uint32_t, enum OpSseKernel); void OpSseUdqIb(struct Machine *, uint32_t, enum OpSseUdqIbKernel); void OpSsePalignr(struct Machine *, uint32_t); +void OpSsePunpcklbw(struct Machine *, uint32_t); +void OpSsePunpcklwd(struct Machine *, uint32_t); +void OpSsePunpckldq(struct Machine *, uint32_t); +void OpSsePacksswb(struct Machine *, uint32_t); +void OpSsePcmpgtb(struct Machine *, uint32_t); +void OpSsePcmpgtw(struct Machine *, uint32_t); +void OpSsePcmpgtd(struct Machine *, uint32_t); +void OpSsePackuswb(struct Machine *, uint32_t); +void OpSsePunpckhbw(struct Machine *, uint32_t); +void OpSsePunpckhwd(struct Machine *, uint32_t); +void OpSsePunpckhdq(struct Machine *, uint32_t); +void OpSsePackssdw(struct Machine *, uint32_t); +void OpSsePunpcklqdq(struct Machine *, uint32_t); +void OpSsePunpckhqdq(struct Machine *, uint32_t); +void OpSsePcmpeqb(struct Machine *, uint32_t); +void OpSsePcmpeqw(struct Machine *, uint32_t); +void OpSsePcmpeqd(struct Machine *, uint32_t); +void OpSsePsrlwv(struct Machine *, uint32_t); +void OpSsePsrldv(struct Machine *, uint32_t); +void OpSsePsrlqv(struct Machine *, uint32_t); +void OpSsePaddq(struct Machine *, uint32_t); +void OpSsePmullw(struct Machine *, uint32_t); +void OpSsePsubusb(struct Machine *, uint32_t); +void OpSsePsubusw(struct Machine *, uint32_t); +void OpSsePminub(struct Machine *, uint32_t); +void OpSsePand(struct Machine *, uint32_t); +void OpSsePaddusb(struct Machine *, uint32_t); +void OpSsePaddusw(struct Machine *, uint32_t); +void OpSsePmaxub(struct Machine *, uint32_t); +void OpSsePandn(struct Machine *, uint32_t); +void OpSsePavgb(struct Machine *, uint32_t); +void OpSsePsrawv(struct Machine *, uint32_t); +void OpSsePsradv(struct Machine *, uint32_t); +void OpSsePavgw(struct Machine *, uint32_t); +void OpSsePmulhuw(struct Machine *, uint32_t); +void OpSsePmulhw(struct Machine *, uint32_t); +void OpSsePsubsb(struct Machine *, uint32_t); +void OpSsePsubsw(struct Machine *, uint32_t); +void OpSsePminsw(struct Machine *, uint32_t); +void OpSsePor(struct Machine *, uint32_t); +void OpSsePaddsb(struct Machine *, uint32_t); +void OpSsePaddsw(struct Machine *, uint32_t); +void OpSsePmaxsw(struct Machine *, uint32_t); +void OpSsePxor(struct Machine *, uint32_t); +void OpSsePsllwv(struct Machine *, uint32_t); +void OpSsePslldv(struct Machine *, uint32_t); +void OpSsePsllqv(struct Machine *, uint32_t); +void OpSsePmuludq(struct Machine *, uint32_t); +void OpSsePmaddwd(struct Machine *, uint32_t); +void OpSsePsadbw(struct Machine *, uint32_t); +void OpSsePsubb(struct Machine *, uint32_t); +void OpSsePsubw(struct Machine *, uint32_t); +void OpSsePsubd(struct Machine *, uint32_t); +void OpSsePsubq(struct Machine *, uint32_t); +void OpSsePaddb(struct Machine *, uint32_t); +void OpSsePaddw(struct Machine *, uint32_t); +void OpSsePaddd(struct Machine *, uint32_t); +void OpSsePshufb(struct Machine *, uint32_t); +void OpSsePhaddw(struct Machine *, uint32_t); +void OpSsePhaddd(struct Machine *, uint32_t); +void OpSsePhaddsw(struct Machine *, uint32_t); +void OpSsePmaddubsw(struct Machine *, uint32_t); +void OpSsePhsubw(struct Machine *, uint32_t); +void OpSsePhsubd(struct Machine *, uint32_t); +void OpSsePhsubsw(struct Machine *, uint32_t); +void OpSsePsignb(struct Machine *, uint32_t); +void OpSsePsignw(struct Machine *, uint32_t); +void OpSsePsignd(struct Machine *, uint32_t); +void OpSsePmulhrsw(struct Machine *, uint32_t); +void OpSsePabsb(struct Machine *, uint32_t); +void OpSsePabsw(struct Machine *, uint32_t); +void OpSsePabsd(struct Machine *, uint32_t); +void OpSsePmulld(struct Machine *, uint32_t); COSMOPOLITAN_C_END_ #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ diff --git a/tool/build/lib/ssefloat.c b/tool/build/lib/ssefloat.c new file mode 100644 index 00000000..d1b23525 --- /dev/null +++ b/tool/build/lib/ssefloat.c @@ -0,0 +1,571 @@ +/*-*- 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 │ +│ │ +│ This program is free software; you can redistribute it and/or modify │ +│ it under the terms of the GNU General Public License as published by │ +│ the Free Software Foundation; version 2 of the License. │ +│ │ +│ This program is distributed in the hope that it will be useful, but │ +│ WITHOUT ANY WARRANTY; without even the implied warranty of │ +│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │ +│ General Public License for more details. │ +│ │ +│ You should have received a copy of the GNU General Public License │ +│ along with this program; if not, write to the Free Software │ +│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │ +│ 02110-1301 USA │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/dce.h" +#include "libc/intrin/pshufd.h" +#include "libc/intrin/pshufhw.h" +#include "libc/intrin/pshuflw.h" +#include "libc/intrin/pshufw.h" +#include "libc/intrin/shufpd.h" +#include "libc/intrin/shufps.h" +#include "libc/macros.h" +#include "libc/math.h" +#include "libc/str/str.h" +#include "tool/build/lib/endian.h" +#include "tool/build/lib/flags.h" +#include "tool/build/lib/modrm.h" +#include "tool/build/lib/ssefloat.h" +#include "tool/build/lib/throw.h" + +#define SSE_BUILTINS \ + (!IsModeDbg() && __SSE3__ + 0 && \ + (__GNUC__ + 0) * 100 + (__GNUC_MINOR__ + 0) >= 408) + +typedef int int_v _Vector_size(16) aligned(16); +typedef long long_v _Vector_size(16) aligned(16); + +static float_v Addps(struct Machine *m, float_v x, float_v y) { + return x + y; +} + +static double_v Addpd(struct Machine *m, double_v x, double_v y) { + return x + y; +} + +static float_v Mulps(struct Machine *m, float_v x, float_v y) { + return x * y; +} + +static double_v Mulpd(struct Machine *m, double_v x, double_v y) { + return x * y; +} + +static float_v Subps(struct Machine *m, float_v x, float_v y) { + return x - y; +} + +static double_v Subpd(struct Machine *m, double_v x, double_v y) { + return x - y; +} + +static float_v Divps(struct Machine *m, float_v x, float_v y) { + return x / y; +} + +static double_v Divpd(struct Machine *m, double_v x, double_v y) { + return x / y; +} + +static float_v Andps(struct Machine *m, float_v x, float_v y) { + return (float_v)((int_v)x & (int_v)y); +} + +static double_v Andpd(struct Machine *m, double_v x, double_v y) { + return (double_v)((long_v)x & (long_v)y); +} + +static float_v Andnps(struct Machine *m, float_v x, float_v y) { + return (float_v)(~(int_v)x & (int_v)y); +} + +static double_v Andnpd(struct Machine *m, double_v x, double_v y) { + return (double_v)(~(long_v)x & (long_v)y); +} + +static float_v Orps(struct Machine *m, float_v x, float_v y) { + return (float_v)((int_v)x | (int_v)y); +} + +static double_v Orpd(struct Machine *m, double_v x, double_v y) { + return (double_v)((long_v)x | (long_v)y); +} + +static float_v Xorps(struct Machine *m, float_v x, float_v y) { + return (float_v)((int_v)x ^ (int_v)y); +} + +static double_v Xorpd(struct Machine *m, double_v x, double_v y) { + return (double_v)((long_v)x ^ (long_v)y); +} + +static float_v Minps(struct Machine *m, float_v x, float_v y) { +#if SSE_BUILTINS + return __builtin_ia32_minps(x, y); +#else + unsigned i; + for (i = 0; i < 4; ++i) { + x[i] = MIN(x[i], y[i]); + } + return x; +#endif +} + +static double_v Minpd(struct Machine *m, double_v x, double_v y) { +#if SSE_BUILTINS + return __builtin_ia32_minpd(x, y); +#else + unsigned i; + for (i = 0; i < 2; ++i) { + x[i] = MIN(x[i], y[i]); + } + return x; +#endif +} + +static float_v Maxps(struct Machine *m, float_v x, float_v y) { +#if SSE_BUILTINS + return __builtin_ia32_maxps(x, y); +#else + unsigned i; + for (i = 0; i < 4; ++i) { + x[i] = MAX(x[i], y[i]); + } + return x; +#endif +} + +static double_v Maxpd(struct Machine *m, double_v x, double_v y) { +#if SSE_BUILTINS + return __builtin_ia32_maxpd(x, y); +#else + unsigned i; + for (i = 0; i < 2; ++i) { + x[i] = MAX(x[i], y[i]); + } + return x; +#endif +} + +static double_v Haddpd(struct Machine *m, double_v x, double_v y) { +#if SSE_BUILTINS + return __builtin_ia32_haddpd(x, y); +#else + return (double_v){x[0] + x[1], y[0] + y[1]}; +#endif +} + +static float_v Haddps(struct Machine *m, float_v x, float_v y) { +#if SSE_BUILTINS + return __builtin_ia32_haddps(x, y); +#else + return (float_v){x[0] + x[1], x[2] + x[3], y[0] + y[1], y[2] + y[3]}; +#endif +} + +static double_v Hsubpd(struct Machine *m, double_v x, double_v y) { +#if SSE_BUILTINS + return __builtin_ia32_hsubpd(x, y); +#else + return (double_v){x[0] - x[1], y[0] - y[1]}; +#endif +} + +static float_v Hsubps(struct Machine *m, float_v x, float_v y) { +#if SSE_BUILTINS + return __builtin_ia32_hsubps(x, y); +#else + return (float_v){x[0] - x[1], x[2] - x[3], y[0] - y[1], y[2] - y[3]}; +#endif +} + +static double_v Addsubpd(struct Machine *m, double_v x, double_v y) { +#if SSE_BUILTINS + return __builtin_ia32_addsubpd(x, y); +#else + return (double_v){x[0] - y[0], x[1] + y[1]}; +#endif +} + +static float_v Addsubps(struct Machine *m, float_v x, float_v y) { +#if SSE_BUILTINS + return __builtin_ia32_addsubps(x, y); +#else + return (float_v){x[0] - y[0], x[1] + y[1], x[2] - y[2], x[3] + y[3]}; +#endif +} + +void OpUnpcklpsd(struct Machine *m, uint32_t rde) { + uint8_t *a, *b; + a = XmmRexrReg(m, rde); + b = GetModrmRegisterXmmPointerRead8(m, rde); + if (Osz(rde)) { + memcpy(a + 8, b, 8); + } else { + memcpy(a + 4 * 3, b + 4, 4); + memcpy(a + 4 * 2, a + 4, 4); + memcpy(a + 4 * 1, b + 0, 4); + } +} + +void OpUnpckhpsd(struct Machine *m, uint32_t rde) { + uint8_t *a, *b; + a = XmmRexrReg(m, rde); + b = GetModrmRegisterXmmPointerRead16(m, rde); + if (Osz(rde)) { + memcpy(a + 0, b + 8, 8); + memcpy(a + 8, b + 8, 8); + } else { + memcpy(a + 4 * 0, a + 4 * 2, 4); + memcpy(a + 4 * 1, b + 4 * 2, 4); + memcpy(a + 4 * 2, a + 4 * 3, 4); + memcpy(a + 4 * 3, b + 4 * 3, 4); + } +} + +void OpPextrwGdqpUdqIb(struct Machine *m, uint32_t rde) { + uint8_t i; + i = m->xedd->op.uimm0; + i &= Osz(rde) ? 7 : 3; + Write16(RegRexrReg(m, rde), Read16(XmmRexbRm(m, rde) + i * 2)); +} + +void OpPinsrwVdqEwIb(struct Machine *m, uint32_t rde) { + uint8_t i; + i = m->xedd->op.uimm0; + i &= Osz(rde) ? 7 : 3; + Write16(XmmRexrReg(m, rde) + i * 2, + Read16(GetModrmRegisterWordPointerRead2(m, rde))); +} + +void OpShuffle(struct Machine *m, uint32_t rde) { + int16_t q16[4]; + int16_t x16[8]; + int32_t x32[4]; + switch (Rep(rde) | Osz(rde)) { + case 0: + memcpy(q16, GetModrmRegisterXmmPointerRead8(m, rde), 8); + (pshufw)(q16, q16, m->xedd->op.uimm0); + memcpy(XmmRexrReg(m, rde), q16, 8); + break; + case 1: + memcpy(x32, GetModrmRegisterXmmPointerRead16(m, rde), 16); + (pshufd)(x32, x32, m->xedd->op.uimm0); + memcpy(XmmRexrReg(m, rde), x32, 16); + break; + case 2: + memcpy(x16, GetModrmRegisterXmmPointerRead16(m, rde), 16); + (pshuflw)(x16, x16, m->xedd->op.uimm0); + memcpy(XmmRexrReg(m, rde), x16, 16); + break; + case 3: + memcpy(x16, GetModrmRegisterXmmPointerRead16(m, rde), 16); + (pshufhw)(x16, x16, m->xedd->op.uimm0); + memcpy(XmmRexrReg(m, rde), x16, 16); + break; + default: + unreachable; + } +} + +static void Shufps(struct Machine *m, uint32_t rde) { + shufps((void *)XmmRexrReg(m, rde), (void *)XmmRexrReg(m, rde), + (void *)GetModrmRegisterXmmPointerRead16(m, rde), m->xedd->op.uimm0); +} + +static void Shufpd(struct Machine *m, uint32_t rde) { + shufpd((void *)XmmRexrReg(m, rde), (void *)XmmRexrReg(m, rde), + (void *)GetModrmRegisterXmmPointerRead16(m, rde), m->xedd->op.uimm0); +} + +void OpShufpsd(struct Machine *m, uint32_t rde) { + if (Osz(rde)) { + Shufpd(m, rde); + } else { + Shufps(m, rde); + } +} + +void OpSqrtpsd(struct Machine *m, uint32_t rde) { + long i; + float_v xf; + double_v xd; + switch (Rep(rde) | Osz(rde)) { + case 0: + memcpy(&xf, GetModrmRegisterXmmPointerRead16(m, rde), 16); + for (i = 0; i < 4; ++i) xf[i] = sqrtf(xf[i]); + memcpy(XmmRexrReg(m, rde), &xf, 16); + break; + case 1: + memcpy(&xd, GetModrmRegisterXmmPointerRead16(m, rde), 16); + for (i = 0; i < 2; ++i) xd[i] = sqrt(xd[i]); + memcpy(XmmRexrReg(m, rde), &xd, 16); + break; + case 2: + memcpy(&xd, GetModrmRegisterXmmPointerRead8(m, rde), 8); + xd[0] = sqrt(xd[0]); + memcpy(XmmRexrReg(m, rde), &xd, 8); + break; + case 3: + memcpy(&xf, GetModrmRegisterXmmPointerRead4(m, rde), 4); + xf[0] = sqrtf(xf[0]); + memcpy(XmmRexrReg(m, rde), &xf, 4); + break; + default: + unreachable; + } +} + +void OpRsqrtps(struct Machine *m, uint32_t rde) { + float_v x; + unsigned i; + if (Rep(rde) != 3) { + memcpy(&x, GetModrmRegisterXmmPointerRead16(m, rde), 16); + for (i = 0; i < 4; ++i) x[i] = 1.f / sqrtf(x[i]); + memcpy(XmmRexrReg(m, rde), &x, 16); + } else { + memcpy(&x, GetModrmRegisterXmmPointerRead4(m, rde), 4); + x[0] = 1.f / sqrtf(x[0]); + memcpy(XmmRexrReg(m, rde), &x, 4); + } +} + +void OpRcpps(struct Machine *m, uint32_t rde) { + float_v x; + unsigned i; + if (Rep(rde) != 3) { + memcpy(&x, GetModrmRegisterXmmPointerRead16(m, rde), 16); + for (i = 0; i < 4; ++i) x[i] = 1.f / x[i]; + memcpy(XmmRexrReg(m, rde), &x, 16); + } else { + memcpy(&x, GetModrmRegisterXmmPointerRead4(m, rde), 4); + x[0] = 1.f / x[0]; + memcpy(XmmRexrReg(m, rde), &x, 4); + } +} + +static void VpsdWpsd(struct Machine *m, uint32_t rde, + float_v opf(struct Machine *, float_v, float_v), + double_v opd(struct Machine *, double_v, double_v), + bool isfloat, bool isdouble) { + float_v xf, yf; + double_v xd, yd; + if (isfloat) { + memcpy(&xf, XmmRexrReg(m, rde), 16); + memcpy(&yf, GetModrmRegisterXmmPointerRead16(m, rde), 16); + xf = opf(m, xf, yf); + memcpy(XmmRexrReg(m, rde), &xf, 16); + } else if (isdouble) { + memcpy(&xd, XmmRexrReg(m, rde), 16); + memcpy(&yd, GetModrmRegisterXmmPointerRead16(m, rde), 16); + xd = opd(m, xd, yd); + memcpy(XmmRexrReg(m, rde), &xd, 16); + } else { + OpUd(m, rde); + } +} + +static void VpsdWpsd66(struct Machine *m, uint32_t rde, + float_v opf(struct Machine *, float_v, float_v), + double_v opd(struct Machine *, double_v, double_v)) { + VpsdWpsd(m, rde, opf, opd, !Osz(rde), Osz(rde)); +} + +static void VpsdWpsd66f2(struct Machine *m, uint32_t rde, + float_v opf(struct Machine *, float_v, float_v), + double_v opd(struct Machine *, double_v, double_v)) { + VpsdWpsd(m, rde, opf, opd, Rep(rde) == 2, Osz(rde)); +} + +static void VspsdWspsd(struct Machine *m, uint32_t rde, + float_v opf(struct Machine *, float_v, float_v), + double_v opd(struct Machine *, double_v, double_v)) { + float_v xf, yf; + double_v xd, yd; + switch (Rep(rde) | Osz(rde)) { + case 0: + memcpy(&yf, GetModrmRegisterXmmPointerRead16(m, rde), 16); + memcpy(&xf, XmmRexrReg(m, rde), 16); + xf = opf(m, xf, yf); + memcpy(XmmRexrReg(m, rde), &xf, 16); + break; + case 1: + memcpy(&yd, GetModrmRegisterXmmPointerRead16(m, rde), 16); + memcpy(&xd, XmmRexrReg(m, rde), 16); + xd = opd(m, xd, yd); + memcpy(XmmRexrReg(m, rde), &xd, 16); + break; + case 2: + memcpy(&yd, GetModrmRegisterXmmPointerRead8(m, rde), 8); + memcpy(&xd, XmmRexrReg(m, rde), 8); + xd = opd(m, xd, yd); + memcpy(XmmRexrReg(m, rde), &xd, 8); + break; + case 3: + memcpy(&yf, GetModrmRegisterXmmPointerRead4(m, rde), 4); + memcpy(&xf, XmmRexrReg(m, rde), 4); + xf = opf(m, xf, yf); + memcpy(XmmRexrReg(m, rde), &xf, 4); + break; + default: + unreachable; + } +} + +void OpComissVsWs(struct Machine *m, uint32_t rde) { + float xf, yf; + double xd, yd; + uint8_t zf, cf, pf, ie; + if (!Osz(rde)) { + memcpy(&xf, XmmRexrReg(m, rde), 4); + memcpy(&yf, GetModrmRegisterXmmPointerRead4(m, rde), 4); + if (!isnan(xf) && !isnan(yf)) { + zf = xf == yf; + cf = xf < yf; + pf = false; + ie = false; + } else { + zf = cf = pf = ie = true; + } + } else { + memcpy(&xd, XmmRexrReg(m, rde), 8); + memcpy(&yd, GetModrmRegisterXmmPointerRead8(m, rde), 8); + if (!isnan(xd) && !isnan(yd)) { + zf = xd == yd; + cf = xd < yd; + pf = false; + ie = false; + } else { + zf = cf = pf = ie = true; + } + } + m->flags = SetFlag(m->flags, FLAGS_ZF, zf); + m->flags = SetFlag(m->flags, FLAGS_PF, pf); + m->flags = SetFlag(m->flags, FLAGS_CF, cf); + m->flags = SetFlag(m->flags, FLAGS_SF, false); + m->flags = SetFlag(m->flags, FLAGS_OF, false); + if ((m->xedd->op.opcode & 1) && (m->sse.ie = ie) && !m->sse.im) { + HaltMachine(m, kMachineSimdException); + } +} + +static float_v Cmpps(struct Machine *m, float_v x, float_v y) { + long i; + switch (m->xedd->op.uimm0) { + case 0: + return x == y; + case 1: + return x < y; + case 2: + return x <= y; + case 3: + for (i = 0; i < 4; ++i) { + x[i] = isnan(x[i]) || isnan(y[i]); + } + return x; + case 4: + return x != y; + case 5: + return x >= y; + case 6: + return x > y; + case 7: + for (i = 0; i < 4; ++i) { + x[i] = !(isnan(x[i]) || isnan(y[i])); + } + return x; + default: + OpUd(m, 0); + } +} + +static double_v Cmppd(struct Machine *m, double_v x, double_v y) { + long i; + switch (m->xedd->op.uimm0) { + case 0: + return x == y; + case 1: + return x < y; + case 2: + return x <= y; + case 3: + for (i = 0; i < 2; ++i) { + x[i] = isnan(x[i]) || isnan(y[i]); + } + return x; + case 4: + return x != y; + case 5: + return x >= y; + case 6: + return x > y; + case 7: + for (i = 0; i < 2; ++i) { + x[i] = !(isnan(x[i]) || isnan(y[i])); + } + return x; + default: + OpUd(m, 0); + } +} + +void OpAddpsd(struct Machine *m, uint32_t rde) { + VspsdWspsd(m, rde, Addps, Addpd); +} + +void OpMulpsd(struct Machine *m, uint32_t rde) { + VspsdWspsd(m, rde, Mulps, Mulpd); +} + +void OpSubpsd(struct Machine *m, uint32_t rde) { + VspsdWspsd(m, rde, Subps, Subpd); +} + +void OpDivpsd(struct Machine *m, uint32_t rde) { + VspsdWspsd(m, rde, Divps, Divpd); +} + +void OpMinpsd(struct Machine *m, uint32_t rde) { + VspsdWspsd(m, rde, Minps, Minpd); +} + +void OpMaxpsd(struct Machine *m, uint32_t rde) { + VspsdWspsd(m, rde, Maxps, Maxpd); +} + +void OpCmppsd(struct Machine *m, uint32_t rde) { + VspsdWspsd(m, rde, Cmpps, Cmppd); +} + +void OpAndpsd(struct Machine *m, uint32_t rde) { + VpsdWpsd66(m, rde, Andps, Andpd); +} + +void OpAndnpsd(struct Machine *m, uint32_t rde) { + VpsdWpsd66(m, rde, Andnps, Andnpd); +} + +void OpOrpsd(struct Machine *m, uint32_t rde) { + VpsdWpsd66(m, rde, Orps, Orpd); +} + +void OpXorpsd(struct Machine *m, uint32_t rde) { + VpsdWpsd66(m, rde, Xorps, Xorpd); +} + +void OpHaddpsd(struct Machine *m, uint32_t rde) { + VpsdWpsd66f2(m, rde, Haddps, Haddpd); +} + +void OpHsubpsd(struct Machine *m, uint32_t rde) { + VpsdWpsd66f2(m, rde, Hsubps, Hsubpd); +} + +void OpAddsubpsd(struct Machine *m, uint32_t rde) { + VpsdWpsd66f2(m, rde, Addsubps, Addsubpd); +} diff --git a/tool/build/lib/ssefloat.h b/tool/build/lib/ssefloat.h new file mode 100644 index 00000000..68a9bebc --- /dev/null +++ b/tool/build/lib/ssefloat.h @@ -0,0 +1,37 @@ +#ifndef COSMOPOLITAN_TOOL_BUILD_LIB_SSEFLOAT_H_ +#define COSMOPOLITAN_TOOL_BUILD_LIB_SSEFLOAT_H_ +#include "tool/build/lib/machine.h" +#if !(__ASSEMBLER__ + __LINKER__ + 0) +COSMOPOLITAN_C_START_ + +typedef float float_v _Vector_size(16) aligned(16); +typedef double double_v _Vector_size(16) aligned(16); + +void OpUnpcklpsd(struct Machine *, uint32_t); +void OpUnpckhpsd(struct Machine *, uint32_t); +void OpPextrwGdqpUdqIb(struct Machine *, uint32_t); +void OpPinsrwVdqEwIb(struct Machine *, uint32_t); +void OpShuffle(struct Machine *, uint32_t); +void OpShufpsd(struct Machine *, uint32_t); +void OpSqrtpsd(struct Machine *, uint32_t); +void OpRsqrtps(struct Machine *, uint32_t); +void OpRcpps(struct Machine *, uint32_t); +void OpComissVsWs(struct Machine *, uint32_t); +void OpAddpsd(struct Machine *, uint32_t); +void OpMulpsd(struct Machine *, uint32_t); +void OpSubpsd(struct Machine *, uint32_t); +void OpDivpsd(struct Machine *, uint32_t); +void OpMinpsd(struct Machine *, uint32_t); +void OpMaxpsd(struct Machine *, uint32_t); +void OpCmppsd(struct Machine *, uint32_t); +void OpAndpsd(struct Machine *, uint32_t); +void OpAndnpsd(struct Machine *, uint32_t); +void OpOrpsd(struct Machine *, uint32_t); +void OpXorpsd(struct Machine *, uint32_t); +void OpHaddpsd(struct Machine *, uint32_t); +void OpHsubpsd(struct Machine *, uint32_t); +void OpAddsubpsd(struct Machine *, uint32_t); + +COSMOPOLITAN_C_END_ +#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ +#endif /* COSMOPOLITAN_TOOL_BUILD_LIB_SSEFLOAT_H_ */ diff --git a/tool/build/lib/ssemov.c b/tool/build/lib/ssemov.c new file mode 100644 index 00000000..a56b39b3 --- /dev/null +++ b/tool/build/lib/ssemov.c @@ -0,0 +1,522 @@ +/*-*- 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 │ +│ │ +│ This program is free software; you can redistribute it and/or modify │ +│ it under the terms of the GNU General Public License as published by │ +│ the Free Software Foundation; version 2 of the License. │ +│ │ +│ This program is distributed in the hope that it will be useful, but │ +│ WITHOUT ANY WARRANTY; without even the implied warranty of │ +│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │ +│ General Public License for more details. │ +│ │ +│ You should have received a copy of the GNU General Public License │ +│ along with this program; if not, write to the Free Software │ +│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │ +│ 02110-1301 USA │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/str/str.h" +#include "tool/build/lib/address.h" +#include "tool/build/lib/endian.h" +#include "tool/build/lib/memory.h" +#include "tool/build/lib/modrm.h" +#include "tool/build/lib/ssemov.h" +#include "tool/build/lib/throw.h" + +static void MovdquVdqWdq(struct Machine *m, uint32_t rde) { + memcpy(XmmRexrReg(m, rde), GetModrmRegisterXmmPointerRead16(m, rde), 16); +} + +static void MovdquWdqVdq(struct Machine *m, uint32_t rde) { + memcpy(GetModrmRegisterXmmPointerWrite16(m, rde), XmmRexrReg(m, rde), 16); +} + +static void MovupsVpsWps(struct Machine *m, uint32_t rde) { + MovdquVdqWdq(m, rde); +} + +static void MovupsWpsVps(struct Machine *m, uint32_t rde) { + MovdquWdqVdq(m, rde); +} + +static void MovupdVpsWps(struct Machine *m, uint32_t rde) { + MovdquVdqWdq(m, rde); +} + +static void MovupdWpsVps(struct Machine *m, uint32_t rde) { + MovdquWdqVdq(m, rde); +} + +void OpLddquVdqMdq(struct Machine *m, uint32_t rde) { + MovdquVdqWdq(m, rde); +} + +void OpMovntiMdqpGdqp(struct Machine *m, uint32_t rde) { + if (Rexw(rde)) { + memcpy(ComputeReserveAddressWrite8(m, rde), XmmRexrReg(m, rde), 8); + } else { + memcpy(ComputeReserveAddressWrite4(m, rde), XmmRexrReg(m, rde), 4); + } +} + +static void MovdqaVdqMdq(struct Machine *m, uint32_t rde) { + int64_t v; + uint8_t *p; + v = ComputeAddress(m, rde); + SetReadAddr(m, v, 16); + if ((v & 15) || !(p = FindReal(m, v))) ThrowSegmentationFault(m, v); + memcpy(XmmRexrReg(m, rde), Abp16(p), 16); +} + +static void MovdqaMdqVdq(struct Machine *m, uint32_t rde) { + int64_t v; + uint8_t *p; + v = ComputeAddress(m, rde); + SetWriteAddr(m, v, 16); + if ((v & 15) || !(p = FindReal(m, v))) ThrowSegmentationFault(m, v); + memcpy(Abp16(p), XmmRexrReg(m, rde), 16); +} + +static void MovdqaVdqWdq(struct Machine *m, uint32_t rde) { + if (IsModrmRegister(rde)) { + memcpy(XmmRexrReg(m, rde), XmmRexbRm(m, rde), 16); + } else { + MovdqaVdqMdq(m, rde); + } +} + +static void MovdqaWdqVdq(struct Machine *m, uint32_t rde) { + if (IsModrmRegister(rde)) { + memcpy(XmmRexbRm(m, rde), XmmRexrReg(m, rde), 16); + } else { + MovdqaMdqVdq(m, rde); + } +} + +static void MovntdqMdqVdq(struct Machine *m, uint32_t rde) { + MovdqaMdqVdq(m, rde); +} + +static void MovntpsMpsVps(struct Machine *m, uint32_t rde) { + MovdqaMdqVdq(m, rde); +} + +static void MovntpdMpdVpd(struct Machine *m, uint32_t rde) { + MovdqaMdqVdq(m, rde); +} + +void OpMovntdqaVdqMdq(struct Machine *m, uint32_t rde) { + MovdqaVdqMdq(m, rde); +} + +static void MovqPqQq(struct Machine *m, uint32_t rde) { + memcpy(MmReg(m, rde), GetModrmRegisterMmPointerRead8(m, rde), 8); +} + +static void MovqQqPq(struct Machine *m, uint32_t rde) { + memcpy(GetModrmRegisterMmPointerWrite8(m, rde), MmReg(m, rde), 8); +} + +static void MovqVdqEqp(struct Machine *m, uint32_t rde) { + memcpy(XmmRexrReg(m, rde), GetModrmRegisterWordPointerRead8(m, rde), 8); + memset(XmmRexrReg(m, rde) + 8, 0, 8); +} + +static void MovdVdqEd(struct Machine *m, uint32_t rde) { + memset(XmmRexrReg(m, rde), 0, 16); + memcpy(XmmRexrReg(m, rde), GetModrmRegisterWordPointerRead4(m, rde), 4); +} + +static void MovqPqEqp(struct Machine *m, uint32_t rde) { + memcpy(MmReg(m, rde), GetModrmRegisterWordPointerRead8(m, rde), 8); +} + +static void MovdPqEd(struct Machine *m, uint32_t rde) { + memcpy(MmReg(m, rde), GetModrmRegisterWordPointerRead4(m, rde), 4); + memset(MmReg(m, rde) + 4, 0, 4); +} + +static void MovdEdVdq(struct Machine *m, uint32_t rde) { + if (IsModrmRegister(rde)) { + Write64(RegRexbRm(m, rde), Read32(XmmRexrReg(m, rde))); + } else { + memcpy(ComputeReserveAddressWrite4(m, rde), XmmRexrReg(m, rde), 4); + } +} + +static void MovqEqpVdq(struct Machine *m, uint32_t rde) { + memcpy(GetModrmRegisterWordPointerWrite8(m, rde), XmmRexrReg(m, rde), 8); +} + +static void MovdEdPq(struct Machine *m, uint32_t rde) { + if (IsModrmRegister(rde)) { + Write64(RegRexbRm(m, rde), Read32(MmReg(m, rde))); + } else { + memcpy(ComputeReserveAddressWrite4(m, rde), MmReg(m, rde), 4); + } +} + +static void MovqEqpPq(struct Machine *m, uint32_t rde) { + memcpy(GetModrmRegisterWordPointerWrite(m, rde, 8), MmReg(m, rde), 8); +} + +static void MovntqMqPq(struct Machine *m, uint32_t rde) { + memcpy(ComputeReserveAddressWrite8(m, rde), MmReg(m, rde), 8); +} + +static void MovqVqWq(struct Machine *m, uint32_t rde) { + memcpy(XmmRexrReg(m, rde), GetModrmRegisterXmmPointerRead8(m, rde), 8); + memset(XmmRexrReg(m, rde) + 8, 0, 8); +} + +static void MovssVpsWps(struct Machine *m, uint32_t rde) { + memcpy(XmmRexrReg(m, rde), GetModrmRegisterXmmPointerRead4(m, rde), 4); +} + +static void MovssWpsVps(struct Machine *m, uint32_t rde) { + memcpy(GetModrmRegisterXmmPointerWrite4(m, rde), XmmRexrReg(m, rde), 4); +} + +static void MovsdVpsWps(struct Machine *m, uint32_t rde) { + memcpy(XmmRexrReg(m, rde), GetModrmRegisterXmmPointerRead16(m, rde), 8); +} + +static void MovsdWpsVps(struct Machine *m, uint32_t rde) { + memcpy(GetModrmRegisterXmmPointerWrite16(m, rde), XmmRexrReg(m, rde), 8); +} + +static void MovhlpsVqUq(struct Machine *m, uint32_t rde) { + memcpy(XmmRexrReg(m, rde), XmmRexbRm(m, rde) + 8, 8); +} + +static void MovlpsVqMq(struct Machine *m, uint32_t rde) { + memcpy(XmmRexrReg(m, rde), ComputeReserveAddressRead8(m, rde), 8); +} + +static void MovlpdVqMq(struct Machine *m, uint32_t rde) { + memcpy(XmmRexrReg(m, rde), ComputeReserveAddressRead8(m, rde), 8); +} + +static void MovddupVqWq(struct Machine *m, uint32_t rde) { + uint8_t *src; + src = GetModrmRegisterXmmPointerRead8(m, rde); + memcpy(XmmRexrReg(m, rde) + 0, src, 8); + memcpy(XmmRexrReg(m, rde) + 8, src, 8); +} + +static void MovsldupVqWq(struct Machine *m, uint32_t rde) { + uint8_t *dst, *src; + dst = XmmRexrReg(m, rde); + src = GetModrmRegisterXmmPointerRead16(m, rde); + memcpy(dst + 0 + 0, src + 0, 4); + memcpy(dst + 0 + 4, src + 0, 4); + memcpy(dst + 8 + 0, src + 8, 4); + memcpy(dst + 8 + 4, src + 8, 4); +} + +static void MovlpsMqVq(struct Machine *m, uint32_t rde) { + memcpy(ComputeReserveAddressWrite8(m, rde), XmmRexrReg(m, rde), 8); +} + +static void MovlpdMqVq(struct Machine *m, uint32_t rde) { + memcpy(ComputeReserveAddressWrite8(m, rde), XmmRexrReg(m, rde), 8); +} + +static void MovlhpsVqUq(struct Machine *m, uint32_t rde) { + memcpy(XmmRexrReg(m, rde) + 8, XmmRexbRm(m, rde), 8); +} + +static void MovhpsVqMq(struct Machine *m, uint32_t rde) { + memcpy(XmmRexrReg(m, rde) + 8, ComputeReserveAddressRead8(m, rde), 8); +} + +static void MovhpdVqMq(struct Machine *m, uint32_t rde) { + memcpy(XmmRexrReg(m, rde) + 8, ComputeReserveAddressRead8(m, rde), 8); +} + +static void MovshdupVqWq(struct Machine *m, uint32_t rde) { + uint8_t *dst, *src; + dst = XmmRexrReg(m, rde); + src = GetModrmRegisterXmmPointerRead16(m, rde); + memcpy(dst + 0 + 0, src + 04, 4); + memcpy(dst + 0 + 4, src + 04, 4); + memcpy(dst + 8 + 0, src + 12, 4); + memcpy(dst + 8 + 4, src + 12, 4); +} + +static void MovhpsMqVq(struct Machine *m, uint32_t rde) { + memcpy(ComputeReserveAddressWrite8(m, rde), XmmRexrReg(m, rde) + 8, 8); +} + +static void MovhpdMqVq(struct Machine *m, uint32_t rde) { + memcpy(ComputeReserveAddressWrite8(m, rde), XmmRexrReg(m, rde) + 8, 8); +} + +static void MovqWqVq(struct Machine *m, uint32_t rde) { + if (IsModrmRegister(rde)) { + memcpy(XmmRexbRm(m, rde), XmmRexrReg(m, rde), 8); + memset(XmmRexbRm(m, rde) + 8, 0, 8); + } else { + memcpy(ComputeReserveAddressWrite8(m, rde), XmmRexrReg(m, rde), 8); + } +} + +static void Movq2dqVdqNq(struct Machine *m, uint32_t rde) { + memcpy(XmmRexrReg(m, rde), MmRm(m, rde), 8); + memset(XmmRexrReg(m, rde) + 8, 0, 8); +} + +static void Movdq2qPqUq(struct Machine *m, uint32_t rde) { + memcpy(MmReg(m, rde), XmmRexbRm(m, rde), 8); +} + +static void MovapsVpsWps(struct Machine *m, uint32_t rde) { + MovdqaVdqWdq(m, rde); +} + +static void MovapdVpdWpd(struct Machine *m, uint32_t rde) { + MovdqaVdqWdq(m, rde); +} + +static void MovapsWpsVps(struct Machine *m, uint32_t rde) { + MovdqaWdqVdq(m, rde); +} + +static void MovapdWpdVpd(struct Machine *m, uint32_t rde) { + MovdqaWdqVdq(m, rde); +} + +void OpMovWpsVps(struct Machine *m, uint32_t rde) { + uint8_t *p, *r; + switch (Rep(rde) | Osz(rde)) { + case 0: + MovupsWpsVps(m, rde); + break; + case 1: + MovupdWpsVps(m, rde); + break; + case 2: + MovsdWpsVps(m, rde); + break; + case 3: + MovssWpsVps(m, rde); + break; + default: + unreachable; + } +} + +void OpMov0f28(struct Machine *m, uint32_t rde) { + if (!Osz(rde)) { + MovapsVpsWps(m, rde); + } else { + MovapdVpdWpd(m, rde); + } +} + +void OpMov0f6e(struct Machine *m, uint32_t rde) { + if (Osz(rde)) { + if (Rexw(rde)) { + MovqVdqEqp(m, rde); + } else { + MovdVdqEd(m, rde); + } + } else { + if (Rexw(rde)) { + MovqPqEqp(m, rde); + } else { + MovdPqEd(m, rde); + } + } +} + +void OpMov0f6f(struct Machine *m, uint32_t rde) { + if (Osz(rde)) { + MovdqaVdqWdq(m, rde); + } else if (Rep(rde) == 3) { + MovdquVdqWdq(m, rde); + } else { + MovqPqQq(m, rde); + } +} + +void OpMov0fE7(struct Machine *m, uint32_t rde) { + if (!Osz(rde)) { + MovntqMqPq(m, rde); + } else { + MovntdqMdqVdq(m, rde); + } +} + +void OpMov0f7e(struct Machine *m, uint32_t rde) { + if (Rep(rde) == 3) { + MovqVqWq(m, rde); + } else if (Osz(rde)) { + if (Rexw(rde)) { + MovqEqpVdq(m, rde); + } else { + MovdEdVdq(m, rde); + } + } else { + if (Rexw(rde)) { + MovqEqpPq(m, rde); + } else { + MovdEdPq(m, rde); + } + } +} + +void OpMov0f7f(struct Machine *m, uint32_t rde) { + if (Rep(rde) == 3) { + MovdquWdqVdq(m, rde); + } else if (Osz(rde)) { + MovdqaWdqVdq(m, rde); + } else { + MovqQqPq(m, rde); + } +} + +void OpMov0f10(struct Machine *m, uint32_t rde) { + uint8_t *p, *r; + switch (Rep(rde) | Osz(rde)) { + case 0: + MovupsVpsWps(m, rde); + break; + case 1: + MovupdVpsWps(m, rde); + break; + case 2: + MovsdVpsWps(m, rde); + break; + case 3: + MovssVpsWps(m, rde); + break; + default: + unreachable; + } +} + +void OpMov0f29(struct Machine *m, uint32_t rde) { + if (!Osz(rde)) { + MovapsWpsVps(m, rde); + } else { + MovapdWpdVpd(m, rde); + } +} + +void OpMov0f2b(struct Machine *m, uint32_t rde) { + if (!Osz(rde)) { + MovntpsMpsVps(m, rde); + } else { + MovntpdMpdVpd(m, rde); + } +} + +void OpMov0f12(struct Machine *m, uint32_t rde) { + switch (Rep(rde) | Osz(rde)) { + case 0: + if (IsModrmRegister(rde)) { + MovhlpsVqUq(m, rde); + } else { + MovlpsVqMq(m, rde); + } + break; + case 1: + MovlpdVqMq(m, rde); + break; + case 2: + MovddupVqWq(m, rde); + break; + case 3: + MovsldupVqWq(m, rde); + break; + default: + unreachable; + } +} + +void OpMov0f13(struct Machine *m, uint32_t rde) { + if (Osz(rde)) { + MovlpdMqVq(m, rde); + } else { + MovlpsMqVq(m, rde); + } +} + +void OpMov0f16(struct Machine *m, uint32_t rde) { + switch (Rep(rde) | Osz(rde)) { + case 0: + if (IsModrmRegister(rde)) { + MovlhpsVqUq(m, rde); + } else { + MovhpsVqMq(m, rde); + } + break; + case 1: + MovhpdVqMq(m, rde); + break; + case 3: + MovshdupVqWq(m, rde); + break; + default: + OpUd(m, rde); + break; + } +} + +void OpMov0f17(struct Machine *m, uint32_t rde) { + if (Osz(rde)) { + MovhpdMqVq(m, rde); + } else { + MovhpsMqVq(m, rde); + } +} + +void OpMov0fD6(struct Machine *m, uint32_t rde) { + if (Rep(rde) == 3) { + Movq2dqVdqNq(m, rde); + } else if (Rep(rde) == 2) { + Movdq2qPqUq(m, rde); + } else if (Osz(rde)) { + MovqWqVq(m, rde); + } else { + OpUd(m, rde); + } +} + +static uint8_t pmovmskb(uint64_t x) { + return (x & 0x0000000000000080) >> 007 | (x & 0x0000000000008000) >> 016 | + (x & 0x0000000000800000) >> 025 | (x & 0x0000000080000000) >> 034 | + (x & 0x0000008000000000) >> 043 | (x & 0x0000800000000000) >> 052 | + (x & 0x0080000000000000) >> 061 | (x & 0x8000000000000000) >> 070; +} + +void OpPmovmskbGdqpNqUdq(struct Machine *m, uint32_t rde) { + uint64_t bitmask; + if (Osz(rde)) { + bitmask = pmovmskb(Read64(XmmRexbRm(m, rde) + 8)) << 8 | + pmovmskb(Read64(XmmRexbRm(m, rde))); + } else { + bitmask = pmovmskb(Read64(MmRm(m, rde) + 8)) << 8 | + pmovmskb(Read64(MmRm(m, rde))); + } + Write64(RegRexrReg(m, rde), bitmask); +} + +void OpMaskMovDiXmmRegXmmRm(struct Machine *m, uint32_t rde) { + void *p[2]; + uint64_t v; + unsigned i, n; + uint8_t *mem, b[16]; + v = AddressDi(m, rde); + n = Osz(rde) ? 16 : 8; + mem = BeginStore(m, v, n, p, b); + for (i = 0; i < n; ++i) { + if (XmmRexbRm(m, rde)[i] & 0x80) { + mem[i] = XmmRexrReg(m, rde)[i]; + } + } + EndStore(m, v, n, p, b); +} diff --git a/tool/build/lib/ssemov.h b/tool/build/lib/ssemov.h new file mode 100644 index 00000000..e8066f05 --- /dev/null +++ b/tool/build/lib/ssemov.h @@ -0,0 +1,30 @@ +#ifndef COSMOPOLITAN_TOOL_BUILD_LIB_SSEMOV_H_ +#define COSMOPOLITAN_TOOL_BUILD_LIB_SSEMOV_H_ +#include "tool/build/lib/machine.h" +#if !(__ASSEMBLER__ + __LINKER__ + 0) +COSMOPOLITAN_C_START_ + +void OpLddquVdqMdq(struct Machine *, uint32_t); +void OpMovntiMdqpGdqp(struct Machine *, uint32_t); +void OpPmovmskbGdqpNqUdq(struct Machine *, uint32_t); +void OpMaskMovDiXmmRegXmmRm(struct Machine *, uint32_t); +void OpMovntdqaVdqMdq(struct Machine *, uint32_t); +void OpMovWpsVps(struct Machine *, uint32_t); +void OpMov0f28(struct Machine *, uint32_t); +void OpMov0f6e(struct Machine *, uint32_t); +void OpMov0f6f(struct Machine *, uint32_t); +void OpMov0fE7(struct Machine *, uint32_t); +void OpMov0f7e(struct Machine *, uint32_t); +void OpMov0f7f(struct Machine *, uint32_t); +void OpMov0f10(struct Machine *, uint32_t); +void OpMov0f29(struct Machine *, uint32_t); +void OpMov0f2b(struct Machine *, uint32_t); +void OpMov0f12(struct Machine *, uint32_t); +void OpMov0f13(struct Machine *, uint32_t); +void OpMov0f16(struct Machine *, uint32_t); +void OpMov0f17(struct Machine *, uint32_t); +void OpMov0fD6(struct Machine *, uint32_t); + +COSMOPOLITAN_C_END_ +#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ +#endif /* COSMOPOLITAN_TOOL_BUILD_LIB_SSEMOV_H_ */ diff --git a/tool/build/lib/stack.c b/tool/build/lib/stack.c index 2794d410..9fc48478 100644 --- a/tool/build/lib/stack.c +++ b/tool/build/lib/stack.c @@ -19,89 +19,167 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/log/check.h" #include "libc/macros.h" +#include "tool/build/lib/address.h" #include "tool/build/lib/endian.h" #include "tool/build/lib/memory.h" #include "tool/build/lib/modrm.h" #include "tool/build/lib/stack.h" +#include "tool/build/lib/throw.h" -void Push64(struct Machine *m, uint64_t x) { - uint64_t v; - void *p[2]; - uint8_t b[8]; - v = Read64(m->sp); - v -= 8; - Write64(m->sp, v); - Write64(AccessRam(m, v, 8, p, b, false), x); - EndStore(m, v, 8, p, b); -} +static const uint8_t kStackOsz[2][3] = { + [0][XED_MODE_REAL] = 2, [0][XED_MODE_LEGACY] = 4, [0][XED_MODE_LONG] = 8, + [1][XED_MODE_REAL] = 4, [1][XED_MODE_LEGACY] = 2, [1][XED_MODE_LONG] = 2, +}; -void Push16(struct Machine *m, uint16_t x) { - uint64_t v; - void *p[2]; - uint8_t b[2]; - v = Read64(m->sp); - v -= 2; - Write64(m->sp, v); - Write16(b, x); - Write64(AccessRam(m, v, 2, p, b, false), x); - EndStore(m, v, 2, p, b); -} +static const uint8_t kCallOsz[2][3] = { + [0][XED_MODE_REAL] = 2, [0][XED_MODE_LEGACY] = 4, [0][XED_MODE_LONG] = 8, + [1][XED_MODE_REAL] = 4, [1][XED_MODE_LEGACY] = 2, [1][XED_MODE_LONG] = 8, +}; -uint64_t Pop64(struct Machine *m, uint16_t extra) { - void *p[2]; - uint8_t b[8]; - uint64_t v, x; - v = Read64(m->sp); - x = Read64(AccessRam(m, v, 8, p, b, true)); - Write64(m->sp, v + 8 + extra); - return x; -} - -uint16_t Pop16(struct Machine *m, uint16_t extra) { - void *p[2]; - uint8_t b[2]; - uint16_t v, x; - v = Read64(m->sp); - x = Read16(AccessRam(m, v, 2, p, b, true)); - Write64(m->sp, v + 2 + extra); - return x; -} - -static void OpCall(struct Machine *m, uint64_t func) { - Push64(m, m->ip); - m->ip = func; -} - -void OpCallJvds(struct Machine *m) { - OpCall(m, m->ip + m->xedd->op.disp); -} - -void OpCallEq(struct Machine *m, uint32_t rde) { - void *p[2]; - uint8_t b[8]; - OpCall(m, Read64(IsModrmRegister(rde) - ? RegRexbRm(m, rde) - : AccessRam(m, ComputeAddress(m, rde), 8, p, b, true))); -} - -void OpLeave(struct Machine *m) { - memcpy(m->sp, m->bp, sizeof(m->sp)); - Write64(m->bp, Pop64(m, 0)); -} - -void OpRet(struct Machine *m, uint16_t n) { - m->ip = Pop64(m, n); -} - -void PushOsz(struct Machine *m, uint32_t rde, uint64_t x) { - if (!Osz(rde)) { - Push64(m, x); +static void WriteStackWord(uint8_t *p, uint32_t rde, uint32_t osz, uint64_t x) { + if (osz == 8) { + Write64(p, x); + } else if (osz == 2) { + Write16(p, x); } else { - Push16(m, x); + Write32(p, x); } } -void OpBofram(struct Machine *m) { +static uint64_t ReadStackWord(uint8_t *p, uint32_t osz) { + if (osz == 8) { + return Read64(p); + } else if (osz == 2) { + return Read16(p); + } else { + return Read32(p); + } +} + +void Push(struct Machine *m, uint32_t rde, uint64_t x) { + uint64_t v; + void *p[2]; + uint8_t b[8]; + unsigned osz; + osz = kStackOsz[m->xedd->op.osz][Mode(rde)]; + switch (Eamode(rde)) { + case XED_MODE_REAL: + v = (Read32(m->sp) - osz) & 0xffff; + Write16(m->sp, v); + v += Read64(m->ss); + break; + case XED_MODE_LEGACY: + v = (Read32(m->sp) - osz) & 0xffffffff; + Write64(m->sp, v); + v += Read64(m->ss); + break; + case XED_MODE_LONG: + v = (Read64(m->sp) - osz) & 0xffffffffffffffff; + Write64(m->sp, v); + break; + default: + unreachable; + } + WriteStackWord(AccessRam(m, v, osz, p, b, false), rde, osz, x); + EndStore(m, v, osz, p, b); +} + +void OpPushZvq(struct Machine *m, uint32_t rde) { + unsigned osz; + osz = kStackOsz[m->xedd->op.osz][Mode(rde)]; + Push(m, rde, ReadStackWord(RegRexbSrm(m, rde), osz)); +} + +uint64_t Pop(struct Machine *m, uint32_t rde, uint16_t extra) { + uint64_t v; + void *p[2]; + uint8_t b[8]; + unsigned osz; + osz = kStackOsz[m->xedd->op.osz][Mode(rde)]; + switch (Eamode(rde)) { + case XED_MODE_LONG: + v = Read64(m->sp); + Write64(m->sp, v + osz + extra); + break; + case XED_MODE_LEGACY: + v = Read32(m->sp); + Write64(m->sp, (v + osz + extra) & 0xffffffff); + v += Read64(m->ss); + break; + case XED_MODE_REAL: + v = Read32(m->sp); + Write16(m->sp, v + osz + extra); + v += Read64(m->ss); + break; + default: + unreachable; + } + return ReadStackWord(AccessRam(m, v, osz, p, b, true), osz); +} + +void OpPopZvq(struct Machine *m, uint32_t rde) { + uint64_t x; + x = Pop(m, rde, 0); + switch (kStackOsz[m->xedd->op.osz][Mode(rde)]) { + case 8: + case 4: + Write64(RegRexbSrm(m, rde), x); + break; + case 2: + Write16(RegRexbSrm(m, rde), x); + break; + default: + unreachable; + } +} + +static void OpCall(struct Machine *m, uint32_t rde, uint64_t func) { + Push(m, rde, m->ip); + m->ip = func; +} + +void OpCallJvds(struct Machine *m, uint32_t rde) { + OpCall(m, rde, m->ip + m->xedd->op.disp); +} + +static uint64_t LoadAddressFromMemory(struct Machine *m, uint32_t rde) { + unsigned osz; + osz = kCallOsz[m->xedd->op.osz][Mode(rde)]; + return ReadStackWord(GetModrmRegisterWordPointerRead(m, rde, osz), osz); +} + +void OpCallEq(struct Machine *m, uint32_t rde) { + OpCall(m, rde, LoadAddressFromMemory(m, rde)); +} + +void OpJmpEq(struct Machine *m, uint32_t rde) { + m->ip = LoadAddressFromMemory(m, rde); +} + +void OpLeave(struct Machine *m, uint32_t rde) { + switch (Eamode(rde)) { + case XED_MODE_LONG: + Write64(m->sp, Read64(m->bp)); + Write64(m->bp, Pop(m, rde, 0)); + break; + case XED_MODE_LEGACY: + Write64(m->sp, Read32(m->bp)); + Write64(m->bp, Pop(m, rde, 0)); + break; + case XED_MODE_REAL: + Write16(m->sp, Read16(m->bp)); + Write16(m->bp, Pop(m, rde, 0)); + break; + default: + unreachable; + } +} + +void OpRet(struct Machine *m, uint32_t rde, uint16_t n) { + m->ip = Pop(m, rde, n); +} + +void OpBofram(struct Machine *m, uint32_t rde) { if (m->xedd->op.disp) { m->bofram[0] = m->ip; m->bofram[1] = m->ip + (m->xedd->op.disp & 0xff); @@ -110,3 +188,105 @@ void OpBofram(struct Machine *m) { m->bofram[1] = 0; } } + +void OpPushEvq(struct Machine *m, uint32_t rde) { + unsigned osz; + osz = kStackOsz[m->xedd->op.osz][Mode(rde)]; + Push(m, rde, + ReadStackWord(GetModrmRegisterWordPointerRead(m, rde, osz), osz)); +} + +void OpPopEvq(struct Machine *m, uint32_t rde) { + unsigned osz; + osz = kStackOsz[m->xedd->op.osz][Mode(rde)]; + WriteStackWord(GetModrmRegisterWordPointerWrite(m, rde, osz), rde, osz, + Pop(m, rde, 0)); +} + +static void Pushaw(struct Machine *m, uint32_t rde) { + uint16_t v; + uint8_t b[8][2]; + memcpy(b[0], m->di, 2); + memcpy(b[1], m->si, 2); + memcpy(b[2], m->bp, 2); + memcpy(b[3], m->sp, 2); + memcpy(b[4], m->bx, 2); + memcpy(b[5], m->dx, 2); + memcpy(b[6], m->cx, 2); + memcpy(b[7], m->ax, 2); + Write16(m->sp, (v = (Read16(m->sp) - sizeof(b)) & 0xffff)); + VirtualRecv(m, Read64(m->ss) + v, b, sizeof(b)); +} + +static void Pushad(struct Machine *m, uint32_t rde) { + uint32_t v; + uint8_t b[8][4]; + memcpy(b[0], m->di, 4); + memcpy(b[1], m->si, 4); + memcpy(b[2], m->bp, 4); + memcpy(b[3], m->sp, 4); + memcpy(b[4], m->bx, 4); + memcpy(b[5], m->dx, 4); + memcpy(b[6], m->cx, 4); + memcpy(b[7], m->ax, 4); + Write64(m->sp, (v = (Read32(m->sp) - sizeof(b)) & 0xffffffff)); + VirtualRecv(m, Read64(m->ss) + v, b, sizeof(b)); +} + +void OpPusha(struct Machine *m, uint32_t rde) { + switch (Eamode(rde)) { + case XED_MODE_REAL: + Pushaw(m, rde); + break; + case XED_MODE_LEGACY: + Pushad(m, rde); + break; + case XED_MODE_LONG: + OpUd(m, rde); + default: + unreachable; + } +} + +static void Popaw(struct Machine *m, uint32_t rde) { + uint8_t b[8][2]; + VirtualSend(m, b, Read64(m->ss) + Read16(m->sp), sizeof(b)); + Write16(m->sp, (Read32(m->sp) + sizeof(b)) & 0xffff); + memcpy(m->di, b[0], 2); + memcpy(m->si, b[1], 2); + memcpy(m->bp, b[2], 2); + memcpy(m->sp, b[3], 2); + memcpy(m->bx, b[4], 2); + memcpy(m->dx, b[5], 2); + memcpy(m->cx, b[6], 2); + memcpy(m->ax, b[7], 2); +} + +static void Popad(struct Machine *m, uint32_t rde) { + uint8_t b[8][4]; + VirtualSend(m, b, Read64(m->ss) + Read32(m->sp), sizeof(b)); + Write64(m->sp, (Read32(m->sp) + sizeof(b)) & 0xffffffff); + memcpy(m->di, b[0], 4); + memcpy(m->si, b[1], 4); + memcpy(m->bp, b[2], 4); + memcpy(m->sp, b[3], 4); + memcpy(m->bx, b[4], 4); + memcpy(m->dx, b[5], 4); + memcpy(m->cx, b[6], 4); + memcpy(m->ax, b[7], 4); +} + +void OpPopa(struct Machine *m, uint32_t rde) { + switch (Eamode(rde)) { + case XED_MODE_REAL: + Popaw(m, rde); + break; + case XED_MODE_LEGACY: + Popad(m, rde); + break; + case XED_MODE_LONG: + OpUd(m, rde); + default: + unreachable; + } +} diff --git a/tool/build/lib/stack.h b/tool/build/lib/stack.h index 255533cc..00c734e7 100644 --- a/tool/build/lib/stack.h +++ b/tool/build/lib/stack.h @@ -4,16 +4,22 @@ #if !(__ASSEMBLER__ + __LINKER__ + 0) COSMOPOLITAN_C_START_ -void Push64(struct Machine *, uint64_t); -uint64_t Pop64(struct Machine *, uint16_t); -void Push16(struct Machine *, uint16_t); -uint16_t Pop16(struct Machine *, uint16_t); -void OpCallJvds(struct Machine *); -void OpRet(struct Machine *, uint16_t); -void OpLeave(struct Machine *); -void PushOsz(struct Machine *, uint32_t, uint64_t); +void Push(struct Machine *, uint32_t, uint64_t); +uint64_t Pop(struct Machine *, uint32_t, uint16_t); +void OpCallJvds(struct Machine *, uint32_t); +void OpRet(struct Machine *, uint32_t, uint16_t); +void OpLeave(struct Machine *, uint32_t); void OpCallEq(struct Machine *, uint32_t); -void OpBofram(struct Machine *); +void OpBofram(struct Machine *, uint32_t); +void OpPopEvq(struct Machine *, uint32_t); +void OpPopZvq(struct Machine *, uint32_t); +void OpPushZvq(struct Machine *, uint32_t); +void OpPushEvq(struct Machine *, uint32_t); +void PopVq(struct Machine *, uint32_t); +void PushVq(struct Machine *, uint32_t); +void OpJmpEq(struct Machine *, uint32_t); +void OpPusha(struct Machine *, uint32_t); +void OpPopa(struct Machine *, uint32_t); COSMOPOLITAN_C_END_ #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ diff --git a/tool/build/lib/string.c b/tool/build/lib/string.c index 13522b2d..c1525002 100644 --- a/tool/build/lib/string.c +++ b/tool/build/lib/string.c @@ -21,6 +21,8 @@ #include "libc/log/log.h" #include "libc/macros.h" #include "libc/runtime/runtime.h" +#include "libc/str/str.h" +#include "tool/build/lib/address.h" #include "tool/build/lib/alu.h" #include "tool/build/lib/endian.h" #include "tool/build/lib/flags.h" @@ -55,7 +57,7 @@ static void WriteInt(uint8_t p[8], uint64_t x, unsigned long w) { Write16(p, x); break; case 2: - Write64(p, x); + Write64(p, x & 0xffffffff); break; case 3: Write64(p, x); @@ -65,164 +67,220 @@ static void WriteInt(uint8_t p[8], uint64_t x, unsigned long w) { } } -void OpString(struct Machine *m, uint32_t rde, int op) { +static void AddDi(struct Machine *m, uint32_t rde, uint64_t x) { + switch (Eamode(rde)) { + case XED_MODE_LONG: + Write64(m->di, Read64(m->di) + x); + return; + case XED_MODE_LEGACY: + Write64(m->di, (Read32(m->di) + x) & 0xffffffff); + return; + case XED_MODE_REAL: + Write16(m->di, Read16(m->di) + x); + return; + default: + unreachable; + } +} + +static void AddSi(struct Machine *m, uint32_t rde, uint64_t x) { + switch (Eamode(rde)) { + case XED_MODE_LONG: + Write64(m->si, Read64(m->si) + x); + return; + case XED_MODE_LEGACY: + Write64(m->si, (Read32(m->si) + x) & 0xffffffff); + return; + case XED_MODE_REAL: + Write16(m->si, Read16(m->si) + x); + return; + default: + unreachable; + } +} + +static uint64_t ReadCx(struct Machine *m, uint32_t rde) { + switch (Eamode(rde)) { + case XED_MODE_LONG: + return Read64(m->cx); + case XED_MODE_LEGACY: + return Read32(m->cx); + case XED_MODE_REAL: + return Read16(m->cx); + default: + unreachable; + } +} + +static uint64_t SubtractCx(struct Machine *m, uint32_t rde, uint64_t x) { + uint64_t cx; + cx = Read64(m->cx) - x; + if (Eamode(rde) != XED_MODE_REAL) { + if (Eamode(rde) == XED_MODE_LEGACY) { + cx &= 0xffffffff; + } + Write64(m->cx, cx); + } else { + cx &= 0xffff; + Write16(m->cx, cx); + } + return cx; +} + +static void StringOp(struct Machine *m, uint32_t rde, int op) { + bool stop; void *p[2]; unsigned n; - uint64_t asz; - bool compare; int64_t sgn, v; uint8_t s[3][8]; - sgn = GetFlag(m->flags, FLAGS_DF) ? -1 : 1; - asz = Asz(rde) ? 0xffffffff : 0xffffffffffffffff; + stop = false; n = 1 << RegLog2(rde); - for (;;) { - if (Rep(rde) && !Read64(m->cx)) break; - v = 0; - *p = NULL; - compare = false; + sgn = GetFlag(m->flags, FLAGS_DF) ? -1 : 1; + do { + if (Rep(rde) && !ReadCx(m, rde)) break; switch (op) { case STRING_CMPS: - Alu(RegLog2(rde), ALU_SUB, - ReadInt(Load(m, (Read64(m->si) + GetSegment(m)) & asz, n, s[2]), - RegLog2(rde)), - ReadInt(Load(m, Read64(m->di) & asz, n, s[1]), RegLog2(rde)), + kAlu[ALU_SUB][RegLog2(rde)]( + ReadInt(Load(m, AddressSi(m, rde), n, s[2]), RegLog2(rde)), + ReadInt(Load(m, AddressDi(m, rde), n, s[1]), RegLog2(rde)), &m->flags); - Write64(m->di, (Read64(m->di) + sgn * n) & asz); - Write64(m->si, (Read64(m->si) + sgn * n) & asz); - compare = true; + AddDi(m, rde, sgn * n); + AddSi(m, rde, sgn * n); + stop = (Rep(rde) == 2 && GetFlag(m->flags, FLAGS_ZF)) || + (Rep(rde) == 3 && !GetFlag(m->flags, FLAGS_ZF)); break; case STRING_MOVS: - memcpy(BeginStore(m, (v = Read64(m->di) & asz), n, p, s[0]), - Load(m, (Read64(m->si) + GetSegment(m)) & asz, n, s[1]), n); - Write64(m->di, (Read64(m->di) + sgn * n) & asz); - Write64(m->si, (Read64(m->si) + sgn * n) & asz); + memcpy(BeginStore(m, (v = AddressDi(m, rde)), n, p, s[0]), + Load(m, AddressSi(m, rde), n, s[1]), n); + AddDi(m, rde, sgn * n); + AddSi(m, rde, sgn * n); + EndStore(m, v, n, p, s[0]); break; case STRING_STOS: - memcpy(BeginStore(m, (v = Read64(m->di) & asz), n, p, s[0]), m->ax, n); - Write64(m->di, (Read64(m->di) + sgn * n) & asz); + memcpy(BeginStore(m, (v = AddressDi(m, rde)), n, p, s[0]), m->ax, n); + AddDi(m, rde, sgn * n); + EndStore(m, v, n, p, s[0]); break; case STRING_LODS: - memcpy(m->ax, Load(m, (Read64(m->si) + GetSegment(m)) & asz, n, s[1]), - n); - Write64(m->si, (Read64(m->si) + sgn * n) & asz); + memcpy(m->ax, Load(m, AddressSi(m, rde), n, s[1]), n); + AddSi(m, rde, sgn * n); break; case STRING_SCAS: - Alu(RegLog2(rde), ALU_SUB, - ReadInt(Load(m, Read64(m->di) & asz, n, s[1]), RegLog2(rde)), + kAlu[ALU_SUB][RegLog2(rde)]( + ReadInt(Load(m, AddressDi(m, rde), n, s[1]), RegLog2(rde)), ReadInt(m->ax, RegLog2(rde)), &m->flags); - Write64(m->di, (Read64(m->di) + sgn * n) & asz); - compare = true; + AddDi(m, rde, sgn * n); + stop = (Rep(rde) == 2 && GetFlag(m->flags, FLAGS_ZF)) || + (Rep(rde) == 3 && !GetFlag(m->flags, FLAGS_ZF)); break; case STRING_OUTS: OpOut(m, Read16(m->dx), - ReadInt(Load(m, (Read64(m->si) + GetSegment(m)) & asz, n, s[1]), - RegLog2(rde))); - Write64(m->si, (Read64(m->si) + sgn * n) & asz); + ReadInt(Load(m, AddressSi(m, rde), n, s[1]), RegLog2(rde))); + AddSi(m, rde, sgn * n); break; case STRING_INS: - WriteInt(BeginStore(m, (v = Read64(m->di) & asz), n, p, s[0]), + WriteInt(BeginStore(m, (v = AddressDi(m, rde)), n, p, s[0]), OpIn(m, Read16(m->dx)), RegLog2(rde)); - Write64(m->di, (Read64(m->di) + sgn * n) & asz); + AddDi(m, rde, sgn * n); + EndStore(m, v, n, p, s[0]); break; default: abort(); } - EndStore(m, v, n, p, s[0]); - if (!Rep(rde)) break; - Write64(m->cx, Read64(m->cx) - 1); - if (compare) { - if (Rep(rde) == 2 && GetFlag(m->flags, FLAGS_ZF)) break; - if (Rep(rde) == 3 && !GetFlag(m->flags, FLAGS_ZF)) break; + if (Rep(rde)) { + SubtractCx(m, rde, 1); + } else { + break; } + } while (!stop); +} + +static void RepMovsbEnhanced(struct Machine *m, uint32_t rde) { + uint8_t *direal, *sireal; + uint64_t diactual, siactual, cx; + unsigned diremain, siremain, i, n; + if ((cx = ReadCx(m, rde))) { + do { + diactual = AddressDi(m, rde); + siactual = AddressSi(m, rde); + SetWriteAddr(m, diactual, cx); + SetReadAddr(m, siactual, cx); + direal = ResolveAddress(m, diactual); + sireal = ResolveAddress(m, siactual); + diremain = 0x1000 - (diactual & 0xfff); + siremain = 0x1000 - (siactual & 0xfff); + n = MIN(cx, MIN(diremain, siremain)); + if ((uintptr_t)direal <= (uintptr_t)sireal || + (uintptr_t)direal >= (uintptr_t)sireal + n) { + memcpy(direal, sireal, n); + } else { + for (i = 0; i < n; ++i) { + direal[i] = sireal[i]; + } + } + AddDi(m, rde, n); + AddSi(m, rde, n); + } while ((cx = SubtractCx(m, rde, n))); } } -void OpRepMovsbEnhanced(struct Machine *m, uint32_t rde) { - bool failed; - uint8_t *direal, *sireal; - unsigned diremain, siremain, i, n; - uint64_t divirtual, sivirtual, diactual, siactual, failaddr, asz, cx; - if (!(cx = Read64(m->cx))) return; - failed = false; - failaddr = 0; - asz = Asz(rde) ? 0xffffffff : 0xffffffffffffffff; - divirtual = Read64(m->di) & asz; - sivirtual = Read64(m->si) & asz; - SetWriteAddr(m, (GetSegment(m) + divirtual) & asz, cx); - SetReadAddr(m, (GetSegment(m) + sivirtual) & asz, cx); - do { - diactual = (GetSegment(m) + divirtual) & asz; - siactual = (GetSegment(m) + sivirtual) & asz; - if (!(direal = FindReal(m, diactual))) { - failaddr = diactual; - failed = true; - break; - } - if (!(sireal = FindReal(m, siactual))) { - failaddr = siactual; - failed = true; - break; - } - diremain = 0x1000 - (divirtual & 0xfff); - siremain = 0x1000 - (sivirtual & 0xfff); - n = MIN(cx, MIN(diremain, siremain)); - for (i = 0; i < n; ++i) { - direal[i] = sireal[i]; - } - cx -= n; - divirtual = (divirtual + n) & asz; - sivirtual = (sivirtual + n) & asz; - } while (cx); - Write64(m->cx, cx); - Write64(m->di, divirtual); - Write64(m->si, sivirtual); - if (failed) ThrowSegmentationFault(m, failaddr); +static void RepStosbEnhanced(struct Machine *m, uint32_t rde) { + uint8_t *direal; + unsigned diremain, n; + uint64_t divirtual, diactual, cx; + if ((cx = ReadCx(m, rde))) { + do { + diactual = AddressDi(m, rde); + SetWriteAddr(m, diactual, cx); + direal = ResolveAddress(m, diactual); + diremain = 0x1000 - (diactual & 0xfff); + n = MIN(cx, diremain); + memset(direal, Read8(m->ax), n); + AddDi(m, rde, n); + } while ((cx = SubtractCx(m, rde, n))); + } } -void OpRepStosbEnhanced(struct Machine *m, uint32_t rde) { - bool failed; - uint8_t *direal, al; - unsigned diremain, i, n; - uint64_t divirtual, diactual, failaddr, asz, cx; - if (!(cx = Read64(m->cx))) return; - failaddr = 0; - failed = false; - al = Read8(m->ax); - asz = Asz(rde) ? 0xffffffff : 0xffffffffffffffff; - divirtual = Read64(m->di) & asz; - SetWriteAddr(m, (GetSegment(m) + divirtual) & asz, cx); - do { - diactual = (GetSegment(m) + divirtual) & asz; - if (!(direal = FindReal(m, diactual))) { - failaddr = diactual; - failed = true; - break; - } - diremain = 0x1000 - (divirtual & 0xfff); - n = MIN(cx, diremain); - for (i = 0; i < n; ++i) { - direal[i] = al; - } - cx -= n; - divirtual = (divirtual + n) & asz; - } while (cx); - Write64(m->cx, cx); - Write64(m->di, divirtual); - if (failed) ThrowSegmentationFault(m, failaddr); +void OpMovs(struct Machine *m, uint32_t rde) { + StringOp(m, rde, STRING_MOVS); +} + +void OpCmps(struct Machine *m, uint32_t rde) { + StringOp(m, rde, STRING_CMPS); +} + +void OpStos(struct Machine *m, uint32_t rde) { + StringOp(m, rde, STRING_STOS); +} + +void OpLods(struct Machine *m, uint32_t rde) { + StringOp(m, rde, STRING_LODS); +} + +void OpScas(struct Machine *m, uint32_t rde) { + StringOp(m, rde, STRING_SCAS); +} + +void OpIns(struct Machine *m, uint32_t rde) { + StringOp(m, rde, STRING_INS); +} + +void OpOuts(struct Machine *m, uint32_t rde) { + StringOp(m, rde, STRING_OUTS); } void OpMovsb(struct Machine *m, uint32_t rde) { if (Rep(rde) && !GetFlag(m->flags, FLAGS_DF)) { - OpRepMovsbEnhanced(m, rde); + RepMovsbEnhanced(m, rde); } else { - OpString(m, rde, STRING_MOVS); + OpMovs(m, rde); } } void OpStosb(struct Machine *m, uint32_t rde) { if (Rep(rde) && !GetFlag(m->flags, FLAGS_DF)) { - OpRepStosbEnhanced(m, rde); + RepStosbEnhanced(m, rde); } else { - OpString(m, rde, STRING_STOS); + OpStos(m, rde); } } diff --git a/tool/build/lib/string.h b/tool/build/lib/string.h index 698b9a8a..0b2fff31 100644 --- a/tool/build/lib/string.h +++ b/tool/build/lib/string.h @@ -13,9 +13,15 @@ #if !(__ASSEMBLER__ + __LINKER__ + 0) COSMOPOLITAN_C_START_ -void OpString(struct Machine *, uint32_t, int); void OpMovsb(struct Machine *, uint32_t); void OpStosb(struct Machine *, uint32_t); +void OpMovs(struct Machine *, uint32_t); +void OpCmps(struct Machine *, uint32_t); +void OpStos(struct Machine *, uint32_t); +void OpLods(struct Machine *, uint32_t); +void OpScas(struct Machine *, uint32_t); +void OpIns(struct Machine *, uint32_t); +void OpOuts(struct Machine *, uint32_t); COSMOPOLITAN_C_END_ #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ diff --git a/tool/build/lib/syscall.c b/tool/build/lib/syscall.c index 50457dc0..07f3243e 100644 --- a/tool/build/lib/syscall.c +++ b/tool/build/lib/syscall.c @@ -20,11 +20,13 @@ #include "libc/calls/calls.h" #include "libc/calls/internal.h" #include "libc/calls/ioctl.h" +#include "libc/calls/struct/iovec.h" #include "libc/calls/struct/sigaction-linux.h" #include "libc/calls/struct/sigaction.h" #include "libc/calls/struct/stat.h" #include "libc/calls/struct/timespec.h" #include "libc/calls/struct/timeval.h" +#include "libc/calls/struct/winsize.h" #include "libc/errno.h" #include "libc/log/check.h" #include "libc/log/log.h" @@ -33,8 +35,12 @@ #include "libc/runtime/runtime.h" #include "libc/sock/sock.h" #include "libc/str/str.h" +#include "libc/sysv/consts/af.h" #include "libc/sysv/consts/at.h" #include "libc/sysv/consts/clock.h" +#include "libc/sysv/consts/f.h" +#include "libc/sysv/consts/fd.h" +#include "libc/sysv/consts/ipproto.h" #include "libc/sysv/consts/map.h" #include "libc/sysv/consts/msync.h" #include "libc/sysv/consts/o.h" @@ -42,7 +48,10 @@ #include "libc/sysv/consts/sa.h" #include "libc/sysv/consts/sig.h" #include "libc/sysv/consts/so.h" +#include "libc/sysv/consts/sock.h" +#include "libc/sysv/consts/sol.h" #include "libc/sysv/consts/tcp.h" +#include "libc/sysv/consts/termios.h" #include "libc/sysv/errfuns.h" #include "libc/time/struct/timezone.h" #include "libc/time/time.h" @@ -56,7 +65,8 @@ #include "tool/build/lib/throw.h" #include "tool/build/lib/xlaterrno.h" -#define AT_FDCWD_LINUX -100 +#define AT_FDCWD_LINUX -100 +#define TIOCGWINSZ_LINUX 0x5413 #define POINTER(x) ((void *)(intptr_t)(x)) #define UNPOINTER(x) ((int64_t)(intptr_t)(x)) @@ -70,6 +80,7 @@ const struct MachineFdCb kMachineFdCbHost = { .close = close, .read = read, .write = write, + .ioctl = ioctl, }; static int XlatSignal(int sig) { @@ -107,7 +118,76 @@ static int XlatSignal(int sig) { XLAT(30, SIGPWR); XLAT(0x10, SIGSTKFLT); default: - return sig; + return einval(); + } +} + +static int XlatSig(int x) { + switch (x) { + XLAT(0, SIG_BLOCK); + XLAT(1, SIG_UNBLOCK); + XLAT(2, SIG_SETMASK); + default: + return einval(); + } +} + +static int XlatSocketFamily(int x) { + switch (x) { + XLAT(0, AF_INET); + XLAT(2, AF_INET); + default: + return epfnosupport(); + } +} + +static int XlatSocketType(int x) { + switch (x) { + XLAT(1, SOCK_STREAM); + XLAT(2, SOCK_DGRAM); + default: + return einval(); + } +} + +static int XlatSocketProtocol(int x) { + switch (x) { + XLAT(6, IPPROTO_TCP); + XLAT(17, IPPROTO_UDP); + default: + return einval(); + } +} + +static unsigned XlatSocketFlags(int flags) { + unsigned res = 0; + if (flags & 0x080000) res |= SOCK_CLOEXEC; + if (flags & 0x000800) res |= SOCK_NONBLOCK; + return res; +} + +static int XlatSocketLevel(int x) { + switch (x) { + XLAT(0, SOL_IP); + XLAT(1, SOL_SOCKET); + XLAT(6, SOL_TCP); + XLAT(17, SOL_UDP); + default: + return einval(); + } +} + +static int XlatSocketOptname(int x) { + switch (x) { + XLAT(2, SO_REUSEADDR); + XLAT(15, SO_REUSEPORT); + XLAT(9, SO_KEEPALIVE); + XLAT(5, SO_DONTROUTE); + XLAT(7, SO_SNDBUF); + XLAT(8, SO_RCVBUF); + XLAT(13, SO_LINGER); + default: + return einval(); } } @@ -130,12 +210,12 @@ static int XlatAccess(int x) { static int XlatSigaction(int x) { unsigned res = 0; + if (x & 0x00000001) res |= SA_NOCLDSTOP; + if (x & 0x00000002) res |= SA_NOCLDWAIT; + if (x & 0x00000004) res |= SA_SIGINFO; if (x & 0x04000000) res |= SA_RESTORER; if (x & 0x08000000) res |= SA_ONSTACK; if (x & 0x10000000) res |= SA_RESTART; - if (x & 1) res |= SA_NOCLDSTOP; - if (x & 2) res |= SA_NOCLDWAIT; - if (x & 4) res |= SA_SIGINFO; if (x & 0x40000000) res |= SA_NODEFER; if (x & 0x40000000) res |= SA_NOMASK; if (x & 0x80000000) res |= SA_RESETHAND; @@ -242,6 +322,26 @@ static unsigned XlatOpenFlags(unsigned flags) { return res; } +static int XlatFcntlCmd(int cmd) { + switch (cmd) { + XLAT(1, F_GETFD); + XLAT(2, F_SETFD); + XLAT(3, F_GETFL); + XLAT(4, F_SETFL); + default: + return einval(); + } +} + +static int XlatFcntlArg(int arg) { + switch (arg) { + XLAT(0, 0); + XLAT(1, FD_CLOEXEC); + default: + return einval(); + } +} + static struct sigaction *CoerceSigactionToCosmo( struct sigaction *dst, const struct sigaction$linux *src) { if (!src) return NULL; @@ -311,6 +411,36 @@ static void *GetDirectBuf(struct Machine *m, int64_t addr, size_t *size) { return page; } +static struct iovec *GetDirectIov(struct Machine *m, int64_t addr, int *len) { + int i; + size_t n, size; + struct iovec *iov; + if (!__builtin_mul_overflow(sizeof(*iov), *len, &n) && n <= 0x7ffff000) { + if ((iov = malloc(n))) { + VirtualSend(m, iov, addr, n); + SetReadAddr(m, addr, n); + for (i = 0; i < *len; ++i) { + size = iov[i].iov_len; + if ((iov[i].iov_base = GetDirectBuf( + m, (int64_t)(intptr_t)iov[i].iov_base, &size)) == MAP_FAILED) { + free(iov); + return (struct iovec *)efault(); + } + if (size < iov[i].iov_len) { + iov[i].iov_len = size; + *len = i + 1; + break; + } + } + return iov; + } else { + return (struct iovec *)-1; + } + } else { + return (struct iovec *)eoverflow(); + } +} + static int OpClose(struct Machine *m, int fd) { int rc; struct FdClosed *closed; @@ -356,6 +486,124 @@ static int OpPipe(struct Machine *m, int64_t pipefds_addr) { return rc; } +static int OpDup(struct Machine *m, int fd) { + int i, rc; + if ((fd = XlatFd(m, fd)) == -1) return -1; + if ((i = MachineFdAdd(&m->fds)) == -1) return -1; + if ((rc = dup(fd)) != -1) { + m->fds.p[i].cb = &kMachineFdCbHost; + m->fds.p[i].fd = rc; + rc = i; + } else { + MachineFdRemove(&m->fds, i); + } + return rc; +} + +static int OpDup2(struct Machine *m, int fd, int newfd) { + int i, rc; + if ((fd = XlatFd(m, fd)) == -1) return -1; + if ((0 <= newfd && newfd < m->fds.i)) { + if ((rc = dup2(fd, m->fds.p[newfd].fd)) != -1) { + m->fds.p[newfd].cb = &kMachineFdCbHost; + m->fds.p[newfd].fd = rc; + rc = newfd; + } + } else if ((i = MachineFdAdd(&m->fds)) != -1) { + if ((rc = dup(fd)) != -1) { + m->fds.p[i].cb = &kMachineFdCbHost; + m->fds.p[i].fd = rc; + rc = i; + } + } else { + rc = -1; + } + return rc; +} + +static int OpSocket(struct Machine *m, int family, int type, int protocol) { + int i, fd; + if ((family = XlatSocketFamily(family)) == -1) return -1; + if ((type = XlatSocketType(type)) == -1) return -1; + if ((protocol = XlatSocketProtocol(protocol)) == -1) return -1; + if ((i = MachineFdAdd(&m->fds)) == -1) return -1; + if ((fd = socket(family, type, protocol)) != -1) { + m->fds.p[i].cb = &kMachineFdCbHost; + m->fds.p[i].fd = fd; + fd = i; + } else { + MachineFdRemove(&m->fds, i); + } + return fd; +} + +static int OpAccept4(struct Machine *m, int fd, int64_t addraddr, + int64_t addrsizeaddr, int flags) { + int i, rc; + void *addr; + uint8_t b[4]; + uint32_t addrsize; + if ((fd = XlatFd(m, fd)) == -1) return -1; + VirtualSend(m, b, addrsizeaddr, 4); + SetReadAddr(m, addrsizeaddr, 4); + addrsize = Read32(b); + if (!(addr = malloc(addrsize))) return -1; + if ((i = rc = MachineFdAdd(&m->fds)) != -1) { + if ((rc = accept4(fd, addr, &addrsize, XlatSocketFlags(flags))) != -1) { + Write32(b, addrsize); + VirtualRecv(m, addrsizeaddr, b, 4); + VirtualRecv(m, addraddr, addr, addrsize); + SetWriteAddr(m, addraddr, addrsize); + m->fds.p[i].cb = &kMachineFdCbHost; + m->fds.p[i].fd = rc; + rc = i; + } else { + MachineFdRemove(&m->fds, i); + } + } + free(addr); + return rc; +} + +static int OpConnectBind(struct Machine *m, int fd, intptr_t addraddr, + uint32_t addrsize, + int impl(int, const void *, uint32_t)) { + int rc; + void *addr; + if ((fd = XlatFd(m, fd)) == -1) return -1; + if (!(addr = malloc(addrsize))) return -1; + VirtualSend(m, addr, addraddr, addrsize); + SetReadAddr(m, addraddr, addrsize); + rc = impl(fd, addr, addrsize); + free(addr); + return rc; +} + +static int OpBind(struct Machine *m, int fd, intptr_t addraddr, + uint32_t addrsize) { + return OpConnectBind(m, fd, addraddr, addrsize, bind); +} + +static int OpConnect(struct Machine *m, int fd, int64_t addraddr, + uint32_t addrsize) { + return OpConnectBind(m, fd, addraddr, addrsize, connect); +} + +static int OpSetsockopt(struct Machine *m, int fd, int level, int optname, + int64_t optvaladdr, uint32_t optvalsize) { + int rc; + void *optval; + if ((level = XlatSocketLevel(level)) == -1) return -1; + if ((optname = XlatSocketOptname(optname)) == -1) return -1; + if ((fd = XlatFd(m, fd)) == -1) return -1; + if (!(optval = malloc(optvalsize))) return -1; + VirtualSend(m, optval, optvaladdr, optvalsize); + SetReadAddr(m, optvaladdr, optvalsize); + rc = setsockopt(fd, level, optname, optval, optvalsize); + free(optval); + return rc; +} + static ssize_t OpRead(struct Machine *m, int fd, int64_t addr, size_t size) { void *data; ssize_t rc; @@ -378,6 +626,22 @@ static ssize_t OpWrite(struct Machine *m, int fd, int64_t addr, size_t size) { return rc; } +static int OpIoctl(struct Machine *m, int fd, uint64_t request, + int64_t memaddr) { + int rc; + struct winsize ws; + if (!(0 <= fd && fd < m->fds.i) || !m->fds.p[fd].cb) return ebadf(); + switch (request) { + case TIOCGWINSZ_LINUX: + rc = (m->fds.p[fd].cb->ioctl)(m->fds.p[fd].fd, TIOCGWINSZ, &ws); + VirtualRecv(m, memaddr, &ws, sizeof(ws)); + SetWriteAddr(m, memaddr, sizeof(ws)); + return rc; + default: + return einval(); + } +} + static ssize_t OpPread(struct Machine *m, int fd, int64_t addr, size_t size, int64_t offset) { void *data; @@ -398,6 +662,37 @@ static ssize_t OpPwrite(struct Machine *m, int fd, int64_t addr, size_t size, return rc; } +static ssize_t OpReadv(struct Machine *m, int fd, int64_t iovaddr, int iovlen) { + ssize_t rc; + struct iovec *iov; + if ((fd = XlatFd(m, fd)) == -1) return -1; + if ((iov = GetDirectIov(m, iovaddr, &iovlen)) == MAP_FAILED) return -1; + rc = readv(fd, iov, iovlen); + free(iov); + return rc; +} + +static ssize_t OpWritev(struct Machine *m, int fd, int64_t iovaddr, + int iovlen) { + ssize_t rc; + struct iovec *iov; + if ((fd = XlatFd(m, fd)) == -1) return -1; + if ((iov = GetDirectIov(m, iovaddr, &iovlen)) == MAP_FAILED) return -1; + rc = writev(fd, iov, iovlen); + free(iov); + return rc; +} + +static int64_t OpLseek(struct Machine *m, int fd, int64_t offset, int whence) { + if ((fd = XlatFd(m, fd)) == -1) return -1; + return lseek(fd, offset, whence); +} + +static ssize_t OpFtruncate(struct Machine *m, int fd, int64_t size) { + if ((fd = XlatFd(m, fd)) == -1) return -1; + return ftruncate(fd, size); +} + static int OpFaccessat(struct Machine *m, int dirfd, int64_t path, int mode, int flags) { flags = XlatAtf(flags); @@ -436,6 +731,38 @@ static int OpFstat(struct Machine *m, int fd, int64_t st) { return rc; } +static int OpListen(struct Machine *m, int fd, int backlog) { + if ((fd = XlatFd(m, fd)) == -1) return -1; + return listen(fd, backlog); +} + +static int OpShutdown(struct Machine *m, int fd, int how) { + if ((fd = XlatFd(m, fd)) == -1) return -1; + return shutdown(fd, how); +} + +static int OpFsync(struct Machine *m, int fd) { + if ((fd = XlatFd(m, fd)) == -1) return -1; + return fsync(fd); +} + +static int OpFdatasync(struct Machine *m, int fd) { + if ((fd = XlatFd(m, fd)) == -1) return -1; + return fdatasync(fd); +} + +static int OpFchmod(struct Machine *m, int fd, uint32_t mode) { + if ((fd = XlatFd(m, fd)) == -1) return -1; + return fchmod(fd, mode); +} + +static int OpFcntl(struct Machine *m, int fd, int cmd, int arg) { + if ((cmd = XlatFcntlCmd(cmd)) == -1) return -1; + if ((arg = XlatFcntlArg(arg)) == -1) return -1; + if ((fd = XlatFd(m, fd)) == -1) return -1; + return fcntl(fd, cmd, arg); +} + static int OpChdir(struct Machine *m, int64_t path) { return chdir(LoadStr(m, path)); } @@ -477,6 +804,15 @@ static int OpChmod(struct Machine *m, int64_t path, uint32_t mode) { return chmod(LoadStr(m, path), mode); } +static int OpFork(struct Machine *m) { + return enosys(); +} + +static int OpExecve(struct Machine *m, int64_t programaddr, int64_t argvaddr, + int64_t envpaddr) { + return enosys(); +} + static int64_t OpGetcwd(struct Machine *m, int64_t bufaddr, size_t size) { size_t n; char *buf; @@ -496,6 +832,7 @@ static int64_t OpGetcwd(struct Machine *m, int64_t bufaddr, size_t size) { } static int OpSigaction(struct Machine *m, int sig, int64_t act, int64_t old) { + return 0; int rc; struct OpSigactionMemory { struct sigaction act, old; @@ -560,6 +897,44 @@ static int OpGettimeofday(struct Machine *m, int64_t tv, int64_t tz) { return rc; } +static int OpPoll(struct Machine *m, int64_t fdsaddr, uint64_t nfds, + int32_t timeout_ms) { + int rc; + size_t n; + struct pollfd *fds; + if (!__builtin_mul_overflow(sizeof(*fds), nfds, &n) && n <= 0x7ffff000) { + if ((fds = malloc(n))) { + VirtualSend(m, fds, fdsaddr, n); + SetReadAddr(m, fdsaddr, n); + rc = poll(fds, nfds, timeout_ms); + free(fds); + return rc; + } else { + return enomem(); + } + } else { + return einval(); + } +} + +static int OpSigprocmask(struct Machine *m, int how, int64_t setaddr, + int64_t oldsetaddr) { + int rc; + sigset_t *set, oldset, ss; + if (setaddr) { + set = &ss; + memset(set, 0, sizeof(ss)); + VirtualSend(m, set, setaddr, 8); + } else { + set = NULL; + } + if ((rc = sigprocmask(XlatSig(how), set, &oldset)) != -1) { + if (setaddr) VirtualRecv(m, setaddr, set, 8); + if (oldsetaddr) VirtualRecv(m, oldsetaddr, &oldset, 8); + } + return rc; +} + static int DoOpen(struct Machine *m, int64_t path, int flags, int mode) { return OpOpenat(m, AT_FDCWD_LINUX, path, flags, mode); } @@ -580,15 +955,20 @@ static int DoLstat(struct Machine *m, int64_t path, int64_t st) { return OpFstatat(m, AT_FDCWD_LINUX, path, st, 0x0400); } -void OpSyscall(struct Machine *m) { +static int DoAccept(struct Machine *m, int fd, int64_t addraddr, + int64_t addrsizeaddr) { + return OpAccept4(m, fd, addraddr, addrsizeaddr, 0); +} + +void OpSyscall(struct Machine *m, uint32_t rde) { uint64_t i, ax, di, si, dx, r0, r8, r9; ax = Read64(m->ax); di = Read64(m->di); si = Read64(m->si); dx = Read64(m->dx); - r0 = Read32(m->r10); - r8 = Read32(m->r8); - r9 = Read32(m->r9); + r0 = Read64(m->r10); + r8 = Read64(m->r8); + r9 = Read64(m->r9); switch (ax & 0x1ff) { SYSCALL(0x000, OpRead(m, di, si, dx)); SYSCALL(0x001, OpWrite(m, di, si, dx)); @@ -597,26 +977,26 @@ void OpSyscall(struct Machine *m) { SYSCALL(0x004, DoStat(m, di, si)); SYSCALL(0x005, OpFstat(m, di, si)); SYSCALL(0x006, DoLstat(m, di, si)); - SYSCALL(0x007, poll(PNN(di), si, dx)); - SYSCALL(0x008, lseek(di, si, dx)); + SYSCALL(0x007, OpPoll(m, di, si, dx)); + SYSCALL(0x008, OpLseek(m, di, si, dx)); SYSCALL(0x009, OpMmap(m, di, si, dx, r0, r8, r9)); SYSCALL(0x01A, OpMsync(m, di, si, dx)); SYSCALL(0x00A, OpMprotect(m, di, si, dx)); SYSCALL(0x00B, OpMunmap(m, di, si)); SYSCALL(0x00D, OpSigaction(m, di, si, dx)); - SYSCALL(0x00E, sigprocmask(di, P(si), P(dx))); - SYSCALL(0x010, ioctl(di, si, P(dx))); + SYSCALL(0x00E, OpSigprocmask(m, di, si, dx)); + SYSCALL(0x010, OpIoctl(m, di, si, dx)); SYSCALL(0x011, OpPread(m, di, si, dx, r0)); SYSCALL(0x012, OpPwrite(m, di, si, dx, r0)); - SYSCALL(0x013, readv(di, P(si), dx)); - SYSCALL(0x014, writev(di, P(si), dx)); + SYSCALL(0x013, OpReadv(m, di, si, dx)); + SYSCALL(0x014, OpWritev(m, di, si, dx)); SYSCALL(0x015, DoAccess(m, di, si)); SYSCALL(0x016, OpPipe(m, di)); SYSCALL(0x017, select(di, P(si), P(dx), P(r0), P(r8))); SYSCALL(0x018, sched_yield()); SYSCALL(0x01C, OpMadvise(m, di, si, dx)); - SYSCALL(0x020, dup(di)); - SYSCALL(0x021, dup2(di, si)); + SYSCALL(0x020, OpDup(m, di)); + SYSCALL(0x021, OpDup2(m, di, si)); SYSCALL(0x022, pause()); SYSCALL(0x023, OpNanosleep(m, di, si)); SYSCALL(0x024, getitimer(di, PNN(si))); @@ -624,29 +1004,29 @@ void OpSyscall(struct Machine *m) { SYSCALL(0x026, setitimer(di, PNN(si), P(dx))); SYSCALL(0x027, getpid()); SYSCALL(0x028, sendfile(di, si, P(dx), r0)); - SYSCALL(0x029, socket(di, si, dx)); - SYSCALL(0x02A, connect(di, PNN(si), dx)); - SYSCALL(0x02B, accept(di, PNN(di), PNN(dx))); + SYSCALL(0x029, OpSocket(m, di, si, dx)); + SYSCALL(0x02A, OpConnect(m, di, si, dx)); + SYSCALL(0x02B, DoAccept(m, di, di, dx)); SYSCALL(0x02C, sendto(di, PNN(si), dx, r0, P(r8), r9)); SYSCALL(0x02D, recvfrom(di, P(si), dx, r0, P(r8), P(r9))); - SYSCALL(0x030, shutdown(di, si)); - SYSCALL(0x031, bind(di, PNN(si), dx)); - SYSCALL(0x032, listen(di, si)); + SYSCALL(0x030, OpShutdown(m, di, si)); + SYSCALL(0x031, OpBind(m, di, si, dx)); + SYSCALL(0x032, OpListen(m, di, si)); SYSCALL(0x033, getsockname(di, PNN(si), PNN(dx))); SYSCALL(0x034, getpeername(di, PNN(si), PNN(dx))); - SYSCALL(0x036, setsockopt(di, si, dx, PNN(r0), r8)); + SYSCALL(0x036, OpSetsockopt(m, di, si, dx, r0, r8)); SYSCALL(0x037, getsockopt(di, si, dx, PNN(r0), PNN(r8))); - SYSCALL(0x039, fork()); - SYSCALL(0x03B, execve(PNN(r8), PNN(r8), PNN(r8))); + SYSCALL(0x039, OpFork(m)); + SYSCALL(0x03B, OpExecve(m, di, si, dx)); SYSCALL(0x03D, wait4(di, P(si), dx, P(r0))); SYSCALL(0x03E, kill(di, si)); SYSCALL(0x03F, uname(P(di))); - SYSCALL(0x048, fcntl(di, si, dx)); + SYSCALL(0x048, OpFcntl(m, di, si, dx)); SYSCALL(0x049, flock(di, si)); - SYSCALL(0x04A, fsync(di)); - SYSCALL(0x04B, fdatasync(di)); + SYSCALL(0x04A, OpFsync(m, di)); + SYSCALL(0x04B, OpFdatasync(m, di)); SYSCALL(0x04C, OpTruncate(m, di, si)); - SYSCALL(0x04D, ftruncate(di, si)); + SYSCALL(0x04D, OpFtruncate(m, di, si)); SYSCALL(0x04F, OpGetcwd(m, di, si)); SYSCALL(0x050, OpChdir(m, di)); SYSCALL(0x052, OpRename(m, di, si)); @@ -657,7 +1037,7 @@ void OpSyscall(struct Machine *m) { SYSCALL(0x057, OpUnlink(m, di)); SYSCALL(0x058, OpSymlink(m, di, si)); SYSCALL(0x05A, OpChmod(m, di, si)); - SYSCALL(0x05B, fchmod(di, si)); + SYSCALL(0x05B, OpFchmod(m, di, si)); SYSCALL(0x060, OpGettimeofday(m, di, si)); SYSCALL(0x061, getrlimit(di, P(si))); SYSCALL(0x062, getrusage(di, P(si))); @@ -691,6 +1071,7 @@ void OpSyscall(struct Machine *m) { SYSCALL(0x113, splice(di, P(si), dx, P(r0), r8, XlatAtf(r9))); SYSCALL(0x115, sync_file_range(di, si, dx, XlatAtf(r0))); SYSCALL(0x118, utimensat(XlatAfd(m, di), P(si), P(dx), XlatAtf(r0))); + SYSCALL(0x120, OpAccept4(m, di, si, dx, r0)); SYSCALL(0x177, vmsplice(di, P(si), dx, r0)); CASE(0xE7, HaltMachine(m, di | 0x100)); default: diff --git a/tool/build/lib/syscall.h b/tool/build/lib/syscall.h index 4a4429ea..0421d53f 100644 --- a/tool/build/lib/syscall.h +++ b/tool/build/lib/syscall.h @@ -7,7 +7,7 @@ COSMOPOLITAN_C_START_ extern const struct MachineFdCb kMachineFdCbHost; -void OpSyscall(struct Machine *); +void OpSyscall(struct Machine *, uint32_t); COSMOPOLITAN_C_END_ #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ diff --git a/tool/build/lib/throw.c b/tool/build/lib/throw.c index ec9a3cd1..9741e367 100644 --- a/tool/build/lib/throw.c +++ b/tool/build/lib/throw.c @@ -20,6 +20,7 @@ #include "libc/log/check.h" #include "libc/runtime/runtime.h" #include "libc/str/str.h" +#include "tool/build/lib/address.h" #include "tool/build/lib/throw.h" static bool IsHaltingInitialized(struct Machine *m) { @@ -39,7 +40,7 @@ void ThrowDivideError(struct Machine *m) { void ThrowSegmentationFault(struct Machine *m, int64_t va) { m->faultaddr = va; - if (m->xedd) m->ip -= m->xedd->length; + m->ip -= m->xedd->length; HaltMachine(m, kMachineSegmentationFault); } @@ -47,15 +48,12 @@ void ThrowProtectionFault(struct Machine *m) { HaltMachine(m, kMachineProtectionFault); } -void OpUd(struct Machine *m) { +void OpUd(struct Machine *m, uint32_t rde) { + DebugBreak(); m->ip -= m->xedd->length; HaltMachine(m, kMachineUndefinedInstruction); } -void OpHlt(struct Machine *m) { +void OpHlt(struct Machine *m, uint32_t rde) { HaltMachine(m, kMachineHalt); } - -void OpInterrupt(struct Machine *m, int i) { - HaltMachine(m, i); -} diff --git a/tool/build/lib/throw.h b/tool/build/lib/throw.h index f88ff8a2..f0903cff 100644 --- a/tool/build/lib/throw.h +++ b/tool/build/lib/throw.h @@ -4,13 +4,12 @@ #if !(__ASSEMBLER__ + __LINKER__ + 0) COSMOPOLITAN_C_START_ -void OpUd(struct Machine *) noreturn; +void OpUd(struct Machine *, uint32_t) noreturn; void HaltMachine(struct Machine *, int) noreturn; void ThrowDivideError(struct Machine *) noreturn; void ThrowSegmentationFault(struct Machine *, int64_t) noreturn; void ThrowProtectionFault(struct Machine *) noreturn; -void OpHlt(struct Machine *) noreturn; -void OpInterrupt(struct Machine *, int) noreturn; +void OpHlt(struct Machine *, uint32_t) noreturn; COSMOPOLITAN_C_END_ #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ diff --git a/tool/build/lib/time.c b/tool/build/lib/time.c index 0fac5e20..bdd72478 100644 --- a/tool/build/lib/time.c +++ b/tool/build/lib/time.c @@ -17,16 +17,21 @@ │ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │ │ 02110-1301 USA │ ╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/calls/calls.h" #include "libc/nexgen32e/rdtsc.h" #include "libc/sysv/consts/clock.h" #include "libc/time/time.h" #include "tool/build/lib/endian.h" #include "tool/build/lib/time.h" +void OpPause(struct Machine *m, uint32_t rde) { + sched_yield(); +} + /** * I am the timelorde. */ -void OpRdtsc(struct Machine *m) { +void OpRdtsc(struct Machine *m, uint32_t rde) { uint64_t c; #ifdef __x86_64__ c = rdtsc(); @@ -38,3 +43,12 @@ void OpRdtsc(struct Machine *m) { Write64(m->ax, (c >> 000) & 0xffffffff); Write64(m->dx, (c >> 040) & 0xffffffff); } + +void OpRdtscp(struct Machine *m, uint32_t rde) { + uint32_t core, node, tscaux; + OpRdtsc(m, rde); + core = 0; + node = 0; + tscaux = (node & 0xfff) << 12 | (core & 0xfff); + Write64(m->ax, tscaux & 0xffffffff); +} diff --git a/tool/build/lib/time.h b/tool/build/lib/time.h index 739230bb..04662194 100644 --- a/tool/build/lib/time.h +++ b/tool/build/lib/time.h @@ -4,7 +4,9 @@ #if !(__ASSEMBLER__ + __LINKER__ + 0) COSMOPOLITAN_C_START_ -void OpRdtsc(struct Machine *); +void OpPause(struct Machine *, uint32_t); +void OpRdtsc(struct Machine *, uint32_t); +void OpRdtscp(struct Machine *, uint32_t); COSMOPOLITAN_C_END_ #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ diff --git a/tool/build/lib/x87.h b/tool/build/lib/x87.h deleted file mode 100644 index 33e19105..00000000 --- a/tool/build/lib/x87.h +++ /dev/null @@ -1,15 +0,0 @@ -#ifndef COSMOPOLITAN_TOOL_BUILD_LIB_X87_H_ -#define COSMOPOLITAN_TOOL_BUILD_LIB_X87_H_ -#if !(__ASSEMBLER__ + __LINKER__ + 0) -COSMOPOLITAN_C_START_ - -long double f2xm1(long double); -long double fyl2x(long double, long double); -long double fyl2xp1(long double, long double); -long double fscale(long double, long double); -long double fprem(long double, long double, uint32_t *); -long double fprem1(long double, long double, uint32_t *); - -COSMOPOLITAN_C_END_ -#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ -#endif /* COSMOPOLITAN_TOOL_BUILD_LIB_X87_H_ */ diff --git a/tool/build/refactor.c b/tool/build/refactor.c index 05334102..349619a0 100644 --- a/tool/build/refactor.c +++ b/tool/build/refactor.c @@ -111,12 +111,12 @@ void RefactorFile(const char *path) { void RefactorDir(const char *dpath) { DIR *dir; struct dirent *ent; - char *path = gc(xmalloc(PATH_MAX)); + char *path = gc(xmalloc(4096)); CHECK_NOTNULL(dir = opendir(firstnonnull(dpath, "."))); while ((ent = readdir(dir))) { if (startswith(ent->d_name, ".")) continue; if (strcmp(ent->d_name, "o") == 0) continue; - snprintf(path, PATH_MAX, "%s%s%s", dpath ? dpath : "", dpath ? "/" : "", + snprintf(path, 4096, "%s%s%s", dpath ? dpath : "", dpath ? "/" : "", ent->d_name); if (isdirectory(path)) { RefactorDir(path); diff --git a/tool/build/tinyemu.c b/tool/build/tinyemu.c index 1532d9a9..c8511352 100644 --- a/tool/build/tinyemu.c +++ b/tool/build/tinyemu.c @@ -17,6 +17,8 @@ │ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │ │ 02110-1301 USA │ ╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/log/log.h" +#include "libc/mem/mem.h" #include "libc/runtime/runtime.h" #include "libc/stdio/stdio.h" #include "libc/sysv/consts/ex.h" @@ -24,6 +26,8 @@ #include "libc/x/x.h" #include "tool/build/lib/loader.h" #include "tool/build/lib/machine.h" +#include "tool/build/lib/memory.h" +#include "tool/build/lib/pty.h" #include "tool/build/lib/syscall.h" struct Machine m[1]; @@ -32,6 +36,7 @@ int main(int argc, char *argv[]) { int rc; struct Elf elf; const char *codepath; + showcrashreports(); codepath = argv[1]; if (argc < 2) { fputs("Usage: ", stderr); @@ -39,6 +44,8 @@ int main(int argc, char *argv[]) { fputs(" PROG [ARGS...]\n", stderr); return EX_USAGE; } + m->cr3 = MallocPage(); + m->mode = XED_MACHINE_MODE_LONG_64; InitMachine(m); LoadProgram(m, argv[1], argv + 2, environ, &elf); m->fds.i = 3; diff --git a/tool/decode/decode.mk b/tool/decode/decode.mk index afc6d744..02a67d4f 100644 --- a/tool/decode/decode.mk +++ b/tool/decode/decode.mk @@ -36,6 +36,7 @@ TOOL_DECODE_DIRECTDEPS = \ LIBC_STR \ LIBC_STUBS \ LIBC_SYSV \ + LIBC_SYSV_CALLS \ LIBC_UNICODE \ LIBC_X \ TOOL_DECODE_LIB \ diff --git a/tool/decode/getdents.c b/tool/decode/getdents.c new file mode 100644 index 00000000..69d65f22 --- /dev/null +++ b/tool/decode/getdents.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 2020 Justine Alexandra Roberts Tunney │ +│ │ +│ This program is free software; you can redistribute it and/or modify │ +│ it under the terms of the GNU General Public License as published by │ +│ the Free Software Foundation; version 2 of the License. │ +│ │ +│ This program is distributed in the hope that it will be useful, but │ +│ WITHOUT ANY WARRANTY; without even the implied warranty of │ +│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │ +│ General Public License for more details. │ +│ │ +│ You should have received a copy of the GNU General Public License │ +│ along with this program; if not, write to the Free Software │ +│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │ +│ 02110-1301 USA │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/calls/calls.h" +#include "libc/calls/internal.h" +#include "libc/mem/mem.h" +#include "libc/stdio/stdio.h" +#include "libc/str/str.h" +#include "libc/sysv/consts/o.h" + +int main(int argc, char *argv[]) { + char *p; + int i, j, rc, fd; + char16_t glyphs[17] = {0}; + p = malloc(4096); + fd = open(".", O_RDONLY | O_DIRECTORY | O_CLOEXEC, 0); + if ((rc = getdents(fd, p, 4096)) != -1) { + for (i = 0; i < ROUNDUP(rc, 16); ++i) { + if (i % 16 == 0) printf("%08x ", i); + if (i < rc) { + glyphs[i % 16] = kCp437[p[i] & 0xff]; + printf("%02x ", p[i] & 0xff); + } else { + glyphs[i % 16] = u'\0'; + printf(" "); + } + if (i % 8 == 7) printf(" "); + if (i % 16 == 15) printf("%hs\n", glyphs); + } + } + close(fd); + free(p); + return 0; +} diff --git a/tool/decode/x86opinfo.c b/tool/decode/x86opinfo.c index e42f13c9..90e2ac96 100644 --- a/tool/decode/x86opinfo.c +++ b/tool/decode/x86opinfo.c @@ -192,7 +192,6 @@ int main(int argc, char *argv[]) { SHOWOP(hint); SHOWOP(ild_f2); SHOWOP(ild_f3); - SHOWOP(ild_seg); SHOWOP(imm1_bytes); SHOWOP(imm_width); SHOWOP(imm_signed); diff --git a/tool/emacs/cosmo-c-builtins.el b/tool/emacs/cosmo-c-builtins.el index 8c0388e5..d50174c0 100644 --- a/tool/emacs/cosmo-c-builtins.el +++ b/tool/emacs/cosmo-c-builtins.el @@ -69,6 +69,7 @@ "__builtin_va_end" "__builtin_abs" "__builtin_strcpy" + "__builtin_stpcpy" "__builtin_setjmp" "__builtin_longjmp" "__builtin_apply_args" @@ -224,6 +225,9 @@ "__builtin_floor" "__builtin_floorf" "__builtin_floorl" + "__builtin_trunc" + "__builtin_truncf" + "__builtin_truncl" "__builtin_round" "__builtin_roundf" "__builtin_roundl" diff --git a/tool/emacs/cosmo-cpp-constants.el b/tool/emacs/cosmo-cpp-constants.el index cb0c528d..be86fde7 100644 --- a/tool/emacs/cosmo-cpp-constants.el +++ b/tool/emacs/cosmo-cpp-constants.el @@ -24,7 +24,29 @@ "__FLT_MIN__" "__FLT_MAX__" "__WCHAR_MAX__" - "__WCHAR_UNSIGNED__")) + "__WCHAR_UNSIGNED__" + "__AES__" + "__AVX__" + "__AVX2__" + "__ABM__" + "__BMI__" + "__BMI2__" + "__FMA__" + "__ADX__" + "__PCLMUL__" + "__POPCNT__" + "__RDRND__" + "__RDSEED__" + "__SHA__" + "__SSE__" + "__SSE2__" + "__SSE3__" + "__SSSE3__" + "__SSE4_1__" + "__SSE4_2__" + "__XSAVE__" + "__CLFLUSHOPT__" + "__RDPID__")) (defconst cosmo-cpp-constants-gcc-92 '("__x86_64__" diff --git a/tool/emacs/cosmo-format.el b/tool/emacs/cosmo-format.el index c4b50e9b..68522f81 100644 --- a/tool/emacs/cosmo-format.el +++ b/tool/emacs/cosmo-format.el @@ -111,6 +111,7 @@ ".clang-format") "-style=file")))) (when arg + (message arg) (write-region nil nil tmp) (let ((buf (get-buffer-create "*clang-format*")) (exe (cosmo--find-clang-format-bin))) diff --git a/tool/net/net.mk b/tool/net/net.mk index 7b7fdd43..6c5a531d 100644 --- a/tool/net/net.mk +++ b/tool/net/net.mk @@ -20,6 +20,7 @@ TOOL_NET_BINS = \ TOOL_NET_DIRECTDEPS = \ LIBC_CALLS \ + LIBC_CONV \ LIBC_DNS \ LIBC_FMT \ LIBC_LOG \ @@ -30,8 +31,10 @@ TOOL_NET_DIRECTDEPS = \ LIBC_STR \ LIBC_STUBS \ LIBC_SYSV \ + LIBC_TIME \ LIBC_UNICODE \ LIBC_X \ + NET_HTTP \ THIRD_PARTY_GETOPT \ TOOL_DECODE_LIB @@ -50,9 +53,13 @@ o/$(MODE)/tool/net/%.com.dbg: \ $(APE) @$(APELINK) -$(TOOL_NET_OBJS): \ - $(BUILD_FILES) \ - tool/net/net.mk +ifeq (,$(MODE)) +$(TOOL_NET_A_OBJS): \ + OVERRIDE_CFLAGS += \ + -fsanitize=address +endif .PHONY: o/$(MODE)/tool/net -o/$(MODE)/tool/net: $(TOOL_NET_BINS) $(TOOL_NET_CHECKS) +o/$(MODE)/tool/net: \ + $(TOOL_NET_BINS) \ + $(TOOL_NET_CHECKS) diff --git a/tool/net/redbean.c b/tool/net/redbean.c new file mode 100644 index 00000000..097f69c1 --- /dev/null +++ b/tool/net/redbean.c @@ -0,0 +1,217 @@ +/*-*- 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 │ +│ │ +│ This program is free software; you can redistribute it and/or modify │ +│ it under the terms of the GNU General Public License as published by │ +│ the Free Software Foundation; version 2 of the License. │ +│ │ +│ This program is distributed in the hope that it will be useful, but │ +│ WITHOUT ANY WARRANTY; without even the implied warranty of │ +│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │ +│ General Public License for more details. │ +│ │ +│ You should have received a copy of the GNU General Public License │ +│ along with this program; if not, write to the Free Software │ +│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │ +│ 02110-1301 USA │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/calls/calls.h" +#include "libc/calls/weirdtypes.h" +#include "libc/conv/conv.h" +#include "libc/conv/itoa.h" +#include "libc/errno.h" +#include "libc/fmt/fmt.h" +#include "libc/log/check.h" +#include "libc/log/log.h" +#include "libc/runtime/gc.h" +#include "libc/runtime/runtime.h" +#include "libc/sock/sock.h" +#include "libc/stdio/stdio.h" +#include "libc/str/str.h" +#include "libc/sysv/consts/af.h" +#include "libc/sysv/consts/ex.h" +#include "libc/sysv/consts/exit.h" +#include "libc/sysv/consts/f.h" +#include "libc/sysv/consts/fd.h" +#include "libc/sysv/consts/inaddr.h" +#include "libc/sysv/consts/ipproto.h" +#include "libc/sysv/consts/sa.h" +#include "libc/sysv/consts/shut.h" +#include "libc/sysv/consts/sig.h" +#include "libc/sysv/consts/so.h" +#include "libc/sysv/consts/sock.h" +#include "libc/sysv/consts/sol.h" +#include "libc/time/struct/tm.h" +#include "libc/time/time.h" +#include "libc/x/x.h" +#include "net/http/http.h" +#include "third_party/getopt/getopt.h" + +#define STPCPY(p, s) mempcpy(p, s, strlen(s)) + +bool daemonize; +bool terminated; +int server, client; +const int yes = true; +char serverdate[128]; +struct HttpRequest req; +uint32_t clientaddrsize; +struct sockaddr_in serveraddr; +struct sockaddr_in clientaddr; +char inbuf[PAGESIZE] aligned(PAGESIZE); +char outbuf[PAGESIZE] aligned(PAGESIZE); +char serveraddrstr[32], clientaddrstr[32]; + +void OnTerminate(void) { + terminated = true; +} + +noreturn void ShowUsage(FILE *f, int rc) { + fprintf(f, "%s: %s %s\n", "Usage", program_invocation_name, + "[-?drv] [-l LISTENIP] [-p PORT] [-t TIMEOUTMS]"); + exit(rc); +} + +char *DescribeAddress(char buf[32], const struct sockaddr_in *addr) { + char ip4buf[16]; + sprintf(buf, "%s:%hu", + inet_ntop(addr->sin_family, &addr->sin_addr.s_addr, ip4buf, + sizeof(ip4buf)), + ntohs(addr->sin_port)); + return buf; +} + +void GetOpts(int argc, char *argv[]) { + int opt; + serveraddr.sin_family = AF_INET; + serveraddr.sin_port = htons(8080); + serveraddr.sin_addr.s_addr = INADDR_ANY; + while ((opt = getopt(argc, argv, "?dvl:p:w:")) != -1) { + switch (opt) { + case 'd': + daemonize = true; + break; + case 'v': + g_loglevel++; + break; + case 'p': + CHECK_NE(0xFFFF, (serveraddr.sin_port = htons(parseport(optarg)))); + break; + case 'l': + CHECK_EQ(1, inet_pton(AF_INET, optarg, &serveraddr.sin_addr)); + break; + case '?': + ShowUsage(stdout, EXIT_SUCCESS); + default: + ShowUsage(stderr, EX_USAGE); + } + } +} + +void GenerateHttpDate(char buf[128]) { + int64_t now; + struct tm tm; + time(&now); + gmtime_r(&now, &tm); + strftime(buf, 128, "%a, %d %b %Y %H:%M:%S GMT", &tm); +} + +int CompareHeaderValue(int h, const char *s) { + return strncmp(s, inbuf + req.headers[h].a, + req.headers[h].b - req.headers[h].a); +} + +ssize_t EasyWrite(int fd, const void *data, size_t size) { + char *p; + ssize_t rc; + size_t wrote, n; + p = data; + n = size; + do { + if ((rc = write(fd, p, n)) != -1) { + wrote = rc; + p += wrote; + n -= wrote; + } else { + return -1; + } + } while (n); + return 0; +} + +void SendResponse(const char *data, size_t size) { + ssize_t rc; + if ((rc = EasyWrite(client, data, size)) == -1) { + LOGF("send error %s %s", clientaddrstr, strerror(errno)); + } +} + +void HandleRequest(void) { + int contentlength; + char *p, ibuf[21]; + const char *content = "\ +

Hello World

\r\n\ +"; + CHECK_NE(-1, shutdown(client, SHUT_RD)); + contentlength = strlen(content); + p = outbuf; + p = STPCPY(p, "HTTP/1.1 200 OK\r\n\ +Connection: close\r\n\ +Content-Type: text/html; charset=utf-8\r\n\ +Date: "); + p = stpcpy(p, serverdate); + p = STPCPY(p, "\r\n\ +Content-Length: "); + p = mempcpy(p, ibuf, int64toarray_radix10(contentlength, ibuf)); + p = STPCPY(p, "\r\n\ +\r\n"); + p = mempcpy(p, content, contentlength); + SendResponse(outbuf, p - outbuf); +} + +void ProcessRequest(void) { + size_t got; + ssize_t rc; + clientaddrsize = sizeof(clientaddr); + CHECK_NE(-1, (client = accept4(server, &clientaddr, &clientaddrsize, + SOCK_CLOEXEC))); + VERBOSEF("accepted %s", DescribeAddress(clientaddrstr, &clientaddr)); + if ((rc = read(client, inbuf, sizeof(inbuf))) != -1) { + if ((got = rc)) { + if (ParseHttpRequest(&req, inbuf, got) != -1) { + HandleRequest(); + } else { + LOGF("parse error %s %s", DescribeAddress(clientaddrstr, &clientaddr), + strerror(errno)); + } + } + } else { + LOGF("recv error %s %s", DescribeAddress(clientaddrstr, &clientaddr), + strerror(errno)); + } + VERBOSEF("closing %s", DescribeAddress(clientaddrstr, &clientaddr)); + LOGIFNEG1(close(client)); +} + +int main(int argc, char *argv[]) { + showcrashreports(); + GetOpts(argc, argv); + GenerateHttpDate(serverdate); + xsigaction(SIGINT, OnTerminate, 0, 0, 0); + xsigaction(SIGTERM, OnTerminate, 0, 0, 0); + CHECK_NE(-1, (server = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP))); + LOGIFNEG1(setsockopt(server, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes))); + LOGIFNEG1(setsockopt(server, SOL_SOCKET, SO_REUSEPORT, &yes, sizeof(yes))); + CHECK_NE(-1, bind(server, &serveraddr, sizeof(serveraddr))); + CHECK_NE(-1, listen(server, 10)); + LOGIFNEG1(fcntl(server, F_SETFD, FD_CLOEXEC)); + DescribeAddress(serveraddrstr, &serveraddr); + LOGF("listening on tcp %s", serveraddrstr); + while (!terminated) { + ProcessRequest(); + } + LOGIFNEG1(close(server)); + return 0; +} diff --git a/tool/net/redbean.html b/tool/net/redbean.html new file mode 100644 index 00000000..77d754bc --- /dev/null +++ b/tool/net/redbean.html @@ -0,0 +1,6 @@ + + + + + +

Red Bean

diff --git a/tool/net/redbean.ico b/tool/net/redbean.ico new file mode 100644 index 0000000000000000000000000000000000000000..5222be9c1d2fbca38217ea8211d09b29964d6e01 GIT binary patch literal 16958 zcmeHO2Y6If+WzjHUNSW^lVs9B5D>7eqS%lX6xX%jBC;qd2*d`0fEXbHAxJ`cLVBN+ zne^UBLLih#Cm{qvdZDbk>*~MdarbAP|2;F{JxYSH{APiJ|1E9Y;2^(VoB)|ZF^65r?b#`3qMWE~KCSYCTMJW@z==_g@73=JE1#i@DG2pZz2-h=RAL<@pJey2|xZD(#oJQ`Ia3w-E)uCXOwU8 z82z{cuL-je}6@;-ra6PhjlP35qgIX4}k}(>I93dgA8)a^8;% zgD>rrzqguPZ>qjeN)`Pgm9=Ps@4;JcmbJ%@r?x{k)8P}NsI}9RTDm-_>5P%;dW=-v ztA)SlsJLHE1p^wg_GmvfUny99q*{-FseiiJ;7*tXIpbO;^i(#W zrs4q=mBRMo0U6l_Wt5HQx!qcA-l7!ic8)0UM}ffreM;Liwg`O%2U5+nzsHmI^!d=< z-q9GI)YR`mbr>}RZd7r~NX5IgT;X9OXR*4HtwF=t>NHf^tEQ5EDdi4IDQ{3ow$t9@ ztPj3aP~i~88?E!-_x*p#YNgxmY8YdphAus9#XMl5x&bfR*~e`6q{3=5mFIeJB?TT_ zZiIo$&vNIsy$c;YVBphJU4)78MlLsBLxpX~r5FYS3W=@p$@xj@_2Dtsl>^q10lMc{ z-Bsb-Sk+IX$Cr%OP+6aj3I?@QIOI-^{YEMs(83-gRUREhw!oXHFlH_E8MH3+@mt+0dVM(>#c!H4lXDA(8=qD!QA_|3+|p9sebg8 zMFN3Z?hL~CYybG;EB?+GBRA60SDxqH-E*FBk!L4pc-s*zRSb$Lb4W$igC^Q>coLtm z(3={M-YUr52pu>L4IFgmb89`Qwo^rU2XvIzDid!FH<6{>1==8iAIPZi^zBnDz73^~ zSG<<*9Dn&#nws%-@>HJqS%>4?E&eSJ!vX!*( z(@j*-uEcW*^pI(R!H~NlIzQ;T*+1jgablw(@oBLvsZ>nKePTZ0pjed>Fkwo}`1G{( z!USs|Z{G*}|MZuCzlN1|iY{0xG)VVa)X+H%)qwLmpz#d@QYwd@l@02ty5E3(HNsvk z6%8sVZAeTpBPvQCRsaXYLts@n=t1?+!m54|{78g&Am+20ocmxWnM{V5aBb_Wnd|qfRPCMFA-)QxO;02$9SvP>uL1p(ckj@-_6f&a{gP7kAFy8VkdGRR4?Tx z-x*;Lo6=T^D6LaQ8H1?r_o#K2C6nhy>cZnU@XtLzk=q=(jrzWD)_EoN68dw(QJOrh z&_yS%%5tYV=>87G`=)+9?A9a4amC)MVK;I;#CXe~j7w-&YvaPbjmdAhA_ht*c~}OY zFab002K=ua5Rz>`%xAaVa&NrwFGHWx*l`m`tyVj*_*NT$(bc~G3tYqOAI(LF1@L2T zigHuyv)&U^?kO?lfQ#uTl%m9qW9|&Qxv265L9qW;&ZIYy{o+NkH&;_b$-DghPgo=- zea$jAu4)&2xf?k??9Yd<+XfVzrNc#+mg=U9dFp|uLuJ;4xA~wC-sLAvO&h1B;%*;m z?e(Dp$d7mRDZv>LbU`A_*+2K4jl!8*;zilf{({pB2d~=3E5Qg~LWeRp2;NWg6W%^K z%~Pq&iO^C>ml`onLzXVNIx%?SFT=d%1uqo{{1$N!@(*!9pCZ4gp_a^GJ|g6x;MTj7 zyyPNVq?qDIB$RUcwg+O|;`3h+Y*;;;ublTRDO-0_dr%NJZ@xth&UYHA1-ZihJ~OrS zK|A|}&;X&((!?v*hVz1;LkjP>Ics)D2>y6s&vnJ%@BjD*6|Gsxk8!V^rseV~b;_9F zIg8#^>-ffcrc)Zq8d6f$ppe44g|5->-2Y6N@_6B^(5Cyz{=W}W`}R#trl>9`m&VVi z@P?k85mVw>gDG-xNO3T4uUb#DX3YXxf2YulCA_Cw^$H#BM1HszdEy@UfBk?9@?;VG zMW{{A6wr$ELJB%BqLiMoQxa~OcQ)j@+P^Js8#iIf4sRnh99EJAw#JNT<>A3@;=L&b zs_)leU*wbw?MfdJ(T0yD(zso|x28-F>{#C+`}6dx&FgrXGCx{GiNhj6 za?`qyAkpIwM@rs&H(Zea{yKiz%t{YEwX~^VzZv$sA#XAuhA5zwVrYfCXZ#YOWchv} zy?;SW5oZ;;jCi}PiN^3yoP2Dp>H_aFM}S>o2A>=v&&5feMc6 zDYsL@C-2s1<33QiWF???gdCv(``>~%(SR6P-_Pt9aOp=(w}qO;;?;2?3izFng3pPB zDF@@0ujOCz3lk>1ZxbYzzQY zq25DIkUfOFYgkCpXN9!woPc7^D#$j392&U-``*$)SC80L^wj%uk#u!3_WySx3Ogs} zk~{BsF4RRYFW#t>H&QH8vWX?Mbi3#AT=u}&?x ziJ0E!LPg+bDlkYJb}_|(WKaUTl(?P@ z*O0-NWt0L=r2^L^TzC735Zo3~@C7++Q~_@(G{)c&J^SV*??{E*%40$b1kXawi@C%> zxjAjIlyZg?ls_O>X084{n|{dqelaebk!$vIr)I>VX2jykeiplxh|ew*2VaOgtA{qD zUWHBB$lF;(`7sTOt6t`09cc}hoza9odbtDqUNhy%ucj??^) zlvaGCKul#kk^n<7B`_`lhe!93dQmJh2qE>Ilfnp zy-^x0Z~hSbuH;;^a^J5#9X+eoGiKV=!}4}DauyZ*m#s}oN!U9J_C5#00{c^XXD=(3 zM`!vAj9x_#3i;BV9_W4e(3z7)I^HXxM&x^y*!$SC2GQs?UU2hS7m7M7MV%*uFGyeq za0E{n$DotI**RiI1QZOr-}-}q-unprAK^SA{J@iQ%zs$EB-W-Zp7Sj3JK%98wq40N zUalYB>O;qm_|V~#-n8!w>Nn)DrSQo@?4cEVmXBP$0Ji7CE`~$uh{w$d=1*o+&{I$N zadTJ2$UOyzip|uCe!y|$wN0?G9_N-h@_Y@jU^RjQIj$Vnl;E1ku^e22Ke6ip1LhY@ zUlh3d6oA_}@70ask$m&hmkT$H&R-_ElkFYLM|7(6nwMdnQh_xRA! zHg7u6=}tSlUD3Bw!xvmoyFts~`z$}VV$BZwhxK03qjWkSdWD|ho?E$1;3Gd4;tl?* z=@9mPH*BoKsD#Zm(3EP73ixmFrTx#sbuwUUHf+yf*M#jE;94T|G1=i80t!1TP`nc_ zrWNpobsr)3I46O20*7I-AZ6DhsagEB;(#S;IqxOgvkAFqyBF;}4f}gg(_qgkk(ZRA zrem?W1oqo7m=9zQDQ`*}#};tsop%z&B$BuE@O(2Bo^eM$tE7YA%MRuP@S%EKrxw?# z02XD41x3Ih{}PW-?>L?_K7iZsaUt+!eFVf>j4g-(fft|$pNMGv$0FJc9z>lL3zDsW zuUtm{{#T#>Gyhn>dOG=P_ulJ8hYxyD>q%%~H#83#!1licb$JoiSB(6x05uBg0<2GJ zPI>s{f_a?TV4zoDT0@iFn7>G^E07CA5y@PbstNhhv31dB3ko_n8MFV)M@K1MN_T`_b=cB#Z=Mo41Q^0w4UB&^X z3%P>=%EWh}7DX;5<`#S=r8oX4rscpO?3~x6ku=<aq@clbW*eIT|l3>+L_TwoY5T@cg8k0j*xnTS^X zULcG*=;vQ7y4LpFkJQroi~!z8vuhdh@^&|9pd0P((NRqw;x5(-&LjUpU3Y1{42Mv} z?Qo1t_-z69wq(GU+Hl|NG<4)lyDPQhv%6sf+k0kz3G}}NShD!fMvemq*87qGTOoQQ z>@}wkFrCRBa`GSGu|7wk!7=3i6(GafXiCedqaw@Z!E+9(q>K?inq zF&tP=gWb1b`6}~aA=ZT)25V13ev|1~vjn!up!K*PaB4Jlw)s-m2~Rq8%0%tG3J8z#B=$#+A>6+Vp z*$3GC=R?u-cJOAgo1$cifp#2lqbB%r9rC*xS zQE%NnJ;sef-o38&GYkf5La6+{81BwrCyjGW5|)`m}qw=a)D#sbfRMvojTz~r%t-j@$O4K9>;#NSSN#~umSsEC)@87 zw)fa`h6Un0eBa6cY=?gs)X70hA{SoQe%NI$n8!|{)U^w^*-L_CW|#bzG*q$&JQZ{mtk(;@f zENNU-@@lSf!-w3Hb7EEQrubEI#nuFc>$XU_E-t~9t3xb3igB#X3-^dku-%Q0;GXzl z^t|@Mmv*35VD(TrI8osk3=@U}8;l1m24MdkcsO$d+((cnw~U&+{g%7$kn!D*rqQ3{ zO1WDX-g;eP!ng6_o3CYc6_b|Fk7PBBz@crdPr$T`_5WMiQ5zm{rw?&IXkWLH_QCf3 z$SqoXRp0@u4`j%ZrO*uwV8C>R#YkqqlN(OES>0@9*TqO36mbcs6xyf_lOGQCc=9)) z!uy_mj9)Wl5m)rVQZD`dZS;w)mfE(4lfAL(x^razmZhXoH2TS)k&Mf1FfA9rcd@s) z2T;-BPJ4mDp3?@}gPfun@uV4g+Kj$8)68nbjye_}7zglqmS+|M183gNaxdfvu$ys# z#ZHzdu(~mJnCG_j2t{#)LP=ztND>{P)Ff{*%9Gc7`NY5Qt4Cvv0inwU-`uZjeY|$Y zYxMexFoCyE{S!)AWr9*zQ6Uu-W~yBZA|-;NLb1r&tVAyz`Q$P5SUR+{0~%WA=y|Kr z|3r<@&*G<356ZCrY%pys1}AV&0QNg;0_G2_MoL25W%VM%7`;e}gKn~(Wh6!j`f4$# zl~WL-GdoNk=`)Yjp1tlIc)ffMWo&$%i?lq&6=%=jVzzDO{0l<3y0`o}{rHNh3hXg* zK-5AzIuI|8tEv2q8nFa119esvtBjmVf_-88#?*#tP7A6Vej*R2fLq` zgZYE=-~)20#9=vx5;4>T?lCIeWozP!bef2xp+DREyFeHQqWwOi?$xomgYD*lVQxEp5wcX95M9Z6JL@&p%` zvVy<;0jrDFR5(|yEeSQKi?*w|fy;Tj(Dp%o!>8kF@g-k=qG!v zupjr()BOYdc>7=f`s3L9@4zhV;C$}335~x%Kjt_z0dWDfAmSbFOXI#&9b#t%Y%YfF zr5MF{p3^ImW<@Zux%#GF#0iEFM#FRBMMGkiZCHF!FHM^XcA zs74GegWlz%&tU73h%@pgOpSG`3rhIW?>)mI)*egNxN^=zQ~#!xDo;CqE5+)8tU(2r z*QVqO>y@0%;^mRCOyzE!F>i6W#P7{*y!{WK{#V$~Fi`cJr`vy3sM7G&m1-(Ir6lVa zsU*98%pJ*-0`oTTNv*T_c~#}SZt>#(8k@iF1MK+|kss4tkJ#K);-cqO3d_^e7DX$| z*5bDn-=Q5pzjtGD-k)**8TX$#@G}Q~=D>d(2e2i0eCgwu>|d(?dA3WO$6w7smyR#b zEt?*4yt12|XATl;uG#H_#FA}0{vRkyK-lqD^TtcZn4{S1583U3m*!0m;rJfAeYYC3 z4?fM|^JcsKBCRCH7m$+MgfIA#)In^%NRmzL3onv@*o7|Q@7L!q{^{5U?@RHD`fIZa z$3D28_|nWiz>b}>^M3$fft%Pd7QFk?JjiCej^#NP>i8mt-6kB1Fgvb*6CAT+#drg= sbVUFF6NX7dK~#9!?V5YET~(Fle{-$exIh_OJx2qIJ| z3Kc+5Xh0BwNFai=779W&U;&m56hsQ45($EUKqx7(cn2kl;Taxz5%Rdt^VsL?z1N!k z$GPxF+uc>jja6xxW86RPIAg56zHhGet#8e_;Dh)eK8O$EgZLo+WJ7j#0CyZRcU^^DHrbWlU@Y`u) z`9kl%aMY)k`Ts8oxcj=>rEt-rGtzKulyD$K-gdAh8Q-<4po1^I^~nW~ zxk5*_`1%`uj|{uB5^zkh5wxt{cyUJFQ>GDQcu_(bO(6(jl!2+HT-}d~KO$W7;#{Tt z_yZfaSN`{L%+3h@*r%_Qwih~F%Gp3FA>-ff-nvCYhAr|@p)fa z{Cg`t*xA5;VcCV|;3W^Wnze7A?a&z1g&0~f0**m)qk!TyKnXF#U^JEXa=QqiJCz1p zapCu6+cbl3>z6tI^Zru2`K>)W*Ot%sPWMpqAOIPnZa_3eNpL1au!tHU0Z9=d)aPIS z+OdB*zVM0k+;4nd|5Foi#EQFQM(o;b1h209giZZNypM{0DBZ73qt*sl6reUI zCnJ}TKpQy8aMA!$kRdb>EFD-EAwGt*-llgCefgLR&$)bQ{vS@jVdpKB0}q}m<;P}e zYvFO(WyQU1Qfp{=?|E6vvoFkv8@2hexpKHDqXP&n7>622_kI7Wqd(^VLkYO)%#(}bfBN9b^t!2GJ>A_org*fL z;$4n(D;gLSgNWh~L~<057ms346%dC?h|v^}K}hkEB7}Hi0?i39s2Z$*(;Sz|#KQRt zHx1nLM-jo(FS%JZO&_2tQ<%Sb6VcSo3_L!cF)J7DrR(d9G8_SgiY3S!WSs`F5nc>N za-4Xy2^%EGjX*2%Ck?m zvzPw&1?kqlPin@*hU9%(i2F_L>Pc0jqhq2*8*Q}!2{W>`7!k!wh#7{hC|(RGC?2Fa z;ikZ4&801ZP{x}Gt2LZSQOPmd^ah?3Z;Dv;7#Bj-b+$f5t+wMe;Nh0eQ|r~n;xf(x zl<_7+brgXL#qubM4TToSgB&-UQBOv0GCUSbj>F?5YZ9UYA_xw}VZV3+JYFhf(r7w441&R<7*Wt1l?+dgNNM=k^Qf;!(JR^9sb|kyeC*3}K7EnC7cB3Y zfQ9GZD7*IEUzoLQ)n~(U^-BTL0|bgnPHG##7z!SY<~Yg7B_#u+uT9r624#$guz<-G zAJj?0K~mF4Dmf|zj8;&|QKUIRF?jVrjuAU-WkZyv!Yu>^rfO^!;Vd0dI&$Z?Wl$uUwvCBRWasH57+s78RX28<^Ua@43V2&e2}B$IH@DF5T*tvg42w8+)p{^BPSszM@5E>P6^Q% z)C~VM0efFS2rxuVT@Z(-fyfJqncMi+-~HmMX=6UQLkPIydsmtRuUfuuJm5|Y5i6*q zIOFjW;IxF(h#bXB1#cSSF$MW$$LRRdj#2H`cgv`Copdx(u%I?a;|g^%KtB9wAq7cM zi7;Bkc#BbongkWWYq9D2v}uu49bOeHZy~XO)>YbNL*FHLUT|tS;#*+Sn*(wC%gNU) z#2MZ?ASDyxm=UlkCK01GT+#Z~<_Se_H_Q=yuB${>{t5Kq4 zVU3&^LxyPHbVme;D59VeG<8ICkhuA?3~z94T4Tc?YF-nG+f_6}OrD!bz4tw^H?V3% zSHR?@KiWIYWRgQnirS3a_~x}zJSqw}RDIK@qs7MkYmT0t{g1nU;vf6LrM_p)hN&+b z+n7R_C@v_I*g6hNq!F_GDK2Dwn7wx1Fx-U-VV7%)KzrP5hdU= z_um%Bi5wJyhKL_tf=W}7wduz}L40%aQc2?!;Al>k?|$_dYmMx+JJuO$L4p%M?7bWg z-@G4)0~K=WcyS;OB*RMvrU4{)sSg)D2k~~W#jof?!Wi|PXx5H#1@Hpnm)>}Y88HH) z)i2G8kdlWWhakrX4ZPHGriL>a2H(u)I~kX#*d$=g5!)#kjq`?^DL4}n=sV8Np`=9k zra>CEvqA(KfqH~yS*y9#q^TEDLCqGV&|1{(afiR9i1=2lkBGE`Vpb}~zlckF>WC5G z>V9&9D`vPb!WQa7H|4WKW8E-ct#SnF+?e^rcE$-C- zd<&uPAorE7+IO~o;?Qp&``1^G3;}K5J5|zZHnEP2>ZC!Lx~-AhI?mKl(?+aQXvtcM zhb^h#Ve@Zi&(C(daLJkRhJmF8Z>Bb=ry1U4qlCLmhLhT6A!ZGV$2%&;^tQUR%f z$w3mllu1vP1BE&&dIQPyK`G{#i`Rp6ic81#> zPO4<4MrOB@T7yufVWtsfF-ARJ8_n{Rq&=mlOXpwwjreVUwiR)1a@WP{=Ep}41&vKr za$7~ofoYihJWPC^7AkunX&qwFqf+72~egIr89}L zZbH{ipaz{@*!qgGv8>9Q7c4bU?fdgxmlsPdH|McDm;9G0_l)>mVD(9-ZJ+o2w;!ri zvZE3*TWOxezKt-mSZ#nLs4<{#;{(Y}N0-Q8b$sC~x9v6Wk)L0AkN-LMGIin1@|)xS z;I)C9Sn_Tc_Waw{x+UM5r9<~s#$_nR=C8i; z?Nb)CtXysUN2cX{(LCM%$?uQr_~$hTlw1>}L zaqXGIcH&lc$Yp5pnTz#-`QO@@k8eLOknlIOMz?MI+(DPu^K?o=E(u7CaeZXTsL^_5 zvS99~es$4L)?D(lCBN5#-tW;jCRM9`0f?!N?z|(I+3wDL_=Wjmme|p>z zZwPLHL3P`on}$wnIz&zCGbUU=QgzG!XM6mqCw{Cmu6=Ohnj<=w zPkVXGixVDSb%Ae~eFbk)q>*&wKTZ#rdDctEe{AKJbY=SLlHajT*8_0bEsvV-{Ml?X zcj)a&_USjyDLcP+fK=Q*)4u-P+yiPec9|wmxS@s&%T(2*eE|5_5e=7Nc`z58p@{e$azx(2qL6!a#? zE0j{hP->$Ul{w??SbfQ5ukG=~TEFD-3*Vj0;uR~+?zen19R1|lQ+%KNl~mI>n-4pq5%s^utb3Qu>U?U`y%T6R1~eft2{lurK@ym^)}C|Z z{GN_}+0c4|zx=BwxE=OJXpg_UR1TOfvfCy9)ZMZ1<>T3+Uo-?Q#^&p#qjYQU!Bg%U z_}Ga9D;|GF*WAAR_p-43qqEzJPi?w3NaJ}1!J?9o(g5QT92w2Zj-x91pzn+x4#ST1 z?b~V#hP1p#D@G^Ko@eAzry^AxnK6Uq{btVn@{=#*03972GB`LmA}ios5&ZIDi=^ks z%ye9P?etC1^!(Et~>nT$UbxH0{P{@iIT9FGi;YOmM6Q;xO3}&TeLPRHT)&Vo$+tJyc!eM zj8(IjCB-+J7i2h7qbf>3h^P>t2my{!gn5QoM2@{9r$ zi$zJ2WMl~#{o7~f^lqzPOi3ShvqoK4J$&BN<9fo{sY~uqR(A2?3KWMPm*A>}Shq|@U*cjIBgpzlo`>4wp z3Tg?5UN!C4&+R@5zfbQ+T21WtV;$We9x5X8i+>H`*yD|VYc-MrNIaEh^lN*4uJ#z~z_S_ylrwA^Pgoq|assm|S|@N>M~(Mi8p^~#PUV8q`CtSpQ>X?(rov=rCY>>h=hQMV3oc**dR<4H&*!r;g;%_6Hd zyG&pRQt1jV>%0EDOV2v)RNavTjOZ5l!MSHey^Vq6-=MFhfbEYd){6vbkz!iFx(MSU z@D>O`!7J!+<5R>Fs4?Ms867X$e$?UrxTC?3_!c;A>+Aaked)>7_T;y%Ik@s%$@F!i4$#U?DX$W>JR)4J%qRU^}d!HK? zzqn?wZ}mFmj}#-O0e9^`X_|R@+XHIZwB^8A$4vOp7yFL9;T#3{vnxI-XWU(F?;5Ii zh2GfSwo)E#*&4cds8OBTGx$QjOYLue{$S3|8mIo~Ci~M-tzW;3!t1w&eFW#?C^(`#uFO{`-qe{QOG`8{V`h;D{>c!q=Ux9YrnaqoN^0HuVE@+T^-Tx4ooV~NF9N=B%QtNB#Hy3(DlPd$y=wcu z3kR26eWLD61iUW|m@rjHr*^N3`s#gKjyUL{4Q+qz;kunlz~7e-m=_CqYw?X&4!!)j nf1Uhhe#ckN+NrYtK>+^?S`-Z<-RbvT00000NkvXXu0mjfQiAex literal 0 HcmV?d00001 diff --git a/tool/viz/deathstar.c b/tool/viz/deathstar.c index ae688323..acbefb2e 100644 --- a/tool/viz/deathstar.c +++ b/tool/viz/deathstar.c @@ -1,4 +1,5 @@ #include "dsp/tty/tty.h" +#include "libc/calls/calls.h" #include "libc/calls/struct/termios.h" #include "libc/log/check.h" #include "libc/log/log.h" @@ -6,6 +7,7 @@ #include "libc/math.h" #include "libc/runtime/runtime.h" #include "libc/stdio/stdio.h" +#include "libc/str/str.h" #include "libc/sysv/consts/fileno.h" #include "libc/sysv/consts/sig.h" #include "libc/time/time.h" @@ -16,6 +18,7 @@ */ #define FRAMERATE 23.976 +#define WRITE(s) write(STDOUT_FILENO, s, strlen(s)) struct Sphere { double cx, cy, cz, r; @@ -97,7 +100,7 @@ static void DrawSphere(double k, double ambient) { } switch (hit_result) { case 0: - fputs("\e[0m ", stdout); + WRITE("\e[0m "); continue; case 1: vec[0] = x - pos_.cx; @@ -111,13 +114,12 @@ static void DrawSphere(double k, double ambient) { break; } Normalize(vec); - fputs( + WRITE( kShades[MIN(ARRAYLEN(kShades) - 1, MAX(0, lround((1 - (pow(Dot(light_, vec), k) + ambient)) * - (ARRAYLEN(kShades) - 1))))], - stdout); + (ARRAYLEN(kShades) - 1))))]); } - fputs("\e[0m\n", stdout); + WRITE("\e[0m\n"); } fflush(stdout); } @@ -131,7 +133,7 @@ int main() { xsigaction(SIGINT, OnCtrlC, 0, 0, NULL); ang = 0; for (;;) { - printf("\e[H"); + WRITE("\e[H"); light_[1] = cos(ang * 2); light_[2] = cos(ang); light_[0] = sin(ang); diff --git a/tool/viz/lib/vizlib.mk b/tool/viz/lib/vizlib.mk index a4ea7df6..a3b7c1e4 100644 --- a/tool/viz/lib/vizlib.mk +++ b/tool/viz/lib/vizlib.mk @@ -92,6 +92,12 @@ $(TOOL_VIZ_LIB_A).pkg: \ $(TOOL_VIZ_LIB_A_OBJS) \ $(foreach x,$(TOOL_VIZ_LIB_A_DIRECTDEPS),$($(x)_A).pkg) +ifeq (,$(MODE)) +$(TOOL_VIZ_LIB_A_OBJS): \ + OVERRIDE_CFLAGS += \ + -fsanitize=address +endif + $(TOOL_VIZ_LIB_A_OBJS): tool/viz/lib/vizlib.mk TOOL_VIZ_LIB_LIBS = $(foreach x,$(TOOL_VIZ_LIB_ARTIFACTS),$($(x))) diff --git a/tool/viz/printimage.c b/tool/viz/printimage.c index 65b1b761..5df1bbea 100644 --- a/tool/viz/printimage.c +++ b/tool/viz/printimage.c @@ -77,7 +77,7 @@ FLAGS\n\ \n\ -o PATH output path\n\ -w INT manual width\n\ - -w INT manual height\n\ + -h INT manual height\n\ -4 unicode blocks\n\ -a ansi color mode\n\ -t true color mode\n\ diff --git a/tool/viz/printvideo.c b/tool/viz/printvideo.c index 121f7440..92a2b32e 100644 --- a/tool/viz/printvideo.c +++ b/tool/viz/printvideo.c @@ -936,7 +936,7 @@ static FILE *OpenVideoHttp(void) { "Content-Length: 0\r\n" "User-Agent: printvideo/1.o\r\n" "\r\n")))); - CHECK_NE(-1, negotiatehttprequest(sock, req, &reqsize, resp, &respsize, + CHECK_NE(-1, NegotiateHttpRequest(sock, req, &reqsize, resp, &respsize, &resphdrsize, true, 2)); CHECK_NOTNULL(strstr(resp, "200 OK")); CHECK_NOTNULL(strstr(resp, "Content-Type: video/mpeg")); diff --git a/tool/viz/viz.mk b/tool/viz/viz.mk index d697ff8f..d5b067a1 100644 --- a/tool/viz/viz.mk +++ b/tool/viz/viz.mk @@ -84,6 +84,12 @@ $(TOOL_VIZ_OBJS): \ $(BUILD_FILES) \ tool/viz/viz.mk +ifeq (,$(MODE)) +$(TOOL_VIZ_OBJS): \ + OVERRIDE_CFLAGS += \ + -fsanitize=address +endif + .PHONY: o/$(MODE)/tool/viz o/$(MODE)/tool/viz: \ o/$(MODE)/tool/viz/lib \ diff --git a/tool/viz/xterm256info.c b/tool/viz/xterm256info.c index 7dfe2506..14ec2171 100644 --- a/tool/viz/xterm256info.c +++ b/tool/viz/xterm256info.c @@ -436,527 +436,272 @@ const struct XtermDb { struct Rgb rgb; const char *text; } kXtermDb[] = { - {{0x00, 0x00, 0x00}, - "0 Black #000000 rgb(0,0,0) hsl(0,0%,0%)"}, - {{0x80, 0x00, 0x00}, - "1 Maroon #800000 rgb(128,0,0) hsl(0,100%,25%)"}, - {{0x00, 0x80, 0x00}, - "2 Green #008000 rgb(0,128,0) hsl(120,100%,25%)"}, - {{0x80, 0x80, 0x00}, - "3 Olive #808000 rgb(128,128,0) hsl(60,100%,25%)"}, - {{0x00, 0x00, 0x80}, - "4 Navy #000080 rgb(0,0,128) hsl(240,100%,25%)"}, - {{0x80, 0x00, 0x80}, - "5 Purple #800080 rgb(128,0,128) hsl(300,100%,25%)"}, - {{0x00, 0x80, 0x80}, - "6 Teal #008080 rgb(0,128,128) hsl(180,100%,25%)"}, - {{0xc0, 0xc0, 0xc0}, - "7 Silver #c0c0c0 rgb(192,192,192) hsl(0,0%,75%)"}, - {{0x80, 0x80, 0x80}, - "8 Grey #808080 rgb(128,128,128) hsl(0,0%,50%)"}, - {{0xff, 0x00, 0x00}, - "9 Red #ff0000 rgb(255,0,0) hsl(0,100%,50%)"}, - {{0x00, 0xff, 0x00}, - "10 Lime #00ff00 rgb(0,255,0) hsl(120,100%,50%)"}, - {{0xff, 0xff, 0x00}, - "11 Yellow #ffff00 rgb(255,255,0) hsl(60,100%,50%)"}, - {{0x00, 0x00, 0xff}, - "12 Blue #0000ff rgb(0,0,255) hsl(240,100%,50%)"}, - {{0xff, 0x00, 0xff}, - "13 Fuchsia #ff00ff rgb(255,0,255) hsl(300,100%,50%)"}, - {{0x00, 0xff, 0xff}, - "14 Aqua #00ffff rgb(0,255,255) hsl(180,100%,50%)"}, - {{0xff, 0xff, 0xff}, - "15 White #ffffff rgb(255,255,255) hsl(0,0%,100%)"}, - {{0x00, 0x00, 0x00}, - "16 Grey0 #000000 rgb(0,0,0) hsl(0,0%,0%)"}, - {{0x00, 0x00, 0x5f}, - "17 NavyBlue #00005f rgb(0,0,95) hsl(240,100%,18%)"}, - {{0x00, 0x00, 0x87}, - "18 DarkBlue #000087 rgb(0,0,135) hsl(240,100%,26%)"}, - {{0x00, 0x00, 0xaf}, - "19 Blue3 #0000af rgb(0,0,175) hsl(240,100%,34%)"}, - {{0x00, 0x00, 0xd7}, - "20 Blue3 #0000d7 rgb(0,0,215) hsl(240,100%,42%)"}, - {{0x00, 0x00, 0xff}, - "21 Blue1 #0000ff rgb(0,0,255) hsl(240,100%,50%)"}, - {{0x00, 0x5f, 0x00}, - "22 DarkGreen #005f00 rgb(0,95,0) hsl(120,100%,18%)"}, - {{0x00, 0x5f, 0x5f}, - "23 DeepSkyBlue4 #005f5f rgb(0,95,95) hsl(180,100%,18%)"}, - {{0x00, 0x5f, 0x87}, - "24 DeepSkyBlue4 #005f87 rgb(0,95,135) hsl(97,100%,26%)"}, - {{0x00, 0x5f, 0xaf}, - "25 DeepSkyBlue4 #005faf rgb(0,95,175) hsl(07,100%,34%)"}, - {{0x00, 0x5f, 0xd7}, - "26 DodgerBlue3 #005fd7 rgb(0,95,215) hsl(13,100%,42%)"}, - {{0x00, 0x5f, 0xff}, - "27 DodgerBlue2 #005fff rgb(0,95,255) hsl(17,100%,50%)"}, - {{0x00, 0x87, 0x00}, - "28 Green4 #008700 rgb(0,135,0) hsl(120,100%,26%)"}, - {{0x00, 0x87, 0x5f}, - "29 SpringGreen4 #00875f rgb(0,135,95) hsl(62,100%,26%)"}, - {{0x00, 0x87, 0x87}, - "30 Turquoise4 #008787 rgb(0,135,135) hsl(180,100%,26%)"}, - {{0x00, 0x87, 0xaf}, - "31 DeepSkyBlue3 #0087af rgb(0,135,175) hsl(93,100%,34%)"}, - {{0x00, 0x87, 0xd7}, - "32 DeepSkyBlue3 #0087d7 rgb(0,135,215) hsl(02,100%,42%)"}, - {{0x00, 0x87, 0xff}, - "33 DodgerBlue1 #0087ff rgb(0,135,255) hsl(08,100%,50%)"}, - {{0x00, 0xaf, 0x00}, - "34 Green3 #00af00 rgb(0,175,0) hsl(120,100%,34%)"}, - {{0x00, 0xaf, 0x5f}, - "35 SpringGreen3 #00af5f rgb(0,175,95) hsl(52,100%,34%)"}, - {{0x00, 0xaf, 0x87}, - "36 DarkCyan #00af87 rgb(0,175,135) hsl(66,100%,34%)"}, - {{0x00, 0xaf, 0xaf}, - "37 LightSeaGreen #00afaf rgb(0,175,175) hsl(180,100%,34%)"}, - {{0x00, 0xaf, 0xd7}, - "38 DeepSkyBlue2 #00afd7 rgb(0,175,215) hsl(91,100%,42%)"}, - {{0x00, 0xaf, 0xff}, - "39 DeepSkyBlue1 #00afff rgb(0,175,255) hsl(98,100%,50%)"}, - {{0x00, 0xd7, 0x00}, - "40 Green3 #00d700 rgb(0,215,0) hsl(120,100%,42%)"}, - {{0x00, 0xd7, 0x5f}, - "41 SpringGreen3 #00d75f rgb(0,215,95) hsl(46,100%,42%)"}, - {{0x00, 0xd7, 0x87}, - "42 SpringGreen2 #00d787 rgb(0,215,135) hsl(57,100%,42%)"}, - {{0x00, 0xd7, 0xaf}, - "43 Cyan3 #00d7af rgb(0,215,175) hsl(68,100%,42%)"}, - {{0x00, 0xd7, 0xd7}, - "44 DarkTurquoise #00d7d7 rgb(0,215,215) hsl(180,100%,42%)"}, - {{0x00, 0xd7, 0xff}, - "45 Turquoise2 #00d7ff rgb(0,215,255) hsl(89,100%,50%)"}, - {{0x00, 0xff, 0x00}, - "46 Green1 #00ff00 rgb(0,255,0) hsl(120,100%,50%)"}, - {{0x00, 0xff, 0x5f}, - "47 SpringGreen2 #00ff5f rgb(0,255,95) hsl(42,100%,50%)"}, - {{0x00, 0xff, 0x87}, - "48 SpringGreen1 #00ff87 rgb(0,255,135) hsl(51,100%,50%)"}, - {{0x00, 0xff, 0xaf}, - "49 MediumSpringGreen #00ffaf rgb(0,255,175) hsl(61,100%,50%)"}, - {{0x00, 0xff, 0xd7}, - "50 Cyan2 #00ffd7 rgb(0,255,215) hsl(70,100%,50%)"}, - {{0x00, 0xff, 0xff}, - "51 Cyan1 #00ffff rgb(0,255,255) hsl(180,100%,50%)"}, - {{0x5f, 0x00, 0x00}, - "52 DarkRed #5f0000 rgb(95,0,0) hsl(0,100%,18%)"}, - {{0x5f, 0x00, 0x5f}, - "53 DeepPink4 #5f005f rgb(95,0,95) hsl(300,100%,18%)"}, - {{0x5f, 0x00, 0x87}, - "54 Purple4 #5f0087 rgb(95,0,135) hsl(82,100%,26%)"}, - {{0x5f, 0x00, 0xaf}, - "55 Purple4 #5f00af rgb(95,0,175) hsl(72,100%,34%)"}, - {{0x5f, 0x00, 0xd7}, - "56 Purple3 #5f00d7 rgb(95,0,215) hsl(66,100%,42%)"}, - {{0x5f, 0x00, 0xff}, - "57 BlueViolet #5f00ff rgb(95,0,255) hsl(62,100%,50%)"}, - {{0x5f, 0x5f, 0x00}, - "58 Orange4 #5f5f00 rgb(95,95,0) hsl(60,100%,18%)"}, - {{0x5f, 0x5f, 0x5f}, - "59 Grey37 #5f5f5f rgb(95,95,95) hsl(0,0%,37%)"}, - {{0x5f, 0x5f, 0x87}, - "60 MediumPurple4 #5f5f87 rgb(95,95,135) hsl(240,17%,45%)"}, - {{0x5f, 0x5f, 0xaf}, - "61 SlateBlue3 #5f5faf rgb(95,95,175) hsl(240,33%,52%)"}, - {{0x5f, 0x5f, 0xd7}, - "62 SlateBlue3 #5f5fd7 rgb(95,95,215) hsl(240,60%,60%)"}, - {{0x5f, 0x5f, 0xff}, - "63 RoyalBlue1 #5f5fff rgb(95,95,255) hsl(240,100%,68%)"}, - {{0x5f, 0x87, 0x00}, - "64 Chartreuse4 #5f8700 rgb(95,135,0) hsl(7,100%,26%)"}, - {{0x5f, 0x87, 0x5f}, - "65 DarkSeaGreen4 #5f875f rgb(95,135,95) hsl(120,17%,45%)"}, - {{0x5f, 0x87, 0x87}, - "66 PaleTurquoise4 #5f8787 rgb(95,135,135) hsl(180,17%,45%)"}, - {{0x5f, 0x87, 0xaf}, - "67 SteelBlue #5f87af rgb(95,135,175) hsl(210,33%,52%)"}, - {{0x5f, 0x87, 0xd7}, - "68 SteelBlue3 #5f87d7 rgb(95,135,215) hsl(220,60%,60%)"}, - {{0x5f, 0x87, 0xff}, - "69 CornflowerBlue #5f87ff rgb(95,135,255) hsl(225,100%,68%)"}, - {{0x5f, 0xaf, 0x00}, - "70 Chartreuse3 #5faf00 rgb(95,175,0) hsl(7,100%,34%)"}, - {{0x5f, 0xaf, 0x5f}, - "71 DarkSeaGreen4 #5faf5f rgb(95,175,95) hsl(120,33%,52%)"}, - {{0x5f, 0xaf, 0x87}, - "72 CadetBlue #5faf87 rgb(95,175,135) hsl(150,33%,52%)"}, - {{0x5f, 0xaf, 0xaf}, - "73 CadetBlue #5fafaf rgb(95,175,175) hsl(180,33%,52%)"}, - {{0x5f, 0xaf, 0xd7}, - "74 SkyBlue3 #5fafd7 rgb(95,175,215) hsl(200,60%,60%)"}, - {{0x5f, 0xaf, 0xff}, - "75 SteelBlue1 #5fafff rgb(95,175,255) hsl(210,100%,68%)"}, - {{0x5f, 0xd7, 0x00}, - "76 Chartreuse3 #5fd700 rgb(95,215,0) hsl(3,100%,42%)"}, - {{0x5f, 0xd7, 0x5f}, - "77 PaleGreen3 #5fd75f rgb(95,215,95) hsl(120,60%,60%)"}, - {{0x5f, 0xd7, 0x87}, - "78 SeaGreen3 #5fd787 rgb(95,215,135) hsl(140,60%,60%)"}, - {{0x5f, 0xd7, 0xaf}, - "79 Aquamarine3 #5fd7af rgb(95,215,175) hsl(160,60%,60%)"}, - {{0x5f, 0xd7, 0xd7}, - "80 MediumTurquoise #5fd7d7 rgb(95,215,215) hsl(180,60%,60%)"}, - {{0x5f, 0xd7, 0xff}, - "81 SteelBlue1 #5fd7ff rgb(95,215,255) hsl(195,100%,68%)"}, - {{0x5f, 0xff, 0x00}, - "82 Chartreuse2 #5fff00 rgb(95,255,0) hsl(7,100%,50%)"}, - {{0x5f, 0xff, 0x5f}, - "83 SeaGreen2 #5fff5f rgb(95,255,95) hsl(120,100%,68%)"}, - {{0x5f, 0xff, 0x87}, - "84 SeaGreen1 #5fff87 rgb(95,255,135) hsl(135,100%,68%)"}, - {{0x5f, 0xff, 0xaf}, - "85 SeaGreen1 #5fffaf rgb(95,255,175) hsl(150,100%,68%)"}, - {{0x5f, 0xff, 0xd7}, - "86 Aquamarine1 #5fffd7 rgb(95,255,215) hsl(165,100%,68%)"}, - {{0x5f, 0xff, 0xff}, - "87 DarkSlateGray2 #5fffff rgb(95,255,255) hsl(180,100%,68%)"}, - {{0x87, 0x00, 0x00}, - "88 DarkRed #870000 rgb(135,0,0) hsl(0,100%,26%)"}, - {{0x87, 0x00, 0x5f}, - "89 DeepPink4 #87005f rgb(135,0,95) hsl(17,100%,26%)"}, - {{0x87, 0x00, 0x87}, - "90 DarkMagenta #870087 rgb(135,0,135) hsl(300,100%,26%)"}, - {{0x87, 0x00, 0xaf}, - "91 DarkMagenta #8700af rgb(135,0,175) hsl(86,100%,34%)"}, - {{0x87, 0x00, 0xd7}, - "92 DarkViolet #8700d7 rgb(135,0,215) hsl(77,100%,42%)"}, - {{0x87, 0x00, 0xff}, - "93 Purple #8700ff rgb(135,0,255) hsl(71,100%,50%)"}, - {{0x87, 0x5f, 0x00}, - "94 Orange4 #875f00 rgb(135,95,0) hsl(2,100%,26%)"}, - {{0x87, 0x5f, 0x5f}, - "95 LightPink4 #875f5f rgb(135,95,95) hsl(0,17%,45%)"}, - {{0x87, 0x5f, 0x87}, - "96 Plum4 #875f87 rgb(135,95,135) hsl(300,17%,45%)"}, - {{0x87, 0x5f, 0xaf}, - "97 MediumPurple3 #875faf rgb(135,95,175) hsl(270,33%,52%)"}, - {{0x87, 0x5f, 0xd7}, - "98 MediumPurple3 #875fd7 rgb(135,95,215) hsl(260,60%,60%)"}, - {{0x87, 0x5f, 0xff}, - "99 SlateBlue1 #875fff rgb(135,95,255) hsl(255,100%,68%)"}, - {{0x87, 0x87, 0x00}, - "100 Yellow4 #878700 rgb(135,135,0) hsl(60,100%,26%)"}, - {{0x87, 0x87, 0x5f}, - "101 Wheat4 #87875f rgb(135,135,95) hsl(60,17%,45%)"}, - {{0x87, 0x87, 0x87}, - "102 Grey53 #878787 rgb(135,135,135) hsl(0,0%,52%)"}, - {{0x87, 0x87, 0xaf}, - "103 LightSlateGrey #8787af rgb(135,135,175) hsl(240,20%,60%)"}, - {{0x87, 0x87, 0xd7}, - "104 MediumPurple #8787d7 rgb(135,135,215) hsl(240,50%,68%)"}, - {{0x87, 0x87, 0xff}, - "105 LightSlateBlue #8787ff rgb(135,135,255) hsl(240,100%,76%)"}, - {{0x87, 0xaf, 0x00}, - "106 Yellow4 #87af00 rgb(135,175,0) hsl(3,100%,34%)"}, - {{0x87, 0xaf, 0x5f}, - "107 DarkOliveGreen3 #87af5f rgb(135,175,95) hsl(90,33%,52%)"}, - {{0x87, 0xaf, 0x87}, - "108 DarkSeaGreen #87af87 rgb(135,175,135) hsl(120,20%,60%)"}, - {{0x87, 0xaf, 0xaf}, - "109 LightSkyBlue3 #87afaf rgb(135,175,175) hsl(180,20%,60%)"}, - {{0x87, 0xaf, 0xd7}, - "110 LightSkyBlue3 #87afd7 rgb(135,175,215) hsl(210,50%,68%)"}, - {{0x87, 0xaf, 0xff}, - "111 SkyBlue2 #87afff rgb(135,175,255) hsl(220,100%,76%)"}, - {{0x87, 0xd7, 0x00}, - "112 Chartreuse2 #87d700 rgb(135,215,0) hsl(2,100%,42%)"}, - {{0x87, 0xd7, 0x5f}, - "113 DarkOliveGreen3 #87d75f rgb(135,215,95) hsl(100,60%,60%)"}, - {{0x87, 0xd7, 0x87}, - "114 PaleGreen3 #87d787 rgb(135,215,135) hsl(120,50%,68%)"}, - {{0x87, 0xd7, 0xaf}, - "115 DarkSeaGreen3 #87d7af rgb(135,215,175) hsl(150,50%,68%)"}, - {{0x87, 0xd7, 0xd7}, - "116 DarkSlateGray3 #87d7d7 rgb(135,215,215) hsl(180,50%,68%)"}, - {{0x87, 0xd7, 0xff}, - "117 SkyBlue1 #87d7ff rgb(135,215,255) hsl(200,100%,76%)"}, - {{0x87, 0xff, 0x00}, - "118 Chartreuse1 #87ff00 rgb(135,255,0) hsl(8,100%,50%)"}, - {{0x87, 0xff, 0x5f}, - "119 LightGreen #87ff5f rgb(135,255,95) hsl(105,100%,68%)"}, - {{0x87, 0xff, 0x87}, - "120 LightGreen #87ff87 rgb(135,255,135) hsl(120,100%,76%)"}, - {{0x87, 0xff, 0xaf}, - "121 PaleGreen1 #87ffaf rgb(135,255,175) hsl(140,100%,76%)"}, - {{0x87, 0xff, 0xd7}, - "122 Aquamarine1 #87ffd7 rgb(135,255,215) hsl(160,100%,76%)"}, - {{0x87, 0xff, 0xff}, - "123 DarkSlateGray1 #87ffff rgb(135,255,255) hsl(180,100%,76%)"}, - {{0xaf, 0x00, 0x00}, - "124 Red3 #af0000 rgb(175,0,0) hsl(0,100%,34%)"}, - {{0xaf, 0x00, 0x5f}, - "125 DeepPink4 #af005f rgb(175,0,95) hsl(27,100%,34%)"}, - {{0xaf, 0x00, 0x87}, - "126 MediumVioletRed #af0087 rgb(175,0,135) hsl(13,100%,34%)"}, - {{0xaf, 0x00, 0xaf}, - "127 Magenta3 #af00af rgb(175,0,175) hsl(300,100%,34%)"}, - {{0xaf, 0x00, 0xd7}, - "128 DarkViolet #af00d7 rgb(175,0,215) hsl(88,100%,42%)"}, - {{0xaf, 0x00, 0xff}, - "129 Purple #af00ff rgb(175,0,255) hsl(81,100%,50%)"}, - {{0xaf, 0x5f, 0x00}, - "130 DarkOrange3 #af5f00 rgb(175,95,0) hsl(2,100%,34%)"}, - {{0xaf, 0x5f, 0x5f}, - "131 IndianRed #af5f5f rgb(175,95,95) hsl(0,33%,52%)"}, - {{0xaf, 0x5f, 0x87}, - "132 HotPink3 #af5f87 rgb(175,95,135) hsl(330,33%,52%)"}, - {{0xaf, 0x5f, 0xaf}, - "133 MediumOrchid3 #af5faf rgb(175,95,175) hsl(300,33%,52%)"}, - {{0xaf, 0x5f, 0xd7}, - "134 MediumOrchid #af5fd7 rgb(175,95,215) hsl(280,60%,60%)"}, - {{0xaf, 0x5f, 0xff}, - "135 MediumPurple2 #af5fff rgb(175,95,255) hsl(270,100%,68%)"}, - {{0xaf, 0x87, 0x00}, - "136 DarkGoldenrod #af8700 rgb(175,135,0) hsl(6,100%,34%)"}, - {{0xaf, 0x87, 0x5f}, - "137 LightSalmon3 #af875f rgb(175,135,95) hsl(30,33%,52%)"}, - {{0xaf, 0x87, 0x87}, - "138 RosyBrown #af8787 rgb(175,135,135) hsl(0,20%,60%)"}, - {{0xaf, 0x87, 0xaf}, - "139 Grey63 #af87af rgb(175,135,175) hsl(300,20%,60%)"}, - {{0xaf, 0x87, 0xd7}, - "140 MediumPurple2 #af87d7 rgb(175,135,215) hsl(270,50%,68%)"}, - {{0xaf, 0x87, 0xff}, - "141 MediumPurple1 #af87ff rgb(175,135,255) hsl(260,100%,76%)"}, - {{0xaf, 0xaf, 0x00}, - "142 Gold3 #afaf00 rgb(175,175,0) hsl(60,100%,34%)"}, - {{0xaf, 0xaf, 0x5f}, - "143 DarkKhaki #afaf5f rgb(175,175,95) hsl(60,33%,52%)"}, - {{0xaf, 0xaf, 0x87}, - "144 NavajoWhite3 #afaf87 rgb(175,175,135) hsl(60,20%,60%)"}, - {{0xaf, 0xaf, 0xaf}, - "145 Grey69 #afafaf rgb(175,175,175) hsl(0,0%,68%)"}, - {{0xaf, 0xaf, 0xd7}, - "146 LightSteelBlue3 #afafd7 rgb(175,175,215) hsl(240,33%,76%)"}, - {{0xaf, 0xaf, 0xff}, - "147 LightSteelBlue #afafff rgb(175,175,255) hsl(240,100%,84%)"}, - {{0xaf, 0xd7, 0x00}, - "148 Yellow3 #afd700 rgb(175,215,0) hsl(1,100%,42%)"}, - {{0xaf, 0xd7, 0x5f}, - "149 DarkOliveGreen3 #afd75f rgb(175,215,95) hsl(80,60%,60%)"}, - {{0xaf, 0xd7, 0x87}, - "150 DarkSeaGreen3 #afd787 rgb(175,215,135) hsl(90,50%,68%)"}, - {{0xaf, 0xd7, 0xaf}, - "151 DarkSeaGreen2 #afd7af rgb(175,215,175) hsl(120,33%,76%)"}, - {{0xaf, 0xd7, 0xd7}, - "152 LightCyan3 #afd7d7 rgb(175,215,215) hsl(180,33%,76%)"}, - {{0xaf, 0xd7, 0xff}, - "153 LightSkyBlue1 #afd7ff rgb(175,215,255) hsl(210,100%,84%)"}, - {{0xaf, 0xff, 0x00}, - "154 GreenYellow #afff00 rgb(175,255,0) hsl(8,100%,50%)"}, - {{0xaf, 0xff, 0x5f}, - "155 DarkOliveGreen2 #afff5f rgb(175,255,95) hsl(90,100%,68%)"}, - {{0xaf, 0xff, 0x87}, - "156 PaleGreen1 #afff87 rgb(175,255,135) hsl(100,100%,76%)"}, - {{0xaf, 0xff, 0xaf}, - "157 DarkSeaGreen2 #afffaf rgb(175,255,175) hsl(120,100%,84%)"}, - {{0xaf, 0xff, 0xd7}, - "158 DarkSeaGreen1 #afffd7 rgb(175,255,215) hsl(150,100%,84%)"}, - {{0xaf, 0xff, 0xff}, - "159 PaleTurquoise1 #afffff rgb(175,255,255) hsl(180,100%,84%)"}, - {{0xd7, 0x00, 0x00}, - "160 Red3 #d70000 rgb(215,0,0) hsl(0,100%,42%)"}, - {{0xd7, 0x00, 0x5f}, - "161 DeepPink3 #d7005f rgb(215,0,95) hsl(33,100%,42%)"}, - {{0xd7, 0x00, 0x87}, - "162 DeepPink3 #d70087 rgb(215,0,135) hsl(22,100%,42%)"}, - {{0xd7, 0x00, 0xaf}, - "163 Magenta3 #d700af rgb(215,0,175) hsl(11,100%,42%)"}, - {{0xd7, 0x00, 0xd7}, - "164 Magenta3 #d700d7 rgb(215,0,215) hsl(300,100%,42%)"}, - {{0xd7, 0x00, 0xff}, - "165 Magenta2 #d700ff rgb(215,0,255) hsl(90,100%,50%)"}, - {{0xd7, 0x5f, 0x00}, - "166 DarkOrange3 #d75f00 rgb(215,95,0) hsl(6,100%,42%)"}, - {{0xd7, 0x5f, 0x5f}, - "167 IndianRed #d75f5f rgb(215,95,95) hsl(0,60%,60%)"}, - {{0xd7, 0x5f, 0x87}, - "168 HotPink3 #d75f87 rgb(215,95,135) hsl(340,60%,60%)"}, - {{0xd7, 0x5f, 0xaf}, - "169 HotPink2 #d75faf rgb(215,95,175) hsl(320,60%,60%)"}, - {{0xd7, 0x5f, 0xd7}, - "170 Orchid #d75fd7 rgb(215,95,215) hsl(300,60%,60%)"}, - {{0xd7, 0x5f, 0xff}, - "171 MediumOrchid1 #d75fff rgb(215,95,255) hsl(285,100%,68%)"}, - {{0xd7, 0x87, 0x00}, - "172 Orange3 #d78700 rgb(215,135,0) hsl(7,100%,42%)"}, - {{0xd7, 0x87, 0x5f}, - "173 LightSalmon3 #d7875f rgb(215,135,95) hsl(20,60%,60%)"}, - {{0xd7, 0x87, 0x87}, - "174 LightPink3 #d78787 rgb(215,135,135) hsl(0,50%,68%)"}, - {{0xd7, 0x87, 0xaf}, - "175 Pink3 #d787af rgb(215,135,175) hsl(330,50%,68%)"}, - {{0xd7, 0x87, 0xd7}, - "176 Plum3 #d787d7 rgb(215,135,215) hsl(300,50%,68%)"}, - {{0xd7, 0x87, 0xff}, - "177 Violet #d787ff rgb(215,135,255) hsl(280,100%,76%)"}, - {{0xd7, 0xaf, 0x00}, - "178 Gold3 #d7af00 rgb(215,175,0) hsl(8,100%,42%)"}, - {{0xd7, 0xaf, 0x5f}, - "179 LightGoldenrod3 #d7af5f rgb(215,175,95) hsl(40,60%,60%)"}, - {{0xd7, 0xaf, 0x87}, - "180 Tan #d7af87 rgb(215,175,135) hsl(30,50%,68%)"}, - {{0xd7, 0xaf, 0xaf}, - "181 MistyRose3 #d7afaf rgb(215,175,175) hsl(0,33%,76%)"}, - {{0xd7, 0xaf, 0xd7}, - "182 Thistle3 #d7afd7 rgb(215,175,215) hsl(300,33%,76%)"}, - {{0xd7, 0xaf, 0xff}, - "183 Plum2 #d7afff rgb(215,175,255) hsl(270,100%,84%)"}, - {{0xd7, 0xd7, 0x00}, - "184 Yellow3 #d7d700 rgb(215,215,0) hsl(60,100%,42%)"}, - {{0xd7, 0xd7, 0x5f}, - "185 Khaki3 #d7d75f rgb(215,215,95) hsl(60,60%,60%)"}, - {{0xd7, 0xd7, 0x87}, - "186 LightGoldenrod2 #d7d787 rgb(215,215,135) hsl(60,50%,68%)"}, - {{0xd7, 0xd7, 0xaf}, - "187 LightYellow3 #d7d7af rgb(215,215,175) hsl(60,33%,76%)"}, - {{0xd7, 0xd7, 0xd7}, - "188 Grey84 #d7d7d7 rgb(215,215,215) hsl(0,0%,84%)"}, - {{0xd7, 0xd7, 0xff}, - "189 LightSteelBlue1 #d7d7ff rgb(215,215,255) hsl(240,100%,92%)"}, - {{0xd7, 0xff, 0x00}, - "190 Yellow2 #d7ff00 rgb(215,255,0) hsl(9,100%,50%)"}, - {{0xd7, 0xff, 0x5f}, - "191 DarkOliveGreen1 #d7ff5f rgb(215,255,95) hsl(75,100%,68%)"}, - {{0xd7, 0xff, 0x87}, - "192 DarkOliveGreen1 #d7ff87 rgb(215,255,135) hsl(80,100%,76%)"}, - {{0xd7, 0xff, 0xaf}, - "193 DarkSeaGreen1 #d7ffaf rgb(215,255,175) hsl(90,100%,84%)"}, - {{0xd7, 0xff, 0xd7}, - "194 Honeydew2 #d7ffd7 rgb(215,255,215) hsl(120,100%,92%)"}, - {{0xd7, 0xff, 0xff}, - "195 LightCyan1 #d7ffff rgb(215,255,255) hsl(180,100%,92%)"}, - {{0xff, 0x00, 0x00}, - "196 Red1 #ff0000 rgb(255,0,0) hsl(0,100%,50%)"}, - {{0xff, 0x00, 0x5f}, - "197 DeepPink2 #ff005f rgb(255,0,95) hsl(37,100%,50%)"}, - {{0xff, 0x00, 0x87}, - "198 DeepPink1 #ff0087 rgb(255,0,135) hsl(28,100%,50%)"}, - {{0xff, 0x00, 0xaf}, - "199 DeepPink1 #ff00af rgb(255,0,175) hsl(18,100%,50%)"}, - {{0xff, 0x00, 0xd7}, - "200 Magenta2 #ff00d7 rgb(255,0,215) hsl(09,100%,50%)"}, - {{0xff, 0x00, 0xff}, - "201 Magenta1 #ff00ff rgb(255,0,255) hsl(300,100%,50%)"}, - {{0xff, 0x5f, 0x00}, - "202 OrangeRed1 #ff5f00 rgb(255,95,0) hsl(2,100%,50%)"}, - {{0xff, 0x5f, 0x5f}, - "203 IndianRed1 #ff5f5f rgb(255,95,95) hsl(0,100%,68%)"}, - {{0xff, 0x5f, 0x87}, - "204 IndianRed1 #ff5f87 rgb(255,95,135) hsl(345,100%,68%)"}, - {{0xff, 0x5f, 0xaf}, - "205 HotPink #ff5faf rgb(255,95,175) hsl(330,100%,68%)"}, - {{0xff, 0x5f, 0xd7}, - "206 HotPink #ff5fd7 rgb(255,95,215) hsl(315,100%,68%)"}, - {{0xff, 0x5f, 0xff}, - "207 MediumOrchid1 #ff5fff rgb(255,95,255) hsl(300,100%,68%)"}, - {{0xff, 0x87, 0x00}, - "208 DarkOrange #ff8700 rgb(255,135,0) hsl(1,100%,50%)"}, - {{0xff, 0x87, 0x5f}, - "209 Salmon1 #ff875f rgb(255,135,95) hsl(15,100%,68%)"}, - {{0xff, 0x87, 0x87}, - "210 LightCoral #ff8787 rgb(255,135,135) hsl(0,100%,76%)"}, - {{0xff, 0x87, 0xaf}, - "211 PaleVioletRed1 #ff87af rgb(255,135,175) hsl(340,100%,76%)"}, - {{0xff, 0x87, 0xd7}, - "212 Orchid2 #ff87d7 rgb(255,135,215) hsl(320,100%,76%)"}, - {{0xff, 0x87, 0xff}, - "213 Orchid1 #ff87ff rgb(255,135,255) hsl(300,100%,76%)"}, - {{0xff, 0xaf, 0x00}, - "214 Orange1 #ffaf00 rgb(255,175,0) hsl(1,100%,50%)"}, - {{0xff, 0xaf, 0x5f}, - "215 SandyBrown #ffaf5f rgb(255,175,95) hsl(30,100%,68%)"}, - {{0xff, 0xaf, 0x87}, - "216 LightSalmon1 #ffaf87 rgb(255,175,135) hsl(20,100%,76%)"}, - {{0xff, 0xaf, 0xaf}, - "217 LightPink1 #ffafaf rgb(255,175,175) hsl(0,100%,84%)"}, - {{0xff, 0xaf, 0xd7}, - "218 Pink1 #ffafd7 rgb(255,175,215) hsl(330,100%,84%)"}, - {{0xff, 0xaf, 0xff}, - "219 Plum1 #ffafff rgb(255,175,255) hsl(300,100%,84%)"}, - {{0xff, 0xd7, 0x00}, - "220 Gold1 #ffd700 rgb(255,215,0) hsl(0,100%,50%)"}, - {{0xff, 0xd7, 0x5f}, - "221 LightGoldenrod2 #ffd75f rgb(255,215,95) hsl(45,100%,68%)"}, - {{0xff, 0xd7, 0x87}, - "222 LightGoldenrod2 #ffd787 rgb(255,215,135) hsl(40,100%,76%)"}, - {{0xff, 0xd7, 0xaf}, - "223 NavajoWhite1 #ffd7af rgb(255,215,175) hsl(30,100%,84%)"}, - {{0xff, 0xd7, 0xd7}, - "224 MistyRose1 #ffd7d7 rgb(255,215,215) hsl(0,100%,92%)"}, - {{0xff, 0xd7, 0xff}, - "225 Thistle1 #ffd7ff rgb(255,215,255) hsl(300,100%,92%)"}, - {{0xff, 0xff, 0x00}, - "226 Yellow1 #ffff00 rgb(255,255,0) hsl(60,100%,50%)"}, - {{0xff, 0xff, 0x5f}, - "227 LightGoldenrod1 #ffff5f rgb(255,255,95) hsl(60,100%,68%)"}, - {{0xff, 0xff, 0x87}, - "228 Khaki1 #ffff87 rgb(255,255,135) hsl(60,100%,76%)"}, - {{0xff, 0xff, 0xaf}, - "229 Wheat1 #ffffaf rgb(255,255,175) hsl(60,100%,84%)"}, - {{0xff, 0xff, 0xd7}, - "230 Cornsilk1 #ffffd7 rgb(255,255,215) hsl(60,100%,92%)"}, - {{0xff, 0xff, 0xff}, - "231 Grey100 #ffffff rgb(255,255,255) hsl(0,0%,100%)"}, - {{0x08, 0x08, 0x08}, - "232 Grey3 #080808 rgb(8,8,8) hsl(0,0%,3%)"}, - {{0x12, 0x12, 0x12}, - "233 Grey7 #121212 rgb(18,18,18) hsl(0,0%,7%)"}, - {{0x1c, 0x1c, 0x1c}, - "234 Grey11 #1c1c1c rgb(28,28,28) hsl(0,0%,10%)"}, - {{0x26, 0x26, 0x26}, - "235 Grey15 #262626 rgb(38,38,38) hsl(0,0%,14%)"}, - {{0x30, 0x30, 0x30}, - "236 Grey19 #303030 rgb(48,48,48) hsl(0,0%,18%)"}, - {{0x3a, 0x3a, 0x3a}, - "237 Grey23 #3a3a3a rgb(58,58,58) hsl(0,0%,22%)"}, - {{0x44, 0x44, 0x44}, - "238 Grey27 #444444 rgb(68,68,68) hsl(0,0%,26%)"}, - {{0x4e, 0x4e, 0x4e}, - "239 Grey30 #4e4e4e rgb(78,78,78) hsl(0,0%,30%)"}, - {{0x58, 0x58, 0x58}, - "240 Grey35 #585858 rgb(88,88,88) hsl(0,0%,34%)"}, - {{0x62, 0x62, 0x62}, - "241 Grey39 #626262 rgb(98,98,98) hsl(0,0%,37%)"}, - {{0x6c, 0x6c, 0x6c}, - "242 Grey42 #6c6c6c rgb(108,108,108) hsl(0,0%,40%)"}, - {{0x76, 0x76, 0x76}, - "243 Grey46 #767676 rgb(118,118,118) hsl(0,0%,46%)"}, - {{0x80, 0x80, 0x80}, - "244 Grey50 #808080 rgb(128,128,128) hsl(0,0%,50%)"}, - {{0x8a, 0x8a, 0x8a}, - "245 Grey54 #8a8a8a rgb(138,138,138) hsl(0,0%,54%)"}, - {{0x94, 0x94, 0x94}, - "246 Grey58 #949494 rgb(148,148,148) hsl(0,0%,58%)"}, - {{0x9e, 0x9e, 0x9e}, - "247 Grey62 #9e9e9e rgb(158,158,158) hsl(0,0%,61%)"}, - {{0xa8, 0xa8, 0xa8}, - "248 Grey66 #a8a8a8 rgb(168,168,168) hsl(0,0%,65%)"}, - {{0xb2, 0xb2, 0xb2}, - "249 Grey70 #b2b2b2 rgb(178,178,178) hsl(0,0%,69%)"}, - {{0xbc, 0xbc, 0xbc}, - "250 Grey74 #bcbcbc rgb(188,188,188) hsl(0,0%,73%)"}, - {{0xc6, 0xc6, 0xc6}, - "251 Grey78 #c6c6c6 rgb(198,198,198) hsl(0,0%,77%)"}, - {{0xd0, 0xd0, 0xd0}, - "252 Grey82 #d0d0d0 rgb(208,208,208) hsl(0,0%,81%)"}, - {{0xda, 0xda, 0xda}, - "253 Grey85 #dadada rgb(218,218,218) hsl(0,0%,85%)"}, - {{0xe4, 0xe4, 0xe4}, - "254 Grey89 #e4e4e4 rgb(228,228,228) hsl(0,0%,89%)"}, - {{0xee, 0xee, 0xee}, - "255 Grey93 #eeeeee rgb(238,238,238) hsl(0,0%,93%)"}, + {{0x00, 0x00, 0x00}, "0 Black #000000"}, + {{0x80, 0x00, 0x00}, "1 Maroon #800000"}, + {{0x00, 0x80, 0x00}, "2 Green #008000"}, + {{0x80, 0x80, 0x00}, "3 Olive #808000"}, + {{0x00, 0x00, 0x80}, "4 Navy #000080"}, + {{0x80, 0x00, 0x80}, "5 Purple #800080"}, + {{0x00, 0x80, 0x80}, "6 Teal #008080"}, + {{0xc0, 0xc0, 0xc0}, "7 Silver #c0c0c0"}, + {{0x80, 0x80, 0x80}, "8 Grey #808080"}, + {{0xff, 0x00, 0x00}, "9 Red #ff0000"}, + {{0x00, 0xff, 0x00}, "10 Lime #00ff00"}, + {{0xff, 0xff, 0x00}, "11 Yellow #ffff00"}, + {{0x00, 0x00, 0xff}, "12 Blue #0000ff"}, + {{0xff, 0x00, 0xff}, "13 Fuchsia #ff00ff"}, + {{0x00, 0xff, 0xff}, "14 Aqua #00ffff"}, + {{0xff, 0xff, 0xff}, "15 White #ffffff"}, + {{0x00, 0x00, 0x00}, "16 Grey0 #000000"}, + {{0x00, 0x00, 0x5f}, "17 NavyBlue #00005f"}, + {{0x00, 0x00, 0x87}, "18 DarkBlue #000087"}, + {{0x00, 0x00, 0xaf}, "19 Blue3 #0000af"}, + {{0x00, 0x00, 0xd7}, "20 Blue3 #0000d7"}, + {{0x00, 0x00, 0xff}, "21 Blue1 #0000ff"}, + {{0x00, 0x5f, 0x00}, "22 DarkGreen #005f00"}, + {{0x00, 0x5f, 0x5f}, "23 DeepSkyBlue4 #005f5f"}, + {{0x00, 0x5f, 0x87}, "24 DeepSkyBlue4 #005f87"}, + {{0x00, 0x5f, 0xaf}, "25 DeepSkyBlue4 #005faf"}, + {{0x00, 0x5f, 0xd7}, "26 DodgerBlue3 #005fd7"}, + {{0x00, 0x5f, 0xff}, "27 DodgerBlue2 #005fff"}, + {{0x00, 0x87, 0x00}, "28 Green4 #008700"}, + {{0x00, 0x87, 0x5f}, "29 SpringGreen4 #00875f"}, + {{0x00, 0x87, 0x87}, "30 Turquoise4 #008787"}, + {{0x00, 0x87, 0xaf}, "31 DeepSkyBlue3 #0087af"}, + {{0x00, 0x87, 0xd7}, "32 DeepSkyBlue3 #0087d7"}, + {{0x00, 0x87, 0xff}, "33 DodgerBlue1 #0087ff"}, + {{0x00, 0xaf, 0x00}, "34 Green3 #00af00"}, + {{0x00, 0xaf, 0x5f}, "35 SpringGreen3 #00af5f"}, + {{0x00, 0xaf, 0x87}, "36 DarkCyan #00af87"}, + {{0x00, 0xaf, 0xaf}, "37 LightSeaGreen #00afaf"}, + {{0x00, 0xaf, 0xd7}, "38 DeepSkyBlue2 #00afd7"}, + {{0x00, 0xaf, 0xff}, "39 DeepSkyBlue1 #00afff"}, + {{0x00, 0xd7, 0x00}, "40 Green3 #00d700"}, + {{0x00, 0xd7, 0x5f}, "41 SpringGreen3 #00d75f"}, + {{0x00, 0xd7, 0x87}, "42 SpringGreen2 #00d787"}, + {{0x00, 0xd7, 0xaf}, "43 Cyan3 #00d7af"}, + {{0x00, 0xd7, 0xd7}, "44 DarkTurquoise #00d7d7"}, + {{0x00, 0xd7, 0xff}, "45 Turquoise2 #00d7ff"}, + {{0x00, 0xff, 0x00}, "46 Green1 #00ff00"}, + {{0x00, 0xff, 0x5f}, "47 SpringGreen2 #00ff5f"}, + {{0x00, 0xff, 0x87}, "48 SpringGreen1 #00ff87"}, + {{0x00, 0xff, 0xaf}, "49 MediumSpringGreen #00ffaf"}, + {{0x00, 0xff, 0xd7}, "50 Cyan2 #00ffd7"}, + {{0x00, 0xff, 0xff}, "51 Cyan1 #00ffff"}, + {{0x5f, 0x00, 0x00}, "52 DarkRed #5f0000"}, + {{0x5f, 0x00, 0x5f}, "53 DeepPink4 #5f005f"}, + {{0x5f, 0x00, 0x87}, "54 Purple4 #5f0087"}, + {{0x5f, 0x00, 0xaf}, "55 Purple4 #5f00af"}, + {{0x5f, 0x00, 0xd7}, "56 Purple3 #5f00d7"}, + {{0x5f, 0x00, 0xff}, "57 BlueViolet #5f00ff"}, + {{0x5f, 0x5f, 0x00}, "58 Orange4 #5f5f00"}, + {{0x5f, 0x5f, 0x5f}, "59 Grey37 #5f5f5f"}, + {{0x5f, 0x5f, 0x87}, "60 MediumPurple4 #5f5f87"}, + {{0x5f, 0x5f, 0xaf}, "61 SlateBlue3 #5f5faf"}, + {{0x5f, 0x5f, 0xd7}, "62 SlateBlue3 #5f5fd7"}, + {{0x5f, 0x5f, 0xff}, "63 RoyalBlue1 #5f5fff"}, + {{0x5f, 0x87, 0x00}, "64 Chartreuse4 #5f8700"}, + {{0x5f, 0x87, 0x5f}, "65 DarkSeaGreen4 #5f875f"}, + {{0x5f, 0x87, 0x87}, "66 PaleTurquoise4 #5f8787"}, + {{0x5f, 0x87, 0xaf}, "67 SteelBlue #5f87af"}, + {{0x5f, 0x87, 0xd7}, "68 SteelBlue3 #5f87d7"}, + {{0x5f, 0x87, 0xff}, "69 CornflowerBlue #5f87ff"}, + {{0x5f, 0xaf, 0x00}, "70 Chartreuse3 #5faf00"}, + {{0x5f, 0xaf, 0x5f}, "71 DarkSeaGreen4 #5faf5f"}, + {{0x5f, 0xaf, 0x87}, "72 CadetBlue #5faf87"}, + {{0x5f, 0xaf, 0xaf}, "73 CadetBlue #5fafaf"}, + {{0x5f, 0xaf, 0xd7}, "74 SkyBlue3 #5fafd7"}, + {{0x5f, 0xaf, 0xff}, "75 SteelBlue1 #5fafff"}, + {{0x5f, 0xd7, 0x00}, "76 Chartreuse3 #5fd700"}, + {{0x5f, 0xd7, 0x5f}, "77 PaleGreen3 #5fd75f"}, + {{0x5f, 0xd7, 0x87}, "78 SeaGreen3 #5fd787"}, + {{0x5f, 0xd7, 0xaf}, "79 Aquamarine3 #5fd7af"}, + {{0x5f, 0xd7, 0xd7}, "80 MediumTurquoise #5fd7d7"}, + {{0x5f, 0xd7, 0xff}, "81 SteelBlue1 #5fd7ff"}, + {{0x5f, 0xff, 0x00}, "82 Chartreuse2 #5fff00"}, + {{0x5f, 0xff, 0x5f}, "83 SeaGreen2 #5fff5f"}, + {{0x5f, 0xff, 0x87}, "84 SeaGreen1 #5fff87"}, + {{0x5f, 0xff, 0xaf}, "85 SeaGreen1 #5fffaf"}, + {{0x5f, 0xff, 0xd7}, "86 Aquamarine1 #5fffd7"}, + {{0x5f, 0xff, 0xff}, "87 DarkSlateGray2 #5fffff"}, + {{0x87, 0x00, 0x00}, "88 DarkRed #870000"}, + {{0x87, 0x00, 0x5f}, "89 DeepPink4 #87005f"}, + {{0x87, 0x00, 0x87}, "90 DarkMagenta #870087"}, + {{0x87, 0x00, 0xaf}, "91 DarkMagenta #8700af"}, + {{0x87, 0x00, 0xd7}, "92 DarkViolet #8700d7"}, + {{0x87, 0x00, 0xff}, "93 Purple #8700ff"}, + {{0x87, 0x5f, 0x00}, "94 Orange4 #875f00"}, + {{0x87, 0x5f, 0x5f}, "95 LightPink4 #875f5f"}, + {{0x87, 0x5f, 0x87}, "96 Plum4 #875f87"}, + {{0x87, 0x5f, 0xaf}, "97 MediumPurple3 #875faf"}, + {{0x87, 0x5f, 0xd7}, "98 MediumPurple3 #875fd7"}, + {{0x87, 0x5f, 0xff}, "99 SlateBlue1 #875fff"}, + {{0x87, 0x87, 0x00}, "100 Yellow4 #878700"}, + {{0x87, 0x87, 0x5f}, "101 Wheat4 #87875f"}, + {{0x87, 0x87, 0x87}, "102 Grey53 #878787"}, + {{0x87, 0x87, 0xaf}, "103 LightSlateGrey #8787af"}, + {{0x87, 0x87, 0xd7}, "104 MediumPurple #8787d7"}, + {{0x87, 0x87, 0xff}, "105 LightSlateBlue #8787ff"}, + {{0x87, 0xaf, 0x00}, "106 Yellow4 #87af00"}, + {{0x87, 0xaf, 0x5f}, "107 DarkOliveGreen3 #87af5f"}, + {{0x87, 0xaf, 0x87}, "108 DarkSeaGreen #87af87"}, + {{0x87, 0xaf, 0xaf}, "109 LightSkyBlue3 #87afaf"}, + {{0x87, 0xaf, 0xd7}, "110 LightSkyBlue3 #87afd7"}, + {{0x87, 0xaf, 0xff}, "111 SkyBlue2 #87afff"}, + {{0x87, 0xd7, 0x00}, "112 Chartreuse2 #87d700"}, + {{0x87, 0xd7, 0x5f}, "113 DarkOliveGreen3 #87d75f"}, + {{0x87, 0xd7, 0x87}, "114 PaleGreen3 #87d787"}, + {{0x87, 0xd7, 0xaf}, "115 DarkSeaGreen3 #87d7af"}, + {{0x87, 0xd7, 0xd7}, "116 DarkSlateGray3 #87d7d7"}, + {{0x87, 0xd7, 0xff}, "117 SkyBlue1 #87d7ff"}, + {{0x87, 0xff, 0x00}, "118 Chartreuse1 #87ff00"}, + {{0x87, 0xff, 0x5f}, "119 LightGreen #87ff5f"}, + {{0x87, 0xff, 0x87}, "120 LightGreen #87ff87"}, + {{0x87, 0xff, 0xaf}, "121 PaleGreen1 #87ffaf"}, + {{0x87, 0xff, 0xd7}, "122 Aquamarine1 #87ffd7"}, + {{0x87, 0xff, 0xff}, "123 DarkSlateGray1 #87ffff"}, + {{0xaf, 0x00, 0x00}, "124 Red3 #af0000"}, + {{0xaf, 0x00, 0x5f}, "125 DeepPink4 #af005f"}, + {{0xaf, 0x00, 0x87}, "126 MediumVioletRed #af0087"}, + {{0xaf, 0x00, 0xaf}, "127 Magenta3 #af00af"}, + {{0xaf, 0x00, 0xd7}, "128 DarkViolet #af00d7"}, + {{0xaf, 0x00, 0xff}, "129 Purple #af00ff"}, + {{0xaf, 0x5f, 0x00}, "130 DarkOrange3 #af5f00"}, + {{0xaf, 0x5f, 0x5f}, "131 IndianRed #af5f5f"}, + {{0xaf, 0x5f, 0x87}, "132 HotPink3 #af5f87"}, + {{0xaf, 0x5f, 0xaf}, "133 MediumOrchid3 #af5faf"}, + {{0xaf, 0x5f, 0xd7}, "134 MediumOrchid #af5fd7"}, + {{0xaf, 0x5f, 0xff}, "135 MediumPurple2 #af5fff"}, + {{0xaf, 0x87, 0x00}, "136 DarkGoldenrod #af8700"}, + {{0xaf, 0x87, 0x5f}, "137 LightSalmon3 #af875f"}, + {{0xaf, 0x87, 0x87}, "138 RosyBrown #af8787"}, + {{0xaf, 0x87, 0xaf}, "139 Grey63 #af87af"}, + {{0xaf, 0x87, 0xd7}, "140 MediumPurple2 #af87d7"}, + {{0xaf, 0x87, 0xff}, "141 MediumPurple1 #af87ff"}, + {{0xaf, 0xaf, 0x00}, "142 Gold3 #afaf00"}, + {{0xaf, 0xaf, 0x5f}, "143 DarkKhaki #afaf5f"}, + {{0xaf, 0xaf, 0x87}, "144 NavajoWhite3 #afaf87"}, + {{0xaf, 0xaf, 0xaf}, "145 Grey69 #afafaf"}, + {{0xaf, 0xaf, 0xd7}, "146 LightSteelBlue3 #afafd7"}, + {{0xaf, 0xaf, 0xff}, "147 LightSteelBlue #afafff"}, + {{0xaf, 0xd7, 0x00}, "148 Yellow3 #afd700"}, + {{0xaf, 0xd7, 0x5f}, "149 DarkOliveGreen3 #afd75f"}, + {{0xaf, 0xd7, 0x87}, "150 DarkSeaGreen3 #afd787"}, + {{0xaf, 0xd7, 0xaf}, "151 DarkSeaGreen2 #afd7af"}, + {{0xaf, 0xd7, 0xd7}, "152 LightCyan3 #afd7d7"}, + {{0xaf, 0xd7, 0xff}, "153 LightSkyBlue1 #afd7ff"}, + {{0xaf, 0xff, 0x00}, "154 GreenYellow #afff00"}, + {{0xaf, 0xff, 0x5f}, "155 DarkOliveGreen2 #afff5f"}, + {{0xaf, 0xff, 0x87}, "156 PaleGreen1 #afff87"}, + {{0xaf, 0xff, 0xaf}, "157 DarkSeaGreen2 #afffaf"}, + {{0xaf, 0xff, 0xd7}, "158 DarkSeaGreen1 #afffd7"}, + {{0xaf, 0xff, 0xff}, "159 PaleTurquoise1 #afffff"}, + {{0xd7, 0x00, 0x00}, "160 Red3 #d70000"}, + {{0xd7, 0x00, 0x5f}, "161 DeepPink3 #d7005f"}, + {{0xd7, 0x00, 0x87}, "162 DeepPink3 #d70087"}, + {{0xd7, 0x00, 0xaf}, "163 Magenta3 #d700af"}, + {{0xd7, 0x00, 0xd7}, "164 Magenta3 #d700d7"}, + {{0xd7, 0x00, 0xff}, "165 Magenta2 #d700ff"}, + {{0xd7, 0x5f, 0x00}, "166 DarkOrange3 #d75f00"}, + {{0xd7, 0x5f, 0x5f}, "167 IndianRed #d75f5f"}, + {{0xd7, 0x5f, 0x87}, "168 HotPink3 #d75f87"}, + {{0xd7, 0x5f, 0xaf}, "169 HotPink2 #d75faf"}, + {{0xd7, 0x5f, 0xd7}, "170 Orchid #d75fd7"}, + {{0xd7, 0x5f, 0xff}, "171 MediumOrchid1 #d75fff"}, + {{0xd7, 0x87, 0x00}, "172 Orange3 #d78700"}, + {{0xd7, 0x87, 0x5f}, "173 LightSalmon3 #d7875f"}, + {{0xd7, 0x87, 0x87}, "174 LightPink3 #d78787"}, + {{0xd7, 0x87, 0xaf}, "175 Pink3 #d787af"}, + {{0xd7, 0x87, 0xd7}, "176 Plum3 #d787d7"}, + {{0xd7, 0x87, 0xff}, "177 Violet #d787ff"}, + {{0xd7, 0xaf, 0x00}, "178 Gold3 #d7af00"}, + {{0xd7, 0xaf, 0x5f}, "179 LightGoldenrod3 #d7af5f"}, + {{0xd7, 0xaf, 0x87}, "180 Tan #d7af87"}, + {{0xd7, 0xaf, 0xaf}, "181 MistyRose3 #d7afaf"}, + {{0xd7, 0xaf, 0xd7}, "182 Thistle3 #d7afd7"}, + {{0xd7, 0xaf, 0xff}, "183 Plum2 #d7afff"}, + {{0xd7, 0xd7, 0x00}, "184 Yellow3 #d7d700"}, + {{0xd7, 0xd7, 0x5f}, "185 Khaki3 #d7d75f"}, + {{0xd7, 0xd7, 0x87}, "186 LightGoldenrod2 #d7d787"}, + {{0xd7, 0xd7, 0xaf}, "187 LightYellow3 #d7d7af"}, + {{0xd7, 0xd7, 0xd7}, "188 Grey84 #d7d7d7"}, + {{0xd7, 0xd7, 0xff}, "189 LightSteelBlue1 #d7d7ff"}, + {{0xd7, 0xff, 0x00}, "190 Yellow2 #d7ff00"}, + {{0xd7, 0xff, 0x5f}, "191 DarkOliveGreen1 #d7ff5f"}, + {{0xd7, 0xff, 0x87}, "192 DarkOliveGreen1 #d7ff87"}, + {{0xd7, 0xff, 0xaf}, "193 DarkSeaGreen1 #d7ffaf"}, + {{0xd7, 0xff, 0xd7}, "194 Honeydew2 #d7ffd7"}, + {{0xd7, 0xff, 0xff}, "195 LightCyan1 #d7ffff"}, + {{0xff, 0x00, 0x00}, "196 Red1 #ff0000"}, + {{0xff, 0x00, 0x5f}, "197 DeepPink2 #ff005f"}, + {{0xff, 0x00, 0x87}, "198 DeepPink1 #ff0087"}, + {{0xff, 0x00, 0xaf}, "199 DeepPink1 #ff00af"}, + {{0xff, 0x00, 0xd7}, "200 Magenta2 #ff00d7"}, + {{0xff, 0x00, 0xff}, "201 Magenta1 #ff00ff"}, + {{0xff, 0x5f, 0x00}, "202 OrangeRed1 #ff5f00"}, + {{0xff, 0x5f, 0x5f}, "203 IndianRed1 #ff5f5f"}, + {{0xff, 0x5f, 0x87}, "204 IndianRed1 #ff5f87"}, + {{0xff, 0x5f, 0xaf}, "205 HotPink #ff5faf"}, + {{0xff, 0x5f, 0xd7}, "206 HotPink #ff5fd7"}, + {{0xff, 0x5f, 0xff}, "207 MediumOrchid1 #ff5fff"}, + {{0xff, 0x87, 0x00}, "208 DarkOrange #ff8700"}, + {{0xff, 0x87, 0x5f}, "209 Salmon1 #ff875f"}, + {{0xff, 0x87, 0x87}, "210 LightCoral #ff8787"}, + {{0xff, 0x87, 0xaf}, "211 PaleVioletRed1 #ff87af"}, + {{0xff, 0x87, 0xd7}, "212 Orchid2 #ff87d7"}, + {{0xff, 0x87, 0xff}, "213 Orchid1 #ff87ff"}, + {{0xff, 0xaf, 0x00}, "214 Orange1 #ffaf00"}, + {{0xff, 0xaf, 0x5f}, "215 SandyBrown #ffaf5f"}, + {{0xff, 0xaf, 0x87}, "216 LightSalmon1 #ffaf87"}, + {{0xff, 0xaf, 0xaf}, "217 LightPink1 #ffafaf"}, + {{0xff, 0xaf, 0xd7}, "218 Pink1 #ffafd7"}, + {{0xff, 0xaf, 0xff}, "219 Plum1 #ffafff"}, + {{0xff, 0xd7, 0x00}, "220 Gold1 #ffd700"}, + {{0xff, 0xd7, 0x5f}, "221 LightGoldenrod2 #ffd75f"}, + {{0xff, 0xd7, 0x87}, "222 LightGoldenrod2 #ffd787"}, + {{0xff, 0xd7, 0xaf}, "223 NavajoWhite1 #ffd7af"}, + {{0xff, 0xd7, 0xd7}, "224 MistyRose1 #ffd7d7"}, + {{0xff, 0xd7, 0xff}, "225 Thistle1 #ffd7ff"}, + {{0xff, 0xff, 0x00}, "226 Yellow1 #ffff00"}, + {{0xff, 0xff, 0x5f}, "227 LightGoldenrod1 #ffff5f"}, + {{0xff, 0xff, 0x87}, "228 Khaki1 #ffff87"}, + {{0xff, 0xff, 0xaf}, "229 Wheat1 #ffffaf"}, + {{0xff, 0xff, 0xd7}, "230 Cornsilk1 #ffffd7"}, + {{0xff, 0xff, 0xff}, "231 Grey100 #ffffff"}, + {{0x08, 0x08, 0x08}, "232 Grey3 #080808"}, + {{0x12, 0x12, 0x12}, "233 Grey7 #121212"}, + {{0x1c, 0x1c, 0x1c}, "234 Grey11 #1c1c1c"}, + {{0x26, 0x26, 0x26}, "235 Grey15 #262626"}, + {{0x30, 0x30, 0x30}, "236 Grey19 #303030"}, + {{0x3a, 0x3a, 0x3a}, "237 Grey23 #3a3a3a"}, + {{0x44, 0x44, 0x44}, "238 Grey27 #444444"}, + {{0x4e, 0x4e, 0x4e}, "239 Grey30 #4e4e4e"}, + {{0x58, 0x58, 0x58}, "240 Grey35 #585858"}, + {{0x62, 0x62, 0x62}, "241 Grey39 #626262"}, + {{0x6c, 0x6c, 0x6c}, "242 Grey42 #6c6c6c"}, + {{0x76, 0x76, 0x76}, "243 Grey46 #767676"}, + {{0x80, 0x80, 0x80}, "244 Grey50 #808080"}, + {{0x8a, 0x8a, 0x8a}, "245 Grey54 #8a8a8a"}, + {{0x94, 0x94, 0x94}, "246 Grey58 #949494"}, + {{0x9e, 0x9e, 0x9e}, "247 Grey62 #9e9e9e"}, + {{0xa8, 0xa8, 0xa8}, "248 Grey66 #a8a8a8"}, + {{0xb2, 0xb2, 0xb2}, "249 Grey70 #b2b2b2"}, + {{0xbc, 0xbc, 0xbc}, "250 Grey74 #bcbcbc"}, + {{0xc6, 0xc6, 0xc6}, "251 Grey78 #c6c6c6"}, + {{0xd0, 0xd0, 0xd0}, "252 Grey82 #d0d0d0"}, + {{0xda, 0xda, 0xda}, "253 Grey85 #dadada"}, + {{0xe4, 0xe4, 0xe4}, "254 Grey89 #e4e4e4"}, + {{0xee, 0xee, 0xee}, "255 Grey93 #eeeeee"}, }; int main(int argc, char *argv[]) { size_t i; - printf("BG FG BB BF XTERM NAME HEX RGB HSL\n"); + printf("BG FG BB BF XTERM NAME HEX\n"); for (i = 0; i < 256; ++i) { printf("\e[48;5;%dm \e[0m \e[38;5;%dm██\e[0m \e[1;48;5;%dm " - "\e[0m \e[1;38;5;%dm██\e[0m %-6hhu%-18s#%02hhu%02hhu%02hhu\n", - i, i, i, i, i, indexdoublenulstring(kXtermName, i)); + "\e[0m \e[1;38;5;%dm██\e[0m %-6hhu%-18s#%02hhx%02hhx%02hhx\n", + i, i, i, i, i, indexdoublenulstring(kXtermName, i), kXtermRgb[i].r, + kXtermRgb[i].g, kXtermRgb[i].b); } return 0; }