code: 9ferno

Download patch

ref: b9b3baa39ef278fcaf53302031c251432d430acd
parent: a62654ed1b81fb99271d6a7e8ebe7a870ea1099c
author: joe9 <joe9mail@gmail.com>
date: Thu Mar 25 16:44:12 EDT 2021

working 9front amd64 build

diff: cannot open b/9front/amd64/include//null: file does not exist: 'b/9front/amd64/include//null' diff: cannot open b/9front/amd64//null: file does not exist: 'b/9front/amd64//null' diff: cannot open b/9front/include//null: file does not exist: 'b/9front/include//null' diff: cannot open b/9front//null: file does not exist: 'b/9front//null' diff: cannot open b/emu/9front//null: file does not exist: 'b/emu/9front//null' diff: cannot open b/libsec/9front-amd64//null: file does not exist: 'b/libsec/9front-amd64//null'
--- /dev/null
+++ b/9front/amd64/include/emu.h
@@ -1,0 +1,23 @@
+/*
+ * system- and machine-specific declarations for emu:
+ * floating-point save and restore, signal handling primitive, and
+ * implementation of the current-process variable `up'.
+ */
+
+extern	Proc**	Xup;
+#define	up	(*Xup)
+
+typedef	struct	FPU	FPU;
+
+/*
+ * This structure must agree with FPsave and FPrestore asm routines
+ */
+struct FPU
+{
+	/* TODO check this 28 bytes. 28 -> 56? */
+	uchar	env[28];
+};
+
+typedef jmp_buf osjmpbuf;
+#define	ossetjmp(buf)	setjmp(buf)
+
--- /dev/null
+++ b/9front/amd64/include/lib9.h
@@ -1,0 +1,1 @@
+#include "../../include/lib9.h"
--- /dev/null
+++ b/9front/amd64/include/u.h
@@ -1,0 +1,1 @@
+#include "/amd64/include/u.h"
--- /dev/null
+++ b/9front/include/lib9.h
@@ -1,0 +1,14 @@
+#include <u.h>
+typedef usize size_t;
+
+#define	Rendez	xRendez
+#include <libc.h>
+#undef Rendez
+
+
+/*
+ *	Extensions for Inferno to basic libc.h
+ */
+
+#define	setbinmode()
+#define	USE_FPdbleword
--- /dev/null
+++ b/9front/include/lib9x.h
@@ -1,0 +1,20 @@
+#include <u.h>
+typedef usize size_t;
+
+#define	Runeerror xRuneerror
+#define	Rendez	xRendez
+#include <libc.h>
+#undef Runeerror
+#undef Rendez
+
+
+enum
+{
+	Runeerror	= 0x80,		/* decoding error in UTF */
+};
+/*
+ *	Extensions for Inferno to basic libc.h
+ */
+
+#define	setbinmode()
+#define	USE_FPdbleword
--- /dev/null
+++ b/emu/9front/asm-386.s
@@ -1,0 +1,33 @@
+
+TEXT	tramp(SB),$0
+	MOVL	nsp+0(FP), BX		/* new stack */
+	MOVL	fn+4(FP), CX		/* func to exec */
+	MOVL	arg+8(FP),DX
+
+	LEAL	-8(BX), SP		/* new stack */
+	PUSHL	DX
+	CALL	*CX
+	POPL	AX
+
+	PUSHL	$0
+	CALL	_exits(SB)
+	POPL	AX
+	RET
+
+TEXT	vstack(SB),$0
+	MOVL	arg+0(FP), AX
+	MOVL	ustack(SB), SP
+	PUSHL	AX
+	CALL	exectramp(SB)
+	POPL	AX			/* dammit ken! */
+	RET
+
+TEXT	FPsave(SB), 1, $0
+	MOVL	fpu+0(FP), AX
+	FSTENV	0(AX)
+	RET
+
+TEXT	FPrestore(SB), 1, $0
+	MOVL	fpu+0(FP), AX
+	FLDENV	0(AX)
+	RET
--- /dev/null
+++ b/emu/9front/asm-amd64.s
@@ -1,0 +1,35 @@
+
+TEXT	tramp(SB),$0
+					/* RARG has the first argument - new stack */
+					/* even though the first argument is in RARG, the 0(FP) is still filled with some value */
+					/* FP is 64 bytes from SP(?) as there is a SUBQ $0x40, SP on function entry */
+	MOVQ	fn+8(FP), CX		/* func to exec - second argument */
+	MOVQ	arg+16(FP),DX		/* argument to the function */
+
+	LEAQ	-16(RARG), SP	/* new stack */
+	MOVQ	DX, RARG
+	PUSHQ	RARG		/* not sure why I need this, but, using it to balance the POPQ below */
+	CALL	*CX
+	POPQ	AX
+
+	MOVQ	$0, RARG
+	PUSHQ	RARG		/* not sure why I need this PUSHQ and CALL. Why not just a JMP to _exits() */
+	CALL	_exits(SB)
+	POPQ	AX
+	RET
+
+TEXT	vstack(SB),$0
+				/* MOVL	arg+0(FP), AX not needed as the first argument is in RARG */
+	MOVQ	ustack(SB), SP
+	PUSHQ	RARG		/* cannot figure out why I need this. But, the compiler will not compile without this */
+	CALL	exectramp(SB)
+	POPQ	AX /* dammit ken! */
+	RET
+
+TEXT	FPsave(SB), 1, $0
+	FSTENV	0(RARG)	/* in amd64, the first argument is passed in RARG */
+	RET
+
+TEXT	FPrestore(SB), 1, $0
+	FLDENV	0(RARG)
+	RET
--- /dev/null
+++ b/emu/9front/asm-arm.s
@@ -1,0 +1,32 @@
+/* for VFP */
+#define VMRS(fp, cpu) WORD $(0xeef00a10 | (fp)<<16 | (cpu)<<12) /* FP → arm */
+#define VMSR(cpu, fp) WORD $(0xeee00a10 | (fp)<<16 | (cpu)<<12) /* arm → FP */
+
+#define Fpscr 1
+
+	TEXT	tramp(SB), 1, $0
+	MOVW	fn+4(FP), R1		/* func to exec */
+	MOVW	arg+8(FP), R2		/* argument */
+	SUB	$8, R0			/* new stack */
+	MOVW	R0, SP
+	MOVW	R2, R0
+	BL	(R1)
+
+	MOVW	$0, R0
+	BL	_exits(SB)
+	RET
+
+	TEXT	vstack(SB), 1, $0
+	MOVW	ustack(SB), SP
+	BL		exectramp(SB)
+	RET
+
+	TEXT	FPsave(SB), 1, $0
+	VMRS(Fpscr, 1)
+	MOVW	R1, 0(R0)
+	RET
+
+	TEXT	FPrestore(SB), 1, $0
+	MOVW	(R0), R0
+	VMSR(0, Fpscr)
+	RET
--- /dev/null
+++ b/emu/9front/asm-mips.s
@@ -1,0 +1,24 @@
+
+	TEXT	tramp(SB), 1, $0
+	ADDU	$-8, R1, R3		/* new stack */
+	MOVW	4(FP), R2		/* func to exec */
+	MOVW	8(FP), R1		/* arg to reg */
+	MOVW	R3, R29			/* new stack */
+	JAL	(R2)
+	MOVW	R0, R1
+	JMP	_exits(SB)
+
+	TEXT	vstack(SB), 1, $0	/* Passes &targ through R1 */
+	MOVW	ustack(SB), R29
+	JMP	exectramp(SB)
+	RET
+
+	TEXT	FPsave(SB), 1, $0
+	MOVW	FCR31, R2
+	MOVW	R2, 0(R1)
+	RET
+
+	TEXT	FPrestore(SB), 1, $0
+	MOVW	0(R1), R2
+	MOVW	R2, FCR31
+	RET
--- /dev/null
+++ b/emu/9front/asm-power.s
@@ -1,0 +1,28 @@
+	TEXT	tramp(SB), 1, $0
+	ADD	$-8, R3, R4		/* new stack */
+	MOVW	4(FP), R5		/* func to exec */
+	MOVW	R5, LR
+	MOVW	8(FP), R3		/* arg to reg */
+	MOVW	R4, R1			/* new stack */
+	BL	(LR)
+	MOVW	R0, R3
+	MOVW	$_exits(SB), R4
+	MOVW	R4, LR
+	BR	(LR)
+
+	TEXT	vstack(SB), 1, $0	/* Passes &targ through R3 */
+	MOVW	ustack(SB), R1
+	MOVW	$exectramp(SB), R4
+	MOVW	R4, CTR
+	BR	(CTR)
+	RETURN
+
+	TEXT	FPsave(SB), 1, $0
+	MOVFL	FPSCR, F0
+	FMOVD	F0, 0(R3)
+	RETURN
+
+	TEXT	FPrestore(SB), 1, $0
+	FMOVD	0(R3), F0
+	MOVFL	F0, FPSCR
+	RETURN
--- /dev/null
+++ b/emu/9front/asm-sparc.s
@@ -1,0 +1,22 @@
+	TEXT	tramp(SB), 1, $0
+	ADD	$-8, R7, R3		/* new stack */
+	MOVW	4(FP), R4		/* func to exec */
+	MOVW	8(FP), R7		/* arg to reg */
+	MOVW	R3, R1			/* new stack */
+	JMPL	(R4)
+	MOVW	R0, R7
+	JMPL	_exits(SB)		/* Leaks the stack in R29 */
+
+	TEXT	vstack(SB), 1, $0	/* Passes &targ through R7 */
+	MOVW	ustack(SB), R1
+	MOVW	$exectramp(SB), R3
+	JMP	(R3)
+	RETURN
+
+	TEXT	FPsave(SB), 1, $0
+	MOVW	FSR, 0(R7)
+	RETURN
+
+	TEXT	FPrestore(SB), 1, $0
+	MOVW	0(R7), FSR
+	RETURN
--- /dev/null
+++ b/emu/9front/cmd.c
@@ -1,0 +1,189 @@
+#include	"dat.h"
+#include	"fns.h"
+#include	"error.h"
+
+extern	void	vstack(void*);
+
+/*
+ * all this is for the benefit of devcmd.
+ * i hope it's grateful.
+ */
+
+typedef struct Targ Targ;
+struct Targ
+{
+	int	fd[3];	/* standard input, output and error */
+	int	wfd;
+	int*	spin;
+	char**	args;
+	char*	dir;
+	int	pid;
+	int	nice;
+};
+
+/*
+ * called by vstack once it has moved to
+ * the unshared stack in the new process.
+ */
+void
+exectramp(Targ *t)
+{
+	int *fd, i, nfd;
+	char filename[128], err[ERRMAX], status[2*ERRMAX];
+
+	t->pid = getpid();
+	*t->spin = 0;	/* allow parent to proceed: can't just rendezvous: see below */
+	fd = t->fd;
+
+	snprint(filename, sizeof(filename), "#d/%d", t->wfd);
+	t->wfd = open(filename, OWRITE|OCEXEC);
+	/* if it failed, we'll manage */
+
+	nfd = MAXNFD;	/* TO DO: should read from /fd */
+	for(i = 0; i < nfd; i++)
+		if(i != fd[0] && i != fd[1] && i != fd[2] && i != t->wfd)
+			close(i);
+
+	if(fd[0] != 0){
+		dup(fd[0], 0);
+		close(fd[0]);
+	}
+	if(fd[1] != 1){
+		dup(fd[1], 1);
+		close(fd[1]);
+	}
+	if(fd[2] != 2){
+		dup(fd[2], 2);
+		close(fd[2]);
+	}
+
+	if(t->dir != nil && chdir(t->dir) < 0){
+		if(t->wfd > 0)
+			fprint(t->wfd, "chdir: %s: %r", t->dir);
+		_exits("bad dir");
+	}
+	if(t->nice)
+		oslopri();
+
+	exec(t->args[0], t->args);
+	err[0] = 0;
+	errstr(err, sizeof(err));
+	if(t->args[0][0] != '/' && t->args[0][0] != '#' &&
+	   strncmp(t->args[0], "../", 3) != 0 && strncmp(t->args[0], "./", 2) != 0 &&
+	   strlen(t->args[0])+5 < sizeof(filename)){
+		snprint(filename, sizeof(filename), "/bin/%s", t->args[0]);
+		exec(filename, t->args);
+		errstr(err, sizeof(err));
+	}
+	snprint(status, sizeof(status), "%s: can't exec: %s", t->args[0], err);
+	if(t->wfd > 0)
+		write(t->wfd, status, strlen(status));
+	_exits(status);
+}
+
+void*
+oscmd(char **args, int nice, char *dir, int *fd)
+{
+	Targ *t;
+	int spin, *spinptr, fd0[2], fd1[2], fd2[2], wfd[2], n;
+	Dir *d;
+
+	up->genbuf[0] = 0;
+	t = mallocz(sizeof(*t), 1);
+	if(t == nil)
+		return nil;
+	t->args = args;
+	t->dir = dir;
+	t->nice = nice;
+	fd0[0] = fd0[1] = -1;
+	fd1[0] = fd1[1] = -1;
+	fd2[0] = fd2[1] = -1;
+	wfd[0] = wfd[1] = -1;
+	if(dir != nil){
+		d = dirstat(dir);
+		if(d == nil)
+			goto Error;
+		free(d);
+	}
+	if(pipe(fd0) < 0 || pipe(fd1) < 0 || pipe(fd2) < 0 || pipe(wfd) < 0)
+		goto Error;
+
+	spinptr = &spin;
+	spin = 1;
+
+	t->fd[0] = fd0[0];
+	t->fd[1] = fd1[1];
+	t->fd[2] = fd2[1];
+	t->wfd = wfd[1];
+	t->spin = spinptr;
+	switch(rfork(RFPROC|RFMEM|RFREND|RFNOTEG|RFFDG|RFNAMEG|RFENVG)) {
+	case -1:
+		goto Error;
+	case 0:
+		/* if child returns first from rfork, its call to vstack replaces ... */
+		vstack(t);
+		/* ... parent's return address from rfork and parent returns here */
+	default:
+		/* if parent returns first from rfork, it comes here */
+		/* can't call anything: on shared stack until child releases spin in exectramp */
+		while(*spinptr)
+			;
+		break;
+	}
+
+	close(fd0[0]);
+	close(fd1[1]);
+	close(fd2[1]);
+	close(wfd[1]);
+
+	n = read(wfd[0], up->genbuf, sizeof(up->genbuf)-1);
+	close(wfd[0]);
+	if(n > 0){
+		close(fd0[1]);
+		close(fd1[0]);
+		close(fd2[0]);
+		up->genbuf[n] = 0;
+		errstr(up->genbuf, sizeof(up->genbuf));
+		free(t);
+		return nil;
+	}
+
+	fd[0] = fd0[1];
+	fd[1] = fd1[0];
+	fd[2] = fd2[0];
+	return t;
+
+Error:
+	errstr(up->genbuf, sizeof(up->genbuf));	/* save the message before close */
+	close(fd0[0]);
+	close(fd0[1]);
+	close(fd1[0]);
+	close(fd1[1]);
+	close(fd2[0]);
+	close(fd2[1]);
+	close(wfd[0]);
+	close(wfd[1]);
+	free(t);
+	errstr(up->genbuf, sizeof(up->genbuf));
+	return nil;
+}
+
+int
+oscmdkill(void *a)
+{
+	Targ *t = a;
+
+	return postnote(PNGROUP, t->pid, "kill");
+}
+
+int
+oscmdwait(void*, char *buf, int n)
+{
+	return await(buf, n);
+}
+
+void
+oscmdfree(void *a)
+{
+	free(a);
+}
--- /dev/null
+++ b/emu/9front/devfs.c
@@ -1,0 +1,365 @@
+/*
+ * Plan 9 file system interface
+ */
+#include	"dat.h"
+#include	"fns.h"
+#include	"error.h"
+
+typedef struct Fsinfo Fsinfo;
+struct Fsinfo
+{
+	int	fd;
+	QLock;		/* serialise access to offset */
+	ulong	offset;	/* offset used only for directory reads */
+	Cname*	name;	/* Plan 9's name for file */
+	Qid	rootqid;		/* Plan 9's qid for Inferno's root */
+	char*	root;		/* prefix to strip from all names in diagnostics */
+};
+#define	FS(c)	((Fsinfo*)((c)->aux))
+
+char	rootdir[MAXROOT] = ROOT;
+
+static void
+fserr(Fsinfo *f)
+{
+	int n;
+	char *p;
+
+	oserrstr(up->env->errstr, ERRMAX);
+	if(f != nil && *up->env->errstr == '\'' && (n = strlen(f->root)) > 1){
+		/* don't reveal full names */
+		if(strncmp(up->env->errstr+1, f->root, n-1) == 0){
+			p = up->env->errstr+1+n;
+			memmove(up->env->errstr+1, p, strlen(p)+1);
+		}
+	}
+	error(up->env->errstr);
+}
+
+static void
+fsfree(Chan *c)
+{
+	cnameclose(FS(c)->name);
+	free(c->aux);
+}
+
+Chan*
+fsattach(char *spec)
+{
+	Chan *c;
+	Dir *d;
+	char *root;
+	Qid rootqid;
+	static int devno;
+	static Lock l;
+
+	if(!emptystr(spec)){
+		if(strcmp(spec, "*") != 0)
+			error(Ebadspec);
+		root = "/";
+	}else
+		root = rootdir;
+
+	d = dirstat(root);
+	if(d == nil)
+		fserr(nil);
+	rootqid = d->qid;
+	free(d);
+
+	c = devattach('U', spec);
+	lock(&l);
+	c->dev = devno++;
+	c->qid = rootqid;
+	unlock(&l);
+	c->aux = smalloc(sizeof(Fsinfo));
+	FS(c)->name = newcname(root);
+	FS(c)->rootqid = rootqid;
+	FS(c)->fd = -1;
+	FS(c)->root = root;
+
+	return c;
+}
+
+Walkqid*
+fswalk(Chan *c, Chan *nc, char **name, int nname)
+{
+	int j, alloc;
+	Walkqid *wq;
+	Dir *dir;
+	char *n;
+	Cname *current, *next;
+	Qid rootqid;
+
+	if(nname > 0)
+		isdir(c);	/* do we need this? */
+
+	alloc = 0;
+	current = nil;
+	wq = smalloc(sizeof(Walkqid)+(nname-1)*sizeof(Qid));
+	if(waserror()){
+		if(alloc && wq->clone!=nil)
+			cclose(wq->clone);
+		cnameclose(current);
+		free(wq);
+		return nil;
+	}
+	if(nc == nil){
+		nc = devclone(c);
+		nc->type = 0;
+		alloc = 1;
+	}
+	wq->clone = nc;
+
+	rootqid = FS(c)->rootqid;
+	current = FS(c)->name;
+	if(current != nil)
+		incref(&current->r);
+	for(j=0; j<nname; j++){
+		if(!(nc->qid.type&QTDIR)){
+			if(j==0)
+				error(Enotdir);
+			break;
+		}
+		n = name[j];
+		if(strcmp(n, ".") != 0 && !(isdotdot(n) && nc->qid.path == rootqid.path)){	/* TO DO: underlying qids aliased */
+			//print("** ufs walk '%s' -> %s\n", current->s, n);
+			next = current;
+			incref(&next->r);
+			next = addelem(current, n);
+			dir = dirstat(next->s);
+			if(dir == nil){
+				cnameclose(next);
+				if(j == 0)
+					error(Enonexist);
+				strcpy(up->env->errstr, Enonexist);
+				break;
+			}
+			nc->qid = dir->qid;
+			free(dir);
+			cnameclose(current);
+			current = next;
+		}
+		wq->qid[wq->nqid++] = nc->qid;
+	}
+//	print("** ufs walk '%s'\n", current->s);
+
+	poperror();
+	if(wq->nqid < nname){
+		cnameclose(current);
+		if(alloc)
+			cclose(wq->clone);
+		wq->clone = nil;
+	}else if(wq->clone){
+		/* now attach to our device */
+		nc->aux = smalloc(sizeof(Fsinfo));
+		nc->type = c->type;
+		FS(nc)->rootqid = FS(c)->rootqid;
+		FS(nc)->name = current;
+		FS(nc)->fd = -1;
+		FS(nc)->root = FS(c)->root;
+	}else
+		panic("fswalk: can't happen");
+	return wq;
+}
+
+int
+fsstat(Chan *c, uchar *dp, int n)
+{
+	if(FS(c)->fd >= 0)
+		n = fstat(FS(c)->fd, dp, n);
+	else
+		n = stat(FS(c)->name->s, dp, n);
+	if(n < 0)
+		fserr(FS(c));
+	/* TO DO: change name to / if rootqid */
+	return n;
+}
+
+Chan*
+fsopen(Chan *c, int mode)
+{
+	osenter();
+	FS(c)->fd = open(FS(c)->name->s, mode);
+	osleave();
+	if(FS(c)->fd < 0)
+		fserr(FS(c));
+	c->mode = openmode(mode);
+	c->offset = 0;
+	FS(c)->offset = 0;
+	c->flag |= COPEN;
+	return c;
+}
+
+void
+fscreate(Chan *c, char *name, int mode, ulong perm)
+{
+	Dir *d;
+	Cname *n;
+
+	if(strcmp(name, ".") == 0 || strcmp(name, "..") == 0)
+		error(Efilename);
+	n = addelem(newcname(FS(c)->name->s), name);
+	osenter();
+	FS(c)->fd = create(n->s, mode, perm);
+	osleave();
+	if(FS(c)->fd < 0) {
+		cnameclose(n);
+		fserr(FS(c));
+	}
+	d = dirfstat(FS(c)->fd);
+	if(d == nil) {
+		cnameclose(n);
+		close(FS(c)->fd);
+		FS(c)->fd = -1;
+		fserr(FS(c));
+	}
+	c->qid = d->qid;
+	free(d);
+
+	cnameclose(FS(c)->name);
+	FS(c)->name = n;
+
+	c->mode = openmode(mode);
+	c->offset = 0;
+	FS(c)->offset = 0;
+	c->flag |= COPEN;
+}
+
+void
+fsclose(Chan *c)
+{
+	if(c->flag & COPEN){
+		osenter();
+		close(FS(c)->fd);
+		osleave();
+	}
+	/* don't need to check for CRCLOSE, because Plan 9 itself implements ORCLOSE */
+	fsfree(c);
+}
+
+static long
+fsdirread(Chan *c, void *va, long count, vlong offset)
+{
+	long n, r;
+	static char slop[16384];
+
+	if(FS(c)->offset != offset){
+		seek(FS(c)->fd, 0, 0);
+		for(n=0; n<offset;) {
+			r = offset - n;
+			if(r > sizeof(slop))
+				r = sizeof(slop);
+			osenter();
+			r = read(FS(c)->fd, slop, r);
+			osleave();
+			if(r <= 0){
+				FS(c)->offset = n;
+				return 0;
+			}
+			n += r;
+		}
+		FS(c)->offset = offset;
+	}
+	osenter();
+	r = read(FS(c)->fd, va, count);
+	osleave();
+	if(r < 0)
+		return r;
+	FS(c)->offset = offset+r;
+	return r;
+}
+
+long
+fsread(Chan *c, void *va, long n, vlong offset)
+{
+	int r;
+
+	if(c->qid.type & QTDIR){	/* need to maintain offset only for directories */
+		qlock(FS(c));
+		if(waserror()){
+			qunlock(FS(c));
+			nexterror();
+		}
+		r = fsdirread(c, va, n, offset);
+		poperror();
+		qunlock(FS(c));
+	}else{
+		osenter();
+		r = pread(FS(c)->fd, va, n, offset);
+		osleave();
+	}
+	if(r < 0)
+		fserr(FS(c));
+	return r;
+}
+
+long
+fswrite(Chan *c, void *va, long n, vlong offset)
+{
+	int r;
+
+	osenter();
+	r = pwrite(FS(c)->fd, va, n, offset);
+	osleave();
+	if(r < 0)
+		fserr(FS(c));
+	return r;
+}
+
+void
+fsremove(Chan *c)
+{
+	int r;
+
+	if(waserror()){
+		fsfree(c);
+		nexterror();
+	}
+	osenter();
+	r = remove(FS(c)->name->s);
+	osleave();
+	if(r < 0)
+		fserr(FS(c));
+	poperror();
+	fsfree(c);
+}
+
+int
+fswstat(Chan *c, uchar *dp, int n)
+{
+	osenter();
+	if(FS(c)->fd >= 0)
+		n = fwstat(FS(c)->fd, dp, n);
+	else
+		n = wstat(FS(c)->name->s, dp, n);
+	osleave();
+	if(n < 0)
+		fserr(FS(c));
+	return n;
+}
+
+void
+setid(char *name, int owner)
+{
+	if(!owner || iseve())
+		kstrdup(&up->env->user, name);
+}
+
+Dev fsdevtab = {
+	'U',
+	"fs",
+
+	devinit,
+	fsattach,
+	fswalk,
+	fsstat,
+	fsopen,
+	fscreate,
+	fsclose,
+	fsread,
+	devbread,
+	fswrite,
+	devbwrite,
+	fsremove,
+	fswstat
+};
--- /dev/null
+++ b/emu/9front/devsrv9.c
@@ -1,0 +1,395 @@
+#include	"dat.h"
+#include	"fns.h"
+#include	"error.h"
+
+typedef struct Srv Srv;
+struct Srv
+{
+	Ref;
+	int	fd;	/* fd for opened /srv or /srv/X, or -1 */
+	int	sfd;	/* fd for created /srv entry or -1 */
+	uvlong	path;
+	Srv	*next;
+};
+
+static QLock	srv9lk;
+static Srv	*srv9;
+static Srv	*srvroot;
+
+static char*
+srvname(Chan *c)
+{
+	char *p;
+
+	p = strrchr(c->name->s, '/');
+	if(p == nil)
+		return "";
+	return p+1;
+}
+
+static Srv*
+srvget(uvlong path)
+{
+	Srv *sv;
+
+	qlock(&srv9lk);
+	for(sv = srv9; sv != nil; sv = sv->next)
+		if(sv->path == path){
+			incref(sv);
+			qunlock(&srv9lk);
+			return sv;
+		}
+	sv = smalloc(sizeof(*sv));
+	sv->path = path;
+	sv->fd = -1;
+	sv->sfd = -1;
+	sv->ref = 1;
+	sv->next = srv9;
+	srv9 = sv;
+	qunlock(&srv9lk);
+	return sv;
+}
+
+static void
+srvput(Srv *sv)
+{
+	Srv **l;
+	int fd, sfd;
+
+	if(sv != nil && decref(sv) == 0){
+		qlock(&srv9lk);
+		for(l = &srv9; *l != nil; l = &(*l)->next)
+			if(*l == sv){
+				*l = sv->next;
+				break;
+			}
+		qunlock(&srv9lk);
+		fd = sv->fd;
+		sfd = sv->sfd;
+		free(sv);
+		if(sfd >= 0){
+			osenter();
+			close(sfd);
+			osleave();
+		}
+		if(fd >= 0){
+			osenter();
+			close(fd);
+			osleave();
+		}
+	}
+}
+
+static void
+srv9init(void)
+{
+	Srv *sv;
+
+	sv = mallocz(sizeof(*srvroot), 1);
+	sv->path = 0;
+	sv->fd = -1;
+	sv->ref = 1;	/* subsequently never reaches zero */
+	srvroot = srv9 = sv;
+}
+
+static Chan*
+srv9attach(char *spec)
+{
+	Chan *c;
+
+	if(*spec)
+		error(Ebadspec);
+	c = devattach(L'₪', spec);
+	if(c != nil){
+		incref(srvroot);
+		c->aux = srvroot;
+	}
+	return c;
+}
+
+static Walkqid*
+srv9walk(Chan *c, Chan *nc, char **name, int nname)
+{
+	int j, alloc;
+	Walkqid *wq;
+	char *n;
+	Dir *d;
+
+	if(nname > 0)
+		isdir(c);
+
+	alloc = 0;
+	wq = smalloc(sizeof(Walkqid)+(nname-1)*sizeof(Qid));
+	if(waserror()){
+		if(alloc)
+			cclose(wq->clone);
+		free(wq);
+		return nil;
+	}
+	if(nc == nil){
+		nc = devclone(c);
+		nc->type = 0;	/* device doesn't know about this channel yet */
+		alloc = 1;
+	}
+	wq->clone = nc;
+
+	for(j=0; j<nname; j++){
+		if(!(nc->qid.type&QTDIR)){
+			if(j==0)
+				error(Enotdir);
+			break;
+		}
+		n = name[j];
+		if(strcmp(n, ".") != 0 && strcmp(n, "..") != 0){
+			snprint(up->genbuf, sizeof(up->genbuf), "/srv/%s", n);
+			d = dirstat(up->genbuf);
+			if(d == nil){
+				if(j == 0)
+					error(Enonexist);
+				kstrcpy(up->env->errstr, Enonexist, ERRMAX);
+				break;
+			}
+			nc->qid = d->qid;
+			free(d);
+		}
+		wq->qid[wq->nqid++] = nc->qid;
+	}
+	poperror();
+	if(wq->nqid < nname){
+		if(alloc)
+			cclose(wq->clone);
+		wq->clone = nil;
+	}else{
+		/* attach cloned channel to device */
+		wq->clone->type = c->type;
+		if(wq->clone != c)
+			nc->aux = srvget(nc->qid.path);
+	}
+	return wq;
+}
+
+static int
+srv9stat(Chan *c, uchar *db, int n)
+{
+	Srv *sv;
+	Dir d;
+
+	if(c->qid.type & QTDIR){
+		devdir(c, c->qid, "#₪", 0, eve, 0775, &d);
+		n = convD2M(&d, db, n);
+		if(n == 0)
+			error(Eshortstat);
+		return n;
+	}
+	sv = c->aux;
+	if(sv->fd >= 0){
+		osenter();
+		n = fstat(sv->fd, db, n);
+		osleave();
+	}else{
+		osenter();
+		n = stat(srvname(c), db, n);
+		osleave();
+	}
+	return n;
+}
+
+static Chan*
+srv9open(Chan *c, int omode)
+{
+	Srv *sv;
+	char *args[10];
+	int fd[2], i, ifd, is9p;
+	Dir *d;
+
+	sv = c->aux;
+	if(c->qid.type == QTDIR){
+		osenter();
+		sv->fd = open("/srv", omode);
+		osleave();
+		if(sv->fd < 0)
+			oserror();
+		c->mode = omode;
+		c->flag |= COPEN;
+		c->offset = 0;
+		return c;
+	}
+
+	if(omode&OTRUNC || openmode(omode) != ORDWR)
+		error(Eperm);
+	if(sv->fd < 0){
+		snprint(up->genbuf, sizeof(up->genbuf), "/srv/%s", srvname(c));
+
+		/* check permission */
+		osenter();
+		ifd = open(up->genbuf, omode);
+		osleave();
+		if(ifd < 0)
+			oserror();
+		osenter();
+		d = dirfstat(ifd);
+		is9p = d != nil && d->qid.type & QTMOUNT;
+		free(d);
+		osleave();
+
+		if(is9p){
+			close(ifd);
+
+			/* spawn exportfs */
+			args[0] = "exportfs";
+			args[1] = "-S";
+			args[2] = up->genbuf;
+			args[3] = nil;
+			if(pipe(fd) < 0)
+				oserror();
+			/* TO DO: without RFMEM there's a copy made of each page touched by any kproc until the exec */
+			switch(rfork(RFPROC|RFNOWAIT|RFREND|RFFDG|RFNAMEG|RFENVG)){	/* no sharing except NOTEG */
+			case -1:
+				oserrstr(up->genbuf, sizeof(up->genbuf));
+				close(fd[0]);
+				close(fd[1]);
+				error(up->genbuf);
+			case 0:
+				for(i=3; i<MAXNFD; i++)
+					if(i != fd[1])
+						close(i);
+				dup(fd[1], 0);
+				if(fd[0] != 0)
+					close(fd[0]);
+				dup(0, 1);
+				exec("/bin/exportfs", args);
+				exits("exportfs failed");
+			default:
+				sv->fd = fd[0];
+				close(fd[1]);
+				break;
+			}
+		}else
+			sv->fd = ifd;
+	}
+
+	c->mode = ORDWR;
+	c->offset = 0;
+	c->flag |= COPEN;
+	return c;
+}
+
+static void
+srv9close(Chan *c)
+{
+	srvput(c->aux);
+}
+
+static long
+srv9read(Chan *c, void *va, long n, vlong off)
+{
+	Srv *sv;
+
+	sv = c->aux;
+	osenter();
+	n = pread(sv->fd, va, n, off);
+	osleave();
+	if(n < 0)
+		oserror();
+	return n;
+}
+
+static long
+srv9write(Chan *c, void *va, long n, vlong off)
+{
+	Srv *sv;
+
+	sv = c->aux;
+	osenter();
+	n = pwrite(sv->fd, va, n, off);
+	osleave();
+	if(n == 0)
+		error(Ehungup);
+	if(n < 0)
+		oserror();
+	return n;
+}
+
+static void
+srv9create(Chan *c, char *name, int omode, ulong perm)
+{
+	Srv *sv;
+	int sfd, fd[2];
+	vlong path;
+	Dir *d;
+
+	if(openmode(omode) != ORDWR)
+		error(Eperm);
+
+	if(pipe(fd) < 0)
+		oserror();
+	if(waserror()){
+		close(fd[0]);
+		close(fd[1]);
+		nexterror();
+	}
+
+	snprint(up->genbuf, sizeof(up->genbuf), "/srv/%s", name);
+	osenter();
+	sfd = create(up->genbuf, OWRITE|ORCLOSE, perm);
+	osleave();
+	if(sfd < 0)
+		oserror();
+	if(waserror()){
+		close(sfd);
+		nexterror();
+	}
+	osenter();
+	if(fprint(sfd, "%d", fd[1]) < 0){
+		osleave();
+		oserror();
+	}
+	d = dirfstat(sfd);
+	osleave();
+	if(d != nil){
+		path = d->qid.path;
+		free(d);
+	}else
+		oserror();
+
+	poperror();
+	poperror();
+	close(fd[1]);
+
+	if(waserror()){
+		close(sfd);
+		close(fd[0]);
+		nexterror();
+	}
+	sv = srvget(path);
+	sv->fd = fd[0];
+	sv->sfd = sfd;
+	poperror();
+
+	srvput((Srv*)c->aux);
+	c->qid.type = QTFILE;
+	c->qid.path = path;
+	c->aux = sv;
+	c->flag |= COPEN;
+	c->mode = ORDWR;
+	c->offset = 0;
+}
+
+Dev srv9devtab = {
+	L'₪',
+	"srv9",
+
+	srv9init,	
+	srv9attach,
+	srv9walk,
+	srv9stat,
+	srv9open,
+	srv9create,	/* TO DO */
+	srv9close,
+	srv9read,
+	devbread,
+	srv9write,
+	devbwrite,
+	devremove,	/* TO DO */
+	devwstat,	/* TO DO */
+};
--- /dev/null
+++ b/emu/9front/emu
@@ -1,0 +1,114 @@
+dev
+	root
+	cons
+	env
+	mnt
+	pipe
+	prog
+	prof
+	srv
+	dup
+	ssl
+	cap
+	fs
+	cmd	cmd
+	indir
+#	sign
+
+	draw	win
+	pointer
+
+	dynld
+	mem
+	srv9
+
+#	ip and eia are simply bound in from Plan 9
+
+lib
+	interp
+	tk
+	freetype
+	math
+	draw
+
+	memlayer
+	memdraw
+	keyring
+	sec
+	mp
+	dynld
+	9
+
+link
+
+mod
+	sys
+	draw
+
+	tk
+	math
+#	srv		not used on Plan 9
+	keyring
+	crypt
+	ipints
+	loader
+	freetype
+
+port
+	alloc
+	cache
+	chan
+	dev
+	devtab
+
+	dial
+	dis
+	discall
+	env
+	error
+	errstr
+	exception
+	exportfs
+	exptab
+	inferno
+	latin1
+	main
+	parse
+	pgrp
+	print
+	proc
+	qio
+	random
+	sysfile
+	uqid
+
+code
+
+init
+	emuinit
+
+root
+	/chan	/
+	/dev	/
+	/fd	/
+	/prog	/
+	/prof	/
+	/net	/
+	/net.alt	/
+	/nvfs	/
+	/env	/
+	/root	/
+	/srv	/
+#	/tmp	/
+#	/dis
+#	/env
+#	/n
+#	/net
+#	/nvfs /
+#	/prog
+#	/icons
+#	/osinit.dis
+#	/dis/emuinit.dis
+#	/dis/lib/auth.dis
+#	/dis/lib/ssl.dis
+#	/n/local /
--- /dev/null
+++ b/emu/9front/mkfile
@@ -1,0 +1,45 @@
+SYSTARG=9front
+OBJTYPE=$objtype
+<../../mkconfig
+
+#Configurable parameters
+
+CONF=emu			#default configuration
+CONFLIST=emu
+CLEANCONFLIST=
+
+INSTALLDIR=$ROOT/$SYSTARG/$OBJTYPE/bin	#path of directory where kernel is installed
+
+#end configurable parameters
+
+<$ROOT/mkfiles/mkfile-$SYSTARG-$OBJTYPE	#set vars based on target system
+
+<| $SHELLNAME ../port/mkdevlist $CONF	#sets $IP, $DEVS, $PORT, $LIBS
+
+OBJ=\
+	asm-$OBJTYPE.$O\
+	os.$O\
+	$CONF.root.$O\
+	$DEVS\
+	$PORT\
+
+
+HFILES=\
+
+CFLAGS='-DROOT="'$ROOT'"' -DEMU -I. -I../port -I$ROOT/$SYSTARG/$OBJTYPE/include -I$ROOT/include -I$ROOT/libinterp $CTHREADFLAGS $CFLAGS $EMUOPTIONS
+KERNDATE=`{$NDATE}
+
+default:V:	$O.$CONF
+
+<../port/portmkfile
+
+$O.$CONF:	$OBJ $CONF.c $CONF.root.h $LIBFILES
+	$CC $CFLAGS '-DKERNDATE='$KERNDATE $CONF.c
+	$LD  -o $target $OBJ $CONF.$O $LIBFILES $SYSLIBS
+
+safeinstall:V:	$O.$CONF
+	mv $INSTALLDIR/$CONF $INSTALLDIR/$CONF.`{date -n}
+	cp $O.$CONF $INSTALLDIR/$CONF
+
+install:V: $O.$CONF
+	cp $O.$CONF $INSTALLDIR/$CONF
--- /dev/null
+++ b/emu/9front/os.c
@@ -1,0 +1,428 @@
+#include	"dat.h"
+#include	"fns.h"
+#include	"error.h"
+
+enum
+{
+	KSTACK	= 16*1024,
+	DELETE	= 0x7F,
+};
+
+Proc	**Xup;
+
+extern	void	killrefresh(void);
+extern	void	tramp(char*, void (*)(void*), void*);
+
+extern	int	usenewwin;
+
+int	*ustack;	/* address on unshared stack: see vstack in asm*.s */
+extern	int	dflag;
+char *hosttype = "Plan9";
+char *cputype;
+
+void
+osblock(void)
+{
+	rendezvous(up, nil);
+}
+
+void
+osready(Proc *p)
+{
+	rendezvous(p, nil);
+}
+
+void
+pexit(char *msg, int)
+{
+	Osenv *e;
+
+	USED(msg);
+
+	lock(&procs.l);
+	if(up->prev) 
+		up->prev->next = up->next;
+	else
+		procs.head = up->next;
+
+	if(up->next)
+		up->next->prev = up->prev;
+	else
+		procs.tail = up->prev;
+	unlock(&procs.l);
+
+/*	print("pexit: %s: %s\n", up->text, msg);	/**/
+	e = up->env;
+	if(e != nil) {
+		closefgrp(e->fgrp);
+		closepgrp(e->pgrp);
+		closeegrp(e->egrp);
+		closesigs(e->sigs);
+	}
+	free(e->user);
+	free(up->prog);
+	up->prog = nil;
+	up->type = Moribund;
+	longjmp(up->privstack, 1);
+}
+
+int
+kproc1(char *name, void (*func)(void*), void *arg, int flags)
+{
+	int pid;
+	Proc *p;
+	Pgrp *pg;
+	Fgrp *fg;
+	Egrp *eg;
+
+	p = newproc();
+	if(p == nil)
+		panic("kproc: no memory");
+	p->kstack = mallocz(KSTACK, 0);
+	if(p->kstack == nil)
+		panic("kproc: no memory");
+
+	if(flags & KPDUPPG) {
+		pg = up->env->pgrp;
+		incref(&pg->r);
+		p->env->pgrp = pg;
+	}
+	if(flags & KPDUPFDG) {
+		fg = up->env->fgrp;
+		incref(&fg->r);
+		p->env->fgrp = fg;
+	}
+	if(flags & KPDUPENVG) {
+		eg = up->env->egrp;
+		incref(&eg->r);
+		p->env->egrp = eg;
+	}
+
+	p->env->uid = up->env->uid;
+	p->env->gid = up->env->gid;
+	kstrdup(&p->env->user, up->env->user);
+
+	strcpy(p->text, name);
+
+	p->func = func;
+	p->arg = arg;
+
+	lock(&procs.l);
+	if(procs.tail != nil) {
+		p->prev = procs.tail;
+		procs.tail->next = p;
+	}
+	else {
+		procs.head = p;
+		p->prev = nil;
+	}
+	procs.tail = p;
+	unlock(&procs.l);
+
+	/*
+	 * switch back to the unshared stack to do the fork
+	 * only the parent returns from kproc
+	 */
+	up->kid = p;
+	up->kidsp = p->kstack;
+	pid = setjmp(up->sharestack);
+	if(pid == 0)
+		longjmp(up->privstack, 1);
+	return pid;
+}
+
+void
+kproc(char *name, void (*func)(void*), void *arg, int flags)
+{
+	kproc1(name, func, arg, flags);
+}
+
+void
+traphandler(void *reg, char *msg)
+{
+	int intwait;
+
+	intwait = up->intwait;
+	up->intwait = 0;
+	/* Ignore pipe writes from devcmd */
+	if(strstr(msg, "write on closed pipe") != nil)
+		noted(NCONT);
+
+	if(sflag) {
+		if(intwait && strcmp(msg, Eintr) == 0)
+			noted(NCONT);
+		else
+			noted(NDFLT);
+	}
+	if(intwait == 0)
+		disfault(reg, msg);
+	noted(NCONT);
+}
+
+int
+readfile(char *path, char *buf, int n)
+{
+	int fd;
+
+	fd = open(path, OREAD);
+	if(fd >= 0) {
+		n = read(fd, buf, n-1);
+		if(n > 0)			/* both calls to readfile() have a ``default'' */
+			buf[n] = '\0';
+		close(fd);
+		return n;
+	}
+	return 0;
+}
+
+static void
+dobinds(void)
+{
+	char dir[MAXROOT+9];
+
+	snprint(dir, sizeof(dir), "%s/net", rootdir);
+	bind("/net", dir, MREPL);
+
+	snprint(dir, sizeof(dir), "%s/net.alt", rootdir);
+	bind("/net.alt", dir, MREPL);
+
+	snprint(dir, sizeof(dir), "%s/dev", rootdir);
+	bind("#t", dir, MAFTER);
+	bind("#A", dir, MAFTER);
+}
+
+void
+libinit(char *imod)
+{
+	char *sp;
+	Proc *xup, *p;
+	int fd, n, pid;
+	char nbuf[64];
+
+	xup = nil;
+	Xup = &xup;
+
+	/*
+	 * setup personality
+	 */
+	if(readfile("/dev/user", nbuf, sizeof nbuf))
+		kstrdup(&eve, nbuf);
+	if(readfile("/dev/sysname", nbuf, sizeof nbuf))
+		kstrdup(&ossysname, nbuf);
+	if(readfile("/env/cputype", nbuf, sizeof nbuf))
+		kstrdup(&cputype, nbuf);
+
+	/*
+	 * guess at a safe stack for vstack
+	 */
+	ustack = &fd;
+
+	rfork(RFNAMEG|RFREND);
+
+	if(!dflag){
+		fd = open("/dev/consctl", OWRITE);
+		if(fd < 0)
+			fprint(2, "libinit: open /dev/consctl: %r\n");
+		n = write(fd, "rawon", 5);
+		if(n != 5)
+			fprint(2, "keyboard rawon (n=%d, %r)\n", n);
+	}
+
+	osmillisec();	/* set the epoch */
+	dobinds();
+
+	notify(traphandler);
+
+	/*
+	 * dummy up a up and stack so the first proc
+	 * calls emuinit after setting up his private jmp_buf
+	 */
+	p = newproc();
+	p->kstack = mallocz(KSTACK, 0);
+	if(p == nil || p->kstack == nil)
+		panic("libinit: no memory");
+	sp = p->kstack;
+	p->func = emuinit;
+	p->arg = imod;
+
+	/*
+	 * set up a stack for forking kids on separate stacks.
+	 * longjmp back here from kproc.
+	 */
+	while(setjmp(p->privstack)){
+		if(up->type == Moribund){
+			free(up->kstack);
+			free(up);
+			_exits("");
+		}
+		p = up->kid;
+		sp = up->kidsp;
+		up->kid = nil;
+		switch(pid = rfork(RFPROC|RFMEM|RFNOWAIT)){
+		case 0:
+			/*
+			 * send the kid around the loop to set up his private jmp_buf
+			 */
+			break;
+		default:
+			/*
+			 * parent just returns to his shared stack in kproc
+			 */
+			longjmp(up->sharestack, pid);
+			panic("longjmp failed");
+		}
+	}
+
+	/*
+	 * you get here only once per Proc
+	 * go to the shared memory stack
+	 */
+	up = p;
+	up->pid = up->sigid = getpid();
+	tramp(sp+KSTACK, up->func, up->arg);
+	panic("tramp returned");
+}
+
+void
+oshostintr(Proc *p)
+{
+	postnote(PNPROC, p->sigid, Eintr);
+}
+
+void
+oslongjmp(void *regs, osjmpbuf env, int val)
+{
+	if(regs != nil)
+		notejmp(regs, env, val);
+	else
+		longjmp(env, val);
+}
+
+void
+osreboot(char*, char**)
+{
+}
+
+void
+cleanexit(int x)
+{
+	USED(x);
+	killrefresh();
+	postnote(PNGROUP, getpid(), "interrupt");
+	exits("interrupt");
+}
+
+int
+readkbd(void)
+{
+	int n;
+	char buf[1];
+
+	n = read(0, buf, sizeof(buf));
+	if(n < 0)
+		fprint(2, "emu: keyboard read error: %r\n");
+	if(n <= 0)
+		pexit("keyboard", 0);
+	switch(buf[0]) {
+	case DELETE:
+		cleanexit(0);
+	case '\r':
+		buf[0] = '\n';
+	}
+	return buf[0];
+}
+
+static vlong
+b2v(uchar *p)
+{
+	int i;
+	vlong v;
+
+	v = 0;
+	for(i=0; i<sizeof(uvlong); i++)
+		v = (v<<8)|p[i];
+	return v;
+}
+
+vlong
+nsec(void)
+{
+	int n;
+	static int nsecfd = -1;
+	uchar buf[sizeof(uvlong)];
+
+	if(nsecfd < 0){
+		nsecfd = open("/dev/bintime", OREAD|OCEXEC);  /* never closed */
+		if(nsecfd<0){
+			fprint(2,"can't open /dev/bintime: %r\n");
+			return 0;
+		}
+	}
+	n = read(nsecfd, buf, sizeof(buf));
+	if(n!=sizeof(buf)) {
+		fprint(2,"read err on /dev/bintime: %r\n");
+		return 0;
+	}
+	return b2v(buf);
+}
+
+long
+osmillisec(void)
+{
+	static vlong nsec0 = 0;
+
+	if(nsec0 == 0){
+		nsec0 = nsec();
+		return 0;
+	}
+	return (nsec()-nsec0)/1000000;
+}
+
+/*
+ * Return the time since the epoch in microseconds
+ * The epoch is defined at 1 Jan 1970
+ */
+vlong
+osusectime(void)
+{
+	return nsec()/1000;
+}
+
+int
+osmillisleep(ulong milsec)
+{
+	sleep(milsec);
+	return 0;
+}
+
+int
+limbosleep(ulong milsec)
+{
+	return osmillisleep(milsec);
+}
+
+void
+osyield(void)
+{
+	sleep(0);
+}
+
+void
+ospause(void)
+{
+	for(;;)
+		sleep(1000000);
+}
+
+void
+oslopri(void)
+{
+	int fd;
+	char buf[32];
+
+	snprint(buf, sizeof(buf), "/proc/%d/ctl", getpid());
+	if((fd = open(buf, OWRITE)) >= 0){
+		fprint(fd, "pri 8");
+		close(fd);
+	}
+}
--- /dev/null
+++ b/emu/9front/win.c
@@ -1,0 +1,566 @@
+#include	"dat.h"
+#include	"fns.h"
+#include	"kernel.h"
+#include	"error.h"
+
+#include	<draw.h>
+#include	<memdraw.h>
+#include	<cursor.h>
+#include	"keyboard.h"
+
+enum
+{
+	Margin	= 4,
+	Lsize		= 100,
+};
+
+extern Memimage *screenimage;
+
+extern int kproc1(char*, void (*)(void*), void*, int);
+
+static	ulong*	attachwindow(Rectangle*, ulong*, int*, int*);
+
+static void	plan9readmouse(void*);
+static void	plan9readkeybd(void*);
+static int	mapspecials(char *s1, char *s2, int *n);
+
+int	usenewwin = 1;
+int	kbdiscons;
+static int	truedepth;
+
+static int		datafd;
+static int		ctlfd;
+static int		mousefd = -1;
+static int		keybdfd;
+static int		mousepid = -1;
+static int		keybdpid = -1;
+static int		cursfd;
+static char	winname[64];
+
+/* Following updated by attachwindow() asynchronously */
+static QLock		ql;
+static Rectangle	tiler;
+static ulong*		data;
+static uchar*		loadbuf;
+static int		cursfd;
+static int		imageid;
+static Rectangle	imager;
+static uchar	*chunk;
+static int	chunksize;
+static	int	dispbufsize;
+
+#define	NINFO	12*12
+#define	HDR		21
+
+
+void
+killrefresh(void)
+{
+	if(mousepid < 0)
+		return;
+	close(mousefd);
+	close(ctlfd);
+	close(datafd);
+	postnote(PNPROC, mousepid, Eintr);
+	postnote(PNPROC, keybdpid, Eintr);
+}
+
+uchar*
+attachscreen(Rectangle *r, ulong *chan, int *d, int *width, int *softscreen)
+{
+	int fd;
+	char *p, buf[128], info[NINFO+1];
+
+	if(usenewwin){
+		p = getenv("wsys");
+		if(p == nil)
+			return nil;
+
+		fd = open(p, ORDWR);
+		if(fd < 0) {
+			fprint(2, "attachscreen: can't open window manager: %r\n");
+			return nil;
+		}
+		sprint(buf, "new -dx %d -dy %d", Xsize+2*Margin, Ysize+2*Margin);
+		if(mount(fd, -1, "/mnt/wsys", MREPL, buf) < 0) {
+			fprint(2, "attachscreen: can't mount window manager: %r\n");
+			return nil;
+		}
+		if(bind("/mnt/wsys", "/dev", MBEFORE) < 0){
+			fprint(2, "attachscreen: can't bind /mnt/wsys before /dev: %r\n");
+			return nil;
+		}
+	}
+
+	cursfd = open("/dev/cursor", OWRITE);
+	if(cursfd < 0) {
+		fprint(2, "attachscreen: open cursor: %r\n");
+		return nil;
+	}
+	
+	/* Set up graphics window console (chars->gkbdq) */
+	keybdfd = open("/dev/cons", OREAD);
+	if(keybdfd < 0) {
+		fprint(2, "attachscreen: open keyboard: %r\n");
+		return nil;
+	}
+	mousefd = open("/dev/mouse", ORDWR);
+	if(mousefd < 0){
+		fprint(2, "attachscreen: can't open mouse: %r\n");
+		return nil;
+	}
+	if(usenewwin || 1){
+		fd = open("/dev/consctl", OWRITE);
+		if(fd < 0)
+			fprint(2, "attachscreen: open /dev/consctl: %r\n");
+		if(write(fd, "rawon", 5) != 5)
+			fprint(2, "attachscreen: write /dev/consctl: %r\n");
+	}
+
+	/* Set up graphics files */
+	ctlfd = open("/dev/draw/new", ORDWR);
+	if(ctlfd < 0){
+		fprint(2, "attachscreen: can't open graphics control file: %r\n");
+		return nil;
+	}
+	if(read(ctlfd, info, sizeof info) < NINFO){
+		close(ctlfd);
+		fprint(2, "attachscreen: can't read graphics control file: %r\n");
+		return nil;
+	}
+	sprint(buf, "/dev/draw/%d/data", atoi(info+0*12));
+	datafd = open(buf, ORDWR|OCEXEC);
+	if(datafd < 0){
+		close(ctlfd);
+		fprint(2, "attachscreen: can't read graphics data file: %r\n");
+		return nil;
+	}
+	dispbufsize = iounit(datafd);
+	if(dispbufsize <= 0)
+		dispbufsize = 8000;
+	if(dispbufsize < 512){
+		close(ctlfd);
+		close(datafd);
+		fprint(2, "attachscreen: iounit %d too small\n", dispbufsize);
+		return nil;
+	}
+	chunksize = dispbufsize - 64;
+
+	if(attachwindow(r, chan, d, width) == nil){
+		close(ctlfd);
+		close(datafd);
+		return nil;
+	}
+	
+	mousepid = kproc1("readmouse", plan9readmouse, nil, 0);
+	keybdpid = kproc1("readkbd", plan9readkeybd, nil, 0);
+
+	fd = open("/dev/label", OWRITE);
+	if(fd >= 0){
+		snprint(buf, sizeof(buf), "inferno %d", getpid());
+		write(fd, buf, strlen(buf));
+		close(fd);
+	}
+
+	*softscreen = 1;
+	return (uchar*)data;
+}
+
+static ulong*
+attachwindow(Rectangle *r, ulong *chan, int *d, int *width)
+{
+	int n, fd, nb;
+	char buf[256];
+	uchar ubuf[128];
+	ulong imagechan;
+
+	/*
+	 * Discover name of window
+	 */
+	fd = open("/mnt/wsys/winname", OREAD);
+	if(fd<0 || (n=read(fd, winname, sizeof winname))<=0){
+		fprint(2, "attachwindow: can only run inferno under rio, not stand-alone\n");
+		return nil;
+	}
+	close(fd);
+	/*
+	 * If had previous window, release it
+	 */
+	if(imageid > 0){
+		ubuf[0] = 'f';
+		BPLONG(ubuf+1, imageid);
+		if(write(datafd, ubuf, 1+4) != 1+4)
+			fprint(2, "attachwindow: cannot free old window: %r\n");
+	}
+	/*
+	 * Allocate image pointing to window, and discover its ID
+	 */
+	ubuf[0] = 'n';
+	++imageid;
+	BPLONG(ubuf+1, imageid);
+	ubuf[5] = n;
+	memmove(ubuf+6, winname, n);
+	if(write(datafd, ubuf, 6+n) != 6+n){
+		fprint(2, "attachwindow: cannot bind %d to window id '%s': %r\n", imageid, winname);
+		return nil;
+	}
+	if(read(ctlfd, buf, sizeof buf) < 12*12){
+		fprint(2, "attachwindow: cannot read window id: %r\n");
+		return nil;
+	}
+	imagechan = strtochan(buf+2*12);
+	truedepth = chantodepth(imagechan);
+	if(truedepth == 0){
+		fprint(2, "attachwindow: cannot handle window depth specifier %.12s\n", buf+2*12);
+		return nil;
+	}
+
+	/*
+	 * Report back
+	 */
+	if(chan != nil)
+		*chan = imagechan;
+	if(d != nil)
+		*d = chantodepth(imagechan);
+	nb = 0;
+	if(r != nil){
+		Xsize = atoi(buf+6*12)-atoi(buf+4*12)-2*Margin;
+		Ysize = atoi(buf+7*12)-atoi(buf+5*12)-2*Margin;
+		r->min.x = 0;
+		r->min.y = 0;
+		r->max.x = Xsize;
+		r->max.y = Ysize;
+		nb = bytesperline(*r, truedepth);
+		data = malloc(nb*Ysize);
+		loadbuf = malloc(nb*Lsize+1);
+		chunk = malloc(HDR+chunksize+5);	/* +5 for flush (1 old, 5 new) */
+	}
+	imager.min.x = atoi(buf+4*12);
+	imager.min.y = atoi(buf+5*12);
+	imager.max.x = atoi(buf+6*12);
+	imager.max.y = atoi(buf+7*12);
+
+	if(width != nil)
+		*width = nb/4;
+
+	tiler.min.x = atoi(buf+4*12)+Margin;
+	tiler.min.y = atoi(buf+5*12)+Margin;
+	tiler.max.x = atoi(buf+6*12)-Margin;
+	tiler.max.y = atoi(buf+7*12)-Margin;
+
+	return data;
+}
+
+static int
+plan9loadimage(Rectangle r, uchar *data, int ndata)
+{
+	long dy;
+	int n, bpl;
+
+	if(!rectinrect(r, imager)){
+		werrstr("loadimage: bad rectangle");
+		return -1;
+	}
+	bpl = bytesperline(r, truedepth);
+	n = bpl*Dy(r);
+	if(n > ndata){
+		werrstr("loadimage: insufficient data");
+		return -1;
+	}
+	ndata = 0;
+	while(r.max.y > r.min.y){
+		dy = r.max.y - r.min.y;
+		if(dy*bpl> chunksize)
+			dy = chunksize/bpl;
+		n = dy*bpl;
+		chunk[0] = 'y';
+		BPLONG(chunk+1, imageid);
+		BPLONG(chunk+5, r.min.x);
+		BPLONG(chunk+9, r.min.y);
+		BPLONG(chunk+13, r.max.x);
+		BPLONG(chunk+17, r.min.y+dy);
+		memmove(chunk+21, data, n);
+		ndata += n;
+		data += n;
+		r.min.y += dy;
+		n += 21;
+		if(r.min.y >= r.max.y)	/* flush to screen */
+			chunk[n++] = 'v';
+		if(write(datafd, chunk, n) != n)
+			return -1;
+	}
+	return ndata;
+}
+
+static void
+_flushmemscreen(Rectangle r)
+{
+	int n, dy, l;
+	Rectangle rr;
+
+	if(data == nil || loadbuf == nil || chunk==nil)
+		return;
+	if(!rectclip(&r, Rect(0, 0, Xsize, Ysize)))
+		return;
+	if(!rectclip(&r, Rect(0, 0, Dx(tiler), Dy(tiler))))
+		return;
+	if(Dx(r)<=0 || Dy(r)<=0)
+		return;
+	l = bytesperline(r, truedepth);
+	while(r.min.y < r.max.y){
+		dy = Dy(r);
+		if(dy > Lsize)
+			dy = Lsize;
+		rr = r;
+		rr.max.y = rr.min.y+dy;
+		n = unloadmemimage(screenimage, rr, loadbuf, l*dy);
+		/* offset from (0,0) to window */
+		rr.min.x += tiler.min.x;
+		rr.min.y += tiler.min.y;
+		rr.max.x += tiler.min.x;
+		rr.max.y += tiler.min.y;
+		if(plan9loadimage(rr, loadbuf, n) != n)
+			fprint(2, "flushmemscreen: %d bytes: %r\n", n);
+		r.min.y += dy;
+	}
+}
+
+void
+flushmemscreen(Rectangle r)
+{
+	qlock(&ql);
+	_flushmemscreen(r);
+	qunlock(&ql);
+}
+
+void
+drawcursor(Drawcursor *c)
+{
+	int j, i, h, w, bpl;
+	uchar *bc, *bs, *cclr, *cset, curs[2*4+2*2*16];
+
+	/* Set the default system cursor */
+	if(c->data == nil) {
+		write(cursfd, curs, 0);
+		return;
+	}
+
+	BPLONG(curs+0*4, c->hotx);
+	BPLONG(curs+1*4, c->hoty);
+
+	w = (c->maxx-c->minx);
+	h = (c->maxy-c->miny)/2;
+
+	cclr = curs+2*4;
+	cset = curs+2*4+2*16;
+	bpl = bytesperline(Rect(c->minx, c->miny, c->maxx, c->maxy), 1);
+	bc = c->data;
+	bs = c->data + h*bpl;
+
+	if(h > 16)
+		h = 16;
+	if(w > 16)
+		w = 16;
+	w /= 8;
+	for(i = 0; i < h; i++) {
+		for(j = 0; j < w; j++) {
+			cclr[j] = bc[j];
+			cset[j] = bs[j];
+		}
+		bc += bpl;
+		bs += bpl;
+		cclr += 2;
+		cset += 2;
+	}
+	write(cursfd, curs, sizeof curs);
+}
+
+static int
+checkmouse(char *buf, int n)
+{
+	int x, y, tick, b;
+	static int lastb, lastt, lastx, lasty, lastclick;
+
+	switch(n){
+	default:
+		kwerrstr("atomouse: bad count");
+		return -1;
+
+	case 1+4*12:
+		if(buf[0] == 'r'){
+			qlock(&ql);
+			if(attachwindow(nil, nil, nil, nil) == nil) {
+				qunlock(&ql);
+				return -1;
+			}
+			_flushmemscreen(Rect(0, 0, Xsize, Ysize));
+			qunlock(&ql);
+		}
+		x = atoi(buf+1+0*12) - tiler.min.x;
+		y = atoi(buf+1+1*12) - tiler.min.y;
+		b = atoi(buf+1+2*12);
+		tick = atoi(buf+1+3*12);
+		if(b && lastb == 0){	/* button newly pressed */
+			if(b==lastclick && tick-lastt<400
+			   && abs(x-lastx)<10 && abs(y-lasty)<10)
+				b |= (1<<8);
+			lastt = tick;
+			lastclick = b&0xff;
+			lastx = x;
+			lasty = y;
+		}
+		lastb = b&0xff;
+		//mouse.msec = tick;
+		mousetrack(b, x, y, 0);
+		return n;
+	}
+}
+
+static void
+plan9readmouse(void *v)
+{
+	int n;
+	char buf[128];
+
+	USED(v);
+	for(;;){
+		n = read(mousefd, buf, sizeof(buf));
+		if(n < 0)	/* probably interrupted */
+			_exits(0);
+		checkmouse(buf, n);
+	}
+}
+
+static void
+plan9readkeybd(void*)
+{
+	int n, partial;
+	char buf[32];
+	char dbuf[32 * 3];		/* overestimate but safe */
+
+	partial = 0;
+	for(;;){
+		n = read(keybdfd, buf + partial, sizeof(buf) - partial);
+		if(n < 0)	/* probably interrupted */
+			_exits(0);
+		partial += n;
+		n = mapspecials(dbuf, buf, &partial);
+		qproduce(gkbdq, dbuf, n);
+	}
+}
+
+void
+setpointer(int x, int y)
+{
+	char buf[50];
+	int n;
+
+	if(mousefd < 0)
+		return;
+	x += tiler.min.x;
+	y += tiler.min.y;
+	n = snprint(buf, sizeof buf, "m%11d %11d ", x, y);
+	write(mousefd, buf, n);
+}
+
+/*
+ * plan9 keyboard codes; from /sys/include/keyboard.h; can't include directly
+ * because constant names clash.
+ */
+enum {
+	P9KF=	0xF000,	/* Rune: beginning of private Unicode space */
+	P9Spec=	0xF800,
+	/* KF|1, KF|2, ..., KF|0xC is F1, F2, ..., F12 */
+	Khome=	P9KF|0x0D,
+	Kup=	P9KF|0x0E,
+	Kpgup=	P9KF|0x0F,
+	Kprint=	P9KF|0x10,
+	Kleft=	P9KF|0x11,
+	Kright=	P9KF|0x12,
+	Kdown=	P9Spec|0x00,
+	Kview=	P9Spec|0x00,
+	Kpgdown=	P9KF|0x13,
+	Kins=	P9KF|0x14,
+	Kend=	KF|0x18,
+
+	Kalt=		P9KF|0x15,
+	Kshift=	P9KF|0x16,
+	Kctl=		P9KF|0x17,
+};
+
+/*
+ * translate plan 9 special characters from s2 (of length *n) into s1;
+ * return number of chars placed into s1.
+ * any trailing incomplete chars are moved to the beginning of s2,
+ * and *n set to the number moved there.
+ */
+static int
+mapspecials(char *s1, char *s2, int *n)
+{
+	char *s, *d, *es2;
+	Rune r;
+	d = s1;
+	s = s2;
+	es2 = s2 + *n;
+	while (fullrune(s, es2 - s)) {
+		s += chartorune(&r, s);
+		switch (r) {
+		case Kshift:
+			r = LShift;
+			break;
+		case Kctl:
+			r = LCtrl;
+			break;
+		case Kalt:
+			r = LAlt;
+			break;
+		case Khome:
+			r = Home;
+			break;
+		case Kend:
+			r = End;
+			break;
+		case Kup:
+			r = Up;
+			break;
+		case Kdown:
+			r = Down;
+			break;
+		case Kleft:
+			r = Left;
+			break;
+		case Kright:
+			r = Right;
+			break;
+		case Kpgup:
+			r = Pgup;
+			break;
+		case Kpgdown:
+			r = Pgdown;
+			break;
+		case Kins:
+			r = Ins;
+			break;
+		/*
+		 * function keys
+		 */
+		case P9KF|1:
+		case P9KF|2:
+		case P9KF|3:
+		case P9KF|4:
+		case P9KF|5:
+		case P9KF|6:
+		case P9KF|7:
+		case P9KF|8:
+		case P9KF|9:
+		case P9KF|10:
+		case P9KF|11:
+		case P9KF|12:
+			r = (r - P9KF) + KF;
+		}
+		d += runetochar(d, &r);
+	}
+	*n = es2 - s;
+	memmove(s2, s, *n);
+	return d - s1;
+}
--- a/emu/mkfile
+++ b/emu/mkfile
@@ -17,3 +17,7 @@
 &-Plan9:QV:
 	echo '@{builtin cd' $SYSTARG '; mk $MKFLAGS $stem}'
 	@{builtin cd $SYSTARG; mk $MKFLAGS $stem }
