mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-07-22 18:40:29 +00:00
Make more improvements
This change includes many bug fixes, for the NT polyfills, strings, memory, boot, and math libraries which were discovered by adding more tools for recreational programming, such as PC emulation. Lemon has also been vendored because it works so well at parsing languages.
This commit is contained in:
parent
416fd86676
commit
23d333c090
201 changed files with 14558 additions and 3082 deletions
|
@ -17,12 +17,6 @@ TOOL_BUILD_OBJS = \
|
|||
TOOL_BUILD_COMS = \
|
||||
$(TOOL_BUILD_SRCS:%.c=o/$(MODE)/%.com)
|
||||
|
||||
TOOL_BUILD_LINK = \
|
||||
$(TOOL_BUILD_DEPS) \
|
||||
o/$(MODE)/tool/build/%.o \
|
||||
$(CRT) \
|
||||
$(APE)
|
||||
|
||||
TOOL_BUILD_CHECKS = \
|
||||
$(TOOL_BUILD).pkg \
|
||||
$(TOOL_BUILD_HDRS:%=o/$(MODE)/%.ok) \
|
||||
|
@ -86,24 +80,10 @@ o/$(MODE)/tool/build/%.com.dbg: \
|
|||
$(APE)
|
||||
-@$(APELINK)
|
||||
|
||||
o/$(MODE)/tool/build/mkdeps.o: tool/build/mkdeps.c
|
||||
-@ACTION=OBJECTIFY.c build/compile $(OBJECTIFY.c) $(OUTPUT_OPTION) $<
|
||||
|
||||
o/$(MODE)/tool/build/emulator.o: \
|
||||
OVERRIDE_COPTS += \
|
||||
-fno-sanitize=pointer-overflow
|
||||
|
||||
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: \
|
||||
o/$(MODE)/tool/build/emucrt \
|
||||
|
|
|
@ -49,14 +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/tiny/tool/build/emubin/spiral.bin.dbg: \
|
||||
$(TOOL_BUILD_EMUBIN_DEPS) \
|
||||
o/tiny/tool/build/emubin/spiral.real.o
|
||||
@$(ELFLINK) -z max-page-size=0x10 -T tool/build/emucrt/real.lds
|
||||
|
||||
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
|
||||
o/tiny/tool/build/emubin/mdatest.bin.dbg: \
|
||||
$(TOOL_BUILD_EMUBIN_DEPS) \
|
||||
o/tiny/tool/build/emubin/mdatest.real.o
|
||||
@$(ELFLINK) -z max-page-size=0x10 -T tool/build/emucrt/real.lds
|
||||
|
||||
.PHONY: o/$(MODE)/tool/build/emubin
|
||||
o/$(MODE)/tool/build/emubin: \
|
||||
|
|
44
tool/build/emubin/mdatest.real.c
Normal file
44
tool/build/emubin/mdatest.real.c
Normal file
|
@ -0,0 +1,44 @@
|
|||
/*-*- 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/emubin/poke.h"
|
||||
#include "tool/build/emubin/real.h"
|
||||
|
||||
/*
|
||||
m=tiny; make -j12 MODE=$m o/$m/tool/build/{tinyemu,emulator}.com \
|
||||
o/$m/tool/build/emubin/mdatest.bin && o/$m/tool/build/emulator.com \
|
||||
-rt o/$m/tool/build/emubin/mdatest.bin
|
||||
*/
|
||||
|
||||
static void MdaTest(uint16_t p[25][80]) {
|
||||
int i, y, x;
|
||||
for (i = 0; i < 256; ++i) {
|
||||
y = i / 16;
|
||||
x = i % 16 * 3;
|
||||
POKE(p[y][x + 0], i << 8 | "0123456789abcdef"[(i & 0xf0) >> 4]);
|
||||
POKE(p[y][x + 1], i << 8 | "0123456789abcdef"[(i & 0x0f) >> 0]);
|
||||
}
|
||||
}
|
||||
|
||||
int main() {
|
||||
SetVideoMode(7);
|
||||
SetEs(0xb0000 >> 4);
|
||||
MdaTest((void *)0);
|
||||
for (;;) asm("pause");
|
||||
}
|
|
@ -19,7 +19,7 @@
|
|||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "tool/build/emubin/metalsha256.h"
|
||||
|
||||
#define DISINGENUOUS /* 100 million NOPs is still 100 MIPS lool */
|
||||
//#define DISINGENUOUS /* 100 million NOPs is still 100 MIPS lool */
|
||||
|
||||
static void Print(uint8_t c) {
|
||||
asm volatile("out\t%0,$0xE9" : /* no outputs */ : "a"(c) : "memory");
|
||||
|
|
11
tool/build/emubin/poke.h
Normal file
11
tool/build/emubin/poke.h
Normal file
|
@ -0,0 +1,11 @@
|
|||
#ifndef COSMOPOLITAN_TOOL_BUILD_EMUBIN_POKE_H_
|
||||
#define COSMOPOLITAN_TOOL_BUILD_EMUBIN_POKE_H_
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
#define POKE(MEM, VAL) \
|
||||
asm volatile("mov\t%1,%%es:%0" : "=m"(MEM) : "Qi"((typeof(MEM))(VAL)))
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_TOOL_BUILD_EMUBIN_POKE_H_ */
|
26
tool/build/emubin/real.h
Normal file
26
tool/build/emubin/real.h
Normal file
|
@ -0,0 +1,26 @@
|
|||
#ifndef COSMOPOLITAN_TOOL_BUILD_EMUBIN_REAL_H_
|
||||
#define COSMOPOLITAN_TOOL_BUILD_EMUBIN_REAL_H_
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
asm(".pushsection .start,\"ax\",@progbits\n\t"
|
||||
".globl\t_start\n"
|
||||
"_start:\n\t"
|
||||
"jmp\t1f\n1:\t"
|
||||
"call\tmain\n\t"
|
||||
"nop\n\t"
|
||||
".popsection");
|
||||
|
||||
forceinline void SetEs(int base) {
|
||||
asm volatile("mov%z0\t%0,%%es" : /* no outputs */ : "r"(base));
|
||||
}
|
||||
|
||||
forceinline void SetVideoMode(int mode) {
|
||||
asm volatile("int\t$0x10"
|
||||
: /* no outputs */
|
||||
: "a"(mode));
|
||||
}
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_TOOL_BUILD_EMUBIN_REAL_H_ */
|
|
@ -17,6 +17,8 @@
|
|||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "tool/build/emubin/poke.h"
|
||||
#include "tool/build/emubin/real.h"
|
||||
|
||||
#define signbit(x) __builtin_signbit(x)
|
||||
|
||||
|
@ -38,45 +40,49 @@ static const unsigned char kBlocks[] = {
|
|||
[0b0001] = 0xdf, // ▀
|
||||
};
|
||||
|
||||
static void *memset(void *di, int al, unsigned long cx) {
|
||||
asm("rep stosb %%al,(%0)"
|
||||
forceinline void *memset(void *di, int al, unsigned long cx) {
|
||||
asm("rep stosb"
|
||||
: "=D"(di), "=c"(cx), "=m"(*(char(*)[cx])di)
|
||||
: "0"(di), "1"(cx), "a"(al));
|
||||
return di;
|
||||
}
|
||||
|
||||
static long double pi(void) {
|
||||
forceinline 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) {
|
||||
forceinline long double tau(void) {
|
||||
return pi() * 2;
|
||||
}
|
||||
|
||||
forceinline 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) {
|
||||
forceinline 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) {
|
||||
forceinline 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) {
|
||||
forceinline long double truncl(long double x) {
|
||||
asm("frndint" : "+t"(x));
|
||||
return x;
|
||||
}
|
||||
|
||||
static long double fabsl(long double x) {
|
||||
forceinline long double fabsl(long double x) {
|
||||
asm("fabs" : "+t"(x));
|
||||
return x;
|
||||
}
|
||||
|
||||
static long lroundl(long double x) {
|
||||
forceinline long lroundl(long double x) {
|
||||
int s = signbit(x);
|
||||
x = truncl(fabsl(x) + .5);
|
||||
if (s) x = -x;
|
||||
|
@ -93,36 +99,40 @@ static void SetFpuControlWord(unsigned short cw) {
|
|||
asm volatile("fldcw\t%0" : /* no outputs */ : "m"(cw));
|
||||
}
|
||||
|
||||
static void InitializeFpu(void) {
|
||||
asm("fninit");
|
||||
}
|
||||
|
||||
static void SetTruncationRounding(void) {
|
||||
SetFpuControlWord(GetFpuControlWord() | 0x0c00);
|
||||
}
|
||||
|
||||
static void spiral(unsigned char p[25][80][2], unsigned char B[25][80]) {
|
||||
static void spiral(unsigned char p[25][80][2], unsigned char B[25][80], int g) {
|
||||
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);
|
||||
h = atan2l(u, v) - .333L * g;
|
||||
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;
|
||||
POKE(p[y >> 1][x >> 1][0], kBlocks[B[y >> 1][x >> 1]]);
|
||||
POKE(p[y >> 1][x >> 1][1], (lrintl((h + tau()) * (8 / tau())) & 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");
|
||||
int g;
|
||||
InitializeFpu();
|
||||
SetTruncationRounding();
|
||||
for (;;) {
|
||||
memset((void *)0x40000, 0, 25 * 80);
|
||||
memset((void *)0xb8000, 0, 25 * 80 * 2);
|
||||
spiral((void *)0xb8000, (void *)0x40000);
|
||||
SetVideoMode(3);
|
||||
for (g = 0;; ++g) {
|
||||
SetEs(0);
|
||||
memset((void *)(0x7c00 + 512), 0, 25 * 80);
|
||||
SetEs(0xb8000 >> 4);
|
||||
memset((void *)0, 0, 25 * 80 * 2);
|
||||
spiral((void *)0, (void *)(0x7c00 + 512), g);
|
||||
}
|
||||
}
|
|
@ -27,6 +27,8 @@ SECTIONS {
|
|||
*(.text .text.*)
|
||||
*(.rodata .rodata.*)
|
||||
*(.data .data.*)
|
||||
. = 0x1fe;
|
||||
SHORT(0xaa55);
|
||||
*(.bss .bss.*)
|
||||
*(COMMON)
|
||||
}
|
|
@ -64,13 +64,16 @@
|
|||
#include "tool/build/lib/breakpoint.h"
|
||||
#include "tool/build/lib/case.h"
|
||||
#include "tool/build/lib/cga.h"
|
||||
#include "tool/build/lib/demangle.h"
|
||||
#include "tool/build/lib/dis.h"
|
||||
#include "tool/build/lib/endian.h"
|
||||
#include "tool/build/lib/fds.h"
|
||||
#include "tool/build/lib/flags.h"
|
||||
#include "tool/build/lib/fpu.h"
|
||||
#include "tool/build/lib/high.h"
|
||||
#include "tool/build/lib/loader.h"
|
||||
#include "tool/build/lib/machine.h"
|
||||
#include "tool/build/lib/mda.h"
|
||||
#include "tool/build/lib/memory.h"
|
||||
#include "tool/build/lib/modrm.h"
|
||||
#include "tool/build/lib/panel.h"
|
||||
|
@ -176,8 +179,10 @@ static const char kSegmentNames[16][4] = {
|
|||
|
||||
static int tyn;
|
||||
static int txn;
|
||||
static int tick;
|
||||
static int speed;
|
||||
static int vidya;
|
||||
static int ttyfd;
|
||||
static bool vidya;
|
||||
static bool react;
|
||||
static bool ssehex;
|
||||
static int exitcode;
|
||||
|
@ -200,7 +205,6 @@ static struct Panels pan;
|
|||
static int64_t readstart;
|
||||
static int64_t writestart;
|
||||
static int64_t stackstart;
|
||||
static struct DisHigh high;
|
||||
static struct Machine m[2];
|
||||
static struct MachinePty *pty;
|
||||
static char logpath[PATH_MAX];
|
||||
|
@ -521,6 +525,9 @@ static void SetupDraw(void) {
|
|||
c2y[1] -= tyn - c2y[2] - 26;
|
||||
c2y[2] = tyn - 26;
|
||||
}
|
||||
if (tyn - c2y[2] < 26) {
|
||||
c2y[2] = tyn - 26;
|
||||
}
|
||||
|
||||
a = (tyn - (cpuy + ssey) - 3) / 4;
|
||||
c3y[0] = cpuy;
|
||||
|
@ -642,15 +649,11 @@ static void SetupDraw(void) {
|
|||
xcalloc(pan.p[i].bottom - pan.p[i].top, sizeof(struct Buffer));
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
MachinePtyResize(pty, pan.display.bottom - pan.display.top,
|
||||
pan.display.right - pan.display.left);
|
||||
}
|
||||
|
||||
static long GetDisIndex(int64_t addr) {
|
||||
static long GetDisIndex(void) {
|
||||
long i;
|
||||
if ((i = DisFind(dis, GetIp())) == -1) {
|
||||
Dis(dis, m, GetIp(), pan.disassembly.bottom - pan.disassembly.top * 2);
|
||||
|
@ -692,12 +695,21 @@ 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);
|
||||
switch (vidya) {
|
||||
case 7:
|
||||
DrawHr(&pan.displayhr, "MONOCHROME DISPLAY ADAPTER");
|
||||
DrawMda(p,
|
||||
VirtualSend(m, gc(xmalloc(25 * 80 * 2)), 0xb0000, 25 * 80 * 2));
|
||||
break;
|
||||
case 3:
|
||||
DrawHr(&pan.displayhr, "COLOR GRAPHICS ADAPTER");
|
||||
DrawCga(p,
|
||||
VirtualSend(m, gc(xmalloc(25 * 80 * 2)), 0xb8000, 25 * 80 * 2));
|
||||
break;
|
||||
default:
|
||||
DrawHr(&pan.displayhr, "TELETYPEWRITER");
|
||||
DrawTerminal(p);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -947,15 +959,17 @@ static void DrawMaps(struct Panel *p) {
|
|||
|
||||
static void DrawBreakpoints(struct Panel *p) {
|
||||
int64_t addr;
|
||||
char buf[128];
|
||||
const char *name;
|
||||
char *s, buf[256];
|
||||
long i, line, sym;
|
||||
for (line = 0, i = breakpoints.i; i--;) {
|
||||
if (breakpoints.p[i].disable) continue;
|
||||
addr = breakpoints.p[i].addr;
|
||||
sym = DisFindSym(dis, addr);
|
||||
name = sym != -1 ? dis->syms.stab + dis->syms.p[sym].name : "UNKNOWN";
|
||||
snprintf(buf, sizeof(buf), "%p %s", addr, name);
|
||||
s = buf;
|
||||
s += sprintf(s, "%p ", addr);
|
||||
CHECK_LT(Demangle(s, name), buf + ARRAYLEN(buf));
|
||||
AppendPanel(p, line, buf);
|
||||
if (sym != -1 && addr != dis->syms.p[sym].addr) {
|
||||
snprintf(buf, sizeof(buf), "+%#lx", addr - dis->syms.p[sym].addr);
|
||||
|
@ -982,8 +996,8 @@ static void DrawTrace(struct Panel *p) {
|
|||
int i, n;
|
||||
long sym;
|
||||
uint8_t *r;
|
||||
char line[128];
|
||||
const char *name;
|
||||
char *s, line[256];
|
||||
int64_t sp, bp, rp;
|
||||
rp = m->ip;
|
||||
bp = Read64(m->bp);
|
||||
|
@ -992,7 +1006,9 @@ static void DrawTrace(struct Panel *p) {
|
|||
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", Read64(m->ss) + bp, rp, name);
|
||||
s = line;
|
||||
s += sprintf(s, "%p %p ", Read64(m->ss) + bp, rp);
|
||||
s = Demangle(s, 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);
|
||||
|
@ -1015,19 +1031,8 @@ static void DrawTrace(struct Panel *p) {
|
|||
break;
|
||||
}
|
||||
sp = bp;
|
||||
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;
|
||||
}
|
||||
bp = Read64(r + 0);
|
||||
rp = Read64(r + 8);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1098,12 +1103,53 @@ static void Redraw(void) {
|
|||
}
|
||||
}
|
||||
|
||||
static void ReactiveDraw(void) {
|
||||
if (tuimode) {
|
||||
m->ip -= m->xedd->length;
|
||||
SetupDraw();
|
||||
Redraw();
|
||||
m->ip += m->xedd->length;
|
||||
tick = speed;
|
||||
}
|
||||
}
|
||||
|
||||
static int OnPtyFdClose(int fd) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool HasPendingInput(int fd) {
|
||||
struct pollfd fds[1];
|
||||
fds[0].fd = fd;
|
||||
fds[0].events = POLLIN;
|
||||
fds[0].revents = 0;
|
||||
poll(fds, ARRAYLEN(fds), 0);
|
||||
return fds[0].revents & (POLLIN | POLLERR);
|
||||
}
|
||||
|
||||
static ssize_t ConsumePtyInput(int fd) {
|
||||
char *buf;
|
||||
ssize_t rc;
|
||||
buf = malloc(PAGESIZE);
|
||||
pty->conf |= kMachinePtyBlinkcursor;
|
||||
ReactiveDraw();
|
||||
rc = read(fd, buf, PAGESIZE);
|
||||
pty->conf &= ~kMachinePtyBlinkcursor;
|
||||
ReactiveDraw();
|
||||
if (rc > 0) MachinePtyWriteInput(pty, buf, rc);
|
||||
free(buf);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static ssize_t OnPtyFdRead(int fd, void *data, size_t size) {
|
||||
return read(fd, data, size);
|
||||
ssize_t rc;
|
||||
if (!size) return 0;
|
||||
if (HasPendingInput(fd)) {
|
||||
if ((rc = ConsumePtyInput(fd)) <= 0) return rc;
|
||||
}
|
||||
while (!(rc = MachinePtyRead(pty, data, size))) {
|
||||
if ((rc = ConsumePtyInput(fd)) <= 0) return rc;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
static ssize_t OnPtyFdWrite(int fd, const void *data, size_t size) {
|
||||
|
@ -1115,12 +1161,46 @@ static ssize_t OnPtyFdWrite(int fd, const void *data, size_t size) {
|
|||
}
|
||||
}
|
||||
|
||||
static int OnPtyFdTiocgwinsz(int fd, struct winsize *ws) {
|
||||
ws->ws_row = pty->yn;
|
||||
ws->ws_col = pty->xn;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int OnPtyFdTcgets(int fd, struct termios *c) {
|
||||
memset(c, 0, sizeof(*c));
|
||||
if (!(pty->conf & kMachinePtyNocanon)) c->c_iflag |= ICANON;
|
||||
if (!(pty->conf & kMachinePtyNoecho)) c->c_iflag |= ECHO;
|
||||
if (!(pty->conf & kMachinePtyNoopost)) c->c_oflag |= OPOST;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int OnPtyFdTcsets(int fd, uint64_t request, struct termios *c) {
|
||||
if (c->c_iflag & ICANON) {
|
||||
pty->conf &= ~kMachinePtyNocanon;
|
||||
} else {
|
||||
pty->conf |= kMachinePtyNocanon;
|
||||
}
|
||||
if (c->c_iflag & ECHO) {
|
||||
pty->conf &= ~kMachinePtyNoecho;
|
||||
} else {
|
||||
pty->conf |= kMachinePtyNoecho;
|
||||
}
|
||||
if (c->c_oflag & OPOST) {
|
||||
pty->conf &= ~kMachinePtyNoopost;
|
||||
} else {
|
||||
pty->conf |= kMachinePtyNoopost;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
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;
|
||||
return OnPtyFdTiocgwinsz(fd, memory);
|
||||
} else if (request == TCGETS) {
|
||||
return OnPtyFdTcgets(fd, memory);
|
||||
} else if (request == TCSETS || request == TCSETSW || request == TCSETSF) {
|
||||
return OnPtyFdTcsets(fd, request, memory);
|
||||
} else {
|
||||
return einval();
|
||||
}
|
||||
|
@ -1278,9 +1358,59 @@ static void OnDiskService(void) {
|
|||
}
|
||||
|
||||
static void OnVidyaServiceSetMode(void) {
|
||||
vidya = m->ax[0];
|
||||
}
|
||||
|
||||
static void OnVidyaServiceSetCursor(void) {
|
||||
static void OnVidyaServiceGetMode(void) {
|
||||
m->ax[0] = vidya;
|
||||
m->ax[1] = 80; /* columns */
|
||||
m->bx[1] = 0; /* page */
|
||||
}
|
||||
|
||||
static void OnVidyaServiceSetCursorPosition(void) {
|
||||
pty->y = m->dx[1];
|
||||
pty->x = m->dx[0];
|
||||
}
|
||||
|
||||
static void OnVidyaServiceGetCursorPosition(void) {
|
||||
m->dx[1] = pty->y;
|
||||
m->dx[0] = pty->x;
|
||||
m->cx[1] = 5; /* cursor ▂ scan lines 5..7 of 0..7 */
|
||||
m->cx[0] = 7 | !!(pty->conf & kMachinePtyNocursor) << 5;
|
||||
}
|
||||
|
||||
static void OnVidyaServiceWriteCharacter(void) {
|
||||
char buf[12];
|
||||
int i, n, y, x;
|
||||
y = pty->y;
|
||||
x = pty->x;
|
||||
n = FormatCga(m->bx[0], buf);
|
||||
n += tpencode(buf + n, 6, kCp437[m->ax[0]], false);
|
||||
i = Read16(m->cx);
|
||||
while (i--) MachinePtyWrite(pty, buf, n);
|
||||
pty->y = y;
|
||||
pty->x = x;
|
||||
}
|
||||
|
||||
static char16_t VidyaServiceXlatTeletype(uint8_t c) {
|
||||
switch (c) {
|
||||
case '\a':
|
||||
case '\b':
|
||||
case '\r':
|
||||
case '\n':
|
||||
case 0177:
|
||||
return c;
|
||||
default:
|
||||
return kCp437[c];
|
||||
}
|
||||
}
|
||||
|
||||
static void OnVidyaServiceTeletypeOutput(void) {
|
||||
int n;
|
||||
char buf[12];
|
||||
n = FormatCga(m->bx[0], buf);
|
||||
n += tpencode(buf + n, 6, VidyaServiceXlatTeletype(m->ax[0]), false);
|
||||
MachinePtyWrite(pty, buf, n);
|
||||
}
|
||||
|
||||
static void OnVidyaService(void) {
|
||||
|
@ -1289,7 +1419,47 @@ static void OnVidyaService(void) {
|
|||
OnVidyaServiceSetMode();
|
||||
break;
|
||||
case 0x02:
|
||||
OnVidyaServiceSetCursor();
|
||||
OnVidyaServiceSetCursorPosition();
|
||||
break;
|
||||
case 0x03:
|
||||
OnVidyaServiceGetCursorPosition();
|
||||
break;
|
||||
case 0x09:
|
||||
OnVidyaServiceWriteCharacter();
|
||||
break;
|
||||
case 0x0E:
|
||||
OnVidyaServiceTeletypeOutput();
|
||||
break;
|
||||
case 0x0F:
|
||||
OnVidyaServiceGetMode();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void OnKeyboardServiceReadKeyPress(void) {
|
||||
uint8_t b;
|
||||
ReactiveDraw();
|
||||
read(0, &b, 1);
|
||||
switch (b) {
|
||||
case 0177:
|
||||
b = '\b';
|
||||
break;
|
||||
case CTRL('C'):
|
||||
raise(SIGINT);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
m->ax[0] = b;
|
||||
m->ax[1] = 0;
|
||||
}
|
||||
|
||||
static void OnKeyboardService(void) {
|
||||
switch (m->ax[1]) {
|
||||
case 0x00:
|
||||
OnKeyboardServiceReadKeyPress();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
@ -1356,6 +1526,9 @@ static bool OnHalt(int interrupt) {
|
|||
case 0x15:
|
||||
OnInt15h();
|
||||
return true;
|
||||
case 0x16:
|
||||
OnKeyboardService();
|
||||
return true;
|
||||
case kMachineSegmentationFault:
|
||||
OnSegmentationFault();
|
||||
return false;
|
||||
|
@ -1394,11 +1567,19 @@ static void OnPageDown(void) {
|
|||
}
|
||||
|
||||
static void OnUpArrow(void) {
|
||||
opstart--;
|
||||
if (action & CONTINUE) {
|
||||
speed = MIN(0x40000000, MAX(1, speed) << 1);
|
||||
} else {
|
||||
--opstart;
|
||||
}
|
||||
}
|
||||
|
||||
static void OnDownArrow(void) {
|
||||
opstart++;
|
||||
if (action & CONTINUE) {
|
||||
speed >>= 1;
|
||||
} else {
|
||||
++opstart;
|
||||
}
|
||||
}
|
||||
|
||||
static void OnHome(void) {
|
||||
|
@ -1422,15 +1603,6 @@ static void OnFeed(void) {
|
|||
}
|
||||
|
||||
static void OnUp(void) {
|
||||
uint8_t b[8];
|
||||
int64_t sp, bp, ret;
|
||||
bp = Read64(m->bp);
|
||||
sp = Read64(m->sp);
|
||||
if (bp >= sp) {
|
||||
VirtualSend(m, b, bp + 8, sizeof(b));
|
||||
ret = Read64(b);
|
||||
ScrollOp(&pan.disassembly, GetDisIndex(ret));
|
||||
}
|
||||
}
|
||||
|
||||
static void OnDown(void) {
|
||||
|
@ -1460,7 +1632,7 @@ static void OnFinish(void) {
|
|||
}
|
||||
|
||||
static void OnContinue(void) {
|
||||
action |= CONTINUE;
|
||||
action ^= CONTINUE;
|
||||
action &= ~STEP;
|
||||
action &= ~NEXT;
|
||||
action &= ~FINISH;
|
||||
|
@ -1495,12 +1667,7 @@ static void OnSseHex(void) {
|
|||
}
|
||||
|
||||
static bool HasPendingKeyboard(void) {
|
||||
struct pollfd fds[1];
|
||||
fds[0].fd = ttyfd;
|
||||
fds[0].events = POLLIN;
|
||||
fds[0].revents = 0;
|
||||
poll(fds, ARRAYLEN(fds), 0);
|
||||
return fds[0].revents & (POLLIN | POLLERR);
|
||||
return HasPendingInput(ttyfd);
|
||||
}
|
||||
|
||||
static bool IsExecuting(void) {
|
||||
|
@ -1700,10 +1867,11 @@ static void Tui(void) {
|
|||
long op;
|
||||
ssize_t bp;
|
||||
int interrupt;
|
||||
bool interactive;
|
||||
LOGF("TUI");
|
||||
TuiSetup();
|
||||
SetupDraw();
|
||||
ScrollOp(&pan.disassembly, GetDisIndex(m->ip));
|
||||
ScrollOp(&pan.disassembly, GetDisIndex());
|
||||
if (!(interrupt = setjmp(m->onhalt))) {
|
||||
for (;;) {
|
||||
if (!(action & FAILURE)) {
|
||||
|
@ -1719,13 +1887,18 @@ static void Tui(void) {
|
|||
GetTtySize();
|
||||
action &= ~WINCHED;
|
||||
}
|
||||
SetupDraw();
|
||||
Redraw();
|
||||
interactive = ++tick > speed;
|
||||
if (!(action & CONTINUE) || interactive) {
|
||||
tick = 0;
|
||||
GetDisIndex();
|
||||
SetupDraw();
|
||||
Redraw();
|
||||
}
|
||||
if (action & FAILURE) {
|
||||
LOGF("TUI FAILURE");
|
||||
PrintMessageBox(ttyfd, systemfailure, tyn, txn);
|
||||
ReadKeyboard();
|
||||
} else if (!IsExecuting() || HasPendingKeyboard()) {
|
||||
} else if (!IsExecuting() || (interactive && HasPendingKeyboard())) {
|
||||
ReadKeyboard();
|
||||
}
|
||||
if (action & INT) {
|
||||
|
@ -1755,7 +1928,7 @@ static void Tui(void) {
|
|||
break;
|
||||
}
|
||||
if (IsExecuting()) {
|
||||
op = GetDisIndex(m->ip);
|
||||
op = GetDisIndex();
|
||||
ScrollOp(&pan.disassembly, op);
|
||||
VERBOSEF("%s", DisGetLine(dis, m, op));
|
||||
memcpy(&m[1], &m[0], sizeof(m[0]));
|
||||
|
@ -1789,7 +1962,7 @@ static void Tui(void) {
|
|||
CheckFramePointer();
|
||||
ops++;
|
||||
if (!(action & CONTINUE)) {
|
||||
ScrollOp(&pan.disassembly, GetDisIndex(m->ip));
|
||||
ScrollOp(&pan.disassembly, GetDisIndex());
|
||||
if ((action & FINISH) && IsRet()) action &= ~FINISH;
|
||||
if (((action & NEXT) && IsRet()) || (action & FINISH)) {
|
||||
action &= ~NEXT;
|
||||
|
@ -1807,7 +1980,7 @@ static void Tui(void) {
|
|||
if (OnHalt(interrupt)) {
|
||||
goto KeepGoing;
|
||||
}
|
||||
ScrollOp(&pan.disassembly, GetDisIndex(m->ip));
|
||||
ScrollOp(&pan.disassembly, GetDisIndex());
|
||||
}
|
||||
TuiCleanup();
|
||||
}
|
||||
|
@ -1825,7 +1998,6 @@ static void GetOpts(int argc, char *argv[]) {
|
|||
break;
|
||||
case 'r':
|
||||
m->mode = XED_MACHINE_MODE_REAL;
|
||||
vidya = true;
|
||||
break;
|
||||
case 's':
|
||||
printstats = true;
|
||||
|
@ -1834,7 +2006,7 @@ static void GetOpts(int argc, char *argv[]) {
|
|||
HandleBreakpointFlag(optarg);
|
||||
break;
|
||||
case 'H':
|
||||
g_dis_high = NULL;
|
||||
memset(&g_high, 0, sizeof(g_high));
|
||||
break;
|
||||
case 'v':
|
||||
++g_loglevel;
|
||||
|
@ -1905,14 +2077,14 @@ int main(int argc, char *argv[]) {
|
|||
m->mode = XED_MACHINE_MODE_LONG_64;
|
||||
ssewidth = 2; /* 16-bit is best bit */
|
||||
if (!NoDebug()) showcrashreports();
|
||||
// OnlyRunOnFirstCpu();
|
||||
/* OnlyRunOnFirstCpu(); */
|
||||
if ((colorize = cancolor())) {
|
||||
high.keyword = 155;
|
||||
high.reg = 215;
|
||||
high.literal = 182;
|
||||
high.label = 221;
|
||||
high.comment = 112;
|
||||
g_dis_high = &high;
|
||||
g_high.keyword = 155;
|
||||
g_high.reg = 215;
|
||||
g_high.literal = 182;
|
||||
g_high.label = 221;
|
||||
g_high.comment = 112;
|
||||
g_high.quote = 215;
|
||||
}
|
||||
GetOpts(argc, argv);
|
||||
if (optind == argc) PrintUsage(EX_USAGE, stderr);
|
||||
|
|
|
@ -47,11 +47,10 @@ uint8_t *GetSegment(struct Machine *m, uint32_t rde, int s) {
|
|||
|
||||
uint64_t AddSegment(struct Machine *m, uint32_t rde, uint64_t i, uint8_t s[8]) {
|
||||
if (!Sego(rde)) {
|
||||
i += Read64(s);
|
||||
return i + Read64(s);
|
||||
} else {
|
||||
i += Read64(GetSegment(m, rde, Sego(rde) - 1));
|
||||
return i + Read64(GetSegment(m, rde, Sego(rde) - 1));
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
uint64_t DataSegment(struct Machine *m, uint32_t rde, uint64_t i) {
|
||||
|
|
37
tool/build/lib/breg.c
Normal file
37
tool/build/lib/breg.c
Normal file
|
@ -0,0 +1,37 @@
|
|||
/*-*- 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/modrm.h"
|
||||
|
||||
/**
|
||||
* 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};
|
|
@ -17,9 +17,9 @@
|
|||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "dsp/tty/tty.h"
|
||||
#include "libc/alg/arraylist2.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/fmt/fmt.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/str/tpencode.h"
|
||||
|
@ -58,5 +58,22 @@ void AppendFmt(struct Buffer *b, const char *fmt, ...) {
|
|||
* Writes buffer until completion, interrupt, or error occurs.
|
||||
*/
|
||||
ssize_t WriteBuffer(struct Buffer *b, int fd) {
|
||||
return ttywrite(fd, b->p, b->i);
|
||||
char *p;
|
||||
ssize_t rc;
|
||||
size_t wrote, n;
|
||||
p = b->p;
|
||||
n = b->i;
|
||||
do {
|
||||
TryAgain:
|
||||
if ((rc = write(fd, p, n)) != -1) {
|
||||
wrote = rc;
|
||||
p += wrote;
|
||||
n -= wrote;
|
||||
} else if (errno == EINTR) {
|
||||
goto TryAgain;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
} while (n);
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -25,7 +25,6 @@ TOOL_BUILD_LIB_A_OBJS = \
|
|||
$(TOOL_BUILD_LIB_A_SRCS_C:%.c=o/$(MODE)/%.o)
|
||||
|
||||
TOOL_BUILD_LIB_A_DIRECTDEPS = \
|
||||
DSP_TTY \
|
||||
LIBC_ALG \
|
||||
LIBC_BITS \
|
||||
LIBC_CONV \
|
||||
|
|
|
@ -17,24 +17,37 @@
|
|||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/conv/itoa.h"
|
||||
#include "libc/macros.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "tool/build/lib/buffer.h"
|
||||
#include "tool/build/lib/cga.h"
|
||||
|
||||
static const uint8_t kCgaToAnsi[] = {30, 34, 32, 36, 31, 35, 33, 37,
|
||||
90, 94, 92, 96, 91, 95, 93, 97};
|
||||
/* blk blu grn cyn red mag yel wht */
|
||||
static const uint8_t kCgaToAnsi[16] = {30, 34, 32, 36, 31, 35, 33, 37,
|
||||
90, 94, 92, 96, 91, 95, 93, 97};
|
||||
|
||||
size_t FormatCga(uint8_t bgfg, char buf[hasatleast 11]) {
|
||||
char *p = buf;
|
||||
*p++ = '\e';
|
||||
*p++ = '[';
|
||||
p += uint64toarray_radix10(kCgaToAnsi[(bgfg & 0xF0) >> 4] + 10, p);
|
||||
*p++ = ';';
|
||||
p += uint64toarray_radix10(kCgaToAnsi[bgfg & 0x0F], p);
|
||||
*p++ = 'm';
|
||||
*p = '\0';
|
||||
return p - buf;
|
||||
}
|
||||
|
||||
void DrawCga(struct Panel *p, uint8_t v[25][80][2]) {
|
||||
char buf[11];
|
||||
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);
|
||||
AppendData(&p->lines[y], buf, FormatCga((a = v[y][x][1]), buf));
|
||||
}
|
||||
AppendWide(&p->lines[y], kCp437[v[y][x][0]]);
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
COSMOPOLITAN_C_START_
|
||||
|
||||
void DrawCga(struct Panel *, uint8_t[25][80][2]);
|
||||
size_t FormatCga(uint8_t, char[hasatleast 11]);
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
|
|
|
@ -35,32 +35,32 @@ void OpCpuid(struct Machine *m, uint32_t rde) {
|
|||
dx = 'o' | 's' << 8 | 'm' << 16 | 'o' << 24;
|
||||
break;
|
||||
case 1:
|
||||
cx |= 1 << 0; /* sse3 */
|
||||
cx |= 0 << 1; /* pclmulqdq */
|
||||
cx |= 1 << 9; /* ssse3 */
|
||||
cx |= 1 << 23; /* popcnt */
|
||||
cx |= 0 << 30; /* rdrnd */
|
||||
cx |= 0 << 25; /* aes */
|
||||
dx |= 1 << 0; /* fpu */
|
||||
dx |= 1 << 4; /* tsc */
|
||||
dx |= 1 << 6; /* pae */
|
||||
dx |= 1 << 8; /* cmpxchg8b */
|
||||
dx |= 1 << 15; /* cmov */
|
||||
dx |= 1 << 19; /* clflush */
|
||||
dx |= 1 << 23; /* mmx */
|
||||
dx |= 1 << 25; /* sse */
|
||||
dx |= 1 << 26; /* sse2 */
|
||||
cx |= 1 << 0; // sse3
|
||||
cx |= 0 << 1; // pclmulqdq
|
||||
cx |= 1 << 9; // ssse3
|
||||
cx |= 1 << 23; // popcnt
|
||||
cx |= 0 << 30; // rdrnd
|
||||
cx |= 0 << 25; // aes
|
||||
dx |= 1 << 0; // fpu
|
||||
dx |= 1 << 4; // tsc
|
||||
dx |= 1 << 6; // pae
|
||||
dx |= 1 << 8; // cmpxchg8b
|
||||
dx |= 1 << 15; // cmov
|
||||
dx |= 1 << 19; // clflush
|
||||
dx |= 1 << 23; // mmx
|
||||
dx |= 1 << 25; // sse
|
||||
dx |= 1 << 26; // sse2
|
||||
break;
|
||||
case 7:
|
||||
bx |= 1 << 9; /* erms */
|
||||
bx |= 1 << 9; // erms
|
||||
break;
|
||||
case 0x80000001:
|
||||
cx |= 1 << 0; /* lahf/sahf */
|
||||
dx |= 1 << 11; /* syscall */
|
||||
dx |= 1 << 29; /* long mode */
|
||||
cx |= 1 << 0; // lahf
|
||||
dx |= 1 << 11; // syscall
|
||||
dx |= 1 << 29; // long
|
||||
break;
|
||||
case 0x80000007:
|
||||
dx |= 1 << 8; /* invtsc */
|
||||
dx |= 1 << 8; // invtsc
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
|
94
tool/build/lib/demangle.c
Normal file
94
tool/build/lib/demangle.c
Normal file
|
@ -0,0 +1,94 @@
|
|||
/*-*- 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/hefty/spawn.h"
|
||||
#include "libc/macros.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "tool/build/lib/demangle.h"
|
||||
|
||||
struct CxxFilt {
|
||||
int pid;
|
||||
int fds[3];
|
||||
} g_cxxfilt;
|
||||
|
||||
void CloseCxxFilt(void) {
|
||||
close(g_cxxfilt.fds[0]);
|
||||
close(g_cxxfilt.fds[1]);
|
||||
g_cxxfilt.pid = -1;
|
||||
}
|
||||
|
||||
void SpawnCxxFilt(void) {
|
||||
int pid;
|
||||
char path[PATH_MAX];
|
||||
if (commandv("c++filt", path)) {
|
||||
g_cxxfilt.fds[0] = -1;
|
||||
g_cxxfilt.fds[1] = -1;
|
||||
g_cxxfilt.fds[2] = 2;
|
||||
if ((pid = spawnve(0, g_cxxfilt.fds, path, (char *const[]){"c++filt", NULL},
|
||||
environ)) != -1) {
|
||||
atexit(CloseCxxFilt);
|
||||
}
|
||||
} else {
|
||||
pid = -1;
|
||||
}
|
||||
g_cxxfilt.pid = pid;
|
||||
}
|
||||
|
||||
char *DemangleCxxFilt(char *p, const char *symbol) {
|
||||
int n;
|
||||
char buf[512];
|
||||
bool iscomplicated;
|
||||
if (!g_cxxfilt.pid) SpawnCxxFilt();
|
||||
if (g_cxxfilt.pid == -1) return NULL;
|
||||
if ((n = strlen(symbol)) >= ARRAYLEN(buf)) return NULL;
|
||||
memcpy(buf, symbol, n);
|
||||
buf[n] = '\n';
|
||||
write(g_cxxfilt.fds[0], buf, n + 1);
|
||||
n = read(g_cxxfilt.fds[1], buf, ARRAYLEN(buf));
|
||||
if (n > 1 && buf[n - 1] == '\n') {
|
||||
if (buf[n - 2] == '\r') --n;
|
||||
--n;
|
||||
iscomplicated = memchr(buf, ' ', n) || memchr(buf, '(', n);
|
||||
if (iscomplicated) *p++ = '"';
|
||||
p = mempcpy(p, buf, n);
|
||||
if (iscomplicated) *p++ = '"';
|
||||
*p = '\0';
|
||||
return p;
|
||||
} else {
|
||||
CloseCxxFilt();
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrypts C++ symbol.
|
||||
*
|
||||
* Decoding these takes roughly the same lines of code as an entire
|
||||
* x86_64 disassembler. That's just for the GNU encoding scheme. So
|
||||
* what we'll do, is just offload this work to the c++filt program.
|
||||
*/
|
||||
char *Demangle(char *p, const char *symbol) {
|
||||
char *r;
|
||||
if (startswith(symbol, "_Z")) {
|
||||
if ((r = DemangleCxxFilt(p, symbol))) return r;
|
||||
}
|
||||
return stpcpy(p, symbol);
|
||||
}
|
10
tool/build/lib/demangle.h
Normal file
10
tool/build/lib/demangle.h
Normal file
|
@ -0,0 +1,10 @@
|
|||
#ifndef COSMOPOLITAN_TOOL_BUILD_LIB_DEMANGLE_H_
|
||||
#define COSMOPOLITAN_TOOL_BUILD_LIB_DEMANGLE_H_
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
char *Demangle(char *, const char *);
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_TOOL_BUILD_LIB_DEMANGLE_H_ */
|
|
@ -33,7 +33,9 @@
|
|||
#include "libc/str/tpencode.h"
|
||||
#include "third_party/xed/x86.h"
|
||||
#include "tool/build/lib/case.h"
|
||||
#include "tool/build/lib/demangle.h"
|
||||
#include "tool/build/lib/dis.h"
|
||||
#include "tool/build/lib/high.h"
|
||||
#include "tool/build/lib/memory.h"
|
||||
#include "tool/build/lib/modrm.h"
|
||||
|
||||
|
@ -73,93 +75,99 @@ static char *DisOctets(char *p, const uint8_t *d, size_t n) {
|
|||
}
|
||||
|
||||
static char *DisByte(char *p, const uint8_t *d, size_t n) {
|
||||
if (g_dis_high) p = DisHigh(p, g_dis_high->keyword);
|
||||
p = HighStart(p, g_high.keyword);
|
||||
p = DisColumn(stpcpy(p, ".byte"), p, NAMELEN);
|
||||
if (g_dis_high) p = DisHigh(p, -1);
|
||||
p = HighEnd(p);
|
||||
p = DisOctets(p, d, n);
|
||||
return p;
|
||||
}
|
||||
|
||||
static char *DisError(struct DisBuilder b, char *p) {
|
||||
p = DisColumn(DisByte(p, b.xedd->bytes, MIN(15, b.xedd->length)), p, CODELEN);
|
||||
if (g_dis_high) p = DisHigh(p, g_dis_high->comment);
|
||||
static char *DisError(struct Dis *d, char *p) {
|
||||
p = DisColumn(DisByte(p, d->xedd->bytes, MIN(15, d->xedd->length)), p,
|
||||
CODELEN);
|
||||
p = HighStart(p, g_high.comment);
|
||||
*p++ = '#';
|
||||
*p++ = ' ';
|
||||
p = stpcpy(p, indexdoublenulstring(kXedErrorNames, b.xedd->op.error));
|
||||
if (g_dis_high) p = DisHigh(p, -1);
|
||||
p = stpcpy(p, indexdoublenulstring(kXedErrorNames, d->xedd->op.error));
|
||||
p = HighEnd(p);
|
||||
*p = '\0';
|
||||
return p;
|
||||
}
|
||||
|
||||
static char *DisAddr(struct DisBuilder b, char *p) {
|
||||
if (INT_MIN <= b.addr && b.addr <= INT_MAX) {
|
||||
return p + uint64toarray_fixed16(b.addr, p, 32);
|
||||
static char *DisAddr(struct Dis *d, char *p) {
|
||||
if (INT32_MIN <= d->addr && d->addr <= INT32_MAX) {
|
||||
return p + uint64toarray_fixed16(d->addr, p, 32);
|
||||
} else {
|
||||
return p + uint64toarray_fixed16(b.addr, p, 48);
|
||||
return p + uint64toarray_fixed16(d->addr, p, 48);
|
||||
}
|
||||
}
|
||||
|
||||
static char *DisRaw(struct DisBuilder b, char *p) {
|
||||
static char *DisRaw(struct Dis *d, char *p) {
|
||||
long i;
|
||||
for (i = 0; i < PFIXLEN - MIN(PFIXLEN, b.xedd->op.PIVOTOP); ++i) {
|
||||
for (i = 0; i < PFIXLEN - MIN(PFIXLEN, d->xedd->op.PIVOTOP); ++i) {
|
||||
*p++ = ' ';
|
||||
*p++ = ' ';
|
||||
}
|
||||
for (i = 0; i < MIN(15, b.xedd->length); ++i) {
|
||||
if (i == b.xedd->op.PIVOTOP) *p++ = ' ';
|
||||
*p++ = "0123456789abcdef"[(b.xedd->bytes[i] & 0xf0) >> 4];
|
||||
*p++ = "0123456789abcdef"[b.xedd->bytes[i] & 0x0f];
|
||||
for (i = 0; i < MIN(15, d->xedd->length); ++i) {
|
||||
if (i == d->xedd->op.PIVOTOP) *p++ = ' ';
|
||||
*p++ = "0123456789abcdef"[(d->xedd->bytes[i] & 0xf0) >> 4];
|
||||
*p++ = "0123456789abcdef"[d->xedd->bytes[i] & 0x0f];
|
||||
}
|
||||
*p = '\0';
|
||||
return p;
|
||||
}
|
||||
|
||||
static char *DisCode(struct DisBuilder b, char *p) {
|
||||
static char *DisCode(struct Dis *d, char *p) {
|
||||
char optspecbuf[128];
|
||||
if (!b.xedd->op.error) {
|
||||
return DisInst(b, p, DisSpec(b.xedd, optspecbuf));
|
||||
if (!d->xedd->op.error) {
|
||||
return DisInst(d, p, DisSpec(d->xedd, optspecbuf));
|
||||
} else {
|
||||
return DisError(b, p);
|
||||
return DisError(d, p);
|
||||
}
|
||||
}
|
||||
|
||||
static char *DisLineCode(struct DisBuilder b, char *p) {
|
||||
p = DisColumn(DisAddr(b, p), p, ADDRLEN);
|
||||
p = DisColumn(DisRaw(b, p), p, PFIXLEN * 2 + 1 + BYTELEN * 2);
|
||||
p = DisCode(b, p);
|
||||
static char *DisLineCode(struct Dis *d, char *p) {
|
||||
p = DisColumn(DisAddr(d, p), p, ADDRLEN);
|
||||
p = DisColumn(DisRaw(d, p), p, PFIXLEN * 2 + 1 + BYTELEN * 2);
|
||||
p = DisCode(d, p);
|
||||
return p;
|
||||
}
|
||||
|
||||
static char *DisLineData(struct DisBuilder b, char *p, const uint8_t *d,
|
||||
size_t n) {
|
||||
static char *DisLineData(struct Dis *d, char *p, const uint8_t *b, size_t n) {
|
||||
size_t i;
|
||||
p = DisColumn(DisAddr(b, p), p, ADDRLEN);
|
||||
p = DisColumn(DisByte(p, d, n), p, 64);
|
||||
if (g_dis_high) p = DisHigh(p, g_dis_high->comment);
|
||||
p = DisColumn(DisAddr(d, p), p, ADDRLEN);
|
||||
p = DisColumn(DisByte(p, b, n), p, 64);
|
||||
p = HighStart(p, g_high.comment);
|
||||
*p++ = '#';
|
||||
*p++ = ' ';
|
||||
for (i = 0; i < n; ++i) p += tpencode(p, 8, bing(d[i], 0), false);
|
||||
if (g_dis_high) p = DisHigh(p, -1);
|
||||
for (i = 0; i < n; ++i) p += tpencode(p, 8, bing(b[i], 0), false);
|
||||
p = HighEnd(p);
|
||||
*p = '\0';
|
||||
return p;
|
||||
}
|
||||
|
||||
static char *DisLabel(struct DisBuilder b, char *p, const char *name) {
|
||||
p = DisColumn(DisAddr(b, p), p, ADDRLEN);
|
||||
if (g_dis_high) p = DisHigh(p, g_dis_high->label);
|
||||
p = stpcpy(p, name);
|
||||
if (g_dis_high) p = DisHigh(p, -1);
|
||||
static char *DisLabel(struct Dis *d, char *p, const char *name) {
|
||||
p = DisColumn(DisAddr(d, p), p, ADDRLEN);
|
||||
p = HighStart(p, g_high.label);
|
||||
p = Demangle(p, name);
|
||||
p = HighEnd(p);
|
||||
*p++ = ':';
|
||||
*p = '\0';
|
||||
return p;
|
||||
}
|
||||
|
||||
long DisFind(struct Dis *d, int64_t addr) {
|
||||
long i;
|
||||
for (i = 0; i < d->ops.i; ++i) {
|
||||
if (addr >= d->ops.p[i].addr &&
|
||||
addr < d->ops.p[i].addr + d->ops.p[i].size) {
|
||||
return i;
|
||||
int l, r, m, i;
|
||||
l = 0;
|
||||
r = d->ops.i - 1;
|
||||
while (l <= r) {
|
||||
m = (l + r) >> 1;
|
||||
if (d->ops.p[m].addr < addr) {
|
||||
l = m + 1;
|
||||
} else if (d->ops.p[m].addr > addr) {
|
||||
r = m - 1;
|
||||
} else {
|
||||
return m;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
|
@ -181,8 +189,8 @@ static long DisOne(struct Dis *d, struct Machine *m, int64_t addr) {
|
|||
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);
|
||||
d->addr = addr;
|
||||
DisLabel(d, 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);
|
||||
}
|
||||
|
@ -238,7 +246,8 @@ const char *DisGetLine(struct Dis *d, struct Machine *m, size_t i) {
|
|||
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);
|
||||
d->addr = d->ops.p[i].addr;
|
||||
p = DisLineCode(d, d->buf);
|
||||
CHECK_LT(p - d->buf, sizeof(d->buf));
|
||||
return d->buf;
|
||||
}
|
||||
|
|
|
@ -45,25 +45,10 @@ struct Dis {
|
|||
} * p;
|
||||
} edges;
|
||||
struct XedDecodedInst xedd[1];
|
||||
uint64_t addr;
|
||||
char buf[512];
|
||||
};
|
||||
|
||||
struct DisBuilder {
|
||||
struct Dis *dis;
|
||||
struct XedDecodedInst *xedd;
|
||||
int64_t addr;
|
||||
};
|
||||
|
||||
struct DisHigh {
|
||||
uint8_t keyword;
|
||||
uint8_t reg;
|
||||
uint8_t literal;
|
||||
uint8_t label;
|
||||
uint8_t comment;
|
||||
};
|
||||
|
||||
extern struct DisHigh *g_dis_high;
|
||||
|
||||
long Dis(struct Dis *, struct Machine *, int64_t, int);
|
||||
long DisFind(struct Dis *, int64_t);
|
||||
void DisFree(struct Dis *);
|
||||
|
@ -74,10 +59,9 @@ long DisFindSym(struct Dis *, int64_t);
|
|||
long DisFindSymByName(struct Dis *, const char *);
|
||||
bool DisIsText(struct Dis *, int64_t);
|
||||
bool DisIsProg(struct Dis *, int64_t);
|
||||
char *DisInst(struct Dis *, char *, const char *);
|
||||
char *DisArg(struct Dis *, char *, const char *);
|
||||
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_
|
||||
|
|
|
@ -24,23 +24,27 @@
|
|||
#include "libc/log/check.h"
|
||||
#include "libc/macros.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "tool/build/lib/demangle.h"
|
||||
#include "tool/build/lib/dis.h"
|
||||
#include "tool/build/lib/endian.h"
|
||||
#include "tool/build/lib/high.h"
|
||||
#include "tool/build/lib/modrm.h"
|
||||
|
||||
static const char kScale[4][4] = {"", ",2", ",4", ",8"};
|
||||
static const char kSegName[8][3] = {"es", "cs", "ss", "ds", "fs", "gs"};
|
||||
static const char kPuttingOnTheRiz[2][4] = {"eiz", "riz"};
|
||||
static const char kPuttingOnTheRip[2][4] = {"eip", "rip"};
|
||||
static const char kRiz[2][4] = {"eiz", "riz"};
|
||||
static const char kRip[2][4] = {"eip", "rip"};
|
||||
static const char kSka[4][4] = {"", ",2", ",4", ",8"};
|
||||
static const char kSeg[8][3] = {"es", "cs", "ss", "ds", "fs", "gs"};
|
||||
static const char kCtl[8][4] = {"cr0", "wut", "cr2", "cr3",
|
||||
"cr4", "wut", "wut", "wut"};
|
||||
|
||||
static const char kRegisterName8[2][2][8][5] = {
|
||||
static const char kBreg[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"}},
|
||||
};
|
||||
|
||||
static const char kRegisterName[2][2][2][8][5] = {
|
||||
static const char kGreg[2][2][2][8][5] = {
|
||||
{{{"eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi"},
|
||||
{"r8d", "r9d", "r10d", "r11d", "r12d", "r13d", "r14d", "r15d"}},
|
||||
{{"rax", "rcx", "rdx", "rbx", "rsp", "rbp", "rsi", "rdi"},
|
||||
|
@ -51,43 +55,39 @@ 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 int64_t RipRelative(struct Dis *d, int64_t i) {
|
||||
return d->addr + d->xedd->length + i;
|
||||
}
|
||||
|
||||
static const char *GetAddrReg(struct DisBuilder b, uint32_t rde, uint8_t x,
|
||||
static const char *GetAddrReg(struct Dis *d, 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];
|
||||
return kGreg[Eamode(rde) == XED_MODE_REAL][Eamode(rde) == XED_MODE_LONG]
|
||||
[x & 1][r & 7];
|
||||
}
|
||||
|
||||
static char *DisRegister(char *p, const char *s) {
|
||||
if (g_dis_high) p = DisHigh(p, g_dis_high->reg);
|
||||
p = HighStart(p, g_high.reg);
|
||||
*p++ = '%';
|
||||
p = stpcpy(p, s);
|
||||
if (g_dis_high) p = DisHigh(p, -1);
|
||||
p = HighEnd(p);
|
||||
return p;
|
||||
}
|
||||
|
||||
static char *DisComment(char *p, const char *s) {
|
||||
if (g_dis_high) p = DisHigh(p, g_dis_high->comment);
|
||||
p = HighStart(p, g_high.comment);
|
||||
p = stpcpy(p, s);
|
||||
if (g_dis_high) p = DisHigh(p, -1);
|
||||
p = HighEnd(p);
|
||||
return p;
|
||||
}
|
||||
|
||||
static char *DisRegisterByte(struct DisBuilder b, uint32_t rde, char *p, bool g,
|
||||
static char *DisRegisterByte(struct Dis *d, uint32_t rde, char *p, bool g,
|
||||
int r) {
|
||||
return DisRegister(p, kRegisterName8[g][Rex(rde)][r]);
|
||||
return DisRegister(p, kBreg[g][Rex(rde)][r]);
|
||||
}
|
||||
|
||||
static char *DisRegisterWord(struct DisBuilder b, uint32_t rde, char *p, bool g,
|
||||
static char *DisRegisterWord(struct Dis *d, uint32_t rde, char *p, bool g,
|
||||
int r) {
|
||||
return DisRegister(p, kRegisterName[Osz(rde)][Rexw(rde)][g][r]);
|
||||
return DisRegister(p, kGreg[Osz(rde)][Rexw(rde)][g][r]);
|
||||
}
|
||||
|
||||
static char *DisInt(char *p, int64_t x) {
|
||||
|
@ -106,14 +106,14 @@ static char *DisInt(char *p, int64_t x) {
|
|||
return p;
|
||||
}
|
||||
|
||||
static char *DisSym(struct DisBuilder b, char *p, int64_t addr) {
|
||||
static char *DisSym(struct Dis *d, char *p, int64_t addr) {
|
||||
long sym;
|
||||
int64_t addend;
|
||||
const char *name;
|
||||
if ((sym = DisFindSym(b.dis, addr)) != -1 && b.dis->syms.p[sym].name) {
|
||||
addend = addr - b.dis->syms.p[sym].addr;
|
||||
name = b.dis->syms.stab + b.dis->syms.p[sym].name;
|
||||
p = stpcpy(p, name);
|
||||
if ((sym = DisFindSym(d, addr)) != -1 && d->syms.p[sym].name) {
|
||||
addend = addr - d->syms.p[sym].addr;
|
||||
name = d->syms.stab + d->syms.p[sym].name;
|
||||
p = Demangle(p, name);
|
||||
if (addend) {
|
||||
*p++ = '+';
|
||||
p = DisInt(p, addend);
|
||||
|
@ -124,79 +124,69 @@ static char *DisSym(struct DisBuilder b, char *p, int64_t addr) {
|
|||
}
|
||||
}
|
||||
|
||||
static char *DisSymLiteral(struct DisBuilder b, char *p, uint64_t x) {
|
||||
static char *DisSymLiteral(struct Dis *d, 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);
|
||||
p = HighStart(p, g_high.literal);
|
||||
p = DisSym(d, p, x);
|
||||
p = HighEnd(p);
|
||||
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 Dis *d, uint32_t rde, char *p) {
|
||||
return DisRegisterWord(d, rde, p, Rexr(rde), ModrmReg(rde));
|
||||
}
|
||||
|
||||
static char *DisGvqp(struct DisBuilder b, uint32_t rde, char *p) {
|
||||
return DisRegisterWord(b, rde, p, Rexr(rde), ModrmReg(rde));
|
||||
static char *DisGdqp(struct Dis *d, uint32_t rde, char *p) {
|
||||
return DisRegister(p, kGreg[0][Rexw(rde)][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 Dis *d, uint32_t rde, char *p) {
|
||||
return DisRegisterByte(d, rde, p, 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) {
|
||||
static char *DisSego(struct Dis *d, uint32_t rde, char *p) {
|
||||
int seg;
|
||||
seg = Sego(rde) ? Sego(rde) : b.xedd->op.hint;
|
||||
seg = Sego(rde) ? Sego(rde) : d->xedd->op.hint;
|
||||
if (seg) {
|
||||
p = DisRegister(p, kSegName[seg - 1]);
|
||||
p = DisRegister(p, kSeg[seg - 1]);
|
||||
*p++ = ':';
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
static char *DisM(struct DisBuilder b, uint32_t rde, char *p) {
|
||||
static char *DisM(struct Dis *d, uint32_t rde, char *p) {
|
||||
int64_t disp;
|
||||
const char *base, *index, *scale;
|
||||
p = DisSego(b, rde, p);
|
||||
p = DisSego(d, 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(rde)) disp = RipRelative(b, disp);
|
||||
p = DisSym(b, p, disp);
|
||||
SibBase(d->xedd) == 0b101)) {
|
||||
disp = d->xedd->op.disp;
|
||||
if (IsRipRelative(rde)) disp = RipRelative(d, disp);
|
||||
p = DisSym(d, p, disp);
|
||||
}
|
||||
if (Eamode(rde) != XED_MODE_REAL) {
|
||||
if (!SibExists(rde)) {
|
||||
DCHECK(!b.xedd->op.has_sib);
|
||||
DCHECK(!d->xedd->op.has_sib);
|
||||
if (IsRipRelative(rde)) {
|
||||
if (Mode(rde) == XED_MODE_LONG) {
|
||||
base = kPuttingOnTheRip[Eamode(rde) == XED_MODE_LONG];
|
||||
base = kRip[Eamode(rde) == XED_MODE_LONG];
|
||||
}
|
||||
} else {
|
||||
base = GetAddrReg(b, rde, Rexb(rde), ModrmRm(rde));
|
||||
base = GetAddrReg(d, 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));
|
||||
} else if (!SibIsAbsolute(d->xedd, rde)) {
|
||||
if (SibHasBase(d->xedd, rde)) {
|
||||
base = GetAddrReg(d, rde, Rexb(rde), SibBase(d->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];
|
||||
if (SibHasIndex(d->xedd)) {
|
||||
index = GetAddrReg(d, rde, Rexx(d->xedd), SibIndex(d->xedd));
|
||||
} else if (d->xedd->op.scale) {
|
||||
index = kRiz[Eamode(rde) == XED_MODE_LONG];
|
||||
}
|
||||
scale = kScale[b.xedd->op.scale];
|
||||
scale = kSka[d->xedd->op.scale];
|
||||
}
|
||||
} else {
|
||||
switch (ModrmRm(rde)) {
|
||||
|
@ -250,206 +240,235 @@ static char *DisM(struct DisBuilder b, uint32_t rde, char *p) {
|
|||
return p;
|
||||
}
|
||||
|
||||
static char *DisEb(struct DisBuilder b, uint32_t rde, char *p) {
|
||||
static char *DisRegMem(struct Dis *d, uint32_t rde, char *p,
|
||||
char *f(struct Dis *, uint32_t, char *)) {
|
||||
if (IsModrmRegister(rde)) {
|
||||
return DisRegisterByte(b, rde, p, Rexb(rde), ModrmRm(rde));
|
||||
return f(d, rde, p);
|
||||
} else {
|
||||
return DisM(b, rde, p);
|
||||
return DisM(d, rde, p);
|
||||
}
|
||||
}
|
||||
|
||||
static char *DisEvqp(struct DisBuilder b, uint32_t rde, char *p) {
|
||||
static noinline char *DisE(struct Dis *d, uint32_t rde, char *p,
|
||||
char *f(struct Dis *, uint32_t, char *, bool, int)) {
|
||||
if (IsModrmRegister(rde)) {
|
||||
return DisRegisterWord(b, rde, p, Rexb(rde), ModrmRm(rde));
|
||||
return f(d, rde, p, Rexb(rde), ModrmRm(rde));
|
||||
} else {
|
||||
return DisM(b, rde, p);
|
||||
return DisM(d, rde, p);
|
||||
}
|
||||
}
|
||||
|
||||
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, rde, p);
|
||||
}
|
||||
static char *DisEb(struct Dis *d, uint32_t rde, char *p) {
|
||||
return DisE(d, rde, p, DisRegisterByte);
|
||||
}
|
||||
|
||||
static char *DisEv(struct DisBuilder b, uint32_t rde, char *p) {
|
||||
const char *s;
|
||||
if (IsModrmRegister(rde)) {
|
||||
return DisRegister(p, kRegisterName[Osz(rde)][0][Rexb(rde)][ModrmRm(rde)]);
|
||||
} else {
|
||||
return DisM(b, rde, p);
|
||||
}
|
||||
static char *DisEvqp(struct Dis *d, uint32_t rde, char *p) {
|
||||
return DisE(d, rde, p, DisRegisterWord);
|
||||
}
|
||||
|
||||
static char *DisGvq(struct DisBuilder b, uint32_t rde, char *p, int r) {
|
||||
static char *DisEdqpReg(struct Dis *d, uint32_t rde, char *p) {
|
||||
return DisRegister(p, kGreg[0][Rexw(rde)][Rexb(rde)][ModrmRm(rde)]);
|
||||
}
|
||||
|
||||
static char *DisEdqp(struct Dis *d, uint32_t rde, char *p) {
|
||||
return DisRegMem(d, rde, p, DisEdqpReg);
|
||||
}
|
||||
|
||||
static char *DisEvReg(struct Dis *d, uint32_t rde, char *p) {
|
||||
return DisRegister(p, kGreg[Osz(rde)][0][Rexb(rde)][ModrmRm(rde)]);
|
||||
}
|
||||
|
||||
static char *DisEv(struct Dis *d, uint32_t rde, char *p) {
|
||||
return DisRegMem(d, rde, p, DisEvReg);
|
||||
}
|
||||
|
||||
static char *DisGvq(struct Dis *d, 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];
|
||||
s = kGreg[Osz(rde)][!Osz(rde)][Rexb(rde)][r];
|
||||
} else {
|
||||
s = kRegisterName[Osz(rde)][0][Rexb(rde)][r];
|
||||
s = kGreg[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 *DisZvq(struct Dis *d, uint32_t rde, char *p) {
|
||||
return DisGvq(d, 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));
|
||||
static char *DisEvqReg(struct Dis *d, uint32_t rde, char *p) {
|
||||
return DisGvq(d, rde, p, ModrmRm(rde));
|
||||
}
|
||||
|
||||
static char *DisEvq(struct Dis *d, uint32_t rde, char *p) {
|
||||
return DisRegMem(d, rde, p, DisEvqReg);
|
||||
}
|
||||
|
||||
static char *DisEdReg(struct Dis *d, uint32_t rde, char *p) {
|
||||
return DisRegister(p, kGreg[0][0][Rexb(rde)][ModrmRm(rde)]);
|
||||
}
|
||||
|
||||
static char *DisEd(struct Dis *d, uint32_t rde, char *p) {
|
||||
return DisRegMem(d, rde, p, DisEdReg);
|
||||
}
|
||||
|
||||
static char *DisEqReg(struct Dis *d, uint32_t rde, char *p) {
|
||||
const char *r;
|
||||
if (Mode(rde) == XED_MODE_LONG) {
|
||||
r = kGreg[0][1][Rexb(rde)][ModrmRm(rde)];
|
||||
} else {
|
||||
return DisM(b, rde, p);
|
||||
r = kGreg[Osz(rde)][0][Rexb(rde)][ModrmRm(rde)];
|
||||
}
|
||||
return DisRegister(p, r);
|
||||
}
|
||||
|
||||
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, rde, p);
|
||||
}
|
||||
static char *DisEq(struct Dis *d, uint32_t rde, char *p) {
|
||||
return DisRegMem(d, rde, p, DisEqReg);
|
||||
}
|
||||
|
||||
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 DisM(b, rde, p);
|
||||
}
|
||||
static char *DisZvqp(struct Dis *d, uint32_t rde, char *p) {
|
||||
return DisRegisterWord(d, rde, p, Rexb(rde), ModrmSrm(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 Dis *d, uint32_t rde, char *p) {
|
||||
return DisRegisterByte(d, rde, p, Rexb(rde), ModrmSrm(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 Dis *d, uint32_t rde, char *p) {
|
||||
return DisRegister(p, kGreg[Osz(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 Dis *d, uint32_t rde, char *p) {
|
||||
return DisRegister(p, kGreg[Osz(rde)][Rexw(rde)][0][0]);
|
||||
}
|
||||
|
||||
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 Dis *d, uint32_t rde, char *p) {
|
||||
return DisRegister(p, kGreg[Osz(rde)][Rexw(rde)][0][2]);
|
||||
}
|
||||
|
||||
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 Dis *d, uint32_t rde, char *p) {
|
||||
return DisRegister(p, kCtl[ModrmReg(rde)]);
|
||||
}
|
||||
|
||||
static char *DisCd(struct DisBuilder b, uint32_t rde, char *p) {
|
||||
return DisRegister(p, kControlName[ModrmReg(rde)]);
|
||||
static char *DisHd(struct Dis *d, uint32_t rde, char *p) {
|
||||
return DisRegister(p, kGreg[0][Mode(rde) == XED_MODE_LONG][0][ModrmRm(rde)]);
|
||||
}
|
||||
|
||||
static char *DisHd(struct DisBuilder b, uint32_t rde, char *p) {
|
||||
return DisRegister(
|
||||
p, kRegisterName[0][Mode(rde) == XED_MODE_LONG][0][ModrmRm(rde)]);
|
||||
static char *DisImm(struct Dis *d, uint32_t rde, char *p) {
|
||||
return DisSymLiteral(d, p, d->xedd->op.uimm0);
|
||||
}
|
||||
|
||||
static char *DisImm(struct DisBuilder b, uint32_t rde, char *p) {
|
||||
return DisSymLiteral(b, p, b.xedd->op.uimm0);
|
||||
static char *DisRvds(struct Dis *d, uint32_t rde, char *p) {
|
||||
return DisSymLiteral(d, p, d->xedd->op.disp);
|
||||
}
|
||||
|
||||
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) {
|
||||
static char *DisKpvds(struct Dis *d, uint32_t rde, char *p, uint64_t x) {
|
||||
*p++ = '$';
|
||||
if (g_dis_high) p = DisHigh(p, g_dis_high->literal);
|
||||
p = DisInt(p, b.xedd->op.uimm0);
|
||||
if (g_dis_high) p = DisHigh(p, -1);
|
||||
p = HighStart(p, g_high.literal);
|
||||
p = DisInt(p, x);
|
||||
p = HighEnd(p);
|
||||
return p;
|
||||
}
|
||||
|
||||
static char *DisOne(struct DisBuilder b, uint32_t rde, char *p) {
|
||||
static char *DisKvds(struct Dis *d, uint32_t rde, char *p) {
|
||||
return DisKpvds(d, rde, p, d->xedd->op.uimm0);
|
||||
}
|
||||
|
||||
static char *DisPvds(struct Dis *d, uint32_t rde, char *p) {
|
||||
return DisKpvds(d, rde, p,
|
||||
d->xedd->op.disp & (Osz(rde) ? 0xffff : 0xffffffff));
|
||||
}
|
||||
|
||||
static char *DisOne(struct Dis *d, uint32_t rde, char *p) {
|
||||
*p++ = '$';
|
||||
if (g_dis_high) p = DisHigh(p, g_dis_high->literal);
|
||||
p = HighStart(p, g_high.literal);
|
||||
p = stpcpy(p, "1");
|
||||
if (g_dis_high) p = DisHigh(p, -1);
|
||||
p = HighEnd(p);
|
||||
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);
|
||||
static char *DisJbs(struct Dis *d, uint32_t rde, char *p) {
|
||||
if (d->xedd->op.disp > 0) *p++ = '+';
|
||||
p += int64toarray_radix10(d->xedd->op.disp, p);
|
||||
return 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);
|
||||
static char *DisJb(struct Dis *d, uint32_t rde, char *p) {
|
||||
if (d->xedd->op.disp > 0) *p++ = '+';
|
||||
p += uint64toarray_radix10(d->xedd->op.disp & 0xff, p);
|
||||
return p;
|
||||
}
|
||||
|
||||
static char *DisJvds(struct DisBuilder b, uint32_t rde, char *p) {
|
||||
return DisSym(b, p, RipRelative(b, b.xedd->op.disp));
|
||||
static char *DisJvds(struct Dis *d, uint32_t rde, char *p) {
|
||||
return DisSym(d, p, RipRelative(d, d->xedd->op.disp));
|
||||
}
|
||||
|
||||
static char *DisAbs(struct DisBuilder b, uint32_t rde, char *p) {
|
||||
return DisSym(b, p, b.xedd->op.disp);
|
||||
static char *DisAbs(struct Dis *d, uint32_t rde, char *p) {
|
||||
return DisSym(d, p, d->xedd->op.disp);
|
||||
}
|
||||
|
||||
static char *DisSw(struct DisBuilder b, uint32_t rde, char *p) {
|
||||
if (kSegName[ModrmReg(rde)][0]) p = DisRegister(p, kSegName[ModrmReg(rde)]);
|
||||
static char *DisSw(struct Dis *d, uint32_t rde, char *p) {
|
||||
if (kSeg[ModrmReg(rde)][0]) p = DisRegister(p, kSeg[ModrmReg(rde)]);
|
||||
return p;
|
||||
}
|
||||
|
||||
static char *DisSpecialAddr(struct DisBuilder b, uint32_t rde, char *p, int r) {
|
||||
static char *DisSpecialAddr(struct Dis *d, uint32_t rde, char *p, int r) {
|
||||
*p++ = '(';
|
||||
p = DisRegister(p, GetAddrReg(b, rde, 0, r));
|
||||
p = DisRegister(p, GetAddrReg(d, rde, 0, r));
|
||||
*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 *DisY(struct Dis *d, uint32_t rde, char *p) {
|
||||
return DisSpecialAddr(d, rde, p, 7); // es:di
|
||||
}
|
||||
|
||||
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 *DisX(struct Dis *d, uint32_t rde, char *p) {
|
||||
DisSego(d, rde, p);
|
||||
return DisSpecialAddr(d, rde, p, 6); // ds:si
|
||||
}
|
||||
|
||||
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 *DisBBb(struct Dis *d, uint32_t rde, char *p) {
|
||||
DisSego(d, rde, p);
|
||||
return DisSpecialAddr(d, rde, p, 3); // ds:bx
|
||||
}
|
||||
|
||||
static char *DisNq(struct DisBuilder b, uint32_t rde, char *p) {
|
||||
return DisXmm(b, rde, p, "mm", ModrmRm(rde));
|
||||
static char *DisXmm(struct Dis *d, uint32_t rde, char *p, const char *s,
|
||||
int reg) {
|
||||
p = HighStart(p, g_high.reg);
|
||||
*p++ = '%';
|
||||
p = stpcpy(p, s);
|
||||
p += uint64toarray_radix10(reg, p);
|
||||
p = HighEnd(p);
|
||||
return p;
|
||||
}
|
||||
|
||||
static char *DisUq(struct DisBuilder b, uint32_t rde, char *p) {
|
||||
return DisXmm(b, rde, p, "mm", ModrmRm(rde));
|
||||
static char *DisNq(struct Dis *d, uint32_t rde, char *p) {
|
||||
return DisXmm(d, rde, p, "mm", ModrmRm(rde));
|
||||
}
|
||||
|
||||
static char *DisPq(struct DisBuilder b, uint32_t rde, char *p) {
|
||||
return DisXmm(b, rde, p, "mm", ModrmReg(rde));
|
||||
static char *DisPq(struct Dis *d, uint32_t rde, char *p) {
|
||||
return DisXmm(d, rde, p, "mm", ModrmReg(rde));
|
||||
}
|
||||
|
||||
static char *DisUdq(struct DisBuilder b, uint32_t rde, char *p) {
|
||||
return DisXmm(b, rde, p, "xmm", ModrmRm(rde));
|
||||
static char *DisUq(struct Dis *d, uint32_t rde, char *p) {
|
||||
return DisXmm(d, rde, p, "xmm", RexbRm(rde));
|
||||
}
|
||||
|
||||
static char *DisVdq(struct DisBuilder b, uint32_t rde, char *p) {
|
||||
return DisXmm(b, rde, p, "xmm", ModrmReg(rde));
|
||||
static char *DisUdq(struct Dis *d, uint32_t rde, char *p) {
|
||||
return DisXmm(d, rde, p, "xmm", RexbRm(rde));
|
||||
}
|
||||
|
||||
static char *DisQq(struct DisBuilder b, uint32_t rde, char *p) {
|
||||
if (IsModrmRegister(rde)) {
|
||||
return DisNq(b, rde, p);
|
||||
} else {
|
||||
return DisM(b, rde, p);
|
||||
}
|
||||
static char *DisVdq(struct Dis *d, uint32_t rde, char *p) {
|
||||
return DisXmm(d, rde, p, "xmm", RexrReg(rde));
|
||||
}
|
||||
|
||||
static char *DisEst(struct DisBuilder b, uint32_t rde, char *p) {
|
||||
static char *DisQq(struct Dis *d, uint32_t rde, char *p) {
|
||||
return DisRegMem(d, rde, p, DisNq);
|
||||
}
|
||||
|
||||
static char *DisEst(struct Dis *d, uint32_t rde, char *p) {
|
||||
p = DisRegister(p, "st");
|
||||
if (ModrmRm(rde) != 0) {
|
||||
*p++ = '(';
|
||||
|
@ -460,29 +479,21 @@ static char *DisEst(struct DisBuilder b, uint32_t rde, char *p) {
|
|||
return p;
|
||||
}
|
||||
|
||||
static char *DisEst1(struct DisBuilder b, uint32_t rde, char *p) {
|
||||
static char *DisEst1(struct Dis *d, uint32_t rde, char *p) {
|
||||
if (ModrmRm(rde) != 1) {
|
||||
p = DisEst(b, rde, p);
|
||||
p = DisEst(d, rde, p);
|
||||
} else {
|
||||
*p = '\0';
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
static char *DisEssr(struct DisBuilder b, uint32_t rde, char *p) {
|
||||
if (IsModrmRegister(rde)) {
|
||||
return DisEst(b, rde, p);
|
||||
} else {
|
||||
return DisM(b, rde, p);
|
||||
}
|
||||
static char *DisEssr(struct Dis *d, uint32_t rde, char *p) {
|
||||
return DisRegMem(d, rde, p, DisEst);
|
||||
}
|
||||
|
||||
static char *DisWps(struct DisBuilder b, uint32_t rde, char *p) {
|
||||
if (IsModrmRegister(rde)) {
|
||||
return DisUdq(b, rde, p);
|
||||
} else {
|
||||
return DisM(b, rde, p);
|
||||
}
|
||||
static char *DisWps(struct Dis *d, uint32_t rde, char *p) {
|
||||
return DisRegMem(d, rde, p, DisUdq);
|
||||
}
|
||||
|
||||
#define DisEdr DisM
|
||||
|
@ -537,7 +548,7 @@ static char *DisWps(struct DisBuilder b, uint32_t rde, char *p) {
|
|||
|
||||
static const struct DisArg {
|
||||
char s[8];
|
||||
char *(*f)(struct DisBuilder, uint32_t, char *);
|
||||
char *(*f)(struct Dis *, uint32_t, char *);
|
||||
} kDisArgs[] = /* <sorted> */ {
|
||||
{"$1", DisOne}, //
|
||||
{"%Cd", DisCd}, //
|
||||
|
@ -610,6 +621,7 @@ static const struct DisArg {
|
|||
{"Mwi", DisMwi}, //
|
||||
{"Ob", DisOb}, //
|
||||
{"Ovqp", DisOvqp}, //
|
||||
{"Pvds", DisPvds}, //
|
||||
{"Qpi", DisQpi}, //
|
||||
{"Qq", DisQq}, //
|
||||
{"Rvds", DisRvds}, //
|
||||
|
@ -635,7 +647,7 @@ static int CompareString8(const char a[8], const char b[8]) {
|
|||
return x > y ? 1 : x < y ? -1 : 0;
|
||||
}
|
||||
|
||||
char *DisArg(struct DisBuilder b, char *p, const char *s) {
|
||||
char *DisArg(struct Dis *d, char *p, const char *s) {
|
||||
char key[8];
|
||||
int c, m, l, r;
|
||||
l = 0;
|
||||
|
@ -649,7 +661,7 @@ char *DisArg(struct DisBuilder b, char *p, const char *s) {
|
|||
} else if (c > 0) {
|
||||
r = m - 1;
|
||||
} else {
|
||||
return kDisArgs[m].f(b, b.xedd->op.rde, p);
|
||||
return kDisArgs[m].f(d, d->xedd->op.rde, p);
|
||||
}
|
||||
}
|
||||
if (*s == '%') {
|
||||
|
|
|
@ -115,31 +115,33 @@ bool DisIsText(struct Dis *d, int64_t addr) {
|
|||
|
||||
long DisFindSym(struct Dis *d, int64_t addr) {
|
||||
size_t i, l, r, m, n;
|
||||
if (DisIsProg(d, addr)) {
|
||||
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;
|
||||
if (d->syms.p) {
|
||||
if (DisIsProg(d, addr)) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
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;
|
||||
if (d->syms.p[l].addr == addr) {
|
||||
return l;
|
||||
}
|
||||
}
|
||||
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;
|
||||
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 (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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include "libc/nexgen32e/tinystrcmp.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "tool/build/lib/dis.h"
|
||||
#include "tool/build/lib/high.h"
|
||||
#include "tool/build/lib/modrm.h"
|
||||
|
||||
static const char kJcxz[3][6] = {"jcxz", "jecxz", "jrcxz"};
|
||||
|
@ -28,43 +29,45 @@ static const char kAluOp[8][4] = {"add", "or", "adc", "sbb",
|
|||
"and", "sub", "xor", "cmp"};
|
||||
static const char kBitOp[8][4] = {"rol", "ror", "rcl", "rcr",
|
||||
"shl", "shr", "sal", "sar"};
|
||||
static const char kCc[16][3] = {"o", "no", "b", "ae", "e", "ne", "be", "a",
|
||||
"s", "ns", "p", "np", "l", "ge", "le", "g"};
|
||||
|
||||
static bool IsProbablyByteOp(struct XedDecodedInst *x) {
|
||||
return !(x->op.opcode & 1);
|
||||
}
|
||||
|
||||
static int IsRepOpcode(struct DisBuilder b) {
|
||||
switch (b.xedd->op.opcode & ~1) {
|
||||
case 0x6C: /* INS */
|
||||
static int IsRepOpcode(struct Dis *d) {
|
||||
switch (d->xedd->op.opcode & ~1) {
|
||||
case 0x6C: // INS
|
||||
return 1;
|
||||
case 0x6E: /* OUTS */
|
||||
case 0x6E: // OUTS
|
||||
return 1;
|
||||
case 0xA4: /* MOVS */
|
||||
case 0xA4: // MOVS
|
||||
return 1;
|
||||
case 0xAA: /* STOS */
|
||||
case 0xAA: // STOS
|
||||
return 1;
|
||||
case 0xAC: /* LODS */
|
||||
case 0xAC: // LODS
|
||||
return 1;
|
||||
case 0xA6: /* CMPS */
|
||||
case 0xA6: // CMPS
|
||||
return 2;
|
||||
case 0xAE: /* SCAS */
|
||||
case 0xAE: // SCAS
|
||||
return 2;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static char *DisRepPrefix(struct DisBuilder b, char *p) {
|
||||
static char *DisRepPrefix(struct Dis *d, char *p) {
|
||||
const char *s;
|
||||
if (Rep(b.xedd->op.rde) && b.xedd->op.map == XED_ILD_MAP0) {
|
||||
switch (IsRepOpcode(b)) {
|
||||
if (Rep(d->xedd->op.rde) && d->xedd->op.map == XED_ILD_MAP0) {
|
||||
switch (IsRepOpcode(d)) {
|
||||
case 0:
|
||||
break;
|
||||
case 1:
|
||||
p = stpcpy(p, "rep ");
|
||||
break;
|
||||
case 2:
|
||||
p = stpcpy(p, Rep(b.xedd->op.rde) == 2 ? "repnz " : "repz ");
|
||||
p = stpcpy(p, Rep(d->xedd->op.rde) == 2 ? "repnz " : "repz ");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
@ -73,8 +76,8 @@ static char *DisRepPrefix(struct DisBuilder b, char *p) {
|
|||
return p;
|
||||
}
|
||||
|
||||
static char *DisBranchTaken(struct DisBuilder b, char *p) {
|
||||
switch (b.xedd->op.hint) {
|
||||
static char *DisBranchTaken(struct Dis *d, char *p) {
|
||||
switch (d->xedd->op.hint) {
|
||||
case XED_HINT_NTAKEN:
|
||||
return stpcpy(p, ",pn");
|
||||
case XED_HINT_TAKEN:
|
||||
|
@ -84,24 +87,26 @@ static char *DisBranchTaken(struct DisBuilder b, char *p) {
|
|||
}
|
||||
}
|
||||
|
||||
static char *DisName(struct DisBuilder b, char *bp, const char *name,
|
||||
static char *DisName(struct Dis *d, 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);
|
||||
rde = d->xedd->op.rde;
|
||||
if (d->xedd->op.lock) p = stpcpy(p, "lock ");
|
||||
p = DisRepPrefix(d, p);
|
||||
if (tinystrcmp(name, "BIT") == 0) {
|
||||
p = stpcpy(p, kBitOp[ModrmReg(rde)]);
|
||||
} else if (tinystrcmp(name, "nop") == 0 && d->xedd->op.rep) {
|
||||
p = stpcpy(p, "pause");
|
||||
} 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, kJcxz[Eamode(rde)]);
|
||||
p = DisBranchTaken(b, p);
|
||||
p = DisBranchTaken(d, p);
|
||||
} else if (tinystrcmp(name, "loop") == 0 || tinystrcmp(name, "loope") == 0 ||
|
||||
tinystrcmp(name, "loopne") == 0) {
|
||||
p = stpcpy(p, name);
|
||||
|
@ -109,7 +114,7 @@ static char *DisName(struct DisBuilder b, char *bp, const char *name,
|
|||
*p++ = "wl"[Eamode(rde)];
|
||||
*p = '\0';
|
||||
}
|
||||
p = DisBranchTaken(b, p);
|
||||
p = DisBranchTaken(d, p);
|
||||
} else if (tinystrcmp(name, "cwtl") == 0) {
|
||||
if (Osz(rde)) name = "cbtw";
|
||||
if (Rexw(rde)) name = "cltq";
|
||||
|
@ -127,10 +132,15 @@ static char *DisName(struct DisBuilder b, char *bp, const char *name,
|
|||
*p++ = *np;
|
||||
}
|
||||
if (tinystrcmp(name, "ALU") == 0) {
|
||||
p = stpcpy(p, kAluOp[(d->xedd->op.opcode & 070) >> 3]);
|
||||
} else if (tinystrcmp(name, "ALU2") == 0) {
|
||||
p = stpcpy(p, kAluOp[ModrmReg(rde)]);
|
||||
} else if (tinystrcmp(np, "WLQ") == 0) {
|
||||
notbyte = true;
|
||||
wantsuffix = true;
|
||||
} else if (tinystrcmp(np, "CC") == 0) {
|
||||
p = stpcpy(p, kCc[d->xedd->op.opcode & 15]);
|
||||
p = DisBranchTaken(d, p);
|
||||
} else if (tinystrcmp(np, "WQ") == 0) {
|
||||
notbyte = true;
|
||||
notlong = Eamode(rde) != XED_MODE_REAL;
|
||||
|
@ -143,8 +153,6 @@ static char *DisName(struct DisBuilder b, char *bp, const char *name,
|
|||
wantsuffixsd = true;
|
||||
} else if (tinystrcmp(np, "ABS") == 0) {
|
||||
if (Rexw(rde)) p = stpcpy(p, "abs");
|
||||
} else if (tinystrcmp(np, "BT") == 0) {
|
||||
p = DisBranchTaken(b, p);
|
||||
}
|
||||
if (wantsuffixsd) {
|
||||
if (Osz(rde)) {
|
||||
|
@ -155,12 +163,12 @@ static char *DisName(struct DisBuilder b, char *bp, const char *name,
|
|||
} else if (wantsuffix || (ambiguous && !startswith(name, "f") &&
|
||||
!startswith(name, "set"))) {
|
||||
if (Osz(rde)) {
|
||||
if (Eamode(rde) != XED_MODE_REAL) {
|
||||
if (Mode(rde) != XED_MODE_REAL) {
|
||||
*p++ = 'w';
|
||||
}
|
||||
} else if (Rexw(rde)) {
|
||||
*p++ = 'q';
|
||||
} else if (ambiguous && !notbyte && IsProbablyByteOp(b.xedd)) {
|
||||
} else if (ambiguous && !notbyte && IsProbablyByteOp(d->xedd)) {
|
||||
*p++ = 'b';
|
||||
} else if (!notlong) {
|
||||
*p++ = 'l';
|
||||
|
@ -177,28 +185,28 @@ static char *DisName(struct DisBuilder b, char *bp, const char *name,
|
|||
* Disassembles instruction based on string spec.
|
||||
* @see DisSpec()
|
||||
*/
|
||||
char *DisInst(struct DisBuilder b, char *p, const char *spec) {
|
||||
char *DisInst(struct Dis *d, char *p, const char *spec) {
|
||||
long i, n;
|
||||
char sbuf[256];
|
||||
char args[4][128];
|
||||
char sbuf[300];
|
||||
char args[4][300];
|
||||
char *s, *name, *state;
|
||||
bool hasarg, hasmodrm, hasregister, hasmemory;
|
||||
CHECK_EQ(0, (int)b.xedd->op.error);
|
||||
CHECK_EQ(0, (int)d->xedd->op.error);
|
||||
DCHECK_LT(strlen(spec), 128);
|
||||
hasarg = false;
|
||||
hasmodrm = b.xedd->op.has_modrm;
|
||||
hasmemory = hasmodrm && !IsModrmRegister(b.xedd->op.rde);
|
||||
hasregister = hasmodrm && IsModrmRegister(b.xedd->op.rde);
|
||||
hasmodrm = d->xedd->op.has_modrm;
|
||||
hasmemory = hasmodrm && !IsModrmRegister(d->xedd->op.rde);
|
||||
hasregister = hasmodrm && IsModrmRegister(d->xedd->op.rde);
|
||||
name = strtok_r(strcpy(sbuf, spec), " ", &state);
|
||||
for (n = 0; (s = strtok_r(NULL, " ", &state)); ++n) {
|
||||
hasarg = true;
|
||||
hasregister |= *s == '%';
|
||||
hasmemory |= *s == 'O';
|
||||
CHECK_LT(DisArg(b, args[n], s) - args[n], sizeof(args[n]));
|
||||
CHECK_LT(DisArg(d, args[n], s) - args[n], sizeof(args[n]));
|
||||
}
|
||||
if (g_dis_high) p = DisHigh(p, g_dis_high->keyword);
|
||||
p = DisName(b, p, name, hasarg && !hasregister && hasmemory);
|
||||
if (g_dis_high) p = DisHigh(p, -1);
|
||||
p = HighStart(p, g_high.keyword);
|
||||
p = DisName(d, p, name, hasarg && !hasregister && hasmemory);
|
||||
p = HighEnd(p);
|
||||
for (i = 0; i < n; ++i) {
|
||||
if (i && args[n - i][0]) {
|
||||
*p++ = ',';
|
||||
|
|
|
@ -36,12 +36,6 @@ static const char kFpuName[][8][8] = {
|
|||
{"fneni", "fndisi", "fnclex", "fninit", "fnsetpm"},
|
||||
};
|
||||
|
||||
char *DisOpFpu0(struct XedDecodedInst *x, int group) {
|
||||
const char *s;
|
||||
s = kFpuName[group][ModrmRm(x->op.rde)];
|
||||
return *s ? s : UNKNOWN;
|
||||
}
|
||||
|
||||
char *DisOpFpu1(struct XedDecodedInst *x, char *p, const char *extra) {
|
||||
stpcpy(stpcpy(p, kFpuName[0][ModrmReg(x->op.rde)]), extra);
|
||||
return p;
|
||||
|
@ -88,68 +82,88 @@ char *DisOpVpsWpsVssWssVpdWpdVsdWsd(struct XedDecodedInst *x, char *p,
|
|||
return p;
|
||||
}
|
||||
|
||||
const char *DisSpecFpu0(struct XedDecodedInst *x, int group) {
|
||||
const char *s;
|
||||
s = kFpuName[group][ModrmRm(x->op.rde)];
|
||||
return *s ? s : UNKNOWN;
|
||||
}
|
||||
|
||||
const char *DisSpecRegMem(struct XedDecodedInst *x, const char *a,
|
||||
const char *b) {
|
||||
if (IsModrmRegister(x->op.rde)) {
|
||||
return a;
|
||||
} else {
|
||||
return b;
|
||||
}
|
||||
}
|
||||
|
||||
const char *DisSpecRegMemFpu0(struct XedDecodedInst *x, int group,
|
||||
const char *b) {
|
||||
return DisSpecRegMem(x, DisSpecFpu0(x, group), b);
|
||||
}
|
||||
|
||||
const char *DisSpecMap0(struct XedDecodedInst *x, char *p) {
|
||||
switch (x->op.opcode & 0xff) {
|
||||
RCASE(0x00, "add Eb %Gb");
|
||||
RCASE(0x01, "add Evqp %Gvqp");
|
||||
RCASE(0x02, "add %Gb Eb");
|
||||
RCASE(0x03, "add %Gvqp Evqp");
|
||||
RCASE(0x04, "add %al Ib");
|
||||
RCASE(0x05, "add %rAX Ivds");
|
||||
RCASE(0x00, "ALU Eb %Gb");
|
||||
RCASE(0x01, "ALU Evqp %Gvqp");
|
||||
RCASE(0x02, "ALU %Gb Eb");
|
||||
RCASE(0x03, "ALU %Gvqp Evqp");
|
||||
RCASE(0x04, "ALU %al Ib");
|
||||
RCASE(0x05, "ALU %rAX Ivds");
|
||||
RCASE(0x06, "push %es");
|
||||
RCASE(0x07, "pop %es");
|
||||
RCASE(0x08, "or Eb %Gb");
|
||||
RCASE(0x09, "or Evqp %Gvqp");
|
||||
RCASE(0x0a, "or %Gb Eb");
|
||||
RCASE(0x0b, "or %Gvqp Evqp");
|
||||
RCASE(0x0c, "or %al Ib");
|
||||
RCASE(0x0d, "or %rAX Ivds");
|
||||
RCASE(0x08, "ALU Eb %Gb");
|
||||
RCASE(0x09, "ALU Evqp %Gvqp");
|
||||
RCASE(0x0a, "ALU %Gb Eb");
|
||||
RCASE(0x0b, "ALU %Gvqp Evqp");
|
||||
RCASE(0x0c, "ALU %al Ib");
|
||||
RCASE(0x0d, "ALU %rAX Ivds");
|
||||
RCASE(0x0e, "push %cs");
|
||||
RCASE(0x0f, "pop %cs");
|
||||
RCASE(0x10, "adc Eb %Gb");
|
||||
RCASE(0x11, "adc Evqp %Gvqp");
|
||||
RCASE(0x12, "adc %Gb Eb");
|
||||
RCASE(0x13, "adc %Gvqp Evqp");
|
||||
RCASE(0x14, "adc %al Ib");
|
||||
RCASE(0x15, "adc %rAX Ivds");
|
||||
RCASE(0x10, "ALU Eb %Gb");
|
||||
RCASE(0x11, "ALU Evqp %Gvqp");
|
||||
RCASE(0x12, "ALU %Gb Eb");
|
||||
RCASE(0x13, "ALU %Gvqp Evqp");
|
||||
RCASE(0x14, "ALU %al Ib");
|
||||
RCASE(0x15, "ALU %rAX Ivds");
|
||||
RCASE(0x16, "push %ss");
|
||||
RCASE(0x17, "pop %ss");
|
||||
RCASE(0x18, "sbb Eb %Gb");
|
||||
RCASE(0x19, "sbb Evqp %Gvqp");
|
||||
RCASE(0x1a, "sbb %Gb Eb");
|
||||
RCASE(0x1b, "sbb %Gvqp Evqp");
|
||||
RCASE(0x1c, "sbb %al Ib");
|
||||
RCASE(0x1d, "sbb %rAX Ivds");
|
||||
RCASE(0x18, "ALU Eb %Gb");
|
||||
RCASE(0x19, "ALU Evqp %Gvqp");
|
||||
RCASE(0x1a, "ALU %Gb Eb");
|
||||
RCASE(0x1b, "ALU %Gvqp Evqp");
|
||||
RCASE(0x1c, "ALU %al Ib");
|
||||
RCASE(0x1d, "ALU %rAX Ivds");
|
||||
RCASE(0x1e, "push %ds");
|
||||
RCASE(0x1f, "pop %ds");
|
||||
RCASE(0x20, "and Eb %Gb");
|
||||
RCASE(0x21, "and Evqp %Gvqp");
|
||||
RCASE(0x22, "and %Gb Eb");
|
||||
RCASE(0x23, "and %Gvqp Evqp");
|
||||
RCASE(0x24, "and %al Ib");
|
||||
RCASE(0x25, "and %rAX Ivds");
|
||||
RCASE(0x20, "ALU Eb %Gb");
|
||||
RCASE(0x21, "ALU Evqp %Gvqp");
|
||||
RCASE(0x22, "ALU %Gb Eb");
|
||||
RCASE(0x23, "ALU %Gvqp Evqp");
|
||||
RCASE(0x24, "ALU %al Ib");
|
||||
RCASE(0x25, "ALU %rAX Ivds");
|
||||
RCASE(0x26, "push %es");
|
||||
RCASE(0x27, "pop %es");
|
||||
RCASE(0x28, "sub Eb %Gb");
|
||||
RCASE(0x29, "sub Evqp %Gvqp");
|
||||
RCASE(0x28, "ALU Eb %Gb");
|
||||
RCASE(0x29, "ALU Evqp %Gvqp");
|
||||
RCASE(0x2a, "ALU %Gb Eb");
|
||||
RCASE(0x2b, "ALU %Gvqp Evqp");
|
||||
RCASE(0x2c, "ALU %al Ib");
|
||||
RCASE(0x2d, "ALU %rAX Ivds");
|
||||
RCASE(0x2F, "das");
|
||||
RCASE(0x2a, "sub %Gb Eb");
|
||||
RCASE(0x2b, "sub %Gvqp Evqp");
|
||||
RCASE(0x2c, "sub %al Ib");
|
||||
RCASE(0x2d, "sub %rAX Ivds");
|
||||
RCASE(0x30, "xor Eb %Gb");
|
||||
RCASE(0x31, "xor Evqp %Gvqp");
|
||||
RCASE(0x32, "xor %Gb Eb");
|
||||
RCASE(0x33, "xor %Gvqp Evqp");
|
||||
RCASE(0x34, "xor %al Ib");
|
||||
RCASE(0x35, "xor %rAX Ivds");
|
||||
RCASE(0x30, "ALU Eb %Gb");
|
||||
RCASE(0x31, "ALU Evqp %Gvqp");
|
||||
RCASE(0x32, "ALU %Gb Eb");
|
||||
RCASE(0x33, "ALU %Gvqp Evqp");
|
||||
RCASE(0x34, "ALU %al Ib");
|
||||
RCASE(0x35, "ALU %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(0x38, "ALU Eb %Gb");
|
||||
RCASE(0x39, "ALU Evqp %Gvqp");
|
||||
RCASE(0x3A, "ALU %Gb Eb");
|
||||
RCASE(0x3B, "ALU %Gvqp Evqp");
|
||||
RCASE(0x3C, "ALU %al Ib");
|
||||
RCASE(0x3D, "ALU %rAX Ivds");
|
||||
RCASE(0x3F, "aas");
|
||||
RCASE(0x40 ... 0x47, "inc %Zv");
|
||||
RCASE(0x48 ... 0x4f, "dec %Zv");
|
||||
|
@ -167,26 +181,11 @@ const char *DisSpecMap0(struct XedDecodedInst *x, char *p) {
|
|||
RCASE(0x6D, "insWL Yv %dx");
|
||||
RCASE(0x6E, "outsb %dx Xb");
|
||||
RCASE(0x6F, "outsWL %dx Xv");
|
||||
RCASE(0x70, "joBT Jbs");
|
||||
RCASE(0x71, "jnoBT Jbs");
|
||||
RCASE(0x72, "jbBT Jbs");
|
||||
RCASE(0x73, "jaeBT Jbs");
|
||||
RCASE(0x74, "jeBT Jbs");
|
||||
RCASE(0x75, "jneBT Jbs");
|
||||
RCASE(0x76, "jbeBT Jbs");
|
||||
RCASE(0x77, "jaBT Jbs");
|
||||
RCASE(0x78, "jsBT Jbs");
|
||||
RCASE(0x79, "jnsBT Jbs");
|
||||
RCASE(0x7a, "jpBT Jbs");
|
||||
RCASE(0x7b, "jnpBT Jbs");
|
||||
RCASE(0x7c, "jlBT Jbs");
|
||||
RCASE(0x7d, "jgeBT Jbs");
|
||||
RCASE(0x7e, "jleBT Jbs");
|
||||
RCASE(0x7f, "jgBT Jbs");
|
||||
RCASE(0x80, "ALU Eb Ib");
|
||||
RCASE(0x81, "ALU Evqp Ivds");
|
||||
RCASE(0x82, "ALU Eb Ib");
|
||||
RCASE(0x83, "ALU Evqp Ibs");
|
||||
RCASE(0x70 ... 0x7f, "jCC Jbs");
|
||||
RCASE(0x80, "ALU2 Eb Ib");
|
||||
RCASE(0x81, "ALU2 Evqp Ivds");
|
||||
RCASE(0x82, "ALU2 Eb Ib");
|
||||
RCASE(0x83, "ALU2 Evqp Ibs");
|
||||
RCASE(0x84, "test Eb %Gb");
|
||||
RCASE(0x85, "test %Gvqp Evqp");
|
||||
RCASE(0x86, "xchg %Gb Eb");
|
||||
|
@ -202,6 +201,7 @@ const char *DisSpecMap0(struct XedDecodedInst *x, char *p) {
|
|||
RCASE(0x91 ... 0x97, "xchg %Zvqp %rAX");
|
||||
RCASE(0x98, "cwtl");
|
||||
RCASE(0x99, "cltd");
|
||||
RCASE(0x9A, "lcall Pvds Kvds");
|
||||
RCASE(0x9B, "fwait");
|
||||
RCASE(0x9C, "pushfWQ");
|
||||
RCASE(0x9D, "popfWQ");
|
||||
|
@ -234,6 +234,8 @@ const char *DisSpecMap0(struct XedDecodedInst *x, char *p) {
|
|||
RCASE(0xC6, "mov Eb Ib");
|
||||
RCASE(0xC7, "mov Evqp Ivds");
|
||||
RCASE(0xC9, "leave");
|
||||
RCASE(0xCA, "lret Iw");
|
||||
RCASE(0xCB, "lret");
|
||||
RCASE(0xCC, "int3");
|
||||
RCASE(0xCD, "int Ib");
|
||||
RCASE(0xD0, "BIT Eb $1");
|
||||
|
@ -280,163 +282,36 @@ const char *DisSpecMap0(struct XedDecodedInst *x, char *p) {
|
|||
switch (ModrmReg(x->op.rde)) {
|
||||
RCASE(1, "fxch EST1");
|
||||
RCASE(3, "fstps Msr %st");
|
||||
case 0:
|
||||
if (IsModrmRegister(x->op.rde)) {
|
||||
return "fld EST";
|
||||
} else {
|
||||
return "flds Msr";
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
if (IsModrmRegister(x->op.rde)) {
|
||||
return "fnop";
|
||||
} else {
|
||||
return "fsts Msr %st";
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
if (IsModrmRegister(x->op.rde)) {
|
||||
return DisOpFpu0(x, 1);
|
||||
} else {
|
||||
return "fldenv Me";
|
||||
}
|
||||
break;
|
||||
case 5:
|
||||
if (IsModrmRegister(x->op.rde)) {
|
||||
return DisOpFpu0(x, 2);
|
||||
} else {
|
||||
return "fldcw Mw";
|
||||
}
|
||||
break;
|
||||
case 6:
|
||||
if (IsModrmRegister(x->op.rde)) {
|
||||
return DisOpFpu0(x, 3);
|
||||
} else {
|
||||
return "fnstenv M";
|
||||
}
|
||||
break;
|
||||
case 7:
|
||||
if (IsModrmRegister(x->op.rde)) {
|
||||
return DisOpFpu0(x, 4);
|
||||
} else {
|
||||
return "fnstcw Mw";
|
||||
}
|
||||
break;
|
||||
RCASE(0, DisSpecRegMem(x, "fld EST", "flds Msr"));
|
||||
RCASE(2, DisSpecRegMem(x, "fnop", "fsts Msr %st"));
|
||||
RCASE(4, DisSpecRegMemFpu0(x, 1, "fldenv Me"));
|
||||
RCASE(5, DisSpecRegMemFpu0(x, 2, "fldcw Mw"));
|
||||
RCASE(6, DisSpecRegMemFpu0(x, 3, "fnstenv M"));
|
||||
RCASE(7, DisSpecRegMemFpu0(x, 4, "fnstcw Mw"));
|
||||
}
|
||||
break;
|
||||
case 0xDA:
|
||||
switch (ModrmReg(x->op.rde)) {
|
||||
case 0:
|
||||
if (!IsModrmRegister(x->op.rde)) {
|
||||
return "fiaddl Mdi";
|
||||
} else {
|
||||
return "fcmovb %st EST";
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
if (!IsModrmRegister(x->op.rde)) {
|
||||
return "fimull Mdi";
|
||||
} else {
|
||||
return "fcmove %st EST";
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
if (!IsModrmRegister(x->op.rde)) {
|
||||
return "ficoml Mdi";
|
||||
} else {
|
||||
return "fcmovbe %st EST";
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
if (!IsModrmRegister(x->op.rde)) {
|
||||
return "ficompl Mdi";
|
||||
} else {
|
||||
return "fcmovu %st EST";
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
if (!IsModrmRegister(x->op.rde)) {
|
||||
return "fisubl Mdi";
|
||||
} else {
|
||||
return "fisubr Mdi";
|
||||
}
|
||||
break;
|
||||
case 5:
|
||||
if (!IsModrmRegister(x->op.rde)) {
|
||||
return "fisubrl Mdi";
|
||||
} else {
|
||||
return "fucompp";
|
||||
}
|
||||
break;
|
||||
case 6:
|
||||
if (!IsModrmRegister(x->op.rde)) {
|
||||
return "fidivl Mdi";
|
||||
} else {
|
||||
return UNKNOWN;
|
||||
}
|
||||
break;
|
||||
case 7:
|
||||
if (!IsModrmRegister(x->op.rde)) {
|
||||
return "fidivrl Mdi";
|
||||
} else {
|
||||
return UNKNOWN;
|
||||
}
|
||||
break;
|
||||
RCASE(0, DisSpecRegMem(x, "fcmovb %st EST", "fiaddl Mdi"));
|
||||
RCASE(1, DisSpecRegMem(x, "fcmove %st EST", "fimull Mdi"));
|
||||
RCASE(2, DisSpecRegMem(x, "fcmovbe %st EST", "ficoml Mdi"));
|
||||
RCASE(3, DisSpecRegMem(x, "fcmovu %st EST", "ficompl Mdi"));
|
||||
RCASE(4, DisSpecRegMem(x, "fisubr Mdi", "fisubl Mdi"));
|
||||
RCASE(5, DisSpecRegMem(x, "fucompp", "fisubrl Mdi"));
|
||||
RCASE(6, DisSpecRegMem(x, "fidivl Mdi", "UNKNOWN"));
|
||||
RCASE(7, DisSpecRegMem(x, "fidivrl Mdi", "UNKNOWN"));
|
||||
}
|
||||
break;
|
||||
case 0xDB:
|
||||
switch (ModrmReg(x->op.rde)) {
|
||||
case 0:
|
||||
if (!IsModrmRegister(x->op.rde)) {
|
||||
return "fildl Mdi";
|
||||
} else {
|
||||
return "fcmovnb %st EST";
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
if (!IsModrmRegister(x->op.rde)) {
|
||||
return "fisttpl Mdi";
|
||||
} else {
|
||||
return "fcmovne %st EST";
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
if (!IsModrmRegister(x->op.rde)) {
|
||||
return "fistl Mdi";
|
||||
} else {
|
||||
return "fcmovnbe %st EST";
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
if (!IsModrmRegister(x->op.rde)) {
|
||||
return "fistpl Mdi";
|
||||
} else {
|
||||
return "fcmovnu %st EST";
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
return DisOpFpu0(x, 5);
|
||||
case 5:
|
||||
if (!IsModrmRegister(x->op.rde)) {
|
||||
return "fldt Mer";
|
||||
} else {
|
||||
return "fucomi %st EST";
|
||||
}
|
||||
break;
|
||||
case 6:
|
||||
if (IsModrmRegister(x->op.rde)) {
|
||||
return "fcomi %st EST";
|
||||
} else {
|
||||
return UNKNOWN;
|
||||
}
|
||||
break;
|
||||
case 7:
|
||||
if (!IsModrmRegister(x->op.rde)) {
|
||||
return "fstpt Mer";
|
||||
} else {
|
||||
return UNKNOWN;
|
||||
}
|
||||
break;
|
||||
RCASE(0, DisSpecRegMem(x, "fcmovnb %st EST", "fildl Mdi"));
|
||||
RCASE(1, DisSpecRegMem(x, "fcmovne %st EST", "fisttpl Mdi"));
|
||||
RCASE(2, DisSpecRegMem(x, "fcmovnbe %st EST", "fistl Mdi"));
|
||||
RCASE(3, DisSpecRegMem(x, "fcmovnu %st EST", "fistpl Mdi"));
|
||||
RCASE(4, DisSpecFpu0(x, 5));
|
||||
RCASE(5, DisSpecRegMem(x, "fucomi %st EST", "fldt Mer"));
|
||||
RCASE(6, DisSpecRegMem(x, "fcomi %st EST", UNKNOWN));
|
||||
RCASE(7, DisSpecRegMem(x, UNKNOWN, "fstpt Mer"));
|
||||
}
|
||||
break;
|
||||
case 0xD8:
|
||||
|
@ -590,22 +465,7 @@ const char *DisSpecMap1(struct XedDecodedInst *x, char *p) {
|
|||
RCASE(0x2E, Osz(x->op.rde) ? "ucomisd %Vsd Wsd" : "ucomiss %Vss Wss");
|
||||
RCASE(0x2F, Osz(x->op.rde) ? "comisd %Vsd Wsd" : "comiss %Vss Wss");
|
||||
RCASE(0x31, "rdtsc");
|
||||
RCASE(0x40, "cmovo %Gvqp Evqp");
|
||||
RCASE(0x41, "cmovno %Gvqp Evqp");
|
||||
RCASE(0x42, "cmovb %Gvqp Evqp");
|
||||
RCASE(0x43, "cmovae %Gvqp Evqp");
|
||||
RCASE(0x44, "cmove %Gvqp Evqp");
|
||||
RCASE(0x45, "cmovne %Gvqp Evqp");
|
||||
RCASE(0x46, "cmovbe %Gvqp Evqp");
|
||||
RCASE(0x47, "cmova %Gvqp Evqp");
|
||||
RCASE(0x48, "cmovs %Gvqp Evqp");
|
||||
RCASE(0x49, "cmovns %Gvqp Evqp");
|
||||
RCASE(0x4a, "cmovp %Gvqp Evqp");
|
||||
RCASE(0x4b, "cmovnp %Gvqp Evqp");
|
||||
RCASE(0x4c, "cmovl %Gvqp Evqp");
|
||||
RCASE(0x4d, "cmovge %Gvqp Evqp");
|
||||
RCASE(0x4e, "cmovle %Gvqp Evqp");
|
||||
RCASE(0x4f, "cmovg %Gvqp Evqp");
|
||||
RCASE(0x40 ... 0x4f, "cmovCC %Gvqp Evqp");
|
||||
RCASE(0x52, DisOpVpsWpsVssWss(x, p, "rsqrt"));
|
||||
RCASE(0x53, DisOpVpsWpsVssWss(x, p, "rcp"));
|
||||
RCASE(0x54, DisOpVpdWpdVpsWps(x, p, "and"));
|
||||
|
@ -635,38 +495,8 @@ const char *DisSpecMap1(struct XedDecodedInst *x, char *p) {
|
|||
RCASE(0x74, DisOpPqQqVdqWdq(x, p, "pcmpeqb"));
|
||||
RCASE(0x75, DisOpPqQqVdqWdq(x, p, "pcmpeqw"));
|
||||
RCASE(0x76, DisOpPqQqVdqWdq(x, p, "pcmpeqd"));
|
||||
RCASE(0x80, "jo Jvds");
|
||||
RCASE(0x81, "jno Jvds");
|
||||
RCASE(0x82, "jb Jvds");
|
||||
RCASE(0x83, "jae Jvds");
|
||||
RCASE(0x84, "je Jvds");
|
||||
RCASE(0x85, "jne Jvds");
|
||||
RCASE(0x86, "jbe Jvds");
|
||||
RCASE(0x87, "ja Jvds");
|
||||
RCASE(0x88, "js Jvds");
|
||||
RCASE(0x89, "jns Jvds");
|
||||
RCASE(0x8a, "jp Jvds");
|
||||
RCASE(0x8b, "jnp Jvds");
|
||||
RCASE(0x8c, "jl Jvds");
|
||||
RCASE(0x8d, "jge Jvds");
|
||||
RCASE(0x8e, "jle Jvds");
|
||||
RCASE(0x8f, "jg Jvds");
|
||||
RCASE(0x90, "seto Eb");
|
||||
RCASE(0x91, "setno Eb");
|
||||
RCASE(0x92, "setb Eb");
|
||||
RCASE(0x93, "setnb Eb");
|
||||
RCASE(0x94, "sete Eb");
|
||||
RCASE(0x95, "setne Eb");
|
||||
RCASE(0x96, "setbe Eb");
|
||||
RCASE(0x97, "seta Eb");
|
||||
RCASE(0x98, "sets Eb");
|
||||
RCASE(0x99, "setns Eb");
|
||||
RCASE(0x9A, "setp Eb");
|
||||
RCASE(0x9B, "setnp Eb");
|
||||
RCASE(0x9C, "setl Eb");
|
||||
RCASE(0x9D, "setge Eb");
|
||||
RCASE(0x9E, "setle Eb");
|
||||
RCASE(0x9F, "setg Eb");
|
||||
RCASE(0x80 ... 0x8f, "jCC Jvds");
|
||||
RCASE(0x90 ... 0x9f, "setCC Jvds");
|
||||
RCASE(0xA0, "push %fs");
|
||||
RCASE(0xA1, "pop %fs");
|
||||
RCASE(0xA2, "cpuid");
|
||||
|
|
55
tool/build/lib/flags.c
Normal file
55
tool/build/lib/flags.c
Normal file
|
@ -0,0 +1,55 @@
|
|||
/*-*- 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/flags.h"
|
||||
|
||||
bool GetParity(uint8_t b) {
|
||||
b ^= b >> 4;
|
||||
b ^= b >> 2;
|
||||
b ^= b >> 1;
|
||||
return ~b & 1;
|
||||
}
|
||||
|
||||
void ImportFlags(struct Machine *m, uint64_t flags) {
|
||||
uint64_t old, mask = 0;
|
||||
mask |= 1u << FLAGS_CF;
|
||||
mask |= 1u << FLAGS_PF;
|
||||
mask |= 1u << FLAGS_AF;
|
||||
mask |= 1u << FLAGS_ZF;
|
||||
mask |= 1u << FLAGS_SF;
|
||||
mask |= 1u << FLAGS_TF;
|
||||
mask |= 1u << FLAGS_IF;
|
||||
mask |= 1u << FLAGS_DF;
|
||||
mask |= 1u << FLAGS_OF;
|
||||
mask |= 1u << FLAGS_NT;
|
||||
mask |= 1u << FLAGS_AC;
|
||||
mask |= 1u << FLAGS_ID;
|
||||
m->flags = (flags & mask) | (m->flags & ~mask);
|
||||
m->flags = SetFlag(m->flags, FLAGS_RF, false);
|
||||
m->flags = SetLazyParityByte(m->flags, !((m->flags >> FLAGS_PF) & 1));
|
||||
}
|
||||
|
||||
uint64_t ExportFlags(uint64_t flags) {
|
||||
flags = SetFlag(flags, FLAGS_IOPL, 3);
|
||||
flags = SetFlag(flags, FLAGS_F1, true);
|
||||
flags = SetFlag(flags, FLAGS_F0, false);
|
||||
flags = flags & ~(1ull << FLAGS_PF);
|
||||
flags |= GetLazyParityBool(flags) << FLAGS_PF;
|
||||
return flags;
|
||||
}
|
|
@ -1,5 +1,6 @@
|
|||
#ifndef COSMOPOLITAN_TOOL_BUILD_LIB_FLAGS_H_
|
||||
#define COSMOPOLITAN_TOOL_BUILD_LIB_FLAGS_H_
|
||||
#include "tool/build/lib/machine.h"
|
||||
|
||||
#define FLAGS_CF 0
|
||||
#define FLAGS_VF 1
|
||||
|
@ -23,18 +24,12 @@
|
|||
#define FLAGS_VIP 20
|
||||
#define FLAGS_ID 21
|
||||
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
#define GetLazyParityBool(f) GetParity((f) >> 24)
|
||||
#define SetLazyParityByte(f, x) (((f) & ~0xFF000000u) | ((x)&0xFFu) << 24)
|
||||
|
||||
#define GetParity(WORD) \
|
||||
({ \
|
||||
unsigned Byte = (WORD); \
|
||||
Byte ^= Byte >> 4; \
|
||||
Byte ^= Byte >> 2; \
|
||||
Byte ^= Byte >> 1; \
|
||||
~Byte & 1; \
|
||||
})
|
||||
|
||||
#define GetFlag(FLAGS, BIT) \
|
||||
({ \
|
||||
autotype(FLAGS) Flags = (FLAGS); \
|
||||
|
@ -66,13 +61,10 @@
|
|||
Flags; \
|
||||
})
|
||||
|
||||
forceinline uint64_t ExportFlags(uint64_t flags) {
|
||||
flags = SetFlag(flags, FLAGS_IOPL, 3);
|
||||
flags = SetFlag(flags, FLAGS_F1, true);
|
||||
flags = SetFlag(flags, FLAGS_F0, false);
|
||||
flags = flags & ~(1ull << FLAGS_PF);
|
||||
flags |= GetLazyParityBool(flags) << FLAGS_PF;
|
||||
return flags;
|
||||
}
|
||||
bool GetParity(uint8_t);
|
||||
uint64_t ExportFlags(uint64_t);
|
||||
void ImportFlags(struct Machine *, uint64_t);
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_TOOL_BUILD_LIB_FLAGS_H_ */
|
||||
|
|
|
@ -298,8 +298,7 @@ static long double FpuRound(struct Machine *m, long double x) {
|
|||
}
|
||||
|
||||
static void FpuCompare(struct Machine *m, long double y) {
|
||||
long double x;
|
||||
x = St0(m);
|
||||
long double x = St0(m);
|
||||
m->fpu.c1 = false;
|
||||
if (!isunordered(x, y)) {
|
||||
m->fpu.c0 = x < y;
|
||||
|
@ -452,7 +451,7 @@ static void OpFsincos(struct Machine *m) {
|
|||
|
||||
static void OpFpatan(struct Machine *m) {
|
||||
FpuClearRoundup(m);
|
||||
FpuSetStPop(m, 1, atan2l(St0(m), St1(m)));
|
||||
FpuSetStPop(m, 1, atan2l(St1(m), St0(m)));
|
||||
}
|
||||
|
||||
static void OpFcom(struct Machine *m) {
|
||||
|
@ -704,8 +703,7 @@ static void OpFincstp(struct Machine *m) {
|
|||
}
|
||||
|
||||
static void OpFxtract(struct Machine *m) {
|
||||
long double x;
|
||||
x = St0(m);
|
||||
long double x = St0(m);
|
||||
FpuSetSt0(m, logbl(x));
|
||||
FpuPush(m, significandl(x));
|
||||
}
|
||||
|
@ -766,30 +764,44 @@ static void OpFldl(struct Machine *m) {
|
|||
FpuPush(m, FpuGetMemoryDouble(m));
|
||||
}
|
||||
|
||||
static long double Fld1(void) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
static long double Fldl2t(void) {
|
||||
return 0xd.49a784bcd1b8afep-2L; /* log₂10 */
|
||||
}
|
||||
|
||||
static long double Fldl2e(void) {
|
||||
return 0xb.8aa3b295c17f0bcp-3L; /* log₂𝑒 */
|
||||
}
|
||||
|
||||
static long double Fldpi(void) {
|
||||
return 0x1.921fb54442d1846ap+1L; /* π */
|
||||
}
|
||||
|
||||
static long double Fldlg2(void) {
|
||||
return 0x9.a209a84fbcff799p-5L; /* log₁₀2 */
|
||||
}
|
||||
|
||||
static long double Fldln2(void) {
|
||||
return 0xb.17217f7d1cf79acp-4L; /* logₑ2 */
|
||||
}
|
||||
|
||||
static long double Fldz(void) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void OpFldConstant(struct Machine *m) {
|
||||
long double x;
|
||||
switch (ModrmRm(m->xedd->op.rde)) {
|
||||
case 0:
|
||||
x = fld1();
|
||||
break;
|
||||
case 1:
|
||||
x = fldl2t();
|
||||
break;
|
||||
case 2:
|
||||
x = fldl2e();
|
||||
break;
|
||||
case 3:
|
||||
x = fldpi();
|
||||
break;
|
||||
case 4:
|
||||
x = fldlg2();
|
||||
break;
|
||||
case 5:
|
||||
x = fldln2();
|
||||
break;
|
||||
case 6:
|
||||
x = fldz();
|
||||
break;
|
||||
CASE(0, x = Fld1());
|
||||
CASE(1, x = Fldl2t());
|
||||
CASE(2, x = Fldl2e());
|
||||
CASE(3, x = Fldpi());
|
||||
CASE(4, x = Fldlg2());
|
||||
CASE(5, x = Fldln2());
|
||||
CASE(6, x = Fldz());
|
||||
default:
|
||||
OpUd(m, m->xedd->op.rde);
|
||||
}
|
||||
|
|
|
@ -19,16 +19,24 @@
|
|||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/conv/itoa.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "tool/build/lib/dis.h"
|
||||
#include "tool/build/lib/high.h"
|
||||
|
||||
struct DisHigh *g_dis_high;
|
||||
struct High g_high;
|
||||
|
||||
char *DisHigh(char *p, int h) {
|
||||
if (h != -1) {
|
||||
char *HighStart(char *p, int h) {
|
||||
if (h) {
|
||||
p = stpcpy(p, "\e[38;5;");
|
||||
p += uint64toarray_radix10(h, p);
|
||||
} else {
|
||||
p = stpcpy(p, "\e[39");
|
||||
p = stpcpy(p, "m");
|
||||
g_high.active = true;
|
||||
}
|
||||
return stpcpy(p, "m");
|
||||
return p;
|
||||
}
|
||||
|
||||
char *HighEnd(char *p) {
|
||||
if (g_high.active) {
|
||||
p = stpcpy(p, "\e[39m");
|
||||
g_high.active = false;
|
||||
}
|
||||
return p;
|
||||
}
|
23
tool/build/lib/high.h
Normal file
23
tool/build/lib/high.h
Normal file
|
@ -0,0 +1,23 @@
|
|||
#ifndef COSMOPOLITAN_TOOL_BUILD_LIB_HIGH_H_
|
||||
#define COSMOPOLITAN_TOOL_BUILD_LIB_HIGH_H_
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
struct High {
|
||||
bool active;
|
||||
uint8_t keyword;
|
||||
uint8_t reg;
|
||||
uint8_t literal;
|
||||
uint8_t label;
|
||||
uint8_t comment;
|
||||
uint8_t quote;
|
||||
};
|
||||
|
||||
extern struct High g_high;
|
||||
|
||||
char *HighStart(char *, int);
|
||||
char *HighEnd(char *);
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_TOOL_BUILD_LIB_HIGH_H_ */
|
|
@ -52,18 +52,33 @@ static void DecodeInstruction(struct Machine *m, uint8_t *p, unsigned n) {
|
|||
}
|
||||
}
|
||||
|
||||
static noinline void LoadInstructionSlow(struct Machine *m, uint64_t ip) {
|
||||
unsigned i;
|
||||
uint8_t *addr;
|
||||
uint8_t copy[15], *toil;
|
||||
i = 0x1000 - (ip & 0xfff);
|
||||
addr = ResolveAddress(m, ip);
|
||||
if ((toil = FindReal(m, ip + i))) {
|
||||
memcpy(copy, addr, i);
|
||||
memcpy(copy + i, toil, 15 - i);
|
||||
DecodeInstruction(m, copy, 15);
|
||||
} else {
|
||||
DecodeInstruction(m, addr, i);
|
||||
}
|
||||
}
|
||||
|
||||
void LoadInstruction(struct Machine *m) {
|
||||
uint64_t ip;
|
||||
unsigned i, key;
|
||||
uint8_t *addr, *toil, copy[15];
|
||||
unsigned key;
|
||||
uint8_t *addr;
|
||||
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) {
|
||||
if ((ip & 0xfff) < 0x1000 - 15) {
|
||||
if (ip - (ip & 0xfff) == m->codevirt && ip) {
|
||||
addr = m->codereal + (ip & 0xfff);
|
||||
} else {
|
||||
m->codevirt = ROUNDDOWN(ip, 0x1000);
|
||||
m->codevirt = ip - (ip & 0xfff);
|
||||
m->codereal = ResolveAddress(m, m->codevirt);
|
||||
addr = m->codereal + (ip & 0xfff);
|
||||
}
|
||||
|
@ -71,13 +86,6 @@ void LoadInstruction(struct Machine *m) {
|
|||
DecodeInstruction(m, addr, 15);
|
||||
}
|
||||
} else {
|
||||
addr = ResolveAddress(m, ip);
|
||||
if ((toil = FindReal(m, ip + i))) {
|
||||
memcpy(copy, addr, i);
|
||||
memcpy(copy + i, toil, 15 - i);
|
||||
DecodeInstruction(m, copy, 15);
|
||||
} else {
|
||||
DecodeInstruction(m, addr, i);
|
||||
}
|
||||
LoadInstructionSlow(m, ip);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -52,6 +52,7 @@ static void LoadElfLoadSegment(struct Machine *m, void *code, size_t codesize,
|
|||
fstart = felf + ROUNDDOWN(phdr->p_offset, align);
|
||||
fend = felf + ROUNDUP(phdr->p_offset + phdr->p_filesz, align);
|
||||
bsssize = vend - vbss;
|
||||
m->brk = MAX(m->brk, vend);
|
||||
CHECK_GE(vend, vstart);
|
||||
CHECK_GE(fend, fstart);
|
||||
CHECK_LE(felf, fstart);
|
||||
|
@ -120,7 +121,7 @@ void LoadProgram(struct Machine *m, const char *prog, char **args, char **vars,
|
|||
DCHECK_NOTNULL(prog);
|
||||
elf->prog = prog;
|
||||
if ((fd = open(prog, O_RDONLY)) == -1 ||
|
||||
(fstat(fd, &st) == -1 || !st.st_size) || !S_ISREG(st.st_mode)) {
|
||||
(fstat(fd, &st) == -1 || !st.st_size) /* || !S_ISREG(st.st_mode) */) {
|
||||
fputs(prog, stderr);
|
||||
fputs(": not found\n", stderr);
|
||||
exit(1);
|
||||
|
|
|
@ -50,6 +50,12 @@
|
|||
#include "tool/build/lib/throw.h"
|
||||
#include "tool/build/lib/time.h"
|
||||
|
||||
#define OpLfence OpNoop
|
||||
#define OpMfence OpNoop
|
||||
#define OpSfence OpNoop
|
||||
#define OpClflush OpNoop
|
||||
#define OpHintNopEv OpNoop
|
||||
|
||||
typedef void (*nexgen32e_f)(struct Machine *, uint32_t);
|
||||
|
||||
static uint64_t ReadMemory(uint32_t rde, uint8_t p[8]) {
|
||||
|
@ -130,38 +136,7 @@ static bool IsGreater(struct Machine *m) {
|
|||
(GetFlag(m->flags, FLAGS_SF) == GetFlag(m->flags, FLAGS_OF));
|
||||
}
|
||||
|
||||
static void ImportFlags(struct Machine *m, uint64_t flags) {
|
||||
uint64_t old, mask = 0;
|
||||
mask |= 1u << FLAGS_CF;
|
||||
mask |= 1u << FLAGS_PF;
|
||||
mask |= 1u << FLAGS_AF;
|
||||
mask |= 1u << FLAGS_ZF;
|
||||
mask |= 1u << FLAGS_SF;
|
||||
mask |= 1u << FLAGS_TF;
|
||||
mask |= 1u << FLAGS_IF;
|
||||
mask |= 1u << FLAGS_DF;
|
||||
mask |= 1u << FLAGS_OF;
|
||||
mask |= 1u << FLAGS_NT;
|
||||
mask |= 1u << FLAGS_AC;
|
||||
mask |= 1u << FLAGS_ID;
|
||||
m->flags = (flags & mask) | (m->flags & ~mask);
|
||||
m->flags = SetFlag(m->flags, FLAGS_RF, false);
|
||||
m->flags = SetLazyParityByte(m->flags, !((m->flags >> FLAGS_PF) & 1));
|
||||
}
|
||||
|
||||
static void OpLfence(struct Machine *m, uint32_t rde) {
|
||||
}
|
||||
|
||||
static void OpMfence(struct Machine *m, uint32_t rde) {
|
||||
}
|
||||
|
||||
static void OpSfence(struct Machine *m, uint32_t rde) {
|
||||
}
|
||||
|
||||
static void OpClflush(struct Machine *m, uint32_t rde) {
|
||||
}
|
||||
|
||||
static void OpWutNopEv(struct Machine *m, uint32_t rde) {
|
||||
static void OpNoop(struct Machine *m, uint32_t rde) {
|
||||
}
|
||||
|
||||
static void OpCmc(struct Machine *m, uint32_t rde) {
|
||||
|
@ -216,27 +191,27 @@ static void OpLeaGvqpM(struct Machine *m, uint32_t rde) {
|
|||
WriteRegister(rde, RegRexrReg(m, rde), ComputeAddress(m, rde));
|
||||
}
|
||||
|
||||
static void OpPushSeg(struct Machine *m, uint32_t rde) {
|
||||
static relegated 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) {
|
||||
static relegated 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) {
|
||||
static relegated 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) {
|
||||
static relegated 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) {
|
||||
static relegated void OpJmpf(struct Machine *m, uint32_t rde) {
|
||||
Write64(m->cs, m->xedd->op.uimm0 << 4);
|
||||
m->ip = m->xedd->op.disp;
|
||||
}
|
||||
|
@ -474,7 +449,8 @@ static void OpBit(struct Machine *m, uint32_t rde) {
|
|||
SetWriteAddr(m, v, 1 << w);
|
||||
}
|
||||
}
|
||||
y = 1ull << bit;
|
||||
y = 1;
|
||||
y <<= bit;
|
||||
x = ReadMemory(rde, p);
|
||||
m->flags = SetFlag(m->flags, FLAGS_CF, !!(y & x));
|
||||
switch (op) {
|
||||
|
@ -495,7 +471,7 @@ static void OpBit(struct Machine *m, uint32_t rde) {
|
|||
WriteRegisterOrMemory(rde, p, z);
|
||||
}
|
||||
|
||||
static void OpConvert1(struct Machine *m, uint32_t rde) {
|
||||
static void OpSax(struct Machine *m, uint32_t rde) {
|
||||
if (Rexw(rde)) {
|
||||
Write64(m->ax, (int32_t)Read32(m->ax));
|
||||
} else if (!Osz(rde)) {
|
||||
|
@ -505,7 +481,7 @@ static void OpConvert1(struct Machine *m, uint32_t rde) {
|
|||
}
|
||||
}
|
||||
|
||||
static void OpConvert2(struct Machine *m, uint32_t rde) {
|
||||
static void OpConvert(struct Machine *m, uint32_t rde) {
|
||||
if (Rexw(rde)) {
|
||||
Write64(m->dx, Read64(m->ax) & 0x8000000000000000 ? 0xffffffffffffffff : 0);
|
||||
} else if (!Osz(rde)) {
|
||||
|
@ -530,7 +506,7 @@ static void OpBswapZvqp(struct Machine *m, uint32_t rde) {
|
|||
((x & 0xff000000) >> 030 | (x & 0x000000ff) << 030 |
|
||||
(x & 0x00ff0000) >> 010 | (x & 0x0000ff00) << 010));
|
||||
} else {
|
||||
Write16(RegRexbSrm(m, rde), ((x & 0x00ff) << 010 | (x & 0xff00) << 010));
|
||||
Write16(RegRexbSrm(m, rde), (x & 0x00ff) << 010 | (x & 0xff00) << 010);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -625,18 +601,41 @@ static void OpMovswGvqpEw(struct Machine *m, uint32_t rde) {
|
|||
}
|
||||
|
||||
static void OpMovsxdGdqpEd(struct Machine *m, uint32_t rde) {
|
||||
uint64_t x;
|
||||
uint8_t *p;
|
||||
x = (int32_t)Read32(GetModrmRegisterWordPointerRead4(m, rde));
|
||||
if (!Rexw(rde)) x &= 0xffffffff; /* wut */
|
||||
Write64(RegRexrReg(m, rde), x);
|
||||
Write64(RegRexrReg(m, rde),
|
||||
(int32_t)Read32(GetModrmRegisterWordPointerRead4(m, rde)));
|
||||
}
|
||||
|
||||
static void OpAlub(struct Machine *m, uint32_t rde) {
|
||||
uint8_t *a;
|
||||
a = GetModrmRegisterBytePointerWrite(m, rde);
|
||||
Write8(a, kAlu[(m->xedd->op.opcode & 070) >> 3][0](
|
||||
Read8(a), Read8(ByteRexrReg(m, rde)), &m->flags));
|
||||
static void Alub(struct Machine *m, uint32_t rde, aluop_f op) {
|
||||
uint8_t *a = GetModrmRegisterBytePointerWrite(m, rde);
|
||||
Write8(a, op(Read8(a), Read8(ByteRexrReg(m, rde)), &m->flags));
|
||||
}
|
||||
|
||||
static void OpAlubAdd(struct Machine *m, uint32_t rde) {
|
||||
Alub(m, rde, Add8);
|
||||
}
|
||||
|
||||
static void OpAlubOr(struct Machine *m, uint32_t rde) {
|
||||
Alub(m, rde, Or8);
|
||||
}
|
||||
|
||||
static void OpAlubAdc(struct Machine *m, uint32_t rde) {
|
||||
Alub(m, rde, Adc8);
|
||||
}
|
||||
|
||||
static void OpAlubSbb(struct Machine *m, uint32_t rde) {
|
||||
Alub(m, rde, Sbb8);
|
||||
}
|
||||
|
||||
static void OpAlubAnd(struct Machine *m, uint32_t rde) {
|
||||
Alub(m, rde, And8);
|
||||
}
|
||||
|
||||
static void OpAlubSub(struct Machine *m, uint32_t rde) {
|
||||
Alub(m, rde, Sub8);
|
||||
}
|
||||
|
||||
static void OpAlubXor(struct Machine *m, uint32_t rde) {
|
||||
Alub(m, rde, Xor8);
|
||||
}
|
||||
|
||||
static void AlubRo(struct Machine *m, uint32_t rde, aluop_f op) {
|
||||
|
@ -652,11 +651,38 @@ static void OpAlubTest(struct Machine *m, uint32_t rde) {
|
|||
AlubRo(m, rde, And8);
|
||||
}
|
||||
|
||||
static void OpAlubFlip(struct Machine *m, uint32_t rde) {
|
||||
static void AlubFlip(struct Machine *m, uint32_t rde, aluop_f op) {
|
||||
Write8(ByteRexrReg(m, rde),
|
||||
kAlu[(m->xedd->op.opcode & 070) >> 3][0](
|
||||
Read8(ByteRexrReg(m, rde)),
|
||||
Read8(GetModrmRegisterBytePointerRead(m, rde)), &m->flags));
|
||||
op(Read8(ByteRexrReg(m, rde)),
|
||||
Read8(GetModrmRegisterBytePointerRead(m, rde)), &m->flags));
|
||||
}
|
||||
|
||||
static void OpAlubFlipAdd(struct Machine *m, uint32_t rde) {
|
||||
AlubFlip(m, rde, Add8);
|
||||
}
|
||||
|
||||
static void OpAlubFlipOr(struct Machine *m, uint32_t rde) {
|
||||
AlubFlip(m, rde, Or8);
|
||||
}
|
||||
|
||||
static void OpAlubFlipAdc(struct Machine *m, uint32_t rde) {
|
||||
AlubFlip(m, rde, Adc8);
|
||||
}
|
||||
|
||||
static void OpAlubFlipSbb(struct Machine *m, uint32_t rde) {
|
||||
AlubFlip(m, rde, Sbb8);
|
||||
}
|
||||
|
||||
static void OpAlubFlipAnd(struct Machine *m, uint32_t rde) {
|
||||
AlubFlip(m, rde, And8);
|
||||
}
|
||||
|
||||
static void OpAlubFlipSub(struct Machine *m, uint32_t rde) {
|
||||
AlubFlip(m, rde, Sub8);
|
||||
}
|
||||
|
||||
static void OpAlubFlipXor(struct Machine *m, uint32_t rde) {
|
||||
AlubFlip(m, rde, Xor8);
|
||||
}
|
||||
|
||||
static void AlubFlipRo(struct Machine *m, uint32_t rde, aluop_f op) {
|
||||
|
@ -765,9 +791,36 @@ static void OpAluwiReg(struct Machine *m, uint32_t rde) {
|
|||
}
|
||||
}
|
||||
|
||||
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 AluAlIb(struct Machine *m, aluop_f op) {
|
||||
Write8(m->ax, op(Read8(m->ax), m->xedd->op.uimm0, &m->flags));
|
||||
}
|
||||
|
||||
static void OpAluAlIbAdd(struct Machine *m, uint32_t rde) {
|
||||
AluAlIb(m, Add8);
|
||||
}
|
||||
|
||||
static void OpAluAlIbOr(struct Machine *m, uint32_t rde) {
|
||||
AluAlIb(m, Or8);
|
||||
}
|
||||
|
||||
static void OpAluAlIbAdc(struct Machine *m, uint32_t rde) {
|
||||
AluAlIb(m, Adc8);
|
||||
}
|
||||
|
||||
static void OpAluAlIbSbb(struct Machine *m, uint32_t rde) {
|
||||
AluAlIb(m, Sbb8);
|
||||
}
|
||||
|
||||
static void OpAluAlIbAnd(struct Machine *m, uint32_t rde) {
|
||||
AluAlIb(m, And8);
|
||||
}
|
||||
|
||||
static void OpAluAlIbSub(struct Machine *m, uint32_t rde) {
|
||||
AluAlIb(m, Sub8);
|
||||
}
|
||||
|
||||
static void OpAluAlIbXor(struct Machine *m, uint32_t rde) {
|
||||
AluAlIb(m, Xor8);
|
||||
}
|
||||
|
||||
static void OpAluRaxIvds(struct Machine *m, uint32_t rde) {
|
||||
|
@ -831,18 +884,19 @@ 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]) {
|
||||
static relegated 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) {
|
||||
static relegated void OpLes(struct Machine *m, uint32_t rde) {
|
||||
LoadFarPointer(m, rde, m->es);
|
||||
}
|
||||
|
||||
static void OpLds(struct Machine *m, uint32_t rde) {
|
||||
static relegated void OpLds(struct Machine *m, uint32_t rde) {
|
||||
LoadFarPointer(m, rde, m->ds);
|
||||
}
|
||||
|
||||
|
@ -853,14 +907,6 @@ 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);
|
||||
}
|
||||
|
@ -1213,17 +1259,18 @@ static void OpNegEb(struct Machine *m, uint32_t rde) {
|
|||
AluEb(m, rde, Neg8);
|
||||
}
|
||||
|
||||
static const nexgen32e_f kOp0f6[] = {
|
||||
OpAlubiTest,
|
||||
OpAlubiTest,
|
||||
OpNotEb,
|
||||
OpNegEb,
|
||||
OpMulAxAlEbUnsigned,
|
||||
OpMulAxAlEbSigned,
|
||||
OpDivAlAhAxEbUnsigned,
|
||||
OpDivAlAhAxEbSigned,
|
||||
};
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -1239,17 +1286,18 @@ static void OpNegEvqp(struct Machine *m, uint32_t rde) {
|
|||
AluEvqp(m, rde, kAlu[ALU_NEG]);
|
||||
}
|
||||
|
||||
static const nexgen32e_f kOp0f7[] = {
|
||||
OpTestEvqpIvds,
|
||||
OpTestEvqpIvds,
|
||||
OpNotEvqp,
|
||||
OpNegEvqp,
|
||||
OpMulRdxRaxEvqpUnsigned,
|
||||
OpMulRdxRaxEvqpSigned,
|
||||
OpDivRdxRaxEvqpUnsigned,
|
||||
OpDivRdxRaxEvqpSigned,
|
||||
};
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -1274,9 +1322,10 @@ static void OpDecEvqp(struct Machine *m, uint32_t rde) {
|
|||
AluEvqp(m, rde, kAlu[ALU_DEC]);
|
||||
}
|
||||
|
||||
static const nexgen32e_f kOp0ff[] = {OpIncEvqp, OpDecEvqp, OpCallEq, OpUd,
|
||||
OpJmpEq, OpUd, OpPushEvq, OpUd};
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -1295,57 +1344,6 @@ static void Op101(struct Machine *m, uint32_t rde) {
|
|||
OpUd(m, rde);
|
||||
}
|
||||
|
||||
static void Op171(struct Machine *m, uint32_t rde) {
|
||||
switch (ModrmReg(rde)) {
|
||||
case 2:
|
||||
OpSseUdqIb(m, rde, kOpSseUdqIbPsrlw);
|
||||
break;
|
||||
case 4:
|
||||
OpSseUdqIb(m, rde, kOpSseUdqIbPsraw);
|
||||
break;
|
||||
case 6:
|
||||
OpSseUdqIb(m, rde, kOpSseUdqIbPsllw);
|
||||
break;
|
||||
default:
|
||||
OpUd(m, rde);
|
||||
}
|
||||
}
|
||||
|
||||
static void Op172(struct Machine *m, uint32_t rde) {
|
||||
switch (ModrmReg(rde)) {
|
||||
case 2:
|
||||
OpSseUdqIb(m, rde, kOpSseUdqIbPsrld);
|
||||
break;
|
||||
case 4:
|
||||
OpSseUdqIb(m, rde, kOpSseUdqIbPsrad);
|
||||
break;
|
||||
case 6:
|
||||
OpSseUdqIb(m, rde, kOpSseUdqIbPslld);
|
||||
break;
|
||||
default:
|
||||
OpUd(m, rde);
|
||||
}
|
||||
}
|
||||
|
||||
static void Op173(struct Machine *m, uint32_t rde) {
|
||||
switch (ModrmReg(rde)) {
|
||||
case 2:
|
||||
OpSseUdqIb(m, rde, kOpSseUdqIbPsrlq);
|
||||
break;
|
||||
case 3:
|
||||
OpSseUdqIb(m, rde, kOpSseUdqIbPsrldq);
|
||||
break;
|
||||
case 6:
|
||||
OpSseUdqIb(m, rde, kOpSseUdqIbPsllq);
|
||||
break;
|
||||
case 7:
|
||||
OpSseUdqIb(m, rde, kOpSseUdqIbPslldq);
|
||||
break;
|
||||
default:
|
||||
OpUd(m, rde);
|
||||
}
|
||||
}
|
||||
|
||||
static void OpDoubleShift(struct Machine *m, uint32_t rde) {
|
||||
uint8_t *p;
|
||||
uint64_t x;
|
||||
|
@ -1386,6 +1384,8 @@ static void OpSalc(struct Machine *m, uint32_t rde) {
|
|||
static void OpNopEv(struct Machine *m, uint32_t rde) {
|
||||
if (ModrmMod(rde) == 0b01 && ModrmReg(rde) == 0 && ModrmRm(rde) == 0b101) {
|
||||
OpBofram(m, rde);
|
||||
} else {
|
||||
OpNoop(m, rde);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1394,63 +1394,65 @@ static void OpNop(struct Machine *m, uint32_t rde) {
|
|||
OpXchgZvqp(m, rde);
|
||||
} else if (Rep(rde) == 3) {
|
||||
OpPause(m, rde);
|
||||
} else {
|
||||
OpNoop(m, rde);
|
||||
}
|
||||
}
|
||||
|
||||
static const nexgen32e_f kNexgen32e[] = {
|
||||
[0x000] = OpAlub,
|
||||
[0x000] = OpAlubAdd,
|
||||
[0x001] = OpAluw,
|
||||
[0x002] = OpAlubFlip,
|
||||
[0x002] = OpAlubFlipAdd,
|
||||
[0x003] = OpAluwFlip,
|
||||
[0x004] = OpAluAlIb,
|
||||
[0x004] = OpAluAlIbAdd,
|
||||
[0x005] = OpAluRaxIvds,
|
||||
[0x006] = OpPushSeg,
|
||||
[0x007] = OpPopSeg,
|
||||
[0x008] = OpAlub,
|
||||
[0x008] = OpAlubOr,
|
||||
[0x009] = OpAluw,
|
||||
[0x00A] = OpAlubFlip,
|
||||
[0x00A] = OpAlubFlipOr,
|
||||
[0x00B] = OpAluwFlip,
|
||||
[0x00C] = OpAluAlIb,
|
||||
[0x00C] = OpAluAlIbOr,
|
||||
[0x00D] = OpAluRaxIvds,
|
||||
[0x00E] = OpPushSeg,
|
||||
[0x00F] = OpPopSeg,
|
||||
[0x010] = OpAlub,
|
||||
[0x010] = OpAlubAdc,
|
||||
[0x011] = OpAluw,
|
||||
[0x012] = OpAlubFlip,
|
||||
[0x012] = OpAlubFlipAdc,
|
||||
[0x013] = OpAluwFlip,
|
||||
[0x014] = OpAluAlIb,
|
||||
[0x014] = OpAluAlIbAdc,
|
||||
[0x015] = OpAluRaxIvds,
|
||||
[0x016] = OpPushSeg,
|
||||
[0x017] = OpPopSeg,
|
||||
[0x018] = OpAlub,
|
||||
[0x018] = OpAlubSbb,
|
||||
[0x019] = OpAluw,
|
||||
[0x01A] = OpAlubFlip,
|
||||
[0x01A] = OpAlubFlipSbb,
|
||||
[0x01B] = OpAluwFlip,
|
||||
[0x01C] = OpAluAlIb,
|
||||
[0x01C] = OpAluAlIbSbb,
|
||||
[0x01D] = OpAluRaxIvds,
|
||||
[0x01E] = OpPushSeg,
|
||||
[0x01F] = OpPopSeg,
|
||||
[0x020] = OpAlub,
|
||||
[0x020] = OpAlubAnd,
|
||||
[0x021] = OpAluw,
|
||||
[0x022] = OpAlubFlip,
|
||||
[0x022] = OpAlubFlipAnd,
|
||||
[0x023] = OpAluwFlip,
|
||||
[0x024] = OpAluAlIb,
|
||||
[0x024] = OpAluAlIbAnd,
|
||||
[0x025] = OpAluRaxIvds,
|
||||
[0x026] = OpPushSeg,
|
||||
[0x027] = OpPopSeg,
|
||||
[0x028] = OpAlub,
|
||||
[0x028] = OpAlubSub,
|
||||
[0x029] = OpAluw,
|
||||
[0x02A] = OpAlubFlip,
|
||||
[0x02A] = OpAlubFlipSub,
|
||||
[0x02B] = OpAluwFlip,
|
||||
[0x02C] = OpAluAlIb,
|
||||
[0x02C] = OpAluAlIbSub,
|
||||
[0x02D] = OpAluRaxIvds,
|
||||
[0x02E] = OpUd,
|
||||
[0x02F] = OpDas,
|
||||
[0x030] = OpAlub,
|
||||
[0x030] = OpAlubXor,
|
||||
[0x031] = OpAluw,
|
||||
[0x032] = OpAlubFlip,
|
||||
[0x032] = OpAlubFlipXor,
|
||||
[0x033] = OpAluwFlip,
|
||||
[0x034] = OpAluAlIb,
|
||||
[0x034] = OpAluAlIbXor,
|
||||
[0x035] = OpAluRaxIvds,
|
||||
[0x036] = OpUd,
|
||||
[0x037] = OpAaa,
|
||||
|
@ -1550,9 +1552,9 @@ static const nexgen32e_f kNexgen32e[] = {
|
|||
[0x095] = OpXchgZvqp,
|
||||
[0x096] = OpXchgZvqp,
|
||||
[0x097] = OpXchgZvqp,
|
||||
[0x098] = OpConvert1,
|
||||
[0x099] = OpConvert2,
|
||||
[0x09A] = OpUd,
|
||||
[0x098] = OpSax,
|
||||
[0x099] = OpConvert,
|
||||
[0x09A] = OpCallf,
|
||||
[0x09B] = OpFwait,
|
||||
[0x09C] = OpPushf,
|
||||
[0x09D] = OpPopf,
|
||||
|
@ -1592,16 +1594,16 @@ static const nexgen32e_f kNexgen32e[] = {
|
|||
[0x0BF] = OpMovZvqpIvqp,
|
||||
[0x0C0] = OpBsubiImm,
|
||||
[0x0C1] = OpBsuwiImm,
|
||||
[0x0C2] = OpRetImm,
|
||||
[0x0C3] = OpRet0,
|
||||
[0x0C2] = OpRet,
|
||||
[0x0C3] = OpRet,
|
||||
[0x0C4] = OpLes,
|
||||
[0x0C5] = OpLds,
|
||||
[0x0C6] = OpMovEbIb,
|
||||
[0x0C7] = OpMovEvqpIvds,
|
||||
[0x0C8] = OpUd,
|
||||
[0x0C9] = OpLeave,
|
||||
[0x0CA] = OpUd,
|
||||
[0x0CB] = OpUd,
|
||||
[0x0CA] = OpRetf,
|
||||
[0x0CB] = OpRetf,
|
||||
[0x0CC] = OpInterrupt3,
|
||||
[0x0CD] = OpInterruptImm,
|
||||
[0x0CE] = OpUd,
|
||||
|
@ -1667,7 +1669,7 @@ static const nexgen32e_f kNexgen32e[] = {
|
|||
[0x10A] = OpUd,
|
||||
[0x10B] = OpUd,
|
||||
[0x10C] = OpUd,
|
||||
[0x10D] = OpWutNopEv,
|
||||
[0x10D] = OpHintNopEv,
|
||||
[0x10E] = OpUd,
|
||||
[0x10F] = OpUd,
|
||||
[0x110] = OpMov0f10,
|
||||
|
@ -1678,12 +1680,12 @@ static const nexgen32e_f kNexgen32e[] = {
|
|||
[0x115] = OpUnpckhpsd,
|
||||
[0x116] = OpMov0f16,
|
||||
[0x117] = OpMov0f17,
|
||||
[0x118] = OpWutNopEv,
|
||||
[0x119] = OpWutNopEv,
|
||||
[0x11A] = OpWutNopEv,
|
||||
[0x11B] = OpWutNopEv,
|
||||
[0x11C] = OpWutNopEv,
|
||||
[0x11D] = OpWutNopEv,
|
||||
[0x118] = OpHintNopEv,
|
||||
[0x119] = OpHintNopEv,
|
||||
[0x11A] = OpHintNopEv,
|
||||
[0x11B] = OpHintNopEv,
|
||||
[0x11C] = OpHintNopEv,
|
||||
[0x11D] = OpHintNopEv,
|
||||
[0x11E] = OpUd,
|
||||
[0x11F] = OpNopEv,
|
||||
[0x120] = OpUd,
|
||||
|
|
|
@ -137,12 +137,13 @@ struct Machine {
|
|||
uint32_t i;
|
||||
void *p[6];
|
||||
} freelist;
|
||||
int64_t brk;
|
||||
int64_t bofram[2];
|
||||
jmp_buf onhalt;
|
||||
int64_t faultaddr;
|
||||
uint8_t stash[4096];
|
||||
uint8_t xmmtype[2][8];
|
||||
uint8_t icache[2048][40] aligned(8);
|
||||
uint8_t icache[4096 / 4][40] aligned(16);
|
||||
struct MachineFds fds;
|
||||
} aligned(64);
|
||||
|
||||
|
|
|
@ -22,12 +22,45 @@
|
|||
#include "tool/build/lib/buffer.h"
|
||||
#include "tool/build/lib/mda.h"
|
||||
|
||||
#define kBlink 1
|
||||
#define kVisible 2
|
||||
#define kUnderline 4
|
||||
#define kBold 8
|
||||
#define kReverse 16
|
||||
|
||||
/**
|
||||
* Decodes Monochrome Display Adapter attributes.
|
||||
* @see https://www.seasip.info/VintagePC/mda.html
|
||||
*/
|
||||
static uint8_t DecodeMdaAttributes(int8_t a) {
|
||||
uint8_t r = 0;
|
||||
if (a & 0x77) {
|
||||
if ((a & 0x77) == 0x70) r |= kReverse;
|
||||
if ((a & 0x07) == 0x01) r |= kUnderline;
|
||||
if (a & 0x08) r |= kBold;
|
||||
if (a < 0) r |= kBlink;
|
||||
r |= kVisible;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
void DrawMda(struct Panel *p, uint8_t v[25][80][2]) {
|
||||
unsigned y, x, n;
|
||||
unsigned y, x, n, a, b;
|
||||
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]) {
|
||||
b = DecodeMdaAttributes(v[y][x][1]);
|
||||
if (a != b) {
|
||||
a = b;
|
||||
AppendStr(&p->lines[y], "\e[0");
|
||||
if (a & kBold) AppendStr(&p->lines[y], ";1");
|
||||
if (a & kUnderline) AppendStr(&p->lines[y], ";4");
|
||||
if (a & kBlink) AppendStr(&p->lines[y], ";5");
|
||||
if (a & kReverse) AppendStr(&p->lines[y], ";7");
|
||||
AppendChar(&p->lines[y], 'm');
|
||||
}
|
||||
if (a) {
|
||||
AppendWide(&p->lines[y], kCp437[v[y][x][0]]);
|
||||
} else {
|
||||
AppendChar(&p->lines[y], ' ');
|
||||
|
|
|
@ -26,29 +26,54 @@
|
|||
#include "tool/build/lib/modrm.h"
|
||||
#include "tool/build/lib/throw.h"
|
||||
|
||||
/**
|
||||
* 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};
|
||||
static relegated noinline int64_t ComputeAddressReal(const struct Machine *m,
|
||||
uint32_t rde, uint8_t *s,
|
||||
uint64_t i) {
|
||||
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;
|
||||
return AddSegment(m, rde, i, s);
|
||||
}
|
||||
|
||||
int64_t ComputeAddress(const struct Machine *m, uint32_t rde) {
|
||||
uint64_t i;
|
||||
uint8_t *s;
|
||||
uint8_t *s = m->ds;
|
||||
uint64_t i = m->xedd->op.disp;
|
||||
DCHECK(!IsModrmRegister(rde));
|
||||
s = m->ds;
|
||||
i = m->xedd->op.disp;
|
||||
if (Eamode(rde) != XED_MODE_REAL) {
|
||||
if (!SibExists(rde)) {
|
||||
if (IsRipRelative(rde)) {
|
||||
|
@ -75,47 +100,10 @@ int64_t ComputeAddress(const struct Machine *m, uint32_t rde) {
|
|||
if (Eamode(rde) == XED_MODE_LEGACY) {
|
||||
i &= 0xffffffff;
|
||||
}
|
||||
return AddSegment(m, rde, i, s);
|
||||
} else {
|
||||
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;
|
||||
return ComputeAddressReal(m, rde, s, i);
|
||||
}
|
||||
return AddSegment(m, rde, i, s);
|
||||
}
|
||||
|
||||
void *ComputeReserveAddressRead(struct Machine *m, uint32_t rde, size_t n) {
|
||||
|
|
|
@ -2,8 +2,6 @@
|
|||
#define COSMOPOLITAN_TOOL_BUILD_LIB_MODRM_H_
|
||||
#include "tool/build/lib/abp.h"
|
||||
#include "tool/build/lib/machine.h"
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
#define Rex(x) ((x & 000000000020) >> 004)
|
||||
#define Osz(x) ((x & 000000000040) >> 005)
|
||||
|
@ -21,12 +19,16 @@ COSMOPOLITAN_C_START_
|
|||
#define ModrmReg(x) ((x & 000000000007) >> 000)
|
||||
#define ModrmSrm(x) ((x & 000000070000) >> 014)
|
||||
#define ModrmMod(x) ((x & 000060000000) >> 026)
|
||||
#define Modrm(x) (ModrmMod(x) << 6 | ModrmReg(x) << 3 | ModrmRm(x))
|
||||
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
#define RexbBase(m, x) (Rexb(x) << 3 | m->xedd->op.base)
|
||||
#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])
|
||||
|
|
|
@ -36,12 +36,13 @@
|
|||
* @param p is panel list in logically sorted order
|
||||
* @param tyn is terminal height in cells
|
||||
* @param txn is terminal width in cells
|
||||
* @return bytes emitted, or -1 w/ errno
|
||||
* @return -1 w/ errno if an error happened
|
||||
* @see nblack's notcurses project too!
|
||||
*/
|
||||
ssize_t PrintPanels(int fd, long pn, struct Panel p[pn], long tyn, long txn) {
|
||||
wint_t wc;
|
||||
ssize_t rc;
|
||||
size_t wrote;
|
||||
struct Buffer b, *l;
|
||||
int x, y, i, j, width;
|
||||
enum { kUtf8, kAnsi, kAnsiCsi } state;
|
||||
|
|
|
@ -53,10 +53,11 @@ static uint64_t *GetPageTable(pml4t_t p, long i, void *NewPhysicalPage(void)) {
|
|||
}
|
||||
|
||||
static void PtFinder(uint64_t *a, uint64_t *b, uint64_t n, pml4t_t pd, int k) {
|
||||
unsigned i;
|
||||
uint64_t e, c;
|
||||
unsigned start;
|
||||
for (start = (*b >> k) & 511; *b - *a < n && ((*b >> k) & 511) >= start;) {
|
||||
e = pd[(*b >> k) & 511];
|
||||
while (*b - *a < n) {
|
||||
i = (*b >> k) & 511;
|
||||
e = pd[i];
|
||||
c = ROUNDUP(*b + 1, 1 << k);
|
||||
if (!IsValidPage(e)) {
|
||||
*b = c;
|
||||
|
@ -65,6 +66,9 @@ static void PtFinder(uint64_t *a, uint64_t *b, uint64_t n, pml4t_t pd, int k) {
|
|||
} else {
|
||||
*a = *b = c;
|
||||
}
|
||||
if (((*b >> k) & 511) < i) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -17,9 +17,11 @@
|
|||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/alg/arraylist2.h"
|
||||
#include "libc/bits/bits.h"
|
||||
#include "libc/bits/safemacros.h"
|
||||
#include "libc/conv/conv.h"
|
||||
#include "libc/conv/itoa.h"
|
||||
#include "libc/log/check.h"
|
||||
#include "libc/macros.h"
|
||||
#include "libc/mem/mem.h"
|
||||
|
@ -32,13 +34,18 @@
|
|||
#include "tool/build/lib/pty.h"
|
||||
|
||||
struct MachinePty *MachinePtyNew(void) {
|
||||
return xcalloc(1, sizeof(struct MachinePty));
|
||||
struct MachinePty *pty;
|
||||
pty = xcalloc(1, sizeof(struct MachinePty));
|
||||
MachinePtyResize(pty, 25, 80);
|
||||
return pty;
|
||||
}
|
||||
|
||||
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;
|
||||
if (xn < 80) xn = 80;
|
||||
if (yn < 25) yn = 25;
|
||||
if (xn == pty->xn && yn == pty->yn) return;
|
||||
wcs = xcalloc(yn * xn, 4);
|
||||
fgs = xcalloc(yn * xn, 4);
|
||||
bgs = xcalloc(yn * xn, 4);
|
||||
|
@ -92,7 +99,9 @@ static void MachinePtyNewline(struct MachinePty *pty) {
|
|||
pty->x = 0;
|
||||
if (++pty->y == pty->yn) {
|
||||
--pty->y;
|
||||
MachinePtyScroll(pty);
|
||||
if (!(pty->conf & kMachinePtyNoopost)) {
|
||||
MachinePtyScroll(pty);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -335,6 +344,38 @@ static void MachinePtyShowCursor(struct MachinePty *pty) {
|
|||
pty->conf &= ~kMachinePtyNocursor;
|
||||
}
|
||||
|
||||
static void MachinePtyReportCursorPosition(struct MachinePty *pty) {
|
||||
char *p;
|
||||
char buf[2 + 10 + 1 + 10 + 1];
|
||||
p = buf;
|
||||
*p++ = '\e';
|
||||
*p++ = '[';
|
||||
p += uint64toarray_radix10((pty->y + 1) & 0xffffffff, p);
|
||||
*p++ = ';';
|
||||
p += uint64toarray_radix10((pty->x + 1) & 0xffffffff, p);
|
||||
*p++ = 'R';
|
||||
CONCAT(&pty->input.p, &pty->input.i, &pty->input.n, buf, p - buf);
|
||||
}
|
||||
|
||||
static void MachinePtyCsiN(struct MachinePty *pty) {
|
||||
switch (atoi(pty->esc.s)) {
|
||||
case 6:
|
||||
MachinePtyReportCursorPosition(pty);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void MachinePtyCsiScrollUp(struct MachinePty *pty) {
|
||||
int n;
|
||||
n = atoi(pty->esc.s);
|
||||
n = MAX(1, n);
|
||||
while (n--) {
|
||||
MachinePtyScroll(pty);
|
||||
}
|
||||
}
|
||||
|
||||
static void MachinePtyCsi(struct MachinePty *pty) {
|
||||
switch (pty->esc.s[pty->esc.i - 1]) {
|
||||
case 'A':
|
||||
|
@ -362,6 +403,12 @@ static void MachinePtyCsi(struct MachinePty *pty) {
|
|||
case 'm':
|
||||
MachinePtySelectGraphicsRendition(pty);
|
||||
break;
|
||||
case 'n':
|
||||
MachinePtyCsiN(pty);
|
||||
break;
|
||||
case 'S':
|
||||
MachinePtyCsiScrollUp(pty);
|
||||
break;
|
||||
case 'l':
|
||||
if (strcmp(pty->esc.s, "?25l") == 0) {
|
||||
MachinePtyHideCursor(pty);
|
||||
|
@ -389,7 +436,6 @@ 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:
|
||||
|
@ -408,6 +454,14 @@ ssize_t MachinePtyWrite(struct MachinePty *pty, const void *data, size_t n) {
|
|||
case '\n':
|
||||
MachinePtyNewline(pty);
|
||||
break;
|
||||
case 0177:
|
||||
case '\b':
|
||||
pty->x = MAX(0, pty->x - 1);
|
||||
break;
|
||||
case '\f':
|
||||
break;
|
||||
case '\a':
|
||||
break;
|
||||
default:
|
||||
SetMachinePtyCell(pty, p[i]);
|
||||
break;
|
||||
|
@ -483,47 +537,87 @@ ssize_t MachinePtyWrite(struct MachinePty *pty, const void *data, size_t n) {
|
|||
return n;
|
||||
}
|
||||
|
||||
ssize_t MachinePtyWriteInput(struct MachinePty *pty, const void *data,
|
||||
size_t n) {
|
||||
const char *p = data;
|
||||
CONCAT(&pty->input.p, &pty->input.i, &pty->input.n, data, n);
|
||||
if (!(pty->conf & kMachinePtyNoecho)) {
|
||||
MachinePtyWrite(pty, data, n);
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
ssize_t MachinePtyRead(struct MachinePty *pty, void *buf, size_t size) {
|
||||
char *p;
|
||||
size_t n;
|
||||
n = MIN(size, pty->input.i);
|
||||
if (!(pty->conf & kMachinePtyNocanon)) {
|
||||
if ((p = memchr(pty->input.p, '\n', n))) {
|
||||
n = MIN(n, pty->input.p - p + 1);
|
||||
} else {
|
||||
n = 0;
|
||||
}
|
||||
}
|
||||
memcpy(buf, pty->input.p, n);
|
||||
memcpy(pty->input.p, pty->input.p + n, pty->input.i - n);
|
||||
pty->input.i -= n;
|
||||
return n;
|
||||
}
|
||||
|
||||
void MachinePtyAppendLine(struct MachinePty *pty, struct Buffer *buf,
|
||||
unsigned y) {
|
||||
bool atcursor;
|
||||
uint32_t x, i, fg, bg, pr, wc, w;
|
||||
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];
|
||||
w = MAX(0, wcwidth(wc));
|
||||
if (w) {
|
||||
if (pty->prs[i] != pr || pty->fgs[i] != fg || pty->bgs[i] != bg) {
|
||||
fg = pty->fgs[i];
|
||||
bg = pty->bgs[i];
|
||||
pr = pty->prs[i];
|
||||
AppendStr(buf, "\e[0");
|
||||
if (pr & kMachinePtyBold) AppendStr(buf, ";1");
|
||||
if (pr & kMachinePtyFaint) AppendStr(buf, ";2");
|
||||
if (pr & kMachinePtyFlip) AppendStr(buf, ";7");
|
||||
if (pr & kMachinePtyFg) {
|
||||
if (pr & kMachinePtyTrue) {
|
||||
AppendFmt(buf, ";38;2;%d;%d;%d", (fg & 0x0000ff) >> 000,
|
||||
(fg & 0x00ff00) >> 010, (fg & 0xff0000) >> 020);
|
||||
} else {
|
||||
AppendFmt(buf, ";38;5;%d", fg);
|
||||
}
|
||||
}
|
||||
if (pr & kMachinePtyBg) {
|
||||
if (pr & kMachinePtyTrue) {
|
||||
AppendFmt(buf, ";48;2;%d;%d;%d", (bg & 0x0000ff) >> 000,
|
||||
(bg & 0x00ff00) >> 010, (bg & 0xff0000) >> 020);
|
||||
} else {
|
||||
AppendFmt(buf, ";48;5;%d", bg);
|
||||
}
|
||||
}
|
||||
AppendStr(buf, "m");
|
||||
atcursor = y == pty->y && x == pty->x;
|
||||
if ((w && atcursor) ||
|
||||
(pty->prs[i] != pr || pty->fgs[i] != fg || pty->bgs[i] != bg)) {
|
||||
fg = pty->fgs[i];
|
||||
bg = pty->bgs[i];
|
||||
pr = pty->prs[i];
|
||||
AppendStr(buf, "\e[0");
|
||||
if (w && atcursor) {
|
||||
pr ^= kMachinePtyFlip;
|
||||
}
|
||||
if (pr & kMachinePtyBold) AppendStr(buf, ";1");
|
||||
if (pr & kMachinePtyFaint) AppendStr(buf, ";2");
|
||||
if (pr & kMachinePtyBlink) AppendStr(buf, ";5");
|
||||
if (pr & kMachinePtyFlip) AppendStr(buf, ";7");
|
||||
if (pr & kMachinePtyFg) {
|
||||
if (pr & kMachinePtyTrue) {
|
||||
AppendFmt(buf, ";38;2;%d;%d;%d", (fg & 0x0000ff) >> 000,
|
||||
(fg & 0x00ff00) >> 010, (fg & 0xff0000) >> 020);
|
||||
} else {
|
||||
AppendFmt(buf, ";38;5;%d", fg);
|
||||
}
|
||||
}
|
||||
if (pr & kMachinePtyBg) {
|
||||
if (pr & kMachinePtyTrue) {
|
||||
AppendFmt(buf, ";48;2;%d;%d;%d", (bg & 0x0000ff) >> 000,
|
||||
(bg & 0x00ff00) >> 010, (bg & 0xff0000) >> 020);
|
||||
} else {
|
||||
AppendFmt(buf, ";48;5;%d", bg);
|
||||
}
|
||||
}
|
||||
AppendStr(buf, "m");
|
||||
}
|
||||
if (w) {
|
||||
AppendWide(buf, wc);
|
||||
} else {
|
||||
w = 1;
|
||||
if (y == pty->y && x == pty->x) {
|
||||
if (atcursor) {
|
||||
if (!(pty->conf & kMachinePtyNocursor)) {
|
||||
AppendStr(buf, "\e[5m▂\e[25m");
|
||||
if (pty->conf & kMachinePtyBlinkcursor) {
|
||||
AppendStr(buf, "\e[5m");
|
||||
}
|
||||
AppendWide(buf, u'▂');
|
||||
if (pty->conf & kMachinePtyBlinkcursor) {
|
||||
AppendStr(buf, "\e[25m");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
AppendChar(buf, ' ');
|
||||
|
|
|
@ -8,17 +8,22 @@
|
|||
#define kMachinePtyBold 0x08
|
||||
#define kMachinePtyFaint 0x10
|
||||
#define kMachinePtyFlip 0x20
|
||||
#define kMachinePtyBlink 0x40
|
||||
|
||||
#define kMachinePtyNocursor 0x01
|
||||
#define kMachinePtyNocursor 0x01
|
||||
#define kMachinePtyBlinkcursor 0x02
|
||||
#define kMachinePtyNocanon 0x04
|
||||
#define kMachinePtyNoecho 0x08
|
||||
#define kMachinePtyNoopost 0x10
|
||||
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
struct MachinePty {
|
||||
uint32_t yn;
|
||||
uint32_t xn;
|
||||
uint32_t y;
|
||||
uint32_t x;
|
||||
int y;
|
||||
int x;
|
||||
int yn;
|
||||
int xn;
|
||||
uint32_t pr;
|
||||
uint32_t fg;
|
||||
uint32_t bg;
|
||||
|
@ -38,12 +43,18 @@ struct MachinePty {
|
|||
unsigned i;
|
||||
char s[64];
|
||||
} esc;
|
||||
struct MachinePtyInput {
|
||||
size_t i, n;
|
||||
char *p;
|
||||
} input;
|
||||
};
|
||||
|
||||
void MachinePtyFree(struct MachinePty *);
|
||||
struct MachinePty *MachinePtyNew(void) nodiscard;
|
||||
void MachinePtyResize(struct MachinePty *, int, int);
|
||||
ssize_t MachinePtyRead(struct MachinePty *, void *, size_t);
|
||||
ssize_t MachinePtyWrite(struct MachinePty *, const void *, size_t);
|
||||
ssize_t MachinePtyWriteInput(struct MachinePty *, const void *, size_t);
|
||||
void MachinePtyAppendLine(struct MachinePty *, struct Buffer *, unsigned);
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
|
|
|
@ -100,19 +100,7 @@
|
|||
#include "tool/build/lib/memory.h"
|
||||
#include "tool/build/lib/modrm.h"
|
||||
#include "tool/build/lib/sse.h"
|
||||
|
||||
union MachineVector {
|
||||
float f32[4];
|
||||
double f64[2];
|
||||
int8_t i8[16];
|
||||
int16_t i16[8];
|
||||
int32_t i32[4];
|
||||
int64_t i64[2];
|
||||
uint8_t u8[16];
|
||||
uint16_t u16[8];
|
||||
uint32_t u32[4];
|
||||
uint64_t u64[2];
|
||||
};
|
||||
#include "tool/build/lib/throw.h"
|
||||
|
||||
static void SsePsubb(void *b, const void *a) {
|
||||
psubb(b, b, a);
|
||||
|
@ -711,29 +699,81 @@ void OpSsePmulld(struct Machine *m, uint32_t rde) {
|
|||
OpSse(m, rde, SsePmulld);
|
||||
}
|
||||
|
||||
void OpSseUdqIb(struct Machine *m, uint32_t rde, enum OpSseUdqIbKernel kernel) {
|
||||
static void SseUdqIb(struct Machine *m, uint32_t rde, int kernel) {
|
||||
void *y;
|
||||
uint8_t i;
|
||||
union MachineVector x;
|
||||
uint8_t x[16];
|
||||
i = m->xedd->op.uimm0;
|
||||
memcpy(&x, XmmRexbRm(m, rde), 16);
|
||||
y = XmmRexbRm(m, rde);
|
||||
switch (kernel) {
|
||||
CASE(kOpSseUdqIbPsrlw, (psrlw)(x.u16, x.u16, i));
|
||||
CASE(kOpSseUdqIbPsraw, (psraw)(x.i16, x.i16, i));
|
||||
CASE(kOpSseUdqIbPsllw, (psllw)(x.u16, x.u16, i));
|
||||
CASE(kOpSseUdqIbPsrld, (psrld)(x.u32, x.u32, i));
|
||||
CASE(kOpSseUdqIbPsrad, (psrad)(x.i32, x.i32, i));
|
||||
CASE(kOpSseUdqIbPslld, (pslld)(x.u32, x.u32, i));
|
||||
CASE(kOpSseUdqIbPsrlq, (psrlq)(x.u64, x.u64, i));
|
||||
CASE(kOpSseUdqIbPsrldq, (psrldq)(x.u8, x.u8, i));
|
||||
CASE(kOpSseUdqIbPsllq, (psllq)(x.u64, x.u64, i));
|
||||
CASE(kOpSseUdqIbPslldq, (pslldq)(x.u8, x.u8, i));
|
||||
CASE(0, (psrlw)((void *)x, y, i));
|
||||
CASE(1, (psraw)((void *)x, y, i));
|
||||
CASE(2, (psllw)((void *)x, y, i));
|
||||
CASE(3, (psrld)((void *)x, y, i));
|
||||
CASE(4, (psrad)((void *)x, y, i));
|
||||
CASE(5, (pslld)((void *)x, y, i));
|
||||
CASE(6, (psrlq)((void *)x, y, i));
|
||||
CASE(7, (psrldq)((void *)x, y, i));
|
||||
CASE(8, (psllq)((void *)x, y, i));
|
||||
CASE(9, (pslldq)((void *)x, y, i));
|
||||
default:
|
||||
unreachable;
|
||||
}
|
||||
if (Osz(rde)) {
|
||||
memcpy(XmmRexbRm(m, rde), &x, 16);
|
||||
memcpy(XmmRexbRm(m, rde), x, 16);
|
||||
} else {
|
||||
memcpy(XmmRexbRm(m, rde), &x, 8);
|
||||
memcpy(XmmRexbRm(m, rde), x, 8);
|
||||
}
|
||||
}
|
||||
|
||||
void Op171(struct Machine *m, uint32_t rde) {
|
||||
switch (ModrmReg(rde)) {
|
||||
case 2:
|
||||
SseUdqIb(m, rde, 0);
|
||||
break;
|
||||
case 4:
|
||||
SseUdqIb(m, rde, 1);
|
||||
break;
|
||||
case 6:
|
||||
SseUdqIb(m, rde, 2);
|
||||
break;
|
||||
default:
|
||||
OpUd(m, rde);
|
||||
}
|
||||
}
|
||||
|
||||
void Op172(struct Machine *m, uint32_t rde) {
|
||||
switch (ModrmReg(rde)) {
|
||||
case 2:
|
||||
SseUdqIb(m, rde, 3);
|
||||
break;
|
||||
case 4:
|
||||
SseUdqIb(m, rde, 4);
|
||||
break;
|
||||
case 6:
|
||||
SseUdqIb(m, rde, 5);
|
||||
break;
|
||||
default:
|
||||
OpUd(m, rde);
|
||||
}
|
||||
}
|
||||
|
||||
void Op173(struct Machine *m, uint32_t rde) {
|
||||
switch (ModrmReg(rde)) {
|
||||
case 2:
|
||||
SseUdqIb(m, rde, 6);
|
||||
break;
|
||||
case 3:
|
||||
SseUdqIb(m, rde, 7);
|
||||
break;
|
||||
case 6:
|
||||
SseUdqIb(m, rde, 8);
|
||||
break;
|
||||
case 7:
|
||||
SseUdqIb(m, rde, 9);
|
||||
break;
|
||||
default:
|
||||
OpUd(m, rde);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -4,96 +4,83 @@
|
|||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
typedef void (*sse_f)(void *, void *, void *);
|
||||
|
||||
enum OpSseUdqIbKernel {
|
||||
kOpSseUdqIbPsrlw,
|
||||
kOpSseUdqIbPsraw,
|
||||
kOpSseUdqIbPsllw,
|
||||
kOpSseUdqIbPsrld,
|
||||
kOpSseUdqIbPsrad,
|
||||
kOpSseUdqIbPslld,
|
||||
kOpSseUdqIbPsrlq,
|
||||
kOpSseUdqIbPsrldq,
|
||||
kOpSseUdqIbPsllq,
|
||||
kOpSseUdqIbPslldq,
|
||||
};
|
||||
|
||||
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 Op171(struct Machine *, uint32_t);
|
||||
void Op172(struct Machine *, uint32_t);
|
||||
void Op173(struct Machine *, uint32_t);
|
||||
void OpSsePabsb(struct Machine *, uint32_t);
|
||||
void OpSsePabsd(struct Machine *, uint32_t);
|
||||
void OpSsePabsw(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 OpSsePacksswb(struct Machine *, uint32_t);
|
||||
void OpSsePackuswb(struct Machine *, uint32_t);
|
||||
void OpSsePaddb(struct Machine *, uint32_t);
|
||||
void OpSsePaddd(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 OpSsePaddusb(struct Machine *, uint32_t);
|
||||
void OpSsePaddusw(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 OpSsePalignr(struct Machine *, uint32_t);
|
||||
void OpSsePand(struct Machine *, uint32_t);
|
||||
void OpSsePandn(struct Machine *, uint32_t);
|
||||
void OpSsePavgb(struct Machine *, uint32_t);
|
||||
void OpSsePavgw(struct Machine *, uint32_t);
|
||||
void OpSsePcmpeqb(struct Machine *, uint32_t);
|
||||
void OpSsePcmpeqd(struct Machine *, uint32_t);
|
||||
void OpSsePcmpeqw(struct Machine *, uint32_t);
|
||||
void OpSsePcmpgtb(struct Machine *, uint32_t);
|
||||
void OpSsePcmpgtd(struct Machine *, uint32_t);
|
||||
void OpSsePcmpgtw(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 OpSsePhaddw(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 OpSsePhsubw(struct Machine *, uint32_t);
|
||||
void OpSsePmaddubsw(struct Machine *, uint32_t);
|
||||
void OpSsePmaddwd(struct Machine *, uint32_t);
|
||||
void OpSsePmaxsw(struct Machine *, uint32_t);
|
||||
void OpSsePmaxub(struct Machine *, uint32_t);
|
||||
void OpSsePminsw(struct Machine *, uint32_t);
|
||||
void OpSsePminub(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 OpSsePmulhuw(struct Machine *, uint32_t);
|
||||
void OpSsePmulhw(struct Machine *, uint32_t);
|
||||
void OpSsePmulld(struct Machine *, uint32_t);
|
||||
void OpSsePmullw(struct Machine *, uint32_t);
|
||||
void OpSsePmuludq(struct Machine *, uint32_t);
|
||||
void OpSsePor(struct Machine *, uint32_t);
|
||||
void OpSsePsadbw(struct Machine *, uint32_t);
|
||||
void OpSsePshufb(struct Machine *, uint32_t);
|
||||
void OpSsePsignb(struct Machine *, uint32_t);
|
||||
void OpSsePsignd(struct Machine *, uint32_t);
|
||||
void OpSsePsignw(struct Machine *, uint32_t);
|
||||
void OpSsePslldv(struct Machine *, uint32_t);
|
||||
void OpSsePsllqv(struct Machine *, uint32_t);
|
||||
void OpSsePsllwv(struct Machine *, uint32_t);
|
||||
void OpSsePsradv(struct Machine *, uint32_t);
|
||||
void OpSsePsrawv(struct Machine *, uint32_t);
|
||||
void OpSsePsrldv(struct Machine *, uint32_t);
|
||||
void OpSsePsrlqv(struct Machine *, uint32_t);
|
||||
void OpSsePsrlwv(struct Machine *, uint32_t);
|
||||
void OpSsePsubb(struct Machine *, uint32_t);
|
||||
void OpSsePsubd(struct Machine *, uint32_t);
|
||||
void OpSsePsubq(struct Machine *, uint32_t);
|
||||
void OpSsePsubsb(struct Machine *, uint32_t);
|
||||
void OpSsePsubsw(struct Machine *, uint32_t);
|
||||
void OpSsePsubusb(struct Machine *, uint32_t);
|
||||
void OpSsePsubusw(struct Machine *, uint32_t);
|
||||
void OpSsePsubw(struct Machine *, uint32_t);
|
||||
void OpSsePunpckhbw(struct Machine *, uint32_t);
|
||||
void OpSsePunpckhdq(struct Machine *, uint32_t);
|
||||
void OpSsePunpckhqdq(struct Machine *, uint32_t);
|
||||
void OpSsePunpckhwd(struct Machine *, uint32_t);
|
||||
void OpSsePunpcklbw(struct Machine *, uint32_t);
|
||||
void OpSsePunpckldq(struct Machine *, uint32_t);
|
||||
void OpSsePunpcklqdq(struct Machine *, uint32_t);
|
||||
void OpSsePunpcklwd(struct Machine *, uint32_t);
|
||||
void OpSsePxor(struct Machine *, uint32_t);
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
|
|
|
@ -56,12 +56,10 @@ static uint64_t ReadStackWord(uint8_t *p, uint32_t osz) {
|
|||
}
|
||||
}
|
||||
|
||||
void Push(struct Machine *m, uint32_t rde, uint64_t x) {
|
||||
static void PushN(struct Machine *m, uint32_t rde, uint64_t x, unsigned osz) {
|
||||
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;
|
||||
|
@ -84,18 +82,21 @@ void Push(struct Machine *m, uint32_t rde, uint64_t x) {
|
|||
EndStore(m, v, osz, p, b);
|
||||
}
|
||||
|
||||
void Push(struct Machine *m, uint32_t rde, uint64_t x) {
|
||||
PushN(m, rde, x, kStackOsz[m->xedd->op.osz][Mode(rde)]);
|
||||
}
|
||||
|
||||
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));
|
||||
PushN(m, rde, ReadStackWord(RegRexbSrm(m, rde), osz), osz);
|
||||
}
|
||||
|
||||
uint64_t Pop(struct Machine *m, uint32_t rde, uint16_t extra) {
|
||||
static uint64_t PopN(struct Machine *m, uint32_t rde, uint16_t extra,
|
||||
unsigned osz) {
|
||||
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);
|
||||
|
@ -117,10 +118,16 @@ uint64_t Pop(struct Machine *m, uint32_t rde, uint16_t extra) {
|
|||
return ReadStackWord(AccessRam(m, v, osz, p, b, true), osz);
|
||||
}
|
||||
|
||||
uint64_t Pop(struct Machine *m, uint32_t rde, uint16_t extra) {
|
||||
return PopN(m, rde, extra, kStackOsz[m->xedd->op.osz][Mode(rde)]);
|
||||
}
|
||||
|
||||
void OpPopZvq(struct Machine *m, uint32_t rde) {
|
||||
uint64_t x;
|
||||
x = Pop(m, rde, 0);
|
||||
switch (kStackOsz[m->xedd->op.osz][Mode(rde)]) {
|
||||
unsigned osz;
|
||||
osz = kStackOsz[m->xedd->op.osz][Mode(rde)];
|
||||
x = PopN(m, rde, 0, osz);
|
||||
switch (osz) {
|
||||
case 8:
|
||||
case 4:
|
||||
Write64(RegRexbSrm(m, rde), x);
|
||||
|
@ -175,8 +182,8 @@ void OpLeave(struct Machine *m, uint32_t rde) {
|
|||
}
|
||||
}
|
||||
|
||||
void OpRet(struct Machine *m, uint32_t rde, uint16_t n) {
|
||||
m->ip = Pop(m, rde, n);
|
||||
void OpRet(struct Machine *m, uint32_t rde) {
|
||||
m->ip = Pop(m, rde, m->xedd->op.uimm0);
|
||||
}
|
||||
|
||||
void OpBofram(struct Machine *m, uint32_t rde) {
|
||||
|
@ -203,7 +210,7 @@ void OpPopEvq(struct Machine *m, uint32_t rde) {
|
|||
Pop(m, rde, 0));
|
||||
}
|
||||
|
||||
static void Pushaw(struct Machine *m, uint32_t rde) {
|
||||
static relegated void Pushaw(struct Machine *m, uint32_t rde) {
|
||||
uint16_t v;
|
||||
uint8_t b[8][2];
|
||||
memcpy(b[0], m->di, 2);
|
||||
|
@ -218,7 +225,7 @@ static void Pushaw(struct Machine *m, uint32_t rde) {
|
|||
VirtualRecv(m, Read64(m->ss) + v, b, sizeof(b));
|
||||
}
|
||||
|
||||
static void Pushad(struct Machine *m, uint32_t rde) {
|
||||
static relegated void Pushad(struct Machine *m, uint32_t rde) {
|
||||
uint32_t v;
|
||||
uint8_t b[8][4];
|
||||
memcpy(b[0], m->di, 4);
|
||||
|
@ -233,7 +240,35 @@ static void Pushad(struct Machine *m, uint32_t rde) {
|
|||
VirtualRecv(m, Read64(m->ss) + v, b, sizeof(b));
|
||||
}
|
||||
|
||||
void OpPusha(struct Machine *m, uint32_t rde) {
|
||||
static relegated 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 relegated 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);
|
||||
}
|
||||
|
||||
relegated void OpPusha(struct Machine *m, uint32_t rde) {
|
||||
switch (Eamode(rde)) {
|
||||
case XED_MODE_REAL:
|
||||
Pushaw(m, rde);
|
||||
|
@ -248,35 +283,7 @@ void OpPusha(struct Machine *m, uint32_t rde) {
|
|||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
relegated void OpPopa(struct Machine *m, uint32_t rde) {
|
||||
switch (Eamode(rde)) {
|
||||
case XED_MODE_REAL:
|
||||
Popaw(m, rde);
|
||||
|
@ -290,3 +297,15 @@ void OpPopa(struct Machine *m, uint32_t rde) {
|
|||
unreachable;
|
||||
}
|
||||
}
|
||||
|
||||
relegated void OpCallf(struct Machine *m, uint32_t rde) {
|
||||
Push(m, rde, Read64(m->cs) >> 4);
|
||||
Push(m, rde, m->ip);
|
||||
Write64(m->cs, m->xedd->op.uimm0 << 4);
|
||||
m->ip = m->xedd->op.disp & (Osz(rde) ? 0xffff : 0xffffffff);
|
||||
}
|
||||
|
||||
relegated void OpRetf(struct Machine *m, uint32_t rde) {
|
||||
m->ip = Pop(m, rde, 0);
|
||||
Write64(m->cs, Pop(m, rde, m->xedd->op.uimm0) << 4);
|
||||
}
|
||||
|
|
|
@ -7,7 +7,8 @@ COSMOPOLITAN_C_START_
|
|||
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 OpRet(struct Machine *, uint32_t);
|
||||
void OpRetf(struct Machine *, uint32_t);
|
||||
void OpLeave(struct Machine *, uint32_t);
|
||||
void OpCallEq(struct Machine *, uint32_t);
|
||||
void OpBofram(struct Machine *, uint32_t);
|
||||
|
@ -20,6 +21,7 @@ void PushVq(struct Machine *, uint32_t);
|
|||
void OpJmpEq(struct Machine *, uint32_t);
|
||||
void OpPusha(struct Machine *, uint32_t);
|
||||
void OpPopa(struct Machine *, uint32_t);
|
||||
void OpCallf(struct Machine *, uint32_t);
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
|
|
|
@ -21,9 +21,11 @@
|
|||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/ioctl.h"
|
||||
#include "libc/calls/struct/iovec.h"
|
||||
#include "libc/calls/struct/rusage.h"
|
||||
#include "libc/calls/struct/sigaction-linux.h"
|
||||
#include "libc/calls/struct/sigaction.h"
|
||||
#include "libc/calls/struct/stat.h"
|
||||
#include "libc/calls/struct/termios.h"
|
||||
#include "libc/calls/struct/timespec.h"
|
||||
#include "libc/calls/struct/timeval.h"
|
||||
#include "libc/calls/struct/winsize.h"
|
||||
|
@ -41,10 +43,14 @@
|
|||
#include "libc/sysv/consts/f.h"
|
||||
#include "libc/sysv/consts/fd.h"
|
||||
#include "libc/sysv/consts/ipproto.h"
|
||||
#include "libc/sysv/consts/lock.h"
|
||||
#include "libc/sysv/consts/madv.h"
|
||||
#include "libc/sysv/consts/map.h"
|
||||
#include "libc/sysv/consts/msync.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
#include "libc/sysv/consts/ok.h"
|
||||
#include "libc/sysv/consts/prot.h"
|
||||
#include "libc/sysv/consts/rusage.h"
|
||||
#include "libc/sysv/consts/sa.h"
|
||||
#include "libc/sysv/consts/sig.h"
|
||||
#include "libc/sysv/consts/so.h"
|
||||
|
@ -52,6 +58,7 @@
|
|||
#include "libc/sysv/consts/sol.h"
|
||||
#include "libc/sysv/consts/tcp.h"
|
||||
#include "libc/sysv/consts/termios.h"
|
||||
#include "libc/sysv/consts/w.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
#include "libc/time/struct/timezone.h"
|
||||
#include "libc/time/time.h"
|
||||
|
@ -67,6 +74,14 @@
|
|||
|
||||
#define AT_FDCWD_LINUX -100
|
||||
#define TIOCGWINSZ_LINUX 0x5413
|
||||
#define TCGETS_LINUX 0x5401
|
||||
#define TCSETS_LINUX 0x5402
|
||||
#define TCSETSW_LINUX 0x5403
|
||||
#define TCSETSF_LINUX 0x5404
|
||||
#define ISIG_LINUX 0b0000000000000001
|
||||
#define ICANON_LINUX 0b0000000000000010
|
||||
#define ECHO_LINUX 0b0000000000001000
|
||||
#define OPOST_LINUX 0b0000000000000001
|
||||
|
||||
#define POINTER(x) ((void *)(intptr_t)(x))
|
||||
#define UNPOINTER(x) ((int64_t)(intptr_t)(x))
|
||||
|
@ -322,8 +337,8 @@ static unsigned XlatOpenFlags(unsigned flags) {
|
|||
return res;
|
||||
}
|
||||
|
||||
static int XlatFcntlCmd(int cmd) {
|
||||
switch (cmd) {
|
||||
static int XlatFcntlCmd(int x) {
|
||||
switch (x) {
|
||||
XLAT(1, F_GETFD);
|
||||
XLAT(2, F_SETFD);
|
||||
XLAT(3, F_GETFL);
|
||||
|
@ -333,8 +348,8 @@ static int XlatFcntlCmd(int cmd) {
|
|||
}
|
||||
}
|
||||
|
||||
static int XlatFcntlArg(int arg) {
|
||||
switch (arg) {
|
||||
static int XlatFcntlArg(int x) {
|
||||
switch (x) {
|
||||
XLAT(0, 0);
|
||||
XLAT(1, FD_CLOEXEC);
|
||||
default:
|
||||
|
@ -342,6 +357,61 @@ static int XlatFcntlArg(int arg) {
|
|||
}
|
||||
}
|
||||
|
||||
static int XlatAdvice(int x) {
|
||||
switch (x) {
|
||||
XLAT(0, MADV_NORMAL);
|
||||
XLAT(1, MADV_RANDOM);
|
||||
XLAT(2, MADV_SEQUENTIAL);
|
||||
XLAT(3, MADV_WILLNEED);
|
||||
XLAT(4, MADV_DONTNEED);
|
||||
XLAT(8, MADV_FREE);
|
||||
XLAT(12, MADV_MERGEABLE);
|
||||
default:
|
||||
return einval();
|
||||
}
|
||||
}
|
||||
|
||||
static int XlatLock(int x) {
|
||||
unsigned res = 0;
|
||||
if (x & 1) res |= LOCK_SH;
|
||||
if (x & 2) res |= LOCK_EX;
|
||||
if (x & 4) res |= LOCK_NB;
|
||||
if (x & 8) res |= LOCK_UN;
|
||||
return res;
|
||||
}
|
||||
|
||||
static int XlatWait(int x) {
|
||||
unsigned res = 0;
|
||||
if (x & 1) res |= WNOHANG;
|
||||
if (x & 2) res |= WUNTRACED;
|
||||
if (x & 8) res |= WCONTINUED;
|
||||
return res;
|
||||
}
|
||||
|
||||
static int XlatRusage(int x) {
|
||||
switch (x) {
|
||||
XLAT(0, RUSAGE_SELF);
|
||||
XLAT(-1, RUSAGE_CHILDREN);
|
||||
XLAT(1, RUSAGE_THREAD);
|
||||
default:
|
||||
return einval();
|
||||
}
|
||||
}
|
||||
|
||||
static void *VirtualSendRead(struct Machine *m, void *dst, int64_t addr,
|
||||
uint64_t n) {
|
||||
VirtualSend(m, dst, addr, n);
|
||||
SetReadAddr(m, addr, n);
|
||||
return dst;
|
||||
}
|
||||
|
||||
static void *VirtualRecvWrite(struct Machine *m, int64_t addr, void *dst,
|
||||
uint64_t n) {
|
||||
VirtualRecv(m, addr, dst, n);
|
||||
SetWriteAddr(m, addr, n);
|
||||
return dst;
|
||||
}
|
||||
|
||||
static struct sigaction *CoerceSigactionToCosmo(
|
||||
struct sigaction *dst, const struct sigaction$linux *src) {
|
||||
if (!src) return NULL;
|
||||
|
@ -364,6 +434,25 @@ static struct sigaction$linux *CoerceSigactionToLinux(
|
|||
return dst;
|
||||
}
|
||||
|
||||
static int OpArchPrctl(struct Machine *m, int code, int64_t addr) {
|
||||
switch (code) {
|
||||
case ARCH_SET_GS:
|
||||
Write64(m->gs, addr);
|
||||
return 0;
|
||||
case ARCH_SET_FS:
|
||||
Write64(m->fs, addr);
|
||||
return 0;
|
||||
case ARCH_GET_GS:
|
||||
VirtualRecvWrite(m, addr, m->gs, 8);
|
||||
return 0;
|
||||
case ARCH_GET_FS:
|
||||
VirtualRecvWrite(m, addr, m->fs, 8);
|
||||
return 0;
|
||||
default:
|
||||
return einval();
|
||||
}
|
||||
}
|
||||
|
||||
static int OpMprotect(struct Machine *m, int64_t addr, uint64_t len, int prot) {
|
||||
return 0;
|
||||
}
|
||||
|
@ -373,6 +462,25 @@ static int OpMadvise(struct Machine *m, int64_t addr, size_t length,
|
|||
return enosys();
|
||||
}
|
||||
|
||||
static int64_t OpBrk(struct Machine *m, int64_t addr) {
|
||||
void *real;
|
||||
if (addr && addr != m->brk) {
|
||||
if (addr < m->brk) {
|
||||
addr = ROUNDUP(addr, FRAMESIZE);
|
||||
FreePml4t(m->cr3, addr, m->brk - addr, free, munmap);
|
||||
m->brk = addr;
|
||||
} else {
|
||||
addr = ROUNDUP(addr, FRAMESIZE);
|
||||
if ((real = mmap(NULL, addr - m->brk, PROT_READ | PROT_WRITE,
|
||||
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0)) != MAP_FAILED) {
|
||||
CHECK_NE(-1, RegisterMemory(m, m->brk, real, addr - m->brk));
|
||||
m->brk = addr;
|
||||
}
|
||||
}
|
||||
}
|
||||
return m->brk;
|
||||
}
|
||||
|
||||
static int64_t OpMmap(struct Machine *m, int64_t virt, size_t size, int prot,
|
||||
int flags, int fd, int64_t off) {
|
||||
void *real;
|
||||
|
@ -417,8 +525,7 @@ static struct iovec *GetDirectIov(struct Machine *m, int64_t addr, int *len) {
|
|||
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);
|
||||
VirtualSendRead(m, iov, addr, n);
|
||||
for (i = 0; i < *len; ++i) {
|
||||
size = iov[i].iov_len;
|
||||
if ((iov[i].iov_base = GetDirectBuf(
|
||||
|
@ -544,16 +651,14 @@ static int OpAccept4(struct Machine *m, int fd, int64_t addraddr,
|
|||
uint8_t b[4];
|
||||
uint32_t addrsize;
|
||||
if ((fd = XlatFd(m, fd)) == -1) return -1;
|
||||
VirtualSend(m, b, addrsizeaddr, 4);
|
||||
SetReadAddr(m, addrsizeaddr, 4);
|
||||
VirtualSendRead(m, b, addrsizeaddr, 4);
|
||||
addrsize = Read32(b);
|
||||
if (!(addr = malloc(addrsize))) return -1;
|
||||
if ((i = rc = MachineFdAdd(&m->fds)) != -1) {
|
||||
if ((rc = accept4(fd, addr, &addrsize, XlatSocketFlags(flags))) != -1) {
|
||||
Write32(b, addrsize);
|
||||
VirtualRecv(m, addrsizeaddr, b, 4);
|
||||
VirtualRecv(m, addraddr, addr, addrsize);
|
||||
SetWriteAddr(m, addraddr, addrsize);
|
||||
VirtualRecvWrite(m, addraddr, addr, addrsize);
|
||||
m->fds.p[i].cb = &kMachineFdCbHost;
|
||||
m->fds.p[i].fd = rc;
|
||||
rc = i;
|
||||
|
@ -572,8 +677,7 @@ static int OpConnectBind(struct Machine *m, int fd, intptr_t addraddr,
|
|||
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);
|
||||
VirtualSendRead(m, addr, addraddr, addrsize);
|
||||
rc = impl(fd, addr, addrsize);
|
||||
free(addr);
|
||||
return rc;
|
||||
|
@ -597,8 +701,7 @@ static int OpSetsockopt(struct Machine *m, int fd, int level, int optname,
|
|||
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);
|
||||
VirtualSendRead(m, optval, optvaladdr, optvalsize);
|
||||
rc = setsockopt(fd, level, optname, optval, optvalsize);
|
||||
free(optval);
|
||||
return rc;
|
||||
|
@ -626,17 +729,63 @@ 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) {
|
||||
static int IoctlTiocgwinsz(struct Machine *m, int fd, int64_t addr,
|
||||
int (*fn)(int, uint64_t, void *)) {
|
||||
int rc;
|
||||
struct winsize ws;
|
||||
if ((rc = fn(fd, TIOCGWINSZ, &ws)) != -1) {
|
||||
VirtualRecvWrite(m, addr, &ws, sizeof(ws));
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int IoctlTcgets(struct Machine *m, int fd, int64_t addr,
|
||||
int (*fn)(int, uint64_t, void *)) {
|
||||
int rc;
|
||||
struct termios tio, tio2;
|
||||
if ((rc = fn(fd, TCGETS, &tio)) != -1) {
|
||||
memcpy(&tio2, &tio, sizeof(tio));
|
||||
tio2.c_iflag = 0;
|
||||
if (tio.c_iflag & ISIG) tio2.c_iflag |= ISIG_LINUX;
|
||||
if (tio.c_iflag & ICANON) tio2.c_iflag |= ICANON_LINUX;
|
||||
if (tio.c_iflag & ECHO) tio2.c_iflag |= ECHO_LINUX;
|
||||
tio2.c_oflag = 0;
|
||||
if (tio.c_oflag & OPOST) tio2.c_oflag |= OPOST_LINUX;
|
||||
VirtualRecvWrite(m, addr, &tio2, sizeof(tio2));
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int IoctlTcsets(struct Machine *m, int fd, int64_t request, int64_t addr,
|
||||
int (*fn)(int, uint64_t, void *)) {
|
||||
struct termios tio, tio2;
|
||||
VirtualSendRead(m, &tio, addr, sizeof(tio));
|
||||
memcpy(&tio2, &tio, sizeof(tio));
|
||||
tio2.c_iflag = 0;
|
||||
if (tio.c_iflag & ISIG_LINUX) tio2.c_iflag |= ISIG;
|
||||
if (tio.c_iflag & ICANON_LINUX) tio2.c_iflag |= ICANON;
|
||||
if (tio.c_iflag & ECHO_LINUX) tio2.c_iflag |= ECHO;
|
||||
tio2.c_oflag = 0;
|
||||
if (tio.c_oflag & OPOST_LINUX) tio2.c_oflag |= OPOST;
|
||||
return fn(fd, request, &tio2);
|
||||
}
|
||||
|
||||
static int OpIoctl(struct Machine *m, int fd, uint64_t request, int64_t addr) {
|
||||
int (*fn)(int, uint64_t, void *);
|
||||
if (!(0 <= fd && fd < m->fds.i) || !m->fds.p[fd].cb) return ebadf();
|
||||
fn = m->fds.p[fd].cb->ioctl;
|
||||
fd = m->fds.p[fd].fd;
|
||||
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;
|
||||
return IoctlTiocgwinsz(m, fd, addr, fn);
|
||||
case TCGETS_LINUX:
|
||||
return IoctlTcgets(m, fd, addr, fn);
|
||||
case TCSETS_LINUX:
|
||||
return IoctlTcsets(m, fd, TCSETS, addr, fn);
|
||||
case TCSETSW_LINUX:
|
||||
return IoctlTcsets(m, fd, TCSETSW, addr, fn);
|
||||
case TCSETSF_LINUX:
|
||||
return IoctlTcsets(m, fd, TCSETSF, addr, fn);
|
||||
default:
|
||||
return einval();
|
||||
}
|
||||
|
@ -763,6 +912,19 @@ static int OpFcntl(struct Machine *m, int fd, int cmd, int arg) {
|
|||
return fcntl(fd, cmd, arg);
|
||||
}
|
||||
|
||||
static int OpFadvise(struct Machine *m, int fd, uint64_t offset, uint64_t len,
|
||||
int advice) {
|
||||
if ((fd = XlatFd(m, fd)) == -1) return -1;
|
||||
if ((advice = XlatAdvice(advice)) == -1) return -1;
|
||||
return fadvise(fd, offset, len, advice);
|
||||
}
|
||||
|
||||
static int OpFlock(struct Machine *m, int fd, int lock) {
|
||||
if ((fd = XlatFd(m, fd)) == -1) return -1;
|
||||
if ((lock = XlatLock(lock)) == -1) return -1;
|
||||
return flock(fd, lock);
|
||||
}
|
||||
|
||||
static int OpChdir(struct Machine *m, int64_t path) {
|
||||
return chdir(LoadStr(m, path));
|
||||
}
|
||||
|
@ -813,6 +975,37 @@ static int OpExecve(struct Machine *m, int64_t programaddr, int64_t argvaddr,
|
|||
return enosys();
|
||||
}
|
||||
|
||||
static int OpWait4(struct Machine *m, int pid, int64_t opt_out_wstatus_addr,
|
||||
int options, int64_t opt_out_rusage_addr) {
|
||||
int rc;
|
||||
int32_t wstatus;
|
||||
struct rusage rusage;
|
||||
if ((options = XlatWait(options)) == -1) return -1;
|
||||
if ((rc = wait4(pid, &wstatus, options, &rusage)) != -1) {
|
||||
if (opt_out_wstatus_addr) {
|
||||
VirtualRecvWrite(m, opt_out_wstatus_addr, &wstatus, sizeof(wstatus));
|
||||
}
|
||||
if (opt_out_rusage_addr) {
|
||||
VirtualRecvWrite(m, opt_out_rusage_addr, &rusage, sizeof(rusage));
|
||||
}
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int OpGetrusage(struct Machine *m, int resource, int64_t rusageaddr) {
|
||||
int rc;
|
||||
struct rusage rusage;
|
||||
if ((resource = XlatRusage(resource)) == -1) return -1;
|
||||
if ((rc = getrusage(resource, &rusage)) != -1) {
|
||||
VirtualRecvWrite(m, rusageaddr, &rusage, sizeof(rusage));
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int OpGetrlimit(struct Machine *m, int resource, int64_t rlimitaddr) {
|
||||
return enosys();
|
||||
}
|
||||
|
||||
static int64_t OpGetcwd(struct Machine *m, int64_t bufaddr, size_t size) {
|
||||
size_t n;
|
||||
char *buf;
|
||||
|
@ -821,8 +1014,7 @@ static int64_t OpGetcwd(struct Machine *m, int64_t bufaddr, size_t size) {
|
|||
if (!(buf = malloc(size))) return enomem();
|
||||
if ((getcwd)(buf, size)) {
|
||||
n = strlen(buf);
|
||||
VirtualRecv(m, bufaddr, buf, n);
|
||||
SetWriteAddr(m, bufaddr, n);
|
||||
VirtualRecvWrite(m, bufaddr, buf, n);
|
||||
res = bufaddr;
|
||||
} else {
|
||||
res = -1;
|
||||
|
@ -904,8 +1096,7 @@ static int OpPoll(struct Machine *m, int64_t fdsaddr, uint64_t nfds,
|
|||
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);
|
||||
VirtualSendRead(m, fds, fdsaddr, n);
|
||||
rc = poll(fds, nfds, timeout_ms);
|
||||
free(fds);
|
||||
return rc;
|
||||
|
@ -924,17 +1115,53 @@ static int OpSigprocmask(struct Machine *m, int how, int64_t setaddr,
|
|||
if (setaddr) {
|
||||
set = &ss;
|
||||
memset(set, 0, sizeof(ss));
|
||||
VirtualSend(m, set, setaddr, 8);
|
||||
VirtualSendRead(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);
|
||||
if (setaddr) VirtualRecvWrite(m, setaddr, set, 8);
|
||||
if (oldsetaddr) VirtualRecvWrite(m, oldsetaddr, &oldset, 8);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int OpGetPid(struct Machine *m) {
|
||||
return getpid();
|
||||
}
|
||||
|
||||
static int OpGetPpid(struct Machine *m) {
|
||||
return getppid();
|
||||
}
|
||||
|
||||
static int OpKill(struct Machine *m, int pid, int sig) {
|
||||
return kill(pid, sig);
|
||||
}
|
||||
|
||||
static int OpGetUid(struct Machine *m) {
|
||||
return getuid();
|
||||
}
|
||||
|
||||
static int OpGetGid(struct Machine *m) {
|
||||
return getgid();
|
||||
}
|
||||
|
||||
static int OpGetTid(struct Machine *m) {
|
||||
return gettid();
|
||||
}
|
||||
|
||||
static int OpSchedYield(struct Machine *m) {
|
||||
return sched_yield();
|
||||
}
|
||||
|
||||
static int OpAlarm(struct Machine *m, unsigned seconds) {
|
||||
return alarm(seconds);
|
||||
}
|
||||
|
||||
static int OpPause(struct Machine *m) {
|
||||
return pause();
|
||||
}
|
||||
|
||||
static int DoOpen(struct Machine *m, int64_t path, int flags, int mode) {
|
||||
return OpOpenat(m, AT_FDCWD_LINUX, path, flags, mode);
|
||||
}
|
||||
|
@ -983,6 +1210,7 @@ void OpSyscall(struct Machine *m, uint32_t rde) {
|
|||
SYSCALL(0x01A, OpMsync(m, di, si, dx));
|
||||
SYSCALL(0x00A, OpMprotect(m, di, si, dx));
|
||||
SYSCALL(0x00B, OpMunmap(m, di, si));
|
||||
SYSCALL(0x00C, OpBrk(m, di));
|
||||
SYSCALL(0x00D, OpSigaction(m, di, si, dx));
|
||||
SYSCALL(0x00E, OpSigprocmask(m, di, si, dx));
|
||||
SYSCALL(0x010, OpIoctl(m, di, si, dx));
|
||||
|
@ -993,16 +1221,16 @@ void OpSyscall(struct Machine *m, uint32_t rde) {
|
|||
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(0x018, OpSchedYield(m));
|
||||
SYSCALL(0x01C, OpMadvise(m, di, si, dx));
|
||||
SYSCALL(0x020, OpDup(m, di));
|
||||
SYSCALL(0x021, OpDup2(m, di, si));
|
||||
SYSCALL(0x022, pause());
|
||||
SYSCALL(0x022, OpPause(m));
|
||||
SYSCALL(0x023, OpNanosleep(m, di, si));
|
||||
SYSCALL(0x024, getitimer(di, PNN(si)));
|
||||
SYSCALL(0x025, alarm(di));
|
||||
SYSCALL(0x025, OpAlarm(m, di));
|
||||
SYSCALL(0x026, setitimer(di, PNN(si), P(dx)));
|
||||
SYSCALL(0x027, getpid());
|
||||
SYSCALL(0x027, OpGetPid(m));
|
||||
SYSCALL(0x028, sendfile(di, si, P(dx), r0));
|
||||
SYSCALL(0x029, OpSocket(m, di, si, dx));
|
||||
SYSCALL(0x02A, OpConnect(m, di, si, dx));
|
||||
|
@ -1018,11 +1246,11 @@ void OpSyscall(struct Machine *m, uint32_t rde) {
|
|||
SYSCALL(0x037, getsockopt(di, si, dx, PNN(r0), 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(0x03D, OpWait4(m, di, si, dx, r0));
|
||||
SYSCALL(0x03E, OpKill(m, di, si));
|
||||
SYSCALL(0x03F, uname(P(di)));
|
||||
SYSCALL(0x048, OpFcntl(m, di, si, dx));
|
||||
SYSCALL(0x049, flock(di, si));
|
||||
SYSCALL(0x049, OpFlock(m, di, si));
|
||||
SYSCALL(0x04A, OpFsync(m, di));
|
||||
SYSCALL(0x04B, OpFdatasync(m, di));
|
||||
SYSCALL(0x04C, OpTruncate(m, di, si));
|
||||
|
@ -1039,13 +1267,13 @@ void OpSyscall(struct Machine *m, uint32_t rde) {
|
|||
SYSCALL(0x05A, OpChmod(m, 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)));
|
||||
SYSCALL(0x061, OpGetrlimit(m, di, si));
|
||||
SYSCALL(0x062, OpGetrusage(m, di, si));
|
||||
SYSCALL(0x063, sysinfo(PNN(di)));
|
||||
SYSCALL(0x064, times(PNN(di)));
|
||||
SYSCALL(0x066, getuid());
|
||||
SYSCALL(0x068, getgid());
|
||||
SYSCALL(0x06E, getppid());
|
||||
SYSCALL(0x066, OpGetUid(m));
|
||||
SYSCALL(0x068, OpGetGid(m));
|
||||
SYSCALL(0x06E, OpGetPpid(m));
|
||||
SYSCALL(0x075, setresuid(di, si, dx));
|
||||
SYSCALL(0x077, setresgid(di, si, dx));
|
||||
SYSCALL(0x082, OpSigsuspend(m, di));
|
||||
|
@ -1055,10 +1283,10 @@ void OpSyscall(struct Machine *m, uint32_t rde) {
|
|||
SYSCALL(0x0A0, setrlimit(di, P(si)));
|
||||
SYSCALL(0x084, utime(PNN(di), PNN(si)));
|
||||
SYSCALL(0x0EB, utimes(P(di), P(si)));
|
||||
SYSCALL(0x09E, arch_prctl(di, si));
|
||||
SYSCALL(0x0BA, gettid());
|
||||
SYSCALL(0x09E, OpArchPrctl(m, di, si));
|
||||
SYSCALL(0x0BA, OpGetTid(m));
|
||||
SYSCALL(0x0CB, sched_setaffinity(di, si, P(dx)));
|
||||
SYSCALL(0x0DD, fadvise(di, si, dx, r0));
|
||||
SYSCALL(0x0DD, OpFadvise(m, di, si, dx, r0));
|
||||
SYSCALL(0x0E4, OpClockGettime(m, di, si));
|
||||
SYSCALL(0x101, OpOpenat(m, di, si, dx, r0));
|
||||
SYSCALL(0x102, mkdirat(XlatAfd(m, di), P(si), dx));
|
||||
|
@ -1075,7 +1303,7 @@ void OpSyscall(struct Machine *m, uint32_t rde) {
|
|||
SYSCALL(0x177, vmsplice(di, P(si), dx, r0));
|
||||
CASE(0xE7, HaltMachine(m, di | 0x100));
|
||||
default:
|
||||
DEBUGF("missing syscall %03x", ax);
|
||||
/* LOGF("missing syscall 0x%03x", ax); */
|
||||
ax = enosys();
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -49,7 +49,6 @@ void ThrowProtectionFault(struct Machine *m) {
|
|||
}
|
||||
|
||||
void OpUd(struct Machine *m, uint32_t rde) {
|
||||
DebugBreak();
|
||||
m->ip -= m->xedd->length;
|
||||
HaltMachine(m, kMachineUndefinedInstruction);
|
||||
}
|
||||
|
|
|
@ -33,13 +33,9 @@ void OpPause(struct Machine *m, uint32_t rde) {
|
|||
*/
|
||||
void OpRdtsc(struct Machine *m, uint32_t rde) {
|
||||
uint64_t c;
|
||||
#ifdef __x86_64__
|
||||
c = rdtsc();
|
||||
#else
|
||||
struct timespec ts;
|
||||
clock_gettime(CLOCK_MONOTONIC, &ts);
|
||||
c = ts.tv_sec * 1000000000 + ts.tv_nsec;
|
||||
#endif
|
||||
Write64(m->ax, (c >> 000) & 0xffffffff);
|
||||
Write64(m->dx, (c >> 040) & 0xffffffff);
|
||||
}
|
||||
|
@ -50,5 +46,5 @@ void OpRdtscp(struct Machine *m, uint32_t rde) {
|
|||
core = 0;
|
||||
node = 0;
|
||||
tscaux = (node & 0xfff) << 12 | (core & 0xfff);
|
||||
Write64(m->ax, tscaux & 0xffffffff);
|
||||
Write64(m->cx, tscaux & 0xffffffff);
|
||||
}
|
||||
|
|
145
tool/build/lisp.c
Normal file
145
tool/build/lisp.c
Normal file
|
@ -0,0 +1,145 @@
|
|||
/*-*- 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/runtime/runtime.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
|
||||
#define T short
|
||||
|
||||
#define CONS 0
|
||||
#define ATOM 1
|
||||
#define INTEGER 2
|
||||
|
||||
#define NIL OBJECT(CONS, 0)
|
||||
#define TYPE(x) ((x)&3)
|
||||
#define VALUE(x) ((x) >> 2)
|
||||
#define OBJECT(t, v) ((v) << 2 | (t))
|
||||
|
||||
static T Mi, Si;
|
||||
static T M[2048];
|
||||
static char S[2048];
|
||||
|
||||
static noreturn void Die(void) {
|
||||
abort();
|
||||
}
|
||||
|
||||
static int Parse(const char *s) {
|
||||
int x, j;
|
||||
for (;;) {
|
||||
switch (*s & 0xff) {
|
||||
case ' ':
|
||||
case '\t':
|
||||
case '\r':
|
||||
case '\n':
|
||||
case '\v':
|
||||
++s;
|
||||
break;
|
||||
case 'A' ... 'Z':
|
||||
x = Si;
|
||||
do {
|
||||
S[Si++] = *s++;
|
||||
} while ('A' <= *s && *s <= 'Z');
|
||||
S[Si++] = 0;
|
||||
M[++Mi] = OBJECT(ATOM, x);
|
||||
return Mi;
|
||||
case '0' ... '9':
|
||||
x = 0;
|
||||
do {
|
||||
x *= 10;
|
||||
x += *s++ - '0';
|
||||
} while ('0' <= *s && *s <= '9');
|
||||
M[++Mi] = OBJECT(INTEGER, x);
|
||||
return Mi;
|
||||
default:
|
||||
Die();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int PrintChar(int c) {
|
||||
return putc(c, stdout);
|
||||
}
|
||||
|
||||
static void PrintString(const char *s) {
|
||||
while (*s) PrintChar(*s++);
|
||||
}
|
||||
|
||||
static void PrintInteger(int x) {
|
||||
int q, r;
|
||||
q = x / 10;
|
||||
r = x % 10;
|
||||
if (q) PrintInteger(q);
|
||||
PrintChar('0' + r);
|
||||
}
|
||||
|
||||
static void PrintObject(int i) {
|
||||
int j, x;
|
||||
switch (TYPE(M[i])) {
|
||||
case CONS:
|
||||
if ((i = VALUE(M[i]))) {
|
||||
PrintChar('(');
|
||||
PrintObject(i);
|
||||
for (;;) {
|
||||
if (TYPE(M[i + 1]) == CONS) {
|
||||
if (!(i = VALUE(M[i + 1]))) break;
|
||||
PrintChar(' ');
|
||||
PrintObject(i);
|
||||
} else {
|
||||
PrintString(" . ");
|
||||
PrintObject(i + 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
PrintChar(')');
|
||||
} else {
|
||||
PrintString("NIL");
|
||||
}
|
||||
break;
|
||||
case ATOM:
|
||||
for (j = VALUE(M[i]); S[j]; ++j) {
|
||||
PrintChar(S[j]);
|
||||
}
|
||||
break;
|
||||
case INTEGER:
|
||||
PrintInteger(VALUE(M[i]));
|
||||
break;
|
||||
default:
|
||||
unreachable;
|
||||
}
|
||||
}
|
||||
|
||||
static void Print(int i) {
|
||||
PrintObject(i);
|
||||
PrintChar('\n');
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
int i;
|
||||
|
||||
M[1] = OBJECT(CONS, 2);
|
||||
M[2] = OBJECT(INTEGER, 123);
|
||||
M[3] = OBJECT(CONS, 4);
|
||||
M[4] = OBJECT(INTEGER, 456);
|
||||
M[5] = OBJECT(CONS, 6);
|
||||
M[6] = OBJECT(INTEGER, 789);
|
||||
M[7] = NIL;
|
||||
Print(1);
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -25,6 +25,7 @@
|
|||
#include "libc/bits/bits.h"
|
||||
#include "libc/bits/safemacros.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/struct/stat.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/fmt/fmt.h"
|
||||
#include "libc/log/check.h"
|
||||
|
@ -39,28 +40,42 @@
|
|||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/madv.h"
|
||||
#include "libc/sysv/consts/map.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
#include "libc/sysv/consts/prot.h"
|
||||
#include "libc/x/x.h"
|
||||
#include "third_party/getopt/getopt.h"
|
||||
|
||||
#define MAX_READ FRAMESIZE
|
||||
|
||||
/**
|
||||
* @fileoverview Make dependency generator.
|
||||
*
|
||||
* This program generates Makefile code saying which sources include
|
||||
* which headers, thus improving build invalidation.
|
||||
* This generates Makefile code for source -> header dependencies.
|
||||
*
|
||||
* The same thing can be accomplished using GCC's -M flag. This tool is
|
||||
* much faster. It's designed to process over 9,000 sources to generate
|
||||
* 50k+ lines of make code in ~80ms using one core and a meg of ram.
|
||||
* Includes look like this:
|
||||
*
|
||||
* - #include "root/of/repository/foo.h"
|
||||
* - .include "root/of/repository/foo.inc"
|
||||
*
|
||||
* They do not look like this:
|
||||
*
|
||||
* - #include "foo.h"
|
||||
* - # include "foo.h"
|
||||
* - #include "foo.h"
|
||||
*
|
||||
* Only the first 64kb of each source file is considered.
|
||||
*/
|
||||
|
||||
static const char kSourceExts[][5] = {".s", ".S", ".c", ".cc", ".cpp"};
|
||||
static alignas(16) const char kIncludePrefix[] = "include \"";
|
||||
alignas(16) const char kIncludePrefix[] = "include \"";
|
||||
|
||||
static const char *const kModelessPackages[] = {
|
||||
"libc/nt/",
|
||||
"libc/stubs/",
|
||||
"libc/sysv/",
|
||||
const char kSourceExts[][5] = {".s", ".S", ".c", ".cc", ".cpp"};
|
||||
|
||||
const char *const kIgnorePrefixes[] = {
|
||||
#if 0
|
||||
"libc/sysv/consts/", "libc/sysv/calls/", "libc/nt/kernel32/",
|
||||
"libc/nt/KernelBase/", "libc/nt/advapi32/", "libc/nt/gdi32/",
|
||||
"libc/nt/ntdll/", "libc/nt/user32/", "libc/nt/shell32/",
|
||||
#endif
|
||||
};
|
||||
|
||||
struct Strings {
|
||||
|
@ -69,14 +84,14 @@ struct Strings {
|
|||
};
|
||||
|
||||
struct Source {
|
||||
uint32_t hash; /* 0 means empty w/ triangle probe */
|
||||
uint32_t name; /* strings.p[name] w/ interning */
|
||||
uint32_t id; /* rehashing changes indexes */
|
||||
unsigned hash; /* 0 means empty w/ triangle probe */
|
||||
unsigned name; /* strings.p[name] w/ interning */
|
||||
unsigned id; /* rehashing changes indexes */
|
||||
};
|
||||
|
||||
struct Edge {
|
||||
int32_t from; /* sources.p[from.id] */
|
||||
int32_t to; /* sources.p[to.id] */
|
||||
unsigned from; /* sources.p[from.id] */
|
||||
unsigned to; /* sources.p[to.id] */
|
||||
};
|
||||
|
||||
struct Sources {
|
||||
|
@ -89,27 +104,42 @@ struct Edges {
|
|||
struct Edge *p;
|
||||
};
|
||||
|
||||
int g_sourceid;
|
||||
struct Strings strings;
|
||||
struct Sources sources;
|
||||
struct Edges edges;
|
||||
const char *buildroot;
|
||||
int *visited;
|
||||
char *out;
|
||||
FILE *fout;
|
||||
int *visited;
|
||||
unsigned counter;
|
||||
struct Edges edges;
|
||||
struct Strings strings;
|
||||
struct Sources sources;
|
||||
const char *buildroot;
|
||||
|
||||
static int CompareSourcesById(struct Source *a, struct Source *b) {
|
||||
int CompareSourcesById(struct Source *a, struct Source *b) {
|
||||
return a->id > b->id ? 1 : a->id < b->id ? -1 : 0;
|
||||
}
|
||||
|
||||
static int CompareEdgesByFrom(struct Edge *a, struct Edge *b) {
|
||||
int CompareEdgesByFrom(struct Edge *a, struct Edge *b) {
|
||||
return a->from > b->from ? 1 : a->from < b->from ? -1 : 0;
|
||||
}
|
||||
|
||||
static uint32_t Hash(const void *s, size_t l) {
|
||||
unsigned Hash(const void *s, size_t l) {
|
||||
return max(1, crc32c(0, s, l));
|
||||
}
|
||||
|
||||
unsigned FindFirstFromEdge(unsigned id) {
|
||||
unsigned m, l, r;
|
||||
l = 0;
|
||||
r = edges.i;
|
||||
while (l < r) {
|
||||
m = (l + r) >> 1;
|
||||
if (edges.p[m].from < id) {
|
||||
l = m + 1;
|
||||
} else {
|
||||
r = m;
|
||||
}
|
||||
}
|
||||
return l;
|
||||
}
|
||||
|
||||
void Crunch(void) {
|
||||
size_t i, j;
|
||||
for (i = 0, j = 0; j < sources.n; ++j) {
|
||||
|
@ -140,9 +170,9 @@ void Rehash(void) {
|
|||
free(old.p);
|
||||
}
|
||||
|
||||
uint32_t GetSourceId(const char *name, size_t len) {
|
||||
unsigned GetSourceId(const char *name, size_t len) {
|
||||
size_t i, step;
|
||||
uint32_t hash;
|
||||
unsigned hash;
|
||||
i = 0;
|
||||
hash = Hash(name, len);
|
||||
if (sources.n) {
|
||||
|
@ -167,55 +197,73 @@ uint32_t GetSourceId(const char *name, size_t len) {
|
|||
sources.p[i].hash = hash;
|
||||
sources.p[i].name = CONCAT(&strings.p, &strings.i, &strings.n, name, len);
|
||||
strings.p[strings.i++] = '\0';
|
||||
return (sources.p[i].id = g_sourceid++);
|
||||
return (sources.p[i].id = counter++);
|
||||
}
|
||||
|
||||
bool ShouldSkipSource(const char *src) {
|
||||
unsigned j;
|
||||
for (j = 0; j < ARRAYLEN(kIgnorePrefixes); ++j) {
|
||||
if (startswith(src, kIgnorePrefixes[j])) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
noreturn void OnMissingFile(const char *list, const char *src) {
|
||||
DCHECK_EQ(ENOENT, errno, "%s", src);
|
||||
/*
|
||||
* This code helps GNU Make automatically fix itself when we
|
||||
* delete a source file. It removes o/.../srcs.txt or
|
||||
* o/.../hdrs.txt and exits nonzero. Since we use hyphen
|
||||
* notation on mkdeps related rules, the build will
|
||||
* automatically restart itself.
|
||||
*/
|
||||
fprintf(stderr, "%s %s...\n", "Refreshing", list);
|
||||
unlink(list);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
void LoadRelationships(int argc, char *argv[]) {
|
||||
struct MappedFile mf;
|
||||
const char *p, *pe;
|
||||
size_t i, linecap = 0;
|
||||
char *line = NULL;
|
||||
int fd;
|
||||
ssize_t rc;
|
||||
bool skipme;
|
||||
FILE *finpaths;
|
||||
struct Edge edge;
|
||||
char *line, *buf;
|
||||
unsigned srcid, dependency;
|
||||
size_t i, linecap, inclen, size;
|
||||
const char *p, *pe, *src, *path, *pathend;
|
||||
line = NULL;
|
||||
linecap = 0;
|
||||
inclen = strlen(kIncludePrefix);
|
||||
buf = gc(xmemalign(PAGESIZE, PAGESIZE + MAX_READ + 16));
|
||||
buf += PAGESIZE;
|
||||
buf[-1] = '\n';
|
||||
for (i = optind; i < argc; ++i) {
|
||||
CHECK_NOTNULL((finpaths = fopen(argv[i], "r")));
|
||||
while (getline(&line, &linecap, finpaths) != -1) {
|
||||
if (mapfileread(chomp(line), &mf) == -1) {
|
||||
CHECK_EQ(ENOENT, errno, "%s", line);
|
||||
/*
|
||||
* This code helps GNU Make automatically fix itself when we
|
||||
* delete a source file. It removes o/.../srcs.txt or
|
||||
* o/.../hdrs.txt and exits nonzero. Since we use hyphen
|
||||
* notation on mkdeps related rules, the build will
|
||||
* automatically restart itself.
|
||||
*/
|
||||
fprintf(stderr, "%s %s...\n", "Refreshing", argv[i]);
|
||||
unlink(argv[i]);
|
||||
exit(1);
|
||||
}
|
||||
if (mf.size) {
|
||||
if (mf.size > PAGESIZE) {
|
||||
madvise(mf.addr, mf.size, MADV_WILLNEED | MADV_SEQUENTIAL);
|
||||
}
|
||||
uint32_t sauce = GetSourceId(line, strlen(line));
|
||||
size_t inclen = strlen(kIncludePrefix);
|
||||
p = mf.addr;
|
||||
pe = p + mf.size;
|
||||
while ((p = strstr(p, kIncludePrefix))) {
|
||||
const char *path = p + inclen;
|
||||
const char *pathend = memchr(path, '"', pe - path);
|
||||
if (pathend && (intptr_t)p > (intptr_t)mf.addr &&
|
||||
(p[-1] == '#' || p[-1] == '.') &&
|
||||
(p - 1 == mf.addr || p[-2] == '\n')) {
|
||||
uint32_t dependency = GetSourceId(path, pathend - path);
|
||||
struct Edge edge;
|
||||
edge.from = sauce;
|
||||
edge.to = dependency;
|
||||
append(&edges, &edge);
|
||||
}
|
||||
p = path;
|
||||
src = chomp(line);
|
||||
if (ShouldSkipSource(src)) continue;
|
||||
srcid = GetSourceId(src, strlen(src));
|
||||
if ((fd = open(src, O_RDONLY)) == -1) OnMissingFile(argv[i], src);
|
||||
CHECK_NE(-1, (rc = read(fd, buf, MAX_READ)));
|
||||
close(fd);
|
||||
size = rc;
|
||||
memset(buf + size, 0, 16);
|
||||
for (p = buf, pe = p + size; p < pe; ++p) {
|
||||
p = strstr(p, kIncludePrefix);
|
||||
if (!p) break;
|
||||
path = p + inclen;
|
||||
pathend = memchr(path, '"', pe - path);
|
||||
if (pathend && (p[-1] == '#' || p[-1] == '.') && p[-2] == '\n') {
|
||||
dependency = GetSourceId(path, pathend - path);
|
||||
edge.from = srcid;
|
||||
edge.to = dependency;
|
||||
append(&edges, &edge);
|
||||
p = pathend;
|
||||
}
|
||||
}
|
||||
CHECK_NE(-1, unmapfile(&mf));
|
||||
}
|
||||
CHECK_NE(-1, fclose(finpaths));
|
||||
}
|
||||
|
@ -258,60 +306,100 @@ const char *StripExt(const char *s) {
|
|||
}
|
||||
|
||||
bool IsObjectSource(const char *name) {
|
||||
for (size_t i = 0; i < ARRAYLEN(kSourceExts); ++i) {
|
||||
int i;
|
||||
for (i = 0; i < ARRAYLEN(kSourceExts); ++i) {
|
||||
if (endswith(name, kSourceExts[i])) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void Dive(uint32_t sauce) {
|
||||
for (uint32_t i = bisectcarleft((const int32_t(*)[2])edges.p, edges.i, sauce);
|
||||
edges.p[i].from == sauce; ++i) {
|
||||
int32_t dep = edges.p[i].to;
|
||||
if (bts(visited, dep)) continue;
|
||||
void Dive(unsigned id) {
|
||||
int i;
|
||||
for (i = FindFirstFromEdge(id); i < edges.i && edges.p[i].from == id; ++i) {
|
||||
if (bts(visited, edges.p[i].to)) continue;
|
||||
fputs(" \\\n\t", fout);
|
||||
fputs(&strings.p[sources.p[dep].name], fout);
|
||||
Dive(dep);
|
||||
fputs(&strings.p[sources.p[edges.p[i].to].name], fout);
|
||||
Dive(edges.p[i].to);
|
||||
}
|
||||
}
|
||||
|
||||
bool IsModeless(const char *path) {
|
||||
size_t i;
|
||||
for (i = 0; i < ARRAYLEN(kModelessPackages); ++i) {
|
||||
if (startswith(path, kModelessPackages[i])) return true;
|
||||
size_t GetFileSizeOrZero(const char *path) {
|
||||
struct stat st;
|
||||
st.st_size = 0;
|
||||
stat(path, &st);
|
||||
return st.st_size;
|
||||
}
|
||||
|
||||
bool FilesHaveSameContent(const char *path1, const char *path2) {
|
||||
bool r;
|
||||
int c1, c2;
|
||||
size_t s1, s2;
|
||||
FILE *f1, *f2;
|
||||
s1 = GetFileSizeOrZero(path1);
|
||||
s2 = GetFileSizeOrZero(path2);
|
||||
if (s1 == s2) {
|
||||
r = true;
|
||||
if (s1) {
|
||||
CHECK_NOTNULL((f1 = fopen(path1, "r")));
|
||||
CHECK_NOTNULL((f2 = fopen(path2, "r")));
|
||||
for (;;) {
|
||||
c1 = getc(f1);
|
||||
c2 = getc(f2);
|
||||
if (c1 != c2) {
|
||||
r = false;
|
||||
break;
|
||||
}
|
||||
if (c1 == -1) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
CHECK_NE(-1, fclose(f2));
|
||||
CHECK_NE(-1, fclose(f1));
|
||||
}
|
||||
} else {
|
||||
r = false;
|
||||
}
|
||||
return false;
|
||||
return r;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
char *tp;
|
||||
bool needprefix;
|
||||
size_t i, bitmaplen;
|
||||
const char *path, *prefix;
|
||||
showcrashreports();
|
||||
out = "/dev/stdout";
|
||||
GetOpts(argc, argv);
|
||||
char *tmp =
|
||||
!fileexists(out) || isregularfile(out) ? xasprintf("%s.tmp", out) : NULL;
|
||||
CHECK_NOTNULL((fout = fopen(tmp ? tmp : out, "w")));
|
||||
tp = !fileexists(out) || isregularfile(out) ? xasprintf("%s.tmp", out) : NULL;
|
||||
CHECK_NOTNULL((fout = fopen(tp ? tp : out, "w")));
|
||||
LoadRelationships(argc, argv);
|
||||
Crunch();
|
||||
size_t bitmaplen = roundup((sources.i + 8) / 8, 4);
|
||||
bitmaplen = roundup((sources.i + 8) / 8, 4);
|
||||
visited = malloc(bitmaplen);
|
||||
for (size_t i = 0; i < sources.i; ++i) {
|
||||
const char *path = &strings.p[sources.p[i].name];
|
||||
for (i = 0; i < sources.i; ++i) {
|
||||
path = &strings.p[sources.p[i].name];
|
||||
if (!IsObjectSource(path)) continue;
|
||||
bool needprefix = !startswith(path, "o/");
|
||||
const char *prefix = !needprefix ? "" : IsModeless(path) ? "o/" : buildroot;
|
||||
needprefix = !startswith(path, "o/");
|
||||
prefix = !needprefix ? "" : buildroot;
|
||||
fprintf(fout, "\n%s%s.o: \\\n\t%s", prefix, StripExt(path), path);
|
||||
memset(visited, 0, bitmaplen);
|
||||
bts(visited, i);
|
||||
Dive(i);
|
||||
fprintf(fout, "\n");
|
||||
}
|
||||
if (fclose(fout) == -1) perror(out), exit(1);
|
||||
if (tmp) {
|
||||
if (rename(tmp, out) == -1) perror(out), exit(1);
|
||||
CHECK_NE(-1, fclose(fout));
|
||||
if (tp) {
|
||||
/* prevent gnu make from restarting unless necessary */
|
||||
if (!FilesHaveSameContent(tp, out)) {
|
||||
CHECK_NE(-1, rename(tp, out));
|
||||
} else {
|
||||
CHECK_NE(-1, unlink(tp));
|
||||
}
|
||||
}
|
||||
free_s(&strings.p);
|
||||
free_s(&sources.p);
|
||||
free_s(&edges.p);
|
||||
free_s(&visited);
|
||||
free_s(&tmp);
|
||||
free_s(&tp);
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -352,7 +352,8 @@ void OpenObject(struct Package *pkg, struct Object *obj, int mode, int prot,
|
|||
CHECK_NE(MAP_FAILED, (obj->elf = mmap(NULL, (obj->size = st.st_size), prot,
|
||||
flags, fd, 0)));
|
||||
CHECK_NE(-1, close(fd));
|
||||
CHECK(iself64binary(obj->elf, obj->size));
|
||||
CHECK(iself64binary(obj->elf, obj->size), "path=%`'s",
|
||||
&pkg->strings.p[obj->path]);
|
||||
CHECK_NOTNULL((obj->strs = getelfstringtable(obj->elf, obj->size)));
|
||||
CHECK_NOTNULL(
|
||||
(obj->syms = getelfsymboltable(obj->elf, obj->size, &obj->symcount)));
|
||||
|
|
|
@ -36,7 +36,6 @@ int main(int argc, char *argv[]) {
|
|||
int rc;
|
||||
struct Elf elf;
|
||||
const char *codepath;
|
||||
showcrashreports();
|
||||
codepath = argv[1];
|
||||
if (argc < 2) {
|
||||
fputs("Usage: ", stderr);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue