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 00000000..5222be9c Binary files /dev/null and b/tool/net/redbean.ico differ diff --git a/tool/net/redbean.png b/tool/net/redbean.png new file mode 100644 index 00000000..02fa1fe5 Binary files /dev/null and b/tool/net/redbean.png differ 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; }