+
+&-9front:QV:
+	echo '@{builtin cd' $SYSTARG '; mk $MKFLAGS $stem}'
+	@{builtin cd $SYSTARG; mk $MKFLAGS $stem }
--- a/emu/port/alloc.c
+++ b/emu/port/alloc.c
@@ -40,6 +40,12 @@
 
 void*	initbrk(ulong);
 
+/* keep the quanta above the size of 5 pointers and 2 longs else the next block
+	will be getting overwritten by the header -- starts a corruption hunt
+	when pointer size = 8 bytes, then 63 = 2^q -1
+		for 4 bytes, 31
+	TODO make this a macro?
+ */
 struct
 {
 	int	n;
@@ -48,9 +54,9 @@
 } table = {
 	3,
 	{
-		{ "main",  0, 	32*1024*1024, 31,  512*1024, 0, 31*1024*1024 },
-		{ "heap",  1, 	32*1024*1024, 31,  512*1024, 0, 31*1024*1024 },
-		{ "image", 2,   64*1024*1024+256, 31, 4*1024*1024, 1, 63*1024*1024 },
+		{ "main",  0, 	32*1024*1024, 63,  512*1024, 0, 31*1024*1024 },
+		{ "heap",  1, 	32*1024*1024, 63,  512*1024, 0, 31*1024*1024 },
+		{ "image", 2,   64*1024*1024+256, 63, 4*1024*1024, 1, 63*1024*1024 },
 	}
 };
 
