Fix bugs and have emulator emulate itself

This commit is contained in:
Justine Tunney 2020-08-31 05:17:31 -07:00
parent 5aabacb361
commit bd29223891
111 changed files with 1283 additions and 2073 deletions

View file

@ -17,7 +17,7 @@ M(1, i, "!", LogicalNot, !x, "logical not")
M(2, i, "||", LogicalOr, x || y, "logical or")
M(2, i, "&&", LogicalAnd, x &&y, "logical and")
M(2, g, "=", Equal1, x == y && fpclassify(x) == fpclassify(y), "equal to")
M(2, g, "=", Equal1, x == y, "equal to")
M(2, g, "!=", Notequal, x != y, "not equal to")
M(2, g, "<", LessThan, x < y, "less than")
M(2, g, ">", GreaterThan, x > y, "greater than")

View file

@ -28,7 +28,7 @@ static void Print(uint8_t c) {
int main(int argc, char *argv[]) {
int i;
#ifdef DISINGENUOUS
for (i = 0; i < 1400 * 1000 * 1000 / 3; ++i) asm("nop");
for (i = 0; i < 100 * 1000 * 1000 / 3; ++i) asm("nop");
#else
size_t size;
struct MetalSha256Ctx ctx;

View file

@ -9,4 +9,4 @@ TOOL_BUILD_EMUCRT = \
.PHONY: o/$(MODE)/tool/build/emucrt
o/$(MODE)/tool/build/emucrt: \
o/$(MODE)/tool/build/emucrt/emucrt.o
$(TOOL_BUILD_EMUCRT)

View file

@ -105,17 +105,15 @@ ARGUMENTS\n\
\n\
PERFORMANCE\n\
\n\
1500 MIPS w/ NOP loop\n\
1000 MIPS w/ NOP loop\n\
Over 9000 MIPS w/ SIMD & Algorithms\n\
\n\
PROTIP\n\
\n\
Fix SSH keyboard latency for debugger TUI in CONTINUE mode:\n\
\n\
sudo sh -c 'echo -n 8192 >/proc/sys/net/core/rmem_default'\n\
sudo sh -c 'echo -n 8192 >/proc/sys/net/core/wmem_default'\n\
\n\
COMPLETENESS\n\
\n\
Long user mode is supported in addition to SSE3 and SSSE3.\n\
Integer ops are implemented rigorously with lots of tests.\n\
Floating point instructions are yolo, and tunable more so.\n\
Loading, virtual memory management, and syscall need work.\n\
\n"
#define DUMPWIDTH 64
@ -274,7 +272,6 @@ static uint8_t CycleSseWidth(uint8_t w) {
}
static void OnBusted(void) {
LOGF("OnBusted");
CHECK(onbusted);
longjmp(onbusted, 1);
}
@ -621,15 +618,10 @@ static void DrawTerminal(struct Panel *p) {
}
}
static void DrawFlag(struct Panel *p, long i, char *name, bool value,
bool previous) {
AppendPanel(p, i, " ");
if (value) {
AppendPanel(p, i, name);
} else {
AppendPanel(p, i, " ");
}
AppendPanel(p, i, " ");
static void DrawFlag(struct Panel *p, long i, char name, bool value) {
char str[] = " ";
if (value) str[1] = name;
AppendPanel(p, i, str);
}
static void DrawRegister(struct Panel *p, long i, long r) {
@ -649,13 +641,12 @@ static void DrawRegister(struct Panel *p, long i, long r) {
static void DrawSt(struct Panel *p, long i, long r) {
char buf[32];
long double value;
bool isempty, changed;
long double value, previous;
isempty = FpuGetTag(m, r) == kFpuTagEmpty;
if (isempty) AppendPanel(p, i, "\e[2m");
value = *FpuSt(&m[0], r);
previous = *FpuSt(&m[1], r);
changed = value != previous;
value = m[0].fpu.st[(r + m[0].fpu.sp) & 0b111];
changed = value != m[1].fpu.st[(r + m[0].fpu.sp) & 0b111];
if (!isempty && changed) AppendPanel(p, i, "\e[7m");
snprintf(buf, sizeof(buf), "ST%d ", r);
AppendPanel(p, i, buf);
@ -689,20 +680,27 @@ static void DrawCpu(struct Panel *p) {
DrawRegister(p, 7, 11), DrawRegister(p, 7, 15), DrawSt(p, 7, 7);
snprintf(buf, sizeof(buf), "RIP 0x%016x FLG", m[0].ip);
AppendPanel(p, 8, buf);
DrawFlag(p, 8, "C", GetFlag(m[0].flags, FLAGS_CF),
GetFlag(m[1].flags, FLAGS_CF));
DrawFlag(p, 8, "Z", GetFlag(m[0].flags, FLAGS_ZF),
GetFlag(m[1].flags, FLAGS_ZF));
DrawFlag(p, 8, "S", GetFlag(m[0].flags, FLAGS_SF),
GetFlag(m[1].flags, FLAGS_SF));
DrawFlag(p, 8, "O", GetFlag(m[0].flags, FLAGS_OF),
GetFlag(m[1].flags, FLAGS_OF));
DrawFlag(p, 8, "P", GetFlag(m[0].flags, FLAGS_PF),
GetFlag(m[1].flags, FLAGS_PF));
DrawFlag(p, 8, "I", GetFlag(m[0].flags, FLAGS_IF),
GetFlag(m[1].flags, FLAGS_IF));
DrawFlag(p, 8, "D", GetFlag(m[0].flags, FLAGS_DF),
GetFlag(m[1].flags, FLAGS_DF));
DrawFlag(p, 8, 'C', GetFlag(m[0].flags, FLAGS_CF));
DrawFlag(p, 8, 'P', GetFlag(m[0].flags, FLAGS_PF));
DrawFlag(p, 8, 'A', GetFlag(m[0].flags, FLAGS_AF));
DrawFlag(p, 8, 'Z', GetFlag(m[0].flags, FLAGS_ZF));
DrawFlag(p, 8, 'S', GetFlag(m[0].flags, FLAGS_SF));
DrawFlag(p, 8, 'I', GetFlag(m[0].flags, FLAGS_IF));
DrawFlag(p, 8, 'D', GetFlag(m[0].flags, FLAGS_DF));
DrawFlag(p, 8, 'O', GetFlag(m[0].flags, FLAGS_OF));
AppendPanel(p, 8, " ");
if (m->fpu.ie) AppendPanel(p, 8, " IE");
if (m->fpu.de) AppendPanel(p, 8, " DE");
if (m->fpu.ze) AppendPanel(p, 8, " ZE");
if (m->fpu.oe) AppendPanel(p, 8, " OE");
if (m->fpu.ue) AppendPanel(p, 8, " UE");
if (m->fpu.pe) AppendPanel(p, 8, " PE");
if (m->fpu.sf) AppendPanel(p, 8, " SF");
if (m->fpu.es) AppendPanel(p, 8, " ES");
if (m->fpu.c0) AppendPanel(p, 8, " C0");
if (m->fpu.c1) AppendPanel(p, 8, " C1");
if (m->fpu.c2) AppendPanel(p, 8, " C2");
if (m->fpu.bf) AppendPanel(p, 8, " BF");
}
static void DrawXmm(struct Panel *p, long i, long r) {

View file

@ -25,8 +25,8 @@
* NexGen32e Arithmetic Unit.
*/
int64_t Alu(int w, int h, uint64_t x, uint64_t y, uint32_t *flags) {
bool zf, sf, c, o, cf;
uint64_t t, z, s, m, k;
bool cf, of, zf, sf, af, carry;
assert(w < 4);
k = 8;
k <<= w;
@ -35,9 +35,10 @@ int64_t Alu(int w, int h, uint64_t x, uint64_t y, uint32_t *flags) {
m = s;
m |= s - 1;
t = x;
c = 0;
o = 0;
cf = GetFlag(*flags, FLAGS_CF);
cf = 0;
of = 0;
af = 0;
carry = GetFlag(*flags, FLAGS_CF);
switch (h & 7) {
case ALU_OR:
z = x | y;
@ -50,22 +51,26 @@ int64_t Alu(int w, int h, uint64_t x, uint64_t y, uint32_t *flags) {
break;
case ALU_CMP:
h |= 8;
cf = 0;
carry = 0;
case ALU_SBB:
t = (x & m) - cf;
c = (x & m) < (t & m);
t = (x & m) - carry;
cf = (x & m) < (t & m);
af = (x & 15) < (t & 15);
case ALU_SUB:
z = (t & m) - (y & m);
c |= (t & m) < (z & m);
o = !!((z ^ x) & (x ^ y) & s);
cf |= (t & m) < (z & m);
af |= (t & 15) < (z & 15);
of = !!((z ^ x) & (x ^ y) & s);
break;
case ALU_ADC:
t = (x & m) + cf;
c = (t & m) < (x & m);
t = (x & m) + carry;
cf = (t & m) < (x & m);
af = (t & 15) < (x & 15);
case ALU_ADD:
z = (t & m) + (y & m);
c |= (z & m) < (y & m);
o = !!((z ^ x) & (z ^ y) & s);
cf |= (z & m) < (y & m);
af |= (z & 15) < (y & 15);
of = !!((z ^ x) & (z ^ y) & s);
break;
default:
unreachable;
@ -73,8 +78,10 @@ int64_t Alu(int w, int h, uint64_t x, uint64_t y, uint32_t *flags) {
z &= m;
zf = !z;
sf = !!(z & s);
*flags &= ~(1 << FLAGS_CF | 1 << FLAGS_ZF | 1 << FLAGS_SF | 1 << FLAGS_OF);
*flags |= c << FLAGS_CF | zf << FLAGS_ZF | sf << FLAGS_SF | o << FLAGS_OF;
*flags = (*flags & ~(1 << FLAGS_CF | 1 << FLAGS_ZF | 1 << FLAGS_SF |
1 << FLAGS_OF | 1 << FLAGS_AF)) |
cf << FLAGS_CF | zf << FLAGS_ZF | sf << FLAGS_SF | of << FLAGS_OF |
af << FLAGS_AF;
*flags = SetLazyParityByte(*flags, x);
if (h & ALU_TEST) z = x;
return z;

View file

@ -11,7 +11,6 @@
#define ALU_XOR 6
#define ALU_CMP 7
#define ALU_TEST 8
#define ALU_FLIP 16
#define BSU_ROL 0
#define BSU_ROR 1

View file

@ -63,6 +63,8 @@ $(TOOL_BUILD_LIB_A).pkg: \
$(TOOL_BUILD_LIB_A_OBJS) \
$(foreach x,$(TOOL_BUILD_LIB_A_DIRECTDEPS),$($(x)_A).pkg)
o/$(MODE)/tool/build/lib/fpu.o: OVERRIDE_CFLAGS += -ffast-math
TOOL_BUILD_LIB_LIBS = $(foreach x,$(TOOL_BUILD_LIB_ARTIFACTS),$($(x)))
TOOL_BUILD_LIB_SRCS = $(foreach x,$(TOOL_BUILD_LIB_ARTIFACTS),$($(x)_SRCS))
TOOL_BUILD_LIB_HDRS = $(foreach x,$(TOOL_BUILD_LIB_ARTIFACTS),$($(x)_HDRS))

View file

@ -7,5 +7,10 @@
CODE; \
break
#define CASR(OP, CODE) \
case OP: \
CODE; \
return
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_TOOL_BUILD_LIB_CASE_H_ */

View file

@ -26,6 +26,21 @@
#include "tool/build/lib/modrm.h"
#include "tool/build/lib/throw.h"
static double SseRoundDouble(struct Machine *m, double x) {
switch (m->sse.rc) {
case 0:
return nearbyint(x);
case 1:
return floor(x);
case 2:
return ceil(x);
case 3:
return trunc(x);
default:
unreachable;
}
}
static void OpGdqpWssCvttss2si(struct Machine *m, uint32_t rde) {
float f;
int64_t n;
@ -57,7 +72,7 @@ static void OpGdqpWsdCvtsd2si(struct Machine *m, uint32_t rde) {
double d;
int64_t n;
memcpy(&d, GetModrmRegisterXmmPointerRead8(m, rde), 8);
n = nearbyint(d);
n = SseRoundDouble(m, d);
if (!Rexw(rde)) n &= 0xffffffff;
Write64(RegRexrReg(m, rde), n);
}
@ -113,11 +128,26 @@ static void OpVpdQpiCvtpi2pd(struct Machine *m, uint32_t rde) {
}
static void OpPpiWpsqCvtps2pi(struct Machine *m, uint32_t rde) {
unsigned i;
float f[2];
int32_t n[2];
memcpy(f, GetModrmRegisterXmmPointerRead8(m, rde), 8);
n[0] = nearbyintf(f[0]);
n[1] = nearbyintf(f[1]);
switch (m->sse.rc) {
case 0:
for (i = 0; i < 2; ++i) n[i] = nearbyintf(f[i]);
break;
case 1:
for (i = 0; i < 2; ++i) n[i] = floorf(f[i]);
break;
case 2:
for (i = 0; i < 2; ++i) n[i] = ceilf(f[i]);
break;
case 3:
for (i = 0; i < 2; ++i) n[i] = truncf(f[i]);
break;
default:
unreachable;
}
Write32(MmReg(m, rde) + 0, n[0]);
Write32(MmReg(m, rde) + 4, n[1]);
}
@ -133,11 +163,11 @@ static void OpPpiWpsqCvttps2pi(struct Machine *m, uint32_t rde) {
}
static void OpPpiWpdCvtpd2pi(struct Machine *m, uint32_t rde) {
unsigned i;
double d[2];
int32_t n[2];
memcpy(d, GetModrmRegisterXmmPointerRead16(m, rde), 16);
n[0] = nearbyint(d[0]);
n[1] = nearbyint(d[1]);
for (i = 0; i < 2; ++i) n[i] = SseRoundDouble(m, d[i]);
Write32(MmReg(m, rde) + 0, n[0]);
Write32(MmReg(m, rde) + 4, n[1]);
}
@ -218,7 +248,22 @@ static void OpVdqWpsCvtps2dq(struct Machine *m, uint32_t rde) {
float f[4];
int32_t n[4];
memcpy(f, GetModrmRegisterXmmPointerRead16(m, rde), 16);
for (i = 0; i < 4; ++i) n[i] = nearbyintf(f[i]);
switch (m->sse.rc) {
case 0:
for (i = 0; i < 4; ++i) n[i] = nearbyintf(f[i]);
break;
case 1:
for (i = 0; i < 4; ++i) n[i] = floorf(f[i]);
break;
case 2:
for (i = 0; i < 4; ++i) n[i] = ceilf(f[i]);
break;
case 3:
for (i = 0; i < 4; ++i) n[i] = truncf(f[i]);
break;
default:
unreachable;
}
memcpy(XmmRexrReg(m, rde), n, 16);
}
@ -236,7 +281,7 @@ static void OpVdqWpdCvtpd2dq(struct Machine *m, uint32_t rde) {
double d[2];
int32_t n[2];
memcpy(d, GetModrmRegisterXmmPointerRead16(m, rde), 16);
for (i = 0; i < 2; ++i) n[i] = nearbyintf(d[i]);
for (i = 0; i < 2; ++i) n[i] = SseRoundDouble(m, d[i]);
memcpy(XmmRexrReg(m, rde), n, 8);
}

View file

@ -23,6 +23,7 @@
#include "libc/conv/itoa.h"
#include "libc/fmt/bing.h"
#include "libc/fmt/fmt.h"
#include "libc/limits.h"
#include "libc/log/check.h"
#include "libc/log/log.h"
#include "libc/macros.h"

View file

@ -17,6 +17,7 @@
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/bits/bits.h"
#include "libc/conv/itoa.h"
#include "libc/limits.h"
#include "libc/log/check.h"

View file

@ -30,6 +30,7 @@
#include "tool/build/lib/memory.h"
#include "tool/build/lib/modrm.h"
#include "tool/build/lib/throw.h"
#include "tool/build/lib/word.h"
#include "tool/build/lib/x87.h"
#define FPUREG 0
@ -92,90 +93,142 @@ static void FpuSetStRmPop(struct Machine *m, long double x) {
FpuSetStPop(m, ModrmRm(m->xedd->op.rde), x);
}
static int16_t GetMemoryShort(struct Machine *m) {
static int16_t FpuGetMemoryShort(struct Machine *m) {
uint8_t b[2];
return Read16(Load(m, m->fpu.dp, 2, b));
}
static int32_t GetMemoryInt(struct Machine *m) {
static int32_t FpuGetMemoryInt(struct Machine *m) {
uint8_t b[4];
return Read32(Load(m, m->fpu.dp, 4, b));
}
static int64_t GetMemoryLong(struct Machine *m) {
static int64_t FpuGetMemoryLong(struct Machine *m) {
uint8_t b[8];
return Read64(Load(m, m->fpu.dp, 8, b));
}
static float GetMemoryFloat(struct Machine *m) {
static float FpuGetMemoryFloat(struct Machine *m) {
float f;
uint8_t b[4];
memcpy(&f, Load(m, m->fpu.dp, 4, b), 4);
return f;
}
static double GetMemoryDouble(struct Machine *m) {
static double FpuGetMemoryDouble(struct Machine *m) {
double f;
uint8_t b[8];
memcpy(&f, Load(m, m->fpu.dp, 8, b), 8);
return f;
}
static long double GetMemoryLongDouble(struct Machine *m) {
static long double FpuGetMemoryLongDouble(struct Machine *m) {
long double f;
uint8_t b[10];
memcpy(&f, Load(m, m->fpu.dp, 10, b), 10);
return f;
}
static void SetMemoryShort(struct Machine *m, int16_t i) {
void *p[2];
uint8_t b[2];
Write16(BeginStore(m, m->fpu.dp, 2, p, b), i);
EndStore(m, m->fpu.dp, 2, p, b);
static void FpuSetMemoryShort(struct Machine *m, int16_t i) {
SetMemoryShort(m, m->fpu.dp, i);
}
static void SetMemoryInt(struct Machine *m, int32_t i) {
void *p[2];
uint8_t b[4];
Write32(BeginStore(m, m->fpu.dp, 4, p, b), i);
EndStore(m, m->fpu.dp, 4, p, b);
static void FpuSetMemoryInt(struct Machine *m, int32_t i) {
SetMemoryInt(m, m->fpu.dp, i);
}
static void SetMemoryLong(struct Machine *m, int64_t i) {
void *p[2];
uint8_t b[8];
Write64(BeginStore(m, m->fpu.dp, 8, p, b), i);
EndStore(m, m->fpu.dp, 8, p, b);
static void FpuSetMemoryLong(struct Machine *m, int64_t i) {
SetMemoryLong(m, m->fpu.dp, i);
}
static void SetMemoryFloat(struct Machine *m, float f) {
void *p[2];
uint8_t b[4];
memcpy(BeginStore(m, m->fpu.dp, 4, p, b), &f, 4);
EndStore(m, m->fpu.dp, 4, p, b);
static void FpuSetMemoryFloat(struct Machine *m, float f) {
SetMemoryFloat(m, m->fpu.dp, f);
}
static void SetMemoryDouble(struct Machine *m, double f) {
void *p[2];
uint8_t b[8];
memcpy(BeginStore(m, m->fpu.dp, 8, p, b), &f, 8);
EndStore(m, m->fpu.dp, 8, p, b);
static void FpuSetMemoryDouble(struct Machine *m, double f) {
SetMemoryDouble(m, m->fpu.dp, f);
}
static void SetMemoryLdbl(struct Machine *m, long double f) {
void *p[2];
uint8_t b[10];
memcpy(BeginStore(m, m->fpu.dp, 10, p, b), &f, 10);
EndStore(m, m->fpu.dp, 10, p, b);
static void FpuSetMemoryLdbl(struct Machine *m, long double f) {
SetMemoryLdbl(m, m->fpu.dp, f);
}
static long double FpuDivide(struct Machine *m, long double x, long double y) {
if (y) {
return x / y;
static long double FpuAdd(struct Machine *m, long double x, long double y) {
if (!isunordered(x, y)) {
switch (isinf(y) << 1 | isinf(x)) {
case 0b00:
return x + y;
case 0b01:
return x;
case 0b10:
return y;
case 0b11:
if (signbit(x) == signbit(y)) {
return x;
} else {
m->fpu.ie = true;
return copysign(NAN, x);
}
default:
unreachable;
}
} else {
m->fpu.ze = true;
return signbit(x) ? -INFINITY : INFINITY;
return NAN;
}
}
static long double FpuSub(struct Machine *m, long double x, long double y) {
if (!isunordered(x, y)) {
switch (isinf(y) << 1 | isinf(x)) {
case 0b00:
return x - y;
case 0b01:
return -x;
case 0b10:
return y;
case 0b11:
if (signbit(x) == signbit(y)) {
m->fpu.ie = true;
return copysign(NAN, x);
} else {
return y;
}
default:
unreachable;
}
} else {
return NAN;
}
}
static long double FpuMul(struct Machine *m, long double x, long double y) {
if (!isunordered(x, y)) {
if (!((isinf(x) && !y) || (isinf(y) && !x))) {
return x * y;
} else {
m->fpu.ie = true;
return -NAN;
}
} else {
return NAN;
}
}
static long double FpuDiv(struct Machine *m, long double x, long double y) {
if (!isunordered(x, y)) {
if (x || y) {
if (y) {
return x / y;
} else {
m->fpu.ze = true;
return copysign(INFINITY, x);
}
} else {
m->fpu.ie = true;
return copysign(NAN, x);
}
} else {
return NAN;
}
}
@ -198,7 +251,7 @@ static void FpuCompare(struct Machine *m, long double y) {
long double x;
x = St0(m);
m->fpu.c1 = false;
if (!isnan(x) && !isnan(y)) {
if (!isunordered(x, y)) {
m->fpu.c0 = x < y;
m->fpu.c2 = false;
m->fpu.c3 = x == y;
@ -210,7 +263,7 @@ static void FpuCompare(struct Machine *m, long double y) {
}
}
static void OpFxam(struct Machine *m) {
void OpFxam(struct Machine *m) {
long double x;
x = *FpuSt(m, 0);
m->fpu.c1 = !!signbit(x);
@ -362,59 +415,59 @@ static void OpFcomp(struct Machine *m) {
}
static void OpFaddStEst(struct Machine *m) {
FpuSetSt0(m, St0(m) + StRm(m));
FpuSetSt0(m, FpuAdd(m, St0(m), StRm(m)));
}
static void OpFmulStEst(struct Machine *m) {
FpuSetSt0(m, St0(m) * StRm(m));
FpuSetSt0(m, FpuMul(m, St0(m), StRm(m)));
}
static void OpFsubStEst(struct Machine *m) {
FpuSetSt0(m, St0(m) - StRm(m));
FpuSetSt0(m, FpuSub(m, St0(m), StRm(m)));
}
static void OpFsubrStEst(struct Machine *m) {
FpuSetSt0(m, StRm(m) - St0(m));
FpuSetSt0(m, FpuSub(m, StRm(m), St0(m)));
}
static void OpFdivStEst(struct Machine *m) {
FpuSetSt0(m, FpuDivide(m, St0(m), StRm(m)));
FpuSetSt0(m, FpuDiv(m, St0(m), StRm(m)));
}
static void OpFdivrStEst(struct Machine *m) {
FpuSetSt0(m, FpuDivide(m, StRm(m), St0(m)));
FpuSetSt0(m, FpuDiv(m, StRm(m), St0(m)));
}
static void OpFaddEstSt(struct Machine *m) {
FpuSetStRm(m, StRm(m) + St0(m));
FpuSetStRm(m, FpuAdd(m, StRm(m), St0(m)));
}
static void OpFmulEstSt(struct Machine *m) {
FpuSetStRm(m, StRm(m) * St0(m));
FpuSetStRm(m, FpuMul(m, StRm(m), St0(m)));
}
static void OpFsubEstSt(struct Machine *m) {
FpuSetStRm(m, St0(m) - StRm(m));
FpuSetStRm(m, FpuSub(m, St0(m), StRm(m)));
}
static void OpFsubrEstSt(struct Machine *m) {
FpuSetStRm(m, StRm(m) - St0(m));
FpuSetStRm(m, FpuSub(m, StRm(m), St0(m)));
}
static void OpFdivEstSt(struct Machine *m) {
FpuSetStRm(m, FpuDivide(m, StRm(m), St0(m)));
FpuSetStRm(m, FpuDiv(m, StRm(m), St0(m)));
}
static void OpFdivrEstSt(struct Machine *m) {
FpuSetStRm(m, FpuDivide(m, St0(m), StRm(m)));
FpuSetStRm(m, FpuDiv(m, St0(m), StRm(m)));
}
static void OpFaddp(struct Machine *m) {
FpuSetStRmPop(m, St0(m) + StRm(m));
FpuSetStRmPop(m, FpuAdd(m, St0(m), StRm(m)));
}
static void OpFmulp(struct Machine *m) {
FpuSetStRmPop(m, St0(m) * StRm(m));
FpuSetStRmPop(m, FpuMul(m, St0(m), StRm(m)));
}
static void OpFcompp(struct Machine *m) {
@ -423,31 +476,31 @@ static void OpFcompp(struct Machine *m) {
}
static void OpFsubp(struct Machine *m) {
FpuSetStRmPop(m, St0(m) - StRm(m));
FpuSetStRmPop(m, FpuSub(m, St0(m), StRm(m)));
}
static void OpFsubrp(struct Machine *m) {
FpuSetStPop(m, 1, StRm(m) - St0(m));
FpuSetStPop(m, 1, FpuSub(m, StRm(m), St0(m)));
}
static void OpFdivp(struct Machine *m) {
FpuSetStRmPop(m, FpuDivide(m, St0(m), StRm(m)));
FpuSetStRmPop(m, FpuDiv(m, St0(m), StRm(m)));
}
static void OpFdivrp(struct Machine *m) {
FpuSetStRmPop(m, FpuDivide(m, StRm(m), St0(m)));
FpuSetStRmPop(m, FpuDiv(m, StRm(m), St0(m)));
}
static void OpFadds(struct Machine *m) {
FpuSetSt0(m, St0(m) + GetMemoryFloat(m));
FpuSetSt0(m, FpuAdd(m, St0(m), FpuGetMemoryFloat(m)));
}
static void OpFmuls(struct Machine *m) {
FpuSetSt0(m, St0(m) * GetMemoryFloat(m));
FpuSetSt0(m, FpuMul(m, St0(m), FpuGetMemoryFloat(m)));
}
static void OpFcoms(struct Machine *m) {
FpuCompare(m, GetMemoryFloat(m));
FpuCompare(m, FpuGetMemoryFloat(m));
}
static void OpFcomps(struct Machine *m) {
@ -456,64 +509,64 @@ static void OpFcomps(struct Machine *m) {
}
static void OpFsubs(struct Machine *m) {
FpuSetSt0(m, St0(m) - GetMemoryFloat(m));
FpuSetSt0(m, FpuSub(m, St0(m), FpuGetMemoryFloat(m)));
}
static void OpFsubrs(struct Machine *m) {
FpuSetSt0(m, GetMemoryFloat(m) - St0(m));
FpuSetSt0(m, FpuSub(m, FpuGetMemoryFloat(m), St0(m)));
}
static void OpFdivs(struct Machine *m) {
FpuSetSt0(m, FpuDivide(m, St0(m), GetMemoryFloat(m)));
FpuSetSt0(m, FpuDiv(m, St0(m), FpuGetMemoryFloat(m)));
}
static void OpFdivrs(struct Machine *m) {
FpuSetSt0(m, FpuDivide(m, GetMemoryFloat(m), St0(m)));
FpuSetSt0(m, FpuDiv(m, FpuGetMemoryFloat(m), St0(m)));
}
static void OpFaddl(struct Machine *m) {
FpuSetSt0(m, St0(m) + GetMemoryDouble(m));
FpuSetSt0(m, FpuAdd(m, St0(m), FpuGetMemoryDouble(m)));
}
static void OpFmull(struct Machine *m) {
FpuSetSt0(m, St0(m) * GetMemoryDouble(m));
FpuSetSt0(m, FpuMul(m, St0(m), FpuGetMemoryDouble(m)));
}
static void OpFcoml(struct Machine *m) {
FpuCompare(m, GetMemoryDouble(m));
FpuCompare(m, FpuGetMemoryDouble(m));
}
static void OpFcompl(struct Machine *m) {
FpuCompare(m, GetMemoryDouble(m));
FpuCompare(m, FpuGetMemoryDouble(m));
FpuPop(m);
}
static void OpFsubl(struct Machine *m) {
FpuSetSt0(m, St0(m) - GetMemoryDouble(m));
FpuSetSt0(m, FpuSub(m, St0(m), FpuGetMemoryDouble(m)));
}
static void OpFsubrl(struct Machine *m) {
FpuSetSt0(m, GetMemoryDouble(m) - St0(m));
FpuSetSt0(m, FpuSub(m, FpuGetMemoryDouble(m), St0(m)));
}
static void OpFdivl(struct Machine *m) {
FpuSetSt0(m, FpuDivide(m, St0(m), GetMemoryDouble(m)));
FpuSetSt0(m, FpuDiv(m, St0(m), FpuGetMemoryDouble(m)));
}
static void OpFdivrl(struct Machine *m) {
FpuSetSt0(m, FpuDivide(m, GetMemoryDouble(m), St0(m)));
FpuSetSt0(m, FpuDiv(m, FpuGetMemoryDouble(m), St0(m)));
}
static void OpFiaddl(struct Machine *m) {
FpuSetSt0(m, St0(m) + GetMemoryInt(m));
FpuSetSt0(m, FpuAdd(m, St0(m), FpuGetMemoryInt(m)));
}
static void OpFimull(struct Machine *m) {
FpuSetSt0(m, St0(m) * GetMemoryInt(m));
FpuSetSt0(m, FpuMul(m, St0(m), FpuGetMemoryInt(m)));
}
static void OpFicoml(struct Machine *m) {
FpuCompare(m, GetMemoryInt(m));
FpuCompare(m, FpuGetMemoryInt(m));
}
static void OpFicompl(struct Machine *m) {
@ -522,31 +575,31 @@ static void OpFicompl(struct Machine *m) {
}
static void OpFisubl(struct Machine *m) {
FpuSetSt0(m, St0(m) - GetMemoryInt(m));
FpuSetSt0(m, FpuSub(m, St0(m), FpuGetMemoryInt(m)));
}
static void OpFisubrl(struct Machine *m) {
FpuSetSt0(m, GetMemoryInt(m) - St0(m));
FpuSetSt0(m, FpuSub(m, FpuGetMemoryInt(m), St0(m)));
}
static void OpFidivl(struct Machine *m) {
FpuSetSt0(m, FpuDivide(m, St0(m), GetMemoryInt(m)));
FpuSetSt0(m, FpuDiv(m, St0(m), FpuGetMemoryInt(m)));
}
static void OpFidivrl(struct Machine *m) {
FpuSetSt0(m, FpuDivide(m, GetMemoryInt(m), St0(m)));
FpuSetSt0(m, FpuDiv(m, FpuGetMemoryInt(m), St0(m)));
}
static void OpFiadds(struct Machine *m) {
FpuSetSt0(m, St0(m) + GetMemoryShort(m));
FpuSetSt0(m, FpuAdd(m, St0(m), FpuGetMemoryShort(m)));
}
static void OpFimuls(struct Machine *m) {
FpuSetSt0(m, St0(m) * GetMemoryShort(m));
FpuSetSt0(m, FpuMul(m, St0(m), FpuGetMemoryShort(m)));
}
static void OpFicoms(struct Machine *m) {
FpuCompare(m, GetMemoryShort(m));
FpuCompare(m, FpuGetMemoryShort(m));
}
static void OpFicomps(struct Machine *m) {
@ -555,19 +608,19 @@ static void OpFicomps(struct Machine *m) {
}
static void OpFisubs(struct Machine *m) {
FpuSetSt0(m, St0(m) - GetMemoryShort(m));
FpuSetSt0(m, FpuSub(m, St0(m), FpuGetMemoryShort(m)));
}
static void OpFisubrs(struct Machine *m) {
FpuSetSt0(m, GetMemoryShort(m) - St0(m));
FpuSetSt0(m, FpuSub(m, FpuGetMemoryShort(m), St0(m)));
}
static void OpFidivs(struct Machine *m) {
FpuSetSt0(m, FpuDivide(m, St0(m), GetMemoryShort(m)));
FpuSetSt0(m, FpuDiv(m, St0(m), FpuGetMemoryShort(m)));
}
static void OpFidivrs(struct Machine *m) {
FpuSetSt0(m, FpuDivide(m, GetMemoryShort(m), St0(m)));
FpuSetSt0(m, FpuDiv(m, FpuGetMemoryShort(m), St0(m)));
}
static void OpFsqrt(struct Machine *m) {
@ -612,11 +665,11 @@ static void OpFld(struct Machine *m) {
}
static void OpFlds(struct Machine *m) {
FpuPush(m, GetMemoryFloat(m));
FpuPush(m, FpuGetMemoryFloat(m));
}
static void OpFsts(struct Machine *m) {
SetMemoryFloat(m, St0(m));
FpuSetMemoryFloat(m, St0(m));
}
static void OpFstps(struct Machine *m) {
@ -625,11 +678,11 @@ static void OpFstps(struct Machine *m) {
}
static void OpFstpt(struct Machine *m) {
SetMemoryLdbl(m, FpuPop(m));
FpuSetMemoryLdbl(m, FpuPop(m));
}
static void OpFstl(struct Machine *m) {
SetMemoryDouble(m, St0(m));
FpuSetMemoryDouble(m, St0(m));
}
static void OpFstpl(struct Machine *m) {
@ -652,15 +705,15 @@ static void OpFxch(struct Machine *m) {
}
static void OpFldcw(struct Machine *m) {
m->fpu.cw = GetMemoryShort(m);
m->fpu.cw = FpuGetMemoryShort(m);
}
static void OpFldt(struct Machine *m) {
FpuPush(m, GetMemoryLongDouble(m));
FpuPush(m, FpuGetMemoryLongDouble(m));
}
static void OpFldl(struct Machine *m) {
FpuPush(m, GetMemoryDouble(m));
FpuPush(m, FpuGetMemoryDouble(m));
}
static void OpFldConstant(struct Machine *m) {
@ -694,43 +747,43 @@ static void OpFldConstant(struct Machine *m) {
}
static void OpFstcw(struct Machine *m) {
SetMemoryShort(m, m->fpu.cw);
FpuSetMemoryShort(m, m->fpu.cw);
}
static void OpFilds(struct Machine *m) {
FpuPush(m, GetMemoryShort(m));
FpuPush(m, FpuGetMemoryShort(m));
}
static void OpFildl(struct Machine *m) {
FpuPush(m, GetMemoryInt(m));
FpuPush(m, FpuGetMemoryInt(m));
}
static void OpFildll(struct Machine *m) {
FpuPush(m, GetMemoryLong(m));
FpuPush(m, FpuGetMemoryLong(m));
}
static void OpFisttpl(struct Machine *m) {
SetMemoryInt(m, FpuPop(m));
FpuSetMemoryInt(m, FpuPop(m));
}
static void OpFisttpll(struct Machine *m) {
SetMemoryLong(m, FpuPop(m));
FpuSetMemoryLong(m, FpuPop(m));
}
static void OpFisttps(struct Machine *m) {
SetMemoryShort(m, FpuPop(m));
FpuSetMemoryShort(m, FpuPop(m));
}
static void OpFists(struct Machine *m) {
SetMemoryShort(m, FpuRound(m, St0(m)));
FpuSetMemoryShort(m, FpuRound(m, St0(m)));
}
static void OpFistl(struct Machine *m) {
SetMemoryInt(m, FpuRound(m, St0(m)));
FpuSetMemoryInt(m, FpuRound(m, St0(m)));
}
static void OpFistll(struct Machine *m) {
SetMemoryLong(m, FpuRound(m, St0(m)));
FpuSetMemoryLong(m, FpuRound(m, St0(m)));
}
static void OpFistpl(struct Machine *m) {
@ -752,7 +805,7 @@ static void OpFcomi(struct Machine *m) {
long double x, y;
x = St0(m);
y = StRm(m);
if (!isnan(x) && !isnan(y)) {
if (!isunordered(x, y)) {
m->flags = SetFlag(m->flags, FLAGS_ZF, x == y);
m->flags = SetFlag(m->flags, FLAGS_CF, x < y);
m->flags = SetFlag(m->flags, FLAGS_PF, false);
@ -796,7 +849,7 @@ static void OpFfreep(struct Machine *m) {
}
static void OpFstswMw(struct Machine *m) {
SetMemoryShort(m, m->fpu.sw);
FpuSetMemoryShort(m, m->fpu.sw);
}
static void OpFstswAx(struct Machine *m) {
@ -975,83 +1028,83 @@ void OpFpu(struct Machine *m) {
CASE(DISP(0xDA, FPUREG, 2), OpFcmovbe(m));
CASE(DISP(0xDA, FPUREG, 3), OpFcmovu(m));
CASE(DISP(0xDA, MEMORY, 0), OpFiaddl(m));
CASE(DISP(0xDa, MEMORY, 1), OpFimull(m));
CASE(DISP(0xDa, MEMORY, 2), OpFicoml(m));
CASE(DISP(0xDa, MEMORY, 3), OpFicompl(m));
CASE(DISP(0xDa, MEMORY, 4), OpFisubl(m));
CASE(DISP(0xDa, MEMORY, 5), OpFisubrl(m));
CASE(DISP(0xDa, MEMORY, 6), OpFidivl(m));
CASE(DISP(0xDa, MEMORY, 7), OpFidivrl(m));
CASE(DISP(0xDb, FPUREG, 0), OpFcmovnb(m));
CASE(DISP(0xDb, FPUREG, 1), OpFcmovne(m));
CASE(DISP(0xDb, FPUREG, 2), OpFcmovnbe(m));
CASE(DISP(0xDb, FPUREG, 3), OpFcmovnu(m));
CASE(DISP(0xDb, FPUREG, 5), OpFucomi(m));
CASE(DISP(0xDb, FPUREG, 6), OpFcomi(m));
CASE(DISP(0xDb, MEMORY, 0), OpFildl(m));
CASE(DISP(0xDb, MEMORY, 1), OpFisttpl(m));
CASE(DISP(0xDb, MEMORY, 2), OpFistl(m));
CASE(DISP(0xDb, MEMORY, 3), OpFistpl(m));
CASE(DISP(0xDb, MEMORY, 5), OpFldt(m));
CASE(DISP(0xDb, MEMORY, 7), OpFstpt(m));
CASE(DISP(0xDc, FPUREG, 0), OpFaddEstSt(m));
CASE(DISP(0xDc, FPUREG, 1), OpFmulEstSt(m));
CASE(DISP(0xDc, FPUREG, 2), OpFcom(m));
CASE(DISP(0xDc, FPUREG, 3), OpFcomp(m));
CASE(DISP(0xDc, FPUREG, 4), OpFsubEstSt(m));
CASE(DISP(0xDc, FPUREG, 5), OpFsubrEstSt(m));
CASE(DISP(0xDc, FPUREG, 6), OpFdivEstSt(m));
CASE(DISP(0xDc, FPUREG, 7), OpFdivrEstSt(m));
CASE(DISP(0xDc, MEMORY, 0), OpFaddl(m));
CASE(DISP(0xDc, MEMORY, 1), OpFmull(m));
CASE(DISP(0xDc, MEMORY, 2), OpFcoml(m));
CASE(DISP(0xDc, MEMORY, 3), OpFcompl(m));
CASE(DISP(0xDc, MEMORY, 4), OpFsubl(m));
CASE(DISP(0xDc, MEMORY, 5), OpFsubrl(m));
CASE(DISP(0xDc, MEMORY, 6), OpFdivl(m));
CASE(DISP(0xDc, MEMORY, 7), OpFdivrl(m));
CASE(DISP(0xDd, FPUREG, 0), OpFfree(m));
CASE(DISP(0xDd, FPUREG, 1), OpFxch(m));
CASE(DISP(0xDd, FPUREG, 2), OpFst(m));
CASE(DISP(0xDd, FPUREG, 3), OpFstp(m));
CASE(DISP(0xDd, FPUREG, 4), OpFucom(m));
CASE(DISP(0xDd, FPUREG, 5), OpFucomp(m));
CASE(DISP(0xDd, MEMORY, 0), OpFldl(m));
CASE(DISP(0xDd, MEMORY, 1), OpFisttpll(m));
CASE(DISP(0xDd, MEMORY, 2), OpFstl(m));
CASE(DISP(0xDd, MEMORY, 3), OpFstpl(m));
CASE(DISP(0xDd, MEMORY, 4), OpFrstor(m));
CASE(DISP(0xDd, MEMORY, 6), OpFsave(m));
CASE(DISP(0xDd, MEMORY, 7), OpFstswMw(m));
CASE(DISP(0xDe, FPUREG, 0), OpFaddp(m));
CASE(DISP(0xDe, FPUREG, 1), OpFmulp(m));
CASE(DISP(0xDe, FPUREG, 2), OpFcomp(m));
CASE(DISP(0xDe, FPUREG, 3), OpFcompp(m));
CASE(DISP(0xDe, FPUREG, 4), OpFsubp(m));
CASE(DISP(0xDe, FPUREG, 5), OpFsubrp(m));
CASE(DISP(0xDe, FPUREG, 6), OpFdivp(m));
CASE(DISP(0xDe, FPUREG, 7), OpFdivrp(m));
CASE(DISP(0xDe, MEMORY, 0), OpFiadds(m));
CASE(DISP(0xDe, MEMORY, 1), OpFimuls(m));
CASE(DISP(0xDe, MEMORY, 2), OpFicoms(m));
CASE(DISP(0xDe, MEMORY, 3), OpFicomps(m));
CASE(DISP(0xDe, MEMORY, 4), OpFisubs(m));
CASE(DISP(0xDe, MEMORY, 5), OpFisubrs(m));
CASE(DISP(0xDe, MEMORY, 6), OpFidivs(m));
CASE(DISP(0xDe, MEMORY, 7), OpFidivrs(m));
CASE(DISP(0xDf, FPUREG, 0), OpFfreep(m));
CASE(DISP(0xDf, FPUREG, 1), OpFxch(m));
CASE(DISP(0xDf, FPUREG, 2), OpFstp(m));
CASE(DISP(0xDf, FPUREG, 3), OpFstp(m));
CASE(DISP(0xDf, FPUREG, 4), OpFstswAx(m));
CASE(DISP(0xDf, FPUREG, 5), OpFucomip(m));
CASE(DISP(0xDf, FPUREG, 6), OpFcomip(m));
CASE(DISP(0xDf, MEMORY, 0), OpFilds(m));
CASE(DISP(0xDf, MEMORY, 1), OpFisttps(m));
CASE(DISP(0xDf, MEMORY, 2), OpFists(m));
CASE(DISP(0xDf, MEMORY, 3), OpFistps(m));
CASE(DISP(0xDf, MEMORY, 5), OpFildll(m));
CASE(DISP(0xDf, MEMORY, 7), OpFistpll(m));
CASE(DISP(0xDA, MEMORY, 1), OpFimull(m));
CASE(DISP(0xDA, MEMORY, 2), OpFicoml(m));
CASE(DISP(0xDA, MEMORY, 3), OpFicompl(m));
CASE(DISP(0xDA, MEMORY, 4), OpFisubl(m));
CASE(DISP(0xDA, MEMORY, 5), OpFisubrl(m));
CASE(DISP(0xDA, MEMORY, 6), OpFidivl(m));
CASE(DISP(0xDA, MEMORY, 7), OpFidivrl(m));
CASE(DISP(0xDB, FPUREG, 0), OpFcmovnb(m));
CASE(DISP(0xDB, FPUREG, 1), OpFcmovne(m));
CASE(DISP(0xDB, FPUREG, 2), OpFcmovnbe(m));
CASE(DISP(0xDB, FPUREG, 3), OpFcmovnu(m));
CASE(DISP(0xDB, FPUREG, 5), OpFucomi(m));
CASE(DISP(0xDB, FPUREG, 6), OpFcomi(m));
CASE(DISP(0xDB, MEMORY, 0), OpFildl(m));
CASE(DISP(0xDB, MEMORY, 1), OpFisttpl(m));
CASE(DISP(0xDB, MEMORY, 2), OpFistl(m));
CASE(DISP(0xDB, MEMORY, 3), OpFistpl(m));
CASE(DISP(0xDB, MEMORY, 5), OpFldt(m));
CASE(DISP(0xDB, MEMORY, 7), OpFstpt(m));
CASE(DISP(0xDC, FPUREG, 0), OpFaddEstSt(m));
CASE(DISP(0xDC, FPUREG, 1), OpFmulEstSt(m));
CASE(DISP(0xDC, FPUREG, 2), OpFcom(m));
CASE(DISP(0xDC, FPUREG, 3), OpFcomp(m));
CASE(DISP(0xDC, FPUREG, 4), OpFsubEstSt(m));
CASE(DISP(0xDC, FPUREG, 5), OpFsubrEstSt(m));
CASE(DISP(0xDC, FPUREG, 6), OpFdivEstSt(m));
CASE(DISP(0xDC, FPUREG, 7), OpFdivrEstSt(m));
CASE(DISP(0xDC, MEMORY, 0), OpFaddl(m));
CASE(DISP(0xDC, MEMORY, 1), OpFmull(m));
CASE(DISP(0xDC, MEMORY, 2), OpFcoml(m));
CASE(DISP(0xDC, MEMORY, 3), OpFcompl(m));
CASE(DISP(0xDC, MEMORY, 4), OpFsubl(m));
CASE(DISP(0xDC, MEMORY, 5), OpFsubrl(m));
CASE(DISP(0xDC, MEMORY, 6), OpFdivl(m));
CASE(DISP(0xDC, MEMORY, 7), OpFdivrl(m));
CASE(DISP(0xDD, FPUREG, 0), OpFfree(m));
CASE(DISP(0xDD, FPUREG, 1), OpFxch(m));
CASE(DISP(0xDD, FPUREG, 2), OpFst(m));
CASE(DISP(0xDD, FPUREG, 3), OpFstp(m));
CASE(DISP(0xDD, FPUREG, 4), OpFucom(m));
CASE(DISP(0xDD, FPUREG, 5), OpFucomp(m));
CASE(DISP(0xDD, MEMORY, 0), OpFldl(m));
CASE(DISP(0xDD, MEMORY, 1), OpFisttpll(m));
CASE(DISP(0xDD, MEMORY, 2), OpFstl(m));
CASE(DISP(0xDD, MEMORY, 3), OpFstpl(m));
CASE(DISP(0xDD, MEMORY, 4), OpFrstor(m));
CASE(DISP(0xDD, MEMORY, 6), OpFsave(m));
CASE(DISP(0xDD, MEMORY, 7), OpFstswMw(m));
CASE(DISP(0xDE, FPUREG, 0), OpFaddp(m));
CASE(DISP(0xDE, FPUREG, 1), OpFmulp(m));
CASE(DISP(0xDE, FPUREG, 2), OpFcomp(m));
CASE(DISP(0xDE, FPUREG, 3), OpFcompp(m));
CASE(DISP(0xDE, FPUREG, 4), OpFsubp(m));
CASE(DISP(0xDE, FPUREG, 5), OpFsubrp(m));
CASE(DISP(0xDE, FPUREG, 6), OpFdivp(m));
CASE(DISP(0xDE, FPUREG, 7), OpFdivrp(m));
CASE(DISP(0xDE, MEMORY, 0), OpFiadds(m));
CASE(DISP(0xDE, MEMORY, 1), OpFimuls(m));
CASE(DISP(0xDE, MEMORY, 2), OpFicoms(m));
CASE(DISP(0xDE, MEMORY, 3), OpFicomps(m));
CASE(DISP(0xDE, MEMORY, 4), OpFisubs(m));
CASE(DISP(0xDE, MEMORY, 5), OpFisubrs(m));
CASE(DISP(0xDE, MEMORY, 6), OpFidivs(m));
CASE(DISP(0xDE, MEMORY, 7), OpFidivrs(m));
CASE(DISP(0xDF, FPUREG, 0), OpFfreep(m));
CASE(DISP(0xDF, FPUREG, 1), OpFxch(m));
CASE(DISP(0xDF, FPUREG, 2), OpFstp(m));
CASE(DISP(0xDF, FPUREG, 3), OpFstp(m));
CASE(DISP(0xDF, FPUREG, 4), OpFstswAx(m));
CASE(DISP(0xDF, FPUREG, 5), OpFucomip(m));
CASE(DISP(0xDF, FPUREG, 6), OpFcomip(m));
CASE(DISP(0xDF, MEMORY, 0), OpFilds(m));
CASE(DISP(0xDF, MEMORY, 1), OpFisttps(m));
CASE(DISP(0xDF, MEMORY, 2), OpFists(m));
CASE(DISP(0xDF, MEMORY, 3), OpFistps(m));
CASE(DISP(0xDF, MEMORY, 5), OpFildll(m));
CASE(DISP(0xDF, MEMORY, 7), OpFistpll(m));
case DISP(0xD9, FPUREG, 4):
switch (ModrmRm(m->xedd->op.rde)) {
CASE(0, OpFchs(m));

View file

@ -26,8 +26,15 @@
#include "tool/build/lib/throw.h"
static bool IsOpcodeEqual(uint8_t *a, uint8_t b[16], size_t size) {
if (likely(size)) {
return memcmp(a, b, size) == 0;
unsigned i;
if (size) {
i = 0;
do {
if (a[i] != b[i]) {
return false;
}
} while (++i < size);
return true;
} else {
return false;
}

View file

@ -49,8 +49,8 @@ static void LoadElfLoadSegment(struct Machine *m, void *code, size_t codesize,
vstart = ROUNDDOWN(phdr->p_vaddr, align);
vbss = ROUNDUP(phdr->p_vaddr + phdr->p_filesz, align);
vend = ROUNDUP(phdr->p_vaddr + phdr->p_memsz, align);
fstart = ROUNDDOWN(felf + phdr->p_offset, align);
fend = ROUNDUP(felf + phdr->p_offset + phdr->p_filesz, align);
fstart = felf + ROUNDDOWN(phdr->p_offset, align);
fend = felf + ROUNDUP(phdr->p_offset + phdr->p_filesz, align);
bsssize = vend - vbss;
CHECK_GE(vend, vstart);
CHECK_GE(fend, fstart);
@ -112,9 +112,11 @@ static void LoadBin(struct Machine *m, intptr_t base, const char *prog,
void LoadProgram(struct Machine *m, const char *prog, char **args, char **vars,
struct Elf *elf) {
int fd;
char *real;
ssize_t rc;
struct stat st;
void *code, *stack;
size_t codesize, stacksize;
size_t i, codesize, mappedsize, extrasize, stacksize;
DCHECK_NOTNULL(prog);
elf->prog = prog;
if ((fd = open(prog, O_RDONLY)) == -1 ||
@ -123,16 +125,30 @@ void LoadProgram(struct Machine *m, const char *prog, char **args, char **vars,
fputs(": not found\n", stderr);
exit(1);
}
codesize = st.st_size;
stacksize = STACKSIZE;
codesize = st.st_size;
mappedsize = ROUNDDOWN(codesize, FRAMESIZE);
extrasize = codesize - mappedsize;
CHECK_NE(MAP_FAILED, (stack = mmap(NULL, stacksize, PROT_READ | PROT_WRITE,
MAP_ANONYMOUS | MAP_PRIVATE, -1, 0)));
CHECK_NE(MAP_FAILED, (code = mmap(NULL, codesize, PROT_READ | PROT_WRITE,
MAP_PRIVATE, fd, 0)));
code = real = (char *)0x0000400000000000;
if (mappedsize) {
CHECK_NE(MAP_FAILED, mmap(real, mappedsize, PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_FIXED, fd, 0));
real += mappedsize;
}
if (extrasize) {
CHECK_NE(MAP_FAILED,
mmap(real, ROUNDUP(extrasize, FRAMESIZE), PROT_READ | PROT_WRITE,
MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED, -1, 0));
for (i = 0; i < extrasize; i += (size_t)rc) {
CHECK_NE(-1, (rc = pread(fd, real + i, extrasize - i, mappedsize + i)));
}
}
CHECK_NE(-1, close(fd));
ResetCpu(m);
Write64(m->sp, 0x800000000000);
RegisterMemory(m, 0x800000000000 - stacksize, stack, stacksize);
Write64(m->sp, 0x0000800000000000);
RegisterMemory(m, 0x0000800000000000 - stacksize, stack, stacksize);
LoadArgv(m, prog, args, vars);
if (memcmp(code, "\177ELF", 4) == 0) {
elf->ehdr = code;

File diff suppressed because it is too large Load diff

View file

@ -60,7 +60,7 @@ struct Machine {
struct TlbEntry {
int64_t v;
void *r;
} tlb[4];
} tlb[16];
uint8_t *veg[2 * 8];
uint8_t *beg[2 * 2 * 8];
struct MachineFpu {

View file

@ -52,6 +52,40 @@ static uint64_t *GetPageTable(pml4t_t p, long i, void *NewPhysicalPage(void)) {
return res;
}
static void PtFinder(uint64_t *a, uint64_t *b, uint64_t n, pml4t_t pd, int k) {
uint64_t e, c;
unsigned start;
for (start = (*b >> k) & 511; *b - *a < n && ((*b >> k) & 511) >= start;) {
e = pd[(*b >> k) & 511];
c = ROUNDUP(*b + 1, 1 << k);
if (!IsValidPage(e)) {
*b = c;
} else if (k && *b - *a + (c - *b) > n) {
PtFinder(a, b, n, UnmaskPageAddr(e), k - 9);
} else {
*a = *b = c;
}
}
}
/**
* Locates free memory range.
*
* @param h specifies signedness and around where to start searching
* @return virtual page address with size bytes free, or -1 w/ errno
*/
int64_t FindPml4t(pml4t_t pml4t, uint64_t h, uint64_t n) {
uint64_t a, b;
n = ROUNDUP(n, 4096) >> 12;
a = b = (h & 0x0000fffffffff000) >> 12;
if (!n || n > 0x10000000) return einval();
PtFinder(&a, &b, n, pml4t, 9 * 3);
if (b > 0x0000001000000000) return eoverflow();
if (h < 0x0000800000000000 && b > 0x0000000800000000) return eoverflow();
if (b - a < n) return enomem();
return a << 12;
}
/**
* Maps virtual page region to system memory region.
*
@ -95,70 +129,6 @@ int RegisterPml4t(pml4t_t pml4t, int64_t v, int64_t r, size_t n,
return enomem();
}
/**
* Locates free memory range.
*
* @param hint specifies signedness and around where to start searching
* @return virtual page address with size bytes free, or -1 w/ errno
*/
int64_t FindPml4t(pml4t_t pml4t, int64_t hint, uint64_t size,
void *NewPhysicalPage(void)) {
int64_t res;
unsigned short a[4], b[4];
uint64_t *pdpt, *pdt, *pd, have;
if (!size) return einval();
have = 0;
size = ROUNDUP(size, 4096) >> 12;
b[0] = a[0] = (hint >> 39) & 511;
b[1] = a[1] = (hint >> 30) & 511;
b[2] = a[2] = (hint >> 21) & 511;
a[3] = 0;
for (; b[0] < 512; ++b[0]) {
if (!(pdpt = GetPageTable(pml4t, b[0], NewPhysicalPage))) return -1;
for (; b[1] < 512; ++b[1]) {
if (!(pdt = GetPageTable(pdpt, b[1], NewPhysicalPage))) return -1;
for (; b[2] < 512; ++b[2]) {
if (!IsValidPage(pdt[b[2]])) {
if ((have += 512) >= size) {
return MakeAddress(a);
}
} else if (size < 0x200) {
pd = UnmaskPageAddr(pdt[b[2]]);
for (b[3] = 0; b[3] < 512; ++b[3]) {
if (!IsValidPage(pd[b[3]])) {
if ((have += 1) >= size) {
return MakeAddress(a);
}
} else {
have = 0;
a[0] = b[0];
a[1] = b[1];
a[2] = b[2];
a[3] = b[3];
if ((a[3] += 1) == 512) {
a[3] = 0;
if ((a[2] += 1) == 512) {
a[2] = 0;
if ((a[1] += 1) == 512) {
a[1] = 0;
a[0] += 1;
if (a[0] == 256 || a[0] == 512) {
return eoverflow();
}
}
}
}
}
}
}
}
a[2] = 0;
}
a[1] = 0;
}
return enomem();
}
/**
* Unmaps pages and frees page tables.
*/

View file

@ -13,7 +13,7 @@ typedef uint64_t pml4t_t[512] aligned(4096);
int FreePml4t(pml4t_t, int64_t, uint64_t, void (*)(void *),
int (*)(void *, size_t));
int RegisterPml4t(pml4t_t, int64_t, int64_t, size_t, void *(*)(void));
int64_t FindPml4t(pml4t_t, int64_t, uint64_t, void *(*)(void));
int64_t FindPml4t(pml4t_t, uint64_t, uint64_t);
char *FormatPml4t(pml4t_t) nodiscard;
COSMOPOLITAN_C_END_

View file

@ -68,10 +68,6 @@ static void ResetTlb(struct Machine *m) {
memset(m->tlb, 0, sizeof(m->tlb));
}
static void ResetMem(struct Machine *m) {
FreePml4t(m->cr3, -0x800000000000, 0x800000000000, free, munmap);
}
void ResetCpu(struct Machine *m) {
m->codevirt = 0;
m->codereal = NULL;
@ -96,5 +92,4 @@ void ResetCpu(struct Machine *m) {
ResetTlb(m);
ResetSse(m);
ResetFpu(m);
ResetMem(m);
}

View file

@ -67,16 +67,14 @@ static void WriteInt(uint8_t p[8], uint64_t x, unsigned long w) {
void OpString(struct Machine *m, uint32_t rde, int op) {
void *p[2];
unsigned n;
uint64_t asz;
bool compare;
int64_t sgn, v;
uint8_t s[3][8];
unsigned n, lg2;
uint64_t asz, seg;
sgn = GetFlag(m->flags, FLAGS_DF) ? -1 : 1;
asz = Asz(rde) ? 0xffffffff : 0xffffffffffffffff;
seg = GetSegment(m);
lg2 = RegLog2(rde);
n = 1 << lg2;
n = 1 << RegLog2(rde);
for (;;) {
if (Rep(rde) && !Read64(m->cx)) break;
v = 0;
@ -84,16 +82,18 @@ void OpString(struct Machine *m, uint32_t rde, int op) {
compare = false;
switch (op) {
case STRING_CMPS:
Alu(lg2, ALU_SUB,
ReadInt(Load(m, (Read64(m->si) + seg) & asz, n, s[2]), lg2),
ReadInt(Load(m, Read64(m->di) & asz, n, s[1]), lg2), &m->flags);
Alu(RegLog2(rde), ALU_SUB,
ReadInt(Load(m, (Read64(m->si) + GetSegment(m)) & asz, n, s[2]),
RegLog2(rde)),
ReadInt(Load(m, Read64(m->di) & asz, n, s[1]), RegLog2(rde)),
&m->flags);
Write64(m->di, (Read64(m->di) + sgn * n) & asz);
Write64(m->si, (Read64(m->si) + sgn * n) & asz);
compare = true;
break;
case STRING_MOVS:
memcpy(BeginStore(m, (v = Read64(m->di) & asz), n, p, s[0]),
Load(m, (Read64(m->si) + seg) & asz, n, s[1]), n);
Load(m, (Read64(m->si) + GetSegment(m)) & asz, n, s[1]), n);
Write64(m->di, (Read64(m->di) + sgn * n) & asz);
Write64(m->si, (Read64(m->si) + sgn * n) & asz);
break;
@ -102,23 +102,26 @@ void OpString(struct Machine *m, uint32_t rde, int op) {
Write64(m->di, (Read64(m->di) + sgn * n) & asz);
break;
case STRING_LODS:
memcpy(m->ax, Load(m, (Read64(m->si) + seg) & asz, n, s[1]), n);
memcpy(m->ax, Load(m, (Read64(m->si) + GetSegment(m)) & asz, n, s[1]),
n);
Write64(m->si, (Read64(m->si) + sgn * n) & asz);
break;
case STRING_SCAS:
Alu(lg2, ALU_SUB, ReadInt(Load(m, Read64(m->di) & asz, n, s[1]), lg2),
ReadInt(m->ax, lg2), &m->flags);
Alu(RegLog2(rde), ALU_SUB,
ReadInt(Load(m, Read64(m->di) & asz, n, s[1]), RegLog2(rde)),
ReadInt(m->ax, RegLog2(rde)), &m->flags);
Write64(m->di, (Read64(m->di) + sgn * n) & asz);
compare = true;
break;
case STRING_OUTS:
OpOut(m, Read16(m->dx),
ReadInt(Load(m, (Read64(m->si) + seg) & asz, n, s[1]), lg2));
ReadInt(Load(m, (Read64(m->si) + GetSegment(m)) & asz, n, s[1]),
RegLog2(rde)));
Write64(m->si, (Read64(m->si) + sgn * n) & asz);
break;
case STRING_INS:
WriteInt(BeginStore(m, (v = Read64(m->di) & asz), n, p, s[0]),
OpIn(m, Read16(m->dx)), lg2);
OpIn(m, Read16(m->dx)), RegLog2(rde));
Write64(m->di, (Read64(m->di) + sgn * n) & asz);
break;
default:
@ -138,19 +141,18 @@ void OpRepMovsbEnhanced(struct Machine *m, uint32_t rde) {
bool failed;
uint8_t *direal, *sireal;
unsigned diremain, siremain, i, n;
uint64_t divirtual, sivirtual, diactual, siactual, failaddr, seg, asz, cx;
uint64_t divirtual, sivirtual, diactual, siactual, failaddr, asz, cx;
if (!(cx = Read64(m->cx))) return;
failed = false;
failaddr = 0;
seg = GetSegment(m);
asz = Asz(rde) ? 0xffffffff : 0xffffffffffffffff;
divirtual = Read64(m->di) & asz;
sivirtual = Read64(m->si) & asz;
SetWriteAddr(m, (seg + divirtual) & asz, cx);
SetReadAddr(m, (seg + sivirtual) & asz, cx);
SetWriteAddr(m, (GetSegment(m) + divirtual) & asz, cx);
SetReadAddr(m, (GetSegment(m) + sivirtual) & asz, cx);
do {
diactual = (seg + divirtual) & asz;
siactual = (seg + sivirtual) & asz;
diactual = (GetSegment(m) + divirtual) & asz;
siactual = (GetSegment(m) + sivirtual) & asz;
if (!(direal = FindReal(m, diactual))) {
failaddr = diactual;
failed = true;
@ -181,17 +183,16 @@ void OpRepStosbEnhanced(struct Machine *m, uint32_t rde) {
bool failed;
uint8_t *direal, al;
unsigned diremain, i, n;
uint64_t divirtual, diactual, failaddr, seg, asz, cx;
uint64_t divirtual, diactual, failaddr, asz, cx;
if (!(cx = Read64(m->cx))) return;
failaddr = 0;
failed = false;
al = Read8(m->ax);
seg = GetSegment(m);
asz = Asz(rde) ? 0xffffffff : 0xffffffffffffffff;
divirtual = Read64(m->di) & asz;
SetWriteAddr(m, (seg + divirtual) & asz, cx);
SetWriteAddr(m, (GetSegment(m) + divirtual) & asz, cx);
do {
diactual = (seg + divirtual) & asz;
diactual = (GetSegment(m) + divirtual) & asz;
if (!(direal = FindReal(m, diactual))) {
failaddr = diactual;
failed = true;

View file

@ -66,7 +66,7 @@
#define P(x) ((x) ? PNN(x) : 0)
#define ASSIGN(D, S) memcpy(&D, &S, MIN(sizeof(S), sizeof(D)))
static const struct MachineFdCb kMachineFdCbHost = {
const struct MachineFdCb kMachineFdCbHost = {
.close = close,
.read = read,
.write = write,
@ -282,7 +282,7 @@ static int64_t OpMmap(struct Machine *m, int64_t virt, size_t size, int prot,
if (real == MAP_FAILED) return -1;
if (!(flags & MAP_FIXED)) {
if (0 <= virt && virt < 0x400000) virt = 0x400000;
if ((virt = FindPml4t(m->cr3, virt, size, MallocPage)) == -1) return -1;
if ((virt = FindPml4t(m->cr3, virt, size)) == -1) return -1;
}
CHECK_NE(-1, RegisterMemory(m, virt, real, size));
return virt;

View file

@ -1,9 +1,12 @@
#ifndef COSMOPOLITAN_TOOL_BUILD_LIB_SYSCALL_H_
#define COSMOPOLITAN_TOOL_BUILD_LIB_SYSCALL_H_
#include "tool/build/lib/fds.h"
#include "tool/build/lib/machine.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
extern const struct MachineFdCb kMachineFdCbHost;
void OpSyscall(struct Machine *);
COSMOPOLITAN_C_END_

64
tool/build/lib/word.c Normal file
View file

@ -0,0 +1,64 @@
/*-*- 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/endian.h"
#include "tool/build/lib/memory.h"
#include "tool/build/lib/word.h"
void SetMemoryShort(struct Machine *m, int64_t v, int16_t i) {
void *p[2];
uint8_t b[2];
Write16(BeginStore(m, v, 2, p, b), i);
EndStore(m, v, 2, p, b);
}
void SetMemoryInt(struct Machine *m, int64_t v, int32_t i) {
void *p[2];
uint8_t b[4];
Write32(BeginStore(m, v, 4, p, b), i);
EndStore(m, v, 4, p, b);
}
void SetMemoryLong(struct Machine *m, int64_t v, int64_t i) {
void *p[2];
uint8_t b[8];
Write64(BeginStore(m, v, 8, p, b), i);
EndStore(m, v, 8, p, b);
}
void SetMemoryFloat(struct Machine *m, int64_t v, float f) {
void *p[2];
uint8_t b[4];
memcpy(BeginStore(m, v, 4, p, b), &f, 4);
EndStore(m, v, 4, p, b);
}
void SetMemoryDouble(struct Machine *m, int64_t v, double f) {
void *p[2];
uint8_t b[8];
memcpy(BeginStore(m, v, 8, p, b), &f, 8);
EndStore(m, v, 8, p, b);
}
void SetMemoryLdbl(struct Machine *m, int64_t v, long double f) {
void *p[2];
uint8_t b[10];
memcpy(BeginStore(m, v, 10, p, b), &f, 10);
EndStore(m, v, 10, p, b);
}

16
tool/build/lib/word.h Normal file
View file

@ -0,0 +1,16 @@
#ifndef COSMOPOLITAN_TOOL_BUILD_LIB_WORD_H_
#define COSMOPOLITAN_TOOL_BUILD_LIB_WORD_H_
#include "tool/build/lib/machine.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
void SetMemoryShort(struct Machine *, int64_t, int16_t);
void SetMemoryInt(struct Machine *, int64_t, int32_t);
void SetMemoryLong(struct Machine *, int64_t, int64_t);
void SetMemoryFloat(struct Machine *, int64_t, float);
void SetMemoryDouble(struct Machine *, int64_t, double);
void SetMemoryLdbl(struct Machine *, int64_t, long double);
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_TOOL_BUILD_LIB_WORD_H_ */

View file

@ -59,7 +59,7 @@ long double fyl2xp1(long double x, long double y) {
}
long double fscale(long double significand, long double exponent) {
return scalbnl(significand, exponent);
return scalbl(significand, exponent);
}
long double fprem(long double dividend, long double modulus, uint32_t *sw) {

View file

@ -18,6 +18,7 @@
02110-1301 USA
*/
#include "libc/alg/alg.h"
#include "libc/bits/bits.h"
#include "libc/bits/safemacros.h"
#include "libc/calls/calls.h"
#include "libc/calls/hefty/spawn.h"
@ -273,7 +274,7 @@ int ReadResponse(void) {
if (!n) break;
do {
CHECK_GE(n, 4 + 1);
CHECK_EQ(RUNITD_MAGIC, read32be(p));
CHECK_EQ(RUNITD_MAGIC, READ32BE(p));
p += 4, n -= 4;
cmd = *p++, n--;
switch (cmd) {

View file

@ -20,8 +20,11 @@
#include "libc/runtime/runtime.h"
#include "libc/stdio/stdio.h"
#include "libc/sysv/consts/ex.h"
#include "libc/sysv/consts/fileno.h"
#include "libc/x/x.h"
#include "tool/build/lib/loader.h"
#include "tool/build/lib/machine.h"
#include "tool/build/lib/syscall.h"
struct Machine m[1];
@ -38,6 +41,15 @@ int main(int argc, char *argv[]) {
}
InitMachine(m);
LoadProgram(m, argv[1], argv + 2, environ, &elf);
m->fds.i = 3;
m->fds.n = 8;
m->fds.p = xcalloc(m->fds.n, sizeof(struct MachineFd));
m->fds.p[0].fd = STDIN_FILENO;
m->fds.p[0].cb = &kMachineFdCbHost;
m->fds.p[1].fd = STDOUT_FILENO;
m->fds.p[1].cb = &kMachineFdCbHost;
m->fds.p[2].fd = STDERR_FILENO;
m->fds.p[2].cb = &kMachineFdCbHost;
if (!(rc = setjmp(m->onhalt))) {
for (;;) {
LoadInstruction(m);

View file

@ -149,7 +149,23 @@
"__builtin_infl"
"__builtin_inffn"
"__builtin_inffnx"
"__builtin_isnan"
"__builtin_signbit"
"__builtin_signbitf"
"__builtin_signbitl"
"__builtin_isfinite"
"__builtin_isinf"
"__builtin_isinfinite"
"__builtin_isnormal"
"__builtin_isinf_sign"
"__builtin_isgreater"
"__builtin_isgreaterequal"
"__builtin_isgreater"
"__builtin_isgreaterequal"
"__builtin_isless"
"__builtin_islessequal"
"__builtin_islessgreater"
"__builtin_isunordered"
"__builtin_nan"
"__builtin_nand32"
"__builtin_nand64"

View file

@ -296,6 +296,7 @@
"__params_nonnull__"
"__weak__"
"__vector_size__"
"__ms_abi__"
"__mode__"))
(clang

View file

@ -105,6 +105,7 @@
"PAGESIZE"
"FRAMESIZE"
"BIGPAGESIZE"
"STACKSIZE"
"ENV_MAX"
"ARG_MAX"
"CMD_MAX"

View file

@ -20,6 +20,7 @@
#include "libc/bits/safemacros.h"
#include "libc/conv/conv.h"
#include "libc/fmt/fmt.h"
#include "libc/limits.h"
#include "libc/log/check.h"
#include "libc/log/log.h"
#include "libc/macros.h"

View file

@ -4,7 +4,7 @@
COSMOPOLITAN_C_START_
typedef void *StringTableFormatter(long yn, long xn, const char *const[yn][xn],
int emit(), void *, const char *,
int (*)(), void *, const char *,
const char *, const char *);
StringTableFormatter FormatStringTable;
@ -15,28 +15,27 @@ StringTableFormatter FormatStringTableForAssertion;
void *FreeStringTableCells(long yn, long xn, char *[yn][xn]);
void FormatMatrixDouble(long yn, long xn, const double[yn][xn], int emit(),
void FormatMatrixDouble(long yn, long xn, const double[yn][xn], int (*)(),
void *, StringTableFormatter, const char *,
const char *, const char *, double,
double rounder(double));
void FormatMatrixFloat(long yn, long xn, const float[yn][xn], int emit(),
void *, StringTableFormatter, const char *, const char *,
const char *, double, double rounder(double));
void FormatMatrixByte(long yn, long xn, const unsigned char[yn][xn], int emit(),
const char *, const char *, double, double (*)(double));
void FormatMatrixFloat(long yn, long xn, const float[yn][xn], int (*)(), void *,
StringTableFormatter, const char *, const char *,
const char *, double, double (*)(double));
void FormatMatrixByte(long yn, long xn, const unsigned char[yn][xn], int (*)(),
void *, StringTableFormatter, const char *, const char *,
const char *);
void FormatMatrixShort(long yn, long xn, const short[yn][xn], int emit(),
void *, StringTableFormatter, const char *, const char *,
void FormatMatrixShort(long yn, long xn, const short[yn][xn], int (*)(), void *,
StringTableFormatter, const char *, const char *,
const char *);
char *StringifyMatrixDouble(long yn, long xn, const double[yn][xn],
StringTableFormatter, const char *, const char *,
const char *, double,
double rounder(double)) mallocesque;
double (*)(double)) mallocesque;
char *StringifyMatrixFloat(long yn, long xn, const float[yn][xn],
StringTableFormatter, const char *, const char *,
const char *, double,
double rounder(double)) mallocesque;
double (*)(double)) mallocesque;
char *StringifyMatrixByte(long yn, long xn, const unsigned char[yn][xn],
StringTableFormatter, const char *, const char *,
const char *) mallocesque;