Add The LISP Challenge

This change introduces a 2.5kb program that's comes pretty close so far
to bootstrapping John McCarthy's metacircular evaluator on bare metal.
This commit is contained in:
Justine Tunney 2020-10-01 01:20:13 -07:00
parent fd22e55b42
commit b6793d42d5
34 changed files with 1056 additions and 358 deletions

View file

@ -23,6 +23,10 @@
#include "tool/build/lib/modrm.h"
#include "tool/build/lib/throw.h"
uint64_t AddressOb(struct Machine *m, uint32_t rde) {
return AddSegment(m, rde, m->xedd->op.disp, m->ds);
}
uint8_t *GetSegment(struct Machine *m, uint32_t rde, int s) {
switch (s & 7) {
case 0:

View file

@ -6,6 +6,7 @@
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
uint64_t AddressOb(struct Machine *, uint32_t);
uint64_t AddressDi(struct Machine *, uint32_t);
uint64_t AddressSi(struct Machine *, uint32_t);
uint64_t DataSegment(struct Machine *, uint32_t, uint64_t);

View file

@ -23,7 +23,7 @@
#include "tool/build/lib/flags.h"
#include "tool/build/lib/throw.h"
void OpDas(struct Machine *m, uint32_t rde) {
relegated void OpDas(struct Machine *m, uint32_t rde) {
uint8_t al, af, cf;
af = cf = 0;
al = m->ax[0];
@ -39,7 +39,7 @@ void OpDas(struct Machine *m, uint32_t rde) {
AluFlags8(m->ax[0], af, &m->flags, 0, cf);
}
void OpAaa(struct Machine *m, uint32_t rde) {
relegated void OpAaa(struct Machine *m, uint32_t rde) {
uint8_t af, cf;
af = cf = 0;
if ((m->ax[0] & 0x0f) > 9 || GetFlag(m->flags, FLAGS_AF)) {
@ -51,7 +51,7 @@ void OpAaa(struct Machine *m, uint32_t rde) {
AluFlags8(m->ax[0], af, &m->flags, 0, cf);
}
void OpAas(struct Machine *m, uint32_t rde) {
relegated void OpAas(struct Machine *m, uint32_t rde) {
uint8_t af, cf;
af = cf = 0;
if ((m->ax[0] & 0x0f) > 9 || GetFlag(m->flags, FLAGS_AF)) {
@ -63,7 +63,7 @@ void OpAas(struct Machine *m, uint32_t rde) {
AluFlags8(m->ax[0], af, &m->flags, 0, cf);
}
void OpAam(struct Machine *m, uint32_t rde) {
relegated void OpAam(struct Machine *m, uint32_t rde) {
uint8_t i = m->xedd->op.uimm0;
if (!i) ThrowDivideError(m);
m->ax[1] = m->ax[0] / i;
@ -71,7 +71,7 @@ void OpAam(struct Machine *m, uint32_t rde) {
AluFlags8(m->ax[0], 0, &m->flags, 0, 0);
}
void OpAad(struct Machine *m, uint32_t rde) {
relegated void OpAad(struct Machine *m, uint32_t rde) {
uint8_t i = m->xedd->op.uimm0;
Write16(m->ax, (m->ax[1] * i + m->ax[0]) & 0xff);
AluFlags8(m->ax[0], 0, &m->flags, 0, 0);

View file

@ -35,6 +35,7 @@
#include "tool/build/lib/case.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/memory.h"
#include "tool/build/lib/modrm.h"
@ -173,19 +174,21 @@ long DisFind(struct Dis *d, int64_t addr) {
return -1;
}
static long DisOne(struct Dis *d, struct Machine *m, int64_t addr) {
static long DisAppendOpLines(struct Dis *d, struct Machine *m, int64_t addr) {
void *r;
int64_t ip;
unsigned k;
uint8_t b[15];
struct DisOp op;
long i, n, symbol;
n = 15;
if ((symbol = DisFindSym(d, addr)) != -1) {
if (d->syms.p[symbol].addr <= addr &&
addr < d->syms.p[symbol].addr + d->syms.p[symbol].size) {
n = d->syms.p[symbol].size - (addr - d->syms.p[symbol].addr);
ip = addr - Read64(m->cs);
if ((symbol = DisFindSym(d, ip)) != -1) {
if (d->syms.p[symbol].addr <= ip &&
ip < d->syms.p[symbol].addr + d->syms.p[symbol].size) {
n = d->syms.p[symbol].size - (ip - d->syms.p[symbol].addr);
}
if (addr == d->syms.p[symbol].addr && d->syms.p[symbol].name) {
if (ip == d->syms.p[symbol].addr && d->syms.p[symbol].name) {
op.addr = addr;
op.size = 0;
op.active = true;
@ -219,18 +222,19 @@ static long DisOne(struct Dis *d, struct Machine *m, int64_t addr) {
return n;
}
long Dis(struct Dis *d, struct Machine *m, int64_t addr, int lines) {
long Dis(struct Dis *d, struct Machine *m, uint64_t addr, uint64_t ip,
int lines) {
int64_t i, j, symbol;
DisFreeOps(&d->ops);
if ((symbol = DisFindSym(d, addr)) != -1 &&
(d->syms.p[symbol].addr < addr &&
addr < d->syms.p[symbol].addr + d->syms.p[symbol].size)) {
for (i = d->syms.p[symbol].addr; i < addr; i += j) {
if ((j = DisOne(d, m, i)) == -1) return -1;
if ((j = DisAppendOpLines(d, m, i)) == -1) return -1;
}
}
for (i = 0; i < lines; ++i, addr += j) {
if ((j = DisOne(d, m, addr)) == -1) return -1;
if ((j = DisAppendOpLines(d, m, addr)) == -1) return -1;
}
return 0;
}
@ -247,6 +251,7 @@ const char *DisGetLine(struct Dis *d, struct Machine *m, size_t i) {
d->xedd, AccessRam(m, d->ops.p[i].addr, d->ops.p[i].size, r, b, true),
d->ops.p[i].size);
d->addr = d->ops.p[i].addr;
d->m = m;
p = DisLineCode(d, d->buf);
CHECK_LT(p - d->buf, sizeof(d->buf));
return d->buf;

View file

@ -45,11 +45,12 @@ struct Dis {
} * p;
} edges;
struct XedDecodedInst xedd[1];
uint64_t addr;
struct Machine *m; /* for the segment registers */
uint64_t addr; /* current effective address */
char buf[512];
};
long Dis(struct Dis *, struct Machine *, int64_t, int);
long Dis(struct Dis *, struct Machine *, uint64_t, uint64_t, int);
long DisFind(struct Dis *, int64_t);
void DisFree(struct Dis *);
void DisFreeOp(struct DisOp *);

View file

@ -59,6 +59,43 @@ static int64_t RipRelative(struct Dis *d, int64_t i) {
return d->addr + d->xedd->length + i;
}
static int64_t ZeroExtend(uint32_t rde, int64_t i) {
switch (Mode(rde)) {
case XED_MODE_REAL:
return i & 0xffff;
case XED_MODE_LEGACY:
return i & 0xffffffff;
default:
return i;
}
}
static int64_t Unrelative(uint32_t rde, int64_t i) {
switch (Eamode(rde)) {
case XED_MODE_REAL:
return i & 0xffff;
case XED_MODE_LEGACY:
return i & 0xffffffff;
default:
return i;
}
}
static int64_t GetSeg(struct Dis *d, uint32_t rde, unsigned char *s) {
switch (Sego(rde) ? Sego(rde) : d->xedd->op.hint) {
default:
return Read64(s);
case 1:
return Read64(d->m->es);
case 2:
return Read64(d->m->cs);
case 3:
return Read64(d->m->ss);
case 4:
return Read64(d->m->ds);
}
}
static const char *GetAddrReg(struct Dis *d, uint32_t rde, uint8_t x,
uint8_t r) {
return kGreg[Eamode(rde) == XED_MODE_REAL][Eamode(rde) == XED_MODE_LONG]
@ -106,12 +143,12 @@ static char *DisInt(char *p, int64_t x) {
return p;
}
static char *DisSym(struct Dis *d, char *p, int64_t addr) {
static char *DisSym(struct Dis *d, char *p, int64_t addr, int64_t ip) {
long sym;
int64_t addend;
const char *name;
if ((sym = DisFindSym(d, addr)) != -1 && d->syms.p[sym].name) {
addend = addr - d->syms.p[sym].addr;
if ((sym = DisFindSym(d, ip)) != -1 && d->syms.p[sym].name) {
addend = ip - d->syms.p[sym].addr;
name = d->syms.stab + d->syms.p[sym].name;
p = Demangle(p, name);
if (addend) {
@ -124,10 +161,11 @@ static char *DisSym(struct Dis *d, char *p, int64_t addr) {
}
}
static char *DisSymLiteral(struct Dis *d, char *p, uint64_t x) {
static char *DisSymLiteral(struct Dis *d, uint32_t rde, char *p, uint64_t addr,
uint64_t ip) {
*p++ = '$';
p = HighStart(p, g_high.literal);
p = DisSym(d, p, x);
p = DisSym(d, p, addr, ip);
p = HighEnd(p);
return p;
}
@ -154,18 +192,30 @@ static char *DisSego(struct Dis *d, uint32_t rde, char *p) {
return p;
}
static bool IsRealModrmAbsolute(uint32_t rde) {
return Eamode(rde) == XED_MODE_REAL && ModrmRm(rde) == 6 && !ModrmMod(rde);
}
static char *DisM(struct Dis *d, uint32_t rde, char *p) {
int64_t disp;
const char *base, *index, *scale;
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)) ||
IsRealModrmAbsolute(rde) ||
(ModrmMod(rde) == 0b00 && ModrmRm(rde) == 0b100 &&
SibBase(d->xedd) == 0b101)) {
disp = d->xedd->op.disp;
if (IsRipRelative(rde)) disp = RipRelative(d, disp);
p = DisSym(d, p, disp);
if (IsRipRelative(rde)) {
if (Mode(rde) == XED_MODE_LONG) {
disp = RipRelative(d, disp);
} else {
disp = Unrelative(rde, disp);
}
} else if (IsRealModrmAbsolute(rde)) {
disp = Unrelative(rde, disp);
}
p = DisSym(d, p, disp, disp);
}
if (Eamode(rde) != XED_MODE_REAL) {
if (!SibExists(rde)) {
@ -355,11 +405,12 @@ static char *DisHd(struct Dis *d, uint32_t rde, char *p) {
}
static char *DisImm(struct Dis *d, uint32_t rde, char *p) {
return DisSymLiteral(d, p, d->xedd->op.uimm0);
return DisSymLiteral(d, rde, p, d->xedd->op.uimm0,
ZeroExtend(rde, d->xedd->op.uimm0));
}
static char *DisRvds(struct Dis *d, uint32_t rde, char *p) {
return DisSymLiteral(d, p, d->xedd->op.disp);
return DisSymLiteral(d, rde, p, d->xedd->op.disp, d->xedd->op.disp);
}
static char *DisKpvds(struct Dis *d, uint32_t rde, char *p, uint64_t x) {
@ -400,11 +451,12 @@ static char *DisJb(struct Dis *d, uint32_t rde, char *p) {
}
static char *DisJvds(struct Dis *d, uint32_t rde, char *p) {
return DisSym(d, p, RipRelative(d, d->xedd->op.disp));
return DisSym(d, p, RipRelative(d, d->xedd->op.disp),
RipRelative(d, d->xedd->op.disp) - Read64(d->m->cs));
}
static char *DisAbs(struct Dis *d, uint32_t rde, char *p) {
return DisSym(d, p, d->xedd->op.disp);
return DisSym(d, p, d->xedd->op.disp, d->xedd->op.disp);
}
static char *DisSw(struct Dis *d, uint32_t rde, char *p) {

View file

@ -188,7 +188,7 @@ static void OpSahf(struct Machine *m, uint32_t rde) {
}
static void OpLeaGvqpM(struct Machine *m, uint32_t rde) {
WriteRegister(rde, RegRexrReg(m, rde), ComputeAddress(m, rde));
WriteRegister(rde, RegRexrReg(m, rde), LoadEffectiveAddress(m, rde).addr);
}
static relegated void OpPushSeg(struct Machine *m, uint32_t rde) {
@ -216,6 +216,14 @@ static relegated void OpJmpf(struct Machine *m, uint32_t rde) {
m->ip = m->xedd->op.disp;
}
static relegated void OpXlatAlBbb(struct Machine *m, uint32_t rde) {
uint64_t v;
v = MaskAddress(Eamode(rde), Read64(m->bx) + Read8(m->ax));
v = DataSegment(m, rde, v);
SetReadAddr(m, v, 1);
Write8(m->ax, Read8(ResolveAddress(m, v)));
}
static void WriteEaxAx(struct Machine *m, uint32_t rde, uint32_t x) {
if (!Osz(rde)) {
Write64(m->ax, x);
@ -264,14 +272,6 @@ static void OpOutDxAx(struct Machine *m, uint32_t rde) {
OpOut(m, Read16(m->dx), ReadEaxAx(m, rde));
}
static void OpXlatAlBbb(struct Machine *m, uint32_t rde) {
uint64_t v;
v = MaskAddress(Eamode(rde), Read64(m->bx) + Read8(m->ax));
v = DataSegment(m, rde, v);
SetReadAddr(m, v, 1);
Write8(m->ax, Read8(ResolveAddress(m, v)));
}
static void AluEb(struct Machine *m, uint32_t rde, aluop_f op) {
uint8_t *p;
p = GetModrmRegisterBytePointerWrite(m, rde);
@ -515,13 +515,17 @@ static void OpMovEbIb(struct Machine *m, uint32_t rde) {
}
static void OpMovAlOb(struct Machine *m, uint32_t rde) {
SetReadAddr(m, m->xedd->op.disp, 1);
Write8(ResolveAddress(m, m->xedd->op.disp), Read8(m->ax));
int64_t addr;
addr = AddressOb(m, rde);
SetWriteAddr(m, addr, 1);
Write8(m->ax, Read8(ResolveAddress(m, addr)));
}
static void OpMovObAl(struct Machine *m, uint32_t rde) {
SetWriteAddr(m, m->xedd->op.disp, 1);
Write8(m->ax, Read8(ResolveAddress(m, m->xedd->op.disp)));
int64_t addr;
addr = AddressOb(m, rde);
SetReadAddr(m, addr, 1);
Write8(ResolveAddress(m, addr), Read8(m->ax));
}
static void OpMovRaxOvqp(struct Machine *m, uint32_t rde) {
@ -1199,35 +1203,6 @@ static void OpJcxz(struct Machine *m, uint32_t rde) {
}
}
static void Loop(struct Machine *m, uint32_t rde, bool cond) {
uint64_t cx;
cx = Read64(m->cx) - 1;
if (Eamode(rde) != XED_MODE_REAL) {
if (Eamode(rde) == XED_MODE_LEGACY) {
cx &= 0xffffffff;
}
Write64(m->cx, cx);
} else {
cx &= 0xffff;
Write16(m->cx, cx);
}
if (cx && cond) {
OpJmp(m, rde);
}
}
static void OpLoope(struct Machine *m, uint32_t rde) {
Loop(m, rde, GetFlag(m->flags, FLAGS_ZF));
}
static void OpLoopne(struct Machine *m, uint32_t rde) {
Loop(m, rde, !GetFlag(m->flags, FLAGS_ZF));
}
static void OpLoop1(struct Machine *m, uint32_t rde) {
Loop(m, rde, true);
}
static void Bitscan(struct Machine *m, uint32_t rde, bitscan_f op) {
WriteRegister(
rde, RegRexrReg(m, rde),
@ -1259,6 +1234,35 @@ static void OpNegEb(struct Machine *m, uint32_t rde) {
AluEb(m, rde, Neg8);
}
static relegated void Loop(struct Machine *m, uint32_t rde, bool cond) {
uint64_t cx;
cx = Read64(m->cx) - 1;
if (Eamode(rde) != XED_MODE_REAL) {
if (Eamode(rde) == XED_MODE_LEGACY) {
cx &= 0xffffffff;
}
Write64(m->cx, cx);
} else {
cx &= 0xffff;
Write16(m->cx, cx);
}
if (cx && cond) {
OpJmp(m, rde);
}
}
static relegated void OpLoope(struct Machine *m, uint32_t rde) {
Loop(m, rde, GetFlag(m->flags, FLAGS_ZF));
}
static relegated void OpLoopne(struct Machine *m, uint32_t rde) {
Loop(m, rde, !GetFlag(m->flags, FLAGS_ZF));
}
static relegated void OpLoop1(struct Machine *m, uint32_t rde) {
Loop(m, rde, true);
}
static const nexgen32e_f kOp0f6[] = {
OpAlubiTest,
OpAlubiTest,

View file

@ -26,51 +26,7 @@
#include "tool/build/lib/modrm.h"
#include "tool/build/lib/throw.h"
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) {
struct AddrSeg LoadEffectiveAddress(const struct Machine *m, uint32_t rde) {
uint8_t *s = m->ds;
uint64_t i = m->xedd->op.disp;
DCHECK(!IsModrmRegister(rde));
@ -100,10 +56,53 @@ 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 {
return ComputeAddressReal(m, rde, s, 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 (struct AddrSeg){i, s};
}
int64_t ComputeAddress(const struct Machine *m, uint32_t rde) {
struct AddrSeg ea;
ea = LoadEffectiveAddress(m, rde);
return AddSegment(m, rde, ea.addr, ea.seg);
}
void *ComputeReserveAddressRead(struct Machine *m, uint32_t rde, size_t n) {

View file

@ -50,9 +50,15 @@ COSMOPOLITAN_C_START_
#define SibIsAbsolute(x, r) (!SibHasBase(x, r) && !SibHasIndex(x))
#define IsRipRelative(x) (ModrmRm(x) == 5 && !ModrmMod(x))
struct AddrSeg {
int64_t addr;
uint8_t *seg;
};
extern const uint8_t kByteReg[32];
int64_t ComputeAddress(const struct Machine *, uint32_t) nosideeffect;
int64_t ComputeAddress(const struct Machine *, uint32_t);
struct AddrSeg LoadEffectiveAddress(const struct Machine *, uint32_t);
void *ComputeReserveAddressRead(struct Machine *, uint32_t, size_t);
void *ComputeReserveAddressRead1(struct Machine *, uint32_t);

View file

@ -469,18 +469,21 @@ ssize_t MachinePtyWrite(struct MachinePty *pty, const void *data, size_t n) {
} else if (!ThomPikeCont(p[i])) {
pty->state = kMachinePtyUtf8;
pty->u8 = ThomPikeByte(p[i]);
pty->n8 = ThomPikeLen(p[i]) - 1;
}
break;
case kMachinePtyUtf8:
if (ThomPikeCont(p[i])) {
pty->u8 <<= 6;
pty->u8 |= p[i] & 0b00111111;
} else {
SetMachinePtyCell(pty, pty->u8);
pty->state = kMachinePtyAscii;
pty->u8 = 0;
--i;
if (--pty->n8) {
break;
}
}
SetMachinePtyCell(pty, pty->u8);
pty->state = kMachinePtyAscii;
pty->u8 = 0;
--i;
break;
case kMachinePtyEsc:
if (p[i] == '[') {
@ -531,9 +534,6 @@ ssize_t MachinePtyWrite(struct MachinePty *pty, const void *data, size_t n) {
abort();
}
}
if (pty->u8) {
SetMachinePtyCell(pty, pty->u8);
}
return n;
}

View file

@ -28,6 +28,7 @@ struct MachinePty {
uint32_t fg;
uint32_t bg;
uint32_t u8;
uint32_t n8;
uint32_t *wcs;
uint32_t *fgs;
uint32_t *bgs;