@@ -84,12 +90,12 @@
 	Monitor = 1
 };
 
-void	(*memmonitor)(int, ulong, ulong, ulong) = nil;
+void	(*memmonitor)(int, uintptr, void *, ulong) = nil;
 #define	MM(v,pc,base,size)	if(!Monitor || memmonitor==nil){} else memmonitor((v),(pc),(base),(size))
 
 #define CKLEAK	0
 int	ckleak;
-#define	ML(v, sz, pc)	if(CKLEAK && ckleak && v){ if(sz) fprint(2, "%lux %lux %lux\n", (ulong)v, (ulong)sz, (ulong)pc); else fprint(2, "%lux\n", (ulong)v); }
+#define	ML(v, sz, pc)	if(CKLEAK && ckleak && v){ if(sz) fprint(2, "%zx %lux %zx\n", (uintptr)v, (ulong)sz, (uintptr)pc); else fprint(2, "%zx\n", (uintptr)v); }
 
 int
 memusehigh(void)
@@ -279,7 +285,7 @@
 }
 
 static void*
-dopoolalloc(Pool *p, ulong asize, ulong pc)
+dopoolalloc(Pool *p, ulong asize, uintptr pc)
 {
 	Bhdr *q, *t;
 	int alloc, ldr, ns, frag;
@@ -306,7 +312,7 @@
 				p->hw = p->cursize;
 			unlock(&p->l);
 			if(p->monitor)
-				MM(p->pnum, pc, (ulong)B2D(t), size);
+				MM(p->pnum, pc, B2D(t), size);
 			return B2D(t);
 		}
 		if(size < t->size) {
@@ -326,7 +332,7 @@
 				p->hw = p->cursize;
 			unlock(&p->l);
 			if(p->monitor)
-				MM(p->pnum, pc, (ulong)B2D(q), size);
+				MM(p->pnum, pc, B2D(q), size);
 			return B2D(q);
 		}
 		/* Split */
@@ -342,7 +348,7 @@
 			p->hw = p->cursize;
 		unlock(&p->l);
 		if(p->monitor)
-			MM(p->pnum, pc, (ulong)B2D(q), size);
+			MM(p->pnum, pc, B2D(q), size);
 		return B2D(q);
 	}
 
@@ -393,7 +399,7 @@
 	}
 #else
 	/* Double alignment */
-	t = (Bhdr *)(((ulong)t + 7) & ~7);
+	t = (Bhdr *)(((uintptr)t + 7) & ~7);
 #endif
 	if(p->chain != nil && (char*)t-(char*)B2LIMIT(p->chain)-ldr == 0){
 		/* can merge chains */
@@ -438,7 +444,7 @@
 		p->hw = p->cursize;
 	unlock(&p->l);
 	if(p->monitor)
-		MM(p->pnum, pc, (ulong)B2D(t), size);
+		MM(p->pnum, pc, B2D(t), size);
 	return B2D(t);
 }
 
@@ -460,7 +466,7 @@
 
 	D2B(b, v);
 	if(p->monitor)
-		MM(p->pnum|(1<<8), getcallerpc(&p), (ulong)v, b->size);
+		MM(p->pnum|(1<<8), getcallerpc(&p), v, b->size);
 
 	lock(&p->l);
 	p->nfree++;
@@ -611,7 +617,7 @@
 		if(v != nil)
 			break;
 		if(0)
-			print("smalloc waiting from %lux\n", getcallerpc(&size));
+			print("smalloc waiting from %zx\n", getcallerpc(&size));
 		osenter();
 		osmillisleep(100);
 		osleave();
@@ -626,16 +632,16 @@
 {
 	void *v;
 
-	v = dopoolalloc(mainmem, size+Npadlong*sizeof(ulong), getcallerpc(&size));
+	v = dopoolalloc(mainmem, size+Npadlong*sizeof(uintptr), getcallerpc(&size));
 	if(v != nil){
 		ML(v, size, getcallerpc(&size));
 		if(Npadlong){
-			v = (ulong*)v+Npadlong;
+			v = (uintptr*)v+Npadlong;
 			setmalloctag(v, getcallerpc(&size));
 			setrealloctag(v, 0);
 		}
 		memset(v, 0, size);
-		MM(0, getcallerpc(&size), (ulong)v, size);
+		MM(0, getcallerpc(&size), v, size);
 	}
 	return v;
 }
@@ -647,18 +653,18 @@
 {
 	void *v;
 
-	v = poolalloc(mainmem, size+Npadlong*sizeof(ulong));
+	v = poolalloc(mainmem, size+Npadlong*sizeof(uintptr));
 	if(v != nil){
 		ML(v, size, getcallerpc(&size));
 		if(Npadlong){
-			v = (ulong*)v+Npadlong;
+			v = (uintptr*)v+Npadlong;
 			setmalloctag(v, getcallerpc(&size));
 			setrealloctag(v, 0);
 		}
 		memset(v, 0, size);
-		MM(0, getcallerpc(&size), (ulong)v, size);
+		MM(0, getcallerpc(&size), v, size);
 	} else 
-		print("malloc failed from %lux\n", getcallerpc(&size));
+		print("malloc failed from %zx\n", getcallerpc(&size));
 	return v;
 }
 
@@ -667,19 +673,19 @@
 {
 	void *v;
 
-	v = poolalloc(mainmem, size+Npadlong*sizeof(ulong));
+	v = poolalloc(mainmem, size+Npadlong*sizeof(uintptr));
 	if(v != nil){
 		ML(v, size, getcallerpc(&size));
 		if(Npadlong){
-			v = (ulong*)v+Npadlong;
+			v = (uintptr*)v+Npadlong;
 			setmalloctag(v, getcallerpc(&size));
 			setrealloctag(v, 0);
 		}
 		if(clr)
 			memset(v, 0, size);
-		MM(0, getcallerpc(&size), (ulong)v, size);
+		MM(0, getcallerpc(&size), v, size);
 	} else 
-		print("mallocz failed from %lux\n", getcallerpc(&size));
+		print("mallocz failed from %zx\n", getcallerpc(&size));
 	return v;
 }
 
@@ -690,10 +696,10 @@
 
 	if(v != nil) {
 		if(Npadlong)
-			v = (ulong*)v-Npadlong;
+			v = (uintptr*)v-Npadlong;
 		D2B(b, v);
 		ML(v, 0, 0);
-		MM(1<<8|0, getcallerpc(&v), (ulong)((ulong*)v+Npadlong), b->size);
+		MM(1<<8|0, getcallerpc(&v), ((uintptr*)v+Npadlong), b->size);
 		poolfree(mainmem, v);
 	}
 }
@@ -706,26 +712,26 @@
 	if(size == 0)
 		return malloc(size);	/* temporary change until realloc calls can be checked */
 	if(v != nil)
-		v = (ulong*)v-Npadlong;
+		v = (uintptr*)v-Npadlong;
 	if(Npadlong!=0 && size!=0)
-		size += Npadlong*sizeof(ulong);
+		size += Npadlong*sizeof(uintptr);
 	nv = poolrealloc(mainmem, v, size);
 	ML(v, 0, 0);
 	ML(nv, size, getcallerpc(&v));
 	if(nv != nil) {
-		nv = (ulong*)nv+Npadlong;
+		nv = (uintptr*)nv+Npadlong;
 		setrealloctag(nv, getcallerpc(&v));
 		if(v == nil)
 			setmalloctag(v, getcallerpc(&v));
 	} else 
-		print("realloc failed from %lux\n", getcallerpc(&v));
+		print("realloc failed from %zx\n", getcallerpc(&v));
 	return nv;
 }
 
 void
-setmalloctag(void *v, ulong pc)
+setmalloctag(void *v, uintptr pc)
 {
-	ulong *u;
+	uintptr *u;
 
 	USED(v);
 	USED(pc);
@@ -735,19 +741,19 @@
 	u[-Npadlong+MallocOffset] = pc;
 }
 
-ulong
+uintptr
 getmalloctag(void *v)
 {
 	USED(v);
 	if(Npadlong <= MallocOffset)
 		return ~0;
-	return ((ulong*)v)[-Npadlong+MallocOffset];
+	return ((uintptr*)v)[-Npadlong+MallocOffset];
 }
 
 void
-setrealloctag(void *v, ulong pc)
+setrealloctag(void *v, uintptr pc)
 {
-	ulong *u;
+	uintptr *u;
 
 	USED(v);
 	USED(pc);
@@ -757,12 +763,12 @@
 	u[-Npadlong+ReallocOffset] = pc;
 }
 
-ulong
+uintptr
 getrealloctag(void *v)
 {
 	USED(v);
 	if(Npadlong <= ReallocOffset)
-		return ((ulong*)v)[-Npadlong+ReallocOffset];
+		return ((uintptr*)v)[-Npadlong+ReallocOffset];
 	return ~0;
 }
 
@@ -771,7 +777,7 @@
 {
 	if(v == nil)
 		return 0;
-	return poolmsize(mainmem, (ulong*)v-Npadlong)-Npadlong*sizeof(ulong);
+	return poolmsize(mainmem, (uintptr*)v-Npadlong)-Npadlong*sizeof(uintptr);
 }
 
 void*
@@ -881,7 +887,7 @@
 }
 
 static void
-dumpvl(char *msg, ulong *v, int n)
+dumpvl(char *msg, uintptr *v, int n)
 {
 	int i, l;
 
@@ -891,7 +897,7 @@
 			print("\n");
 			l = print("    %p: ", v);
 		}
-		l += print(" %lux", *v++);
+		l += print(" %zx", *v++);
 	}
 	print("\n");
 }
@@ -901,7 +907,7 @@
 {
 	print("%s(%p): pool %s CORRUPT: %s at %p'%lud(magic=%lux)\n",
 		str, v, p->name, msg, b, b->size, b->magic);
-	dumpvl("bad Bhdr", (ulong *)((ulong)b & ~3)-4, 10);
+	dumpvl("bad Bhdr", (uintptr *)((uintptr)b & ~3)-4, 10);
 }
 
 static void
@@ -981,7 +987,7 @@
 			print(" is %s '%lux\n", fmsg, fsz);
 		else
 			print(" in %s at %p'%lux\n", fmsg, fb, fsz);
-		dumpvl("area", (ulong *)((ulong)v & ~3)-4, 20);
+		dumpvl("area", (uintptr *)((uintptr)v & ~3)-4, 20);
 	}
 }
 
--- a/emu/port/fns.h
+++ b/emu/port/fns.h
@@ -78,7 +78,7 @@
 void		freeb(Block*);
 void		freeblist(Block*);
 void		freeskey(Signerkey*);
-ulong	getcallerpc(void*);
+uintptr	getcallerpc(void*);
 ulong	getFPcontrol(void);
 ulong	getFPstatus(void);
 void		gkbdputc(Queue*, int);
--- /dev/null
+++ b/lib9/errstr-9front.c
@@ -1,0 +1,8 @@
+#include "lib9.h"
+
+void
+oserrstr(char *buf, uint nerr)
+{
+	*buf = 0;
+	errstr(buf, nerr);
+}
--- /dev/null
+++ b/lib9/mkfile-9front
@@ -1,0 +1,2 @@
+TARGFILES=errstr-9front.$O\
+
--- /dev/null
+++ b/libdynld/dynld-amd64.c
@@ -1,0 +1,42 @@
+#include "lib9.h"
+#include <a.out.h>
+#include <dynld.h>
+
+#define	CHK(i,ntab)	if((unsigned)(i)>=(ntab))return "bad relocation index"
+
+long
+dynmagic(void)
+{
+	return DYN_MAGIC | I_MAGIC;
+}
+
+char*
+dynreloc(uchar *b, ulong p, int m, Dynsym **tab, int ntab)
+{
+	int i;
+	ulong v, *pp;
+
+	p += (ulong)b;
+	pp = (ulong*)p;
+	v = *pp;
+	switch(m){
+	case 0:
+		v += (ulong)b;
+		break;
+	case 1:
+		i = v>>22;
+		v &= 0x3fffff;
+		CHK(i, ntab);
+		v += tab[i]->addr;
+		break;
+	case 2:
+		i = v>>22;
+		CHK(i, ntab);
+		v = tab[i]->addr -p-4;
+		break;
+	default:
+		return "bad relocation mode";
+	}
+	*pp = v;
+	return nil;
+}
--- /dev/null
+++ b/libinterp/comp-amd64.c
@@ -1,0 +1,1991 @@
+#include "lib9.h"
+#include "isa.h"
+#include "interp.h"
+#include "raise.h"
+
+#define DOT			((ulong)code)
+
+#define	RESCHED 1	/* check for interpreter reschedule */
+
+enum
+{
+	RAX	= 0,
+	RAH	= 4,
+	RCX	= 1,
+	RDX	= 2,
+	RBX	= 3,
+	RSP	= 4,
+	RBP	= 5,
+	RSI	= 6,
+	RDI	= 7,
+
+	RFP	= RSI,
+	RMP	= RDI,
+	RTA	= RDX,
+	RTMP	= RBX,
+
+	Omovzxb	= 0xb6,
+	Omovzxw	= 0xb7,
+	Osal	= 0xd1,
+	Oaddf	= 0xdc,
+	Ocall	= 0xe8,
+	Ocallrm	= 0xff,
+	Ocdq	= 0x99,
+	Ocld	= 0xfc,
+	Ocmpb	= 0x38,
+	Ocmpw	= 0x39,
+	Ocmpi	= 0x83,
+	Odecrm	= 0xff,
+	Oincr	= 0x40,
+	Oincrm	= 0xff,
+	Ojccl	= 0x83,
+	Ojcsl	= 0x82,
+	Ojeqb	= 0x74,
+	Ojeql	= 0x84,
+	Ojgel	= 0x8d,
+	Ojgtl	= 0x8f,
+	Ojhil	= 0x87,
+	Ojlel	= 0x8e,
+	Ojlsl	= 0x86,
+	Ojltl	= 0x8c,
+	Ojol	= 0x80,
+	Ojnol	= 0x81,
+	Ojbl	= 0x82,
+	Ojael	= 0x83,
+	Ojal	= 0x87,
+	Ojnel	= 0x85,
+	Ojbel	= 0x86,
+	Ojneb	= 0x75,
+	Ojgtb	= 0x7f,
+	Ojgeb	= 0x7d,
+	Ojleb	= 0x7e,
+	Ojltb	= 0x7c,
+	Ojmp	= 0xe9,
+	Ojmpb	= 0xeb,
+	Ojmprm	= 0xff,
+	Oldb	= 0x8a,
+	Olds	= 0x89,
+	Oldw	= 0x8b,
+	Olea	= 0x8d,
+	Otestib	= 0xf6,
+	Oshld	= 0xa5,
+	Oshrd	= 0xad,
+	Osar	= 0xd3,
+	Osarimm = 0xc1,
+	Omov	= 0xc7,
+	Omovf	= 0xdd,
+	Omovimm	= 0xb8,
+	Omovsb	= 0xa4,
+	Orep	= 0xf3,
+	Oret	= 0xc3,
+	Oshl	= 0xd3,
+	Oshr	= 0xd1,
+	Ostb	= 0x88,
+	Ostw	= 0x89,
+	Osubf	= 0xdc,
+	Oxchg	= 0x87,
+	OxchgAX	= 0x90,
+	Oxor	= 0x31,
+	Opopl	= 0x58,
+	Opushl	= 0x50,
+	Opushrm	= 0xff,
+	Oneg	= 0xf7,
+
+	SRCOP	= (1<<0),
+	DSTOP	= (1<<1),
+	WRTPC	= (1<<2),
+	TCHECK	= (1<<3),
+	NEWPC	= (1<<4),
+	DBRAN	= (1<<5),
+	THREOP	= (1<<6),
+
+	ANDAND	= 1,
+	OROR	= 2,
+	EQAND	= 3,
+
+	MacFRP	= 0,
+	MacRET	= 1,
+	MacCASE	= 2,
+	MacCOLR	= 3,
+	MacMCAL	= 4,
+	MacFRAM	= 5,
+	MacMFRA	= 6,
+	MacRELQ = 7,
+	NMACRO
+};
+
+static	uchar*	code;
+static	uchar*	base;
+static	ulong*	patch;
+static	int	pass;
+static	Module*	mod;
+static	uchar*	tinit;
+static	ulong*	litpool;
+static	int	nlit;
+static	void	macfrp(void);
+static	void	macret(void);
+static	void	maccase(void);
+static	void	maccolr(void);
+static	void	macmcal(void);
+static	void	macfram(void);
+static	void	macmfra(void);
+static	void	macrelq(void);
+static	ulong	macro[NMACRO];
+	void	(*comvec)(void);
+extern	void	das(uchar*, int);
+
+#define T(r)	*((void**)(R.r))
+
+struct
+{
+	int	idx;
+	void	(*gen)(void);
+} mactab[] =
+{
+	MacFRP,		macfrp,		/* decrement and free pointer */
+	MacRET,		macret,		/* return instruction */
+	MacCASE,	maccase,	/* case instruction */
+	MacCOLR,	maccolr,	/* increment and color pointer */
+	MacMCAL,	macmcal,	/* mcall bottom half */
+	MacFRAM,	macfram,	/* frame instruction */
+	MacMFRA,	macmfra,	/* punt mframe because t->initialize==0 */
+	MacRELQ,		macrelq,	/* reschedule */
+};
+
+static void
+bounds(void)
+{
+	error(exBounds);
+}
+
+static void
+rdestroy(void)
+{
+	destroy(R.s);
+}
+
+static void
+rmcall(void)
+{
+	Prog *p;
+	Frame *f;
+
+	if((void*)R.dt == H)
+		error(exModule);
+
+	f = (Frame*)R.FP;
+	if(f == H)
+		error(exModule);
+
+	f->mr = nil;
+	((void(*)(Frame*))R.dt)(f);
+	R.SP = (uchar*)f;
+	R.FP = f->fp;
+	if(f->t == nil)
+		unextend(f);
+	else
+		freeptrs(f, f->t);
+	p = currun();
+	if(p->kill != nil)
+		error(p->kill);
+}
+
+static void
+rmfram(void)
+{
+	Type *t;
+	Frame *f;
+	uchar *nsp;
+
+	t = (Type*)R.s;
+	if(t == H)
+		error(exModule);
+
+	nsp = R.SP + t->size;
+	if(nsp >= R.TS) {
+		R.s = t;
+		extend();
+		T(d) = R.s;
+		return;
+	}
+	f = (Frame*)R.SP;
+	R.SP = nsp;
+	f->t = t;
+	f->mr = nil;
+	initmem(t, f);
+	T(d) = f;
+}
+
+static int
+bc(int o)
+{
+	if(o < 127 && o > -128)
+		return 1;
+	return 0;
+}
+
+static void
+urk(void)
+{
+	error(exCompile);
+}
+
+static void
+genb(uchar o)
+{
+	*code++ = o;
+}
+
+static void
+gen2(uchar o1, uchar o2)
+{
+	code[0] = o1;
+	code[1] = o2;
+	code += 2;
+}
+
+static void
+genw(ulong o)
+{
+	*(ulong*)code = o;
+	code += 4;
+}
+
+static void
+modrm(int inst, ulong disp, int rm, int r)
+{
+	*code++ = inst;
+	if(disp == 0) {
+		*code++ = (0<<6)|(r<<3)|rm;
+		return;
+	}
+	if(bc(disp)) {
+		code[0] = (1<<6)|(r<<3)|rm;
+		code[1] = disp;
+		code += 2;
+		return;
+	}
+	*code++ = (2<<6)|(r<<3)|rm;
+	*(ulong*)code = disp;
+	code += 4;
+}
+
+static void
+con(ulong o, int r)
+{
+	if(o == 0) {
+		gen2(Oxor, (3<<6)|(r<<3)|r);
+		return;
+	}
+	genb(Omovimm+r);
+	genw(o);
+}
+
+static void
+opwld(Inst *i, int mi, int r)
+{
+	int ir, rta;
+
+	switch(UXSRC(i->add)) {
+	default:
+		print("%D\n", i);
+		urk();
+	case SRC(AFP):
+		modrm(mi, i->s.ind, RFP, r);
+		return;
+	case SRC(AMP):
+		modrm(mi, i->s.ind, RMP, r);
+		return;
+	case SRC(AIMM):
+		con(i->s.imm, r);
+		return;
+	case SRC(AIND|AFP):
+		ir = RFP;
+		break;
+	case SRC(AIND|AMP):
+		ir = RMP;
+		break;
+	}
+	rta = RTA;
+	if(mi == Olea)
+		rta = r;
+	modrm(Oldw, i->s.i.f, ir, rta);
+	modrm(mi, i->s.i.s, rta, r);
+}
+
+static void
+opwst(Inst *i, int mi, int r)
+{
+	int ir, rta;
+
+	switch(UXDST(i->add)) {
+	default:
+		print("%D\n", i);
+		urk();
+	case DST(AIMM):
+		con(i->d.imm, r);
+		return;
+	case DST(AFP):
+		modrm(mi, i->d.ind, RFP, r);
+		return;
+	case DST(AMP):
+		modrm(mi, i->d.ind, RMP, r);
+		return;
+	case DST(AIND|AFP):
+		ir = RFP;
+		break;
+	case DST(AIND|AMP):
+		ir = RMP;
+		break;
+	}
+	rta = RTA;
+	if(mi == Olea)
+		rta = r;
+	modrm(Oldw, i->d.i.f, ir, rta);
+	modrm(mi, i->d.i.s, rta, r);
+}
+
+static void
+bra(ulong dst, int op)
+{
+	dst -= (DOT+5);
+	genb(op);
+	genw(dst);
+}
+
+static void
+rbra(ulong dst, int op)
+{
+	dst += (ulong)base;
+	dst -= DOT+5;
+	genb(op);
+	genw(dst);
+}
+
+static void
+literal(ulong imm, int roff)
+{
+	nlit++;
+
+	genb(Omovimm+RAX);
+	genw((ulong)litpool);
+	modrm(Ostw, roff, RTMP, RAX);
+
+	if(pass == 0)
+		return;
+
+	*litpool = imm;
+	litpool++;	
+}
+
+static void
+punt(Inst *i, int m, void (*fn)(void))
+{
+	ulong pc;
+
+	con((ulong)&R, RTMP);
+
+	if(m & SRCOP) {
+		if(UXSRC(i->add) == SRC(AIMM))
+			literal(i->s.imm, O(REG, s));
+		else {
+			opwld(i, Olea, RAX);
+			modrm(Ostw, O(REG, s), RTMP, RAX);
+		}
+	}
+
+	if(m & DSTOP) {
+		opwst(i, Olea, 0);
+		modrm(Ostw, O(REG, d), RTMP, RAX);
+	}
+	if(m & WRTPC) {
+		modrm(Omov, O(REG, PC), RTMP, 0);
+		pc = patch[i-mod->prog+1];
+		genw((ulong)base + pc);
+	}
+	if(m & DBRAN) {
+		pc = patch[(Inst*)i->d.imm-mod->prog];
+		literal((ulong)base+pc, O(REG, d));
+	}
+
+	switch(i->add&ARM) {
+	case AXNON:
+		if(m & THREOP) {
+			modrm(Oldw, O(REG, d), RTMP, RAX);
+			modrm(Ostw, O(REG, m), RTMP, RAX);
+		}
+		break;
+	case AXIMM:
+		literal((short)i->reg, O(REG, m));
+		break;
+	case AXINF:
+		modrm(Olea, i->reg, RFP, RAX);
+		modrm(Ostw, O(REG, m), RTMP, RAX);
+		break;
+	case AXINM:
+		modrm(Olea, i->reg, RMP, RAX);
+		modrm(Ostw, O(REG, m), RTMP, RAX);
+		break;
+	}
+	modrm(Ostw, O(REG, FP), RTMP, RFP);
+
+	bra((ulong)fn, Ocall);
+
+	con((ulong)&R, RTMP);
+	if(m & TCHECK) {
+		modrm(Ocmpi, O(REG, t), RTMP, 7);// CMPL $0, R.t
+		genb(0x00);
+		gen2(Ojeqb, 0x06);		// JEQ	.+6
+		genb(Opopl+RDI);
+		genb(Opopl+RSI);
+		genb(Opopl+RDX);
+		genb(Opopl+RCX);
+		genb(Opopl+RBX);
+		genb(Oret);
+	}
+
+	modrm(Oldw, O(REG, FP), RTMP, RFP);
+	modrm(Oldw, O(REG, MP), RTMP, RMP);
+
+	if(m & NEWPC) {
+		modrm(Oldw, O(REG, PC), RTMP, RAX);
+		gen2(Ojmprm, (3<<6)|(4<<3)|RAX);
+	}
+}
+
+static void
+mid(Inst *i, uchar mi, int r)
+{
+	int ir;
+
+	switch(i->add&ARM) {
+	default:
+		opwst(i, mi, r);
+		return;
+	case AXIMM:
+		con((short)i->reg, r);
+		return;
+	case AXINF:
+		ir = RFP;
+		break;
+	case AXINM:
+		ir = RMP;
+		break;
+	}
+	modrm(mi, i->reg, ir, r);
+}
+
+static void
+arith(Inst *i, int op2, int rm)
+{
+	if(UXSRC(i->add) != SRC(AIMM)) {
+		if(i->add&ARM) {
+			mid(i, Oldw, RAX);
+			opwld(i, op2|2, 0);
+			opwst(i, Ostw, 0);
+			return;
+		}
+		opwld(i, Oldw, RAX);
+		opwst(i, op2, 0);
+		return;
+	}
+	if(i->add&ARM) {
+		mid(i, Oldw, RAX);
+		if(bc(i->s.imm)) {
+			gen2(0x83, (3<<6)|(rm<<3)|RAX);
+			genb(i->s.imm);
+		}
+		else {
+			gen2(0x81, (3<<6)|(rm<<3)|RAX);
+			genw(i->s.imm);
+		}
+		opwst(i, Ostw, RAX);
+		return;
+	}
+	if(bc(i->s.imm)) {
+		opwst(i, 0x83, rm);
+		genb(i->s.imm);
+		return;
+	}
+	opwst(i, 0x81, rm);
+	genw(i->s.imm);
+}
+
+static void
+arithb(Inst *i, int op2)
+{
+	if(UXSRC(i->add) == SRC(AIMM))
+		urk();
+
+	if(i->add&ARM) {
+		mid(i, Oldb, RAX);
+		opwld(i, op2|2, 0);
+		opwst(i, Ostb, 0);
+		return;
+	}
+	opwld(i, Oldb, RAX);
+	opwst(i, op2, RAX);
+}
+
+static void
+shift(Inst *i, int ld, int st, int op, int r)
+{
+	mid(i, ld, RAX);
+	opwld(i, Oldw, RCX);
+	gen2(op, (3<<6)|(r<<3)|RAX);
+	opwst(i, st, RAX);
+}
+
+static void
+arithf(Inst *i, int op)
+{
+	opwld(i, Omovf, 0);
+	mid(i, 0xdc, op);
+	opwst(i, Omovf, 3);
+}
+
+static void
+cmpl(int r, ulong v)
+{
+	if(bc(v)) {
+		gen2(0x83, (3<<6)|(7<<3)|r);
+		genb(v);
+		return;
+	}
+	gen2(0x81, (3<<6)|(7<<3)|r);
+	genw(v);
+}
+
+static int
+swapbraop(int b)
+{
+	switch(b) {
+	case Ojgel:
+		return Ojlel;
+	case Ojlel:
+		return Ojgel;
+	case Ojgtl:
+		return Ojltl;
+	case Ojltl:
+		return Ojgtl;
+	}
+	return b;
+}
+
+static void
+schedcheck(Inst *i)
+{
+	if(RESCHED && i->d.ins <= i){
+		con((ulong)&R, RTMP);
+		/* sub $1, R.IC */
+		modrm(0x83, O(REG, IC), RTMP, 5);
+		genb(1);
+		gen2(Ojgtb, 5);
+		rbra(macro[MacRELQ], Ocall);
+	}
+}
+
+static void
+cbra(Inst *i, int jmp)
+{
+	if(RESCHED)
+		schedcheck(i);
+	mid(i, Oldw, RAX);
+	if(UXSRC(i->add) == SRC(AIMM)) {
+		cmpl(RAX, i->s.imm);
+		jmp = swapbraop(jmp);
+	}
+	else
+		opwld(i, Ocmpw, RAX);
+	genb(0x0f);
+	rbra(patch[i->d.ins-mod->prog], jmp);
+}
+
+static void
+cbral(Inst *i, int jmsw, int jlsw, int mode)
+{
+	ulong dst;
+	uchar *label;
+
+	if(RESCHED)
+		schedcheck(i);
+	opwld(i, Olea, RTMP);
+	mid(i, Olea, RTA);
+	modrm(Oldw, 4, RTA, RAX);
+	modrm(Ocmpw, 4, RTMP, RAX);
+	label = 0;
+	dst = patch[i->d.ins-mod->prog];
+	switch(mode) {
+	case ANDAND:
+		gen2(Ojneb, 0);
+		label = code-1;
+		break;
+	case OROR:
+		genb(0x0f);
+		rbra(dst, jmsw);
+		break;
+	case EQAND:
+		genb(0x0f);
+		rbra(dst, jmsw);
+		gen2(Ojneb, 0);
+		label = code-1;
+		break;
+	}
+	modrm(Oldw, 0, RTA, RAX);
+	modrm(Ocmpw, 0, RTMP, RAX);
+	genb(0x0f);
+	rbra(dst, jlsw);
+	if(label != nil)
+		*label = code-label-1;
+}
+
+static void
+cbrab(Inst *i, int jmp)
+{
+	if(RESCHED)
+		schedcheck(i);
+	mid(i, Oldb, RAX);
+	if(UXSRC(i->add) == SRC(AIMM))
+		urk();
+
+	opwld(i, Ocmpb, RAX);
+	genb(0x0f);
+	rbra(patch[i->d.ins-mod->prog], jmp);
+}
+
+static void
+cbraf(Inst *i, int jmp)
+{
+	if(RESCHED)
+		schedcheck(i);
+	opwld(i, Omovf, 0);
+	mid(i, 0xdc, 3);	// FCOMP
+	genb(0x9b);		// FWAIT
+	gen2(0xdf, 0xe0);	// FSTSW AX
+	genb(0x9e);		// SAHF
+
+	genb(0x0f);
+	rbra(patch[i->d.ins-mod->prog], jmp);
+}
+
+static void
+comcase(Inst *i, int w)
+{
+	int l;
+	WORD *t, *e;
+
+	if(w != 0) {
+		opwld(i, Oldw, RAX);		// v
+		genb(Opushl+RSI);
+		opwst(i, Olea, RSI);		// table
+		rbra(macro[MacCASE], Ojmp);
+	}
+
+	t = (WORD*)(mod->origmp+i->d.ind+4);
+	l = t[-1];
+
+	/* have to take care not to relocate the same table twice - 
+	 * the limbo compiler can duplicate a case instruction
+	 * during its folding phase
+	 */
+
+	if(pass == 0) {
+		if(l >= 0)
+			t[-1] = -l-1;	/* Mark it not done */
+		return;
+	}
+	if(l >= 0)			/* Check pass 2 done */
+		return;
+	t[-1] = -l-1;			/* Set real count */
+	e = t + t[-1]*3;
+	while(t < e) {
+		t[2] = (ulong)base + patch[t[2]];
+		t += 3;
+	}
+	t[0] = (ulong)base + patch[t[0]];
+}
+
+static void
+comcasel(Inst *i)
+{
+	int l;
+	WORD *t, *e;
+
+	t = (WORD*)(mod->origmp+i->d.ind+8);
+	l = t[-2];
+	if(pass == 0) {
+		if(l >= 0)
+			t[-2] = -l-1;	/* Mark it not done */
+		return;
+	}
+	if(l >= 0)			/* Check pass 2 done */
+		return;
+	t[-2] = -l-1;			/* Set real count */
+	e = t + t[-2]*6;
+	while(t < e) {
+		t[4] = (ulong)base + patch[t[4]];
+		t += 6;
+	}
+	t[0] = (ulong)base + patch[t[0]];
+}
+
+static void
+commframe(Inst *i)
+{
+	int o;
+	uchar *punt, *mlnil;
+
+	opwld(i, Oldw, RAX);
+	cmpl(RAX, (ulong)H);
+	gen2(Ojeqb, 0);
+	mlnil = code - 1;
+	if((i->add&ARM) == AXIMM) {
+		o = OA(Modlink, links)+i->reg*sizeof(Modl)+O(Modl, frame);
+		modrm(Oldw, o, RAX, RTA);
+	} else {
+		gen2(Oldw, (3<<6)|(RTMP<<3)|RAX);	// MOVL	AX, RTMP
+		mid(i, Oldw, RCX);			// index
+		gen2(Olea, (0<<6)|(0<<3)|4);		// lea	(AX)(RCX*8)
+		genb((3<<6)|(RCX<<3)|RAX);		// assumes sizeof(Modl) == 8 hence 3
+		o = OA(Modlink, links)+O(Modl, frame);
+		modrm(Oldw, o, RAX, RTA);		// frame
+		genb(OxchgAX+RTMP);			// get old AX back
+	}
+	modrm(0x83, O(Type, initialize), RTA, 7);
+	genb(0);
+	gen2(Ojneb, 0);
+	punt = code - 1;
+	genb(OxchgAX+RTA);
+	opwst(i, Olea, RTA);
+	*mlnil = code-mlnil-1;
+	rbra(macro[MacMFRA], Ocall);
+	rbra(patch[i-mod->prog+1], Ojmp);
+
+	*punt = code-punt-1;
+	rbra(macro[MacFRAM], Ocall);
+	opwst(i, Ostw, RCX);
+}
+
+static void
+commcall(Inst *i)
+{
+	uchar *mlnil;
+
+	con((ulong)&R, RTMP);			// MOVL	$R, RTMP
+	opwld(i, Oldw, RCX);
+	modrm(Omov, O(Frame, lr), RCX, 0);	// MOVL $.+1, lr(CX)	f->lr = R.PC
+	genw((ulong)base+patch[i-mod->prog+1]);
+	modrm(Ostw, O(Frame, fp), RCX, RFP); 	// MOVL RFP, fp(CX)	f->fp = R.FP
+	modrm(Oldw, O(REG, M), RTMP, RTA);	// MOVL R.M, RTA
+	modrm(Ostw, O(Frame, mr), RCX, RTA);	// MOVL RTA, mr(CX) 	f->mr = R.M
+	opwst(i, Oldw, RTA);			// MOVL ml, RTA
+	cmpl(RTA, (ulong)H);
+	gen2(Ojeqb, 0);
+	mlnil = code - 1;
+	if((i->add&ARM) == AXIMM)
+		modrm(Oldw, OA(Modlink, links)+i->reg*sizeof(Modl)+O(Modl, u.pc), RTA, RAX);
+	else {
+		genb(Opushl+RCX);
+		mid(i, Oldw, RCX);		// index
+		gen2(Olea, (0<<6)|(0<<3)|4);	// lea	(RTA)(RCX*8)
+		genb((3<<6)|(RCX<<3)|RTA);	// assumes sizeof(Modl) == 8 hence 3
+		modrm(Oldw, OA(Modlink, links)+O(Modl, u.pc), RAX, RAX);
+		genb(Opopl+RCX);
+	}
+	*mlnil = code-mlnil-1;
+	rbra(macro[MacMCAL], Ocall);
+}
+
+static void
+larith(Inst *i, int op, int opc)
+{
+	opwld(i, Olea, RTMP);
+	mid(i, Olea, RTA);
+	modrm(Oldw, 0, RTA, RAX);	// MOVL	0(RTA), AX
+	modrm(op, 0, RTMP, RAX);	// ADDL 0(RTMP), AX
+	modrm(Oldw, 4, RTA, RCX);	// MOVL 4(RTA), CX
+	modrm(opc, 4, RTMP, RCX);	// ADCL 4(RTMP), CX
+	if((i->add&ARM) != AXNON)
+		opwst(i, Olea, RTA);
+	modrm(Ostw, 0, RTA, RAX);
+	modrm(Ostw, 4, RTA, RCX);
+}
+
+static void
+shll(Inst *i)
+{
+	uchar *label, *label1;
+
+	opwld(i, Oldw, RCX);
+	mid(i, Olea, RTA);
+	gen2(Otestib, (3<<6)|(0<<3)|RCX);
+	genb(0x20);
+	gen2(Ojneb, 0);
+	label = code-1;
+	modrm(Oldw, 0, RTA, RAX);
+	modrm(Oldw, 4, RTA, RBX);
+	genb(0x0f);
+	gen2(Oshld, (3<<6)|(RAX<<3)|RBX);
+	gen2(Oshl, (3<<6)|(4<<3)|RAX);
+	gen2(Ojmpb, 0);
+	label1 = code-1;
+	*label = code-label-1;
+	modrm(Oldw, 0, RTA, RBX);
+	con(0, RAX);
+	gen2(Oshl, (3<<6)|(4<<3)|RBX);
+	*label1 = code-label1-1;
+	opwst(i, Olea, RTA);
+	modrm(Ostw, 0, RTA, RAX);
+	modrm(Ostw, 4, RTA, RBX);
+}
+
+static void
+shrl(Inst *i)
+{
+	uchar *label, *label1;
+
+	opwld(i, Oldw, RCX);
+	mid(i, Olea, RTA);
+	gen2(Otestib, (3<<6)|(0<<3)|RCX);
+	genb(0x20);
+	gen2(Ojneb, 0);
+	label = code-1;
+	modrm(Oldw, 0, RTA, RAX);
+	modrm(Oldw, 4, RTA, RBX);
+	genb(0x0f);
+	gen2(Oshrd, (3<<6)|(RBX<<3)|RAX);
+	gen2(Osar, (3<<6)|(7<<3)|RBX);
+	gen2(Ojmpb, 0);
+	label1 = code-1;
+	*label = code-label-1;
+	modrm(Oldw, 4, RTA, RBX);
+	gen2(Oldw, (3<<6)|(RAX<<3)|RBX);
+	gen2(Osarimm, (3<<6)|(7<<3)|RBX);
+	genb(0x1f);
+	gen2(Osar, (3<<6)|(7<<3)|RAX);
+	*label1 = code-label1-1;
+	opwst(i, Olea, RTA);
+	modrm(Ostw, 0, RTA, RAX);
+	modrm(Ostw, 4, RTA, RBX);
+}
+
+static
+void
+compdbg(void)
+{
+	print("%s:%lud@%.8lux\n", R.M->m->name, *(ulong*)R.m, *(ulong*)R.s);
+}
+
+static void
+comp(Inst *i)
+{
+	int r;
+	WORD *t, *e;
+	char buf[64];
+
+	if(0) {
+		Inst xx;
+		xx.add = AXIMM|SRC(AIMM);
+		xx.s.imm = (ulong)code;
+		xx.reg = i-mod->prog;
+		punt(&xx, SRCOP, compdbg);
+	}
+
+	switch(i->op) {
+	default:
+		snprint(buf, sizeof buf, "%s compile, no '%D'", mod->name, i);
+		error(buf);
+		break;
+	case IMCALL:
+		if((i->add&ARM) == AXIMM)
+			commcall(i);
+		else
+			punt(i, SRCOP|DSTOP|THREOP|WRTPC|NEWPC, optab[i->op]);
+		break;
+	case ISEND:
+	case IRECV:
+	case IALT:
+		punt(i, SRCOP|DSTOP|TCHECK|WRTPC, optab[i->op]);
+		break;
+	case ISPAWN:
+		punt(i, SRCOP|DBRAN, optab[i->op]);
+		break;
+	case IBNEC:
+	case IBEQC:
+	case IBLTC:
+	case IBLEC:
+	case IBGTC:
+	case IBGEC:
+		punt(i, SRCOP|DBRAN|NEWPC|WRTPC, optab[i->op]);
+		break;
+	case ICASEC:
+		comcase(i, 0);
+		punt(i, SRCOP|DSTOP|NEWPC, optab[i->op]);
+		break;
+	case ICASEL:
+		comcasel(i);
+		punt(i, SRCOP|DSTOP|NEWPC, optab[i->op]);
+		break;
+	case IADDC:
+	case IMULL:
+	case IDIVL:
+	case IMODL:
+	case IMNEWZ:
+	case ILSRW:
+	case ILSRL:
+		punt(i, SRCOP|DSTOP|THREOP, optab[i->op]);
+		break;
+	case ILOAD:
+	case INEWA:
+	case INEWAZ:
+	case INEW:
+	case INEWZ:
+	case ISLICEA:
+	case ISLICELA:
+	case ICONSB:
+	case ICONSW:
+	case ICONSL:
+	case ICONSF:
+	case ICONSM:
+	case ICONSMP:
+	case ICONSP:
+	case IMOVMP:
+	case IHEADMP:
+	case IHEADL:
+	case IINSC:
+	case ICVTAC:
+	case ICVTCW:
+	case ICVTWC:
+	case ICVTLC:
+	case ICVTCL:
+	case ICVTFC:
+	case ICVTCF:
+	case ICVTRF:
+	case ICVTFR:
+	case ICVTWS:
+	case ICVTSW:
+	case IMSPAWN:
+	case ICVTCA:
+	case ISLICEC:
+	case INBALT:
+		punt(i, SRCOP|DSTOP, optab[i->op]);
+		break;
+	case INEWCM:
+	case INEWCMP:
+		punt(i, SRCOP|DSTOP|THREOP, optab[i->op]);
+		break;
+	case IMFRAME:
+		if((i->add&ARM) == AXIMM)
+			commframe(i);
+		else
+			punt(i, SRCOP|DSTOP|THREOP, optab[i->op]);
+		break;
+	case INEWCB:
+	case INEWCW:
+	case INEWCF:
+	case INEWCP:
+	case INEWCL:
+		punt(i, DSTOP|THREOP, optab[i->op]);
+		break;
+	case IEXIT:
+		punt(i, 0, optab[i->op]);
+		break;
+	case ICVTBW:
+		opwld(i, Oldb, RAX);
+		genb(0x0f);
+		gen2(0xb6, (3<<6)|(RAX<<3)|RAX);
+		opwst(i, Ostw, RAX);
+		break;
+	case ICVTWB:
+		opwld(i, Oldw, RAX);
+		opwst(i, Ostb, RAX);
+		break;
+	case ICVTFW:
+		if(1){
+			punt(i, SRCOP|DSTOP, optab[i->op]);
+			break;
+		}
+		opwld(i, Omovf, 0);
+		opwst(i, 0xdb, 3);
+		break;
+	case ICVTWF:
+		if(1){
+			punt(i, SRCOP|DSTOP, optab[i->op]);
+			break;
+		}
+		opwld(i, 0xdb, 0);
+		opwst(i, Omovf, 3);
+		break;
+	case ICVTLF:
+		if(1){
+			punt(i, SRCOP|DSTOP, optab[i->op]);
+			break;
+		}
+		opwld(i, 0xdf, 5);
+		opwst(i, Omovf, 3);
+		break;
+	case ICVTFL:
+		if(1){
+			punt(i, SRCOP|DSTOP, optab[i->op]);
+			break;
+		}
+		opwld(i, Omovf, 0);
+		opwst(i, 0xdf, 7);
+		break;
+	case IHEADM:
+		opwld(i, Oldw, RAX);
+		modrm(Olea, OA(List, data), RAX, RAX);
+		goto movm;
+	case IMOVM:
+		opwld(i, Olea, RAX);
+	movm:
+		opwst(i, Olea, RBX);
+		mid(i, Oldw, RCX);
+		genb(OxchgAX+RSI);
+		gen2(Oxchg, (3<<6)|(RDI<<3)|RBX);
+		genb(Ocld);
+		gen2(Orep, Omovsb);
+		genb(OxchgAX+RSI);
+		gen2(Oxchg, (3<<6)|(RDI<<3)|RBX);
+		break;
+	case IRET:
+		rbra(macro[MacRET], Ojmp);
+		break;
+	case IFRAME:
+		if(UXSRC(i->add) != SRC(AIMM)) {
+			punt(i, SRCOP|DSTOP, optab[i->op]);
+			break;
+		}
+		tinit[i->s.imm] = 1;
+		con((ulong)mod->type[i->s.imm], RTA);
+		rbra(macro[MacFRAM], Ocall);
+		opwst(i, Ostw, RCX);
+		break;
+	case ILEA:
+		if(UXSRC(i->add) == SRC(AIMM)) {
+			gen2(Ojmpb, 4);
+			genw(i->s.imm);
+			con((ulong)(code-4), RAX);
+		}
+		else
+			opwld(i, Olea, RAX);
+		opwst(i, Ostw, RAX);
+		break;
+	case IHEADW:
+		opwld(i, Oldw, RAX);
+		modrm(Oldw, OA(List, data), RAX, RAX);
+		opwst(i, Ostw, RAX);
+		break;
+	case IHEADF:
+		opwld(i, Oldw, RAX);
+		modrm(Omovf, OA(List, data), RAX, 0);
+		opwst(i, Omovf, 3);
+		break;
+	case IHEADB:
+		opwld(i, Oldw, RAX);
+		modrm(Oldb, OA(List, data), RAX, RAX);
+		opwst(i, Ostb, RAX);
+		break;
+	case ITAIL:
+		opwld(i, Oldw, RAX);
+		modrm(Oldw, O(List, tail), RAX, RBX);
+		goto movp;
+	case IMOVP:
+	case IHEADP:
+		opwld(i, Oldw, RBX);
+		if(i->op == IHEADP)
+			modrm(Oldw, OA(List, data), RBX, RBX);
+	movp:
+		cmpl(RBX, (ulong)H);
+		gen2(Ojeqb, 0x05);
+		rbra(macro[MacCOLR], Ocall);
+		opwst(i, Oldw, RAX);
+		opwst(i, Ostw, RBX);
+		rbra(macro[MacFRP], Ocall);
+		break;
+	case ILENA:
+		opwld(i, Oldw, RBX);
+		con(0, RAX);
+		cmpl(RBX, (ulong)H);
+		gen2(Ojeqb, 0x02);
+		modrm(Oldw, O(Array, len), RBX, RAX);
+		opwst(i, Ostw, RAX);
+		break;
+	case ILENC:
+		opwld(i, Oldw, RBX);
+		con(0, RAX);
+		cmpl(RBX, (ulong)H);
+		gen2(Ojeqb, 0x09);
+		modrm(Oldw, O(String, len), RBX, RAX);
+		cmpl(RAX, 0);
+		gen2(Ojgeb, 0x02);
+		gen2(Oneg, (3<<6)|(3<<3)|RAX);
+		opwst(i, Ostw, RAX);
+		break;
+	case ILENL:
+		con(0, RAX);
+		opwld(i, Oldw, RBX);
+		cmpl(RBX, (ulong)H);
+		gen2(Ojeqb, 0x05);
+		modrm(Oldw, O(List, tail), RBX, RBX);
+		genb(Oincr+RAX);
+		gen2(Ojmpb, 0xf6);
+		opwst(i, Ostw, RAX);
+		break;
+	case IBEQF:
+		cbraf(i, Ojeql);
+		break;
+	case IBNEF:
+		cbraf(i, Ojnel);
+		break;
+	case IBLEF:
+		cbraf(i, Ojlsl);
+		break;
+	case IBLTF:
+		cbraf(i, Ojcsl);
+		break;
+	case IBGEF:
+		cbraf(i, Ojccl);
+		break;
+	case IBGTF:
+		cbraf(i, Ojhil);
+		break;
+	case IBEQW:
+		cbra(i, Ojeql);
+		break;
+	case IBLEW:
+		cbra(i, Ojlel);
+		break;
+	case IBNEW:
+		cbra(i, Ojnel);
+		break;
+	case IBGTW:
+		cbra(i, Ojgtl);
+		break;
+	case IBLTW:
+		cbra(i, Ojltl);
+		break;
+	case IBGEW:
+		cbra(i, Ojgel);
+		break;
+	case IBEQB:
+		cbrab(i, Ojeql);
+		break;
+	case IBLEB:
+		cbrab(i, Ojlsl);
+		break;
+	case IBNEB:
+		cbrab(i, Ojnel);
+		break;
+	case IBGTB:
+		cbrab(i, Ojhil);
+		break;
+	case IBLTB:
+		cbrab(i, Ojbl);
+		break;
+	case IBGEB:
+		cbrab(i, Ojael);
+		break;
+	case ISUBW:
+		arith(i, 0x29, 5);
+		break;
+	case ISUBB:
+		arithb(i, 0x28);
+		break;
+	case ISUBF:
+		arithf(i, 5);
+		break;
+	case IADDW:
+		arith(i, 0x01, 0);
+		break;
+	case IADDB:
+		arithb(i, 0x00);
+		break;
+	case IADDF:
+		arithf(i, 0);
+		break;
+	case IORW:
+		arith(i, 0x09, 1);
+		break;
+	case IORB:
+		arithb(i, 0x08);
+		break;
+	case IANDW:
+		arith(i, 0x21, 4);
+		break;
+	case IANDB:
+		arithb(i, 0x20);
+		break;
+	case IXORW:
+		arith(i, Oxor, 6);
+		break;
+	case IXORB:
+		arithb(i, 0x30);
+		break;
+	case ISHLW:
+		shift(i, Oldw, Ostw, 0xd3, 4);
+		break;
+	case ISHLB:
+		shift(i, Oldb, Ostb, 0xd2, 4);
+		break;
+	case ISHRW:
+		shift(i, Oldw, Ostw, 0xd3, 7);
+		break;
+	case ISHRB:
+		shift(i, Oldb, Ostb, 0xd2, 5);
+		break;
+	case IMOVF:
+		opwld(i, Omovf, 0);
+		opwst(i, Omovf, 3);
+		break;
+	case INEGF:
+		opwld(i, Omovf, 0);
+		genb(0xd9);
+		genb(0xe0);
+		opwst(i, Omovf, 3);
+		break;
+	case IMOVB:
+		opwld(i, Oldb, RAX);
+		opwst(i, Ostb, RAX);
+		break;
+	case IMOVW:
+	case ICVTLW:			// Little endian
+		if(UXSRC(i->add) == SRC(AIMM)) {
+			opwst(i, Omov, RAX);
+			genw(i->s.imm);
+			break;
+		}
+		opwld(i, Oldw, RAX);
+		opwst(i, Ostw, RAX);
+		break;
+	case ICVTWL:
+		opwst(i, Olea, RTMP);
+		opwld(i, Oldw, RAX);
+		modrm(Ostw, 0, RTMP, RAX);
+		genb(0x99);
+		modrm(Ostw, 4, RTMP, RDX);
+		break;
+	case ICALL:
+		if(UXDST(i->add) != DST(AIMM))
+			opwst(i, Oldw, RTA);
+		opwld(i, Oldw, RAX);
+		modrm(Omov, O(Frame, lr), RAX, 0);	// MOVL $.+1, lr(AX)
+		genw((ulong)base+patch[i-mod->prog+1]);
+		modrm(Ostw, O(Frame, fp), RAX, RFP); 	// MOVL RFP, fp(AX)
+		gen2(Oldw, (3<<6)|(RFP<<3)|RAX);	// MOVL AX,RFP
+		if(UXDST(i->add) != DST(AIMM)){
+			gen2(Ojmprm, (3<<6)|(4<<3)|RTA);
+			break;
+		}
+		/* no break */
+	case IJMP:
+		if(RESCHED)
+			schedcheck(i);
+		rbra(patch[i->d.ins-mod->prog], Ojmp);
+		break;
+	case IMOVPC:
+		opwst(i, Omov, RAX);
+		genw(patch[i->s.imm]+(ulong)base);
+		break;
+	case IGOTO:
+		opwst(i, Olea, RBX);
+		opwld(i, Oldw, RAX);
+		gen2(Ojmprm, (0<<6)|(4<<3)|4);
+		genb((2<<6)|(RAX<<3)|RBX);
+
+		if(pass == 0)
+			break;
+
+		t = (WORD*)(mod->origmp+i->d.ind);
+		e = t + t[-1];
+		t[-1] = 0;
+		while(t < e) {
+			t[0] = (ulong)base + patch[t[0]];
+			t++;
+		}
+		break;
+	case IMULF:
+		arithf(i, 1);
+		break;
+	case IDIVF:
+		arithf(i, 7);
+		break;
+	case IMODW:
+	case IDIVW:
+	case IMULW:
+		mid(i, Oldw, RAX);
+		opwld(i, Oldw, RTMP);
+		if(i->op == IMULW)
+			gen2(0xf7, (3<<6)|(4<<3)|RTMP);
+		else {
+			genb(Ocdq);
+			gen2(0xf7, (3<<6)|(7<<3)|RTMP);	// IDIV AX, RTMP
+			if(i->op == IMODW)
+				genb(0x90+RDX);		// XCHG	AX, DX
+		}
+		opwst(i, Ostw, RAX);
+		break;
+	case IMODB:
+	case IDIVB:
+	case IMULB:
+		mid(i, Oldb, RAX);
+		opwld(i, Oldb, RTMP);
+		if(i->op == IMULB)
+			gen2(0xf6, (3<<6)|(4<<3)|RTMP);
+		else {
+			genb(Ocdq);
+			gen2(0xf6, (3<<6)|(7<<3)|RTMP);	// IDIV AX, RTMP
+			if(i->op == IMODB)
+				genb(0x90+RDX);		// XCHG	AX, DX
+		}
+		opwst(i, Ostb, RAX);
+		break;
+	case IINDX:
+		opwld(i, Oldw, RTMP);			// MOVW	xx(s), BX
+
+		if(bflag){
+			opwst(i, Oldw, RAX);
+			modrm(0x3b, O(Array, len), RTMP, RAX);	/* CMP index, len */
+			gen2(0x72, 5);		/* JB */
+			bra((ulong)bounds, Ocall);
+			modrm(Oldw, O(Array, t), RTMP, RTA);
+			modrm(0xf7, O(Type, size), RTA, 5);		/* IMULL AX, xx(t) */
+		}
+		else{
+			modrm(Oldw, O(Array, t), RTMP, RAX);	// MOVW	t(BX), AX
+			modrm(Oldw, O(Type, size), RAX, RAX);	// MOVW size(AX), AX
+			if(UXDST(i->add) == DST(AIMM)) {
+				gen2(0x69, (3<<6)|(RAX<<3)|0);
+				genw(i->d.imm);
+			}
+			else
+				opwst(i, 0xf7, 5);		// IMULL AX,xx(d)
+		}
+
+		modrm(0x03, O(Array, data), RBX, RAX);	// ADDL data(BX), AX
+		r = RMP;
+		if((i->add&ARM) == AXINF)
+			r = RFP;
+		modrm(Ostw, i->reg, r, RAX);
+		break;
+	case IINDB:
+		r = 0;
+		goto idx;
+	case IINDF:
+	case IINDL:
+		r = 3;
+		goto idx;
+	case IINDW:
+		r = 2;
+	idx:
+		opwld(i, Oldw, RAX);
+		opwst(i, Oldw, RTMP);
+		if(bflag){
+			modrm(0x3b, O(Array, len), RAX, RTMP);	/* CMP index, len */
+			gen2(0x72, 5);		/* JB */
+			bra((ulong)bounds, Ocall);
+		}
+		modrm(Oldw, O(Array, data), RAX, RAX);
+		gen2(Olea, (0<<6)|(0<<3)|4);		/* lea	(AX)(RTMP*r) */
+		genb((r<<6)|(RTMP<<3)|RAX);
+		r = RMP;
+		if((i->add&ARM) == AXINF)
+			r = RFP;
+		modrm(Ostw, i->reg, r, RAX);
+		break;
+	case IINDC:
+		opwld(i, Oldw, RAX);			// string
+		mid(i, Oldw, RBX);			// index
+		if(bflag){
+			modrm(Oldw, O(String, len), RAX, RTA);
+			cmpl(RTA, 0);
+			gen2(Ojltb, 16);
+			gen2(0x3b, (3<<6)|(RBX<<3)|RTA);	/* cmp index, len */
+			gen2(0x72, 5);		/* JB */
+			bra((ulong)bounds, Ocall);
+			genb(0x0f);
+			gen2(Omovzxb, (1<<6)|(0<<3)|4);
+			gen2((0<<6)|(RBX<<3)|RAX, O(String, data));
+			gen2(Ojmpb, sizeof(Rune)==4? 10: 11);
+			gen2(Oneg, (3<<6)|(3<<3)|RTA);
+			gen2(0x3b, (3<<6)|(RBX<<3)|RTA);	/* cmp index, len */
+			gen2(0x73, 0xee);		/* JNB */
+			if(sizeof(Rune) == 4){
+				gen2(Oldw, (1<<6)|(0<<3)|4);
+				gen2((2<<6)|(RBX<<3)|RAX, O(String, data));
+			}else{
+				genb(0x0f);
+				gen2(Omovzxw, (1<<6)|(0<<3)|4);
+				gen2((1<<6)|(RBX<<3)|RAX, O(String, data));
+			}
+			opwst(i, Ostw, RAX);
+			break;
+		}
+		modrm(Ocmpi, O(String, len), RAX, 7);
+		genb(0);
+		gen2(Ojltb, 7);
+		genb(0x0f);
+		gen2(Omovzxb, (1<<6)|(0<<3)|4);		/* movzbx 12(AX)(RBX*1), RAX */
+		gen2((0<<6)|(RBX<<3)|RAX, O(String, data));
+		if(sizeof(Rune) == 4){
+			gen2(Ojmpb, 4);
+			gen2(Oldw, (1<<6)|(0<<3)|4);		/* movl 12(AX)(RBX*4), RAX */
+			gen2((2<<6)|(RBX<<3)|RAX, O(String, data));
+		}else{
+			gen2(Ojmpb, 5);
+			genb(0x0f);
+			gen2(Omovzxw, (1<<6)|(0<<3)|4);		/* movzwx 12(AX)(RBX*2), RAX */
+			gen2((1<<6)|(RBX<<3)|RAX, O(String, data));
+		}
+		opwst(i, Ostw, RAX);
+		break;
+	case ICASE:
+		comcase(i, 1);
+		break;
+	case IMOVL:
+		opwld(i, Olea, RTA);
+		opwst(i, Olea, RTMP);
+		modrm(Oldw, 0, RTA, RAX);
+		modrm(Ostw, 0, RTMP, RAX);
+		modrm(Oldw, 4, RTA, RAX);
+		modrm(Ostw, 4, RTMP, RAX);
+		break;
+	case IADDL:
+		larith(i, 0x03, 0x13);
+		break;
+	case ISUBL:
+		larith(i, 0x2b, 0x1b);
+		break;
+	case IORL:
+		larith(i, 0x0b, 0x0b);
+		break;
+	case IANDL:
+		larith(i, 0x23, 0x23);
+		break;
+	case IXORL:
+		larith(i, 0x33, 0x33);
+		break;
+	case IBEQL:
+		cbral(i, Ojnel, Ojeql, ANDAND);
+		break;
+	case IBNEL:
+		cbral(i, Ojnel, Ojnel, OROR);
+		break;
+	case IBLEL:
+		cbral(i, Ojltl, Ojbel, EQAND);
+		break;
+	case IBGTL:
+		cbral(i, Ojgtl, Ojal, EQAND);
+		break;
+	case IBLTL:
+		cbral(i, Ojltl, Ojbl, EQAND);
+		break;
+	case IBGEL:
+		cbral(i, Ojgtl, Ojael, EQAND);
+		break;
+	case ISHLL:
+		shll(i);
+		break;
+	case ISHRL:
+		shrl(i);
+		break;
+	case IRAISE:
+		punt(i, SRCOP|WRTPC|NEWPC, optab[i->op]);
+		break;
+	case IMULX:
+	case IDIVX:
+	case ICVTXX:
+	case IMULX0:
+	case IDIVX0:
+	case ICVTXX0:
+	case IMULX1:
+	case IDIVX1:
+	case ICVTXX1:
+	case ICVTFX:
+	case ICVTXF:
+	case IEXPW:
+	case IEXPL:
+	case IEXPF:
+		punt(i, SRCOP|DSTOP|THREOP, optab[i->op]);
+		break;
+	case ISELF:
+		punt(i, DSTOP, optab[i->op]);
+		break;
+	}
+}
+
+static void
+preamble(void)
+{
+	if(comvec)
+		return;
+
+	comvec = malloc(32);
+	if(comvec == nil)
+		error(exNomem);
+	code = (uchar*)comvec;
+
+	genb(Opushl+RBX);
+	genb(Opushl+RCX);
+	genb(Opushl+RDX);
+	genb(Opushl+RSI);
+	genb(Opushl+RDI);
+	con((ulong)&R, RTMP);
+	modrm(Oldw, O(REG, FP), RTMP, RFP);
+	modrm(Oldw, O(REG, MP), RTMP, RMP);
+	modrm(Ojmprm, O(REG, PC), RTMP, 4);
+
+	segflush(comvec, 32);
+}
+
+static void
+maccase(void)
+{
+	uchar *loop, *def, *lab1;
+
+	modrm(Oldw, 0, RSI, RDX);		// n = t[0]
+	modrm(Olea, 4, RSI, RSI);		// t = &t[1]
+	gen2(Oldw, (3<<6)|(RBX<<3)|RDX);	// MOVL	DX, BX
+	gen2(Oshr, (3<<6)|(4<<3)|RBX);		// SHL	BX,1
+	gen2(0x01, (3<<6)|(RDX<<3)|RBX);	// ADDL	DX, BX	BX = n*3
+	gen2(Opushrm, (0<<6)|(6<<3)|4);
+	genb((2<<6)|(RBX<<3)|RSI);		// PUSHL 0(SI)(BX*4)
+	loop = code;
+	cmpl(RDX, 0);
+	gen2(Ojleb, 0);
+	def = code-1;
+	gen2(Oldw, (3<<6)|(RCX<<3)|RDX);	// MOVL	DX, CX	n2 = n
+	gen2(Oshr, (3<<6)|(5<<3)|RCX);		// SHR	CX,1	n2 = n2>>1
+	gen2(Oldw, (3<<6)|(RBX<<3)|RCX);	// MOVL	CX, BX
+	gen2(Oshr, (3<<6)|(4<<3)|RBX);		// SHL	BX,1
+	gen2(0x01, (3<<6)|(RCX<<3)|RBX);	// ADDL	CX, BX	BX = n2*3
+	gen2(0x3b, (0<<6)|(RAX<<3)|4);
+	genb((2<<6)|(RBX<<3)|RSI);		// CMPL AX, 0(SI)(BX*4)
+	gen2(Ojgeb, 0);				// JGE	lab1
+	lab1 = code-1;
+	gen2(Oldw, (3<<6)|(RDX<<3)|RCX);
+	gen2(Ojmpb, loop-code-2);
+	*lab1 = code-lab1-1;			// lab1:
+	gen2(0x3b, (1<<6)|(RAX<<3)|4);
+	gen2((2<<6)|(RBX<<3)|RSI, 4);		// CMPL AX, 4(SI)(BX*4)
+	gen2(Ojltb, 0);
+	lab1 = code-1;
+	gen2(Olea, (1<<6)|(RSI<<3)|4);
+	gen2((2<<6)|(RBX<<3)|RSI, 12);		// LEA	12(SI)(RBX*4), RSI
+	gen2(0x2b, (3<<6)|(RDX<<3)|RCX);	// SUBL	CX, DX		n -= n2
+	gen2(Odecrm, (3<<6)|(1<<3)|RDX);	// DECL	DX		n -= 1
+	gen2(Ojmpb, loop-code-2);
+	*lab1 = code-lab1-1;			// lab1:
+	gen2(Oldw, (1<<6)|(RAX<<3)|4);
+	gen2((2<<6)|(RBX<<3)|RSI, 8);		// MOVL 8(SI)(BX*4), AX
+	genb(Opopl+RSI);			// ditch default
+	genb(Opopl+RSI);
+	gen2(Ojmprm, (3<<6)|(4<<3)|RAX);	// JMP*L AX
+	*def = code-def-1;			// def:
+	genb(Opopl+RAX);			// ditch default
+	genb(Opopl+RSI);
+	gen2(Ojmprm, (3<<6)|(4<<3)|RAX);
+}
+
+static void
+macfrp(void)
+{
+	cmpl(RAX, (ulong)H);			// CMPL AX, $H
+	gen2(Ojneb, 0x01);			// JNE	.+1
+	genb(Oret);				// RET
+	modrm(0x83, O(Heap, ref)-sizeof(Heap), RAX, 7);
+	genb(0x01);				// CMP	AX.ref, $1
+	gen2(Ojeqb, 0x04);			// JNE	.+4
+	modrm(Odecrm, O(Heap, ref)-sizeof(Heap), RAX, 1);
+	genb(Oret);				// DEC	AX.ref
+						// RET
+	con((ulong)&R, RTMP);			// MOV  $R, RTMP
+	modrm(Ostw, O(REG, FP), RTMP, RFP);	// MOVL	RFP, R.FP
+	modrm(Ostw, O(REG, s), RTMP, RAX);	// MOVL	RAX, R.s
+	bra((ulong)rdestroy, Ocall);		// CALL rdestroy
+	con((ulong)&R, RTMP);			// MOVL	$R, RTMP
+	modrm(Oldw, O(REG, FP), RTMP, RFP);	// MOVL	R.MP, RMP
+	modrm(Oldw, O(REG, MP), RTMP, RMP);	// MOVL R.FP, RFP
+	genb(Oret);
+}
+
+static void
+macret(void)
+{
+	Inst i;
+	uchar *s;
+	static ulong lpunt, lnomr, lfrmr, linterp;
+
+	s = code;
+
+	lpunt -= 2;
+	lnomr -= 2;
+	lfrmr -= 2;
+	linterp -= 2;
+
+	con(0, RBX);				// MOVL  $0, RBX
+	modrm(Oldw, O(Frame, t), RFP, RAX);	// MOVL  t(FP), RAX
+	gen2(Ocmpw, (3<<6)|(RAX<<3)|RBX);	// CMPL  RAX, RBX
+	gen2(Ojeqb, lpunt-(code-s));		// JEQ	 lpunt
+	modrm(Oldw, O(Type, destroy), RAX, RAX);// MOVL  destroy(RAX), RAX
+	gen2(Ocmpw, (3<<6)|(RAX<<3)|RBX);	// CMPL	 RAX, RBX
+	gen2(Ojeqb, lpunt-(code-s));		// JEQ	 lpunt
+	modrm(Ocmpw, O(Frame, fp), RFP, RBX);	// CMPL	 fp(FP), RBX
+	gen2(Ojeqb, lpunt-(code-s));		// JEQ	 lpunt
+	modrm(Ocmpw, O(Frame, mr), RFP, RBX);	// CMPL	 mr(FP), RBX
+	gen2(Ojeqb, lnomr-(code-s));		// JEQ	 lnomr
+	con((ulong)&R, RTMP);			// MOVL	 $R, RTMP
+	modrm(Oldw, O(REG, M), RTMP, RTA);	// MOVL	 R.M, RTA
+	modrm(Odecrm, O(Heap, ref)-sizeof(Heap), RTA, 1);
+	gen2(Ojneb, lfrmr-(code-s));		// JNE	 lfrmr
+	modrm(Oincrm, O(Heap, ref)-sizeof(Heap), RTA, 0);
+	gen2(Ojmpb, lpunt-(code-s));		// JMP	 lpunt
+	lfrmr = code - s;
+	modrm(Oldw, O(Frame, mr), RFP, RTA);	// MOVL	 mr(FP), RTA
+	modrm(Ostw, O(REG, M), RTMP, RTA);	// MOVL	 RTA, R.M
+	modrm(Oldw, O(Modlink, MP), RTA, RMP);	// MOVL	 MP(RTA), RMP
+	modrm(Ostw, O(REG, MP), RTMP, RMP);	// MOVL	 RMP, R.MP
+	modrm(Ocmpi, O(Modlink, compiled), RTA, 7);// CMPL $0, M.compiled
+	genb(0x00);
+	gen2(Ojeqb, linterp-(code-s));		// JEQ	linterp
+	lnomr = code - s;
+	gen2(Ocallrm, (3<<6)|(2<<3)|RAX);	// CALL* AX
+	con((ulong)&R, RTMP);			// MOVL	 $R, RTMP
+	modrm(Ostw, O(REG, SP), RTMP, RFP);	// MOVL  RFP, R.SP
+	modrm(Oldw, O(Frame, lr), RFP, RAX);	// MOVL  lr(RFP), RAX
+	modrm(Oldw, O(Frame, fp), RFP, RFP);	// MOVL  fp(RFP), RFP
+	modrm(Ostw, O(REG, FP), RTMP, RFP);	// MOVL  RFP, R.FP
+	gen2(Ojmprm, (3<<6)|(4<<3)|RAX);	// JMP*L AX
+
+	linterp = code - s;			// return to uncompiled code
+	gen2(Ocallrm, (3<<6)|(2<<3)|RAX);	// CALL* AX
+	con((ulong)&R, RTMP);			// MOVL	 $R, RTMP
+	modrm(Ostw, O(REG, SP), RTMP, RFP);	// MOVL  RFP, R.SP
+	modrm(Oldw, O(Frame, lr), RFP, RAX);	// MOVL  lr(RFP), RAX
+	modrm(Ostw, O(REG, PC), RTMP, RAX);	// MOVL  RAX, R.PC
+	modrm(Oldw, O(Frame, fp), RFP, RFP);	// MOVL  fp(RFP), RFP
+	modrm(Ostw, O(REG, FP), RTMP, RFP);	// MOVL  RFP, R.FP
+	genb(Opopl+RDI);			// return to uncompiled code
+	genb(Opopl+RSI);
+	genb(Opopl+RDX);
+	genb(Opopl+RCX);
+	genb(Opopl+RBX);
+	genb(Oret);
+						// label:
+	lpunt = code - s;
+
+	i.add = AXNON;
+	punt(&i, TCHECK|NEWPC, optab[IRET]);
+}
+
+static void
+maccolr(void)
+{
+	modrm(Oincrm, O(Heap, ref)-sizeof(Heap), RBX, 0);
+	gen2(Oldw, (0<<6)|(RAX<<3)|5);		// INCL	ref(BX)
+	genw((ulong)&mutator);			// MOVL	mutator, RAX
+	modrm(Ocmpw, O(Heap, color)-sizeof(Heap), RBX, RAX);
+	gen2(Ojneb, 0x01);			// CMPL	color(BX), RAX
+	genb(Oret);				// MOVL $propagator,RTMP
+	con(propagator, RAX);			// MOVL	RTMP, color(BX)
+	modrm(Ostw, O(Heap, color)-sizeof(Heap), RBX, RAX);
+	gen2(Ostw, (0<<6)|(RAX<<3)|5);		// can be any !0 value
+	genw((ulong)&nprop);			// MOVL	RBX, nprop
+	genb(Oret);
+}
+
+static void
+macmcal(void)
+{
+	uchar *label, *mlnil, *interp;
+
+	cmpl(RAX, (ulong)H);
+	gen2(Ojeqb, 0);
+	mlnil = code - 1;
+	modrm(0x83, O(Modlink, prog), RTA, 7);	// CMPL $0, ml->prog
+	genb(0x00);
+	gen2(Ojneb, 0);				// JNE	patch
+	label = code-1;
+	*mlnil = code-mlnil-1;
+	modrm(Ostw, O(REG, FP), RTMP, RCX);
+	modrm(Ostw, O(REG, dt), RTMP, RAX);
+	bra((ulong)rmcall, Ocall);		// CALL rmcall
+	con((ulong)&R, RTMP);			// MOVL	$R, RTMP
+	modrm(Oldw, O(REG, FP), RTMP, RFP);
+	modrm(Oldw, O(REG, MP), RTMP, RMP);
+	genb(Oret);				// RET
+	*label = code-label-1;			// patch:
+	gen2(Oldw, (3<<6)|(RFP<<3)|RCX);	// MOVL CX, RFP		R.FP = f
+	modrm(Ostw, O(REG, M), RTMP, RTA);	// MOVL RTA, R.M
+	modrm(Oincrm, O(Heap, ref)-sizeof(Heap), RTA, 0);
+	modrm(Oldw, O(Modlink, MP), RTA, RMP);	// MOVL R.M->mp, RMP
+	modrm(Ostw, O(REG, MP), RTMP, RMP);	// MOVL RMP, R.MP	R.MP = ml->MP
+	modrm(Ocmpi, O(Modlink, compiled), RTA, 7);// CMPL $0, M.compiled
+	genb(0x00);
+	genb(Opopl+RTA);			// balance call
+	gen2(Ojeqb, 0);				// JEQ	interp
+	interp = code-1;
+	gen2(Ojmprm, (3<<6)|(4<<3)|RAX);	// JMP*L AX
+	*interp = code-interp-1;		// interp:
+	modrm(Ostw, O(REG, FP), RTMP, RFP);	// MOVL FP, R.FP
+	modrm(Ostw, O(REG, PC), RTMP, RAX);	// MOVL PC, R.PC
+	genb(Opopl+RDI);			// call to uncompiled code
+	genb(Opopl+RSI);
+	genb(Opopl+RDX);
+	genb(Opopl+RCX);
+	genb(Opopl+RBX);
+	genb(Oret);
+}
+
+static void
+macfram(void)
+{
+	uchar *label;
+
+	con((ulong)&R, RTMP);			// MOVL	$R, RTMP
+	modrm(Oldw, O(REG, SP), RTMP, RAX);	// MOVL	R.SP, AX
+	modrm(0x03, O(Type, size), RTA, RAX);	// ADDL size(RCX), RAX
+	modrm(0x3b, O(REG, TS), RTMP, RAX);	// CMPL	AX, R.TS
+	gen2(0x7c, 0x00);			// JL	.+(patch)
+	label = code-1;
+
+	modrm(Ostw, O(REG, s), RTMP, RTA);
+	modrm(Ostw, O(REG, FP), RTMP, RFP);	// MOVL	RFP, R.FP
+	bra((ulong)extend, Ocall);		// CALL	extend
+	con((ulong)&R, RTMP);
+	modrm(Oldw, O(REG, FP), RTMP, RFP);	// MOVL	R.MP, RMP
+	modrm(Oldw, O(REG, MP), RTMP, RMP);	// MOVL R.FP, RFP
+	modrm(Oldw, O(REG, s), RTMP, RCX);	// MOVL	R.s, *R.d
+	genb(Oret);				// RET
+	*label = code-label-1;
+	modrm(Oldw, O(REG, SP), RTMP, RCX);	// MOVL	R.SP, CX
+	modrm(Ostw, O(REG, SP), RTMP, RAX);	// MOVL	AX, R.SP
+
+	modrm(Ostw, O(Frame, t), RCX, RTA);	// MOVL	RTA, t(CX) f->t = t
+	modrm(Omov, REGMOD*4, RCX, 0);     	// MOVL $0, mr(CX) f->mr
+	genw(0);
+	modrm(Oldw, O(Type, initialize), RTA, RTA);
+	gen2(Ojmprm, (3<<6)|(4<<3)|RTA);	// JMP*L RTA
+	genb(Oret);				// RET
+}
+
+static void
+macmfra(void)
+{
+	con((ulong)&R, RTMP);			// MOVL	$R, RTMP
+	modrm(Ostw, O(REG, FP), RTMP, RFP);
+	modrm(Ostw, O(REG, s), RTMP, RAX);	// Save type
+	modrm(Ostw, O(REG, d), RTMP, RTA);	// Save destination
+	bra((ulong)rmfram, Ocall);		// CALL rmfram
+	con((ulong)&R, RTMP);			// MOVL	$R, RTMP
+	modrm(Oldw, O(REG, FP), RTMP, RFP);
+	modrm(Oldw, O(REG, MP), RTMP, RMP);
+	genb(Oret);				// RET
+}
+
+static void
+macrelq(void)
+{
+	modrm(Ostw, O(REG, FP), RTMP, RFP);	// MOVL FP, R.FP
+	genb(Opopl+RAX);
+	modrm(Ostw, O(REG, PC), RTMP, RAX);	// MOVL PC, R.PC
+	genb(Opopl+RDI);
+	genb(Opopl+RSI);
+	genb(Opopl+RDX);
+	genb(Opopl+RCX);
+	genb(Opopl+RBX);
+	genb(Oret);
+}
+
+void
+comd(Type *t)
+{
+	int i, j, m, c;
+
+	for(i = 0; i < t->np; i++) {
+		c = t->map[i];
+		j = i<<5;
+		for(m = 0x80; m != 0; m >>= 1) {
+			if(c & m) {
+				modrm(Oldw, j, RFP, RAX);
+				rbra(macro[MacFRP], Ocall);
+			}
+			j += sizeof(WORD*);
+		}
+	}
+	genb(Oret);
+}
+
+void
+comi(Type *t)
+{
+	int i, j, m, c;
+
+	con((ulong)H, RAX);
+	for(i = 0; i < t->np; i++) {
+		c = t->map[i];
+		j = i<<5;
+		for(m = 0x80; m != 0; m >>= 1) {
+			if(c & m)
+				modrm(Ostw, j, RCX, RAX);
+			j += sizeof(WORD*);
+		}
+	}
+	genb(Oret);
+}
+
+void
+typecom(Type *t)
+{
+	int n;
+	uchar *tmp;
+
+	if(t == nil || t->initialize != 0)
+		return;
+
+	tmp = mallocz(4096*sizeof(uchar), 0);
+	if(tmp == nil)
+		error(exNomem);
+
+	code = tmp;
+	comi(t);
+	n = code - tmp;
+	code = tmp;
+	comd(t);
+	n += code - tmp;
+	free(tmp);
+
+	code = mallocz(n, 0);
+	if(code == nil)
+		return;
+
+	t->initialize = code;
+	comi(t);
+	t->destroy = code;
+	comd(t);
+
+	if(cflag > 3)
+		print("typ= %.8lux %4d i %.8lux d %.8lux asm=%d\n",
+			(ulong)t, t->size, (ulong)t->initialize, (ulong)t->destroy, n);
+
+	segflush(t->initialize, n);
+}
+
+static void
+patchex(Module *m, ulong *p)
+{
+	Handler *h;
+	Except *e;
+
+	if((h = m->htab) == nil)
+		return;
+	for( ; h->etab != nil; h++){
+		h->pc1 = p[h->pc1];
+		h->pc2 = p[h->pc2];
+		for(e = h->etab; e->s != nil; e++)
+			e->pc = p[e->pc];
+		if(e->pc != -1)
+			e->pc = p[e->pc];
+	}
+}
+
+int
+compile(Module *m, int size, Modlink *ml)
+{
+	ulong v;
+	Modl *e;
+	Link *l;
+	int i, n;
+	uchar *s, *tmp;
+
+	base = nil;
+	patch = mallocz(size*sizeof(*patch), 0);
+	tinit = malloc(m->ntype*sizeof(*tinit));
+	tmp = mallocz(4096*sizeof(uchar),0);
+	if(tinit == nil || patch == nil || tmp == nil)
+		goto bad;
+
+	preamble();
+
+	mod = m;
+	n = 0;
+	pass = 0;
+	nlit = 0;
+
+	for(i = 0; i < size; i++) {
+		code = tmp;
+		comp(&m->prog[i]);
+		patch[i] = n;
+		n += code - tmp;
+	}
+
+	for(i = 0; i < nelem(mactab); i++) {
+		code = tmp;
+		mactab[i].gen();
+		macro[mactab[i].idx] = n;
+		n += code - tmp;
+	}
+
+	n = (n+3)&~3;
+
+	nlit *= sizeof(ulong);
+	base = mallocz(n + nlit, 0);
+	if(base == nil)
+		goto bad;
+
+	if(cflag > 3)
+		print("dis=%5d %5d 386=%5d asm=%.8lux lit=%d: %s\n",
+			size, size*sizeof(Inst), n, (ulong)base, nlit, m->name);
+
+	pass++;
+	nlit = 0;
+	litpool = (ulong*)(base+n);
+	code = base;
+
+	for(i = 0; i < size; i++) {
+		s = code;
+		comp(&m->prog[i]);
+		if(cflag > 4) {
+			print("%D\n", &m->prog[i]);
+			das(s, code-s);
+		}
+	}
+
+	for(i = 0; i < nelem(mactab); i++)
+		mactab[i].gen();
+
+	v = (ulong)base;
+	for(l = m->ext; l->name; l++) {
+		l->u.pc = (Inst*)(v+patch[l->u.pc-m->prog]);
+		typecom(l->frame);
+	}
+	if(ml != nil) {
+		e = &ml->links[0];
+		for(i = 0; i < ml->nlinks; i++) {
+			e->u.pc = (Inst*)(v+patch[e->u.pc-m->prog]);
+			typecom(e->frame);
+			e++;
+		}
+	}
+	for(i = 0; i < m->ntype; i++) {
+		if(tinit[i] != 0)
+			typecom(m->type[i]);
+	}
+	patchex(m, patch);
+	m->entry = (Inst*)(v+patch[mod->entry-mod->prog]);
+	free(patch);
+	free(tinit);
+	free(tmp);
+	free(m->prog);
+	m->prog = (Inst*)base;
+	m->compiled = 1;
+	segflush(base, n*sizeof(base));
+	return 1;
+bad:
+	free(patch);
+	free(tinit);
+	free(tmp);
+	free(base);
+	return 0;
+}
+
--- /dev/null
+++ b/libinterp/das-amd64.c
@@ -1,0 +1,1630 @@
+#include <lib9.h>
+#include <kernel.h>
+
+int	i386inst(ulong, char, char*, int);
+int	i386das(ulong, char*, int);
+int	i386instlen(ulong);
+
+static uchar *dasdata;
+
+static char *
+_hexify(char *buf, ulong p, int zeros)
+{
+	ulong d;
+
+	d = p/16;
+	if(d)
+		buf = _hexify(buf, d, zeros-1);
+	else
+		while(zeros--)
+			*buf++ = '0';
+	*buf++ = "0123456789abcdef"[p&0x0f];
+	return buf;
+}
+
+/*
+ *  an instruction
+ */
+typedef struct Instr Instr;
+struct	Instr
+{
+	uchar	mem[1+1+1+1+2+1+1+4+4];		/* raw instruction */
+	ulong	addr;		/* address of start of instruction */
+	int	n;		/* number of bytes in instruction */
+	char	*prefix;	/* instr prefix */
+	char	*segment;	/* segment override */
+	uchar	jumptype;	/* set to the operand type for jump/ret/call */
+	char	osize;		/* 'W' or 'L' */
+	char	asize;		/* address size 'W' or 'L' */
+	uchar	mod;		/* bits 6-7 of mod r/m field */
+	uchar	reg;		/* bits 3-5 of mod r/m field */
+	char	ss;		/* bits 6-7 of SIB */
+	char	index;		/* bits 3-5 of SIB */
+	char	base;		/* bits 0-2 of SIB */
+	short	seg;		/* segment of far address */
+	ulong	disp;		/* displacement */
+	ulong 	imm;		/* immediate */
+	ulong 	imm2;		/* second immediate operand */
+	char	*curr;		/* fill level in output buffer */
+	char	*end;		/* end of output buffer */
+	char	*err;		/* error message */
+};
+
+	/* 386 register (ha!) set */
+enum{
+	AX=0,
+	CX,
+	DX,
+	BX,
+	SP,
+	BP,
+	SI,
+	DI,
+};
+	/* Operand Format codes */
+/*
+%A	-	address size register modifier (!asize -> 'E')
+%C	-	Control register CR0/CR1/CR2
+%D	-	Debug register DR0/DR1/DR2/DR3/DR6/DR7
+%I	-	second immediate operand
+%O	-	Operand size register modifier (!osize -> 'E')
+%T	-	Test register TR6/TR7
+%S	-	size code ('W' or 'L')
+%X	-	Weird opcode: OSIZE == 'W' => "CBW"; else => "CWDE"
+%d	-	displacement 16-32 bits
+%e	-	effective address - Mod R/M value
+%f	-	floating point register F0-F7 - from Mod R/M register
+%g	-	segment register
+%i	-	immediate operand 8-32 bits
+%p	-	PC-relative - signed displacement in immediate field
+%r	-	Reg from Mod R/M
+%x	-	Weird opcode: OSIZE == 'W' => "CWD"; else => "CDQ"
+*/
+
+typedef struct Optable Optable;
+struct Optable
+{
+	char	operand[2];
+	void	*proto;		/* actually either (char*) or (Optable*) */
+};
+	/* Operand decoding codes */
+enum {
+	Ib = 1,			/* 8-bit immediate - (no sign extension)*/
+	Ibs,			/* 8-bit immediate (sign extended) */
+	Jbs,			/* 8-bit sign-extended immediate in jump or call */
+	Iw,			/* 16-bit immediate -> imm */
+	Iw2,			/* 16-bit immediate -> imm2 */
+	Iwd,			/* Operand-sized immediate (no sign extension)*/
+	Awd,			/* Address offset */
+	Iwds,			/* Operand-sized immediate (sign extended) */
+	RM,			/* Word or long R/M field with register (/r) */
+	RMB,			/* Byte R/M field with register (/r) */
+	RMOP,			/* Word or long R/M field with op code (/digit) */
+	RMOPB,			/* Byte R/M field with op code (/digit) */
+	RMR,			/* R/M register only (mod = 11) */
+	RMM,			/* R/M memory only (mod = 0/1/2) */
+	R0,			/* Base reg of Mod R/M is literal 0x00 */
+	R1,			/* Base reg of Mod R/M is literal 0x01 */
+	FRMOP,			/* Floating point R/M field with opcode */
+	FRMEX,			/* Extended floating point R/M field with opcode */
+	JUMP,			/* Jump or Call flag - no operand */
+	RET,			/* Return flag - no operand */
+	OA,			/* literal 0x0a byte */
+	PTR,			/* Seg:Displacement addr (ptr16:16 or ptr16:32) */
+	AUX,			/* Multi-byte op code - Auxiliary table */
+	PRE,			/* Instr Prefix */
+	SEG,			/* Segment Prefix */
+	OPOVER,			/* Operand size override */
+	ADDOVER,		/* Address size override */
+};
+	
+static Optable optab0F00[8]=
+{
+	0,0,		"MOVW	LDT,%e",
+	0,0,		"MOVW	TR,%e",
+	0,0,		"MOVW	%e,LDT",
+	0,0,		"MOVW	%e,TR",
+	0,0,		"VERR	%e",
+	0,0,		"VERW	%e",
+};
+
+static Optable optab0F01[8]=
+{
+	0,0,		"MOVL	GDTR,%e",
+	0,0,		"MOVL	IDTR,%e",
+	0,0,		"MOVL	%e,GDTR",
+	0,0,		"MOVL	%e,IDTR",
+	0,0,		"MOVW	MSW,%e",	/* word */
+	0,0,		nil,
+	0,0,		"MOVW	%e,MSW",	/* word */
+};
+
+static Optable optab0FBA[8]=
+{
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	Ib,0,		"BT%S	%i,%e",
+	Ib,0,		"BTS%S	%i,%e",
+	Ib,0,		"BTR%S	%i,%e",
+	Ib,0,		"BTC%S	%i,%e",
+};
+
+static Optable optab0F[256]=
+{
+	RMOP,0,		optab0F00,
+	RMOP,0,		optab0F01,
+	RM,0,		"LAR	%e,%r",
+	RM,0,		"LSL	%e,%r",
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		"CLTS",
+	0,0,		nil,
+	0,0,		"INVD",
+	0,0,		"WBINVD",
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+
+	RMR,0,		"MOVL	%C,%e",		/* [0x20] */
+	RMR,0,		"MOVL	%D,%e",
+	RMR,0,		"MOVL	%e,%C",
+	RMR,0,		"MOVL	%e,%D",
+	RMR,0,		"MOVL	%T,%e",
+	0,0,		nil,
+	RMR,0,		"MOVL	%e,%T",
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+
+	0,0,		"WRMSR",		/* [0x30] */
+	0,0,		"RDTSC",
+	0,0,		"RDMSR",
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+
+	Iwds,0,		"JOS	%p",	/* [0x80] */
+	Iwds,0,		"JOC	%p",
+	Iwds,0,		"JCS	%p",
+	Iwds,0,		"JCC	%p",
+	Iwds,0,		"JEQ	%p",
+	Iwds,0,		"JNE	%p",
+	Iwds,0,		"JLS	%p",
+	Iwds,0,		"JHI	%p",
+	Iwds,0,		"JMI	%p",
+	Iwds,0,		"JPL	%p",
+	Iwds,0,		"JPS	%p",
+	Iwds,0,		"JPC	%p",
+	Iwds,0,		"JLT	%p",
+	Iwds,0,		"JGE	%p",
+	Iwds,0,		"JLE	%p",
+	Iwds,0,		"JGT	%p",
+
+	RMB,0,		"SETOS	%e",	/* [0x90] */
+	RMB,0,		"SETOC	%e",
+	RMB,0,		"SETCS	%e",
+	RMB,0,		"SETCC	%e",
+	RMB,0,		"SETEQ	%e",
+	RMB,0,		"SETNE	%e",
+	RMB,0,		"SETLS	%e",
+	RMB,0,		"SETHI	%e",
+	RMB,0,		"SETMI	%e",
+	RMB,0,		"SETPL	%e",
+	RMB,0,		"SETPS	%e",
+	RMB,0,		"SETPC	%e",
+	RMB,0,		"SETLT	%e",
+	RMB,0,		"SETGE	%e",
+	RMB,0,		"SETLE	%e",
+	RMB,0,		"SETGT	%e",
+
+	0,0,		"PUSHL	FS",	/* [0xa0] */
+	0,0,		"POPL	FS",
+	0,0,		"CPUID",
+	RM,0,		"BT%S	%r,%e",
+	RM,Ib,		"SHLD%S	%r,%i,%e",
+	RM,0,		"SHLD%S	%r,CL,%e",
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		"PUSHL	GS",
+	0,0,		"POPL	GS",
+	0,0,		nil,
+	RM,0,		"BTS%S	%r,%e",
+	RM,Ib,		"SHRD%S	%r,%i,%e",
+	RM,0,		"SHRD%S	%r,CL,%e",
+	0,0,		nil,
+	RM,0,		"IMUL%S	%e,%r",
+
+	0,0,		nil,
+	0,0,		nil,
+	RMM,0,		"LSS	%e,%r",	/* [0xb2] */
+	RM,0,		"BTR%S	%r,%e",
+	RMM,0,		"LFS	%e,%r",
+	RMM,0,		"LGS	%e,%r",
+	RMB,0,		"MOVBZX	%e,%R",
+	RM,0,		"MOVWZX	%e,%R",
+	0,0,		nil,
+	0,0,		nil,
+	RMOP,0,		optab0FBA,
+	RM,0,		"BTC%S	%e,%r",
+	RM,0,		"BSF%S	%e,%r",
+	RM,0,		"BSR%S	%e,%r",
+	RMB,0,		"MOVBSX	%e,%R",
+	RM,0,		"MOVWSX	%e,%R",
+};
+
+static Optable optab80[8]=
+{
+	Ib,0,		"ADDB	%i,%e",
+	Ib,0,		"ORB	%i,%e",
+	Ib,0,		"ADCB	%i,%e",
+	Ib,0,		"SBBB	%i,%e",
+	Ib,0,		"ANDB	%i,%e",
+	Ib,0,		"SUBB	%i,%e",
+	Ib,0,		"XORB	%i,%e",
+	Ib,0,		"CMPB	%e,%i",
+};
+
+static Optable optab81[8]=
+{
+	Iwd,0,		"ADD%S	%i,%e",
+	Iwd,0,		"OR%S	%i,%e",
+	Iwd,0,		"ADC%S	%i,%e",
+	Iwd,0,		"SBB%S	%i,%e",
+	Iwd,0,		"AND%S	%i,%e",
+	Iwd,0,		"SUB%S	%i,%e",
+	Iwd,0,		"XOR%S	%i,%e",
+	Iwd,0,		"CMP%S	%e,%i",
+};
+
+static Optable optab83[8]=
+{
+	Ibs,0,		"ADD%S	%i,%e",
+	Ibs,0,		"OR%S	%i,%e",
+	Ibs,0,		"ADC%S	%i,%e",
+	Ibs,0,		"SBB%S	%i,%e",
+	Ibs,0,		"AND%S	%i,%e",
+	Ibs,0,		"SUB%S	%i,%e",
+	Ibs,0,		"XOR%S	%i,%e",
+	Ibs,0,		"CMP%S	%e,%i",
+};
+
+static Optable optabC0[8] =
+{
+	Ib,0,		"ROLB	%i,%e",
+	Ib,0,		"RORB	%i,%e",
+	Ib,0,		"RCLB	%i,%e",
+	Ib,0,		"RCRB	%i,%e",
+	Ib,0,		"SHLB	%i,%e",
+	Ib,0,		"SHRB	%i,%e",
+	0,0,		nil,
+	Ib,0,		"SARB	%i,%e",
+};
+
+static Optable optabC1[8] =
+{
+	Ib,0,		"ROL%S	%i,%e",
+	Ib,0,		"ROR%S	%i,%e",
+	Ib,0,		"RCL%S	%i,%e",
+	Ib,0,		"RCR%S	%i,%e",
+	Ib,0,		"SHL%S	%i,%e",
+	Ib,0,		"SHR%S	%i,%e",
+	0,0,		nil,
+	Ib,0,		"SAR%S	%i,%e",
+};
+
+static Optable optabD0[8] =
+{
+	0,0,		"ROLB	%e",
+	0,0,		"RORB	%e",
+	0,0,		"RCLB	%e",
+	0,0,		"RCRB	%e",
+	0,0,		"SHLB	%e",
+	0,0,		"SHRB	%e",
+	0,0,		nil,
+	0,0,		"SARB	%e",
+};
+
+static Optable optabD1[8] =
+{
+	0,0,		"ROL%S	%e",
+	0,0,		"ROR%S	%e",
+	0,0,		"RCL%S	%e",
+	0,0,		"RCR%S	%e",
+	0,0,		"SHL%S	%e",
+	0,0,		"SHR%S	%e",
+	0,0,		nil,
+	0,0,		"SAR%S	%e",
+};
+
+static Optable optabD2[8] =
+{
+	0,0,		"ROLB	CL,%e",
+	0,0,		"RORB	CL,%e",
+	0,0,		"RCLB	CL,%e",
+	0,0,		"RCRB	CL,%e",
+	0,0,		"SHLB	CL,%e",
+	0,0,		"SHRB	CL,%e",
+	0,0,		nil,
+	0,0,		"SARB	CL,%e",
+};
+
+static Optable optabD3[8] =
+{
+	0,0,		"ROL%S	CL,%e",
+	0,0,		"ROR%S	CL,%e",
+	0,0,		"RCL%S	CL,%e",
+	0,0,		"RCR%S	CL,%e",
+	0,0,		"SHL%S	CL,%e",
+	0,0,		"SHR%S	CL,%e",
+	0,0,		nil,
+	0,0,		"SAR%S	CL,%e",
+};
+
+static Optable optabD8[8+8] =
+{
+	0,0,		"FADDF	%e,F0",
+	0,0,		"FMULF	%e,F0",
+	0,0,		"FCOMF	%e,F0",
+	0,0,		"FCOMFP	%e,F0",
+	0,0,		"FSUBF	%e,F0",
+	0,0,		"FSUBRF	%e,F0",
+	0,0,		"FDIVF	%e,F0",
+	0,0,		"FDIVRF	%e,F0",
+	0,0,		"FADDD	%f,F0",
+	0,0,		"FMULD	%f,F0",
+	0,0,		"FCOMD	%f,F0",
+	0,0,		"FCOMPD	%f,F0",
+	0,0,		"FSUBD	%f,F0",
+	0,0,		"FSUBRD	%f,F0",
+	0,0,		"FDIVD	%f,F0",
+	0,0,		"FDIVRD	%f,F0",
+};
+/*
+ *	optabD9 and optabDB use the following encoding: 
+ *	if (0 <= modrm <= 2) instruction = optabDx[modrm&0x07];
+ *	else instruction = optabDx[(modrm&0x3f)+8];
+ *
+ *	the instructions for MOD == 3, follow the 8 instructions
+ *	for the other MOD values stored at the front of the table.
+ */
+static Optable optabD9[64+8] =
+{
+	0,0,		"FMOVF	%e,F0",
+	0,0,		nil,
+	0,0,		"FMOVF	F0,%e",
+	0,0,		"FMOVFP	F0,%e",
+	0,0,		"FLDENV%S %e",
+	0,0,		"FLDCW	%e",
+	0,0,		"FSTENV%S %e",
+	0,0,		"FSTCW	%e",
+	0,0,		"FMOVD	F0,F0",		/* Mod R/M = 11xx xxxx*/
+	0,0,		"FMOVD	F1,F0",
+	0,0,		"FMOVD	F2,F0",
+	0,0,		"FMOVD	F3,F0",
+	0,0,		"FMOVD	F4,F0",
+	0,0,		"FMOVD	F5,F0",
+	0,0,		"FMOVD	F6,F0",
+	0,0,		"FMOVD	F7,F0",
+	0,0,		"FXCHD	F0,F0",
+	0,0,		"FXCHD	F1,F0",
+	0,0,		"FXCHD	F2,F0",
+	0,0,		"FXCHD	F3,F0",
+	0,0,		"FXCHD	F4,F0",
+	0,0,		"FXCHD	F5,F0",
+	0,0,		"FXCHD	F6,F0",
+	0,0,		"FXCHD	F7,F0",
+	0,0,		"FNOP",
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		"FCHS",		/* [0x28] */
+	0,0,		"FABS",
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		"FTST",
+	0,0,		"FXAM",
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		"FLD1",
+	0,0,		"FLDL2T",
+	0,0,		"FLDL2E",
+	0,0,		"FLDPI",
+	0,0,		"FLDLG2",
+	0,0,		"FLDLN2",
+	0,0,		"FLDZ",
+	0,0,		nil,
+	0,0,		"F2XM1",
+	0,0,		"FYL2X",
+	0,0,		"FPTAN",
+	0,0,		"FPATAN",
+	0,0,		"FXTRACT",
+	0,0,		"FPREM1",
+	0,0,		"FDECSTP",
+	0,0,		"FNCSTP",
+	0,0,		"FPREM",
+	0,0,		"FYL2XP1",
+	0,0,		"FSQRT",
+	0,0,		"FSINCOS",
+	0,0,		"FRNDINT",
+	0,0,		"FSCALE",
+	0,0,		"FSIN",
+	0,0,		"FCOS",
+};
+
+static Optable optabDA[8+8] =
+{
+	0,0,		"FADDL	%e,F0",
+	0,0,		"FMULL	%e,F0",
+	0,0,		"FCOML	%e,F0",
+	0,0,		"FCOMLP	%e,F0",
+	0,0,		"FSUBL	%e,F0",
+	0,0,		"FSUBRL	%e,F0",
+	0,0,		"FDIVL	%e,F0",
+	0,0,		"FDIVRL	%e,F0",
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	R1,0,		"FUCOMPP",	/* [0x0d] */
+};
+
+static Optable optabDB[8+64] =
+{
+	0,0,		"FMOVL	%e,F0",
+	0,0,		nil,
+	0,0,		"FMOVL	F0,%e",
+	0,0,		"FMOVLP	F0,%e",
+	0,0,		nil,
+	0,0,		"FMOVX	%e,F0",
+	0,0,		nil,
+	0,0,		"FMOVXP	F0,%e",
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		"FCLEX",	/* [0x2a] */
+	0,0,		"FINIT",
+};
+
+static Optable optabDC[8+8] =
+{
+	0,0,		"FADDD	%e,F0",
+	0,0,		"FMULD	%e,F0",
+	0,0,		"FCOMD	%e,F0",
+	0,0,		"FCOMDP	%e,F0",
+	0,0,		"FSUBD	%e,F0",
+	0,0,		"FSUBRD	%e,F0",
+	0,0,		"FDIVD	%e,F0",
+	0,0,		"FDIVRD	%e,F0",
+	0,0,		"FADDD	F0,%f",
+	0,0,		"FMULD	F0,%f",
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		"FSUBRD	F0,%f",
+	0,0,		"FSUBD	F0,%f",
+	0,0,		"FDIVRD	F0,%f",
+	0,0,		"FDIVD	F0,%f",
+};
+
+static Optable optabDD[8+8] =
+{
+	0,0,		"FMOVD	%e,F0",
+	0,0,		nil,
+	0,0,		"FMOVD	F0,%e",
+	0,0,		"FMOVDP	F0,%e",
+	0,0,		"FRSTOR%S %e",
+	0,0,		nil,
+	0,0,		"FSAVE%S %e",
+	0,0,		"FSTSW	%e",
+	0,0,		"FFREED	%f",
+	0,0,		nil,
+	0,0,		"FMOVD	%f,F0",
+	0,0,		"FMOVDP	%f,F0",
+	0,0,		"FUCOMD	%f,F0",
+	0,0,		"FUCOMDP %f,F0",
+};
+
+static Optable optabDE[8+8] =
+{
+	0,0,		"FADDW	%e,F0",
+	0,0,		"FMULW	%e,F0",
+	0,0,		"FCOMW	%e,F0",
+	0,0,		"FCOMWP	%e,F0",
+	0,0,		"FSUBW	%e,F0",
+	0,0,		"FSUBRW	%e,F0",
+	0,0,		"FDIVW	%e,F0",
+	0,0,		"FDIVRW	%e,F0",
+	0,0,		"FADDDP	F0,%f",
+	0,0,		"FMULDP	F0,%f",
+	0,0,		nil,
+	R1,0,		"FCOMPDP",
+	0,0,		"FSUBRDP F0,%f",
+	0,0,		"FSUBDP	F0,%f",
+	0,0,		"FDIVRDP F0,%f",
+	0,0,		"FDIVDP	F0,%f",
+};
+
+static Optable optabDF[8+8] =
+{
+	0,0,		"FMOVW	%e,F0",
+	0,0,		nil,
+	0,0,		"FMOVW	F0,%e",
+	0,0,		"FMOVWP	F0,%e",
+	0,0,		"FBLD	%e",
+	0,0,		"FMOVL	%e,F0",
+	0,0,		"FBSTP	%e",
+	0,0,		"FMOVLP	F0,%e",
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	R0,0,		"FSTSW	%OAX",
+};
+
+static Optable optabF6[8] =
+{
+	Ib,0,		"TESTB	%i,%e",
+	0,0,		nil,
+	0,0,		"NOTB	%e",
+	0,0,		"NEGB	%e",
+	0,0,		"MULB	AL,%e",
+	0,0,		"IMULB	AL,%e",
+	0,0,		"DIVB	AL,%e",
+	0,0,		"IDIVB	AL,%e",
+};
+
+static Optable optabF7[8] =
+{
+	Iwd,0,		"TEST%S	%i,%e",
+	0,0,		nil,
+	0,0,		"NOT%S	%e",
+	0,0,		"NEG%S	%e",
+	0,0,		"MUL%S	%OAX,%e",
+	0,0,		"IMUL%S	%OAX,%e",
+	0,0,		"DIV%S	%OAX,%e",
+	0,0,		"IDIV%S	%OAX,%e",
+};
+
+static Optable optabFE[8] =
+{
+	0,0,		"INCB	%e",
+	0,0,		"DECB	%e",
+};
+
+static Optable optabFF[8] =
+{
+	0,0,		"INC%S	%e",
+	0,0,		"DEC%S	%e",
+	JUMP,0,		"CALL*%S %e",
+	JUMP,0,		"CALLF*%S %e",
+	JUMP,0,		"JMP*%S	%e",
+	JUMP,0,		"JMPF*%S %e",
+	0,0,		"PUSHL	%e",
+};
+
+static Optable optable[256] =
+{
+	RMB,0,		"ADDB	%r,%e",
+	RM,0,		"ADD%S	%r,%e",
+	RMB,0,		"ADDB	%e,%r",
+	RM,0,		"ADD%S	%e,%r",
+	Ib,0,		"ADDB	%i,AL",
+	Iwd,0,		"ADD%S	%i,%OAX",
+	0,0,		"PUSHL	ES",
+	0,0,		"POPL	ES",
+	RMB,0,		"ORB	%r,%e",
+	RM,0,		"OR%S	%r,%e",
+	RMB,0,		"ORB	%e,%r",
+	RM,0,		"OR%S	%e,%r",
+	Ib,0,		"ORB	%i,AL",
+	Iwd,0,		"OR%S	%i,%OAX",
+	0,0,		"PUSHL	CS",
+	AUX,0,		optab0F,
+	RMB,0,		"ADCB	%r,%e",
+	RM,0,		"ADC%S	%r,%e",
+	RMB,0,		"ADCB	%e,%r",
+	RM,0,		"ADC%S	%e,%r",
+	Ib,0,		"ADCB	%i,AL",
+	Iwd,0,		"ADC%S	%i,%OAX",
+	0,0,		"PUSHL	SS",
+	0,0,		"POPL	SS",
+	RMB,0,		"SBBB	%r,%e",
+	RM,0,		"SBB%S	%r,%e",
+	RMB,0,		"SBBB	%e,%r",
+	RM,0,		"SBB%S	%e,%r",
+	Ib,0,		"SBBB	%i,AL",
+	Iwd,0,		"SBB%S	%i,%OAX",
+	0,0,		"PUSHL	DS",
+	0,0,		"POPL	DS",
+	RMB,0,		"ANDB	%r,%e",
+	RM,0,		"AND%S	%r,%e",
+	RMB,0,		"ANDB	%e,%r",
+	RM,0,		"AND%S	%e,%r",
+	Ib,0,		"ANDB	%i,AL",
+	Iwd,0,		"AND%S	%i,%OAX",
+	SEG,0,		"ES:",
+	0,0,		"DAA",
+	RMB,0,		"SUBB	%r,%e",
+	RM,0,		"SUB%S	%r,%e",
+	RMB,0,		"SUBB	%e,%r",
+	RM,0,		"SUB%S	%e,%r",
+	Ib,0,		"SUBB	%i,AL",
+	Iwd,0,		"SUB%S	%i,%OAX",
+	SEG,0,		"CS:",
+	0,0,		"DAS",
+	RMB,0,		"XORB	%r,%e",
+	RM,0,		"XOR%S	%r,%e",
+	RMB,0,		"XORB	%e,%r",
+	RM,0,		"XOR%S	%e,%r",
+	Ib,0,		"XORB	%i,AL",
+	Iwd,0,		"XOR%S	%i,%OAX",
+	SEG,0,		"SS:",
+	0,0,		"AAA",
+	RMB,0,		"CMPB	%r,%e",
+	RM,0,		"CMP%S	%r,%e",
+	RMB,0,		"CMPB	%e,%r",
+	RM,0,		"CMP%S	%e,%r",
+	Ib,0,		"CMPB	%i,AL",
+	Iwd,0,		"CMP%S	%i,%OAX",
+	SEG,0,		"DS:",
+	0,0,		"AAS",
+	0,0,		"INC%S	%OAX",
+	0,0,		"INC%S	%OCX",
+	0,0,		"INC%S	%ODX",
+	0,0,		"INC%S	%OBX",
+	0,0,		"INC%S	%OSP",
+	0,0,		"INC%S	%OBP",
+	0,0,		"INC%S	%OSI",
+	0,0,		"INC%S	%ODI",
+	0,0,		"DEC%S	%OAX",
+	0,0,		"DEC%S	%OCX",
+	0,0,		"DEC%S	%ODX",
+	0,0,		"DEC%S	%OBX",
+	0,0,		"DEC%S	%OSP",
+	0,0,		"DEC%S	%OBP",
+	0,0,		"DEC%S	%OSI",
+	0,0,		"DEC%S	%ODI",
+	0,0,		"PUSH%S	%OAX",
+	0,0,		"PUSH%S	%OCX",
+	0,0,		"PUSH%S	%ODX",
+	0,0,		"PUSH%S	%OBX",
+	0,0,		"PUSH%S	%OSP",
+	0,0,		"PUSH%S	%OBP",
+	0,0,		"PUSH%S	%OSI",
+	0,0,		"PUSH%S	%ODI",
+	0,0,		"POP%S	%OAX",
+	0,0,		"POP%S	%OCX",
+	0,0,		"POP%S	%ODX",
+	0,0,		"POP%S	%OBX",
+	0,0,		"POP%S	%OSP",
+	0,0,		"POP%S	%OBP",
+	0,0,		"POP%S	%OSI",
+	0,0,		"POP%S	%ODI",
+	0,0,		"PUSHA%S",
+	0,0,		"POPA%S",
+	RMM,0,		"BOUND	%e,%r",
+	RM,0,		"ARPL	%r,%e",
+	SEG,0,		"FS:",
+	SEG,0,		"GS:",
+	OPOVER,0,	"",
+	ADDOVER,0,	"",
+	Iwd,0,		"PUSH%S	%i",
+	RM,Iwd,		"IMUL%S	%e,%i,%r",
+	Ib,0,		"PUSH%S	%i",
+	RM,Ibs,		"IMUL%S	%e,%i,%r",
+	0,0,		"INSB	DX,(%ODI)",
+	0,0,		"INS%S	DX,(%ODI)",
+	0,0,		"OUTSB	(%ASI),DX",
+	0,0,		"OUTS%S	(%ASI),DX",
+	Jbs,0,		"JOS	%p",
+	Jbs,0,		"JOC	%p",
+	Jbs,0,		"JCS	%p",
+	Jbs,0,		"JCC	%p",
+	Jbs,0,		"JEQ	%p",
+	Jbs,0,		"JNE	%p",
+	Jbs,0,		"JLS	%p",
+	Jbs,0,		"JHI	%p",
+	Jbs,0,		"JMI	%p",
+	Jbs,0,		"JPL	%p",
+	Jbs,0,		"JPS	%p",
+	Jbs,0,		"JPC	%p",
+	Jbs,0,		"JLT	%p",
+	Jbs,0,		"JGE	%p",
+	Jbs,0,		"JLE	%p",
+	Jbs,0,		"JGT	%p",
+	RMOPB,0,	optab80,
+	RMOP,0,		optab81,
+	0,0,		nil,
+	RMOP,0,		optab83,
+	RMB,0,		"TESTB	%r,%e",
+	RM,0,		"TEST%S	%r,%e",
+	RMB,0,		"XCHGB	%r,%e",
+	RM,0,		"XCHG%S	%r,%e",
+	RMB,0,		"MOVB	%r,%e",
+	RM,0,		"MOV%S	%r,%e",
+	RMB,0,		"MOVB	%e,%r",
+	RM,0,		"MOV%S	%e,%r",
+	RM,0,		"MOVW	%g,%e",
+	RM,0,		"LEA	%e,%r",
+	RM,0,		"MOVW	%e,%g",
+	RM,0,		"POP%S	%e",
+	0,0,		"NOP",
+	0,0,		"XCHG	%OCX,%OAX",
+	0,0,		"XCHG	%ODX,%OAX",
+	0,0,		"XCHG	%OBX,%OAX",
+	0,0,		"XCHG	%OSP,%OAX",
+	0,0,		"XCHG	%OBP,%OAX",
+	0,0,		"XCHG	%OSI,%OAX",
+	0,0,		"XCHG	%ODI,%OAX",
+	0,0,		"%X",			/* miserable CBW or CWDE */
+	0,0,		"%x",			/* idiotic CWD or CDQ */
+	PTR,0,		"CALL%S	%d",
+	0,0,		"WAIT",
+	0,0,		"PUSH	FLAGS",
+	0,0,		"POP	FLAGS",
+	0,0,		"SAHF",
+	0,0,		"LAHF",
+	Awd,0,		"MOVB	%i,AL",
+	Awd,0,		"MOV%S	%i,%OAX",
+	Awd,0,		"MOVB	AL,%i",
+	Awd,0,		"MOV%S	%OAX,%i",
+	0,0,		"MOVSB	(%ASI),(%ADI)",
+	0,0,		"MOVS%S	(%ASI),(%ADI)",
+	0,0,		"CMPSB	(%ASI),(%ADI)",
+	0,0,		"CMPS%S	(%ASI),(%ADI)",
+	Ib,0,		"TESTB	%i,AL",
+	Iwd,0,		"TEST%S	%i,%OAX",
+	0,0,		"STOSB	AL,(%ADI)",
+	0,0,		"STOS%S	%OAX,(%ADI)",
+	0,0,		"LODSB	(%ASI),AL",
+	0,0,		"LODS%S	(%ASI),%OAX",
+	0,0,		"SCASB	(%ADI),AL",
+	0,0,		"SCAS%S	(%ADI),%OAX",
+	Ib,0,		"MOVB	%i,AL",
+	Ib,0,		"MOVB	%i,CL",
+	Ib,0,		"MOVB	%i,DL",
+	Ib,0,		"MOVB	%i,BL",
+	Ib,0,		"MOVB	%i,AH",
+	Ib,0,		"MOVB	%i,CH",
+	Ib,0,		"MOVB	%i,DH",
+	Ib,0,		"MOVB	%i,BH",
+	Iwd,0,		"MOV%S	%i,%OAX",
+	Iwd,0,		"MOV%S	%i,%OCX",
+	Iwd,0,		"MOV%S	%i,%ODX",
+	Iwd,0,		"MOV%S	%i,%OBX",
+	Iwd,0,		"MOV%S	%i,%OSP",
+	Iwd,0,		"MOV%S	%i,%OBP",
+	Iwd,0,		"MOV%S	%i,%OSI",
+	Iwd,0,		"MOV%S	%i,%ODI",
+	RMOPB,0,	optabC0,
+	RMOP,0,		optabC1,
+	Iw,0,		"RET	%i",
+	RET,0,		"RET",
+	RM,0,		"LES	%e,%r",
+	RM,0,		"LDS	%e,%r",
+	RMB,Ib,		"MOVB	%i,%e",
+	RM,Iwd,		"MOV%S	%i,%e",
+	Iw2,Ib,		"ENTER	%i,%I",		/* loony ENTER */
+	RET,0,		"LEAVE",		/* bizarre LEAVE */
+	Iw,0,		"RETF	%i",
+	RET,0,		"RETF",
+	0,0,		"INT	3",
+	Ib,0,		"INTB	%i",
+	0,0,		"INTO",
+	0,0,		"IRET",
+	RMOPB,0,	optabD0,
+	RMOP,0,		optabD1,
+	RMOPB,0,	optabD2,
+	RMOP,0,		optabD3,
+	OA,0,		"AAM",
+	OA,0,		"AAD",
+	0,0,		nil,
+	0,0,		"XLAT",
+	FRMOP,0,	optabD8,
+	FRMEX,0,	optabD9,
+	FRMOP,0,	optabDA,
+	FRMEX,0,	optabDB,
+	FRMOP,0,	optabDC,
+	FRMOP,0,	optabDD,
+	FRMOP,0,	optabDE,
+	FRMOP,0,	optabDF,
+	Jbs,0,		"LOOPNE	%p",
+	Jbs,0,		"LOOPE	%p",
+	Jbs,0,		"LOOP	%p",
+	Jbs,0,		"JCXZ	%p",
+	Ib,0,		"INB	%i,AL",
+	Ib,0,		"IN%S	%i,%OAX",
+	Ib,0,		"OUTB	AL,%i",
+	Ib,0,		"OUT%S	%OAX,%i",
+	Iwds,0,		"CALL	%p",
+	Iwds,0,		"JMP	%p",
+	PTR,0,		"JMP	%d",
+	Jbs,0,		"JMP	%p",
+	0,0,		"INB	DX,AL",
+	0,0,		"IN%S	DX,%OAX",
+	0,0,		"OUTB	AL,DX",
+	0,0,		"OUT%S	%OAX,DX",
+	PRE,0,		"LOCK",
+	0,0,		nil,
+	PRE,0,		"REPNE",
+	PRE,0,		"REP",
+	0,0,		"HALT",
+	0,0,		"CMC",
+	RMOPB,0,	optabF6,
+	RMOP,0,		optabF7,
+	0,0,		"CLC",
+	0,0,		"STC",
+	0,0,		"CLI",
+	0,0,		"STI",
+	0,0,		"CLD",
+	0,0,		"STD",
+	RMOPB,0,	optabFE,
+	RMOP,0,		optabFF,
+};
+
+/*
+ *  get a byte of the instruction
+ */
+static int
+igetc(Instr *ip, uchar *c)
+{
+	if(ip->n+1 > sizeof(ip->mem)){
+		kwerrstr("instruction too long");
+		return -1;
+	}
+	*c = dasdata[ip->addr+ip->n];
+	ip->mem[ip->n++] = *c;
+	return 1;
+}
+
+/*
+ *  get two bytes of the instruction
+ */
+static int
+igets(Instr *ip, ushort *sp)
+{
+	uchar	c;
+	ushort s;
+
+	if (igetc(ip, &c) < 0)
+		return -1;
+	s = c;
+	if (igetc(ip, &c) < 0)
+		return -1;
+	s |= (c<<8);
+	*sp = s;
+	return 1;
+}
+
+/*
+ *  get 4 bytes of the instruction
+ */
+static int
+igetl(Instr *ip, ulong *lp)
+{
+	ushort s;
+	long	l;
+
+	if (igets(ip, &s) < 0)
+		return -1;
+	l = s;
+	if (igets(ip, &s) < 0)
+		return -1;
+	l |= (s<<16);
+	*lp = l;
+	return 1;
+}
+
+static int
+getdisp(Instr *ip, int mod, int rm, int code)
+{
+	uchar c;
+	ushort s;
+
+	if (mod > 2)
+		return 1;
+	if (mod == 1) {
+		if (igetc(ip, &c) < 0)
+			return -1;
+		if (c&0x80)
+			ip->disp = c|0xffffff00;
+		else
+			ip->disp = c&0xff;
+	} else if (mod == 2 || rm == code) {
+		if (ip->asize == 'E') {
+			if (igetl(ip, &ip->disp) < 0)
+				return -1;
+		} else {
+			if (igets(ip, &s) < 0)
+				return -1;
+			if (s&0x8000)
+				ip->disp = s|0xffff0000;
+			else
+				ip->disp = s;
+		}
+		if (mod == 0)
+			ip->base = -1;
+	}
+	return 1;
+}
+
+static int
+modrm(Instr *ip, uchar c)
+{
+	uchar rm, mod;
+
+	mod = (c>>6)&3;
+	rm = c&7;
+	ip->mod = mod;
+	ip->base = rm;
+	ip->reg = (c>>3)&7;
+	if (mod == 3)			/* register */
+		return 1;
+	if (ip->asize == 0) {		/* 16-bit mode */
+		switch(rm)
+		{
+		case 0:
+			ip->base = BX; ip->index = SI;
+			break;
+		case 1:
+			ip->base = BX; ip->index = DI;
+			break;
+		case 2:
+			ip->base = BP; ip->index = SI;
+			break;
+		case 3:
+			ip->base = BP; ip->index = DI;
+			break;
+		case 4:
+			ip->base = SI;
+			break;
+		case 5:
+			ip->base = DI;
+			break;
+		case 6:
+			ip->base = BP;
+			break;
+		case 7:
+			ip->base = BX;
+			break;
+		default:
+			break;
+		}
+		return getdisp(ip, mod, rm, 6);
+	}
+	if (rm == 4) {	/* scummy sib byte */
+		if (igetc(ip, &c) < 0)
+			return -1;
+		ip->ss = (c>>6)&0x03;
+		ip->index = (c>>3)&0x07;
+		if (ip->index == 4)
+			ip->index = -1;
+		ip->base = c&0x07;
+		return getdisp(ip, mod, ip->base, 5);
+	}
+	return getdisp(ip, mod, rm, 5);
+}
+
+static Optable *
+mkinstr(Instr *ip, ulong pc)
+{
+	int i, n;
+	uchar c;
+	ushort s;
+	Optable *op, *obase;
+	char buf[128];
+
+	memset(ip, 0, sizeof(*ip));
+	ip->base = -1;
+	ip->index = -1;
+	ip->osize = 'L';
+	ip->asize = 'E';
+	ip->addr = pc;
+	if (igetc(ip, &c) < 0)
+		return 0;
+	obase = optable;
+newop:
+	op = &obase[c];
+	if (op->proto == 0) {
+badop:
+		n = snprint(buf, sizeof(buf), "opcode: ??");
+		for (i = 0; i < ip->n && n < sizeof(buf)-3; i++, n+=2)
+			_hexify(buf+n, ip->mem[i], 1);
+		strcpy(buf+n, "??");
+		kwerrstr(buf);
+		return 0;
+	}
+	for(i = 0; i < 2 && op->operand[i]; i++) {
+		switch(op->operand[i])
+		{
+		case Ib:	/* 8-bit immediate - (no sign extension)*/
+			if (igetc(ip, &c) < 0)
+				return 0;
+			ip->imm = c&0xff;
+			break;
+		case Jbs:	/* 8-bit jump immediate (sign extended) */
+			if (igetc(ip, &c) < 0)
+				return 0;
+			if (c&0x80)
+				ip->imm = c|0xffffff00;
+			else
+				ip->imm = c&0xff;
+			ip->jumptype = Jbs;
+			break;
+		case Ibs:	/* 8-bit immediate (sign extended) */
+			if (igetc(ip, &c) < 0)
+				return 0;
+			if (c&0x80)
+				if (ip->osize == 'L')
+					ip->imm = c|0xffffff00;
+				else
+					ip->imm = c|0xff00;
+			else
+				ip->imm = c&0xff;
+			break;
+		case Iw:	/* 16-bit immediate -> imm */
+			if (igets(ip, &s) < 0)
+				return 0;
+			ip->imm = s&0xffff;
+			ip->jumptype = Iw;
+			break;
+		case Iw2:	/* 16-bit immediate -> in imm2*/
+			if (igets(ip, &s) < 0)
+				return 0;
+			ip->imm2 = s&0xffff;
+			break;
+		case Iwd:	/* Operand-sized immediate (no sign extension)*/
+			if (ip->osize == 'L') {
+				if (igetl(ip, &ip->imm) < 0)
+					return 0;
+			} else {
+				if (igets(ip, &s)< 0)
+					return 0;
+				ip->imm = s&0xffff;
+			}
+			break;
+		case Awd:	/* Address-sized immediate (no sign extension)*/
+			if (ip->asize == 'E') {
+				if (igetl(ip, &ip->imm) < 0)
+					return 0;
+			} else {
+				if (igets(ip, &s)< 0)
+					return 0;
+				ip->imm = s&0xffff;
+			}
+			break;
+		case Iwds:	/* Operand-sized immediate (sign extended) */
+			if (ip->osize == 'L') {
+				if (igetl(ip, &ip->imm) < 0)
+					return 0;
+			} else {
+				if (igets(ip, &s)< 0)
+					return 0;
+				if (s&0x8000)
+					ip->imm = s|0xffff0000;
+				else
+					ip->imm = s&0xffff;
+			}
+			ip->jumptype = Iwds;
+			break;
+		case OA:	/* literal 0x0a byte */
+			if (igetc(ip, &c) < 0)
+				return 0;
+			if (c != 0x0a)
+				goto badop;
+			break;
+		case R0:	/* base register must be R0 */
+			if (ip->base != 0)
+				goto badop;
+			break;
+		case R1:	/* base register must be R1 */
+			if (ip->base != 1)
+				goto badop;
+			break;
+		case RMB:	/* R/M field with byte register (/r)*/
+			if (igetc(ip, &c) < 0)
+				return 0;
+			if (modrm(ip, c) < 0)
+				return 0;
+			ip->osize = 'B';
+			break;
+		case RM:	/* R/M field with register (/r) */
+			if (igetc(ip, &c) < 0)
+				return 0;
+			if (modrm(ip, c) < 0)
+				return 0;
+			break;
+		case RMOPB:	/* R/M field with op code (/digit) */
+			if (igetc(ip, &c) < 0)
+				return 0;
+			if (modrm(ip, c) < 0)
+				return 0;
+			c = ip->reg;		/* secondary op code */
+			obase = (Optable*)op->proto;
+			ip->osize = 'B';
+			goto newop;
+		case RMOP:	/* R/M field with op code (/digit) */
+			if (igetc(ip, &c) < 0)
+				return 0;
+			if (modrm(ip, c) < 0)
+				return 0;
+			c = ip->reg;
+			obase = (Optable*)op->proto;
+			goto newop;
+		case FRMOP:	/* FP R/M field with op code (/digit) */
+			if (igetc(ip, &c) < 0)
+				return 0;
+			if (modrm(ip, c) < 0)
+				return 0;
+			if ((c&0xc0) == 0xc0)
+				c = ip->reg+8;		/* 16 entry table */
+			else
+				c = ip->reg;
+			obase = (Optable*)op->proto;
+			goto newop;
+		case FRMEX:	/* Extended FP R/M field with op code (/digit) */
+			if (igetc(ip, &c) < 0)
+				return 0;
+			if (modrm(ip, c) < 0)
+				return 0;
+			if ((c&0xc0) == 0xc0)
+				c = (c&0x3f)+8;		/* 64-entry table */
+			else
+				c = ip->reg;
+			obase = (Optable*)op->proto;
+			goto newop;
+		case RMR:	/* R/M register only (mod = 11) */
+			if (igetc(ip, &c) < 0)
+				return 0;
+			if ((c&0xc0) != 0xc0) {
+				kwerrstr("invalid R/M register: %x", c);
+				return 0;
+			}
+			if (modrm(ip, c) < 0)
+				return 0;
+			break;
+		case RMM:	/* R/M register only (mod = 11) */
+			if (igetc(ip, &c) < 0)
+				return 0;
+			if ((c&0xc0) == 0xc0) {
+				kwerrstr("invalid R/M memory mode: %x", c);
+				return 0;
+			}
+			if (modrm(ip, c) < 0)
+				return 0;
+			break;
+		case PTR:	/* Seg:Displacement addr (ptr16:16 or ptr16:32) */
+			if (ip->osize == 'L') {
+				if (igetl(ip, &ip->disp) < 0)
+					return 0;
+			} else {
+				if (igets(ip, &s)< 0)
+					return 0;
+				ip->disp = s&0xffff;
+			}
+			if (igets(ip, (ushort*)&ip->seg) < 0)
+				return 0;
+			ip->jumptype = PTR;
+			break;
+		case AUX:	/* Multi-byte op code - Auxiliary table */
+			obase = (Optable*)op->proto;
+			if (igetc(ip, &c) < 0)
+				return 0;
+			goto newop;
+		case PRE:	/* Instr Prefix */
+			ip->prefix = (char*)op->proto;
+			if (igetc(ip, &c) < 0)
+				return 0;
+			goto newop;
+		case SEG:	/* Segment Prefix */
+			ip->segment = (char*)op->proto;
+			if (igetc(ip, &c) < 0)
+				return 0;
+			goto newop;
+		case OPOVER:	/* Operand size override */
+			ip->osize = 'W';
+			if (igetc(ip, &c) < 0)
+				return 0;
+			goto newop;
+		case ADDOVER:	/* Address size override */
+			ip->asize = 0;
+			if (igetc(ip, &c) < 0)
+				return 0;
+			goto newop;
+		case JUMP:	/* mark instruction as JUMP or RET */
+		case RET:
+			ip->jumptype = op->operand[i];
+			break;
+		default:
+			kwerrstr("bad operand type %d", op->operand[i]);
+			return 0;
+		}
+	}
+	return op;
+}
+
+static void
+bprint(Instr *ip, char *fmt, ...)
+{
+	va_list arg;
+
+	va_start(arg, fmt);
+	ip->curr = vseprint(ip->curr, ip->end, fmt, arg);
+	va_end(arg);
+}
+
+/*
+ *  if we want to call 16 bit regs AX,BX,CX,...
+ *  and 32 bit regs EAX,EBX,ECX,... then
+ *  change the defs of ANAME and ONAME to:
+ *  #define	ANAME(ip)	((ip->asize == 'E' ? "E" : "")
+ *  #define	ONAME(ip)	((ip)->osize == 'L' ? "E" : "")
+ */
+#define	ANAME(ip)	""
+#define	ONAME(ip)	""
+
+static char *reg[] =  {
+	"AX",
+	"CX",
+	"DX",
+	"BX",
+	"SP",
+	"BP",
+	"SI",
+	"DI",
+};
+
+static char *breg[] = { "AL", "CL", "DL", "BL", "AH", "CH", "DH", "BH" };
+static char *sreg[] = { "ES", "CS", "SS", "DS", "FS", "GS" };
+
+static void
+plocal(Instr *ip)
+{
+	int offset;
+
+	offset = ip->disp;
+
+	bprint(ip, "%lux(SP)", offset);
+}
+
+static void
+pea(Instr *ip)
+{
+	if (ip->mod == 3) {
+		if (ip->osize == 'B')
+			bprint(ip, breg[ip->base]);
+		else
+			bprint(ip, "%s%s", ANAME(ip), reg[ip->base]);
+		return;
+	}
+	if (ip->segment)
+		bprint(ip, ip->segment);
+	if (ip->asize == 'E' && ip->base == SP)
+		plocal(ip);
+	else {
+		bprint(ip,"%lux", ip->disp);
+		if (ip->base >= 0)
+			bprint(ip,"(%s%s)", ANAME(ip), reg[ip->base]);
+	}
+	if (ip->index >= 0)
+		bprint(ip,"(%s%s*%d)", ANAME(ip), reg[ip->index], 1<<ip->ss);
+}
+
+static void
+immediate(Instr *ip, long val)
+{
+	bprint(ip, "%lux", val);
+}
+
+static void
+prinstr(Instr *ip, char *fmt)
+{
+	if (ip->prefix)
+		bprint(ip, "%s ", ip->prefix);
+	for (; *fmt && ip->curr < ip->end; fmt++) {
+		if (*fmt != '%')
+			*ip->curr++ = *fmt;
+		else switch(*++fmt)
+		{
+		case '%':
+			*ip->curr++ = '%';
+			break;
+		case 'A':
+			bprint(ip, "%s", ANAME(ip));
+			break;
+		case 'C':
+			bprint(ip, "CR%d", ip->reg);
+			break;
+		case 'D':
+			if (ip->reg < 4 || ip->reg == 6 || ip->reg == 7)
+				bprint(ip, "DR%d",ip->reg);
+			else
+				bprint(ip, "???");
+			break;
+		case 'I':
+			bprint(ip, "$");
+			immediate(ip, ip->imm2);
+			break;
+		case 'O':
+			bprint(ip,"%s", ONAME(ip));
+			break;
+		case 'i':
+			bprint(ip, "$");
+			immediate(ip,ip->imm);
+			break;
+		case 'R':
+			bprint(ip, "%s%s", ONAME(ip), reg[ip->reg]);
+			break;
+		case 'S':
+			bprint(ip, "%c", ip->osize);
+			break;
+		case 'T':
+			if (ip->reg == 6 || ip->reg == 7)
+				bprint(ip, "TR%d",ip->reg);
+			else
+				bprint(ip, "???");
+			break;
+		case 'X':
+			if (ip->osize == 'L')
+				bprint(ip,"CWDE");
+			else
+				bprint(ip, "CBW");
+			break;
+		case 'd':
+			bprint(ip,"%lux:%lux",ip->seg,ip->disp);
+			break;
+		case 'e':
+			pea(ip);
+			break;
+		case 'f':
+			bprint(ip, "F%d", ip->base);
+			break;
+		case 'g':
+			if (ip->reg < 6)
+				bprint(ip,"%s",sreg[ip->reg]);
+			else
+				bprint(ip,"???");
+			break;
+		case 'p':
+			immediate(ip, ip->imm+ip->addr+ip->n);
+			break;
+		case 'r':
+			if (ip->osize == 'B')
+				bprint(ip,"%s",breg[ip->reg]);
+			else
+				bprint(ip, reg[ip->reg]);
+			break;
+		case 'x':
+			if (ip->osize == 'L')
+				bprint(ip,"CDQ");
+			else
+				bprint(ip, "CWD");
+			break;
+		default:
+			bprint(ip, "%%%c", *fmt);
+			break;
+		}
+	}
+	*ip->curr = 0;		/* there's always room for 1 byte */
+}
+
+int
+i386inst(ulong pc, char modifier, char *buf, int n)
+{
+	Instr	instr;
+	Optable *op;
+
+	USED(modifier);
+	op = mkinstr(&instr, pc);
+	if (op == 0) {
+		kgerrstr(buf, n);
+		return -1;
+	}
+	instr.curr = buf;
+	instr.end = buf+n-1;
+	prinstr(&instr, op->proto);
+	return instr.n;
+}
+
+int
+i386das(ulong pc, char *buf, int n)
+{
+	Instr	instr;
+	int i;
+
+	if (mkinstr(&instr, pc) == 0) {
+		kgerrstr(buf, n);
+		return -1;
+	}
+	for(i = 0; i < instr.n && n > 2; i++) {
+		_hexify(buf, instr.mem[i], 1);
+		buf += 2;
+		n -= 2;
+	}
+	*buf = 0;
+	return instr.n;
+}
+
+int
+i386instlen(ulong pc)
+{
+	Instr i;
+
+	if (mkinstr(&i, pc))
+		return i.n;
+	return -1;
+}
+
+void
+das(uchar *x, int n)
+{
+	int l, pc;
+	char buf[128];
+/*
+	int i;
+	for(i = 0; i < n; i++)
+		print("%.2ux", x[i]);
+	print("\n");
+*/
+
+	dasdata = x;
+	pc = 0;
+	while(n > 0) {
+		i386das(pc, buf, sizeof(buf));
+		print("%.8lux %2x %-20s ", (ulong)(dasdata+pc), pc, buf);
+		l = i386inst(pc, 'i', buf, sizeof(buf));
+		print("\t%s\n", buf);
+
+		pc += l;
+		n -= l;
+	}
+}
--- /dev/null
+++ b/libinterp/dlm-9front.c
@@ -1,0 +1,101 @@
+#include "lib9.h"
+#include "isa.h"
+#include "interp.h"
+#include "raise.h"
+#include "pool.h"
+#include "kernel.h"
+#include "dynld.h"
+
+#define	DBG	if(1) print
+
+extern Dynobj* dynld(int);
+extern char*	enverror(void);
+
+typedef struct{char *name; long sig; void (*fn)(void*); int size; int np; uchar map[16];} Runtab;
+
+static void*
+addr(char *pre, char *suf, Dynobj *o, ulong sig)
+{
+	char buf[64];
+
+	if(o == nil || strlen(pre)+strlen(suf) > 64-1)
+		return nil;
+	snprint(buf, sizeof(buf), "%s%s", pre, suf);
+	return dynimport(o, buf, sig);
+}
+
+Module*
+newdyncode(int fd, char *path, Dir *dir)
+{
+	Module *m;
+	void *v;
+	Runtab *r;
+	Dynobj *o;
+	char *name;
+
+	DBG("module path is %s\n", path);
+	m = nil;
+	o = dynld(fd);
+	if(o == nil){
+		DBG("%s\n", enverror());
+		goto Error;
+	}
+	v = addr("XXX", "module", o, signof(char*));
+	if(v == nil)
+		goto Error;
+	name = *(char**)v;
+	DBG("module name is %s\n", name);
+	r = addr(name, "modtab", o, signof(Runtab[]));
+	if(r == nil)
+		goto Error;
+	m = builtinmod(name, r, 0);
+	m->rt = DYNMOD;
+	m->dev = dir->dev;
+	m->dtype = dir->type;
+	m->qid = dir->qid;
+	m->mtime = dir->mtime;
+	m->path = strdup(path);
+	if(m->path == nil)
+		goto Error;
+	m->dlm = o;
+	DBG("module base is 0x%p\n", o->base);
+	return m;
+Error:
+	if(o != nil)
+		dynobjfree(o);
+	if(m != nil)
+		freemod(m);
+	return nil;
+}
+
+void
+freedyncode(Module *m)
+{
+	dynobjfree(m->dlm);
+}
+
+static void
+callfn(Module *m, char *fn)
+{
+	void *v, (*f)(void);
+
+	if(m->ref != 1)
+		return;
+	v = addr(m->name, fn, m->dlm, signof(*f));
+	if(v != nil){
+		f = v;
+		(*f)();
+	}
+}
+
+void
+newdyndata(Modlink *ml)
+{
+	callfn(ml->m, "init");
+}
+
+void
+freedyndata(Modlink *ml)
+{
+	callfn(ml->m, "end");
+}
--- /dev/null
+++ b/libmath/FPcontrol-9front.c
@@ -1,0 +1,1 @@
+#include "FPcontrol-Inferno.c"
--- /dev/null
+++ b/libmemdraw/mkfile-9front
@@ -1,0 +1,9 @@
+#
+#	Object files specific for Inferno/Plan9
+#
+SYSFILES=alloc.$O\
+	cload.$O\
+	draw.$O\
+	load.$O\
+	unload.$O\
+
--- /dev/null
+++ b/libmemlayer/mkfile-9front
@@ -1,0 +1,4 @@
+#
+#	System dependent objects for Inferno model systems
+#
+SYSFILES=lalloc.$O
--- /dev/null
+++ b/libsec/9front-amd64/md5block.s
@@ -1,0 +1,212 @@
+/*
+ *  rfc1321 requires that I include this.  The code is new.  The constants
+ *  all come from the rfc (hence the copyright).  We trade a table for the
+ *  macros in rfc.  The total size is a lot less. -- presotto
+ *
+ *	Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
+ *	rights reserved.
+ *
+ *	License to copy and use this software is granted provided that it
+ *	is identified as the "RSA Data Security, Inc. MD5 Message-Digest
+ *	Algorithm" in all material mentioning or referencing this software
+ *	or this function.
+ *
+ *	License is also granted to make and use derivative works provided
+ *	that such works are identified as "derived from the RSA Data
+ *	Security, Inc. MD5 Message-Digest Algorithm" in all material
+ *	mentioning or referencing the derived work.
+ *
+ *	RSA Data Security, Inc. makes no representations concerning either
+ *	the merchantability of this software or the suitability of this
+ *	software forany particular purpose. It is provided "as is"
+ *	without express or implied warranty of any kind.
+ *	These notices must be retained in any copies of any part of this
+ *	documentation and/or software.
+ */
+#define S11 7
+#define S12 12
+#define S13 17
+#define S14 22
+
+#define S21 5
+#define S22 9
+#define S23 14
+#define S24 20
+
+#define S31 4
+#define S32 11
+#define S33 16
+#define S34 23
+
+#define S41 6
+#define S42 10
+#define S43 15
+#define S44 21
+
+/*
+ * SI is data
+ *	a += FN(B,C,D);
+ *	a += x[sh] + t[sh];
+ *	a = (a << S11) | (a >> (32 - S11));
+ *	a += b;
+ */
+
+#define BODY1(off,V,FN,SH,A,B,C,D)\
+	FN(B,C,D)\
+	LEAL V(A)(DI*1),A;\
+	ADDL (off)(BP),A;\
+	ROLL $SH,A;\
+	ADDL B,A;\
+
+#define BODY(off,V,FN,SH,A,B,C,D)\
+	FN(B,C,D)\
+	LEAL V(A)(DI*1),A;\
+	ADDL (off)(BP),A;\
+	ROLL $SH,A;\
+	ADDL B,A;\
+
+/*
+ * fn1 = ((c ^ d) & b) ^ d
+ */
+#define FN1(B,C,D)\
+	MOVL C,DI;\
+	XORL D,DI;\
+	ANDL B,DI;\
+	XORL D,DI;\
+
+/*
+ * fn2 = ((b ^ c) & d) ^ c;
+ */
+#define FN2(B,C,D)\
+	MOVL B,DI;\
+	XORL C,DI;\
+	ANDL D,DI;\
+	XORL C,DI;\
+
+/*
+ * fn3 = b ^ c ^ d;
+ */
+#define FN3(B,C,D)\
+	MOVL B,DI;\
+	XORL C,DI;\
+	XORL D,DI;\
+
+/*
+ * fn4 = c ^ (b | ~d);
+ */
+#define FN4(B,C,D)\
+	MOVL D,DI;\
+	XORL $-1,DI;\
+	ORL B,DI;\
+	XORL C,DI;\
+
+#define	LEN	8
+#define	STATE	16
+
+TEXT	_md5block+0(SB),$0
+
+	MOVQ	RARG,R8
+	MOVLQZX len+LEN(FP),BX
+	ADDQ	BX,R8
+
+mainloop:
+	MOVQ state+STATE(FP),SI
+	MOVL (SI),AX
+	MOVL 4(SI),BX
+	MOVL 8(SI),CX
+	MOVL 12(SI),DX
+
+	BODY1( 0*4,0xd76aa478,FN1,S11,AX,BX,CX,DX)
+	BODY1( 1*4,0xe8c7b756,FN1,S12,DX,AX,BX,CX)
+	BODY1( 2*4,0x242070db,FN1,S13,CX,DX,AX,BX)
+	BODY1( 3*4,0xc1bdceee,FN1,S14,BX,CX,DX,AX)
+
+	BODY1( 4*4,0xf57c0faf,FN1,S11,AX,BX,CX,DX)
+	BODY1( 5*4,0x4787c62a,FN1,S12,DX,AX,BX,CX)
+	BODY1( 6*4,0xa8304613,FN1,S13,CX,DX,AX,BX)
+	BODY1( 7*4,0xfd469501,FN1,S14,BX,CX,DX,AX)
+
+	BODY1( 8*4,0x698098d8,FN1,S11,AX,BX,CX,DX)
+	BODY1( 9*4,0x8b44f7af,FN1,S12,DX,AX,BX,CX)
+	BODY1(10*4,0xffff5bb1,FN1,S13,CX,DX,AX,BX)
+	BODY1(11*4,0x895cd7be,FN1,S14,BX,CX,DX,AX)
+
+	BODY1(12*4,0x6b901122,FN1,S11,AX,BX,CX,DX)
+	BODY1(13*4,0xfd987193,FN1,S12,DX,AX,BX,CX)
+	BODY1(14*4,0xa679438e,FN1,S13,CX,DX,AX,BX)
+	BODY1(15*4,0x49b40821,FN1,S14,BX,CX,DX,AX)
+
+
+	BODY( 1*4,0xf61e2562,FN2,S21,AX,BX,CX,DX)
+	BODY( 6*4,0xc040b340,FN2,S22,DX,AX,BX,CX)
+	BODY(11*4,0x265e5a51,FN2,S23,CX,DX,AX,BX)
+	BODY( 0*4,0xe9b6c7aa,FN2,S24,BX,CX,DX,AX)
+
+	BODY( 5*4,0xd62f105d,FN2,S21,AX,BX,CX,DX)
+	BODY(10*4,0x02441453,FN2,S22,DX,AX,BX,CX)
+	BODY(15*4,0xd8a1e681,FN2,S23,CX,DX,AX,BX)
+	BODY( 4*4,0xe7d3fbc8,FN2,S24,BX,CX,DX,AX)
+
+	BODY( 9*4,0x21e1cde6,FN2,S21,AX,BX,CX,DX)
+	BODY(14*4,0xc33707d6,FN2,S22,DX,AX,BX,CX)
+	BODY( 3*4,0xf4d50d87,FN2,S23,CX,DX,AX,BX)
+	BODY( 8*4,0x455a14ed,FN2,S24,BX,CX,DX,AX)
+
+	BODY(13*4,0xa9e3e905,FN2,S21,AX,BX,CX,DX)
+	BODY( 2*4,0xfcefa3f8,FN2,S22,DX,AX,BX,CX)
+	BODY( 7*4,0x676f02d9,FN2,S23,CX,DX,AX,BX)
+	BODY(12*4,0x8d2a4c8a,FN2,S24,BX,CX,DX,AX)
+
+
+	BODY( 5*4,0xfffa3942,FN3,S31,AX,BX,CX,DX)
+	BODY( 8*4,0x8771f681,FN3,S32,DX,AX,BX,CX)
+	BODY(11*4,0x6d9d6122,FN3,S33,CX,DX,AX,BX)
+	BODY(14*4,0xfde5380c,FN3,S34,BX,CX,DX,AX)
+
+	BODY( 1*4,0xa4beea44,FN3,S31,AX,BX,CX,DX)
+	BODY( 4*4,0x4bdecfa9,FN3,S32,DX,AX,BX,CX)
+	BODY( 7*4,0xf6bb4b60,FN3,S33,CX,DX,AX,BX)
+	BODY(10*4,0xbebfbc70,FN3,S34,BX,CX,DX,AX)
+
+	BODY(13*4,0x289b7ec6,FN3,S31,AX,BX,CX,DX)
+	BODY( 0*4,0xeaa127fa,FN3,S32,DX,AX,BX,CX)
+	BODY( 3*4,0xd4ef3085,FN3,S33,CX,DX,AX,BX)
+	BODY( 6*4,0x04881d05,FN3,S34,BX,CX,DX,AX)
+
+	BODY( 9*4,0xd9d4d039,FN3,S31,AX,BX,CX,DX)
+	BODY(12*4,0xe6db99e5,FN3,S32,DX,AX,BX,CX)
+	BODY(15*4,0x1fa27cf8,FN3,S33,CX,DX,AX,BX)
+	BODY( 2*4,0xc4ac5665,FN3,S34,BX,CX,DX,AX)
+
+
+	BODY( 0*4,0xf4292244,FN4,S41,AX,BX,CX,DX)
+	BODY( 7*4,0x432aff97,FN4,S42,DX,AX,BX,CX)
+	BODY(14*4,0xab9423a7,FN4,S43,CX,DX,AX,BX)
+	BODY( 5*4,0xfc93a039,FN4,S44,BX,CX,DX,AX)
+
+	BODY(12*4,0x655b59c3,FN4,S41,AX,BX,CX,DX)
+	BODY( 3*4,0x8f0ccc92,FN4,S42,DX,AX,BX,CX)
+	BODY(10*4,0xffeff47d,FN4,S43,CX,DX,AX,BX)
+	BODY( 1*4,0x85845dd1,FN4,S44,BX,CX,DX,AX)
+
+	BODY( 8*4,0x6fa87e4f,FN4,S41,AX,BX,CX,DX)
+	BODY(15*4,0xfe2ce6e0,FN4,S42,DX,AX,BX,CX)
+	BODY( 6*4,0xa3014314,FN4,S43,CX,DX,AX,BX)
+	BODY(13*4,0x4e0811a1,FN4,S44,BX,CX,DX,AX)
+
+	BODY( 4*4,0xf7537e82,FN4,S41,AX,BX,CX,DX)
+	BODY(11*4,0xbd3af235,FN4,S42,DX,AX,BX,CX)
+	BODY( 2*4,0x2ad7d2bb,FN4,S43,CX,DX,AX,BX)
+	BODY( 9*4,0xeb86d391,FN4,S44,BX,CX,DX,AX)
+
+	ADDQ $(16*4),BP
+	MOVQ state+STATE(FP),DI
+	ADDL AX,0(DI)
+	ADDL BX,4(DI)
+	ADDL CX,8(DI)
+	ADDL DX,12(DI)
+
+	CMPL BP,R8
+	JCS mainloop
+
+	RET
--- /dev/null
+++ b/libsec/9front-amd64/mkfile
@@ -1,0 +1,16 @@
+objtype=386
+OBJTYPE=$objtype
+<../../mkconfig
+
+LIB=libsec.a
+FILES=\
+	md5block\
+	sha1block\
+
+HFILES=$ROOT/include/libsec.h
+
+SFILES=${FILES:%=%.s}
+
+OFILES=${FILES:%=%.$O}
+
+<$ROOT/mkfiles/mksyslib-$SHELLTYPE
--- /dev/null
+++ b/libsec/9front-amd64/sha1block.s
@@ -1,0 +1,197 @@
+	TEXT	_sha1block+0(SB),$384
+
+/* x = (wp[off-f] ^ wp[off-8] ^ wp[off-14] ^ wp[off-16]) <<< 1;
+ * wp[off] = x;
+ * x += A <<< 5;
+ * E += 0xca62c1d6 + x;
+ * x = FN(B,C,D);
+ * E += x;
+ * B >>> 2
+ */
+#define BSWAPDI	BYTE $0x0f; BYTE $0xcf;
+
+#define BODY(off,FN,V,A,B,C,D,E)\
+	MOVL (off-64)(BP),DI;\
+	XORL (off-56)(BP),DI;\
+	XORL (off-32)(BP),DI;\
+	XORL (off-12)(BP),DI;\
+	ROLL $1,DI;\
+	MOVL DI,off(BP);\
+	LEAL V(DI)(E*1),E;\
+	MOVL A,DI;\
+	ROLL $5,DI;\
+	ADDL DI,E;\
+	FN(B,C,D)\
+	ADDL DI,E;\
+	RORL $2,B;\
+
+#define BODY0(off,FN,V,A,B,C,D,E)\
+	MOVLQZX off(BX),DI;\
+	BSWAPDI;\
+	MOVL DI,off(BP);\
+	LEAL V(DI)(E*1),E;\
+	MOVL A,DI;\
+	ROLL $5,DI;\
+	ADDL DI,E;\
+	FN(B,C,D)\
+	ADDL DI,E;\
+	RORL $2,B;\
+
+/*
+ * fn1 = (((C^D)&B)^D);
+ */
+#define FN1(B,C,D)\
+	MOVL C,DI;\
+	XORL D,DI;\
+	ANDL B,DI;\
+	XORL D,DI;\
+
+/*
+ * fn24 = B ^ C ^ D
+ */
+#define FN24(B,C,D)\
+	MOVL B,DI;\
+	XORL C,DI;\
+	XORL D,DI;\
+
+/*
+ * fn3 = ((B ^ C) & (D ^= B)) ^ B
+ * D ^= B to restore D
+ */
+#define FN3(B,C,D)\
+	MOVL B,DI;\
+	XORL C,DI;\
+	XORL B,D;\
+	ANDL D,DI;\
+	XORL B,DI;\
+	XORL B,D;\
+
+/*
+ * stack offsets
+ * void sha1block(uchar *DATA, int LEN, ulong *STATE)
+ */
+#define	DATA	0
+#define	LEN	8
+#define	STATE	16
+
+/*
+ * stack offsets for locals
+ * ulong w[80];
+ * uchar *edata;
+ * ulong *w15, *w40, *w60, *w80;
+ * register local
+ * ulong *wp = BP
+ * ulong a = eax, b = ebx, c = ecx, d = edx, e = esi
+ * ulong tmp = edi
+ */
+#define Rpdata	R8
+#define WARRAY	(-8-(80*4))
+#define TMP1	(-16-(80*4))
+#define TMP2	(-24-(80*4))
+#define W15	(-32-(80*4))
+#define W40	(-40-(80*4))
+#define W60	(-48-(80*4))
+#define W80	(-56-(80*4))
+#define EDATA	(-64-(80*4))
+
+	MOVQ RARG, Rpdata
+	MOVLQZX len+LEN(FP),BX
+	ADDQ BX, RARG
+	MOVQ RARG,edata+EDATA(SP)
+
+	LEAQ aw15+(WARRAY+15*4)(SP),DI
+	MOVQ DI,w15+W15(SP)
+	LEAQ aw40+(WARRAY+40*4)(SP),DX
+	MOVQ DX,w40+W40(SP)
+	LEAQ aw60+(WARRAY+60*4)(SP),CX
+	MOVQ CX,w60+W60(SP)
+	LEAQ aw80+(WARRAY+80*4)(SP),DI
+	MOVQ DI,w80+W80(SP)
+
+mainloop:
+	LEAQ warray+WARRAY(SP),BP
+
+	MOVQ state+STATE(FP),DI
+	MOVL (DI),AX
+	MOVL 4(DI),BX
+	MOVL BX,tmp1+TMP1(SP)
+	MOVL 8(DI),CX
+	MOVL 12(DI),DX
+	MOVL 16(DI),SI
+
+	MOVQ Rpdata,BX
+
+loop1:
+	BODY0(0,FN1,0x5a827999,AX,tmp1+TMP1(SP),CX,DX,SI)
+	MOVL SI,tmp2+TMP2(SP)
+	BODY0(4,FN1,0x5a827999,SI,AX,tmp1+TMP1(SP),CX,DX)
+	MOVL tmp1+TMP1(SP),SI
+	BODY0(8,FN1,0x5a827999,DX,tmp2+TMP2(SP),AX,SI,CX)
+	BODY0(12,FN1,0x5a827999,CX,DX,tmp2+TMP2(SP),AX,SI)
+	MOVL SI,tmp1+TMP1(SP)
+	BODY0(16,FN1,0x5a827999,SI,CX,DX,tmp2+TMP2(SP),AX)
+	MOVL tmp2+TMP2(SP),SI
+
+	ADDQ $20,BX
+	ADDQ $20,BP
+	CMPQ BP,w15+W15(SP)
+	JCS loop1
+
+	BODY0(0,FN1,0x5a827999,AX,tmp1+TMP1(SP),CX,DX,SI)
+	ADDQ $4,BX
+	MOVQ BX,R8
+	MOVQ tmp1+TMP1(SP),BX
+
+	BODY(4,FN1,0x5a827999,SI,AX,BX,CX,DX)
+	BODY(8,FN1,0x5a827999,DX,SI,AX,BX,CX)
+	BODY(12,FN1,0x5a827999,CX,DX,SI,AX,BX)
+	BODY(16,FN1,0x5a827999,BX,CX,DX,SI,AX)
+
+	ADDQ $20,BP
+
+loop2:
+	BODY(0,FN24,0x6ed9eba1,AX,BX,CX,DX,SI)
+	BODY(4,FN24,0x6ed9eba1,SI,AX,BX,CX,DX)
+	BODY(8,FN24,0x6ed9eba1,DX,SI,AX,BX,CX)
+	BODY(12,FN24,0x6ed9eba1,CX,DX,SI,AX,BX)
+	BODY(16,FN24,0x6ed9eba1,BX,CX,DX,SI,AX)
+
+	ADDQ $20,BP
+	CMPQ BP,w40+W40(SP)
+	JCS loop2
+
+loop3:
+	BODY(0,FN3,0x8f1bbcdc,AX,BX,CX,DX,SI)
+	BODY(4,FN3,0x8f1bbcdc,SI,AX,BX,CX,DX)
+	BODY(8,FN3,0x8f1bbcdc,DX,SI,AX,BX,CX)
+	BODY(12,FN3,0x8f1bbcdc,CX,DX,SI,AX,BX)
+	BODY(16,FN3,0x8f1bbcdc,BX,CX,DX,SI,AX)
+
+	ADDQ $20,BP
+	CMPQ BP,w60+W60(SP)
+	JCS loop3
+
+loop4:
+	BODY(0,FN24,0xca62c1d6,AX,BX,CX,DX,SI)
+	BODY(4,FN24,0xca62c1d6,SI,AX,BX,CX,DX)
+	BODY(8,FN24,0xca62c1d6,DX,SI,AX,BX,CX)
+	BODY(12,FN24,0xca62c1d6,CX,DX,SI,AX,BX)
+	BODY(16,FN24,0xca62c1d6,BX,CX,DX,SI,AX)
+
+	ADDQ $20,BP
+	CMPQ BP,w80+W80(SP)
+	JCS loop4
+
+	MOVQ state+STATE(FP),DI
+	ADDL AX,0(DI)
+	ADDL BX,4(DI)
+	ADDL CX,8(DI)
+	ADDL DX,12(DI)
+	ADDL SI,16(DI)
+
+	MOVQ edata+EDATA(SP),DI
+	CMPQ data+DATA(FP),DI
+	JCS mainloop
+
+	RET
+	END
--- a/mkfile
+++ b/mkfile
@@ -94,6 +94,13 @@
 		@{builtin cd $j; mk $MKFLAGS $stem }
 	}
 
+&-9front:QV:
+	for (j in $DIRS utils)
+	{
+		echo '@{builtin cd' $j '; mk $MKFLAGS $stem}'
+		@{builtin cd $j; mk $MKFLAGS $stem }
+	}
+
 emu/&-Posix:QV:
 	for j in $EMUDIRS
 	do
@@ -115,6 +122,13 @@
 		@{builtin cd $j; mk $MKFLAGS $stem }
 	}
 
+emu/&-9front:QV:
+	for (j in $EMUDIRS)
+	{
+		echo '@{builtin cd' $j '; mk $MKFLAGS $stem}'
+		@{builtin cd $j; mk $MKFLAGS $stem }
+	}
+
 kernel/&-Posix:QV:
 	for j in $KERNEL_DIRS
 	do
@@ -143,6 +157,13 @@
 		@{builtin cd $j; mk $MKFLAGS $stem }
 	}
 
+kernel/&-9front:QV:
+	for (j in $KERNEL_DIRS)
+	{
+		echo '@{builtin cd' $j '; mk $MKFLAGS $stem}'
+		@{builtin cd $j; mk $MKFLAGS $stem }
+	}
+
 # Convenience targets
 
 Inferno-% inferno-% Inferno-386-% inferno-386-%:V:
@@ -153,6 +174,9 @@
 
 Plan9-% plan9-%:V:
 	mk 'SYSHOST=Plan9' 'OBJTYPE=386' $stem
+
+9front-% 9front-%:V:
+	mk 'SYSHOST=9front' 'OBJTYPE=amd64' $stem
 
 Irix-% irix-%:V:
 	mk 'SYSHOST=Irix' 'OBJTYPE=mips' $stem
--- /dev/null
+++ b/mkfiles/mkfile-9front-amd64
@@ -1,0 +1,24 @@
+TARGMODEL=	9front
+TARGSHTYPE=	rc
+CPUS=		386 sparc mips power amd64
+
+O=		6
+OS=		v851ok0q26
+
+AR=		ar
+ARFLAGS=	vu
+
+AS=		6a
+ASFLAGS=
+
+CC=		6c
+CFLAGS=		-wFV -I$ROOT/9front/$OBJTYPE/include -I$ROOT/9front/include -I$ROOT/include
+ANSICPP= -p
+
+LD=		6l
+LDFLAGS=
+
+SYSLIBS=-lc
+
+YACC=		yacc
+YFLAGS=		-d
--- /dev/null
+++ b/mkfiles/mkhost-9front
@@ -1,0 +1,12 @@
+
+#	Variables for host system type = Plan9
+
+SHELLTYPE=	rc
+SHELLNAME=	rc
+HOSTMODEL=	9front
+OSTARG=		Inferno
+
+DATA2S=	data2s
+NDATE=		date -n
+KSIZE=		size
+AWK=		awk
--- /dev/null
+++ b/utils/acid/os-9front.c
@@ -1,0 +1,157 @@
+/*
+ * Plan9
+ */
+
+#include <lib9.h>
+#include <bio.h>
+#include <ctype.h>
+#include "mach.h"
+#define Extern extern
+#include "acid.h"
+
+int
+opentty(char *tty, int baud)
+{
+	int fd, cfd;
+	char ctty[100];
+
+	if(tty == 0)
+		tty = "/dev/eia0";
+	sprint(ctty, "%sctl", tty);
+	fd = open(tty, 2);
+	if(fd < 0)
+		return -1;
+	if(baud){
+		cfd = open(ctty, 1);
+		if(cfd < 0)
+			return fd;
+		fprint(cfd, "b%d", baud);
+		close(cfd);
+	}
+	return fd;
+}
+
+void
+detach(void)
+{
+	rfork(RFNAMEG|RFNOTEG|RFREND);
+}
+
+char *
+waitfor(int pid)
+{
+	Waitmsg *w;
+	static char buf[ERRMAX];
+
+	for(;;) {
+		w = wait();
+		if(w == nil)
+			error("wait %r");
+		if(w->pid == pid){
+			strecpy(buf, buf+ERRMAX, w->msg);
+			free(w);
+			return buf;
+		}
+		free(w);
+	}
+	/* not reached */
+}
+
+char *
+runcmd(char *cmd)
+{
+	char *argv[4];
+	int pid;
+
+	argv[0] = "/bin/rc";
+	argv[1] = "-c";
+	argv[2] = cmd;
+	argv[3] = 0;
+
+	pid = fork();
+	switch(pid) {
+	case -1:
+		error("fork %r");
+	case 0:
+		exec("/bin/rc", argv);
+		exits(0);
+	default:
+		return waitfor(pid);
+	}
+	/* not reached */
+}
+
+void
+catcher(void *junk, char *s)
+{
+	USED(junk);
+
+	if(strstr(s, "interrupt")) {
+		gotint = 1;
+		noted(NCONT);
+	}
+	noted(NDFLT);
+}
+
+void (*notefunc)(void *, char *);
+
+void
+setup_os_notify(void)
+{
+	notify(catcher);
+}
+
+int
+nproc(char **argv)
+{
+	char buf[128];
+	int pid, i, fd;
+
+	pid = fork();
+	switch(pid) {
+	case -1:
+		error("new: fork %r");
+	case 0:
+		rfork(RFNAMEG|RFNOTEG);
+
+		sprint(buf, "/proc/%d/ctl", getpid());
+		fd = open(buf, ORDWR);
+		if(fd < 0)
+			fatal("new: open %s: %r", buf);
+		write(fd, "hang", 4);
+		close(fd);
+
+		close(0);
+		close(1);
+		close(2);
+		for(i = 3; i < NFD; i++)
+			close(i);
+
+		open("/dev/cons", OREAD);
+		open("/dev/cons", OWRITE);
+		open("/dev/cons", OWRITE);
+		exec(argv[0], argv);
+		fatal("new: exec %s: %r");
+	default:
+		install(pid);
+		msg(pid, "waitstop");
+		notes(pid);
+		sproc(pid);
+		dostop(pid);
+		break;
+	}
+
+	return pid;
+}
+
+int
+remote_read(int fd, char *buf, int bytes)
+{
+	return read(fd, buf, bytes);
+}
+
+int
+remote_write(int fd, char *buf, int bytes)
+{
+	return write(fd, buf, bytes);
+}
--- /dev/null
+++ b/utils/c2l/9front.c
@@ -1,0 +1,108 @@
+#include	"cc.h"
+
+void*
+mysbrk(ulong size)
+{
+	return sbrk(size);
+}
+
+int
+mycreat(char *n, int p)
+{
+
+	return create(n, 1, p);
+}
+
+int
+mywait(int *s)
+{
+	int p;
+	Waitmsg *w;
+
+	if((w = wait()) == nil)
+		return -1;
+	else{
+		p = w->pid;
+		*s = 0;
+		if(w->msg[0])
+			*s = 1;
+		free(w);
+		return p;
+	}
+}
+
+int
+mydup(int f1, int f2)
+{
+	return dup(f1,f2);
+}
+
+int
+mypipe(int *fd)
+{
+	return pipe(fd);
+}
+
+int
+systemtype(int sys)
+{
+
+	return sys&Plan9;
+}
+
+int
+pathchar(void)
+{
+	return '/';
+}
+
+char*
+mygetwd(char *path, int len)
+{
+	return getwd(path, len);
+}
+
+int
+myexec(char *path, char *argv[])
+{
+	return exec(path, argv);
+}
+
+/*
+ * fake mallocs
+ */
+void*
+malloc(ulong n)
+{
+	return alloc(n);
+}
+
+void*
+calloc(ulong m, ulong n)
+{
+	return alloc(m*n);
+}
+
+void*
+realloc(void*, ulong)
+{
+	fprint(2, "realloc called\n");
+	abort();
+	return 0;
+}
+
+void
+free(void*)
+{
+}
+
+int
+myfork(void)
+{
+	return fork();
+}
+
+void
+setmalloctag(void*, uintptr)
+{
+}
--- /dev/null
+++ b/utils/cc/9front.c
@@ -1,0 +1,114 @@
+#include	"cc.h"
+
+void*
+mysbrk(ulong size)
+{
+	return sbrk(size);
+}
+
+int
+mycreat(char *n, int p)
+{
+
+	return create(n, 1, p);
+}
+
+int
+mywait(int *s)
+{
+	int p;
+	Waitmsg *w;
+
+	if((w = wait()) == nil)
+		return -1;
+	else{
+		p = w->pid;
+		*s = 0;
+		if(w->msg[0])
+			*s = 1;
+		free(w);
+		return p;
+	}
+}
+
+int
+mydup(int f1, int f2)
+{
+	return dup(f1,f2);
+}
+
+int
+mypipe(int *fd)
+{
+	return pipe(fd);
+}
+
+int
+systemtype(int sys)
+{
+
+	return sys&Plan9;
+}
+
+int
+pathchar(void)
+{
+	return '/';
+}
+
+char*
+mygetwd(char *path, int len)
+{
+	return getwd(path, len);
+}
+
+int
+myexec(char *path, char *argv[])
+{
+	return exec(path, argv);
+}
+
+int
+myfork(void)
+{
+	return fork();
+}
+
+/*
+ * fake mallocs
+ */
+void*
+malloc(ulong n)
+{
+	return alloc(n);
+}
+
+void*
+calloc(ulong m, ulong n)
+{
+	return alloc(m*n);
+}
+
+void*
+realloc(void*, ulong)
+{
+	fprint(2, "realloc called\n");
+	abort();
+	return 0;
+}
+
+void
+free(void*)
+{
+}
+
+int
+myaccess(char *f)
+{
+	return access(f, AEXIST);
+}
+
+void
+setmalloctag(void*, uintptr)
+{
+}
--- /dev/null
+++ b/utils/iar/9front.c
@@ -1,0 +1,7 @@
+#include	<lib9.h>
+
+char *
+myctime(long x)
+{
+	return ctime(x);
+}
--- /dev/null
+++ b/utils/mk/mkfile-9front
@@ -1,0 +1,3 @@
+#
+#	install rule for Inferno/Plan9 - use the default
+#
--- a/utils/mkfile
+++ b/utils/mkfile
@@ -92,6 +92,15 @@
 		} || test ! -e $j
 	}
 
+%-9front:QV:
+	for (j in $ALWAYS)
+	{
+		test -d $j && {
+			echo '@{cd' $j '; mk $MKFLAGS $stem}'
+			@{cd $j; mk $MKFLAGS $stem }
+		} || test ! -e $j
+	}
+
 %-Posix:QV:
 	for j in  $ALWAYS $NOTPLAN9
 	do
--- /dev/null
+++ b/utils/srclist/9front.c
@@ -1,0 +1,7 @@
+#include	"lib9.h"
+
+char*
+mygetwd(char *path, int len)
+{
+	return getwd(path, len);
+}