diff --git a/src/cmd/5g/galign.c b/src/cmd/5g/galign.c
index 62f435e0e35a4b80c06986b2b5f649e40b0826a4..14d323fa7eff2a92d92896d41c137e383625f6f3 100644
--- a/src/cmd/5g/galign.c
+++ b/src/cmd/5g/galign.c
@@ -29,6 +29,7 @@ betypeinit(void)
 {
 	widthptr = 4;
 	widthint = 4;
+	widthreg = 4;
 
 	zprog.link = P;
 	zprog.as = AGOK;
diff --git a/src/cmd/6g/cgen.c b/src/cmd/6g/cgen.c
index 5afa25e4032b62b2617b70c2304e17d857f88716..e1b5d1140ee8a5d57553b2ddf4ccfdccfa23b9fa 100644
--- a/src/cmd/6g/cgen.c
+++ b/src/cmd/6g/cgen.c
@@ -1417,23 +1417,23 @@ sgen(Node *n, Node *ns, int64 w)
 		// reverse direction
 		gins(ASTD, N, N);		// set direction flag
 		if(c > 0) {
-			gconreg(AADDQ, w-1, D_SI);
-			gconreg(AADDQ, w-1, D_DI);
+			gconreg(addptr, w-1, D_SI);
+			gconreg(addptr, w-1, D_DI);
 
-			gconreg(AMOVQ, c, D_CX);
+			gconreg(movptr, c, D_CX);
 			gins(AREP, N, N);	// repeat
 			gins(AMOVSB, N, N);	// MOVB *(SI)-,*(DI)-
 		}
 
 		if(q > 0) {
 			if(c > 0) {
-				gconreg(AADDQ, -7, D_SI);
-				gconreg(AADDQ, -7, D_DI);
+				gconreg(addptr, -7, D_SI);
+				gconreg(addptr, -7, D_DI);
 			} else {
-				gconreg(AADDQ, w-8, D_SI);
-				gconreg(AADDQ, w-8, D_DI);
+				gconreg(addptr, w-8, D_SI);
+				gconreg(addptr, w-8, D_DI);
 			}
-			gconreg(AMOVQ, q, D_CX);
+			gconreg(movptr, q, D_CX);
 			gins(AREP, N, N);	// repeat
 			gins(AMOVSQ, N, N);	// MOVQ *(SI)-,*(DI)-
 		}
@@ -1442,7 +1442,7 @@ sgen(Node *n, Node *ns, int64 w)
 	} else {
 		// normal direction
 		if(q >= 4) {
-			gconreg(AMOVQ, q, D_CX);
+			gconreg(movptr, q, D_CX);
 			gins(AREP, N, N);	// repeat
 			gins(AMOVSQ, N, N);	// MOVQ *(SI)+,*(DI)+
 		} else
diff --git a/src/cmd/6g/galign.c b/src/cmd/6g/galign.c
index 3ea57d761640cefb81861f64e001a866dfa5167f..ec37ceb23308f764997c70c9397db8d360279d3d 100644
--- a/src/cmd/6g/galign.c
+++ b/src/cmd/6g/galign.c
@@ -12,6 +12,12 @@ LinkArch*	thelinkarch = &linkamd64;
 
 vlong MAXWIDTH = 1LL<<50;
 
+int	addptr = AADDQ;
+int	movptr = AMOVQ;
+int	leaptr = ALEAQ;
+int	stosptr = ASTOSQ;
+int	cmpptr = ACMPQ;
+
 /*
  * go declares several platform-specific type aliases:
  * int, uint, float, and uintptr
@@ -29,6 +35,20 @@ betypeinit(void)
 {
 	widthptr = 8;
 	widthint = 8;
+	widthreg = 8;
+	if(strcmp(getgoarch(), "amd64p32") == 0) {
+		widthptr = 4;
+		widthint = 4;
+		addptr = AADDL;
+		movptr = AMOVL;
+		leaptr = ALEAL;
+		stosptr = ASTOSL;
+		cmpptr = ACMPL;
+		typedefs[0].sameas = TINT32;
+		typedefs[1].sameas = TUINT32;
+		typedefs[2].sameas = TUINT32;
+		
+	}
 
 	zprog.link = P;
 	zprog.as = AGOK;
diff --git a/src/cmd/6g/gg.h b/src/cmd/6g/gg.h
index a3c5faf6c42075ca29854bca7893e4e59ef9964c..0bc8885cf3ee6ce7d796b928dff5cb892910b685 100644
--- a/src/cmd/6g/gg.h
+++ b/src/cmd/6g/gg.h
@@ -21,8 +21,14 @@ EXTERN	Node*	deferproc;
 EXTERN	Node*	deferreturn;
 EXTERN	Node*	panicindex;
 EXTERN	Node*	panicslice;
+EXTERN	Node*	panicdiv;
 EXTERN	Node*	throwreturn;
 extern	vlong	unmappedzero;
+extern	int	addptr;
+extern	int	cmpptr;
+extern	int	movptr;
+extern	int	leaptr;
+extern	int	stosptr;
 
 /*
  * ggen.c
diff --git a/src/cmd/6g/ggen.c b/src/cmd/6g/ggen.c
index b5c28bb089b1607346bd5384809804299a02f039..8b0c287400391fe976d4117d8ce756e272bb972a 100644
--- a/src/cmd/6g/ggen.c
+++ b/src/cmd/6g/ggen.c
@@ -180,17 +180,21 @@ ginscall(Node *f, int proc)
 
 	case 1:	// call in new proc (go)
 	case 2:	// deferred call (defer)
-		nodreg(&reg, types[TINT64], D_CX);
-		if(flag_largemodel) {
-			regalloc(&r1, f->type, f);
+		nodconst(&con, types[TINT64], argsize(f->type));
+		if(widthptr == 4) {
+			nodreg(&r1, types[TINT32], D_CX);
 			gmove(f, &r1);
-			gins(APUSHQ, &r1, N);
-			regfree(&r1);
+			nodreg(&reg, types[TINT64], D_CX);
+			nodconst(&r1, types[TINT64], 32);
+			gins(ASHLQ, &r1, &reg);
+			gins(AORQ, &con, &reg);
+			gins(APUSHQ, &reg, N);
 		} else {
-			gins(APUSHQ, f, N);
+			nodreg(&reg, types[TINT64], D_CX);
+			gmove(f, &reg);
+			gins(APUSHQ, &reg, N);
+			gins(APUSHQ, &con, N);
 		}
-		nodconst(&con, types[TINT32], argsize(f->type));
-		gins(APUSHQ, &con, N);
 		if(proc == 1)
 			ginscall(newproc, 0);
 		else {
@@ -198,8 +202,10 @@ ginscall(Node *f, int proc)
 				fatal("hasdefer=0 but has defer");
 			ginscall(deferproc, 0);
 		}
+		nodreg(&reg, types[TINT64], D_CX);
 		gins(APOPQ, N, &reg);
-		gins(APOPQ, N, &reg);
+		if(widthptr == 8)
+			gins(APOPQ, N, &reg);
 		if(proc == 2) {
 			nodreg(&reg, types[TINT64], D_AX);
 			gins(ATESTQ, &reg, &reg);
@@ -387,11 +393,11 @@ cgen_aret(Node *n, Node *res)
 
 	if(res->op != OREGISTER) {
 		regalloc(&nod2, types[tptr], res);
-		gins(ALEAQ, &nod1, &nod2);
-		gins(AMOVQ, &nod2, res);
+		gins(leaptr, &nod1, &nod2);
+		gins(movptr, &nod2, res);
 		regfree(&nod2);
 	} else
-		gins(ALEAQ, &nod1, res);
+		gins(leaptr, &nod1, res);
 }
 
 /*
@@ -634,6 +640,18 @@ dodiv(int op, Node *nl, Node *nr, Node *res)
 	}
 
 	p2 = P;
+	if(nacl) {
+		// Native Client does not relay the divide-by-zero trap
+		// to the executing program, so we must insert a check
+		// for ourselves.
+		nodconst(&n4, t, 0);
+		gins(optoas(OCMP, t), &n3, &n4);
+		p1 = gbranch(optoas(ONE, t), T, +1);
+		if(panicdiv == N)
+			panicdiv = sysfunc("panicdivide");
+		ginscall(panicdiv, -1);
+		patch(p1, pc);
+	}
 	if(check) {
 		nodconst(&n4, t, -1);
 		gins(optoas(OCMP, t), &n3, &n4);
@@ -1045,10 +1063,10 @@ clearfat(Node *nl)
 	agen(nl, &n1);
 
 	savex(D_AX, &ax, &oldax, N, types[tptr]);
-	gconreg(AMOVQ, 0, D_AX);
+	gconreg(AMOVL, 0, D_AX);
 
 	if(q >= 4) {
-		gconreg(AMOVQ, q, D_CX);
+		gconreg(movptr, q, D_CX);
 		gins(AREP, N, N);	// repeat
 		gins(ASTOSQ, N, N);	// STOQ AL,*(DI)+
 	} else
@@ -1111,7 +1129,7 @@ expandchecks(Prog *firstp)
 		p2->lineno = p->lineno;
 		p1->pc = 9999;
 		p2->pc = 9999;
-		p->as = ACMPQ;
+		p->as = cmpptr;
 		p->to.type = D_CONST;
 		p->to.offset = 0;
 		p1->as = AJNE;
diff --git a/src/cmd/6g/gsubr.c b/src/cmd/6g/gsubr.c
index f4861ceecf0f141d0030c27121a820c6186d3536..e8a62fb8a61fc32cf72937474f2c7b6e5678a620 100644
--- a/src/cmd/6g/gsubr.c
+++ b/src/cmd/6g/gsubr.c
@@ -296,6 +296,11 @@ ginit(void)
 
 	for(i=0; i<nelem(resvd); i++)
 		reg[resvd[i]]++;
+	
+	if(nacl) {
+		reg[D_BP]++;
+		reg[D_R15]++;
+	}
 }
 
 void
@@ -305,6 +310,11 @@ gclean(void)
 
 	for(i=0; i<nelem(resvd); i++)
 		reg[resvd[i]]--;
+	if(nacl) {
+		reg[D_BP]--;
+		reg[D_R15]--;
+	}
+
 
 	for(i=D_AX; i<=D_R15; i++)
 		if(reg[i])
@@ -520,7 +530,16 @@ gconreg(int as, vlong c, int reg)
 {
 	Node nr;
 
-	nodreg(&nr, types[TINT64], reg);
+	switch(as) {
+	case AADDL:
+	case AMOVL:
+	case ALEAL:
+		nodreg(&nr, types[TINT32], reg);
+		break;
+	default:
+		nodreg(&nr, types[TINT64], reg);
+	}
+
 	ginscon(as, c, &nr);
 }
 
@@ -533,10 +552,18 @@ ginscon(int as, vlong c, Node *n2)
 {
 	Node n1, ntmp;
 
-	nodconst(&n1, types[TINT64], c);
+	switch(as) {
+	case AADDL:
+	case AMOVL:
+	case ALEAL:
+		nodconst(&n1, types[TINT32], c);
+		break;
+	default:
+		nodconst(&n1, types[TINT64], c);
+	}
 
 	if(as != AMOVQ && (c < -(1LL<<31) || c >= 1LL<<31)) {
-		// cannot have 64-bit immediokate in ADD, etc.
+		// cannot have 64-bit immediate in ADD, etc.
 		// instead, MOV into register first.
 		regalloc(&ntmp, types[TINT64], N);
 		gins(AMOVQ, &n1, &ntmp);
@@ -2040,7 +2067,7 @@ odot:
 	for(i=1; i<o; i++) {
 		if(oary[i] >= 0)
 			fatal("can't happen");
-		gins(AMOVQ, &n1, reg);
+		gins(movptr, &n1, reg);
 		cgen_checknil(reg);
 		n1.xoffset = -(oary[i]+1);
 	}
@@ -2252,7 +2279,7 @@ oindex_const_sudo:
 	if(reg->op == OEMPTY)
 		regalloc(reg, types[tptr], N);
 
-	p1 = gins(AMOVQ, N, reg);
+	p1 = gins(movptr, N, reg);
 	p1->from = *a;
 
 	n2 = *reg;
diff --git a/src/cmd/6g/prog.c b/src/cmd/6g/prog.c
index 76c9be14fc120e61e9ced78d8db6af7c59f02f0d..8fe759d79ab1a04bfe01dfc201b94024da8387c9 100644
--- a/src/cmd/6g/prog.c
+++ b/src/cmd/6g/prog.c
@@ -143,6 +143,7 @@ static ProgInfo progtable[ALAST] = {
 
 	[AJMP]=		{Jump | Break | KillCarry},
 
+	[ALEAL]=	{LeftAddr | RightWrite},
 	[ALEAQ]=	{LeftAddr | RightWrite},
 
 	[AMOVBLSX]=	{SizeL | LeftRead | RightWrite | Conv},
diff --git a/src/cmd/6g/reg.c b/src/cmd/6g/reg.c
index 45bc4a2670cf5e3a3d29689561be2013477983e3..eadd1cadc25311e243210fd611b502f46f2260d3 100644
--- a/src/cmd/6g/reg.c
+++ b/src/cmd/6g/reg.c
@@ -487,7 +487,7 @@ addmove(Reg *r, int bn, int rn, int f)
 	// need to clean this up with wptr and
 	// some of the defaults
 	p1->as = AMOVL;
-	switch(v->etype) {
+	switch(simtype[(uchar)v->etype]) {
 	default:
 		fatal("unknown type %E", v->etype);
 	case TINT8:
@@ -501,7 +501,6 @@ addmove(Reg *r, int bn, int rn, int f)
 		break;
 	case TINT64:
 	case TUINT64:
-	case TUINTPTR:
 	case TPTR64:
 		p1->as = AMOVQ;
 		break;
@@ -511,8 +510,6 @@ addmove(Reg *r, int bn, int rn, int f)
 	case TFLOAT64:
 		p1->as = AMOVSD;
 		break;
-	case TINT:
-	case TUINT:
 	case TINT32:
 	case TUINT32:
 	case TPTR32:
@@ -1088,6 +1085,8 @@ int
 BtoR(int32 b)
 {
 	b &= 0xffffL;
+	if(nacl)
+		b &= ~((1<<(D_BP-D_AX)) | (1<<(D_R15-D_AX)));
 	if(b == 0)
 		return 0;
 	return bitno(b) + D_AX;
diff --git a/src/cmd/8g/galign.c b/src/cmd/8g/galign.c
index f8197c895ff85ec49519f67afd8d97431db81203..439e741553f60f847f684d2a4c479ad313e9cb36 100644
--- a/src/cmd/8g/galign.c
+++ b/src/cmd/8g/galign.c
@@ -29,6 +29,7 @@ betypeinit(void)
 {
 	widthptr = 4;
 	widthint = 4;
+	widthreg = 4;
 
 	zprog.link = P;
 	zprog.as = AGOK;
diff --git a/src/cmd/8g/gg.h b/src/cmd/8g/gg.h
index 3830f31d93a50cdc14c7b9bde5d271d7f7032309..8a2fcb67722f6675cfac2997a58084329bf43726 100644
--- a/src/cmd/8g/gg.h
+++ b/src/cmd/8g/gg.h
@@ -29,6 +29,7 @@ EXTERN	Node*	deferproc;
 EXTERN	Node*	deferreturn;
 EXTERN	Node*	panicindex;
 EXTERN	Node*	panicslice;
+EXTERN	Node*	panicdiv;
 EXTERN	Node*	throwreturn;
 EXTERN	int	maxstksize;
 extern	uint32	unmappedzero;
diff --git a/src/cmd/8g/ggen.c b/src/cmd/8g/ggen.c
index b3e2665ca4e94fa7f87bdd7ecb585b548ee205ba..f761fa6b03e245ee13d9d290d9cd317761280d29 100644
--- a/src/cmd/8g/ggen.c
+++ b/src/cmd/8g/ggen.c
@@ -664,6 +664,18 @@ dodiv(int op, Node *nl, Node *nr, Node *res, Node *ax, Node *dx)
 	gmove(&t2, &n1);
 	gmove(&t1, ax);
 	p2 = P;
+	if(nacl) {
+		// Native Client does not relay the divide-by-zero trap
+		// to the executing program, so we must insert a check
+		// for ourselves.
+		nodconst(&n4, t, 0);
+		gins(optoas(OCMP, t), &n1, &n4);
+		p1 = gbranch(optoas(ONE, t), T, +1);
+		if(panicdiv == N)
+			panicdiv = sysfunc("panicdivide");
+		ginscall(panicdiv, -1);
+		patch(p1, pc);
+	}
 	if(check) {
 		nodconst(&n4, t, -1);
 		gins(optoas(OCMP, t), &n1, &n4);
diff --git a/src/cmd/dist/build.c b/src/cmd/dist/build.c
index dff0a6e11d4f5c6bb37700ac0cea6a7448c03a8c..e79b7188e0fa550cd649d89266c7844b75334197 100644
--- a/src/cmd/dist/build.c
+++ b/src/cmd/dist/build.c
@@ -38,13 +38,14 @@ static void dopack(char*, char*, char**, int);
 static char *findgoversion(void);
 
 // The known architecture letters.
-static char *gochars = "568";
+static char *gochars = "5668";
 
 // The known architectures.
 static char *okgoarch[] = {
 	// same order as gochars
 	"arm",
 	"amd64",
+	"amd64p32",
 	"386",
 };
 
@@ -55,6 +56,7 @@ static char *okgoos[] = {
 	"linux",
 	"solaris",
 	"freebsd",
+	"nacl",
 	"netbsd",
 	"openbsd",
 	"plan9",
diff --git a/src/cmd/gc/align.c b/src/cmd/gc/align.c
index 8e9677e75b6e73cc69647f6577411fd08bdb0c74..b809640e4227a71b610c4489039185a3e06f410b 100644
--- a/src/cmd/gc/align.c
+++ b/src/cmd/gc/align.c
@@ -175,11 +175,11 @@ dowidth(Type *t)
 	case TFLOAT64:
 	case TCOMPLEX64:
 		w = 8;
-		t->align = widthptr;
+		t->align = widthreg;
 		break;
 	case TCOMPLEX128:
 		w = 16;
-		t->align = widthptr;
+		t->align = widthreg;
 		break;
 	case TPTR32:
 		w = 4;
@@ -288,10 +288,10 @@ dowidth(Type *t)
 		// compute their widths as side-effect.
 		t1 = t->type;
 		w = widstruct(t->type, *getthis(t1), 0, 0);
-		w = widstruct(t->type, *getinarg(t1), w, widthptr);
-		w = widstruct(t->type, *getoutarg(t1), w, widthptr);
+		w = widstruct(t->type, *getinarg(t1), w, widthreg);
+		w = widstruct(t->type, *getoutarg(t1), w, widthreg);
 		t1->argwid = w;
-		if(w%widthptr)
+		if(w%widthreg)
 			warn("bad type %T %d\n", t1, w);
 		t->align = 1;
 		break;
diff --git a/src/cmd/gc/builtin.c b/src/cmd/gc/builtin.c
index 4955231c20231a18e609b7078069754a0491bd46..1f4aed5baa404e856ac0c76f62a3f0d24f6896e4 100644
--- a/src/cmd/gc/builtin.c
+++ b/src/cmd/gc/builtin.c
@@ -5,6 +5,7 @@ char *runtimeimport =
 	"func @\"\".new (@\"\".typ·2 *byte) (? *any)\n"
 	"func @\"\".panicindex ()\n"
 	"func @\"\".panicslice ()\n"
+	"func @\"\".panicdivide ()\n"
 	"func @\"\".throwreturn ()\n"
 	"func @\"\".throwinit ()\n"
 	"func @\"\".panicwrap (? string, ? string, ? string)\n"
diff --git a/src/cmd/gc/go.h b/src/cmd/gc/go.h
index e5d12a83450f6c2ada2c2437ce01ce90d2eb936e..68ec37bee33d382b7f59427dc9811b12d06b3486 100644
--- a/src/cmd/gc/go.h
+++ b/src/cmd/gc/go.h
@@ -950,6 +950,7 @@ EXTERN	Node*	curfn;
 
 EXTERN	int	widthptr;
 EXTERN	int	widthint;
+EXTERN	int	widthreg;
 
 EXTERN	Node*	typesw;
 EXTERN	Node*	nblank;
@@ -982,6 +983,8 @@ EXTERN	int	writearchive;
 
 EXTERN	Biobuf	bstdout;
 
+EXTERN	int	nacl;
+
 /*
  *	y.tab.c
  */
diff --git a/src/cmd/gc/lex.c b/src/cmd/gc/lex.c
index 2a817f3d9a5227fe9ff24b01d067bf738580518f..90def10b8205ee853af4b3d0aabdf921d91130a5 100644
--- a/src/cmd/gc/lex.c
+++ b/src/cmd/gc/lex.c
@@ -258,8 +258,18 @@ main(int argc, char *argv[])
 
 	goroot = getgoroot();
 	goos = getgoos();
-	goarch = thestring;
+
+	// Allow GOARCH=thestring or GOARCH=thestringsuffix,
+	// but not other values.	
+	p = getgoarch();
+	if(strncmp(p, thestring, strlen(thestring)) != 0)
+		fatal("cannot use %cg with GOARCH=%s", thechar, p);
+	goarch = p;
 	
+	nacl = strcmp(goos, "nacl") == 0;
+	if(nacl)
+		flag_largemodel = 1;
+
 	setexp();
 
 	outfile = nil;
@@ -779,7 +789,7 @@ importfile(Val *f, int line)
 			yyerror("import %s: not a go object file", file);
 			errorexit();
 		}
-		q = smprint("%s %s %s %s", getgoos(), thestring, getgoversion(), expstring());
+		q = smprint("%s %s %s %s", getgoos(), getgoarch(), getgoversion(), expstring());
 		if(strcmp(p+10, q) != 0) {
 			yyerror("import %s: object is [%s] expected [%s]", file, p+10, q);
 			errorexit();
diff --git a/src/cmd/gc/obj.c b/src/cmd/gc/obj.c
index 635a30d4027e293c05f3e582d0e21c648afe48fd..c7315e0f76573392ac7cc443e03dce3ac5a32380 100644
--- a/src/cmd/gc/obj.c
+++ b/src/cmd/gc/obj.c
@@ -47,7 +47,7 @@ dumpobj(void)
 		Bwrite(bout, arhdr, sizeof arhdr);
 		startobj = Boffset(bout);
 	}
-	Bprint(bout, "go object %s %s %s %s\n", getgoos(), thestring, getgoversion(), expstring());
+	Bprint(bout, "go object %s %s %s %s\n", getgoos(), getgoarch(), getgoversion(), expstring());
 	dumpexport();
 	
 	if(writearchive) {
diff --git a/src/cmd/gc/pgen.c b/src/cmd/gc/pgen.c
index 62153cb52449ec5a3cf9c11448bdc873950a767f..1048a62cc8bb158f9f10b1d602e90aa90081dc3a 100644
--- a/src/cmd/gc/pgen.c
+++ b/src/cmd/gc/pgen.c
@@ -426,7 +426,7 @@ allocauto(Prog* ptxt)
 		}
 		n->stkdelta = -stksize - n->xoffset;
 	}
-	stksize = rnd(stksize, widthptr);
+	stksize = rnd(stksize, widthreg);
 	stkptrsize = rnd(stkptrsize, widthptr);
 	stkzerosize = rnd(stkzerosize, widthptr);
 
diff --git a/src/cmd/gc/reflect.c b/src/cmd/gc/reflect.c
index 68b21772451c34dfed2b371fd6efd26173de2374..88ef57f409b3cff8f44fe29a4f036b49c2b0448f 100644
--- a/src/cmd/gc/reflect.c
+++ b/src/cmd/gc/reflect.c
@@ -143,6 +143,11 @@ mapbucket(Type *t)
 	overflowfield->sym = mal(sizeof(Sym)); // not important but needs to be set to give this type a name
 	overflowfield->sym->name = "overflow";
 	offset += widthptr;
+	
+	// The keys are padded to the native integer alignment.
+	// This is usually the same as widthptr; the exception (as usual) is nacl/amd64.
+	if(widthreg > widthptr)
+		offset += widthreg - widthptr;
 
 	keysfield = typ(TFIELD);
 	keysfield->type = typ(TARRAY);
diff --git a/src/cmd/gc/runtime.go b/src/cmd/gc/runtime.go
index c65365f55ae05e9763df18f437679dcaa42915f3..9ea4a79fd3bbe11b906210d5d79c270c8ebec13b 100644
--- a/src/cmd/gc/runtime.go
+++ b/src/cmd/gc/runtime.go
@@ -15,6 +15,7 @@ package PACKAGE
 func new(typ *byte) *any
 func panicindex()
 func panicslice()
+func panicdivide()
 func throwreturn()
 func throwinit()
 func panicwrap(string, string, string)
diff --git a/src/cmd/gc/walk.c b/src/cmd/gc/walk.c
index 068e38cf3ba69f088a7fc8145abee533233674d4..717c771336c39bf847302377496c1ab659e05d4e 100644
--- a/src/cmd/gc/walk.c
+++ b/src/cmd/gc/walk.c
@@ -1059,7 +1059,7 @@ walkexpr(Node **np, NodeList **init)
 		switch(n->op) {
 		case OMOD:
 		case ODIV:
-			if(widthptr > 4 || (et != TUINT64 && et != TINT64))
+			if(widthreg >= 8 || (et != TUINT64 && et != TINT64))
 				goto ret;
 			if(et == TINT64)
 				strcpy(namebuf, "int64");
diff --git a/src/cmd/go/build.go b/src/cmd/go/build.go
index dcc24d99c42979ca97afdeeef9c92571e93581b4..6c9b9f7e50369638f6daecbc1bbd9551ffa5a76b 100644
--- a/src/cmd/go/build.go
+++ b/src/cmd/go/build.go
@@ -204,6 +204,9 @@ type stringsFlag []string
 func (v *stringsFlag) Set(s string) error {
 	var err error
 	*v, err = splitQuotedFields(s)
+	if *v == nil {
+		*v = []string{}
+	}
 	return err
 }
 
diff --git a/src/cmd/go/run.go b/src/cmd/go/run.go
index 8d42622b8660168c52f546d52a882f420f912013..b6449713dfa200deb8c38ac2fdddc9627051d553 100644
--- a/src/cmd/go/run.go
+++ b/src/cmd/go/run.go
@@ -8,9 +8,27 @@ import (
 	"fmt"
 	"os"
 	"os/exec"
+	"runtime"
 	"strings"
 )
 
+var execCmd []string // -exec flag, for run and test
+
+func findExecCmd() []string {
+	if execCmd != nil {
+		return execCmd
+	}
+	execCmd = []string{} // avoid work the second time
+	if goos == runtime.GOOS && goarch == runtime.GOARCH {
+		return execCmd
+	}
+	path, err := exec.LookPath(fmt.Sprintf("go_%s_%s_exec", goos, goarch))
+	if err == nil {
+		execCmd = []string{path}
+	}
+	return execCmd
+}
+
 var cmdRun = &Command{
 	UsageLine: "run [build flags] gofiles... [arguments...]",
 	Short:     "compile and run Go program",
@@ -28,6 +46,7 @@ func init() {
 	cmdRun.Run = runRun // break init loop
 
 	addBuildFlags(cmdRun)
+	cmdRun.Flag.Var((*stringsFlag)(&execCmd), "exec", "")
 }
 
 func printStderr(args ...interface{}) (int, error) {
@@ -90,20 +109,20 @@ func runRun(cmd *Command, args []string) {
 // runProgram is the action for running a binary that has already
 // been compiled.  We ignore exit status.
 func (b *builder) runProgram(a *action) error {
+	cmdline := stringList(findExecCmd(), a.deps[0].target, a.args)
 	if buildN || buildX {
-		b.showcmd("", "%s %s", a.deps[0].target, strings.Join(a.args, " "))
+		b.showcmd("", "%s", strings.Join(cmdline, " "))
 		if buildN {
 			return nil
 		}
 	}
 
-	runStdin(a.deps[0].target, a.args)
+	runStdin(cmdline)
 	return nil
 }
 
 // runStdin is like run, but connects Stdin.
-func runStdin(cmdargs ...interface{}) {
-	cmdline := stringList(cmdargs...)
+func runStdin(cmdline []string) {
 	cmd := exec.Command(cmdline[0], cmdline[1:]...)
 	cmd.Stdin = os.Stdin
 	cmd.Stdout = os.Stdout
diff --git a/src/cmd/go/signal_unix.go b/src/cmd/go/signal_unix.go
index 8faa7efa76e54723278354fe7cf939e8f9edf937..e86cd4652311ccdb851d7cfa72c596a6dbb2fdf9 100644
--- a/src/cmd/go/signal_unix.go
+++ b/src/cmd/go/signal_unix.go
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build darwin dragonfly freebsd linux netbsd openbsd solaris
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris
 
 package main
 
diff --git a/src/cmd/go/test.go b/src/cmd/go/test.go
index 26b7f87f48f5cb60a1d494e9b877be2d93a3597d..2da63ef04a2805405a1f6d1eaab75ba852a05391 100644
--- a/src/cmd/go/test.go
+++ b/src/cmd/go/test.go
@@ -293,6 +293,8 @@ func runTest(cmd *Command, args []string) {
 	var pkgArgs []string
 	pkgArgs, testArgs = testFlags(args)
 
+	findExecCmd() // initialize cached result
+
 	raceInit()
 	pkgs := packagesForBuild(pkgArgs)
 	if len(pkgs) == 0 {
@@ -835,7 +837,7 @@ func declareCoverVars(importPath string, files ...string) map[string]*CoverVar {
 
 // runTest is the action for running a test binary.
 func (b *builder) runTest(a *action) error {
-	args := stringList(a.deps[0].target, testArgs)
+	args := stringList(findExecCmd(), a.deps[0].target, testArgs)
 	a.testOutput = new(bytes.Buffer)
 
 	if buildN || buildX {
diff --git a/src/cmd/go/testflag.go b/src/cmd/go/testflag.go
index aea81d8f83479c63606988fd0485fe0ba924c20c..69c33d39e66710b6e722b0bd0b5bc387da19d4b1 100644
--- a/src/cmd/go/testflag.go
+++ b/src/cmd/go/testflag.go
@@ -77,6 +77,7 @@ var testFlagDefn = []*testFlagSpec{
 	{name: "x", boolVar: &buildX},
 	{name: "work", boolVar: &buildWork},
 	{name: "gcflags"},
+	{name: "exec"},
 	{name: "ldflags"},
 	{name: "gccgoflags"},
 	{name: "tags"},
@@ -154,6 +155,11 @@ func testFlags(args []string) (packageNames, passToTest []string) {
 			setBoolFlag(f.boolVar, value)
 		case "p":
 			setIntFlag(&buildP, value)
+		case "exec":
+			execCmd, err = splitQuotedFields(value)
+			if err != nil {
+				fatalf("invalid flag argument for -%s: %v", f.name, err)
+			}
 		case "gcflags":
 			buildGcflags, err = splitQuotedFields(value)
 			if err != nil {
diff --git a/src/pkg/crypto/md5/md5block_amd64p32.s b/src/pkg/crypto/md5/md5block_amd64p32.s
new file mode 100644
index 0000000000000000000000000000000000000000..a78a3f6100e76990b72d5c633e2cf143cf965162
--- /dev/null
+++ b/src/pkg/crypto/md5/md5block_amd64p32.s
@@ -0,0 +1,184 @@
+// Original source:
+//	http://www.zorinaq.com/papers/md5-amd64.html
+//	http://www.zorinaq.com/papers/md5-amd64.tar.bz2
+//
+// Translated from Perl generating GNU assembly into
+// #defines generating 6a assembly by the Go Authors.
+//
+// Restrictions to make code safe for Native Client:
+// replace BP with R11, reloaded before use at return.
+// replace R15 with R11.
+
+#include "../../../cmd/ld/textflag.h"
+
+// MD5 optimized for AMD64.
+//
+// Author: Marc Bevand <bevand_m (at) epita.fr>
+// Licence: I hereby disclaim the copyright on this code and place it
+// in the public domain.
+
+TEXT	·block(SB),NOSPLIT,$0-32
+	MOVL	dig+0(FP),	R11
+	MOVL	p+4(FP),	SI
+	MOVL	p_len+8(FP), DX
+	SHRQ	$6,		DX
+	SHLQ	$6,		DX
+
+	LEAQ	(SI)(DX*1),	DI
+	MOVL	(0*4)(R11),	AX
+	MOVL	(1*4)(R11),	BX
+	MOVL	(2*4)(R11),	CX
+	MOVL	(3*4)(R11),	DX
+
+	CMPQ	SI,		DI
+	JEQ	end
+
+loop:
+	MOVL	AX,		R12
+	MOVL	BX,		R13
+	MOVL	CX,		R14
+	MOVL	DX,		R11
+
+	MOVL	(0*4)(SI),	R8
+	MOVL	DX,		R9
+
+#define ROUND1(a, b, c, d, index, const, shift) \
+	XORL	c, R9; \
+	LEAL	const(a)(R8*1), a; \
+	ANDL	b, R9; \
+	XORL d, R9; \
+	MOVL (index*4)(SI), R8; \
+	ADDL R9, a; \
+	ROLL $shift, a; \
+	MOVL c, R9; \
+	ADDL b, a
+
+	ROUND1(AX,BX,CX,DX, 1,0xd76aa478, 7);
+	ROUND1(DX,AX,BX,CX, 2,0xe8c7b756,12);
+	ROUND1(CX,DX,AX,BX, 3,0x242070db,17);
+	ROUND1(BX,CX,DX,AX, 4,0xc1bdceee,22);
+	ROUND1(AX,BX,CX,DX, 5,0xf57c0faf, 7);
+	ROUND1(DX,AX,BX,CX, 6,0x4787c62a,12);
+	ROUND1(CX,DX,AX,BX, 7,0xa8304613,17);
+	ROUND1(BX,CX,DX,AX, 8,0xfd469501,22);
+	ROUND1(AX,BX,CX,DX, 9,0x698098d8, 7);
+	ROUND1(DX,AX,BX,CX,10,0x8b44f7af,12);
+	ROUND1(CX,DX,AX,BX,11,0xffff5bb1,17);
+	ROUND1(BX,CX,DX,AX,12,0x895cd7be,22);
+	ROUND1(AX,BX,CX,DX,13,0x6b901122, 7);
+	ROUND1(DX,AX,BX,CX,14,0xfd987193,12);
+	ROUND1(CX,DX,AX,BX,15,0xa679438e,17);
+	ROUND1(BX,CX,DX,AX, 0,0x49b40821,22);
+
+	MOVL	(1*4)(SI),	R8
+	MOVL	DX,		R9
+	MOVL	DX,		R10
+
+#define ROUND2(a, b, c, d, index, const, shift) \
+	NOTL	R9; \
+	LEAL	const(a)(R8*1),a; \
+	ANDL	b,		R10; \
+	ANDL	c,		R9; \
+	MOVL	(index*4)(SI),R8; \
+	ORL	R9,		R10; \
+	MOVL	c,		R9; \
+	ADDL	R10,		a; \
+	MOVL	c,		R10; \
+	ROLL	$shift,	a; \
+	ADDL	b,		a
+
+	ROUND2(AX,BX,CX,DX, 6,0xf61e2562, 5);
+	ROUND2(DX,AX,BX,CX,11,0xc040b340, 9);
+	ROUND2(CX,DX,AX,BX, 0,0x265e5a51,14);
+	ROUND2(BX,CX,DX,AX, 5,0xe9b6c7aa,20);
+	ROUND2(AX,BX,CX,DX,10,0xd62f105d, 5);
+	ROUND2(DX,AX,BX,CX,15, 0x2441453, 9);
+	ROUND2(CX,DX,AX,BX, 4,0xd8a1e681,14);
+	ROUND2(BX,CX,DX,AX, 9,0xe7d3fbc8,20);
+	ROUND2(AX,BX,CX,DX,14,0x21e1cde6, 5);
+	ROUND2(DX,AX,BX,CX, 3,0xc33707d6, 9);
+	ROUND2(CX,DX,AX,BX, 8,0xf4d50d87,14);
+	ROUND2(BX,CX,DX,AX,13,0x455a14ed,20);
+	ROUND2(AX,BX,CX,DX, 2,0xa9e3e905, 5);
+	ROUND2(DX,AX,BX,CX, 7,0xfcefa3f8, 9);
+	ROUND2(CX,DX,AX,BX,12,0x676f02d9,14);
+	ROUND2(BX,CX,DX,AX, 0,0x8d2a4c8a,20);
+ 
+	MOVL	(5*4)(SI),	R8
+	MOVL	CX,		R9
+
+#define ROUND3(a, b, c, d, index, const, shift) \
+	LEAL	const(a)(R8*1),a; \
+	MOVL	(index*4)(SI),R8; \
+	XORL	d,		R9; \
+	XORL	b,		R9; \
+	ADDL	R9,		a; \
+	ROLL	$shift,		a; \
+	MOVL	b,		R9; \
+	ADDL	b,		a
+
+	ROUND3(AX,BX,CX,DX, 8,0xfffa3942, 4);
+	ROUND3(DX,AX,BX,CX,11,0x8771f681,11);
+	ROUND3(CX,DX,AX,BX,14,0x6d9d6122,16);
+	ROUND3(BX,CX,DX,AX, 1,0xfde5380c,23);
+	ROUND3(AX,BX,CX,DX, 4,0xa4beea44, 4);
+	ROUND3(DX,AX,BX,CX, 7,0x4bdecfa9,11);
+	ROUND3(CX,DX,AX,BX,10,0xf6bb4b60,16);
+	ROUND3(BX,CX,DX,AX,13,0xbebfbc70,23);
+	ROUND3(AX,BX,CX,DX, 0,0x289b7ec6, 4);
+	ROUND3(DX,AX,BX,CX, 3,0xeaa127fa,11);
+	ROUND3(CX,DX,AX,BX, 6,0xd4ef3085,16);
+	ROUND3(BX,CX,DX,AX, 9, 0x4881d05,23);
+	ROUND3(AX,BX,CX,DX,12,0xd9d4d039, 4);
+	ROUND3(DX,AX,BX,CX,15,0xe6db99e5,11);
+	ROUND3(CX,DX,AX,BX, 2,0x1fa27cf8,16);
+	ROUND3(BX,CX,DX,AX, 0,0xc4ac5665,23);
+
+	MOVL	(0*4)(SI),	R8
+	MOVL	$0xffffffff,	R9
+	XORL	DX,		R9
+
+#define ROUND4(a, b, c, d, index, const, shift) \
+	LEAL	const(a)(R8*1),a; \
+	ORL	b,		R9; \
+	XORL	c,		R9; \
+	ADDL	R9,		a; \
+	MOVL	(index*4)(SI),R8; \
+	MOVL	$0xffffffff,	R9; \
+	ROLL	$shift,		a; \
+	XORL	c,		R9; \
+	ADDL	b,		a
+	
+	ROUND4(AX,BX,CX,DX, 7,0xf4292244, 6);
+	ROUND4(DX,AX,BX,CX,14,0x432aff97,10);
+	ROUND4(CX,DX,AX,BX, 5,0xab9423a7,15);
+	ROUND4(BX,CX,DX,AX,12,0xfc93a039,21);
+	ROUND4(AX,BX,CX,DX, 3,0x655b59c3, 6);
+	ROUND4(DX,AX,BX,CX,10,0x8f0ccc92,10);
+	ROUND4(CX,DX,AX,BX, 1,0xffeff47d,15);
+	ROUND4(BX,CX,DX,AX, 8,0x85845dd1,21);
+	ROUND4(AX,BX,CX,DX,15,0x6fa87e4f, 6);
+	ROUND4(DX,AX,BX,CX, 6,0xfe2ce6e0,10);
+	ROUND4(CX,DX,AX,BX,13,0xa3014314,15);
+	ROUND4(BX,CX,DX,AX, 4,0x4e0811a1,21);
+	ROUND4(AX,BX,CX,DX,11,0xf7537e82, 6);
+	ROUND4(DX,AX,BX,CX, 2,0xbd3af235,10);
+	ROUND4(CX,DX,AX,BX, 9,0x2ad7d2bb,15);
+	ROUND4(BX,CX,DX,AX, 0,0xeb86d391,21);
+
+	ADDL	R12,	AX
+	ADDL	R13,	BX
+	ADDL	R14,	CX
+	ADDL	R11,	DX
+
+	ADDQ	$64,		SI
+	CMPQ	SI,		DI
+	JB	loop
+
+end:
+	MOVL	dig+0(FP),	R11
+	MOVL	AX,		(0*4)(R11)
+	MOVL	BX,		(1*4)(R11)
+	MOVL	CX,		(2*4)(R11)
+	MOVL	DX,		(3*4)(R11)
+	RET
diff --git a/src/pkg/crypto/md5/md5block_decl.go b/src/pkg/crypto/md5/md5block_decl.go
index c4d6aaaf03a1e33b46feac4bfda30c3639ae69f1..d7956a6d203ee753bd3197650cc6a1aab9b0bde7 100644
--- a/src/pkg/crypto/md5/md5block_decl.go
+++ b/src/pkg/crypto/md5/md5block_decl.go
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build amd64 386 arm
+// +build amd64 amd64p32 386 arm
 
 package md5
 
diff --git a/src/pkg/crypto/rand/rand_unix.go b/src/pkg/crypto/rand/rand_unix.go
index 0fbd7eaf5794bab6492f4e84d894df833cf42bf6..1e741fda193b111eaa421f200291677538560439 100644
--- a/src/pkg/crypto/rand/rand_unix.go
+++ b/src/pkg/crypto/rand/rand_unix.go
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build darwin dragonfly freebsd linux netbsd openbsd plan9 solaris
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd plan9 solaris
 
 // Unix cryptographically secure pseudorandom number
 // generator.
diff --git a/src/pkg/crypto/rc4/rc4_amd64p32.s b/src/pkg/crypto/rc4/rc4_amd64p32.s
new file mode 100644
index 0000000000000000000000000000000000000000..27d8495071e3aafa67d6ba105ba853cfdf3c52c9
--- /dev/null
+++ b/src/pkg/crypto/rc4/rc4_amd64p32.s
@@ -0,0 +1,192 @@
+// Original source:
+//	http://www.zorinaq.com/papers/rc4-amd64.html
+//	http://www.zorinaq.com/papers/rc4-amd64.tar.bz2
+
+#include "../../../cmd/ld/textflag.h"
+
+// Local modifications:
+//
+// Transliterated from GNU to 6a assembly syntax by the Go authors.
+// The comments and spacing are from the original.
+//
+// The new EXTEND macros avoid a bad stall on some systems after 8-bit math.
+//
+// The original code accumulated 64 bits of key stream in an integer
+// register and then XOR'ed the key stream into the data 8 bytes at a time.
+// Modified to accumulate 128 bits of key stream into an XMM register
+// and then XOR the key stream into the data 16 bytes at a time.
+// Approximately doubles throughput.
+//
+// Converted to amd64p32.
+//
+// To make safe for Native Client, avoid use of BP, R15,
+// and two-register addressing modes.
+
+// NOTE: Changing EXTEND to a no-op makes the code run 1.2x faster on Core i5
+// but makes the code run 2.0x slower on Xeon.
+#define EXTEND(r) MOVBLZX r, r
+
+/*
+** RC4 implementation optimized for AMD64.
+**
+** Author: Marc Bevand <bevand_m (at) epita.fr>
+** Licence: I hereby disclaim the copyright on this code and place it
+** in the public domain.
+**
+** The code has been designed to be easily integrated into openssl:
+** the exported RC4() function can replace the actual implementations
+** openssl already contains. Please note that when linking with openssl,
+** it requires that sizeof(RC4_INT) == 8. So openssl must be compiled
+** with -DRC4_INT='unsigned long'.
+**
+** The throughput achieved by this code is about 320 MBytes/sec, on
+** a 1.8 GHz AMD Opteron (rev C0) processor.
+*/
+
+TEXT ·xorKeyStream(SB),NOSPLIT,$0
+	MOVL	n+8(FP),	BX		// rbx = ARG(len)
+	MOVL	src+4(FP),	SI		// in = ARG(in)
+	MOVL	dst+0(FP),	DI		// out = ARG(out)
+	MOVL	state+12(FP),	R10		// d = ARG(data)
+	MOVL	i+16(FP),	AX
+	MOVBQZX	0(AX),		CX		// x = *xp
+	MOVL	j+20(FP),	AX
+	MOVBQZX	0(AX),		DX		// y = *yp
+
+	LEAQ	(SI)(BX*1),	R9		// limit = in+len
+
+l1:	CMPQ	SI,		R9		// cmp in with in+len
+	JGE	finished			// jump if (in >= in+len)
+
+	INCB	CX
+	EXTEND(CX)
+	TESTL	$15,		CX
+	JZ	wordloop
+	LEAL	(R10)(CX*4), R12
+
+	MOVBLZX	(R12),	AX
+
+	ADDB	AX,		DX		// y += tx
+	EXTEND(DX)
+	LEAL (R10)(DX*4), R11
+	MOVBLZX	(R11),	BX		// ty = d[y]
+	MOVB	BX,		(R12)	// d[x] = ty
+	ADDB	AX,		BX		// val = ty+tx
+	EXTEND(BX)
+	LEAL (R10)(BX*4), R13
+	MOVB	AX,		(R11)	// d[y] = tx
+	MOVBLZX	(R13),	R8		// val = d[val]
+	XORB	(SI),		R8		// xor 1 byte
+	MOVB	R8,		(DI)
+	INCQ	SI				// in++
+	INCQ	DI				// out++
+	JMP l1
+
+wordloop:
+	SUBQ	$16,		R9
+	CMPQ	SI,		R9
+	JGT	end
+
+start:
+	ADDQ	$16,		SI		// increment in
+	ADDQ	$16,		DI		// increment out
+
+	// Each KEYROUND generates one byte of key and
+	// inserts it into an XMM register at the given 16-bit index.
+	// The key state array is uint32 words only using the bottom
+	// byte of each word, so the 16-bit OR only copies 8 useful bits.
+	// We accumulate alternating bytes into X0 and X1, and then at
+	// the end we OR X1<<8 into X0 to produce the actual key.
+	//
+	// At the beginning of the loop, CX%16 == 0, so the 16 loads
+	// at state[CX], state[CX+1], ..., state[CX+15] can precompute
+	// (state+CX) as R12 and then become R12[0], R12[1], ... R12[15],
+	// without fear of the byte computation CX+15 wrapping around.
+	//
+	// The first round needs R12[0], the second needs R12[1], and so on.
+	// We can avoid memory stalls by starting the load for round n+1
+	// before the end of round n, using the LOAD macro.
+	LEAQ	(R10)(CX*4),	R12
+
+#define KEYROUND(xmm, load, off, r1, r2, index) \
+	LEAL (R10)(DX*4), R11; \
+	MOVBLZX	(R11),	R8; \
+	MOVB	r1,		(R11); \
+	load((off+1), r2); \
+	MOVB	R8,		(off*4)(R12); \
+	ADDB	r1,		R8; \
+	EXTEND(R8); \
+	LEAL (R10)(R8*4), R14; \
+	PINSRW	$index, (R14), xmm
+
+#define LOAD(off, reg) \
+	MOVBLZX	(off*4)(R12),	reg; \
+	ADDB	reg,		DX; \
+	EXTEND(DX)
+
+#define SKIP(off, reg)
+
+	LOAD(0, AX)
+	KEYROUND(X0, LOAD, 0, AX, BX, 0)
+	KEYROUND(X1, LOAD, 1, BX, AX, 0)
+	KEYROUND(X0, LOAD, 2, AX, BX, 1)
+	KEYROUND(X1, LOAD, 3, BX, AX, 1)
+	KEYROUND(X0, LOAD, 4, AX, BX, 2)
+	KEYROUND(X1, LOAD, 5, BX, AX, 2)
+	KEYROUND(X0, LOAD, 6, AX, BX, 3)
+	KEYROUND(X1, LOAD, 7, BX, AX, 3)
+	KEYROUND(X0, LOAD, 8, AX, BX, 4)
+	KEYROUND(X1, LOAD, 9, BX, AX, 4)
+	KEYROUND(X0, LOAD, 10, AX, BX, 5)
+	KEYROUND(X1, LOAD, 11, BX, AX, 5)
+	KEYROUND(X0, LOAD, 12, AX, BX, 6)
+	KEYROUND(X1, LOAD, 13, BX, AX, 6)
+	KEYROUND(X0, LOAD, 14, AX, BX, 7)
+	KEYROUND(X1, SKIP, 15, BX, AX, 7)
+	
+	ADDB	$16,		CX
+
+	PSLLQ	$8,		X1
+	PXOR	X1,		X0
+	MOVOU	-16(SI),	X2
+	PXOR	X0,		X2
+	MOVOU	X2,		-16(DI)
+
+	CMPQ	SI,		R9		// cmp in with in+len-16
+	JLE	start				// jump if (in <= in+len-16)
+
+end:
+	DECB	CX
+	ADDQ	$16,		R9		// tmp = in+len
+
+	// handle the last bytes, one by one
+l2:	CMPQ	SI,		R9		// cmp in with in+len
+	JGE	finished			// jump if (in >= in+len)
+
+	INCB	CX
+	EXTEND(CX)
+	LEAL (R10)(CX*4), R12
+	MOVBLZX	(R12),	AX
+
+	ADDB	AX,		DX		// y += tx
+	EXTEND(DX)
+	LEAL (R10)(DX*4), R11
+	MOVBLZX	(R11),	BX		// ty = d[y]
+	MOVB	BX,		(R12)	// d[x] = ty
+	ADDB	AX,		BX		// val = ty+tx
+	EXTEND(BX)
+	LEAL (R10)(BX*4), R13
+	MOVB	AX,		(R11)	// d[y] = tx
+	MOVBLZX	(R13),	R8		// val = d[val]
+	XORB	(SI),		R8		// xor 1 byte
+	MOVB	R8,		(DI)
+	INCQ	SI				// in++
+	INCQ	DI				// out++
+	JMP l2
+
+finished:
+	MOVL	j+20(FP),	BX
+	MOVB	DX, 0(BX)
+	MOVL	i+16(FP),	AX
+	MOVB	CX, 0(AX)
+	RET
diff --git a/src/pkg/crypto/rc4/rc4_asm.go b/src/pkg/crypto/rc4/rc4_asm.go
index c582a4488b85d98c09e3c5373fe2304659cbce6a..fc71b9a6fa2f50199eb95a4f3e361b500a82f009 100644
--- a/src/pkg/crypto/rc4/rc4_asm.go
+++ b/src/pkg/crypto/rc4/rc4_asm.go
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build amd64 arm 386
+// +build amd64 amd64p32 arm 386
 
 package rc4
 
diff --git a/src/pkg/crypto/rc4/rc4_ref.go b/src/pkg/crypto/rc4/rc4_ref.go
index bdf5e1db2ddf127801d7b182bacf0e08d726adf6..1ecce1a7fbcd457ed0a0be54bc39536937debebb 100644
--- a/src/pkg/crypto/rc4/rc4_ref.go
+++ b/src/pkg/crypto/rc4/rc4_ref.go
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build !amd64,!arm,!386
+// +build !amd64,!amd64p32,!arm,!386
 
 package rc4
 
diff --git a/src/pkg/crypto/sha1/sha1block_amd64p32.s b/src/pkg/crypto/sha1/sha1block_amd64p32.s
new file mode 100644
index 0000000000000000000000000000000000000000..3c589d94fe01ebbd9ba1ff5e02b9c3c563fc8f24
--- /dev/null
+++ b/src/pkg/crypto/sha1/sha1block_amd64p32.s
@@ -0,0 +1,216 @@
+// Copyright 2013 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "../../../cmd/ld/textflag.h"
+
+// SHA1 block routine. See sha1block.go for Go equivalent.
+//
+// There are 80 rounds of 4 types:
+//   - rounds 0-15 are type 1 and load data (ROUND1 macro).
+//   - rounds 16-19 are type 1 and do not load data (ROUND1x macro).
+//   - rounds 20-39 are type 2 and do not load data (ROUND2 macro).
+//   - rounds 40-59 are type 3 and do not load data (ROUND3 macro).
+//   - rounds 60-79 are type 4 and do not load data (ROUND4 macro).
+//
+// Each round loads or shuffles the data, then computes a per-round
+// function of b, c, d, and then mixes the result into and rotates the
+// five registers a, b, c, d, e holding the intermediate results.
+//
+// The register rotation is implemented by rotating the arguments to
+// the round macros instead of by explicit move instructions.
+//
+// amd64p32 version.
+// To ensure safety for Native Client, avoids use of BP and R15
+// as well as two-register addressing modes.
+
+#define LOAD(index) \
+	MOVL	(index*4)(SI), R10; \
+	BSWAPL	R10; \
+	MOVL	R10, (index*4)(SP)
+
+#define SHUFFLE(index) \
+	MOVL	(((index)&0xf)*4)(SP), R10; \
+	XORL	(((index-3)&0xf)*4)(SP), R10; \
+	XORL	(((index-8)&0xf)*4)(SP), R10; \
+	XORL	(((index-14)&0xf)*4)(SP), R10; \
+	ROLL	$1, R10; \
+	MOVL	R10, (((index)&0xf)*4)(SP)
+
+#define FUNC1(a, b, c, d, e) \
+	MOVL	d, R9; \
+	XORL	c, R9; \
+	ANDL	b, R9; \
+	XORL	d, R9
+
+#define FUNC2(a, b, c, d, e) \
+	MOVL	b, R9; \
+	XORL	c, R9; \
+	XORL	d, R9
+
+#define FUNC3(a, b, c, d, e) \
+	MOVL	b, R8; \
+	ORL	c, R8; \
+	ANDL	d, R8; \
+	MOVL	b, R9; \
+	ANDL	c, R9; \
+	ORL	R8, R9
+	
+#define FUNC4 FUNC2
+
+#define MIX(a, b, c, d, e, const) \
+	ROLL	$30, b; \
+	ADDL	R9, e; \
+	MOVL	a, R8; \
+	ROLL	$5, R8; \
+	LEAL	const(e)(R10*1), e; \
+	ADDL	R8, e
+
+#define ROUND1(a, b, c, d, e, index) \
+	LOAD(index); \
+	FUNC1(a, b, c, d, e); \
+	MIX(a, b, c, d, e, 0x5A827999)
+
+#define ROUND1x(a, b, c, d, e, index) \
+	SHUFFLE(index); \
+	FUNC1(a, b, c, d, e); \
+	MIX(a, b, c, d, e, 0x5A827999)
+
+#define ROUND2(a, b, c, d, e, index) \
+	SHUFFLE(index); \
+	FUNC2(a, b, c, d, e); \
+	MIX(a, b, c, d, e, 0x6ED9EBA1)
+
+#define ROUND3(a, b, c, d, e, index) \
+	SHUFFLE(index); \
+	FUNC3(a, b, c, d, e); \
+	MIX(a, b, c, d, e, 0x8F1BBCDC)
+
+#define ROUND4(a, b, c, d, e, index) \
+	SHUFFLE(index); \
+	FUNC4(a, b, c, d, e); \
+	MIX(a, b, c, d, e, 0xCA62C1D6)
+
+TEXT ·block(SB),NOSPLIT,$64-32
+	MOVL	dig+0(FP),	R14
+	MOVL	p_base+4(FP),	SI
+	MOVL	p_len+8(FP),	DX
+	SHRQ	$6,		DX
+	SHLQ	$6,		DX
+	
+	LEAQ	(SI)(DX*1),	DI
+	MOVL	(0*4)(R14),	AX
+	MOVL	(1*4)(R14),	BX
+	MOVL	(2*4)(R14),	CX
+	MOVL	(3*4)(R14),	DX
+	MOVL	(4*4)(R14),	R13
+
+	CMPQ	SI,		DI
+	JEQ	end
+
+loop:
+#define BP R13 /* keep diff from sha1block_amd64.s small */
+	ROUND1(AX, BX, CX, DX, BP, 0)
+	ROUND1(BP, AX, BX, CX, DX, 1)
+	ROUND1(DX, BP, AX, BX, CX, 2)
+	ROUND1(CX, DX, BP, AX, BX, 3)
+	ROUND1(BX, CX, DX, BP, AX, 4)
+	ROUND1(AX, BX, CX, DX, BP, 5)
+	ROUND1(BP, AX, BX, CX, DX, 6)
+	ROUND1(DX, BP, AX, BX, CX, 7)
+	ROUND1(CX, DX, BP, AX, BX, 8)
+	ROUND1(BX, CX, DX, BP, AX, 9)
+	ROUND1(AX, BX, CX, DX, BP, 10)
+	ROUND1(BP, AX, BX, CX, DX, 11)
+	ROUND1(DX, BP, AX, BX, CX, 12)
+	ROUND1(CX, DX, BP, AX, BX, 13)
+	ROUND1(BX, CX, DX, BP, AX, 14)
+	ROUND1(AX, BX, CX, DX, BP, 15)
+
+	ROUND1x(BP, AX, BX, CX, DX, 16)
+	ROUND1x(DX, BP, AX, BX, CX, 17)
+	ROUND1x(CX, DX, BP, AX, BX, 18)
+	ROUND1x(BX, CX, DX, BP, AX, 19)
+	
+	ROUND2(AX, BX, CX, DX, BP, 20)
+	ROUND2(BP, AX, BX, CX, DX, 21)
+	ROUND2(DX, BP, AX, BX, CX, 22)
+	ROUND2(CX, DX, BP, AX, BX, 23)
+	ROUND2(BX, CX, DX, BP, AX, 24)
+	ROUND2(AX, BX, CX, DX, BP, 25)
+	ROUND2(BP, AX, BX, CX, DX, 26)
+	ROUND2(DX, BP, AX, BX, CX, 27)
+	ROUND2(CX, DX, BP, AX, BX, 28)
+	ROUND2(BX, CX, DX, BP, AX, 29)
+	ROUND2(AX, BX, CX, DX, BP, 30)
+	ROUND2(BP, AX, BX, CX, DX, 31)
+	ROUND2(DX, BP, AX, BX, CX, 32)
+	ROUND2(CX, DX, BP, AX, BX, 33)
+	ROUND2(BX, CX, DX, BP, AX, 34)
+	ROUND2(AX, BX, CX, DX, BP, 35)
+	ROUND2(BP, AX, BX, CX, DX, 36)
+	ROUND2(DX, BP, AX, BX, CX, 37)
+	ROUND2(CX, DX, BP, AX, BX, 38)
+	ROUND2(BX, CX, DX, BP, AX, 39)
+	
+	ROUND3(AX, BX, CX, DX, BP, 40)
+	ROUND3(BP, AX, BX, CX, DX, 41)
+	ROUND3(DX, BP, AX, BX, CX, 42)
+	ROUND3(CX, DX, BP, AX, BX, 43)
+	ROUND3(BX, CX, DX, BP, AX, 44)
+	ROUND3(AX, BX, CX, DX, BP, 45)
+	ROUND3(BP, AX, BX, CX, DX, 46)
+	ROUND3(DX, BP, AX, BX, CX, 47)
+	ROUND3(CX, DX, BP, AX, BX, 48)
+	ROUND3(BX, CX, DX, BP, AX, 49)
+	ROUND3(AX, BX, CX, DX, BP, 50)
+	ROUND3(BP, AX, BX, CX, DX, 51)
+	ROUND3(DX, BP, AX, BX, CX, 52)
+	ROUND3(CX, DX, BP, AX, BX, 53)
+	ROUND3(BX, CX, DX, BP, AX, 54)
+	ROUND3(AX, BX, CX, DX, BP, 55)
+	ROUND3(BP, AX, BX, CX, DX, 56)
+	ROUND3(DX, BP, AX, BX, CX, 57)
+	ROUND3(CX, DX, BP, AX, BX, 58)
+	ROUND3(BX, CX, DX, BP, AX, 59)
+	
+	ROUND4(AX, BX, CX, DX, BP, 60)
+	ROUND4(BP, AX, BX, CX, DX, 61)
+	ROUND4(DX, BP, AX, BX, CX, 62)
+	ROUND4(CX, DX, BP, AX, BX, 63)
+	ROUND4(BX, CX, DX, BP, AX, 64)
+	ROUND4(AX, BX, CX, DX, BP, 65)
+	ROUND4(BP, AX, BX, CX, DX, 66)
+	ROUND4(DX, BP, AX, BX, CX, 67)
+	ROUND4(CX, DX, BP, AX, BX, 68)
+	ROUND4(BX, CX, DX, BP, AX, 69)
+	ROUND4(AX, BX, CX, DX, BP, 70)
+	ROUND4(BP, AX, BX, CX, DX, 71)
+	ROUND4(DX, BP, AX, BX, CX, 72)
+	ROUND4(CX, DX, BP, AX, BX, 73)
+	ROUND4(BX, CX, DX, BP, AX, 74)
+	ROUND4(AX, BX, CX, DX, BP, 75)
+	ROUND4(BP, AX, BX, CX, DX, 76)
+	ROUND4(DX, BP, AX, BX, CX, 77)
+	ROUND4(CX, DX, BP, AX, BX, 78)
+	ROUND4(BX, CX, DX, BP, AX, 79)
+#undef BP
+
+	ADDL	(0*4)(R14), AX
+	ADDL	(1*4)(R14), BX
+	ADDL	(2*4)(R14), CX
+	ADDL	(3*4)(R14), DX
+	ADDL	(4*4)(R14), R13
+
+	MOVL	AX, (0*4)(R14)
+	MOVL	BX, (1*4)(R14)
+	MOVL	CX, (2*4)(R14)
+	MOVL	DX, (3*4)(R14)
+	MOVL	R13, (4*4)(R14)
+
+	ADDQ	$64, SI
+	CMPQ	SI, DI
+	JB	loop
+
+end:
+	RET
diff --git a/src/pkg/crypto/sha1/sha1block_decl.go b/src/pkg/crypto/sha1/sha1block_decl.go
index b2c68f0e8baaf2f1d65d18f278530e4ebe1afea4..2331deb3a99ec04146f4b843119fe9ecac14c8c3 100644
--- a/src/pkg/crypto/sha1/sha1block_decl.go
+++ b/src/pkg/crypto/sha1/sha1block_decl.go
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build amd64 386 arm
+// +build amd64 amd64p32 386
 
 package sha1
 
diff --git a/src/pkg/crypto/x509/root_unix.go b/src/pkg/crypto/x509/root_unix.go
index a5bd19e821695d6352a00f2ecf2d428b6f6a129b..11ad3c440d20468f8f6a9cba43fdde9f839a7809 100644
--- a/src/pkg/crypto/x509/root_unix.go
+++ b/src/pkg/crypto/x509/root_unix.go
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build dragonfly freebsd linux openbsd netbsd solaris
+// +build dragonfly freebsd linux nacl netbsd openbsd solaris
 
 package x509
 
diff --git a/src/pkg/go/build/build.go b/src/pkg/go/build/build.go
index 98ec5ea5ed9a428fa728df4a1ef33be080eb2929..8a390762dc8a09623e2d802c60cc0b0d0dfea744 100644
--- a/src/pkg/go/build/build.go
+++ b/src/pkg/go/build/build.go
@@ -1209,7 +1209,7 @@ func ArchChar(goarch string) (string, error) {
 	switch goarch {
 	case "386":
 		return "8", nil
-	case "amd64":
+	case "amd64", "amd64p32":
 		return "6", nil
 	case "arm":
 		return "5", nil
diff --git a/src/pkg/go/build/deps_test.go b/src/pkg/go/build/deps_test.go
index 3e7ae22a82a8bcd42eb99c4c7487388c59874049..7421e144f15d3c32310149d576764c872c3bd361 100644
--- a/src/pkg/go/build/deps_test.go
+++ b/src/pkg/go/build/deps_test.go
@@ -8,6 +8,7 @@
 package build
 
 import (
+	"runtime"
 	"sort"
 	"testing"
 )
@@ -359,7 +360,7 @@ func allowed(pkg string) map[string]bool {
 }
 
 var bools = []bool{false, true}
-var geese = []string{"darwin", "dragonfly", "freebsd", "linux", "netbsd", "openbsd", "plan9", "solaris", "windows"}
+var geese = []string{"darwin", "dragonfly", "freebsd", "linux", "nacl", "netbsd", "openbsd", "plan9", "solaris", "windows"}
 var goarches = []string{"386", "amd64", "arm"}
 
 type osPkg struct {
@@ -374,6 +375,11 @@ var allowedErrors = map[osPkg]bool{
 }
 
 func TestDependencies(t *testing.T) {
+	if runtime.GOOS == "nacl" {
+		// NaCl tests run in a limited file system and we do not
+		// provide access to every source file.
+		t.Skip("skipping on NaCl")
+	}
 	var all []string
 
 	for k := range pkgDeps {
@@ -387,6 +393,9 @@ func TestDependencies(t *testing.T) {
 			if isMacro(pkg) {
 				continue
 			}
+			if pkg == "runtime/cgo" && !ctxt.CgoEnabled {
+				continue
+			}
 			p, err := ctxt.Import(pkg, "", 0)
 			if err != nil {
 				if allowedErrors[osPkg{ctxt.GOOS, pkg}] {
diff --git a/src/pkg/go/build/syslist.go b/src/pkg/go/build/syslist.go
index f4702d0dc401552d891b24e28db6fc40a82094ba..5c42b946b09434d060eb70565a22cd71a24880a8 100644
--- a/src/pkg/go/build/syslist.go
+++ b/src/pkg/go/build/syslist.go
@@ -4,5 +4,5 @@
 
 package build
 
-const goosList = "darwin dragonfly freebsd linux netbsd openbsd plan9 solaris windows "
-const goarchList = "386 amd64 arm "
+const goosList = "darwin dragonfly freebsd linux nacl netbsd openbsd plan9 solaris windows "
+const goarchList = "386 amd64 amd64p32 arm "
diff --git a/src/pkg/hash/crc32/crc32_amd64p32.s b/src/pkg/hash/crc32/crc32_amd64p32.s
new file mode 100644
index 0000000000000000000000000000000000000000..e34f20867776240289d39bc007c728ebc27a9e84
--- /dev/null
+++ b/src/pkg/hash/crc32/crc32_amd64p32.s
@@ -0,0 +1,64 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "../../../cmd/ld/textflag.h"
+
+// func castagnoliSSE42(crc uint32, p []byte) uint32
+TEXT ·castagnoliSSE42(SB),NOSPLIT,$0
+	MOVL crc+0(FP), AX  // CRC value
+	MOVL p+4(FP), SI  // data pointer
+	MOVL p_len+8(FP), CX  // len(p)
+
+	NOTL AX
+
+	/* If there's less than 8 bytes to process, we do it byte-by-byte. */
+	CMPQ CX, $8
+	JL cleanup
+
+	/* Process individual bytes until the input is 8-byte aligned. */
+startup:
+	MOVQ SI, BX
+	ANDQ $7, BX
+	JZ aligned
+
+	CRC32B (SI), AX
+	DECQ CX
+	INCQ SI
+	JMP startup
+
+aligned:
+	/* The input is now 8-byte aligned and we can process 8-byte chunks. */
+	CMPQ CX, $8
+	JL cleanup
+
+	CRC32Q (SI), AX
+	ADDQ $8, SI
+	SUBQ $8, CX
+	JMP aligned
+
+cleanup:
+	/* We may have some bytes left over that we process one at a time. */
+	CMPQ CX, $0
+	JE done
+
+	CRC32B (SI), AX
+	INCQ SI
+	DECQ CX
+	JMP cleanup
+
+done:
+	NOTL AX
+	MOVL AX, ret+16(FP)
+	RET
+
+// func haveSSE42() bool
+TEXT ·haveSSE42(SB),NOSPLIT,$0
+	XORQ AX, AX
+	INCL AX
+	CPUID
+	SHRQ $20, CX
+	ANDQ $1, CX
+	MOVB CX, ret+0(FP)
+	RET
+
diff --git a/src/pkg/hash/crc32/crc32_amd64.go b/src/pkg/hash/crc32/crc32_amd64x.go
similarity index 96%
rename from src/pkg/hash/crc32/crc32_amd64.go
rename to src/pkg/hash/crc32/crc32_amd64x.go
index b5bc6d3cf07df50da42a27afc27c27e576aaa3db..b7e359930a4ca59e2f3445f01a68bcad2cc984c7 100644
--- a/src/pkg/hash/crc32/crc32_amd64.go
+++ b/src/pkg/hash/crc32/crc32_amd64x.go
@@ -2,6 +2,8 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
+// +build amd64 amd64p32
+
 package crc32
 
 // This file contains the code to call the SSE 4.2 version of the Castagnoli
diff --git a/src/pkg/log/syslog/syslog.go b/src/pkg/log/syslog/syslog.go
index 0cbfa9011b8e0fa0dd9648634797bec0816bd6c1..1c7588e3656842e4a468bfdc0da90fb8f0b1ebb8 100644
--- a/src/pkg/log/syslog/syslog.go
+++ b/src/pkg/log/syslog/syslog.go
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build !windows,!plan9
+// +build !windows,!nacl,!plan9
 
 // Package syslog provides a simple interface to the system log
 // service. It can send messages to the syslog daemon using UNIX
diff --git a/src/pkg/log/syslog/syslog_test.go b/src/pkg/log/syslog/syslog_test.go
index 760a5c7d1e99169e399db5da6af4c8a3732816be..24a460f6d9eaaa0b33348e4a1a1c51e946a9d09a 100644
--- a/src/pkg/log/syslog/syslog_test.go
+++ b/src/pkg/log/syslog/syslog_test.go
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build !windows,!plan9
+// +build !windows,!nacl,!plan9
 
 package syslog
 
diff --git a/src/pkg/log/syslog/syslog_unix.go b/src/pkg/log/syslog/syslog_unix.go
index 28a294af96387eb96a2546522b54df304f62723d..f6d2f1b7a399ef89a1958b985dd8be6d9fd1e38c 100644
--- a/src/pkg/log/syslog/syslog_unix.go
+++ b/src/pkg/log/syslog/syslog_unix.go
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build !windows,!plan9
+// +build !windows,!nacl,!plan9
 
 package syslog
 
diff --git a/src/pkg/mime/type_unix.go b/src/pkg/mime/type_unix.go
index d949ba3f3e5ece6473337cdb51935a7bb32d39c6..1d394315a49b0cafd80d0177340a6f6c1d983e55 100644
--- a/src/pkg/mime/type_unix.go
+++ b/src/pkg/mime/type_unix.go
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build darwin dragonfly freebsd linux netbsd openbsd solaris
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris
 
 package mime
 
diff --git a/src/pkg/net/conn_test.go b/src/pkg/net/conn_test.go
index 7250dcb85ad766d9f8897d776041640bfe6bdb76..78aaa130df8acd43d756773b6fb8cf79908be8f3 100644
--- a/src/pkg/net/conn_test.go
+++ b/src/pkg/net/conn_test.go
@@ -33,7 +33,7 @@ func TestConnAndListener(t *testing.T) {
 		switch tt.net {
 		case "unix", "unixpacket":
 			switch runtime.GOOS {
-			case "plan9", "windows":
+			case "plan9", "windows", "nacl":
 				continue
 			}
 			if tt.net == "unixpacket" && runtime.GOOS != "linux" {
diff --git a/src/pkg/net/dnsclient_unix.go b/src/pkg/net/dnsclient_unix.go
index 7840d4eebbd680453775cd18da16be2e1ae1729d..2211e2190c7af304657fc8b9af880c54e5ce585a 100644
--- a/src/pkg/net/dnsclient_unix.go
+++ b/src/pkg/net/dnsclient_unix.go
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build darwin dragonfly freebsd linux netbsd openbsd solaris
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris
 
 // DNS client: see RFC 1035.
 // Has to be linked into package net for Dial.
diff --git a/src/pkg/net/dnsconfig_unix.go b/src/pkg/net/dnsconfig_unix.go
index 656b270f180dbdaf3c9b3e0aca09bbbb868474c3..af288253e09bacea861f751c779ae823c98035b2 100644
--- a/src/pkg/net/dnsconfig_unix.go
+++ b/src/pkg/net/dnsconfig_unix.go
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build darwin dragonfly freebsd linux netbsd openbsd solaris
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris
 
 // Read system DNS config from /etc/resolv.conf
 
diff --git a/src/pkg/net/fd_poll_nacl.go b/src/pkg/net/fd_poll_nacl.go
new file mode 100644
index 0000000000000000000000000000000000000000..a3701f8764833fcee124e49119ef13d8bdc14737
--- /dev/null
+++ b/src/pkg/net/fd_poll_nacl.go
@@ -0,0 +1,94 @@
+// Copyright 2013 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package net
+
+import (
+	"syscall"
+	"time"
+)
+
+type pollDesc struct {
+	fd      *netFD
+	closing bool
+}
+
+func (pd *pollDesc) Init(fd *netFD) error { pd.fd = fd; return nil }
+
+func (pd *pollDesc) Close() {}
+
+func (pd *pollDesc) Lock() {}
+
+func (pd *pollDesc) Unlock() {}
+
+func (pd *pollDesc) Wakeup() {}
+
+func (pd *pollDesc) Evict() bool {
+	pd.closing = true
+	if pd.fd != nil {
+		syscall.StopIO(pd.fd.sysfd)
+	}
+	return false
+}
+
+func (pd *pollDesc) Prepare(mode int) error {
+	if pd.closing {
+		return errClosing
+	}
+	return nil
+}
+
+func (pd *pollDesc) PrepareRead() error { return pd.Prepare('r') }
+
+func (pd *pollDesc) PrepareWrite() error { return pd.Prepare('w') }
+
+func (pd *pollDesc) Wait(mode int) error {
+	if pd.closing {
+		return errClosing
+	}
+	return errTimeout
+}
+
+func (pd *pollDesc) WaitRead() error { return pd.Wait('r') }
+
+func (pd *pollDesc) WaitWrite() error { return pd.Wait('w') }
+
+func (pd *pollDesc) WaitCanceled(mode int) {}
+
+func (pd *pollDesc) WaitCanceledRead() {}
+
+func (pd *pollDesc) WaitCanceledWrite() {}
+
+func (fd *netFD) setDeadline(t time.Time) error {
+	return setDeadlineImpl(fd, t, 'r'+'w')
+}
+
+func (fd *netFD) setReadDeadline(t time.Time) error {
+	return setDeadlineImpl(fd, t, 'r')
+}
+
+func (fd *netFD) setWriteDeadline(t time.Time) error {
+	return setDeadlineImpl(fd, t, 'w')
+}
+
+func setDeadlineImpl(fd *netFD, t time.Time, mode int) error {
+	d := t.UnixNano()
+	if t.IsZero() {
+		d = 0
+	}
+	if err := fd.incref(); err != nil {
+		return err
+	}
+	switch mode {
+	case 'r':
+		syscall.SetReadDeadline(fd.sysfd, d)
+	case 'w':
+		syscall.SetWriteDeadline(fd.sysfd, d)
+	case 'r' + 'w':
+		syscall.SetReadDeadline(fd.sysfd, d)
+		syscall.SetWriteDeadline(fd.sysfd, d)
+	}
+	fd.decref()
+	return nil
+}
diff --git a/src/pkg/net/fd_unix.go b/src/pkg/net/fd_unix.go
index f96dbf975df65f7604341aa3010140f9a88bd3d3..54aeaeb1984999a2f2e9488b9edb708a5319e28c 100644
--- a/src/pkg/net/fd_unix.go
+++ b/src/pkg/net/fd_unix.go
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build darwin dragonfly freebsd linux netbsd openbsd solaris
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris
 
 package net
 
diff --git a/src/pkg/net/file_test.go b/src/pkg/net/file_test.go
index e4615b74fc376de976fe9d9e0e95e8348ac5cfb1..09d1f4dcc0ad82464d2e4ae14f3633ecc30f6d60 100644
--- a/src/pkg/net/file_test.go
+++ b/src/pkg/net/file_test.go
@@ -181,7 +181,7 @@ var filePacketConnTests = []struct {
 
 func TestFilePacketConn(t *testing.T) {
 	switch runtime.GOOS {
-	case "plan9", "windows":
+	case "plan9", "windows", "nacl":
 		t.Skipf("skipping test on %q", runtime.GOOS)
 	}
 
diff --git a/src/pkg/net/file_unix.go b/src/pkg/net/file_unix.go
index 214a4196c8e3cfca5376ab380ef7912c07e7de97..c674b9b32013d827ef68728c7c52b305c997f954 100644
--- a/src/pkg/net/file_unix.go
+++ b/src/pkg/net/file_unix.go
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build darwin dragonfly freebsd linux netbsd openbsd solaris
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris
 
 package net
 
@@ -24,6 +24,7 @@ func newFileFD(f *os.File) (*netFD, error) {
 
 	sotype, err := syscall.GetsockoptInt(fd, syscall.SOL_SOCKET, syscall.SO_TYPE)
 	if err != nil {
+		println("getsockopt failed", fd, err.Error())
 		closesocket(fd)
 		return nil, os.NewSyscallError("getsockopt", err)
 	}
diff --git a/src/pkg/net/interface_stub.go b/src/pkg/net/interface_stub.go
index 31f6ee3e1c495b001537903b961e15675c09b76e..c38fb7f7651d9f584de7e0a272dad1aeca79d98d 100644
--- a/src/pkg/net/interface_stub.go
+++ b/src/pkg/net/interface_stub.go
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build plan9 solaris
+// +build nacl plan9 solaris
 
 package net
 
diff --git a/src/pkg/net/ipraw_test.go b/src/pkg/net/ipraw_test.go
index 1408b065d3ce1f95d6e0cbea60c8c077b7c1c7e4..51a1b2c2fecd1a2127b52c2c50aa5e0ab71f049d 100644
--- a/src/pkg/net/ipraw_test.go
+++ b/src/pkg/net/ipraw_test.go
@@ -247,7 +247,7 @@ var ipConnLocalNameTests = []struct {
 
 func TestIPConnLocalName(t *testing.T) {
 	switch runtime.GOOS {
-	case "plan9", "windows":
+	case "plan9", "windows", "nacl":
 		t.Skipf("skipping test on %q", runtime.GOOS)
 	default:
 		if os.Getuid() != 0 {
diff --git a/src/pkg/net/iprawsock_posix.go b/src/pkg/net/iprawsock_posix.go
index 517bea21f3944405a16bfc3904111258aaac0ca2..ff6c768481185cc608acebddecb4d7062f28e240 100644
--- a/src/pkg/net/iprawsock_posix.go
+++ b/src/pkg/net/iprawsock_posix.go
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build darwin dragonfly freebsd linux netbsd openbsd solaris windows
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris windows
 
 package net
 
diff --git a/src/pkg/net/ipsock_posix.go b/src/pkg/net/ipsock_posix.go
index 486c3f2b9a1646a25040848b2061f9a1dd3d4000..d2f45060f9876a83f750c7487b0e442d46445498 100644
--- a/src/pkg/net/ipsock_posix.go
+++ b/src/pkg/net/ipsock_posix.go
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build darwin dragonfly freebsd linux netbsd openbsd solaris windows
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris windows
 
 // Internet protocol family sockets for POSIX
 
diff --git a/src/pkg/net/lookup_unix.go b/src/pkg/net/lookup_unix.go
index a54578456d7c6ac49df2a0ae56460c90afaa3e0c..b1d2f8f31a9e6eea37a9659464e970e12699e6ff 100644
--- a/src/pkg/net/lookup_unix.go
+++ b/src/pkg/net/lookup_unix.go
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build darwin dragonfly freebsd linux netbsd openbsd solaris
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris
 
 package net
 
diff --git a/src/pkg/net/multicast_test.go b/src/pkg/net/multicast_test.go
index 0f313cc4cb8035598b478e119858223b41e2dc1b..63dbce88e9a5550b18e1bba1dacba3befac90fd0 100644
--- a/src/pkg/net/multicast_test.go
+++ b/src/pkg/net/multicast_test.go
@@ -25,7 +25,7 @@ var ipv4MulticastListenerTests = []struct {
 // port.
 func TestIPv4MulticastListener(t *testing.T) {
 	switch runtime.GOOS {
-	case "plan9":
+	case "nacl", "plan9":
 		t.Skipf("skipping test on %q", runtime.GOOS)
 	case "solaris":
 		t.Skipf("skipping test on solaris, see issue 7399")
diff --git a/src/pkg/net/net_test.go b/src/pkg/net/net_test.go
index c9fb433ec91b10edf57c3bbb8c3f265307ac5a71..93eb8659eac98f55ff66488c2b42e1d3aaa42308 100644
--- a/src/pkg/net/net_test.go
+++ b/src/pkg/net/net_test.go
@@ -62,7 +62,7 @@ func TestShutdown(t *testing.T) {
 
 func TestShutdownUnix(t *testing.T) {
 	switch runtime.GOOS {
-	case "windows", "plan9":
+	case "nacl", "plan9", "windows":
 		t.Skipf("skipping test on %q", runtime.GOOS)
 	}
 	f, err := ioutil.TempFile("", "go_net_unixtest")
diff --git a/src/pkg/net/port_unix.go b/src/pkg/net/port_unix.go
index a1beb840d595e82eb866c2b18f939331e30b8e76..5b803e610064aec9ad147586fc92118e91dd639a 100644
--- a/src/pkg/net/port_unix.go
+++ b/src/pkg/net/port_unix.go
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build darwin dragonfly freebsd linux netbsd openbsd solaris
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris
 
 // Read system port mappings from /etc/services
 
diff --git a/src/pkg/net/sendfile_stub.go b/src/pkg/net/sendfile_stub.go
index d7401e274da37a7d95539528c911f7f3a80a5dfc..03426ef0df17897e9966d95b7c44b5cd08e3759d 100644
--- a/src/pkg/net/sendfile_stub.go
+++ b/src/pkg/net/sendfile_stub.go
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build darwin netbsd openbsd solaris
+// +build darwin nacl netbsd openbsd solaris
 
 package net
 
diff --git a/src/pkg/net/sock_bsd.go b/src/pkg/net/sock_bsd.go
index 6c37109f5e4b02d84924719372e957bfb357bb13..48fb7852757c23687f3445f96ce46248bb7a1eb7 100644
--- a/src/pkg/net/sock_bsd.go
+++ b/src/pkg/net/sock_bsd.go
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build darwin dragonfly freebsd netbsd openbsd
+// +build darwin dragonfly freebsd nacl netbsd openbsd
 
 package net
 
diff --git a/src/pkg/net/sock_posix.go b/src/pkg/net/sock_posix.go
index 290596247efbb8cd3ec8b801c193073e82fd0ff4..a6ef874c9fda0b3304dd503f2c1b836d2b5e200f 100644
--- a/src/pkg/net/sock_posix.go
+++ b/src/pkg/net/sock_posix.go
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build darwin dragonfly freebsd linux netbsd openbsd solaris windows
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris windows
 
 package net
 
diff --git a/src/pkg/net/sockopt_bsd.go b/src/pkg/net/sockopt_bsd.go
index ef6eb85053bc9487747c08ce369276156eaea2b8..c0255f1644798eb068a0f4509ae3dbb5ce1daae9 100644
--- a/src/pkg/net/sockopt_bsd.go
+++ b/src/pkg/net/sockopt_bsd.go
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build darwin dragonfly freebsd netbsd openbsd
+// +build darwin dragonfly freebsd nacl netbsd openbsd
 
 package net
 
diff --git a/src/pkg/net/sockopt_posix.go b/src/pkg/net/sockopt_posix.go
index 1654d1b85e46c6481e0b7ebb5c009b3e205faa0f..921918c37f543b42dbb17569d82c3e2b2fcc45b5 100644
--- a/src/pkg/net/sockopt_posix.go
+++ b/src/pkg/net/sockopt_posix.go
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build darwin dragonfly freebsd linux netbsd openbsd solaris windows
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris windows
 
 package net
 
diff --git a/src/pkg/net/sockoptip_bsd.go b/src/pkg/net/sockoptip_bsd.go
index 0fa74718a6a38ffe5ea6dc4f8f2b36e5fbf46e9e..c6b339fa5a44d5015ec296b0b363b8ecac9626ee 100644
--- a/src/pkg/net/sockoptip_bsd.go
+++ b/src/pkg/net/sockoptip_bsd.go
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build darwin dragonfly freebsd netbsd openbsd solaris
+// +build darwin dragonfly freebsd nacl netbsd openbsd solaris
 
 package net
 
diff --git a/src/pkg/net/sockoptip_posix.go b/src/pkg/net/sockoptip_posix.go
index f38bb4f04069f51f4765c2c855e90750e7d8c32f..2aea6830b1c7296e6ba2680f6377c94374821c92 100644
--- a/src/pkg/net/sockoptip_posix.go
+++ b/src/pkg/net/sockoptip_posix.go
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build darwin dragonfly freebsd linux netbsd openbsd solaris windows
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris windows
 
 package net
 
diff --git a/src/pkg/net/sys_cloexec.go b/src/pkg/net/sys_cloexec.go
index cdc669b6210314038a074e947ba5d3d48ac05f45..19ba0fc00ccca91c128d8c6ee67138094fc1fa8d 100644
--- a/src/pkg/net/sys_cloexec.go
+++ b/src/pkg/net/sys_cloexec.go
@@ -5,7 +5,7 @@
 // This file implements sysSocket and accept for platforms that do not
 // provide a fast path for setting SetNonblock and CloseOnExec.
 
-// +build darwin dragonfly freebsd netbsd openbsd solaris
+// +build darwin dragonfly freebsd nacl netbsd openbsd solaris
 
 package net
 
diff --git a/src/pkg/net/tcpsock_posix.go b/src/pkg/net/tcpsock_posix.go
index 3727e470e63452c175df667cc71395b5e349915a..cbae7f3c62179be941c6d202bd11ac5f1157a2dd 100644
--- a/src/pkg/net/tcpsock_posix.go
+++ b/src/pkg/net/tcpsock_posix.go
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build darwin dragonfly freebsd linux netbsd openbsd solaris windows
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris windows
 
 package net
 
diff --git a/src/pkg/net/tcpsockopt_posix.go b/src/pkg/net/tcpsockopt_posix.go
index 0abf3f97f6b4e028f5ddfa0c792b951140453d1a..6484bad4b45d6f3a4856095cd8a0f42e8cc1a2e4 100644
--- a/src/pkg/net/tcpsockopt_posix.go
+++ b/src/pkg/net/tcpsockopt_posix.go
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build darwin dragonfly freebsd linux netbsd openbsd solaris windows
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris windows
 
 package net
 
diff --git a/src/pkg/net/tcpsockopt_unix.go b/src/pkg/net/tcpsockopt_unix.go
index 89d9143b52e2bfb54ac301decf8112b86e163cda..15d4fd9651960dfd1173ce5b9c9052751cd06730 100644
--- a/src/pkg/net/tcpsockopt_unix.go
+++ b/src/pkg/net/tcpsockopt_unix.go
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build dragonfly freebsd linux netbsd
+// +build dragonfly freebsd linux nacl netbsd
 
 package net
 
diff --git a/src/pkg/net/udpsock_posix.go b/src/pkg/net/udpsock_posix.go
index 11f9621dc363c966355a2673176fcbf6a087fb72..d81c2535687f5cd19a33d9c5285d0e0779d52cf7 100644
--- a/src/pkg/net/udpsock_posix.go
+++ b/src/pkg/net/udpsock_posix.go
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build darwin dragonfly freebsd linux netbsd openbsd solaris windows
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris windows
 
 package net
 
diff --git a/src/pkg/net/unixsock_posix.go b/src/pkg/net/unixsock_posix.go
index 5f1503acab969619a497051199f1361811d9953b..83f7c3f979851787d0d0d8f095653a1415da5e48 100644
--- a/src/pkg/net/unixsock_posix.go
+++ b/src/pkg/net/unixsock_posix.go
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build darwin dragonfly freebsd linux netbsd openbsd solaris windows
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris windows
 
 package net
 
diff --git a/src/pkg/os/dir_unix.go b/src/pkg/os/dir_unix.go
index 67c390283c7336349d714bef3c36d13126088a97..d353e405e54178088608408609ede466248fcfbb 100644
--- a/src/pkg/os/dir_unix.go
+++ b/src/pkg/os/dir_unix.go
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build darwin dragonfly freebsd linux netbsd openbsd solaris
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris
 
 package os
 
diff --git a/src/pkg/os/error_unix.go b/src/pkg/os/error_unix.go
index f281495e6b8e09ecc4eb144022f1fd4346282e28..f2aabbb45c43b5282ce97d1225cd08d568c826fd 100644
--- a/src/pkg/os/error_unix.go
+++ b/src/pkg/os/error_unix.go
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build darwin dragonfly freebsd linux netbsd openbsd solaris
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris
 
 package os
 
diff --git a/src/pkg/os/exec/lp_unix.go b/src/pkg/os/exec/lp_unix.go
index 7b9dec7e8b50894c4d1a1b0ff9848465c59c7087..3f895d5b3bacbe9d1001e21d1bba1adf9dfb80cb 100644
--- a/src/pkg/os/exec/lp_unix.go
+++ b/src/pkg/os/exec/lp_unix.go
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build darwin dragonfly freebsd linux netbsd openbsd solaris
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris
 
 package exec
 
diff --git a/src/pkg/os/exec_posix.go b/src/pkg/os/exec_posix.go
index 8a4d019d2f748ee4d45a513370b5a59c5a20f628..fb9d291e66453a936beb1fe3c01273c74dd938c1 100644
--- a/src/pkg/os/exec_posix.go
+++ b/src/pkg/os/exec_posix.go
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build darwin dragonfly freebsd linux netbsd openbsd solaris windows
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris windows
 
 package os
 
diff --git a/src/pkg/os/exec_unix.go b/src/pkg/os/exec_unix.go
index 3c05b8f080625136d1692f5e4a35b245194afb47..848a5de8f98e56878e72f1880fe47a35b2fdfcd0 100644
--- a/src/pkg/os/exec_unix.go
+++ b/src/pkg/os/exec_unix.go
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build darwin dragonfly freebsd linux netbsd openbsd solaris
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris
 
 package os
 
diff --git a/src/pkg/os/file_posix.go b/src/pkg/os/file_posix.go
index 441ad5384d70a20d3e75a7566789c69ed3d82d61..b3466b15cc8446477bec4ff602df29dd96a53953 100644
--- a/src/pkg/os/file_posix.go
+++ b/src/pkg/os/file_posix.go
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build darwin dragonfly freebsd linux netbsd openbsd solaris windows
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris windows
 
 package os
 
diff --git a/src/pkg/os/file_unix.go b/src/pkg/os/file_unix.go
index cfe0c1c2f87b5fed84fdbd9825e77fba39c764a4..f6d76f289df4608972e22b4298d80839a2f10ea9 100644
--- a/src/pkg/os/file_unix.go
+++ b/src/pkg/os/file_unix.go
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build darwin dragonfly freebsd linux netbsd openbsd solaris
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris
 
 package os
 
diff --git a/src/pkg/os/path_unix.go b/src/pkg/os/path_unix.go
index bdf9fe642187b58548a85e414fc8807251faea75..0211107ddfc42d3bb8a7610b043d5edb2ad0ed36 100644
--- a/src/pkg/os/path_unix.go
+++ b/src/pkg/os/path_unix.go
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build darwin dragonfly freebsd linux netbsd openbsd solaris
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris
 
 package os
 
diff --git a/src/pkg/os/pipe_bsd.go b/src/pkg/os/pipe_bsd.go
index 0ea8e4b1f83cd531219e1085de4e41bf60e0dc6d..3b81ed20f1b72df2d0de968721a92909c187c3e0 100644
--- a/src/pkg/os/pipe_bsd.go
+++ b/src/pkg/os/pipe_bsd.go
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build darwin dragonfly freebsd netbsd openbsd solaris
+// +build darwin dragonfly freebsd nacl netbsd openbsd solaris
 
 package os
 
diff --git a/src/pkg/os/signal/sig.s b/src/pkg/os/signal/sig.s
index 888823cf453a6ab9074de5f5252a88f94a5a46c1..f860924aa0b697b28fc52cdedbc464883984bdfe 100644
--- a/src/pkg/os/signal/sig.s
+++ b/src/pkg/os/signal/sig.s
@@ -4,7 +4,7 @@
 
 // Assembly to get into package runtime without using exported symbols.
 
-// +build amd64 arm 386
+// +build amd64 amd64p32 arm 386
 
 #include "../../../cmd/ld/textflag.h"
 
diff --git a/src/pkg/os/signal/signal_unix.go b/src/pkg/os/signal/signal_unix.go
index 80dc4304aaa4d625586ecb0c8f35bca5cf21b0e4..94b8ab3ddbf455795b5d222dcc6f1ca71b175e88 100644
--- a/src/pkg/os/signal/signal_unix.go
+++ b/src/pkg/os/signal/signal_unix.go
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build darwin dragonfly freebsd linux netbsd openbsd solaris windows
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris windows
 
 package signal
 
diff --git a/src/pkg/os/stat_nacl.go b/src/pkg/os/stat_nacl.go
new file mode 100644
index 0000000000000000000000000000000000000000..a503b59fa3fd2e461bb12928e95e1af97172cf59
--- /dev/null
+++ b/src/pkg/os/stat_nacl.go
@@ -0,0 +1,62 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package os
+
+import (
+	"syscall"
+	"time"
+)
+
+func sameFile(fs1, fs2 *fileStat) bool {
+	stat1 := fs1.sys.(*syscall.Stat_t)
+	stat2 := fs2.sys.(*syscall.Stat_t)
+	return stat1.Dev == stat2.Dev && stat1.Ino == stat2.Ino
+}
+
+func fileInfoFromStat(st *syscall.Stat_t, name string) FileInfo {
+	fs := &fileStat{
+		name:    basename(name),
+		size:    int64(st.Size),
+		modTime: timespecToTime(st.Mtime, st.MtimeNsec),
+		sys:     st,
+	}
+	fs.mode = FileMode(st.Mode & 0777)
+	switch st.Mode & syscall.S_IFMT {
+	case syscall.S_IFBLK:
+		fs.mode |= ModeDevice
+	case syscall.S_IFCHR:
+		fs.mode |= ModeDevice | ModeCharDevice
+	case syscall.S_IFDIR:
+		fs.mode |= ModeDir
+	case syscall.S_IFIFO:
+		fs.mode |= ModeNamedPipe
+	case syscall.S_IFLNK:
+		fs.mode |= ModeSymlink
+	case syscall.S_IFREG:
+		// nothing to do
+	case syscall.S_IFSOCK:
+		fs.mode |= ModeSocket
+	}
+	if st.Mode&syscall.S_ISGID != 0 {
+		fs.mode |= ModeSetgid
+	}
+	if st.Mode&syscall.S_ISUID != 0 {
+		fs.mode |= ModeSetuid
+	}
+	if st.Mode&syscall.S_ISVTX != 0 {
+		fs.mode |= ModeSticky
+	}
+	return fs
+}
+
+func timespecToTime(sec, nsec int64) time.Time {
+	return time.Unix(sec, nsec)
+}
+
+// For testing.
+func atime(fi FileInfo) time.Time {
+	st := fi.Sys().(*syscall.Stat_t)
+	return timespecToTime(st.Atime, st.AtimeNsec)
+}
diff --git a/src/pkg/os/sys_bsd.go b/src/pkg/os/sys_bsd.go
index 9ad2f8546b99f2242f4f01403a0afb96008a3121..8ad5e21837100c395e3cc4cadb6cd70f00291d3e 100644
--- a/src/pkg/os/sys_bsd.go
+++ b/src/pkg/os/sys_bsd.go
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build darwin dragonfly freebsd netbsd openbsd
+// +build darwin dragonfly freebsd nacl netbsd openbsd
 
 // os code shared between *BSD systems including OS X (Darwin)
 // and FreeBSD.
diff --git a/src/pkg/path/filepath/path_unix.go b/src/pkg/path/filepath/path_unix.go
index 2be675c3af1dc0b89765a5787507c67c7394903e..7aba0ab5b9bb2e09488612c8236a91859c0157ef 100644
--- a/src/pkg/path/filepath/path_unix.go
+++ b/src/pkg/path/filepath/path_unix.go
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build darwin dragonfly freebsd linux netbsd openbsd solaris
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris
 
 package filepath
 
diff --git a/src/pkg/reflect/asm_amd64p32.s b/src/pkg/reflect/asm_amd64p32.s
new file mode 100644
index 0000000000000000000000000000000000000000..75413c752101ff0375ec9bfc68d47186bd332afb
--- /dev/null
+++ b/src/pkg/reflect/asm_amd64p32.s
@@ -0,0 +1,27 @@
+// Copyright 2012 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "../../cmd/ld/textflag.h"
+
+// makeFuncStub is the code half of the function returned by MakeFunc.
+// See the comment on the declaration of makeFuncStub in makefunc.go
+// for more details.
+// No argsize here, gc generates argsize info at call site.
+TEXT ·makeFuncStub(SB),(NOSPLIT|WRAPPER),$8
+	MOVL	DX, 0(SP)
+	LEAL	argframe+0(FP), CX
+	MOVL	CX, 4(SP)
+	CALL	·callReflect(SB)
+	RET
+
+// methodValueCall is the code half of the function returned by makeMethodValue.
+// See the comment on the declaration of methodValueCall in makefunc.go
+// for more details.
+// No argsize here, gc generates argsize info at call site.
+TEXT ·methodValueCall(SB),(NOSPLIT|WRAPPER),$8
+	MOVL	DX, 0(SP)
+	LEAL	argframe+0(FP), CX
+	MOVL	CX, 4(SP)
+	CALL	·callMethod(SB)
+	RET
diff --git a/src/pkg/reflect/type.go b/src/pkg/reflect/type.go
index 51fdc1ecad69b523a9b19db75852efdb0aa0dfe3..3b4fe2190e133d7870ab0a759111b7ade46fc65d 100644
--- a/src/pkg/reflect/type.go
+++ b/src/pkg/reflect/type.go
@@ -16,6 +16,7 @@
 package reflect
 
 import (
+	"runtime"
 	"strconv"
 	"sync"
 	"unsafe"
@@ -1572,6 +1573,10 @@ func bucketOf(ktyp, etyp *rtype) *rtype {
 	gc = append(gc, _GC_PTR, offset, 0 /*self pointer set below*/) // overflow
 	offset += ptrsize
 
+	if runtime.GOARCH == "amd64p32" {
+		offset += 4
+	}
+
 	// keys
 	if ktyp.kind&kindNoPointers == 0 {
 		gc = append(gc, _GC_ARRAY_START, offset, _BUCKETSIZE, ktyp.size)
diff --git a/src/pkg/runtime/arch_386.h b/src/pkg/runtime/arch_386.h
index ebdb3ff4e27c85f11d3dcdf7560db3c95c9409c8..5c0a54f8c07b915dc59331bb65b63817df89e526 100644
--- a/src/pkg/runtime/arch_386.h
+++ b/src/pkg/runtime/arch_386.h
@@ -7,5 +7,10 @@ enum {
 	BigEndian = 0,
 	CacheLineSize = 64,
 	RuntimeGogoBytes = 64,
+#ifdef GOOS_nacl
+	PhysPageSize = 65536,
+#else
+	PhysPageSize = 4096,
+#endif
 	PCQuantum = 1
 };
diff --git a/src/pkg/runtime/arch_amd64.h b/src/pkg/runtime/arch_amd64.h
index 171839481bc00b42f4fa82c15e12866a882b073e..88b68cc6df58b7ebc500b5f0fbddbe537b8139ab 100644
--- a/src/pkg/runtime/arch_amd64.h
+++ b/src/pkg/runtime/arch_amd64.h
@@ -10,6 +10,11 @@ enum {
 	RuntimeGogoBytes = 80,
 #else
 	RuntimeGogoBytes = 64,
+#endif
+#ifdef GOOS_nacl
+	PhysPageSize = 65536,
+#else
+	PhysPageSize = 4096,
 #endif
 	PCQuantum = 1
 };
diff --git a/src/pkg/runtime/arch_amd64p32.h b/src/pkg/runtime/arch_amd64p32.h
new file mode 100644
index 0000000000000000000000000000000000000000..88b68cc6df58b7ebc500b5f0fbddbe537b8139ab
--- /dev/null
+++ b/src/pkg/runtime/arch_amd64p32.h
@@ -0,0 +1,20 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+enum {
+	thechar = '6',
+	BigEndian = 0,
+	CacheLineSize = 64,
+#ifdef GOOS_solaris
+	RuntimeGogoBytes = 80,
+#else
+	RuntimeGogoBytes = 64,
+#endif
+#ifdef GOOS_nacl
+	PhysPageSize = 65536,
+#else
+	PhysPageSize = 4096,
+#endif
+	PCQuantum = 1
+};
diff --git a/src/pkg/runtime/arch_arm.h b/src/pkg/runtime/arch_arm.h
index e5da01c6033be40ff5c1aa71c7b03d89a5b3cd13..b9711289f4fab26326ae7f77a1d723473e200153 100644
--- a/src/pkg/runtime/arch_arm.h
+++ b/src/pkg/runtime/arch_arm.h
@@ -7,5 +7,6 @@ enum {
 	BigEndian = 0,
 	CacheLineSize = 32,
 	RuntimeGogoBytes = 80,
+	PhysPageSize = 4096,
 	PCQuantum = 4
 };
diff --git a/src/pkg/runtime/mem_linux.c b/src/pkg/runtime/mem_linux.c
index b0f2956335453bdc31b1d1c6732177761264ad5a..2786ad70f6867bc43595491b77b5cc034f6f8fb3 100644
--- a/src/pkg/runtime/mem_linux.c
+++ b/src/pkg/runtime/mem_linux.c
@@ -11,6 +11,7 @@
 enum
 {
 	_PAGE_SIZE = 4096,
+	EACCES = 13,
 };
 
 static int32
diff --git a/src/pkg/runtime/mem_nacl.c b/src/pkg/runtime/mem_nacl.c
new file mode 100644
index 0000000000000000000000000000000000000000..993d194dd542dd4b4f8726de6c7ed105334fc1cf
--- /dev/null
+++ b/src/pkg/runtime/mem_nacl.c
@@ -0,0 +1,109 @@
+// Copyright 2010 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "runtime.h"
+#include "arch_GOARCH.h"
+#include "defs_GOOS_GOARCH.h"
+#include "os_GOOS.h"
+#include "malloc.h"
+
+enum
+{
+	Debug = 0,
+};
+
+void*
+runtime·SysAlloc(uintptr n, uint64 *stat)
+{
+	void *v;
+
+	v = runtime·mmap(nil, n, PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, -1, 0);
+	if(v < (void*)4096) {
+		if(Debug)
+			runtime·printf("SysAlloc(%p): %p\n", n, v);
+		return nil;
+	}
+	runtime·xadd64(stat, n);
+	if(Debug)
+		runtime·printf("SysAlloc(%p) = %p\n", n, v);
+	return v;
+}
+
+void
+runtime·SysUnused(void *v, uintptr n)
+{
+	if(Debug)
+		runtime·printf("SysUnused(%p, %p)\n", v, n);
+}
+
+void
+runtime·SysUsed(void *v, uintptr n)
+{
+	USED(v);
+	USED(n);
+}
+
+void
+runtime·SysFree(void *v, uintptr n, uint64 *stat)
+{
+	if(Debug)
+		runtime·printf("SysFree(%p, %p)\n", v, n);
+	runtime·xadd64(stat, -(uint64)n);
+	runtime·munmap(v, n);
+}
+
+void*
+runtime·SysReserve(void *v, uintptr n)
+{
+	void *p;
+
+	// On 64-bit, people with ulimit -v set complain if we reserve too
+	// much address space.  Instead, assume that the reservation is okay
+	// and check the assumption in SysMap.
+	if(NaCl || sizeof(void*) == 8)
+		return v;
+	
+	p = runtime·mmap(v, n, PROT_NONE, MAP_ANON|MAP_PRIVATE, -1, 0);
+	if(p < (void*)4096)
+		return nil;
+	return p;
+}
+
+void
+runtime·SysMap(void *v, uintptr n, uint64 *stat)
+{
+	void *p;
+	
+	runtime·xadd64(stat, n);
+
+	// On 64-bit, we don't actually have v reserved, so tread carefully.
+	if(sizeof(void*) == 8) {
+		p = runtime·mmap(v, n, PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, -1, 0);
+		if(p == (void*)ENOMEM) {
+			runtime·printf("SysMap(%p, %p): %p\n", v, n, p);
+			runtime·throw("runtime: out of memory");
+		}
+		if(p != v) {
+			runtime·printf("SysMap(%p, %p): %p\n", v, n, p);
+			runtime·printf("runtime: address space conflict: map(%p) = %p\n", v, p);
+			runtime·throw("runtime: address space conflict");
+		}
+		if(Debug)
+			runtime·printf("SysMap(%p, %p) = %p\n", v, n, p);
+		return;
+	}
+
+	p = runtime·mmap(v, n, PROT_READ|PROT_WRITE, MAP_ANON|MAP_FIXED|MAP_PRIVATE, -1, 0);
+	if(p == (void*)ENOMEM) {
+		runtime·printf("SysMap(%p, %p): %p\n", v, n, p);
+		runtime·throw("runtime: out of memory");
+	}
+	if(p != v) {
+		runtime·printf("SysMap(%p, %p): %p\n", v, n, p);
+		runtime·printf("mmap MAP_FIXED %p returned %p\n", v, p);
+		runtime·throw("runtime: cannot map pages in arena address space");
+	}
+	if(Debug)
+		runtime·printf("SysMap(%p, %p) = %p\n", v, n, p);
+}
diff --git a/src/pkg/runtime/mgc0.c b/src/pkg/runtime/mgc0.c
index 95c3e831516f25ebce18c31457d93a0c5c917127..8d91a6db2e4cfa7f555d54dad662800d64d74481 100644
--- a/src/pkg/runtime/mgc0.c
+++ b/src/pkg/runtime/mgc0.c
@@ -2771,6 +2771,7 @@ runtime·MHeap_MapBits(MHeap *h)
 
 	n = (h->arena_used - h->arena_start) / wordsPerBitmapWord;
 	n = ROUND(n, bitmapChunk);
+	n = ROUND(n, PhysPageSize);
 	if(h->bitmap_mapped >= n)
 		return;
 
diff --git a/src/pkg/runtime/mheap.c b/src/pkg/runtime/mheap.c
index ba46b6404e6456afe425004bb63a2c684adc76e4..d89512d3f10f2231f7812f3107b4185e1b307ca0 100644
--- a/src/pkg/runtime/mheap.c
+++ b/src/pkg/runtime/mheap.c
@@ -82,7 +82,7 @@ runtime·MHeap_MapSpans(MHeap *h)
 	n = (uintptr)h->arena_used;
 	n -= (uintptr)h->arena_start;
 	n = n / PageSize * sizeof(h->spans[0]);
-	n = ROUND(n, PageSize);
+	n = ROUND(n, PhysPageSize);
 	if(h->spans_mapped >= n)
 		return;
 	runtime·SysMap((byte*)h->spans + h->spans_mapped, n - h->spans_mapped, &mstats.other_sys);
diff --git a/src/pkg/runtime/mknacl.sh b/src/pkg/runtime/mknacl.sh
new file mode 100644
index 0000000000000000000000000000000000000000..47fb7bd88b06f4db6e187260a1eacd2179b83190
--- /dev/null
+++ b/src/pkg/runtime/mknacl.sh
@@ -0,0 +1,15 @@
+#!/bin/bash
+# Copyright 2013 The Go Authors.  All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+cat /Users/rsc/pub/native_client/src/trusted/service_runtime/include/bits/nacl_syscalls.h |
+	awk '
+	BEGIN {
+		printf("// generated by mknacl.sh - do not edit\n")
+	}
+	NF==3 && $1=="#define" && $2~/^NACL_sys_/ {
+		name=$2
+		sub(/^NACL_sys_/, "SYS_", name)
+		printf("#define %s %s\n", name, $3)
+	}' >syscall_nacl.h
diff --git a/src/pkg/runtime/netpoll.goc b/src/pkg/runtime/netpoll.goc
index 9cc5eb5a36b4614a26228eeeafb7d3201be0cdb2..77ddde9d60160e5c5d9d2977be5888ff2a0f087f 100644
--- a/src/pkg/runtime/netpoll.goc
+++ b/src/pkg/runtime/netpoll.goc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build darwin dragonfly freebsd linux netbsd openbsd solaris windows
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris windows
 
 package net
 
diff --git a/src/pkg/runtime/netpoll_nacl.c b/src/pkg/runtime/netpoll_nacl.c
new file mode 100644
index 0000000000000000000000000000000000000000..b75753a23b787b9d4d65d774a3f399c130c8b69e
--- /dev/null
+++ b/src/pkg/runtime/netpoll_nacl.c
@@ -0,0 +1,37 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "runtime.h"
+#include "defs_GOOS_GOARCH.h"
+#include "os_GOOS.h"
+
+// Fake network poller for NaCl.
+// Should never be used, because NaCl network connections do not honor "SetNonblock".
+
+void
+runtime·netpollinit(void)
+{
+}
+
+int32
+runtime·netpollopen(uintptr fd, PollDesc *pd)
+{
+	USED(fd);
+	USED(pd);
+	return 0;
+}
+
+int32
+runtime·netpollclose(uintptr fd)
+{
+	USED(fd);
+	return 0;
+}
+
+G*
+runtime·netpoll(bool block)
+{
+	USED(block);
+	return nil;
+}
diff --git a/src/pkg/runtime/os_nacl.c b/src/pkg/runtime/os_nacl.c
new file mode 100644
index 0000000000000000000000000000000000000000..3c5e487ad1278dc02443063399fe05bb248f905d
--- /dev/null
+++ b/src/pkg/runtime/os_nacl.c
@@ -0,0 +1,275 @@
+// Copyright 2010 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "runtime.h"
+#include "defs_GOOS_GOARCH.h"
+#include "os_GOOS.h"
+#include "arch_GOARCH.h"
+#include "../../cmd/ld/textflag.h"
+#include "stack.h"
+
+int8 *goos = "nacl";
+extern SigTab runtime·sigtab[];
+
+void runtime·sigtramp(void);
+
+// Called to initialize a new m (including the bootstrap m).
+// Called on the parent thread (main thread in case of bootstrap), can allocate memory.
+void
+runtime·mpreinit(M *mp)
+{
+	mp->gsignal = runtime·malg(32*1024);	// OS X wants >=8K, Linux >=2K
+}
+
+// Called to initialize a new m (including the bootstrap m).
+// Called on the new thread, can not allocate memory.
+void
+runtime·minit(void)
+{
+	int32 ret;
+
+	// Initialize signal handling
+	ret = runtime·nacl_exception_stack((byte*)m->gsignal->stackguard - StackGuard, 32*1024);
+	if(ret < 0)
+		runtime·printf("runtime: nacl_exception_stack: error %d\n", -ret);
+
+	ret = runtime·nacl_exception_handler(runtime·sigtramp, nil);
+	if(ret < 0)
+		runtime·printf("runtime: nacl_exception_handler: error %d\n", -ret);
+}
+
+// Called from dropm to undo the effect of an minit.
+void
+runtime·unminit(void)
+{
+}
+
+int8 runtime·sigtrampf[] = "runtime: signal at PC=%X AX=%X CX=%X DX=%X BX=%X DI=%X R15=%X *SP=%X\n";
+int8 runtime·sigtrampp[] = "runtime: sigtramp";
+
+extern byte runtime·tls0[];
+
+void
+runtime·osinit(void)
+{
+	runtime·ncpu = 1;
+	m->procid = 2;
+//runtime·nacl_exception_handler(runtime·sigtramp, nil);
+}
+
+void
+runtime·crash(void)
+{
+	*(int32*)0 = 0;
+}
+
+void
+runtime·get_random_data(byte **rnd, int32 *rnd_len)
+{
+	*rnd = nil;
+	*rnd_len = 0;
+}
+
+void
+runtime·goenvs(void)
+{
+	runtime·goenvs_unix();
+}
+
+void
+runtime·initsig(void)
+{
+}
+
+#pragma textflag NOSPLIT
+void
+runtime·usleep(uint32 us)
+{
+	Timespec ts;
+	
+	ts.tv_sec = us/1000000;
+	ts.tv_nsec = (us%1000000)*1000;
+	runtime·nacl_nanosleep(&ts, nil);
+}
+
+void runtime·mstart_nacl(void);
+
+void
+runtime·newosproc(M *mp, void *stk)
+{
+	int32 ret;
+	void **tls;
+
+	tls = (void**)mp->tls;
+	tls[0] = mp->g0;
+	tls[1] = mp;
+	ret = runtime·nacl_thread_create(runtime·mstart_nacl, stk, tls+2, 0);
+	if(ret < 0) {
+		runtime·printf("nacl_thread_create: error %d\n", -ret);
+		runtime·throw("newosproc");
+	}
+}
+
+uintptr
+runtime·semacreate(void)
+{
+	int32 mu, cond;
+	
+	mu = runtime·nacl_mutex_create(0);
+	if(mu < 0) {
+		runtime·printf("nacl_mutex_create: error %d\n", -mu);
+		runtime·throw("semacreate");
+	}
+	cond = runtime·nacl_cond_create(0);
+	if(cond < 0) {
+		runtime·printf("nacl_cond_create: error %d\n", -cond);
+		runtime·throw("semacreate");
+	}
+	m->waitsemalock = mu;
+	return cond; // assigned to m->waitsema
+}
+
+#pragma textflag NOSPLIT
+int32
+runtime·semasleep(int64 ns)
+{
+	int32 ret;
+	
+	ret = runtime·nacl_mutex_lock(m->waitsemalock);
+	if(ret < 0) {
+		//runtime·printf("nacl_mutex_lock: error %d\n", -ret);
+		runtime·throw("semasleep");
+	}
+	if(m->waitsemacount > 0) {
+		m->waitsemacount = 0;
+		runtime·nacl_mutex_unlock(m->waitsemalock);
+		return 0;
+	}
+
+	while(m->waitsemacount == 0) {
+		if(ns < 0) {
+			ret = runtime·nacl_cond_wait(m->waitsema, m->waitsemalock);
+			if(ret < 0) {
+				//runtime·printf("nacl_cond_wait: error %d\n", -ret);
+				runtime·throw("semasleep");
+			}
+		} else {
+			Timespec ts;
+			
+			ns += runtime·nanotime();
+			ts.tv_sec = runtime·timediv(ns, 1000000000, (int32*)&ts.tv_nsec);
+			ret = runtime·nacl_cond_timed_wait_abs(m->waitsema, m->waitsemalock, &ts);
+			if(ret == -ETIMEDOUT) {
+				runtime·nacl_mutex_unlock(m->waitsemalock);
+				return -1;
+			}
+			if(ret < 0) {
+				//runtime·printf("nacl_cond_timed_wait_abs: error %d\n", -ret);
+				runtime·throw("semasleep");
+			}
+		}
+	}
+			
+	m->waitsemacount = 0;
+	runtime·nacl_mutex_unlock(m->waitsemalock);
+	return 0;
+}
+
+void
+runtime·semawakeup(M *mp)
+{
+	int32 ret;
+	
+	ret = runtime·nacl_mutex_lock(mp->waitsemalock);
+	if(ret < 0) {
+		//runtime·printf("nacl_mutex_lock: error %d\n", -ret);
+		runtime·throw("semawakeup");
+	}
+	if(mp->waitsemacount != 0) {
+		//runtime·printf("semawakeup: double wakeup\n");
+		runtime·throw("semawakeup");
+	}
+	mp->waitsemacount = 1;
+	runtime·nacl_cond_signal(mp->waitsema);
+	runtime·nacl_mutex_unlock(mp->waitsemalock);
+}
+
+void
+os·sigpipe(void)
+{
+	runtime·throw("too many writes on closed pipe");
+}
+
+uintptr
+runtime·memlimit(void)
+{
+	runtime·printf("memlimit\n");
+	return 0;
+}
+
+#pragma dataflag NOPTR
+static int8 badsignal[] = "runtime: signal received on thread not created by Go.\n";
+
+// This runs on a foreign stack, without an m or a g.  No stack split.
+#pragma textflag NOSPLIT
+void
+runtime·badsignal2(void)
+{
+	runtime·write(2, badsignal, sizeof badsignal - 1);
+	runtime·exit(2);
+}
+
+void	runtime·madvise(byte*, uintptr, int32) { }
+void runtime·munmap(byte*, uintptr) {}
+
+void
+runtime·resetcpuprofiler(int32 hz)
+{
+	USED(hz);
+}
+
+void
+runtime·sigdisable(uint32)
+{
+}
+
+void
+runtime·sigenable(uint32)
+{
+}
+
+void
+runtime·closeonexec(int32)
+{
+}
+
+void
+runtime·sigpanic(void)
+{
+	// Native Client only invokes the exception handler for memory faults.
+	g->sig = SIGSEGV;
+	if(g->sigpc == 0)
+		runtime·panicstring("call of nil func value");
+	runtime·panicstring("invalid memory address or nil pointer dereference");
+}
+
+uint32 runtime·writelock; // test-and-set spin lock for runtime.write
+
+/*
+An attempt at IRT. Doesn't work. See end of sys_nacl_amd64.s.
+
+void (*runtime·nacl_irt_query)(void);
+
+int8 runtime·nacl_irt_basic_v0_1_str[] = "nacl-irt-basic-0.1";
+void *runtime·nacl_irt_basic_v0_1[6]; // exit, gettod, clock, nanosleep, sched_yield, sysconf
+int32 runtime·nacl_irt_basic_v0_1_size = sizeof(runtime·nacl_irt_basic_v0_1);
+
+int8 runtime·nacl_irt_memory_v0_3_str[] = "nacl-irt-memory-0.3";
+void *runtime·nacl_irt_memory_v0_3[3]; // mmap, munmap, mprotect
+int32 runtime·nacl_irt_memory_v0_3_size = sizeof(runtime·nacl_irt_memory_v0_3);
+
+int8 runtime·nacl_irt_thread_v0_1_str[] = "nacl-irt-thread-0.1";
+void *runtime·nacl_irt_thread_v0_1[3]; // thread_create, thread_exit, thread_nice
+int32 runtime·nacl_irt_thread_v0_1_size = sizeof(runtime·nacl_irt_thread_v0_1);
+*/
\ No newline at end of file
diff --git a/src/pkg/runtime/os_nacl.h b/src/pkg/runtime/os_nacl.h
new file mode 100644
index 0000000000000000000000000000000000000000..7c9d9c242fddf4dc5e30ca593136c47d1a452cd3
--- /dev/null
+++ b/src/pkg/runtime/os_nacl.h
@@ -0,0 +1,162 @@
+enum {
+	NSIG = 32,
+	SI_USER = 1,
+
+	// native_client/src/trusted/service_runtime/include/sys/errno.h
+	// The errors are mainly copied from Linux.
+	EPERM = 1,  /* Operation not permitted */
+	ENOENT = 2,  /* No such file or directory */
+	ESRCH = 3,  /* No such process */
+	EINTR = 4,  /* Interrupted system call */
+	EIO = 5,  /* I/O error */
+	ENXIO = 6,  /* No such device or address */
+	E2BIG = 7,  /* Argument list too long */
+	ENOEXEC = 8,  /* Exec format error */
+	EBADF = 9,  /* Bad file number */
+	ECHILD = 10,  /* No child processes */
+	EAGAIN = 11,  /* Try again */
+	ENOMEM = 12,  /* Out of memory */
+	EACCES = 13,  /* Permission denied */
+	EFAULT = 14,  /* Bad address */
+	EBUSY = 16,  /* Device or resource busy */
+	EEXIST = 17,  /* File exists */
+	EXDEV = 18,  /* Cross-device link */
+	ENODEV = 19,  /* No such device */
+	ENOTDIR = 20,  /* Not a directory */
+	EISDIR = 21,  /* Is a directory */
+	EINVAL = 22,  /* Invalid argument */
+	ENFILE = 23,  /* File table overflow */
+	EMFILE = 24,  /* Too many open files */
+	ENOTTY = 25,  /* Not a typewriter */
+	EFBIG = 27,  /* File too large */
+	ENOSPC = 28,  /* No space left on device */
+	ESPIPE = 29,  /* Illegal seek */
+	EROFS = 30,  /* Read-only file system */
+	EMLINK = 31,  /* Too many links */
+	EPIPE = 32,  /* Broken pipe */
+	ENAMETOOLONG = 36,  /* File name too long */
+	ENOSYS = 38,  /* Function not implemented */
+	EDQUOT = 122, /* Quota exceeded */
+	EDOM = 33,   /* Math arg out of domain of func */
+	ERANGE = 34, /* Math result not representable */
+	EDEADLK = 35,  /* Deadlock condition */
+	ENOLCK = 37, /* No record locks available */
+	ENOTEMPTY = 39,  /* Directory not empty */
+	ELOOP = 40,  /* Too many symbolic links */
+	ENOMSG = 42, /* No message of desired type */
+	EIDRM = 43,  /* Identifier removed */
+	ECHRNG = 44, /* Channel number out of range */
+	EL2NSYNC = 45, /* Level 2 not synchronized */
+	EL3HLT = 46, /* Level 3 halted */
+	EL3RST = 47, /* Level 3 reset */
+	ELNRNG = 48, /* Link number out of range */
+	EUNATCH = 49,  /* Protocol driver not attached */
+	ENOCSI = 50, /* No CSI structure available */
+	EL2HLT = 51, /* Level 2 halted */
+	EBADE = 52,  /* Invalid exchange */
+	EBADR = 53,  /* Invalid request descriptor */
+	EXFULL = 54, /* Exchange full */
+	ENOANO = 55, /* No anode */
+	EBADRQC = 56,  /* Invalid request code */
+	EBADSLT = 57,  /* Invalid slot */
+	EDEADLOCK = EDEADLK,  /* File locking deadlock error */
+	EBFONT = 59, /* Bad font file fmt */
+	ENOSTR = 60, /* Device not a stream */
+	ENODATA = 61,  /* No data (for no delay io) */
+	ETIME = 62,  /* Timer expired */
+	ENOSR = 63,  /* Out of streams resources */
+	ENONET = 64, /* Machine is not on the network */
+	ENOPKG = 65, /* Package not installed */
+	EREMOTE = 66,  /* The object is remote */
+	ENOLINK = 67,  /* The link has been severed */
+	EADV = 68,   /* Advertise error */
+	ESRMNT = 69, /* Srmount error */
+	ECOMM = 70,  /* Communication error on send */
+	EPROTO = 71, /* Protocol error */
+	EMULTIHOP = 72,  /* Multihop attempted */
+	EDOTDOT = 73,  /* Cross mount point (not really error) */
+	EBADMSG = 74,  /* Trying to read unreadable message */
+	EOVERFLOW = 75, /* Value too large for defined data type */
+	ENOTUNIQ = 76, /* Given log. name not unique */
+	EBADFD = 77, /* f.d. invalid for this operation */
+	EREMCHG = 78,  /* Remote address changed */
+	ELIBACC = 79,  /* Can't access a needed shared lib */
+	ELIBBAD = 80,  /* Accessing a corrupted shared lib */
+	ELIBSCN = 81,  /* .lib section in a.out corrupted */
+	ELIBMAX = 82,  /* Attempting to link in too many libs */
+	ELIBEXEC = 83, /* Attempting to exec a shared library */
+	EILSEQ = 84,
+	EUSERS = 87,
+	ENOTSOCK = 88,  /* Socket operation on non-socket */
+	EDESTADDRREQ = 89,  /* Destination address required */
+	EMSGSIZE = 90,    /* Message too long */
+	EPROTOTYPE = 91,  /* Protocol wrong type for socket */
+	ENOPROTOOPT = 92, /* Protocol not available */
+	EPROTONOSUPPORT = 93, /* Unknown protocol */
+	ESOCKTNOSUPPORT = 94, /* Socket type not supported */
+	EOPNOTSUPP = 95, /* Operation not supported on transport endpoint */
+	EPFNOSUPPORT = 96, /* Protocol family not supported */
+	EAFNOSUPPORT = 97, /* Address family not supported by protocol family */
+	EADDRINUSE = 98,    /* Address already in use */
+	EADDRNOTAVAIL = 99, /* Address not available */
+	ENETDOWN = 100,    /* Network interface is not configured */
+	ENETUNREACH = 101,   /* Network is unreachable */
+	ENETRESET = 102,
+	ECONNABORTED = 103,  /* Connection aborted */
+	ECONNRESET = 104,  /* Connection reset by peer */
+	ENOBUFS = 105, /* No buffer space available */
+	EISCONN = 106,   /* Socket is already connected */
+	ENOTCONN = 107,    /* Socket is not connected */
+	ESHUTDOWN = 108, /* Can't send after socket shutdown */
+	ETOOMANYREFS = 109,
+	ETIMEDOUT = 110,   /* Connection timed out */
+	ECONNREFUSED = 111,  /* Connection refused */
+	EHOSTDOWN = 112,   /* Host is down */
+	EHOSTUNREACH = 113,  /* Host is unreachable */
+	EALREADY = 114,    /* Socket already connected */
+	EINPROGRESS = 115,   /* Connection already in progress */
+	ESTALE = 116,
+	ENOTSUP = EOPNOTSUPP,   /* Not supported */
+	ENOMEDIUM = 123,   /* No medium (in tape drive) */
+	ECANCELED = 125, /* Operation canceled. */
+	ELBIN = 2048,  /* Inode is remote (not really error) */
+	EFTYPE = 2049,  /* Inappropriate file type or format */
+	ENMFILE = 2050,  /* No more files */
+	EPROCLIM = 2051,
+	ENOSHARE = 2052,  /* No such host or network path */
+	ECASECLASH = 2053,  /* Filename exists with different case */
+	EWOULDBLOCK = EAGAIN,      /* Operation would block */
+
+	// native_client/src/trusted/service_runtime/include/bits/mman.h.
+	// NOTE: DO NOT USE native_client/src/shared/imc/nacl_imc_c.h.
+	// Those MAP_*values are different from these.
+	PROT_NONE	= 0x0,
+	PROT_READ	= 0x1,
+	PROT_WRITE	= 0x2,
+	PROT_EXEC	= 0x4,
+
+	MAP_SHARED	= 0x1,
+	MAP_PRIVATE	= 0x2,
+	MAP_FIXED	= 0x10,
+	MAP_ANON	= 0x20,
+};
+typedef byte* kevent_udata;
+
+int32	runtime·nacl_exception_stack(byte*, int32);
+int32	runtime·nacl_exception_handler(void*, void*);
+int32	runtime·nacl_sem_create(int32);
+int32	runtime·nacl_sem_wait(int32);
+int32	runtime·nacl_sem_post(int32);
+int32	runtime·nacl_mutex_create(int32);
+int32	runtime·nacl_mutex_lock(int32);
+int32	runtime·nacl_mutex_trylock(int32);
+int32	runtime·nacl_mutex_unlock(int32);
+int32	runtime·nacl_cond_create(int32);
+int32	runtime·nacl_cond_wait(int32, int32);
+int32	runtime·nacl_cond_signal(int32);
+int32	runtime·nacl_cond_broadcast(int32);
+int32	runtime·nacl_cond_timed_wait_abs(int32, int32, Timespec*);
+int32	runtime·nacl_thread_create(void*, void*, void*, void*);
+int32	runtime·nacl_nanosleep(Timespec*, Timespec*);
+
+void	runtime·sigpanic(void);
diff --git a/src/pkg/runtime/runtime.h b/src/pkg/runtime/runtime.h
index c9887b66372ce328a22620c97512f59590353489..0069d5a774d71f8ae008f8c57d11849224d62bcf 100644
--- a/src/pkg/runtime/runtime.h
+++ b/src/pkg/runtime/runtime.h
@@ -21,11 +21,19 @@ typedef	uint64		uintptr;
 typedef	int64		intptr;
 typedef	int64		intgo; // Go's int
 typedef	uint64		uintgo; // Go's uint
+typedef	uint64		uintreg;
 #else
 typedef	uint32		uintptr;
 typedef	int32		intptr;
 typedef	int32		intgo; // Go's int
 typedef	uint32		uintgo; // Go's uint
+typedef	uint32		uintreg;
+#endif
+
+#ifdef _64BITREG
+//typedef	uint64		uintreg;
+#else
+//typedef	uint32		uintreg;
 #endif
 
 /*
@@ -209,8 +217,8 @@ struct	Gobuf
 	uintptr	sp;
 	uintptr	pc;
 	G*	g;
-	uintptr	ret;
 	void*	ctxt;
+	uintreg	ret;
 	uintptr	lr;
 };
 struct	GCStats
@@ -295,8 +303,8 @@ struct	M
 
 	// Fields not known to debuggers.
 	uint32	moreframesize;	// size arguments to morestack
-	uint32	moreargsize;
-	uintptr	cret;		// return value from C
+	uint32	moreargsize;	// known by amd64 asm to follow moreframesize
+	uintreg	cret;		// return value from C
 	uint64	procid;		// for debuggers, but offset not hard-coded
 	G*	gsignal;	// signal-handling G
 	uintptr	tls[4];		// thread-local storage (for x86 extern register)
@@ -479,6 +487,16 @@ struct	Itab
 	void	(*fun[])(void);
 };
 
+#ifdef GOOS_nacl
+enum {
+   NaCl = 1,
+};
+#else
+enum {
+   NaCl = 0,
+};
+#endif
+
 #ifdef GOOS_windows
 enum {
    Windows = 1
@@ -512,6 +530,8 @@ struct	Timers
 
 // Package time knows the layout of this structure.
 // If this struct changes, adjust ../time/sleep.go:/runtimeTimer.
+// For GOOS=nacl, package syscall knows the layout of this structure.
+// If this struct changes, adjust ../syscall/net_nacl.go:/runtimeTimer.
 struct	Timer
 {
 	int32	i;	// heap index
@@ -588,7 +608,7 @@ extern bool runtime·precisestack;
  * known to compiler
  */
 enum {
-	Structrnd = sizeof(uintptr)
+	Structrnd = sizeof(uintreg),
 };
 
 /*
@@ -762,6 +782,7 @@ void	runtime·dump(byte*, int32);
 int32	runtime·runetochar(byte*, int32);
 int32	runtime·charntorune(int32*, uint8*, int32);
 
+
 /*
  * This macro is used when writing C functions
  * called as if they were Go functions.
@@ -774,8 +795,6 @@ int32	runtime·charntorune(int32*, uint8*, int32);
  * first output value. Almost all code should write such
  * functions in .goc files, where goc2c (part of cmd/dist)
  * can arrange the correct alignment for the target system.
- * Goc2c also takes care of conveying to the garbage collector
- * which parts of the argument list are input vs outputs.
  *
  * Therefore, do NOT use this macro if at all possible.
  */ 
@@ -926,6 +945,7 @@ void	runtime·parsedebugvars(void);
 void	_rt0_go(void);
 void*	runtime·funcdata(Func*, int32);
 int32	runtime·setmaxthreads(int32);
+G*	runtime·timejump(void);
 
 #pragma	varargck	argpos	runtime·printf	1
 #pragma	varargck	type	"c"	int32
@@ -1016,13 +1036,6 @@ void	runtime·parforsetup(ParFor *desc, uint32 nthr, uint32 n, void *ctx, bool w
 void	runtime·parfordo(ParFor *desc);
 void	runtime·parforiters(ParFor*, uintptr, uintptr*, uintptr*);
 
-/*
- * This is consistent across Linux and BSD.
- * If a new OS is added that is different, move this to
- * $GOOS/$GOARCH/defs.h.
- */
-#define EACCES		13
-
 /*
  * low level C-called
  */
@@ -1057,6 +1070,7 @@ void	reflect·call(FuncVal*, byte*, uint32);
 void	runtime·panic(Eface);
 void	runtime·panicindex(void);
 void	runtime·panicslice(void);
+void	runtime·panicdivide(void);
 
 /*
  * runtime c-called (but written in Go)
diff --git a/src/pkg/runtime/signal_386.c b/src/pkg/runtime/signal_386.c
index 553ea87e49b38a8e718f1d1a099873ba26f1688c..9f3f52179c480a1bb9b7a0ef35ee941d06bf9269 100644
--- a/src/pkg/runtime/signal_386.c
+++ b/src/pkg/runtime/signal_386.c
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build darwin dragonfly freebsd linux netbsd openbsd
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd
 
 #include "runtime.h"
 #include "defs_GOOS_GOARCH.h"
diff --git a/src/pkg/runtime/signal_nacl_386.h b/src/pkg/runtime/signal_nacl_386.h
new file mode 100644
index 0000000000000000000000000000000000000000..c9481b5f4f3b078a0a2cc44c30eef750de188123
--- /dev/null
+++ b/src/pkg/runtime/signal_nacl_386.h
@@ -0,0 +1,23 @@
+// Copyright 2013 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#define SIG_REGS(ctxt) (((ExcContext*)(ctxt))->regs)
+
+#define SIG_EAX(info, ctxt) (SIG_REGS(ctxt).eax)
+#define SIG_EBX(info, ctxt) (SIG_REGS(ctxt).ebx)
+#define SIG_ECX(info, ctxt) (SIG_REGS(ctxt).ecx)
+#define SIG_EDX(info, ctxt) (SIG_REGS(ctxt).edx)
+#define SIG_EDI(info, ctxt) (SIG_REGS(ctxt).edi)
+#define SIG_ESI(info, ctxt) (SIG_REGS(ctxt).esi)
+#define SIG_EBP(info, ctxt) (SIG_REGS(ctxt).ebp)
+#define SIG_ESP(info, ctxt) (SIG_REGS(ctxt).esp)
+#define SIG_EIP(info, ctxt) (SIG_REGS(ctxt).eip)
+#define SIG_EFLAGS(info, ctxt) (SIG_REGS(ctxt).eflags)
+
+#define SIG_CS(info, ctxt) (~0)
+#define SIG_FS(info, ctxt) (~0)
+#define SIG_GS(info, ctxt) (~0)
+
+#define SIG_CODE0(info, ctxt) (~0)
+#define SIG_CODE1(info, ctxt) (0)
diff --git a/src/pkg/runtime/signal_nacl_amd64p32.h b/src/pkg/runtime/signal_nacl_amd64p32.h
new file mode 100644
index 0000000000000000000000000000000000000000..c58593a2918ad5571ff2c54484929891df894923
--- /dev/null
+++ b/src/pkg/runtime/signal_nacl_amd64p32.h
@@ -0,0 +1,31 @@
+// Copyright 2013 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#define SIG_REGS(ctxt) (((ExcContext*)(ctxt))->regs64)
+
+#define SIG_RAX(info, ctxt) (SIG_REGS(ctxt).rax)
+#define SIG_RBX(info, ctxt) (SIG_REGS(ctxt).rbx)
+#define SIG_RCX(info, ctxt) (SIG_REGS(ctxt).rcx)
+#define SIG_RDX(info, ctxt) (SIG_REGS(ctxt).rdx)
+#define SIG_RDI(info, ctxt) (SIG_REGS(ctxt).rdi)
+#define SIG_RSI(info, ctxt) (SIG_REGS(ctxt).rsi)
+#define SIG_RBP(info, ctxt) (SIG_REGS(ctxt).rbp)
+#define SIG_RSP(info, ctxt) (SIG_REGS(ctxt).rsp)
+#define SIG_R8(info, ctxt) (SIG_REGS(ctxt).r8)
+#define SIG_R9(info, ctxt) (SIG_REGS(ctxt).r9)
+#define SIG_R10(info, ctxt) (SIG_REGS(ctxt).r10)
+#define SIG_R11(info, ctxt) (SIG_REGS(ctxt).r11)
+#define SIG_R12(info, ctxt) (SIG_REGS(ctxt).r12)
+#define SIG_R13(info, ctxt) (SIG_REGS(ctxt).r13)
+#define SIG_R14(info, ctxt) (SIG_REGS(ctxt).r14)
+#define SIG_R15(info, ctxt) (SIG_REGS(ctxt).r15)
+#define SIG_RIP(info, ctxt) (SIG_REGS(ctxt).rip)
+#define SIG_RFLAGS(info, ctxt) (SIG_REGS(ctxt).rflags)
+
+#define SIG_CS(info, ctxt) (~0)
+#define SIG_FS(info, ctxt) (~0)
+#define SIG_GS(info, ctxt) (~0)
+
+#define SIG_CODE0(info, ctxt) (~0)
+#define SIG_CODE1(info, ctxt) (0)
diff --git a/src/pkg/runtime/signals_nacl.h b/src/pkg/runtime/signals_nacl.h
new file mode 100644
index 0000000000000000000000000000000000000000..229b585902565f4445d32a0d21980287545301ff
--- /dev/null
+++ b/src/pkg/runtime/signals_nacl.h
@@ -0,0 +1,50 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#define N SigNotify
+#define K SigKill
+#define T SigThrow
+#define P SigPanic
+#define D SigDefault
+
+SigTab runtime·sigtab[] = {
+	/* 0 */	0, "SIGNONE: no trap",
+	/* 1 */	N+K, "SIGHUP: terminal line hangup",
+	/* 2 */	N+K, "SIGINT: interrupt",
+	/* 3 */	N+T, "SIGQUIT: quit",
+	/* 4 */	T, "SIGILL: illegal instruction",
+	/* 5 */	T, "SIGTRAP: trace trap",
+	/* 6 */	N+T, "SIGABRT: abort",
+	/* 7 */	T, "SIGEMT: emulate instruction executed",
+	/* 8 */	P, "SIGFPE: floating-point exception",
+	/* 9 */	0, "SIGKILL: kill",
+	/* 10 */	P, "SIGBUS: bus error",
+	/* 11 */	P, "SIGSEGV: segmentation violation",
+	/* 12 */	T, "SIGSYS: bad system call",
+	/* 13 */	N, "SIGPIPE: write to broken pipe",
+	/* 14 */	N, "SIGALRM: alarm clock",
+	/* 15 */	N+K, "SIGTERM: termination",
+	/* 16 */	N, "SIGURG: urgent condition on socket",
+	/* 17 */	0, "SIGSTOP: stop",
+	/* 18 */	N+D, "SIGTSTP: keyboard stop",
+	/* 19 */	0, "SIGCONT: continue after stop",
+	/* 20 */	N, "SIGCHLD: child status has changed",
+	/* 21 */	N+D, "SIGTTIN: background read from tty",
+	/* 22 */	N+D, "SIGTTOU: background write to tty",
+	/* 23 */	N, "SIGIO: i/o now possible",
+	/* 24 */	N, "SIGXCPU: cpu limit exceeded",
+	/* 25 */	N, "SIGXFSZ: file size limit exceeded",
+	/* 26 */	N, "SIGVTALRM: virtual alarm clock",
+	/* 27 */	N, "SIGPROF: profiling alarm clock",
+	/* 28 */	N, "SIGWINCH: window size change",
+	/* 29 */	N, "SIGINFO: status request from keyboard",
+	/* 30 */	N, "SIGUSR1: user-defined signal 1",
+	/* 31 */	N, "SIGUSR2: user-defined signal 2",
+};
+
+#undef N
+#undef K
+#undef T
+#undef P
+#undef D
diff --git a/src/pkg/runtime/sys_x86.c b/src/pkg/runtime/sys_x86.c
index f24337eac71240121c0eefea079613be34265c2e..a450b3e58443363280950ffcbda63cc537520d5d 100644
--- a/src/pkg/runtime/sys_x86.c
+++ b/src/pkg/runtime/sys_x86.c
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build amd64 386
+// +build amd64 amd64p32 386
 
 #include "runtime.h"
 
@@ -14,6 +14,8 @@ runtime·gostartcall(Gobuf *gobuf, void (*fn)(void), void *ctxt)
 	uintptr *sp;
 	
 	sp = (uintptr*)gobuf->sp;
+	if(sizeof(uintreg) > sizeof(uintptr))
+		*--sp = 0;
 	*--sp = (uintptr)gobuf->pc;
 	gobuf->sp = (uintptr)sp;
 	gobuf->pc = (uintptr)fn;
diff --git a/src/pkg/runtime/syscall_nacl.h b/src/pkg/runtime/syscall_nacl.h
new file mode 100644
index 0000000000000000000000000000000000000000..b33852ec8d0d7410be29ce32117ac38319d95d7e
--- /dev/null
+++ b/src/pkg/runtime/syscall_nacl.h
@@ -0,0 +1,71 @@
+// generated by mknacl.sh - do not edit
+#define SYS_null 1
+#define SYS_nameservice 2
+#define SYS_dup 8
+#define SYS_dup2 9
+#define SYS_open 10
+#define SYS_close 11
+#define SYS_read 12
+#define SYS_write 13
+#define SYS_lseek 14
+#define SYS_ioctl 15
+#define SYS_stat 16
+#define SYS_fstat 17
+#define SYS_chmod 18
+#define SYS_brk 20
+#define SYS_mmap 21
+#define SYS_munmap 22
+#define SYS_getdents 23
+#define SYS_mprotect 24
+#define SYS_list_mappings 25
+#define SYS_exit 30
+#define SYS_getpid 31
+#define SYS_sched_yield 32
+#define SYS_sysconf 33
+#define SYS_gettimeofday 40
+#define SYS_clock 41
+#define SYS_nanosleep 42
+#define SYS_clock_getres 43
+#define SYS_clock_gettime 44
+#define SYS_mkdir 45
+#define SYS_rmdir 46
+#define SYS_chdir 47
+#define SYS_getcwd 48
+#define SYS_unlink 49
+#define SYS_imc_makeboundsock 60
+#define SYS_imc_accept 61
+#define SYS_imc_connect 62
+#define SYS_imc_sendmsg 63
+#define SYS_imc_recvmsg 64
+#define SYS_imc_mem_obj_create 65
+#define SYS_imc_socketpair 66
+#define SYS_mutex_create 70
+#define SYS_mutex_lock 71
+#define SYS_mutex_trylock 72
+#define SYS_mutex_unlock 73
+#define SYS_cond_create 74
+#define SYS_cond_wait 75
+#define SYS_cond_signal 76
+#define SYS_cond_broadcast 77
+#define SYS_cond_timed_wait_abs 79
+#define SYS_thread_create 80
+#define SYS_thread_exit 81
+#define SYS_tls_init 82
+#define SYS_thread_nice 83
+#define SYS_tls_get 84
+#define SYS_second_tls_set 85
+#define SYS_second_tls_get 86
+#define SYS_exception_handler 87
+#define SYS_exception_stack 88
+#define SYS_exception_clear_flag 89
+#define SYS_sem_create 100
+#define SYS_sem_wait 101
+#define SYS_sem_post 102
+#define SYS_sem_get_value 103
+#define SYS_dyncode_create 104
+#define SYS_dyncode_modify 105
+#define SYS_dyncode_delete 106
+#define SYS_test_infoleak 109
+#define SYS_test_crash 110
+#define SYS_test_syscall_1 111
+#define SYS_test_syscall_2 112
diff --git a/src/pkg/runtime/traceback_x86.c b/src/pkg/runtime/traceback_x86.c
index fa46d547a837222f2872ff5fb97c394aa92d0e02..bd431be2245dd209b7646f73db8731a70877cba8 100644
--- a/src/pkg/runtime/traceback_x86.c
+++ b/src/pkg/runtime/traceback_x86.c
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build amd64 386
+// +build amd64 amd64p32 386
 
 #include "runtime.h"
 #include "arch_GOARCH.h"
@@ -52,7 +52,7 @@ runtime·gentraceback(uintptr pc0, uintptr sp0, uintptr lr0, G *gp, int32 skip,
 	// Start in the caller's frame.
 	if(frame.pc == 0) {
 		frame.pc = *(uintptr*)frame.sp;
-		frame.sp += sizeof(uintptr);
+		frame.sp += sizeof(uintreg);
 	}
 	
 	f = runtime·findfunc(frame.pc);
@@ -101,14 +101,14 @@ runtime·gentraceback(uintptr pc0, uintptr sp0, uintptr lr0, G *gp, int32 skip,
 		// Derive frame pointer and link register.
 		if(frame.fp == 0) {
 			frame.fp = frame.sp + runtime·funcspdelta(f, frame.pc);
-			frame.fp += sizeof(uintptr); // caller PC
+			frame.fp += sizeof(uintreg); // caller PC
 		}
 		if(runtime·topofstack(f)) {
 			frame.lr = 0;
 			flr = nil;
 		} else {
 			if(frame.lr == 0)
-				frame.lr = ((uintptr*)frame.fp)[-1];
+				frame.lr = ((uintreg*)frame.fp)[-1];
 			flr = runtime·findfunc(frame.lr);
 			if(flr == nil) {
 				runtime·printf("runtime: unexpected return pc for %s called from %p\n", runtime·funcname(f), frame.lr);
@@ -117,7 +117,7 @@ runtime·gentraceback(uintptr pc0, uintptr sp0, uintptr lr0, G *gp, int32 skip,
 			}
 		}
 		
-		frame.varp = (byte*)frame.fp - sizeof(uintptr);
+		frame.varp = (byte*)frame.fp - sizeof(uintreg);
 
 		// Derive size of arguments.
 		// Most functions have a fixed-size argument block,
diff --git a/src/pkg/runtime/vlrt_386.c b/src/pkg/runtime/vlrt_386.c
index 8d965c086e4df1b5029fe3011d515a646bfacc55..ace1beb4cce7733549283bbb8ac8f17e0b683108 100644
--- a/src/pkg/runtime/vlrt_386.c
+++ b/src/pkg/runtime/vlrt_386.c
@@ -32,6 +32,8 @@
  * to generate the code directly now.  Find and remove.
  */
 
+extern void runtime·panicdivide(void);
+
 typedef	unsigned long	ulong;
 typedef	unsigned int	uint;
 typedef	unsigned short	ushort;
@@ -240,6 +242,8 @@ dodiv(Vlong num, Vlong den, Vlong *qp, Vlong *rp)
 		}
 	} else {
 		if(num.hi >= den.lo){
+			if(den.lo == 0)
+				runtime·panicdivide();
 			q.hi = n = num.hi/den.lo;
 			num.hi -= den.lo*n;
 		} else {
@@ -263,6 +267,8 @@ _divvu(Vlong *q, Vlong n, Vlong d)
 {
 
 	if(n.hi == 0 && d.hi == 0) {
+		if(d.lo == 0)
+			runtime·panicdivide();
 		q->hi = 0;
 		q->lo = n.lo / d.lo;
 		return;
@@ -281,6 +287,8 @@ _modvu(Vlong *r, Vlong n, Vlong d)
 {
 
 	if(n.hi == 0 && d.hi == 0) {
+		if(d.lo == 0)
+			runtime·panicdivide();
 		r->hi = 0;
 		r->lo = n.lo % d.lo;
 		return;
@@ -319,6 +327,8 @@ _divv(Vlong *q, Vlong n, Vlong d)
 			q->hi = 0;
 			return;
 		}
+		if(d.lo == 0)
+			runtime·panicdivide();
 		q->lo = (long)n.lo / (long)d.lo;
 		q->hi = ((long)q->lo) >> 31;
 		return;
@@ -353,6 +363,8 @@ _modv(Vlong *r, Vlong n, Vlong d)
 			r->hi = 0;
 			return;
 		}
+		if(d.lo == 0)
+			runtime·panicdivide();
 		r->lo = (long)n.lo % (long)d.lo;
 		r->hi = ((long)r->lo) >> 31;
 		return;
diff --git a/src/pkg/runtime/vlrt_arm.c b/src/pkg/runtime/vlrt_arm.c
index 219163c60f7bc213b5e040a4e33cbe82db8d2102..9606e1607643d3ed3c7fba272c3d7c4529c9a432 100644
--- a/src/pkg/runtime/vlrt_arm.c
+++ b/src/pkg/runtime/vlrt_arm.c
@@ -36,12 +36,6 @@ typedef signed char     schar;
 
 #define SIGN(n) (1UL<<(n-1))
 
-void
-runtime·panicdivide(void)
-{
-	runtime·panicstring("integer divide by zero");
-}
-
 typedef struct  Vlong   Vlong;
 struct  Vlong
 {
diff --git a/src/pkg/sync/atomic/asm_amd64p32.s b/src/pkg/sync/atomic/asm_amd64p32.s
new file mode 100644
index 0000000000000000000000000000000000000000..4c602ab5945c0065f0100fcab17093f3f6dc23cd
--- /dev/null
+++ b/src/pkg/sync/atomic/asm_amd64p32.s
@@ -0,0 +1,159 @@
+// Copyright 2011 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "../../../cmd/ld/textflag.h"
+
+TEXT ·SwapInt32(SB),NOSPLIT,$0-12
+	JMP	·SwapUint32(SB)
+
+TEXT ·SwapUint32(SB),NOSPLIT,$0-12
+	MOVL	addr+0(FP), BX
+	MOVL	new+4(FP), AX
+	XCHGL	AX, 0(BX)
+	MOVL	AX, new+8(FP)
+	RET
+
+TEXT ·SwapInt64(SB),NOSPLIT,$0-24
+	JMP	·SwapUint64(SB)
+
+TEXT ·SwapUint64(SB),NOSPLIT,$0-24
+	MOVL	addr+0(FP), BX
+	TESTL	$7, BX
+	JZ	2(PC)
+	MOVL	0, BX // crash with nil ptr deref
+	MOVQ	new+8(FP), AX
+	XCHGQ	AX, 0(BX)
+	MOVQ	AX, new+16(FP)
+	RET
+
+TEXT ·SwapUintptr(SB),NOSPLIT,$0-24
+	JMP	·SwapUint32(SB)
+
+TEXT ·SwapPointer(SB),NOSPLIT,$0-24
+	JMP	·SwapUint32(SB)
+
+TEXT ·CompareAndSwapInt32(SB),NOSPLIT,$0-17
+	JMP	·CompareAndSwapUint32(SB)
+
+TEXT ·CompareAndSwapUint32(SB),NOSPLIT,$0-17
+	MOVL	addr+0(FP), BX
+	MOVL	old+4(FP), AX
+	MOVL	new+8(FP), CX
+	LOCK
+	CMPXCHGL	CX, 0(BX)
+	SETEQ	swapped+16(FP)
+	RET
+
+TEXT ·CompareAndSwapUintptr(SB),NOSPLIT,$0-25
+	JMP	·CompareAndSwapUint32(SB)
+
+TEXT ·CompareAndSwapPointer(SB),NOSPLIT,$0-25
+	JMP	·CompareAndSwapUint32(SB)
+
+TEXT ·CompareAndSwapInt64(SB),NOSPLIT,$0-25
+	JMP	·CompareAndSwapUint64(SB)
+
+TEXT ·CompareAndSwapUint64(SB),NOSPLIT,$0-25
+	MOVL	addr+0(FP), BX
+	TESTL	$7, BX
+	JZ	2(PC)
+	MOVL	0, BX // crash with nil ptr deref
+	MOVQ	old+8(FP), AX
+	MOVQ	new+16(FP), CX
+	LOCK
+	CMPXCHGQ	CX, 0(BX)
+	SETEQ	swapped+24(FP)
+	RET
+
+TEXT ·AddInt32(SB),NOSPLIT,$0-12
+	JMP	·AddUint32(SB)
+
+TEXT ·AddUint32(SB),NOSPLIT,$0-12
+	MOVL	addr+0(FP), BX
+	MOVL	delta+4(FP), AX
+	MOVL	AX, CX
+	LOCK
+	XADDL	AX, 0(BX)
+	ADDL	AX, CX
+	MOVL	CX, new+8(FP)
+	RET
+
+TEXT ·AddUintptr(SB),NOSPLIT,$0-12
+	JMP	·AddUint32(SB)
+
+TEXT ·AddInt64(SB),NOSPLIT,$0-12
+	JMP	·AddUint64(SB)
+
+TEXT ·AddUint64(SB),NOSPLIT,$0-24
+	MOVL	addr+0(FP), BX
+	TESTL	$7, BX
+	JZ	2(PC)
+	MOVL	0, BX // crash with nil ptr deref
+	MOVQ	delta+8(FP), AX
+	MOVQ	AX, CX
+	LOCK
+	XADDQ	AX, 0(BX)
+	ADDQ	AX, CX
+	MOVQ	CX, new+16(FP)
+	RET
+
+TEXT ·LoadInt32(SB),NOSPLIT,$0-12
+	JMP	·LoadUint32(SB)
+
+TEXT ·LoadUint32(SB),NOSPLIT,$0-12
+	MOVL	addr+0(FP), AX
+	MOVL	0(AX), AX
+	MOVL	AX, val+8(FP)
+	RET
+
+TEXT ·LoadInt64(SB),NOSPLIT,$0-16
+	JMP	·LoadUint64(SB)
+
+TEXT ·LoadUint64(SB),NOSPLIT,$0-16
+	MOVL	addr+0(FP), AX
+	TESTL	$7, AX
+	JZ	2(PC)
+	MOVL	0, AX // crash with nil ptr deref
+	MOVQ	0(AX), AX
+	MOVQ	AX, val+8(FP)
+	RET
+
+TEXT ·LoadUintptr(SB),NOSPLIT,$0-12
+	JMP	·LoadPointer(SB)
+
+TEXT ·LoadPointer(SB),NOSPLIT,$0-12
+	MOVL	addr+0(FP), AX
+	MOVL	0(AX), AX
+	MOVL	AX, val+8(FP)
+	RET
+
+TEXT ·StoreInt32(SB),NOSPLIT,$0-8
+	JMP	·StoreUint32(SB)
+
+TEXT ·StoreUint32(SB),NOSPLIT,$0-8
+	MOVL	addr+0(FP), BX
+	MOVL	val+4(FP), AX
+	XCHGL	AX, 0(BX)
+	RET
+
+TEXT ·StoreInt64(SB),NOSPLIT,$0-16
+	JMP	·StoreUint64(SB)
+
+TEXT ·StoreUint64(SB),NOSPLIT,$0-16
+	MOVL	addr+0(FP), BX
+	TESTL	$7, BX
+	JZ	2(PC)
+	MOVL	0, BX // crash with nil ptr deref
+	MOVQ	val+8(FP), AX
+	XCHGQ	AX, 0(BX)
+	RET
+
+TEXT ·StoreUintptr(SB),NOSPLIT,$0-8
+	JMP	·StorePointer(SB)
+
+TEXT ·StorePointer(SB),NOSPLIT,$0-8
+	MOVL	addr+0(FP), BX
+	MOVL	val+4(FP), AX
+	XCHGL	AX, 0(BX)
+	RET
diff --git a/src/pkg/sync/atomic/atomic_test.go b/src/pkg/sync/atomic/atomic_test.go
index e10effe7e6293c662ae03b9d5a943eb564ade696..c702158e8ccfba5bc5b770c0a36dfe1eb7bf510e 100644
--- a/src/pkg/sync/atomic/atomic_test.go
+++ b/src/pkg/sync/atomic/atomic_test.go
@@ -813,7 +813,7 @@ func hammerSwapUintptr32(uaddr *uint32, count int) {
 		new := uintptr(seed+i)<<16 | uintptr(seed+i)<<16>>16
 		old := SwapUintptr(addr, new)
 		if old>>16 != old<<16>>16 {
-			panic(fmt.Sprintf("SwapUintptr is not atomic: %v", old))
+			panic(fmt.Sprintf("SwapUintptr is not atomic: %#08x", old))
 		}
 	}
 }
@@ -827,7 +827,7 @@ func hammerSwapPointer32(uaddr *uint32, count int) {
 		new := uintptr(seed+i)<<16 | uintptr(seed+i)<<16>>16
 		old := uintptr(SwapPointer(addr, unsafe.Pointer(new)))
 		if old>>16 != old<<16>>16 {
-			panic(fmt.Sprintf("SwapPointer is not atomic: %v", old))
+			panic(fmt.Sprintf("SwapPointer is not atomic: %#08x", old))
 		}
 	}
 }
diff --git a/src/pkg/syscall/asm_nacl_386.s b/src/pkg/syscall/asm_nacl_386.s
new file mode 100644
index 0000000000000000000000000000000000000000..7f330d3d6c8573102a596a89a5f430f6cddcd649
--- /dev/null
+++ b/src/pkg/syscall/asm_nacl_386.s
@@ -0,0 +1,43 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "../../cmd/ld/textflag.h"
+#include "../runtime/syscall_nacl.h"
+
+//
+// System call support for 386, Native Client
+//
+
+#define NACL_SYSCALL(code) \
+	MOVL $(0x10000 + ((code)<<5)), AX; CALL AX
+
+#define NACL_SYSJMP(code) \
+	MOVL $(0x10000 + ((code)<<5)), AX; JMP AX
+
+TEXT syscall·Syscall(SB),NOSPLIT,$12-32
+	CALL	runtime·entersyscall(SB)
+	MOVL	trap+0(FP), AX
+	MOVL	a1+4(FP), BX
+	MOVL	BX, 0(SP)
+	MOVL	a2+8(FP), BX
+	MOVL	BX, 4(SP)
+	MOVL	a3+12(FP), BX
+	MOVL	BX, 8(SP)
+	SHLL	$5, AX
+	ADDL	$0x10000, AX
+	CALL	AX
+	CMPL	AX, $0
+	JGE	ok
+	MOVL	$-1, r1+16(FP)
+	MOVL	$-1, r2+20(FP)
+	NEGL	AX
+	MOVL	AX, errno+24(FP)
+	CALL	runtime·exitsyscall(SB)
+	RET
+ok:
+	MOVL	AX, r1+16(FP)
+	MOVL	DX, r2+20(FP)
+	MOVL	$0, errno+24(FP)
+	CALL	runtime·exitsyscall(SB)
+	RET	
diff --git a/src/pkg/syscall/asm_nacl_amd64p32.s b/src/pkg/syscall/asm_nacl_amd64p32.s
new file mode 100644
index 0000000000000000000000000000000000000000..0ff6ece3d4e4b70b88c6692b9dc4b71baba967b6
--- /dev/null
+++ b/src/pkg/syscall/asm_nacl_amd64p32.s
@@ -0,0 +1,41 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "../../cmd/ld/textflag.h"
+#include "../runtime/syscall_nacl.h"
+
+//
+// System call support for amd64, Native Client
+//
+
+#define NACL_SYSCALL(code) \
+	MOVL $(0x10000 + ((code)<<5)), AX; CALL AX
+
+#define NACL_SYSJMP(code) \
+	MOVL $(0x10000 + ((code)<<5)), AX; JMP AX
+
+TEXT syscall·Syscall(SB),NOSPLIT,$0-32
+	CALL	runtime·entersyscall(SB)
+	MOVL	trap+0(FP), AX
+	MOVL	a1+4(FP), DI
+	MOVL	a2+8(FP), SI
+	MOVL	a3+12(FP), DX
+	// more args would use CX, R8, R9
+	SHLL	$5, AX
+	ADDL	$0x10000, AX
+	CALL	AX
+	CMPL	AX, $0
+	JGE	ok
+	MOVL	$-1, r1+16(FP)
+	MOVL	$-1, r2+20(FP)
+	NEGL	AX
+	MOVL	AX, errno+24(FP)
+	CALL	runtime·exitsyscall(SB)
+	RET
+ok:
+	MOVL	AX, r1+16(FP)
+	MOVL	DX, r2+20(FP)
+	MOVL	$0, errno+24(FP)
+	CALL	runtime·exitsyscall(SB)
+	RET	
diff --git a/src/pkg/syscall/env_unix.go b/src/pkg/syscall/env_unix.go
index 76663c6c415e15ad930fbfd5b83e674ec3be22a2..ad354ed05785cfcdc5ee6230930667a16a26ea12 100644
--- a/src/pkg/syscall/env_unix.go
+++ b/src/pkg/syscall/env_unix.go
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build darwin dragonfly freebsd linux netbsd openbsd solaris
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris
 
 // Unix environment variables.
 
diff --git a/src/pkg/syscall/fd_nacl.go b/src/pkg/syscall/fd_nacl.go
new file mode 100644
index 0000000000000000000000000000000000000000..cbc8315e44aeb0b4c80c79cdb4e955eaba35494e
--- /dev/null
+++ b/src/pkg/syscall/fd_nacl.go
@@ -0,0 +1,320 @@
+// Copyright 2013 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// File descriptor support for Native Client.
+// We want to provide access to a broader range of (simulated) files than
+// Native Client allows, so we maintain our own file descriptor table exposed
+// to higher-level packages.
+
+package syscall
+
+import (
+	"sync"
+)
+
+// files is the table indexed by a file descriptor.
+var files struct {
+	sync.RWMutex
+	tab []*file
+}
+
+// A file is an open file, something with a file descriptor.
+// A particular *file may appear in files multiple times, due to use of Dup or Dup2.
+type file struct {
+	fdref int      // uses in files.tab
+	impl  fileImpl // underlying implementation
+}
+
+// A fileImpl is the implementation of something that can be a file.
+type fileImpl interface {
+	// Standard operations.
+	// These can be called concurrently from multiple goroutines.
+	stat(*Stat_t) error
+	read([]byte) (int, error)
+	write([]byte) (int, error)
+	seek(int64, int) (int64, error)
+	pread([]byte, int64) (int, error)
+	pwrite([]byte, int64) (int, error)
+
+	// Close is called when the last reference to a *file is removed
+	// from the file descriptor table. It may be called concurrently
+	// with active operations such as blocked read or write calls.
+	close() error
+}
+
+// newFD adds impl to the file descriptor table,
+// returning the new file descriptor.
+// Like Unix, it uses the lowest available descriptor.
+func newFD(impl fileImpl) int {
+	files.Lock()
+	defer files.Unlock()
+	f := &file{impl: impl, fdref: 1}
+	for fd, oldf := range files.tab {
+		if oldf == nil {
+			files.tab[fd] = f
+			return fd
+		}
+	}
+	fd := len(files.tab)
+	files.tab = append(files.tab, f)
+	return fd
+}
+
+// Install Native Client stdin, stdout, stderr.
+func init() {
+	newFD(&naclFile{naclFD: 0})
+	newFD(&naclFile{naclFD: 1})
+	newFD(&naclFile{naclFD: 2})
+}
+
+// fdToFile retrieves the *file corresponding to a file descriptor.
+func fdToFile(fd int) (*file, error) {
+	files.Lock()
+	defer files.Unlock()
+	if fd < 0 || fd >= len(files.tab) || files.tab[fd] == nil {
+		return nil, EBADF
+	}
+	return files.tab[fd], nil
+}
+
+func Close(fd int) error {
+	files.Lock()
+	if fd < 0 || fd >= len(files.tab) || files.tab[fd] == nil {
+		files.Unlock()
+		return EBADF
+	}
+	f := files.tab[fd]
+	files.tab[fd] = nil
+	f.fdref--
+	fdref := f.fdref
+	files.Unlock()
+	if fdref > 0 {
+		return nil
+	}
+	return f.impl.close()
+}
+
+func CloseOnExec(fd int) {
+	// nothing to do - no exec
+}
+
+func Dup(fd int) (int, error) {
+	files.Lock()
+	defer files.Unlock()
+	if fd < 0 || fd >= len(files.tab) || files.tab[fd] == nil {
+		return -1, EBADF
+	}
+	f := files.tab[fd]
+	f.fdref++
+	for newfd, oldf := range files.tab {
+		if oldf == nil {
+			files.tab[newfd] = f
+			return newfd, nil
+		}
+	}
+	newfd := len(files.tab)
+	files.tab = append(files.tab, f)
+	return newfd, nil
+}
+
+func Dup2(fd, newfd int) error {
+	files.Lock()
+	defer files.Unlock()
+	if fd < 0 || fd >= len(files.tab) || files.tab[fd] == nil || newfd < 0 || newfd >= len(files.tab)+100 {
+		files.Unlock()
+		return EBADF
+	}
+	f := files.tab[fd]
+	f.fdref++
+	for cap(files.tab) <= newfd {
+		files.tab = append(files.tab[:cap(files.tab)], nil)
+	}
+	oldf := files.tab[newfd]
+	var oldfdref int
+	if oldf != nil {
+		oldf.fdref--
+		oldfdref = oldf.fdref
+	}
+	files.tab[newfd] = f
+	files.Unlock()
+	if oldf != nil {
+		if oldfdref == 0 {
+			oldf.impl.close()
+		}
+	}
+	return nil
+}
+
+func Fstat(fd int, st *Stat_t) error {
+	f, err := fdToFile(fd)
+	if err != nil {
+		return err
+	}
+	return f.impl.stat(st)
+}
+
+func Read(fd int, b []byte) (int, error) {
+	f, err := fdToFile(fd)
+	if err != nil {
+		return 0, err
+	}
+	return f.impl.read(b)
+}
+
+func Write(fd int, b []byte) (int, error) {
+	f, err := fdToFile(fd)
+	if err != nil {
+		return 0, err
+	}
+	return f.impl.write(b)
+}
+
+func Pread(fd int, b []byte, offset int64) (int, error) {
+	f, err := fdToFile(fd)
+	if err != nil {
+		return 0, err
+	}
+	return f.impl.pread(b, offset)
+}
+
+func Pwrite(fd int, b []byte, offset int64) (int, error) {
+	f, err := fdToFile(fd)
+	if err != nil {
+		return 0, err
+	}
+	return f.impl.pwrite(b, offset)
+}
+
+func Seek(fd int, offset int64, whence int) (int64, error) {
+	f, err := fdToFile(fd)
+	if err != nil {
+		return 0, err
+	}
+	return f.impl.seek(offset, whence)
+}
+
+// defaulFileImpl imlements fileImpl.
+// It can be embedded to complete a partial fileImpl implementation.
+type defaultFileImpl struct{}
+
+func (*defaultFileImpl) close() error                      { return nil }
+func (*defaultFileImpl) stat(*Stat_t) error                { return ENOSYS }
+func (*defaultFileImpl) read([]byte) (int, error)          { return 0, ENOSYS }
+func (*defaultFileImpl) write([]byte) (int, error)         { return 0, ENOSYS }
+func (*defaultFileImpl) seek(int64, int) (int64, error)    { return 0, ENOSYS }
+func (*defaultFileImpl) pread([]byte, int64) (int, error)  { return 0, ENOSYS }
+func (*defaultFileImpl) pwrite([]byte, int64) (int, error) { return 0, ENOSYS }
+
+// naclFile is the fileImpl implementation for a Native Client file descriptor.
+type naclFile struct {
+	defaultFileImpl
+	naclFD int
+}
+
+func (f *naclFile) stat(st *Stat_t) error {
+	return naclFstat(f.naclFD, st)
+}
+
+func (f *naclFile) read(b []byte) (int, error) {
+	n, err := naclRead(f.naclFD, b)
+	if err != nil {
+		n = 0
+	}
+	return n, err
+}
+
+// implemented in package runtime, to add time header on playground
+func naclWrite(fd int, b []byte) int
+
+func (f *naclFile) write(b []byte) (int, error) {
+	n := naclWrite(f.naclFD, b)
+	if n < 0 {
+		return 0, Errno(-n)
+	}
+	return n, nil
+}
+
+func (f *naclFile) seek(off int64, whence int) (int64, error) {
+	old := off
+	err := naclSeek(f.naclFD, &off, whence)
+	if err != nil {
+		return old, err
+	}
+	return off, nil
+}
+
+func (f *naclFile) prw(b []byte, offset int64, rw func([]byte) (int, error)) (int, error) {
+	// NaCl has no pread; simulate with seek and hope for no races.
+	old, err := f.seek(0, 1)
+	if err != nil {
+		return 0, err
+	}
+	if _, err := f.seek(offset, 0); err != nil {
+		return 0, err
+	}
+	n, err := rw(b)
+	f.seek(old, 0)
+	return n, err
+}
+
+func (f *naclFile) pread(b []byte, offset int64) (int, error) {
+	return f.prw(b, offset, f.read)
+}
+
+func (f *naclFile) pwrite(b []byte, offset int64) (int, error) {
+	return f.prw(b, offset, f.write)
+}
+
+func (f *naclFile) close() error {
+	err := naclClose(f.naclFD)
+	f.naclFD = -1
+	return err
+}
+
+// A pipeFile is an in-memory implementation of a pipe.
+// The byteq implementation is in net_nacl.go.
+type pipeFile struct {
+	defaultFileImpl
+	rd *byteq
+	wr *byteq
+}
+
+func (f *pipeFile) close() error {
+	if f.rd != nil {
+		f.rd.close()
+	}
+	if f.wr != nil {
+		f.wr.close()
+	}
+	return nil
+}
+
+func (f *pipeFile) read(b []byte) (int, error) {
+	if f.rd == nil {
+		return 0, EINVAL
+	}
+	n, err := f.rd.read(b, 0)
+	if err == EAGAIN {
+		err = nil
+	}
+	return n, err
+}
+
+func (f *pipeFile) write(b []byte) (int, error) {
+	if f.wr == nil {
+		return 0, EINVAL
+	}
+	n, err := f.wr.write(b, 0)
+	if err == EAGAIN {
+		err = EPIPE
+	}
+	return n, err
+}
+
+func Pipe(fd []int) error {
+	q := newByteq()
+	fd[0] = newFD(&pipeFile{rd: q})
+	fd[1] = newFD(&pipeFile{wr: q})
+	return nil
+}
diff --git a/src/pkg/syscall/fs_nacl.go b/src/pkg/syscall/fs_nacl.go
new file mode 100644
index 0000000000000000000000000000000000000000..ac9239483b65a59ecb7026931f518c8d1c1636e2
--- /dev/null
+++ b/src/pkg/syscall/fs_nacl.go
@@ -0,0 +1,815 @@
+// Copyright 2013 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// A simulated Unix-like file system for use within NaCl.
+//
+// The simulation is not particularly tied to NaCl other than the reuse
+// of NaCl's definition for the Stat_t structure.
+//
+// The file system need never be written to disk, so it is represented as
+// in-memory Go data structures, never in a serialized form.
+//
+// TODO: Perhaps support symlinks, although they muck everything up.
+
+package syscall
+
+import (
+	"sync"
+	"unsafe"
+)
+
+// Provided by package runtime.
+func now() (sec int64, nsec int32)
+
+// An fsys is a file system.
+// Since there is no I/O (everything is in memory),
+// the global lock mu protects the whole file system state,
+// and that's okay.
+type fsys struct {
+	mu   sync.Mutex
+	root *inode                    // root directory
+	cwd  *inode                    // process current directory
+	inum uint64                    // number of inodes created
+	dev  []func() (devFile, error) // table for opening devices
+}
+
+// A devFile is the implementation required of device files
+// like /dev/null or /dev/random.
+type devFile interface {
+	pread([]byte, int64) (int, error)
+	pwrite([]byte, int64) (int, error)
+}
+
+// An inode is a (possibly special) file in the file system.
+type inode struct {
+	Stat_t
+	data []byte
+	dir  []dirent
+}
+
+// A dirent describes a single directory entry.
+type dirent struct {
+	name  string
+	inode *inode
+}
+
+// An fsysFile is the fileImpl implementation backed by the file system.
+type fsysFile struct {
+	defaultFileImpl
+	fsys     *fsys
+	inode    *inode
+	openmode int
+	offset   int64
+	dev      devFile
+}
+
+// newFsys creates a new file system.
+func newFsys() *fsys {
+	fs := &fsys{}
+	fs.mu.Lock()
+	defer fs.mu.Unlock()
+	ip := fs.newInode()
+	ip.Mode = 0555 | S_IFDIR
+	fs.dirlink(ip, ".", ip)
+	fs.dirlink(ip, "..", ip)
+	fs.cwd = ip
+	fs.root = ip
+	return fs
+}
+
+var fs = newFsys()
+
+func init() {
+	Mkdir("/dev", 0555)
+	Mkdir("/tmp", 0777)
+	mkdev("/dev/null", 0666, openNull)
+	mkdev("/dev/random", 0444, openRandom)
+	mkdev("/dev/urandom", 0444, openRandom)
+	mkdev("/dev/zero", 0666, openZero)
+	chdirEnv()
+}
+
+func chdirEnv() {
+	pwd, ok := Getenv("NACLPWD")
+	if ok {
+		Chdir(pwd)
+	}
+}
+
+// Except where indicated otherwise, unexported methods on fsys
+// expect fs.mu to have been locked by the caller.
+
+// newInode creates a new inode.
+func (fs *fsys) newInode() *inode {
+	fs.inum++
+	ip := &inode{
+		Stat_t: Stat_t{
+			Ino:     fs.inum,
+			Blksize: 512,
+		},
+	}
+	return ip
+}
+
+// atime sets ip.Atime to the current time.
+func (fs *fsys) atime(ip *inode) {
+	sec, nsec := now()
+	ip.Atime, ip.AtimeNsec = sec, int64(nsec)
+}
+
+// mtime sets ip.Mtime to the current time.
+func (fs *fsys) mtime(ip *inode) {
+	sec, nsec := now()
+	ip.Mtime, ip.MtimeNsec = sec, int64(nsec)
+}
+
+// dirlookup looks for an entry in the directory dp with the given name.
+// It returns the directory entry and its index within the directory.
+func (fs *fsys) dirlookup(dp *inode, name string) (de *dirent, index int, err error) {
+	fs.atime(dp)
+	for i := range dp.dir {
+		de := &dp.dir[i]
+		if de.name == name {
+			fs.atime(de.inode)
+			return de, i, nil
+		}
+	}
+	return nil, 0, ENOENT
+}
+
+// dirlink adds to the directory dp an entry for name pointing at the inode ip.
+// If dp already contains an entry for name, that entry is overwritten.
+func (fs *fsys) dirlink(dp *inode, name string, ip *inode) {
+	fs.mtime(dp)
+	fs.atime(ip)
+	ip.Nlink++
+	for i := range dp.dir {
+		if dp.dir[i].name == name {
+			dp.dir[i] = dirent{name, ip}
+			return
+		}
+	}
+	dp.dir = append(dp.dir, dirent{name, ip})
+	dp.dirSize()
+}
+
+func (dp *inode) dirSize() {
+	dp.Size = int64(len(dp.dir)) * (8 + 8 + 2 + 256) // Dirent
+}
+
+// skipelem splits path into the first element and the remainder.
+// the returned first element contains no slashes, and the returned
+// remainder does not begin with a slash.
+func skipelem(path string) (elem, rest string) {
+	for len(path) > 0 && path[0] == '/' {
+		path = path[1:]
+	}
+	if len(path) == 0 {
+		return "", ""
+	}
+	i := 0
+	for i < len(path) && path[i] != '/' {
+		i++
+	}
+	elem, path = path[:i], path[i:]
+	for len(path) > 0 && path[0] == '/' {
+		path = path[1:]
+	}
+	return elem, path
+}
+
+// namei translates a file system path name into an inode.
+// If parent is false, the returned ip corresponds to the given name, and elem is the empty string.
+// If parent is false, the walk stops at the next-to-last element in the name,
+// so that ip is the parent directory and elem is the final element in the path.
+func (fs *fsys) namei(path string, parent bool) (ip *inode, elem string, err error) {
+	// Reject NUL in name.
+	for i := 0; i < len(path); i++ {
+		if path[i] == '\x00' {
+			return nil, "", EINVAL
+		}
+	}
+
+	// Reject empty name.
+	if path == "" {
+		return nil, "", EINVAL
+	}
+
+	if path[0] == '/' {
+		ip = fs.root
+	} else {
+		ip = fs.cwd
+	}
+
+	for len(path) > 0 && path[len(path)-1] == '/' {
+		path = path[:len(path)-1]
+	}
+
+	for {
+		elem, rest := skipelem(path)
+		if elem == "" {
+			if parent && ip.Mode&S_IFMT == S_IFDIR {
+				return ip, ".", nil
+			}
+			break
+		}
+		if ip.Mode&S_IFMT != S_IFDIR {
+			return nil, "", ENOTDIR
+		}
+		if len(elem) >= 256 {
+			return nil, "", ENAMETOOLONG
+		}
+		if parent && rest == "" {
+			// Stop one level early.
+			return ip, elem, nil
+		}
+		de, _, err := fs.dirlookup(ip, elem)
+		if err != nil {
+			return nil, "", err
+		}
+		ip = de.inode
+		path = rest
+	}
+	if parent {
+		return nil, "", ENOTDIR
+	}
+	return ip, "", nil
+}
+
+// open opens or creates a file with the given name, open mode,
+// and permission mode bits.
+func (fs *fsys) open(name string, openmode int, mode uint32) (fileImpl, error) {
+	dp, elem, err := fs.namei(name, true)
+	if err != nil {
+		return nil, err
+	}
+	var (
+		ip  *inode
+		dev devFile
+	)
+	de, _, err := fs.dirlookup(dp, elem)
+	if err != nil {
+		if openmode&O_CREATE == 0 {
+			return nil, err
+		}
+		ip = fs.newInode()
+		ip.Mode = mode
+		fs.dirlink(dp, elem, ip)
+		if ip.Mode&S_IFMT == S_IFDIR {
+			fs.dirlink(ip, ".", ip)
+			fs.dirlink(ip, "..", dp)
+		}
+	} else {
+		ip = de.inode
+		if openmode&(O_CREATE|O_EXCL) == O_CREATE|O_EXCL {
+			return nil, EEXIST
+		}
+		if openmode&O_TRUNC != 0 {
+			if ip.Mode&S_IFMT == S_IFDIR {
+				return nil, EISDIR
+			}
+			ip.data = nil
+		}
+		if ip.Mode&S_IFMT == S_IFCHR {
+			if ip.Rdev < 0 || ip.Rdev >= int64(len(fs.dev)) || fs.dev[ip.Rdev] == nil {
+				return nil, ENODEV
+			}
+			dev, err = fs.dev[ip.Rdev]()
+			if err != nil {
+				return nil, err
+			}
+		}
+	}
+
+	switch openmode & O_ACCMODE {
+	case O_WRONLY, O_RDWR:
+		if ip.Mode&S_IFMT == S_IFDIR {
+			return nil, EISDIR
+		}
+	}
+
+	switch ip.Mode & S_IFMT {
+	case S_IFDIR:
+		if openmode&O_ACCMODE != O_RDONLY {
+			return nil, EISDIR
+		}
+
+	case S_IFREG:
+		// ok
+
+	case S_IFCHR:
+		// handled above
+
+	default:
+		// TODO: some kind of special file
+		return nil, EPERM
+	}
+
+	f := &fsysFile{
+		fsys:     fs,
+		inode:    ip,
+		openmode: openmode,
+		dev:      dev,
+	}
+	if openmode&O_APPEND != 0 {
+		f.offset = ip.Size
+	}
+	return f, nil
+}
+
+// fsysFile methods to implement fileImpl.
+
+func (f *fsysFile) stat(st *Stat_t) error {
+	f.fsys.mu.Lock()
+	defer f.fsys.mu.Unlock()
+	*st = f.inode.Stat_t
+	return nil
+}
+
+func (f *fsysFile) read(b []byte) (int, error) {
+	f.fsys.mu.Lock()
+	defer f.fsys.mu.Unlock()
+	n, err := f.preadLocked(b, f.offset)
+	f.offset += int64(n)
+	return n, err
+}
+
+func ReadDirent(fd int, buf []byte) (int, error) {
+	f, err := fdToFsysFile(fd)
+	if err != nil {
+		return 0, err
+	}
+	f.fsys.mu.Lock()
+	defer f.fsys.mu.Unlock()
+	if f.inode.Mode&S_IFMT != S_IFDIR {
+		return 0, EINVAL
+	}
+	n, err := f.preadLocked(buf, f.offset)
+	f.offset += int64(n)
+	return n, err
+}
+
+func (f *fsysFile) write(b []byte) (int, error) {
+	f.fsys.mu.Lock()
+	defer f.fsys.mu.Unlock()
+	n, err := f.pwriteLocked(b, f.offset)
+	f.offset += int64(n)
+	return n, err
+}
+
+func (f *fsysFile) seek(offset int64, whence int) (int64, error) {
+	f.fsys.mu.Lock()
+	defer f.fsys.mu.Unlock()
+	switch whence {
+	case 1:
+		offset += f.offset
+	case 2:
+		offset += f.inode.Size
+	}
+	if offset < 0 {
+		return 0, EINVAL
+	}
+	if offset > f.inode.Size {
+		return 0, EINVAL
+	}
+	f.offset = offset
+	return offset, nil
+}
+
+func (f *fsysFile) pread(b []byte, offset int64) (int, error) {
+	f.fsys.mu.Lock()
+	defer f.fsys.mu.Unlock()
+	return f.preadLocked(b, offset)
+}
+
+func (f *fsysFile) pwrite(b []byte, offset int64) (int, error) {
+	f.fsys.mu.Lock()
+	defer f.fsys.mu.Unlock()
+	return f.pwriteLocked(b, offset)
+}
+
+func (f *fsysFile) preadLocked(b []byte, offset int64) (int, error) {
+	if f.openmode&O_ACCMODE == O_WRONLY {
+		return 0, EINVAL
+	}
+	if offset < 0 {
+		return 0, EINVAL
+	}
+	if f.dev != nil {
+		f.fsys.atime(f.inode)
+		f.fsys.mu.Unlock()
+		defer f.fsys.mu.Lock()
+		return f.dev.pread(b, offset)
+	}
+	if offset > f.inode.Size {
+		return 0, nil
+	}
+	if int64(len(b)) > f.inode.Size-offset {
+		b = b[:f.inode.Size-offset]
+	}
+
+	if f.inode.Mode&S_IFMT == S_IFDIR {
+		if offset%direntSize != 0 || len(b) != 0 && len(b) < direntSize {
+			return 0, EINVAL
+		}
+		fs.atime(f.inode)
+		n := 0
+		for len(b) >= direntSize {
+			src := f.inode.dir[int(offset/direntSize)]
+			dst := (*Dirent)(unsafe.Pointer(&b[0]))
+			dst.Ino = int64(src.inode.Ino)
+			dst.Off = offset
+			dst.Reclen = direntSize
+			for i := range dst.Name {
+				dst.Name[i] = 0
+			}
+			copy(dst.Name[:], src.name)
+			n += direntSize
+			offset += direntSize
+			b = b[direntSize:]
+		}
+		return n, nil
+	}
+
+	fs.atime(f.inode)
+	n := copy(b, f.inode.data[offset:])
+	return n, nil
+}
+
+func (f *fsysFile) pwriteLocked(b []byte, offset int64) (int, error) {
+	if f.openmode&O_ACCMODE == O_RDONLY {
+		return 0, EINVAL
+	}
+	if offset < 0 {
+		return 0, EINVAL
+	}
+	if f.dev != nil {
+		f.fsys.atime(f.inode)
+		f.fsys.mu.Unlock()
+		defer f.fsys.mu.Lock()
+		return f.dev.pwrite(b, offset)
+	}
+	if offset > f.inode.Size {
+		return 0, EINVAL
+	}
+	f.fsys.mtime(f.inode)
+	n := copy(f.inode.data[offset:], b)
+	if n < len(b) {
+		f.inode.data = append(f.inode.data, b[n:]...)
+		f.inode.Size = int64(len(f.inode.data))
+	}
+	return len(b), nil
+}
+
+// Standard Unix system calls.
+
+func Open(path string, openmode int, perm uint32) (fd int, err error) {
+	fs.mu.Lock()
+	defer fs.mu.Unlock()
+	f, err := fs.open(path, openmode, perm&0777|S_IFREG)
+	if err != nil {
+		return -1, err
+	}
+	return newFD(f), nil
+}
+
+func Mkdir(path string, perm uint32) error {
+	fs.mu.Lock()
+	defer fs.mu.Unlock()
+	_, err := fs.open(path, O_CREATE|O_EXCL, perm&0777|S_IFDIR)
+	return err
+}
+
+func Getcwd(buf []byte) (n int, err error) {
+	// Force package os to default to the old algorithm using .. and directory reads.
+	return 0, ENOSYS
+}
+
+func Stat(path string, st *Stat_t) error {
+	fs.mu.Lock()
+	defer fs.mu.Unlock()
+	ip, _, err := fs.namei(path, false)
+	if err != nil {
+		return err
+	}
+	*st = ip.Stat_t
+	return nil
+}
+
+func Lstat(path string, st *Stat_t) error {
+	return Stat(path, st)
+}
+
+func unlink(path string, isdir bool) error {
+	fs.mu.Lock()
+	defer fs.mu.Unlock()
+	dp, elem, err := fs.namei(path, true)
+	if err != nil {
+		return err
+	}
+	if elem == "." || elem == ".." {
+		return EINVAL
+	}
+	de, _, err := fs.dirlookup(dp, elem)
+	if err != nil {
+		return err
+	}
+	if isdir {
+		if de.inode.Mode&S_IFMT != S_IFDIR {
+			return ENOTDIR
+		}
+		if len(de.inode.dir) != 2 {
+			return ENOTEMPTY
+		}
+	} else {
+		if de.inode.Mode&S_IFMT == S_IFDIR {
+			return EISDIR
+		}
+	}
+	de.inode.Nlink--
+	*de = dp.dir[len(dp.dir)-1]
+	dp.dir = dp.dir[:len(dp.dir)-1]
+	dp.dirSize()
+	return nil
+}
+
+func Unlink(path string) error {
+	return unlink(path, false)
+}
+
+func Rmdir(path string) error {
+	return unlink(path, true)
+}
+
+func Chmod(path string, mode uint32) error {
+	fs.mu.Lock()
+	defer fs.mu.Unlock()
+	ip, _, err := fs.namei(path, false)
+	if err != nil {
+		return err
+	}
+	ip.Mode = ip.Mode&^0777 | mode&0777
+	return nil
+}
+
+func Fchmod(fd int, mode uint32) error {
+	f, err := fdToFsysFile(fd)
+	if err != nil {
+		return err
+	}
+	f.fsys.mu.Lock()
+	defer f.fsys.mu.Unlock()
+	f.inode.Mode = f.inode.Mode&^0777 | mode&0777
+	return nil
+}
+
+func Chown(path string, uid, gid int) error {
+	fs.mu.Lock()
+	defer fs.mu.Unlock()
+	ip, _, err := fs.namei(path, false)
+	if err != nil {
+		return err
+	}
+	ip.Uid = uint32(uid)
+	ip.Gid = uint32(gid)
+	return nil
+}
+
+func Fchown(fd int, uid, gid int) error {
+	fs.mu.Lock()
+	defer fs.mu.Unlock()
+	f, err := fdToFsysFile(fd)
+	if err != nil {
+		return err
+	}
+	f.fsys.mu.Lock()
+	defer f.fsys.mu.Unlock()
+	f.inode.Uid = uint32(uid)
+	f.inode.Gid = uint32(gid)
+	return nil
+}
+
+func Lchown(path string, uid, gid int) error {
+	return Chown(path, uid, gid)
+}
+
+func UtimesNano(path string, ts []Timespec) error {
+	if len(ts) != 2 {
+		return EINVAL
+	}
+	fs.mu.Lock()
+	defer fs.mu.Unlock()
+	ip, _, err := fs.namei(path, false)
+	if err != nil {
+		return err
+	}
+	ip.Atime = ts[0].Sec
+	ip.AtimeNsec = int64(ts[0].Nsec)
+	ip.Mtime = ts[1].Sec
+	ip.MtimeNsec = int64(ts[1].Nsec)
+	return nil
+}
+
+func Link(path, link string) error {
+	ip, _, err := fs.namei(path, false)
+	if err != nil {
+		return err
+	}
+	dp, elem, err := fs.namei(link, true)
+	if err != nil {
+		return err
+	}
+	if ip.Mode&S_IFMT == S_IFDIR {
+		return EPERM
+	}
+	fs.dirlink(dp, elem, ip)
+	return nil
+}
+
+func Rename(from, to string) error {
+	fdp, felem, err := fs.namei(from, true)
+	if err != nil {
+		return err
+	}
+	fde, _, err := fs.dirlookup(fdp, felem)
+	if err != nil {
+		return err
+	}
+	tdp, telem, err := fs.namei(to, true)
+	if err != nil {
+		return err
+	}
+	fs.dirlink(tdp, telem, fde.inode)
+	fde.inode.Nlink--
+	*fde = fdp.dir[len(fdp.dir)-1]
+	fdp.dir = fdp.dir[:len(fdp.dir)-1]
+	fdp.dirSize()
+	return nil
+}
+
+func (fs *fsys) truncate(ip *inode, length int64) error {
+	if length > 1e9 || ip.Mode&S_IFMT != S_IFREG {
+		return EINVAL
+	}
+	if length < int64(len(ip.data)) {
+		ip.data = ip.data[:length]
+	} else {
+		data := make([]byte, length)
+		copy(data, ip.data)
+		ip.data = data
+	}
+	ip.Size = int64(len(ip.data))
+	return nil
+}
+
+func Truncate(path string, length int64) error {
+	fs.mu.Lock()
+	defer fs.mu.Unlock()
+	ip, _, err := fs.namei(path, false)
+	if err != nil {
+		return err
+	}
+	return fs.truncate(ip, length)
+}
+
+func Ftruncate(fd int, length int64) error {
+	f, err := fdToFsysFile(fd)
+	if err != nil {
+		return err
+	}
+	f.fsys.mu.Lock()
+	defer f.fsys.mu.Unlock()
+	return f.fsys.truncate(f.inode, length)
+}
+
+func Chdir(path string) error {
+	fs.mu.Lock()
+	defer fs.mu.Unlock()
+	ip, _, err := fs.namei(path, false)
+	if err != nil {
+		return err
+	}
+	fs.cwd = ip
+	return nil
+}
+
+func Fchdir(fd int) error {
+	f, err := fdToFsysFile(fd)
+	if err != nil {
+		return err
+	}
+	f.fsys.mu.Lock()
+	defer f.fsys.mu.Unlock()
+	if f.inode.Mode&S_IFMT != S_IFDIR {
+		return ENOTDIR
+	}
+	fs.cwd = f.inode
+	return nil
+}
+
+func Readlink(path string, buf []byte) (n int, err error) {
+	return 0, ENOSYS
+}
+
+func Symlink(path, link string) error {
+	return ENOSYS
+}
+
+func Fsync(fd int) error {
+	return nil
+}
+
+// Special devices.
+
+func mkdev(path string, mode uint32, open func() (devFile, error)) error {
+	fs.mu.Lock()
+	fs.mu.Unlock()
+	f, err := fs.open(path, O_CREATE|O_RDONLY|O_EXCL, S_IFCHR|mode)
+	if err != nil {
+		return err
+	}
+	ip := f.(*fsysFile).inode
+	ip.Rdev = int64(len(fs.dev))
+	fs.dev = append(fs.dev, open)
+	return nil
+}
+
+type nullFile struct{}
+
+func openNull() (devFile, error)                               { return &nullFile{}, nil }
+func (f *nullFile) close() error                               { return nil }
+func (f *nullFile) pread(b []byte, offset int64) (int, error)  { return 0, nil }
+func (f *nullFile) pwrite(b []byte, offset int64) (int, error) { return len(b), nil }
+
+type zeroFile struct{}
+
+func openZero() (devFile, error)                               { return &zeroFile{}, nil }
+func (f *zeroFile) close() error                               { return nil }
+func (f *zeroFile) pwrite(b []byte, offset int64) (int, error) { return len(b), nil }
+
+func (f *zeroFile) pread(b []byte, offset int64) (int, error) {
+	for i := range b {
+		b[i] = 0
+	}
+	return len(b), nil
+}
+
+type randomFile struct {
+	naclFD int
+}
+
+func openRandom() (devFile, error) {
+	fd, err := openNamedService("SecureRandom", O_RDONLY)
+	if err != nil {
+		return nil, err
+	}
+	return &randomFile{naclFD: fd}, nil
+}
+
+func (f *randomFile) close() error {
+	naclClose(f.naclFD)
+	f.naclFD = -1
+	return nil
+}
+
+func (f *randomFile) pread(b []byte, offset int64) (int, error) {
+	return naclRead(f.naclFD, b)
+}
+
+func (f *randomFile) pwrite(b []byte, offset int64) (int, error) {
+	return 0, EPERM
+}
+
+func fdToFsysFile(fd int) (*fsysFile, error) {
+	f, err := fdToFile(fd)
+	if err != nil {
+		return nil, err
+	}
+	impl := f.impl
+	fsysf, ok := impl.(*fsysFile)
+	if !ok {
+		return nil, EINVAL
+	}
+	return fsysf, nil
+}
+
+// create creates a file in the file system with the given name, mode, time, and data.
+// It is meant to be called when initializing the file system image.
+func create(name string, mode uint32, sec int64, data []byte) error {
+	fs.mu.Lock()
+	fs.mu.Unlock()
+	f, err := fs.open(name, O_CREATE|O_EXCL, mode)
+	if err != nil {
+		return err
+	}
+	ip := f.(*fsysFile).inode
+	ip.Atime = sec
+	ip.Mtime = sec
+	ip.Ctime = sec
+	if len(data) > 0 {
+		ip.Size = int64(len(data))
+		ip.data = data
+	}
+	return nil
+}
diff --git a/src/pkg/syscall/mkall.sh b/src/pkg/syscall/mkall.sh
index 79a3bc889e556578f8deb605a470ec1b367a5e59..1bd6ccb0218e09ddf44e8f122ba147a5c6fd8c51 100755
--- a/src/pkg/syscall/mkall.sh
+++ b/src/pkg/syscall/mkall.sh
@@ -174,6 +174,18 @@ linux_arm)
 	mksysnum="curl -s 'http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/plain/arch/arm/include/uapi/asm/unistd.h' | ./mksysnum_linux.pl"
 	mktypes="GOARCH=$GOARCH go tool cgo -godefs"
 	;;
+nacl_386)
+	mkerrors=""
+	mksyscall="./mksyscall.pl -l32 -nacl"
+	mksysnum=""
+	mktypes=""
+	;;
+nacl_amd64p32)
+	mkerrors=""
+	mksyscall="./mksyscall.pl -nacl"
+	mksysnum=""
+	mktypes=""
+	;;
 netbsd_386)
 	mkerrors="$mkerrors -m32"
 	mksyscall="./mksyscall.pl -l32 -netbsd"
diff --git a/src/pkg/syscall/mksyscall.pl b/src/pkg/syscall/mksyscall.pl
index b4ece9a5424d2143acefd66dbb776003e6bfa170..6d35fa6892745ed39c5a2eb2d83a5b3b46edafda 100755
--- a/src/pkg/syscall/mksyscall.pl
+++ b/src/pkg/syscall/mksyscall.pl
@@ -28,6 +28,7 @@ my $plan9 = 0;
 my $openbsd = 0;
 my $netbsd = 0;
 my $dragonfly = 0;
+my $nacl = 0;
 my $arm = 0; # 64-bit value should use (even, odd)-pair
 
 if($ARGV[0] eq "-b32") {
@@ -53,6 +54,10 @@ if($ARGV[0] eq "-dragonfly") {
 	$dragonfly = 1;
 	shift;
 }
+if($ARGV[0] eq "-nacl") {
+	$nacl = 1;
+	shift;
+}
 if($ARGV[0] eq "-arm") {
 	$arm = 1;
 	shift;
@@ -95,7 +100,7 @@ while(<>) {
 	# Line must be of the form
 	#	func Open(path string, mode int, perm int) (fd int, errno error)
 	# Split into name, in params, out params.
-	if(!/^\/\/sys(nb)? (\w+)\(([^()]*)\)\s*(?:\(([^()]+)\))?\s*(?:=\s*(SYS_[A-Z0-9_]+))?$/) {
+	if(!/^\/\/sys(nb)? (\w+)\(([^()]*)\)\s*(?:\(([^()]+)\))?\s*(?:=\s*((?i)SYS_[A-Z0-9_]+))?$/) {
 		print STDERR "$ARGV:$.: malformed //sys declaration\n";
 		$errors = 1;
 		next;
@@ -219,6 +224,9 @@ while(<>) {
 		$sysname = "SYS_$func";
 		$sysname =~ s/([a-z])([A-Z])/${1}_$2/g;	# turn FooBar into Foo_Bar
 		$sysname =~ y/a-z/A-Z/;
+		if($nacl) {
+			$sysname =~ y/A-Z/a-z/;
+		}
 	}
 
 	# Actual call.
diff --git a/src/pkg/syscall/srpc_nacl.go b/src/pkg/syscall/srpc_nacl.go
new file mode 100644
index 0000000000000000000000000000000000000000..dd07373d1a68059b77e4d8acbd7e8bbef74a2375
--- /dev/null
+++ b/src/pkg/syscall/srpc_nacl.go
@@ -0,0 +1,822 @@
+// Copyright 2013 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Native Client SRPC message passing.
+// This code is needed to invoke SecureRandom, the NaCl equivalent of /dev/random.
+
+package syscall
+
+import (
+	"errors"
+	"sync"
+	"unsafe"
+)
+
+// An srpcClient represents the client side of an SRPC connection.
+type srpcClient struct {
+	fd      int // to server
+	r       msgReceiver
+	s       msgSender
+	service map[string]srpcService // services by name
+
+	outMu sync.Mutex // protects writing to connection
+
+	mu      sync.Mutex // protects following fields
+	muxer   bool       // is someone reading and muxing responses
+	pending map[uint32]*srpc
+	idGen   uint32 // generator for request IDs
+}
+
+// An srpcService is a single method that the server offers.
+type srpcService struct {
+	num uint32 // method number
+	fmt string // argument format; see "parsing of RPC messages" below
+}
+
+// An srpc represents a single srpc issued by a client.
+type srpc struct {
+	Ret  []interface{}
+	Done chan *srpc
+	Err  error
+	c    *srpcClient
+	id   uint32
+}
+
+// newClient allocates a new SRPC client using the file descriptor fd.
+func newClient(fd int) (*srpcClient, error) {
+	c := new(srpcClient)
+	c.fd = fd
+	c.r.fd = fd
+	c.s.fd = fd
+	c.service = make(map[string]srpcService)
+	c.pending = make(map[uint32]*srpc)
+
+	// service discovery request
+	m := &msg{
+		isRequest: 1,
+		template:  []interface{}{[]byte(nil)},
+		size:      []int{4000}, // max size to accept for returned byte slice
+	}
+	if err := m.pack(); err != nil {
+		return nil, errors.New("Native Client SRPC service_discovery: preparing request: " + err.Error())
+	}
+	c.s.send(m)
+	m, err := c.r.recv()
+	if err != nil {
+		return nil, err
+	}
+	m.unpack()
+	if m.status != uint32(srpcOK) {
+		return nil, errors.New("Native Client SRPC service_discovery: " + srpcErrno(m.status).Error())
+	}
+	list := m.value[0].([]byte)
+	var n uint32
+	for len(list) > 0 {
+		var line []byte
+		i := byteIndex(list, '\n')
+		if i < 0 {
+			line, list = list, nil
+		} else {
+			line, list = list[:i], list[i+1:]
+		}
+		i = byteIndex(line, ':')
+		if i >= 0 {
+			c.service[string(line)] = srpcService{n, string(line[i+1:])}
+		}
+		n++
+	}
+
+	return c, nil
+}
+
+func byteIndex(b []byte, c byte) int {
+	for i, bi := range b {
+		if bi == c {
+			return i
+		}
+	}
+	return -1
+}
+
+var yourTurn srpc
+
+func (c *srpcClient) wait(r *srpc) {
+	var rx *srpc
+	for rx = range r.Done {
+		if rx != &yourTurn {
+			break
+		}
+		c.input()
+	}
+	return
+}
+
+func (c *srpcClient) input() {
+	// read message
+	m, err := c.r.recv()
+	if err != nil {
+		println("Native Client SRPC receive error:", err.Error())
+		return
+	}
+	if m.unpack(); m.status != uint32(srpcOK) {
+		println("Native Client SRPC receive error: invalid message: ", srpcErrno(m.status).Error())
+		return
+	}
+
+	// deliver to intended recipient
+	c.mu.Lock()
+	rpc, ok := c.pending[m.id]
+	if ok {
+		delete(c.pending, m.id)
+	}
+
+	// wake a new muxer if there are more RPCs to read
+	c.muxer = false
+	for _, rpc := range c.pending {
+		c.muxer = true
+		rpc.Done <- &yourTurn
+		break
+	}
+	c.mu.Unlock()
+	if !ok {
+		println("Native Client: unexpected response for ID", m.id)
+		return
+	}
+	rpc.Ret = m.value
+	rpc.Done <- rpc
+}
+
+// Wait blocks until the RPC has finished.
+func (r *srpc) Wait() {
+	r.c.wait(r)
+}
+
+// Start issues an RPC request for method name with the given arguments.
+// The RPC r must not be in use for another pending request.
+// To wait for the RPC to finish, receive from r.Done and then
+// inspect r.Ret and r.Errno.
+func (r *srpc) Start(name string, arg []interface{}) {
+	r.Err = nil
+	r.c.mu.Lock()
+	srv, ok := r.c.service[name]
+	if !ok {
+		r.c.mu.Unlock()
+		r.Err = srpcErrBadRPCNumber
+		r.Done <- r
+		return
+	}
+	r.c.pending[r.id] = r
+	if !r.c.muxer {
+		r.c.muxer = true
+		r.Done <- &yourTurn
+	}
+	r.c.mu.Unlock()
+
+	var m msg
+	m.id = r.id
+	m.isRequest = 1
+	m.rpc = srv.num
+	m.value = arg
+
+	// Fill in the return values and sizes to generate
+	// the right type chars.  We'll take most any size.
+
+	// Skip over input arguments.
+	// We could check them against arg, but the server
+	// will do that anyway.
+	i := 0
+	for srv.fmt[i] != ':' {
+		i++
+	}
+	format := srv.fmt[i+1:]
+
+	// Now the return prototypes.
+	m.template = make([]interface{}, len(format))
+	m.size = make([]int, len(format))
+	for i := 0; i < len(format); i++ {
+		switch format[i] {
+		default:
+			println("Native Client SRPC: unexpected service type " + string(format[i]))
+			r.Err = srpcErrBadRPCNumber
+			r.Done <- r
+			return
+		case 'b':
+			m.template[i] = false
+		case 'C':
+			m.template[i] = []byte(nil)
+			m.size[i] = 1 << 30
+		case 'd':
+			m.template[i] = float64(0)
+		case 'D':
+			m.template[i] = []float64(nil)
+			m.size[i] = 1 << 30
+		case 'h':
+			m.template[i] = int(-1)
+		case 'i':
+			m.template[i] = int32(0)
+		case 'I':
+			m.template[i] = []int32(nil)
+			m.size[i] = 1 << 30
+		case 's':
+			m.template[i] = ""
+			m.size[i] = 1 << 30
+		}
+	}
+
+	if err := m.pack(); err != nil {
+		r.Err = errors.New("Native Client RPC Start " + name + ": preparing request: " + err.Error())
+		r.Done <- r
+		return
+	}
+
+	r.c.outMu.Lock()
+	r.c.s.send(&m)
+	r.c.outMu.Unlock()
+}
+
+// Call is a convenience wrapper that starts the RPC request,
+// waits for it to finish, and then returns the results.
+// Its implementation is:
+//
+//	r.Start(name, arg)
+//	r.Wait()
+//	return r.Ret, r.Errno
+//
+func (c *srpcClient) Call(name string, arg ...interface{}) (ret []interface{}, err error) {
+	r := c.NewRPC(nil)
+	r.Start(name, arg)
+	r.Wait()
+	return r.Ret, r.Err
+}
+
+// NewRPC creates a new RPC on the client connection.
+func (c *srpcClient) NewRPC(done chan *srpc) *srpc {
+	if done == nil {
+		done = make(chan *srpc, 1)
+	}
+	c.mu.Lock()
+	id := c.idGen
+	c.idGen++
+	c.mu.Unlock()
+	return &srpc{Done: done, c: c, id: id}
+}
+
+// The current protocol number.
+// Kind of useless, since there have been backwards-incompatible changes
+// to the wire protocol that did not update the protocol number.
+// At this point it's really just a sanity check.
+const protocol = 0xc0da0002
+
+// An srpcErrno is an SRPC status code.
+type srpcErrno uint32
+
+const (
+	srpcOK srpcErrno = 256 + iota
+	srpcErrBreak
+	srpcErrMessageTruncated
+	srpcErrNoMemory
+	srpcErrProtocolMismatch
+	srpcErrBadRPCNumber
+	srpcErrBadArgType
+	srpcErrTooFewArgs
+	srpcErrTooManyArgs
+	srpcErrInArgTypeMismatch
+	srpcErrOutArgTypeMismatch
+	srpcErrInternalError
+	srpcErrAppError
+)
+
+var srpcErrstr = [...]string{
+	srpcOK - srpcOK:                    "ok",
+	srpcErrBreak - srpcOK:              "break",
+	srpcErrMessageTruncated - srpcOK:   "message truncated",
+	srpcErrNoMemory - srpcOK:           "out of memory",
+	srpcErrProtocolMismatch - srpcOK:   "protocol mismatch",
+	srpcErrBadRPCNumber - srpcOK:       "invalid RPC method number",
+	srpcErrBadArgType - srpcOK:         "unexpected argument type",
+	srpcErrTooFewArgs - srpcOK:         "too few arguments",
+	srpcErrTooManyArgs - srpcOK:        "too many arguments",
+	srpcErrInArgTypeMismatch - srpcOK:  "input argument type mismatch",
+	srpcErrOutArgTypeMismatch - srpcOK: "output argument type mismatch",
+	srpcErrInternalError - srpcOK:      "internal error",
+	srpcErrAppError - srpcOK:           "application error",
+}
+
+func (e srpcErrno) Error() string {
+	if e < srpcOK || int(e-srpcOK) >= len(srpcErrstr) {
+		return "srpcErrno(" + itoa(int(e)) + ")"
+	}
+	return srpcErrstr[e-srpcOK]
+}
+
+// A msgHdr is the data argument to the imc_recvmsg
+// and imc_sendmsg system calls.
+type msgHdr struct {
+	iov   *iov
+	niov  int32
+	desc  *int32
+	ndesc int32
+	flags uint32
+}
+
+// A single region for I/O.
+type iov struct {
+	base *byte
+	len  int32
+}
+
+const maxMsgSize = 1<<16 - 4*4
+
+// A msgReceiver receives messages from a file descriptor.
+type msgReceiver struct {
+	fd   int
+	data [maxMsgSize]byte
+	desc [8]int32
+	hdr  msgHdr
+	iov  iov
+}
+
+func (r *msgReceiver) recv() (*msg, error) {
+	// Init pointers to buffers where syscall recvmsg can write.
+	r.iov.base = &r.data[0]
+	r.iov.len = int32(len(r.data))
+	r.hdr.iov = &r.iov
+	r.hdr.niov = 1
+	r.hdr.desc = &r.desc[0]
+	r.hdr.ndesc = int32(len(r.desc))
+	n, _, e := Syscall(sys_imc_recvmsg, uintptr(r.fd), uintptr(unsafe.Pointer(&r.hdr)), 0)
+	if e != 0 {
+		println("Native Client imc_recvmsg: ", e.Error())
+		return nil, e
+	}
+
+	// Make a copy of the data so that the next recvmsg doesn't
+	// smash it.  The system call did not update r.iov.len.  Instead it
+	// returned the total byte count as n.
+	m := new(msg)
+	m.data = make([]byte, n)
+	copy(m.data, r.data[0:])
+
+	// Make a copy of the desc too.
+	// The system call *did* update r.hdr.ndesc.
+	if r.hdr.ndesc > 0 {
+		m.desc = make([]int32, r.hdr.ndesc)
+		copy(m.desc, r.desc[:])
+	}
+
+	return m, nil
+}
+
+// A msgSender sends messages on a file descriptor.
+type msgSender struct {
+	fd  int
+	hdr msgHdr
+	iov iov
+}
+
+func (s *msgSender) send(m *msg) error {
+	if len(m.data) > 0 {
+		s.iov.base = &m.data[0]
+	}
+	s.iov.len = int32(len(m.data))
+	s.hdr.iov = &s.iov
+	s.hdr.niov = 1
+	s.hdr.desc = nil
+	s.hdr.ndesc = 0
+	_, _, e := Syscall(sys_imc_sendmsg, uintptr(s.fd), uintptr(unsafe.Pointer(&s.hdr)), 0)
+	if e != 0 {
+		println("Native Client imc_sendmsg: ", e.Error())
+		return e
+	}
+	return nil
+}
+
+// A msg is the Go representation of an SRPC message.
+type msg struct {
+	data []byte  // message data
+	desc []int32 // message file descriptors
+
+	// parsed version of message
+	id        uint32
+	isRequest uint32
+	rpc       uint32
+	status    uint32
+	value     []interface{}
+	template  []interface{}
+	size      []int
+	format    string
+	broken    bool
+}
+
+// reading from a msg
+
+func (m *msg) uint32() uint32 {
+	if m.broken {
+		return 0
+	}
+	if len(m.data) < 4 {
+		m.broken = true
+		return 0
+	}
+	b := m.data[:4]
+	x := uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24
+	m.data = m.data[4:]
+	return x
+}
+
+func (m *msg) uint64() uint64 {
+	x := uint64(m.uint32()) | uint64(m.uint32())<<32
+	if m.broken {
+		return 0
+	}
+	return x
+}
+
+func (m *msg) bytes(n int) []byte {
+	if m.broken {
+		return nil
+	}
+	if len(m.data) < n {
+		m.broken = true
+		return nil
+	}
+	x := m.data[0:n]
+	m.data = m.data[n:]
+	return x
+}
+
+// writing to a msg
+
+func (m *msg) wuint32(x uint32) {
+	m.data = append(m.data, byte(x), byte(x>>8), byte(x>>16), byte(x>>24))
+}
+
+func (m *msg) wuint64(x uint64) {
+	lo := uint32(x)
+	hi := uint32(x >> 32)
+	m.data = append(m.data, byte(lo), byte(lo>>8), byte(lo>>16), byte(lo>>24), byte(hi), byte(hi>>8), byte(hi>>16), byte(hi>>24))
+}
+
+func (m *msg) wbytes(p []byte) {
+	m.data = append(m.data, p...)
+}
+
+func (m *msg) wstring(s string) {
+	m.data = append(m.data, s...)
+}
+
+// Parsing of RPC messages.
+//
+// Each message begins with
+//	total_size uint32
+//	total_descs uint32
+//	fragment_size uint32
+//	fragment_descs uint32
+//
+// If fragment_size < total_size or fragment_descs < total_descs, the actual
+// message is broken up in multiple messages; follow-up messages omit
+// the "total" fields and begin with the "fragment" fields.
+// We do not support putting fragmented messages back together.
+// To do this we would need to change the message receiver.
+//
+// After that size information, the message header follows:
+//	protocol uint32
+//	requestID uint32
+//	isRequest uint32
+//	rpcNumber uint32
+//	status uint32
+//	numValue uint32
+//	numTemplate uint32
+//
+// After the header come numTemplate fixed-size arguments,
+// numValue fixed-size arguments, and then the variable-sized
+// part of the values. The templates describe the expected results
+// and have no associated variable sized data in the request.
+//
+// Each fixed-size argument has the form:
+//	tag uint32 // really a char, like 'b' or 'C'
+//	pad uint32 // unused
+//	val1 uint32
+//	val2 uint32
+//
+// The tags are:
+//	'b':	bool; val1 == 0 or 1
+//	'C':	[]byte; val1 == len, data in variable-sized section
+//	'd':	float64; (val1, val2) is data
+//	'D':	[]float64; val1 == len, data in variable-sized section
+//	'h':	int; val1 == file descriptor
+//	'i':	int32; descriptor in next entry in m.desc
+//	'I':	[]int; val1 == len, data in variable-sized section
+//	's':	string; val1 == len, data in variable-sized section
+//
+
+func (m *msg) pack() error {
+	m.data = m.data[:0]
+	m.desc = m.desc[:0]
+
+	// sizes, to fill in later
+	m.wuint32(0)
+	m.wuint32(0)
+	m.wuint32(0)
+	m.wuint32(0)
+
+	// message header
+	m.wuint32(protocol)
+	m.wuint32(m.id)
+	m.wuint32(m.isRequest)
+	m.wuint32(m.rpc)
+	m.wuint32(m.status)
+	m.wuint32(uint32(len(m.value)))
+	m.wuint32(uint32(len(m.template)))
+
+	// fixed-size templates
+	for i, x := range m.template {
+		var tag, val1, val2 uint32
+		switch x.(type) {
+		default:
+			return errors.New("unexpected template type")
+		case bool:
+			tag = 'b'
+		case []byte:
+			tag = 'C'
+			val1 = uint32(m.size[i])
+		case float64:
+			tag = 'd'
+		case []float64:
+			tag = 'D'
+			val1 = uint32(m.size[i])
+		case int:
+			tag = 'h'
+		case int32:
+			tag = 'i'
+		case []int32:
+			tag = 'I'
+			val1 = uint32(m.size[i])
+		case string:
+			tag = 's'
+			val1 = uint32(m.size[i])
+		}
+		m.wuint32(tag)
+		m.wuint32(0)
+		m.wuint32(val1)
+		m.wuint32(val2)
+	}
+
+	// fixed-size values
+	for _, x := range m.value {
+		var tag, val1, val2 uint32
+		switch x := x.(type) {
+		default:
+			return errors.New("unexpected value type")
+		case bool:
+			tag = 'b'
+			if x {
+				val1 = 1
+			}
+		case []byte:
+			tag = 'C'
+			val1 = uint32(len(x))
+		case float64:
+			tag = 'd'
+			v := float64bits(x)
+			val1 = uint32(v)
+			val2 = uint32(v >> 32)
+		case []float64:
+			tag = 'D'
+			val1 = uint32(len(x))
+		case int32:
+			tag = 'i'
+			m.desc = append(m.desc, x)
+		case []int32:
+			tag = 'I'
+			val1 = uint32(len(x))
+		case string:
+			tag = 's'
+			val1 = uint32(len(x) + 1)
+		}
+		m.wuint32(tag)
+		m.wuint32(0)
+		m.wuint32(val1)
+		m.wuint32(val2)
+	}
+
+	// variable-length data for values
+	for _, x := range m.value {
+		switch x := x.(type) {
+		case []byte:
+			m.wbytes(x)
+		case []float64:
+			for _, f := range x {
+				m.wuint64(float64bits(f))
+			}
+		case []int32:
+			for _, j := range x {
+				m.wuint32(uint32(j))
+			}
+		case string:
+			m.wstring(x)
+			m.wstring("\x00")
+		}
+	}
+
+	// fill in sizes
+	data := m.data
+	m.data = m.data[:0]
+	m.wuint32(uint32(len(data)))
+	m.wuint32(uint32(len(m.desc)))
+	m.wuint32(uint32(len(data)))
+	m.wuint32(uint32(len(m.desc)))
+	m.data = data
+
+	return nil
+}
+
+func (m *msg) unpack() error {
+	totalSize := m.uint32()
+	totalDesc := m.uint32()
+	fragSize := m.uint32()
+	fragDesc := m.uint32()
+	if totalSize != fragSize || totalDesc != fragDesc {
+		return errors.New("Native Client: fragmented RPC messages not supported")
+	}
+	if m.uint32() != protocol {
+		return errors.New("Native Client: RPC protocol mismatch")
+	}
+
+	// message header
+	m.id = m.uint32()
+	m.isRequest = m.uint32()
+	m.rpc = m.uint32()
+	m.status = m.uint32()
+	m.value = make([]interface{}, m.uint32())
+	m.template = make([]interface{}, m.uint32())
+	m.size = make([]int, len(m.template))
+	if m.broken {
+		return errors.New("Native Client: malformed message")
+	}
+
+	// fixed-size templates
+	for i := range m.template {
+		tag := m.uint32()
+		m.uint32() // padding
+		val1 := m.uint32()
+		m.uint32() // val2
+		switch tag {
+		default:
+			return errors.New("Native Client: unexpected template type " + string(rune(tag)))
+		case 'b':
+			m.template[i] = false
+		case 'C':
+			m.template[i] = []byte(nil)
+			m.size[i] = int(val1)
+		case 'd':
+			m.template[i] = float64(0)
+		case 'D':
+			m.template[i] = []float64(nil)
+			m.size[i] = int(val1)
+		case 'i':
+			m.template[i] = int32(0)
+		case 'I':
+			m.template[i] = []int32(nil)
+			m.size[i] = int(val1)
+		case 'h':
+			m.template[i] = int(0)
+		case 's':
+			m.template[i] = ""
+			m.size[i] = int(val1)
+		}
+	}
+
+	// fixed-size values
+	var (
+		strsize []uint32
+		d       int
+	)
+	for i := range m.value {
+		tag := m.uint32()
+		m.uint32() // padding
+		val1 := m.uint32()
+		val2 := m.uint32()
+		switch tag {
+		default:
+			return errors.New("Native Client: unexpected value type " + string(rune(tag)))
+		case 'b':
+			m.value[i] = val1 > 0
+		case 'C':
+			m.value[i] = []byte(nil)
+			strsize = append(strsize, val1)
+		case 'd':
+			m.value[i] = float64frombits(uint64(val1) | uint64(val2)<<32)
+		case 'D':
+			m.value[i] = make([]float64, val1)
+		case 'i':
+			m.value[i] = int32(val1)
+		case 'I':
+			m.value[i] = make([]int32, val1)
+		case 'h':
+			m.value[i] = int(m.desc[d])
+			d++
+		case 's':
+			m.value[i] = ""
+			strsize = append(strsize, val1)
+		}
+	}
+
+	// variable-sized parts of values
+	for i, x := range m.value {
+		switch x := x.(type) {
+		case []byte:
+			m.value[i] = m.bytes(int(strsize[0]))
+			strsize = strsize[1:]
+		case []float64:
+			for i := range x {
+				x[i] = float64frombits(m.uint64())
+			}
+		case []int32:
+			for i := range x {
+				x[i] = int32(m.uint32())
+			}
+		case string:
+			m.value[i] = string(m.bytes(int(strsize[0])))
+			strsize = strsize[1:]
+		}
+	}
+
+	if len(m.data) > 0 {
+		return errors.New("Native Client: junk at end of message")
+	}
+	return nil
+}
+
+func float64bits(x float64) uint64 {
+	return *(*uint64)(unsafe.Pointer(&x))
+}
+
+func float64frombits(x uint64) float64 {
+	return *(*float64)(unsafe.Pointer(&x))
+}
+
+// At startup, connect to the name service.
+var nsClient = nsConnect()
+
+func nsConnect() *srpcClient {
+	var ns int32 = -1
+	_, _, errno := Syscall(sys_nameservice, uintptr(unsafe.Pointer(&ns)), 0, 0)
+	if errno != 0 {
+		println("Native Client nameservice:", errno.Error())
+		return nil
+	}
+
+	sock, _, errno := Syscall(sys_imc_connect, uintptr(ns), 0, 0)
+	if errno != 0 {
+		println("Native Client nameservice connect:", errno.Error())
+		return nil
+	}
+
+	c, err := newClient(int(sock))
+	if err != nil {
+		println("Native Client nameservice init:", err.Error())
+		return nil
+	}
+
+	return c
+}
+
+const (
+	nsSuccess               = 0
+	nsNameNotFound          = 1
+	nsDuplicateName         = 2
+	nsInsufficientResources = 3
+	nsPermissionDenied      = 4
+	nsInvalidArgument       = 5
+)
+
+func openNamedService(name string, mode int32) (fd int, err error) {
+	if nsClient == nil {
+		return 0, errors.New("no name service")
+	}
+	ret, err := nsClient.Call("lookup:si:ih", name, int32(mode))
+	if err != nil {
+		return 0, err
+	}
+	status := ret[0].(int32)
+	fd = ret[1].(int)
+	switch status {
+	case nsSuccess:
+		// ok
+	case nsNameNotFound:
+		return -1, ENOENT
+	case nsDuplicateName:
+		return -1, EEXIST
+	case nsInsufficientResources:
+		return -1, EWOULDBLOCK
+	case nsPermissionDenied:
+		return -1, EPERM
+	case nsInvalidArgument:
+		return -1, EINVAL
+	default:
+		return -1, EINVAL
+	}
+	return fd, nil
+}
diff --git a/src/pkg/syscall/syscall_nacl.go b/src/pkg/syscall/syscall_nacl.go
new file mode 100644
index 0000000000000000000000000000000000000000..c2788b20ab485e866297190bfa336525606aba0a
--- /dev/null
+++ b/src/pkg/syscall/syscall_nacl.go
@@ -0,0 +1,311 @@
+// Copyright 2013 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package syscall
+
+import (
+	"sync"
+	"unsafe"
+)
+
+//sys	naclClose(fd int) (err error) = sys_close
+//sys	Exit(code int) (err error)
+//sys	naclFstat(fd int, stat *Stat_t) (err error) = sys_fstat
+//sys	naclRead(fd int, b []byte) (n int, err error) = sys_read
+//sys	naclSeek(fd int, off *int64, whence int) (err error) = sys_lseek
+
+const direntSize = 8 + 8 + 2 + 256
+
+// native_client/src/trusted/service_runtime/include/sys/dirent.h
+type Dirent struct {
+	Ino    int64
+	Off    int64
+	Reclen uint16
+	Name   [256]byte
+}
+
+func ParseDirent(buf []byte, max int, names []string) (consumed int, count int, newnames []string) {
+	origlen := len(buf)
+	count = 0
+	for max != 0 && len(buf) > 0 {
+		dirent := (*Dirent)(unsafe.Pointer(&buf[0]))
+		buf = buf[dirent.Reclen:]
+		if dirent.Ino == 0 { // File absent in directory.
+			continue
+		}
+		bytes := (*[512 + PathMax]byte)(unsafe.Pointer(&dirent.Name[0]))
+		var name = string(bytes[0:clen(bytes[:])])
+		if name == "." || name == ".." { // Useless names
+			continue
+		}
+		max--
+		count++
+		names = append(names, name)
+	}
+	return origlen - len(buf), count, names
+}
+
+func clen(n []byte) int {
+	for i := 0; i < len(n); i++ {
+		if n[i] == 0 {
+			return i
+		}
+	}
+	return len(n)
+}
+
+const PathMax = 256
+
+// An Errno is an unsigned number describing an error condition.
+// It implements the error interface.  The zero Errno is by convention
+// a non-error, so code to convert from Errno to error should use:
+//	err = nil
+//	if errno != 0 {
+//		err = errno
+//	}
+type Errno uintptr
+
+func (e Errno) Error() string {
+	if 0 <= int(e) && int(e) < len(errorstr) {
+		s := errorstr[e]
+		if s != "" {
+			return s
+		}
+	}
+	return "errno " + itoa(int(e))
+}
+
+func (e Errno) Temporary() bool {
+	return e == EINTR || e == EMFILE || e.Timeout()
+}
+
+func (e Errno) Timeout() bool {
+	return e == EAGAIN || e == EWOULDBLOCK || e == ETIMEDOUT
+}
+
+// A Signal is a number describing a process signal.
+// It implements the os.Signal interface.
+type Signal int
+
+const (
+	_ Signal = iota
+	SIGCHLD
+	SIGINT
+	SIGKILL
+	SIGTRAP
+	SIGQUIT
+)
+
+func (s Signal) Signal() {}
+
+func (s Signal) String() string {
+	if 0 <= s && int(s) < len(signals) {
+		str := signals[s]
+		if str != "" {
+			return str
+		}
+	}
+	return "signal " + itoa(int(s))
+}
+
+var signals = [...]string{}
+
+// File system
+
+const (
+	Stdin  = 0
+	Stdout = 1
+	Stderr = 2
+)
+
+// native_client/src/trusted/service_runtime/include/sys/fcntl.h
+const (
+	O_RDONLY  = 0
+	O_WRONLY  = 1
+	O_RDWR    = 2
+	O_ACCMODE = 3
+
+	O_CREAT    = 0100
+	O_CREATE   = O_CREAT // for ken
+	O_TRUNC    = 01000
+	O_APPEND   = 02000
+	O_EXCL     = 0200
+	O_NONBLOCK = 04000
+	O_NDELAY   = O_NONBLOCK
+	O_SYNC     = 010000
+	O_FSYNC    = O_SYNC
+	O_ASYNC    = 020000
+
+	O_CLOEXEC = 0
+
+	FD_CLOEXEC = 1
+)
+
+// native_client/src/trusted/service_runtime/include/sys/fcntl.h
+const (
+	F_DUPFD   = 0
+	F_GETFD   = 1
+	F_SETFD   = 2
+	F_GETFL   = 3
+	F_SETFL   = 4
+	F_GETOWN  = 5
+	F_SETOWN  = 6
+	F_GETLK   = 7
+	F_SETLK   = 8
+	F_SETLKW  = 9
+	F_RGETLK  = 10
+	F_RSETLK  = 11
+	F_CNVT    = 12
+	F_RSETLKW = 13
+
+	F_RDLCK   = 1
+	F_WRLCK   = 2
+	F_UNLCK   = 3
+	F_UNLKSYS = 4
+)
+
+// native_client/src/trusted/service_runtime/include/bits/stat.h
+const (
+	S_IFMT        = 0000370000
+	S_IFSHM_SYSV  = 0000300000
+	S_IFSEMA      = 0000270000
+	S_IFCOND      = 0000260000
+	S_IFMUTEX     = 0000250000
+	S_IFSHM       = 0000240000
+	S_IFBOUNDSOCK = 0000230000
+	S_IFSOCKADDR  = 0000220000
+	S_IFDSOCK     = 0000210000
+
+	S_IFSOCK = 0000140000
+	S_IFLNK  = 0000120000
+	S_IFREG  = 0000100000
+	S_IFBLK  = 0000060000
+	S_IFDIR  = 0000040000
+	S_IFCHR  = 0000020000
+	S_IFIFO  = 0000010000
+
+	S_UNSUP = 0000370000
+
+	S_ISUID = 0004000
+	S_ISGID = 0002000
+	S_ISVTX = 0001000
+
+	S_IREAD  = 0400
+	S_IWRITE = 0200
+	S_IEXEC  = 0100
+
+	S_IRWXU = 0700
+	S_IRUSR = 0400
+	S_IWUSR = 0200
+	S_IXUSR = 0100
+
+	S_IRWXG = 070
+	S_IRGRP = 040
+	S_IWGRP = 020
+	S_IXGRP = 010
+
+	S_IRWXO = 07
+	S_IROTH = 04
+	S_IWOTH = 02
+	S_IXOTH = 01
+)
+
+// native_client/src/trusted/service_runtime/include/sys/stat.h
+// native_client/src/trusted/service_runtime/include/machine/_types.h
+type Stat_t struct {
+	Dev       int64
+	Ino       uint64
+	Mode      uint32
+	Nlink     uint32
+	Uid       uint32
+	Gid       uint32
+	Rdev      int64
+	Size      int64
+	Blksize   int32
+	Blocks    int32
+	Atime     int64
+	AtimeNsec int64
+	Mtime     int64
+	MtimeNsec int64
+	Ctime     int64
+	CtimeNsec int64
+}
+
+// Processes
+// Not supported on NaCl - just enough for package os.
+
+var ForkLock sync.RWMutex
+
+type WaitStatus uint32
+
+func (w WaitStatus) Exited() bool       { return false }
+func (w WaitStatus) ExitStatus() int    { return 0 }
+func (w WaitStatus) Signaled() bool     { return false }
+func (w WaitStatus) Signal() Signal     { return 0 }
+func (w WaitStatus) CoreDump() bool     { return false }
+func (w WaitStatus) Stopped() bool      { return false }
+func (w WaitStatus) Continued() bool    { return false }
+func (w WaitStatus) StopSignal() Signal { return 0 }
+func (w WaitStatus) TrapCause() int     { return 0 }
+
+// XXX made up
+type Rusage struct {
+	Utime Timeval
+	Stime Timeval
+}
+
+// XXX made up
+type ProcAttr struct {
+	Dir   string
+	Env   []string
+	Files []uintptr
+	Sys   *SysProcAttr
+}
+
+type SysProcAttr struct {
+}
+
+// System
+
+func Syscall(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err Errno)
+func Syscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno) { return 0, 0, ENOSYS }
+func RawSyscall(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err Errno)           { return 0, 0, ENOSYS }
+func RawSyscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno) {
+	return 0, 0, ENOSYS
+}
+
+func Sysctl(key string) (string, error) {
+	if key == "kern.hostname" {
+		return "naclbox", nil
+	}
+	return "", ENOSYS
+}
+
+// Unimplemented Unix midden heap.
+
+const ImplementsGetwd = false
+
+func Getwd() (wd string, err error)     { return "", ENOSYS }
+func Getegid() int                      { return 1 }
+func Geteuid() int                      { return 1 }
+func Getgid() int                       { return 1 }
+func Getgroups() ([]int, error)         { return []int{1}, nil }
+func Getpagesize() int                  { return 65536 }
+func Getppid() int                      { return 2 }
+func Getpid() int                       { return 3 }
+func Getuid() int                       { return 1 }
+func Kill(pid int, signum Signal) error { return ENOSYS }
+func Sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) {
+	return 0, ENOSYS
+}
+func StartProcess(argv0 string, argv []string, attr *ProcAttr) (pid int, handle uintptr, err error) {
+	return 0, 0, ENOSYS
+}
+func Wait4(pid int, wstatus *WaitStatus, options int, rusage *Rusage) (wpid int, err error) {
+	return 0, ENOSYS
+}
+func RouteRIB(facility, param int) ([]byte, error)                { return nil, ENOSYS }
+func ParseRoutingMessage(b []byte) ([]RoutingMessage, error)      { return nil, ENOSYS }
+func ParseRoutingSockaddr(msg RoutingMessage) ([]Sockaddr, error) { return nil, ENOSYS }
+func SysctlUint32(name string) (value uint32, err error)          { return 0, ENOSYS }
diff --git a/src/pkg/syscall/syscall_nacl_386.go b/src/pkg/syscall/syscall_nacl_386.go
new file mode 100644
index 0000000000000000000000000000000000000000..d12f8e2d6d0771f159a6a2f0d9c81b766d5a3b6b
--- /dev/null
+++ b/src/pkg/syscall/syscall_nacl_386.go
@@ -0,0 +1,32 @@
+// Copyright 2013 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package syscall
+
+type Timespec struct {
+	Sec  int64
+	Nsec int32
+}
+
+type Timeval struct {
+	Sec  int64
+	Usec int32
+}
+
+func TimespecToNsec(ts Timespec) int64 { return int64(ts.Sec)*1e9 + int64(ts.Nsec) }
+
+func NsecToTimespec(nsec int64) (ts Timespec) {
+	ts.Sec = int64(nsec / 1e9)
+	ts.Nsec = int32(nsec % 1e9)
+	return
+}
+
+func TimevalToNsec(tv Timeval) int64 { return int64(tv.Sec)*1e9 + int64(tv.Usec)*1e3 }
+
+func NsecToTimeval(nsec int64) (tv Timeval) {
+	nsec += 999 // round up to microsecond
+	tv.Usec = int32(nsec % 1e9 / 1e3)
+	tv.Sec = int64(nsec / 1e9)
+	return
+}
diff --git a/src/pkg/syscall/syscall_nacl_amd64p32.go b/src/pkg/syscall/syscall_nacl_amd64p32.go
new file mode 100644
index 0000000000000000000000000000000000000000..d12f8e2d6d0771f159a6a2f0d9c81b766d5a3b6b
--- /dev/null
+++ b/src/pkg/syscall/syscall_nacl_amd64p32.go
@@ -0,0 +1,32 @@
+// Copyright 2013 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package syscall
+
+type Timespec struct {
+	Sec  int64
+	Nsec int32
+}
+
+type Timeval struct {
+	Sec  int64
+	Usec int32
+}
+
+func TimespecToNsec(ts Timespec) int64 { return int64(ts.Sec)*1e9 + int64(ts.Nsec) }
+
+func NsecToTimespec(nsec int64) (ts Timespec) {
+	ts.Sec = int64(nsec / 1e9)
+	ts.Nsec = int32(nsec % 1e9)
+	return
+}
+
+func TimevalToNsec(tv Timeval) int64 { return int64(tv.Sec)*1e9 + int64(tv.Usec)*1e3 }
+
+func NsecToTimeval(nsec int64) (tv Timeval) {
+	nsec += 999 // round up to microsecond
+	tv.Usec = int32(nsec % 1e9 / 1e3)
+	tv.Sec = int64(nsec / 1e9)
+	return
+}
diff --git a/src/pkg/syscall/tables_nacl.go b/src/pkg/syscall/tables_nacl.go
new file mode 100644
index 0000000000000000000000000000000000000000..08f4ced5398802f551ba94d1b8d51ae5a5db61b8
--- /dev/null
+++ b/src/pkg/syscall/tables_nacl.go
@@ -0,0 +1,324 @@
+// Copyright 2013 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package syscall
+
+// TODO: generate with runtime/mknacl.sh, allow override with IRT.
+const (
+	sys_null                 = 1
+	sys_nameservice          = 2
+	sys_dup                  = 8
+	sys_dup2                 = 9
+	sys_open                 = 10
+	sys_close                = 11
+	sys_read                 = 12
+	sys_write                = 13
+	sys_lseek                = 14
+	sys_ioctl                = 15
+	sys_stat                 = 16
+	sys_fstat                = 17
+	sys_chmod                = 18
+	sys_brk                  = 20
+	sys_mmap                 = 21
+	sys_munmap               = 22
+	sys_getdents             = 23
+	sys_mprotect             = 24
+	sys_list_mappings        = 25
+	sys_exit                 = 30
+	sys_getpid               = 31
+	sys_sched_yield          = 32
+	sys_sysconf              = 33
+	sys_gettimeofday         = 40
+	sys_clock                = 41
+	sys_nanosleep            = 42
+	sys_clock_getres         = 43
+	sys_clock_gettime        = 44
+	sys_mkdir                = 45
+	sys_rmdir                = 46
+	sys_chdir                = 47
+	sys_getcwd               = 48
+	sys_unlink               = 49
+	sys_imc_makeboundsock    = 60
+	sys_imc_accept           = 61
+	sys_imc_connect          = 62
+	sys_imc_sendmsg          = 63
+	sys_imc_recvmsg          = 64
+	sys_imc_mem_obj_create   = 65
+	sys_imc_socketpair       = 66
+	sys_mutex_create         = 70
+	sys_mutex_lock           = 71
+	sys_mutex_trylock        = 72
+	sys_mutex_unlock         = 73
+	sys_cond_create          = 74
+	sys_cond_wait            = 75
+	sys_cond_signal          = 76
+	sys_cond_broadcast       = 77
+	sys_cond_timed_wait_abs  = 79
+	sys_thread_create        = 80
+	sys_thread_exit          = 81
+	sys_tls_init             = 82
+	sys_thread_nice          = 83
+	sys_tls_get              = 84
+	sys_second_tls_set       = 85
+	sys_second_tls_get       = 86
+	sys_exception_handler    = 87
+	sys_exception_stack      = 88
+	sys_exception_clear_flag = 89
+	sys_sem_create           = 100
+	sys_sem_wait             = 101
+	sys_sem_post             = 102
+	sys_sem_get_value        = 103
+	sys_dyncode_create       = 104
+	sys_dyncode_modify       = 105
+	sys_dyncode_delete       = 106
+	sys_test_infoleak        = 109
+	sys_test_crash           = 110
+	sys_test_syscall_1       = 111
+	sys_test_syscall_2       = 112
+)
+
+// TODO: Auto-generate some day. (Hard-coded in binaries so not likely to change.)
+const (
+	// native_client/src/trusted/service_runtime/include/sys/errno.h
+	// The errors are mainly copied from Linux.
+	EPERM           Errno = 1       /* Operation not permitted */
+	ENOENT          Errno = 2       /* No such file or directory */
+	ESRCH           Errno = 3       /* No such process */
+	EINTR           Errno = 4       /* Interrupted system call */
+	EIO             Errno = 5       /* I/O error */
+	ENXIO           Errno = 6       /* No such device or address */
+	E2BIG           Errno = 7       /* Argument list too long */
+	ENOEXEC         Errno = 8       /* Exec format error */
+	EBADF           Errno = 9       /* Bad file number */
+	ECHILD          Errno = 10      /* No child processes */
+	EAGAIN          Errno = 11      /* Try again */
+	ENOMEM          Errno = 12      /* Out of memory */
+	EACCES          Errno = 13      /* Permission denied */
+	EFAULT          Errno = 14      /* Bad address */
+	EBUSY           Errno = 16      /* Device or resource busy */
+	EEXIST          Errno = 17      /* File exists */
+	EXDEV           Errno = 18      /* Cross-device link */
+	ENODEV          Errno = 19      /* No such device */
+	ENOTDIR         Errno = 20      /* Not a directory */
+	EISDIR          Errno = 21      /* Is a directory */
+	EINVAL          Errno = 22      /* Invalid argument */
+	ENFILE          Errno = 23      /* File table overflow */
+	EMFILE          Errno = 24      /* Too many open files */
+	ENOTTY          Errno = 25      /* Not a typewriter */
+	EFBIG           Errno = 27      /* File too large */
+	ENOSPC          Errno = 28      /* No space left on device */
+	ESPIPE          Errno = 29      /* Illegal seek */
+	EROFS           Errno = 30      /* Read-only file system */
+	EMLINK          Errno = 31      /* Too many links */
+	EPIPE           Errno = 32      /* Broken pipe */
+	ENAMETOOLONG    Errno = 36      /* File name too long */
+	ENOSYS          Errno = 38      /* Function not implemented */
+	EDQUOT          Errno = 122     /* Quota exceeded */
+	EDOM            Errno = 33      /* Math arg out of domain of func */
+	ERANGE          Errno = 34      /* Math result not representable */
+	EDEADLK         Errno = 35      /* Deadlock condition */
+	ENOLCK          Errno = 37      /* No record locks available */
+	ENOTEMPTY       Errno = 39      /* Directory not empty */
+	ELOOP           Errno = 40      /* Too many symbolic links */
+	ENOMSG          Errno = 42      /* No message of desired type */
+	EIDRM           Errno = 43      /* Identifier removed */
+	ECHRNG          Errno = 44      /* Channel number out of range */
+	EL2NSYNC        Errno = 45      /* Level 2 not synchronized */
+	EL3HLT          Errno = 46      /* Level 3 halted */
+	EL3RST          Errno = 47      /* Level 3 reset */
+	ELNRNG          Errno = 48      /* Link number out of range */
+	EUNATCH         Errno = 49      /* Protocol driver not attached */
+	ENOCSI          Errno = 50      /* No CSI structure available */
+	EL2HLT          Errno = 51      /* Level 2 halted */
+	EBADE           Errno = 52      /* Invalid exchange */
+	EBADR           Errno = 53      /* Invalid request descriptor */
+	EXFULL          Errno = 54      /* Exchange full */
+	ENOANO          Errno = 55      /* No anode */
+	EBADRQC         Errno = 56      /* Invalid request code */
+	EBADSLT         Errno = 57      /* Invalid slot */
+	EDEADLOCK       Errno = EDEADLK /* File locking deadlock error */
+	EBFONT          Errno = 59      /* Bad font file fmt */
+	ENOSTR          Errno = 60      /* Device not a stream */
+	ENODATA         Errno = 61      /* No data (for no delay io) */
+	ETIME           Errno = 62      /* Timer expired */
+	ENOSR           Errno = 63      /* Out of streams resources */
+	ENONET          Errno = 64      /* Machine is not on the network */
+	ENOPKG          Errno = 65      /* Package not installed */
+	EREMOTE         Errno = 66      /* The object is remote */
+	ENOLINK         Errno = 67      /* The link has been severed */
+	EADV            Errno = 68      /* Advertise error */
+	ESRMNT          Errno = 69      /* Srmount error */
+	ECOMM           Errno = 70      /* Communication error on send */
+	EPROTO          Errno = 71      /* Protocol error */
+	EMULTIHOP       Errno = 72      /* Multihop attempted */
+	EDOTDOT         Errno = 73      /* Cross mount point (not really error) */
+	EBADMSG         Errno = 74      /* Trying to read unreadable message */
+	EOVERFLOW       Errno = 75      /* Value too large for defined data type */
+	ENOTUNIQ        Errno = 76      /* Given log. name not unique */
+	EBADFD          Errno = 77      /* f.d. invalid for this operation */
+	EREMCHG         Errno = 78      /* Remote address changed */
+	ELIBACC         Errno = 79      /* Can't access a needed shared lib */
+	ELIBBAD         Errno = 80      /* Accessing a corrupted shared lib */
+	ELIBSCN         Errno = 81      /* .lib section in a.out corrupted */
+	ELIBMAX         Errno = 82      /* Attempting to link in too many libs */
+	ELIBEXEC        Errno = 83      /* Attempting to exec a shared library */
+	EILSEQ          Errno = 84
+	EUSERS          Errno = 87
+	ENOTSOCK        Errno = 88  /* Socket operation on non-socket */
+	EDESTADDRREQ    Errno = 89  /* Destination address required */
+	EMSGSIZE        Errno = 90  /* Message too long */
+	EPROTOTYPE      Errno = 91  /* Protocol wrong type for socket */
+	ENOPROTOOPT     Errno = 92  /* Protocol not available */
+	EPROTONOSUPPORT Errno = 93  /* Unknown protocol */
+	ESOCKTNOSUPPORT Errno = 94  /* Socket type not supported */
+	EOPNOTSUPP      Errno = 95  /* Operation not supported on transport endpoint */
+	EPFNOSUPPORT    Errno = 96  /* Protocol family not supported */
+	EAFNOSUPPORT    Errno = 97  /* Address family not supported by protocol family */
+	EADDRINUSE      Errno = 98  /* Address already in use */
+	EADDRNOTAVAIL   Errno = 99  /* Address not available */
+	ENETDOWN        Errno = 100 /* Network interface is not configured */
+	ENETUNREACH     Errno = 101 /* Network is unreachable */
+	ENETRESET       Errno = 102
+	ECONNABORTED    Errno = 103 /* Connection aborted */
+	ECONNRESET      Errno = 104 /* Connection reset by peer */
+	ENOBUFS         Errno = 105 /* No buffer space available */
+	EISCONN         Errno = 106 /* Socket is already connected */
+	ENOTCONN        Errno = 107 /* Socket is not connected */
+	ESHUTDOWN       Errno = 108 /* Can't send after socket shutdown */
+	ETOOMANYREFS    Errno = 109
+	ETIMEDOUT       Errno = 110 /* Connection timed out */
+	ECONNREFUSED    Errno = 111 /* Connection refused */
+	EHOSTDOWN       Errno = 112 /* Host is down */
+	EHOSTUNREACH    Errno = 113 /* Host is unreachable */
+	EALREADY        Errno = 114 /* Socket already connected */
+	EINPROGRESS     Errno = 115 /* Connection already in progress */
+	ESTALE          Errno = 116
+	ENOTSUP         Errno = EOPNOTSUPP /* Not supported */
+	ENOMEDIUM       Errno = 123        /* No medium (in tape drive) */
+	ECANCELED       Errno = 125        /* Operation canceled. */
+	ELBIN           Errno = 2048       /* Inode is remote (not really error) */
+	EFTYPE          Errno = 2049       /* Inappropriate file type or format */
+	ENMFILE         Errno = 2050       /* No more files */
+	EPROCLIM        Errno = 2051
+	ENOSHARE        Errno = 2052   /* No such host or network path */
+	ECASECLASH      Errno = 2053   /* Filename exists with different case */
+	EWOULDBLOCK     Errno = EAGAIN /* Operation would block */
+)
+
+// TODO: Auto-generate some day. (Hard-coded in binaries so not likely to change.)
+var errorstr = [...]string{
+	EPERM:           "Operation not permitted",
+	ENOENT:          "No such file or directory",
+	ESRCH:           "No such process",
+	EINTR:           "Interrupted system call",
+	EIO:             "I/O error",
+	ENXIO:           "No such device or address",
+	E2BIG:           "Argument list too long",
+	ENOEXEC:         "Exec format error",
+	EBADF:           "Bad file number",
+	ECHILD:          "No child processes",
+	EAGAIN:          "Try again",
+	ENOMEM:          "Out of memory",
+	EACCES:          "Permission denied",
+	EFAULT:          "Bad address",
+	EBUSY:           "Device or resource busy",
+	EEXIST:          "File exists",
+	EXDEV:           "Cross-device link",
+	ENODEV:          "No such device",
+	ENOTDIR:         "Not a directory",
+	EISDIR:          "Is a directory",
+	EINVAL:          "Invalid argument",
+	ENFILE:          "File table overflow",
+	EMFILE:          "Too many open files",
+	ENOTTY:          "Not a typewriter",
+	EFBIG:           "File too large",
+	ENOSPC:          "No space left on device",
+	ESPIPE:          "Illegal seek",
+	EROFS:           "Read-only file system",
+	EMLINK:          "Too many links",
+	EPIPE:           "Broken pipe",
+	ENAMETOOLONG:    "File name too long",
+	ENOSYS:          "not implemented on Native Client",
+	EDQUOT:          "Quota exceeded",
+	EDOM:            "Math arg out of domain of func",
+	ERANGE:          "Math result not representable",
+	EDEADLK:         "Deadlock condition",
+	ENOLCK:          "No record locks available",
+	ENOTEMPTY:       "Directory not empty",
+	ELOOP:           "Too many symbolic links",
+	ENOMSG:          "No message of desired type",
+	EIDRM:           "Identifier removed",
+	ECHRNG:          "Channel number out of range",
+	EL2NSYNC:        "Level 2 not synchronized",
+	EL3HLT:          "Level 3 halted",
+	EL3RST:          "Level 3 reset",
+	ELNRNG:          "Link number out of range",
+	EUNATCH:         "Protocol driver not attached",
+	ENOCSI:          "No CSI structure available",
+	EL2HLT:          "Level 2 halted",
+	EBADE:           "Invalid exchange",
+	EBADR:           "Invalid request descriptor",
+	EXFULL:          "Exchange full",
+	ENOANO:          "No anode",
+	EBADRQC:         "Invalid request code",
+	EBADSLT:         "Invalid slot",
+	EBFONT:          "Bad font file fmt",
+	ENOSTR:          "Device not a stream",
+	ENODATA:         "No data (for no delay io)",
+	ETIME:           "Timer expired",
+	ENOSR:           "Out of streams resources",
+	ENONET:          "Machine is not on the network",
+	ENOPKG:          "Package not installed",
+	EREMOTE:         "The object is remote",
+	ENOLINK:         "The link has been severed",
+	EADV:            "Advertise error",
+	ESRMNT:          "Srmount error",
+	ECOMM:           "Communication error on send",
+	EPROTO:          "Protocol error",
+	EMULTIHOP:       "Multihop attempted",
+	EDOTDOT:         "Cross mount point (not really error)",
+	EBADMSG:         "Trying to read unreadable message",
+	EOVERFLOW:       "Value too large for defined data type",
+	ENOTUNIQ:        "Given log. name not unique",
+	EBADFD:          "f.d. invalid for this operation",
+	EREMCHG:         "Remote address changed",
+	ELIBACC:         "Can't access a needed shared lib",
+	ELIBBAD:         "Accessing a corrupted shared lib",
+	ELIBSCN:         ".lib section in a.out corrupted",
+	ELIBMAX:         "Attempting to link in too many libs",
+	ELIBEXEC:        "Attempting to exec a shared library",
+	ENOTSOCK:        "Socket operation on non-socket",
+	EDESTADDRREQ:    "Destination address required",
+	EMSGSIZE:        "Message too long",
+	EPROTOTYPE:      "Protocol wrong type for socket",
+	ENOPROTOOPT:     "Protocol not available",
+	EPROTONOSUPPORT: "Unknown protocol",
+	ESOCKTNOSUPPORT: "Socket type not supported",
+	EOPNOTSUPP:      "Operation not supported on transport endpoint",
+	EPFNOSUPPORT:    "Protocol family not supported",
+	EAFNOSUPPORT:    "Address family not supported by protocol family",
+	EADDRINUSE:      "Address already in use",
+	EADDRNOTAVAIL:   "Address not available",
+	ENETDOWN:        "Network interface is not configured",
+	ENETUNREACH:     "Network is unreachable",
+	ECONNABORTED:    "Connection aborted",
+	ECONNRESET:      "Connection reset by peer",
+	ENOBUFS:         "No buffer space available",
+	EISCONN:         "Socket is already connected",
+	ENOTCONN:        "Socket is not connected",
+	ESHUTDOWN:       "Can't send after socket shutdown",
+	ETIMEDOUT:       "Connection timed out",
+	ECONNREFUSED:    "Connection refused",
+	EHOSTDOWN:       "Host is down",
+	EHOSTUNREACH:    "Host is unreachable",
+	EALREADY:        "Socket already connected",
+	EINPROGRESS:     "Connection already in progress",
+	ENOMEDIUM:       "No medium (in tape drive)",
+	ECANCELED:       "Operation canceled.",
+	ELBIN:           "Inode is remote (not really error)",
+	EFTYPE:          "Inappropriate file type or format",
+	ENMFILE:         "No more files",
+	ENOSHARE:        "No such host or network path",
+	ECASECLASH:      "Filename exists with different case",
+}
diff --git a/src/pkg/syscall/time_nacl_386.s b/src/pkg/syscall/time_nacl_386.s
new file mode 100644
index 0000000000000000000000000000000000000000..b5a22d31b5a12499a4dd75f6c80bc7113b0d87b7
--- /dev/null
+++ b/src/pkg/syscall/time_nacl_386.s
@@ -0,0 +1,11 @@
+// Copyright 2013 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "../../cmd/ld/textflag.h"
+
+TEXT ·startTimer(SB),NOSPLIT,$0
+	JMP time·startTimer(SB)
+
+TEXT ·stopTimer(SB),NOSPLIT,$0
+	JMP time·stopTimer(SB)
diff --git a/src/pkg/syscall/time_nacl_amd64p32.s b/src/pkg/syscall/time_nacl_amd64p32.s
new file mode 100644
index 0000000000000000000000000000000000000000..b5a22d31b5a12499a4dd75f6c80bc7113b0d87b7
--- /dev/null
+++ b/src/pkg/syscall/time_nacl_amd64p32.s
@@ -0,0 +1,11 @@
+// Copyright 2013 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "../../cmd/ld/textflag.h"
+
+TEXT ·startTimer(SB),NOSPLIT,$0
+	JMP time·startTimer(SB)
+
+TEXT ·stopTimer(SB),NOSPLIT,$0
+	JMP time·stopTimer(SB)
diff --git a/src/pkg/syscall/unzip_nacl.go b/src/pkg/syscall/unzip_nacl.go
new file mode 100644
index 0000000000000000000000000000000000000000..5845e44f01af6bb169116c21eb60802bc014063a
--- /dev/null
+++ b/src/pkg/syscall/unzip_nacl.go
@@ -0,0 +1,685 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Small in-memory unzip implementation.
+// A simplified copy of the pre-Go 1 compress/flate/inflate.go
+// and a modified copy of the zip reader in package time.
+// (The one in package time does not support decompression; this one does.)
+
+package syscall
+
+const (
+	maxCodeLen = 16    // max length of Huffman code
+	maxHist    = 32768 // max history required
+	maxLit     = 286
+	maxDist    = 32
+	numCodes   = 19 // number of codes in Huffman meta-code
+)
+
+type decompressor struct {
+	in  string // compressed input
+	out []byte // uncompressed output
+	b   uint32 // input bits, at top of b
+	nb  uint
+	err bool // invalid input
+	eof bool // reached EOF
+
+	h1, h2   huffmanDecoder        // decoders for literal/length, distance
+	bits     [maxLit + maxDist]int // lengths defining Huffman codes
+	codebits [numCodes]int
+}
+
+func (f *decompressor) nextBlock() {
+	for f.nb < 1+2 {
+		if f.moreBits(); f.err {
+			return
+		}
+	}
+	f.eof = f.b&1 == 1
+	f.b >>= 1
+	typ := f.b & 3
+	f.b >>= 2
+	f.nb -= 1 + 2
+	switch typ {
+	case 0:
+		f.dataBlock()
+	case 1:
+		// compressed, fixed Huffman tables
+		f.huffmanBlock(&fixedHuffmanDecoder, nil)
+	case 2:
+		// compressed, dynamic Huffman tables
+		if f.readHuffman(); f.err {
+			break
+		}
+		f.huffmanBlock(&f.h1, &f.h2)
+	default:
+		// 3 is reserved.
+		f.err = true
+	}
+}
+
+// RFC 1951 section 3.2.7.
+// Compression with dynamic Huffman codes
+
+var codeOrder = [...]int{16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}
+
+func (f *decompressor) readHuffman() {
+	// HLIT[5], HDIST[5], HCLEN[4].
+	for f.nb < 5+5+4 {
+		if f.moreBits(); f.err {
+			return
+		}
+	}
+	nlit := int(f.b&0x1F) + 257
+	f.b >>= 5
+	ndist := int(f.b&0x1F) + 1
+	f.b >>= 5
+	nclen := int(f.b&0xF) + 4
+	f.b >>= 4
+	f.nb -= 5 + 5 + 4
+
+	// (HCLEN+4)*3 bits: code lengths in the magic codeOrder order.
+	for i := 0; i < nclen; i++ {
+		for f.nb < 3 {
+			if f.moreBits(); f.err {
+				return
+			}
+		}
+		f.codebits[codeOrder[i]] = int(f.b & 0x7)
+		f.b >>= 3
+		f.nb -= 3
+	}
+	for i := nclen; i < len(codeOrder); i++ {
+		f.codebits[codeOrder[i]] = 0
+	}
+	if !f.h1.init(f.codebits[0:]) {
+		f.err = true
+		return
+	}
+
+	// HLIT + 257 code lengths, HDIST + 1 code lengths,
+	// using the code length Huffman code.
+	for i, n := 0, nlit+ndist; i < n; {
+		x := f.huffSym(&f.h1)
+		if f.err {
+			return
+		}
+		if x < 16 {
+			// Actual length.
+			f.bits[i] = x
+			i++
+			continue
+		}
+		// Repeat previous length or zero.
+		var rep int
+		var nb uint
+		var b int
+		switch x {
+		default:
+			f.err = true
+			return
+		case 16:
+			rep = 3
+			nb = 2
+			if i == 0 {
+				f.err = true
+				return
+			}
+			b = f.bits[i-1]
+		case 17:
+			rep = 3
+			nb = 3
+			b = 0
+		case 18:
+			rep = 11
+			nb = 7
+			b = 0
+		}
+		for f.nb < nb {
+			if f.moreBits(); f.err {
+				return
+			}
+		}
+		rep += int(f.b & uint32(1<<nb-1))
+		f.b >>= nb
+		f.nb -= nb
+		if i+rep > n {
+			f.err = true
+			return
+		}
+		for j := 0; j < rep; j++ {
+			f.bits[i] = b
+			i++
+		}
+	}
+
+	if !f.h1.init(f.bits[0:nlit]) || !f.h2.init(f.bits[nlit:nlit+ndist]) {
+		f.err = true
+		return
+	}
+}
+
+// Decode a single Huffman block from f.
+// hl and hd are the Huffman states for the lit/length values
+// and the distance values, respectively.  If hd == nil, using the
+// fixed distance encoding associated with fixed Huffman blocks.
+func (f *decompressor) huffmanBlock(hl, hd *huffmanDecoder) {
+	for {
+		v := f.huffSym(hl)
+		if f.err {
+			return
+		}
+		var n uint // number of bits extra
+		var length int
+		switch {
+		case v < 256:
+			f.out = append(f.out, byte(v))
+			continue
+		case v == 256:
+			// Done with huffman block; read next block.
+			return
+		// otherwise, reference to older data
+		case v < 265:
+			length = v - (257 - 3)
+			n = 0
+		case v < 269:
+			length = v*2 - (265*2 - 11)
+			n = 1
+		case v < 273:
+			length = v*4 - (269*4 - 19)
+			n = 2
+		case v < 277:
+			length = v*8 - (273*8 - 35)
+			n = 3
+		case v < 281:
+			length = v*16 - (277*16 - 67)
+			n = 4
+		case v < 285:
+			length = v*32 - (281*32 - 131)
+			n = 5
+		default:
+			length = 258
+			n = 0
+		}
+		if n > 0 {
+			for f.nb < n {
+				if f.moreBits(); f.err {
+					return
+				}
+			}
+			length += int(f.b & uint32(1<<n-1))
+			f.b >>= n
+			f.nb -= n
+		}
+
+		var dist int
+		if hd == nil {
+			for f.nb < 5 {
+				if f.moreBits(); f.err {
+					return
+				}
+			}
+			dist = int(reverseByte[(f.b&0x1F)<<3])
+			f.b >>= 5
+			f.nb -= 5
+		} else {
+			if dist = f.huffSym(hd); f.err {
+				return
+			}
+		}
+
+		switch {
+		case dist < 4:
+			dist++
+		case dist >= 30:
+			f.err = true
+			return
+		default:
+			nb := uint(dist-2) >> 1
+			// have 1 bit in bottom of dist, need nb more.
+			extra := (dist & 1) << nb
+			for f.nb < nb {
+				if f.moreBits(); f.err {
+					return
+				}
+			}
+			extra |= int(f.b & uint32(1<<nb-1))
+			f.b >>= nb
+			f.nb -= nb
+			dist = 1<<(nb+1) + 1 + extra
+		}
+
+		// Copy [-dist:-dist+length] into output.
+		// Encoding can be prescient, so no check on length.
+		if dist > len(f.out) {
+			f.err = true
+			return
+		}
+
+		p := len(f.out) - dist
+		for i := 0; i < length; i++ {
+			f.out = append(f.out, f.out[p])
+			p++
+		}
+	}
+}
+
+// Copy a single uncompressed data block from input to output.
+func (f *decompressor) dataBlock() {
+	// Uncompressed.
+	// Discard current half-byte.
+	f.nb = 0
+	f.b = 0
+
+	if len(f.in) < 4 {
+		f.err = true
+		return
+	}
+
+	buf := f.in[:4]
+	f.in = f.in[4:]
+	n := int(buf[0]) | int(buf[1])<<8
+	nn := int(buf[2]) | int(buf[3])<<8
+	if uint16(nn) != uint16(^n) {
+		f.err = true
+		return
+	}
+
+	if len(f.in) < n {
+		f.err = true
+		return
+	}
+	f.out = append(f.out, f.in[:n]...)
+	f.in = f.in[n:]
+}
+
+func (f *decompressor) moreBits() {
+	if len(f.in) == 0 {
+		f.err = true
+		return
+	}
+	c := f.in[0]
+	f.in = f.in[1:]
+	f.b |= uint32(c) << f.nb
+	f.nb += 8
+}
+
+// Read the next Huffman-encoded symbol from f according to h.
+func (f *decompressor) huffSym(h *huffmanDecoder) int {
+	for n := uint(h.min); n <= uint(h.max); n++ {
+		lim := h.limit[n]
+		if lim == -1 {
+			continue
+		}
+		for f.nb < n {
+			if f.moreBits(); f.err {
+				return 0
+			}
+		}
+		v := int(f.b & uint32(1<<n-1))
+		v <<= 16 - n
+		v = int(reverseByte[v>>8]) | int(reverseByte[v&0xFF])<<8 // reverse bits
+		if v <= lim {
+			f.b >>= n
+			f.nb -= n
+			return h.codes[v-h.base[n]]
+		}
+	}
+	f.err = true
+	return 0
+}
+
+var reverseByte = [256]byte{
+	0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
+	0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
+	0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
+	0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
+	0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
+	0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
+	0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
+	0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
+	0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
+	0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
+	0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
+	0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
+	0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
+	0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
+	0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
+	0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
+	0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
+	0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
+	0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
+	0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
+	0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
+	0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
+	0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
+	0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
+	0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
+	0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
+	0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
+	0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
+	0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
+	0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
+	0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
+	0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff,
+}
+
+// Hard-coded Huffman tables for DEFLATE algorithm.
+// See RFC 1951, section 3.2.6.
+var fixedHuffmanDecoder = huffmanDecoder{
+	7, 9,
+	[maxCodeLen + 1]int{7: 23, 199, 511},
+	[maxCodeLen + 1]int{7: 0, 24, 224},
+	[]int{
+		// length 7: 256-279
+		256, 257, 258, 259, 260, 261, 262,
+		263, 264, 265, 266, 267, 268, 269,
+		270, 271, 272, 273, 274, 275, 276,
+		277, 278, 279,
+
+		// length 8: 0-143
+		0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
+		12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
+		22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+		32, 33, 34, 35, 36, 37, 38, 39, 40, 41,
+		42, 43, 44, 45, 46, 47, 48, 49, 50, 51,
+		52, 53, 54, 55, 56, 57, 58, 59, 60, 61,
+		62, 63, 64, 65, 66, 67, 68, 69, 70, 71,
+		72, 73, 74, 75, 76, 77, 78, 79, 80, 81,
+		82, 83, 84, 85, 86, 87, 88, 89, 90, 91,
+		92, 93, 94, 95, 96, 97, 98, 99, 100,
+		101, 102, 103, 104, 105, 106, 107, 108,
+		109, 110, 111, 112, 113, 114, 115, 116,
+		117, 118, 119, 120, 121, 122, 123, 124,
+		125, 126, 127, 128, 129, 130, 131, 132,
+		133, 134, 135, 136, 137, 138, 139, 140,
+		141, 142, 143,
+
+		// length 8: 280-287
+		280, 281, 282, 283, 284, 285, 286, 287,
+
+		// length 9: 144-255
+		144, 145, 146, 147, 148, 149, 150, 151,
+		152, 153, 154, 155, 156, 157, 158, 159,
+		160, 161, 162, 163, 164, 165, 166, 167,
+		168, 169, 170, 171, 172, 173, 174, 175,
+		176, 177, 178, 179, 180, 181, 182, 183,
+		184, 185, 186, 187, 188, 189, 190, 191,
+		192, 193, 194, 195, 196, 197, 198, 199,
+		200, 201, 202, 203, 204, 205, 206, 207,
+		208, 209, 210, 211, 212, 213, 214, 215,
+		216, 217, 218, 219, 220, 221, 222, 223,
+		224, 225, 226, 227, 228, 229, 230, 231,
+		232, 233, 234, 235, 236, 237, 238, 239,
+		240, 241, 242, 243, 244, 245, 246, 247,
+		248, 249, 250, 251, 252, 253, 254, 255,
+	},
+}
+
+// Huffman decoder is based on
+// J. Brian Connell, ``A Huffman-Shannon-Fano Code,''
+// Proceedings of the IEEE, 61(7) (July 1973), pp 1046-1047.
+type huffmanDecoder struct {
+	// min, max code length
+	min, max int
+
+	// limit[i] = largest code word of length i
+	// Given code v of length n,
+	// need more bits if v > limit[n].
+	limit [maxCodeLen + 1]int
+
+	// base[i] = smallest code word of length i - seq number
+	base [maxCodeLen + 1]int
+
+	// codes[seq number] = output code.
+	// Given code v of length n, value is
+	// codes[v - base[n]].
+	codes []int
+}
+
+// Initialize Huffman decoding tables from array of code lengths.
+func (h *huffmanDecoder) init(bits []int) bool {
+	// Count number of codes of each length,
+	// compute min and max length.
+	var count [maxCodeLen + 1]int
+	var min, max int
+	for _, n := range bits {
+		if n == 0 {
+			continue
+		}
+		if min == 0 || n < min {
+			min = n
+		}
+		if n > max {
+			max = n
+		}
+		count[n]++
+	}
+	if max == 0 {
+		return false
+	}
+
+	h.min = min
+	h.max = max
+
+	// For each code range, compute
+	// nextcode (first code of that length),
+	// limit (last code of that length), and
+	// base (offset from first code to sequence number).
+	code := 0
+	seq := 0
+	var nextcode [maxCodeLen]int
+	for i := min; i <= max; i++ {
+		n := count[i]
+		nextcode[i] = code
+		h.base[i] = code - seq
+		code += n
+		seq += n
+		h.limit[i] = code - 1
+		code <<= 1
+	}
+
+	// Make array mapping sequence numbers to codes.
+	if len(h.codes) < len(bits) {
+		h.codes = make([]int, len(bits))
+	}
+	for i, n := range bits {
+		if n == 0 {
+			continue
+		}
+		code := nextcode[n]
+		nextcode[n]++
+		seq := code - h.base[n]
+		h.codes[seq] = i
+	}
+	return true
+}
+
+func inflate(in string) (out []byte) {
+	var d decompressor
+	d.in = in
+	for !d.err && !d.eof {
+		d.nextBlock()
+	}
+	if len(d.in) != 0 {
+		println("fs unzip: junk at end of compressed data")
+		return nil
+	}
+	return d.out
+}
+
+// get4 returns the little-endian 32-bit value in b.
+func zget4(b string) int {
+	if len(b) < 4 {
+		return 0
+	}
+	return int(b[0]) | int(b[1])<<8 | int(b[2])<<16 | int(b[3])<<24
+}
+
+// get2 returns the little-endian 16-bit value in b.
+func zget2(b string) int {
+	if len(b) < 2 {
+		return 0
+	}
+	return int(b[0]) | int(b[1])<<8
+}
+
+func unzip(data string) {
+	const (
+		zecheader   = 0x06054b50
+		zcheader    = 0x02014b50
+		ztailsize   = 22
+		zheadersize = 30
+		zheader     = 0x04034b50
+	)
+
+	buf := data[len(data)-ztailsize:]
+	n := zget2(buf[10:])
+	size := zget4(buf[12:])
+	off := zget4(buf[16:])
+
+	hdr := data[off : off+size]
+	for i := 0; i < n; i++ {
+		// zip entry layout:
+		//	0	magic[4]
+		//	4	madevers[1]
+		//	5	madeos[1]
+		//	6	extvers[1]
+		//	7	extos[1]
+		//	8	flags[2]
+		//	10	meth[2]
+		//	12	modtime[2]
+		//	14	moddate[2]
+		//	16	crc[4]
+		//	20	csize[4]
+		//	24	uncsize[4]
+		//	28	namelen[2]
+		//	30	xlen[2]
+		//	32	fclen[2]
+		//	34	disknum[2]
+		//	36	iattr[2]
+		//	38	eattr[4]
+		//	42	off[4]
+		//	46	name[namelen]
+		//	46+namelen+xlen+fclen - next header
+		//
+		if zget4(hdr) != zcheader {
+			println("fs unzip: bad magic")
+			break
+		}
+		meth := zget2(hdr[10:])
+		mtime := zget2(hdr[12:])
+		mdate := zget2(hdr[14:])
+		csize := zget4(hdr[20:])
+		size := zget4(hdr[24:])
+		namelen := zget2(hdr[28:])
+		xlen := zget2(hdr[30:])
+		fclen := zget2(hdr[32:])
+		xattr := uint32(zget4(hdr[38:])) >> 16
+		off := zget4(hdr[42:])
+		name := hdr[46 : 46+namelen]
+		hdr = hdr[46+namelen+xlen+fclen:]
+
+		// zip per-file header layout:
+		//	0	magic[4]
+		//	4	extvers[1]
+		//	5	extos[1]
+		//	6	flags[2]
+		//	8	meth[2]
+		//	10	modtime[2]
+		//	12	moddate[2]
+		//	14	crc[4]
+		//	18	csize[4]
+		//	22	uncsize[4]
+		//	26	namelen[2]
+		//	28	xlen[2]
+		//	30	name[namelen]
+		//	30+namelen+xlen - file data
+		//
+		buf := data[off : off+zheadersize+namelen]
+		if zget4(buf) != zheader ||
+			zget2(buf[8:]) != meth ||
+			zget2(buf[26:]) != namelen ||
+			buf[30:30+namelen] != name {
+			println("fs unzip: inconsistent zip file")
+			return
+		}
+		xlen = zget2(buf[28:])
+
+		off += zheadersize + namelen + xlen
+
+		var fdata []byte
+		switch meth {
+		case 0:
+			// buf is uncompressed
+			buf = data[off : off+size]
+			fdata = []byte(buf)
+		case 8:
+			// buf is deflate-compressed
+			buf = data[off : off+csize]
+			fdata = inflate(buf)
+			if len(fdata) != size {
+				println("fs unzip: inconsistent size in zip file")
+				return
+			}
+		}
+
+		if xattr&S_IFMT == 0 {
+			if xattr&0777 == 0 {
+				xattr |= 0666
+			}
+			if len(name) > 0 && name[len(name)-1] == '/' {
+				xattr |= S_IFDIR
+				xattr |= 0111
+			} else {
+				xattr |= S_IFREG
+			}
+		}
+
+		if err := create(name, xattr, zipToTime(mdate, mtime), fdata); err != nil {
+			print("fs unzip: create ", name, ": ", err.Error(), "\n")
+		}
+	}
+
+	chdirEnv()
+}
+
+func zipToTime(date, time int) int64 {
+	dd := date & 0x1f
+	mm := date >> 5 & 0xf
+	yy := date >> 9 // since 1980
+
+	sec := int64(315532800) // jan 1 1980
+	sec += int64(yy) * 365 * 86400
+	sec += int64(yy) / 4 * 86400
+	if yy%4 > 0 || mm >= 3 {
+		sec += 86400
+	}
+	sec += int64(daysBeforeMonth[mm]) * 86400
+	sec += int64(dd-1) * 86400
+
+	h := time >> 11
+	m := time >> 5 & 0x3F
+	s := time & 0x1f * 2
+	sec += int64(h*3600 + m*60 + s)
+
+	return sec
+}
+
+var daysBeforeMonth = [...]int32{
+	0,
+	0,
+	31,
+	31 + 28,
+	31 + 28 + 31,
+	31 + 28 + 31 + 30,
+	31 + 28 + 31 + 30 + 31,
+	31 + 28 + 31 + 30 + 31 + 30,
+	31 + 28 + 31 + 30 + 31 + 30 + 31,
+	31 + 28 + 31 + 30 + 31 + 30 + 31 + 31,
+	31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30,
+	31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31,
+	31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30,
+	31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30 + 31,
+}
diff --git a/src/pkg/syscall/zsyscall_nacl_386.go b/src/pkg/syscall/zsyscall_nacl_386.go
new file mode 100644
index 0000000000000000000000000000000000000000..32eed339af6a203049b41ef91e76eda558d81d3f
--- /dev/null
+++ b/src/pkg/syscall/zsyscall_nacl_386.go
@@ -0,0 +1,63 @@
+// mksyscall.pl -l32 -nacl syscall_nacl.go syscall_nacl_386.go
+// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
+
+package syscall
+
+import "unsafe"
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func naclClose(fd int) (err error) {
+	_, _, e1 := Syscall(sys_close, uintptr(fd), 0, 0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Exit(code int) (err error) {
+	_, _, e1 := Syscall(sys_exit, uintptr(code), 0, 0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func naclFstat(fd int, stat *Stat_t) (err error) {
+	_, _, e1 := Syscall(sys_fstat, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func naclRead(fd int, b []byte) (n int, err error) {
+	var _p0 unsafe.Pointer
+	if len(b) > 0 {
+		_p0 = unsafe.Pointer(&b[0])
+	} else {
+		_p0 = unsafe.Pointer(&_zero)
+	}
+	r0, _, e1 := Syscall(sys_read, uintptr(fd), uintptr(_p0), uintptr(len(b)))
+	n = int(r0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func naclSeek(fd int, off *int64, whence int) (err error) {
+	_, _, e1 := Syscall(sys_lseek, uintptr(fd), uintptr(unsafe.Pointer(off)), uintptr(whence))
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
diff --git a/src/pkg/syscall/zsyscall_nacl_amd64p32.go b/src/pkg/syscall/zsyscall_nacl_amd64p32.go
new file mode 100644
index 0000000000000000000000000000000000000000..8bc81fac9eea977ee3501ccfb62a526e8c491eed
--- /dev/null
+++ b/src/pkg/syscall/zsyscall_nacl_amd64p32.go
@@ -0,0 +1,63 @@
+// mksyscall.pl -nacl syscall_nacl.go syscall_nacl_amd64p32.go
+// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
+
+package syscall
+
+import "unsafe"
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func naclClose(fd int) (err error) {
+	_, _, e1 := Syscall(sys_close, uintptr(fd), 0, 0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Exit(code int) (err error) {
+	_, _, e1 := Syscall(sys_exit, uintptr(code), 0, 0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func naclFstat(fd int, stat *Stat_t) (err error) {
+	_, _, e1 := Syscall(sys_fstat, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func naclRead(fd int, b []byte) (n int, err error) {
+	var _p0 unsafe.Pointer
+	if len(b) > 0 {
+		_p0 = unsafe.Pointer(&b[0])
+	} else {
+		_p0 = unsafe.Pointer(&_zero)
+	}
+	r0, _, e1 := Syscall(sys_read, uintptr(fd), uintptr(_p0), uintptr(len(b)))
+	n = int(r0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func naclSeek(fd int, off *int64, whence int) (err error) {
+	_, _, e1 := Syscall(sys_lseek, uintptr(fd), uintptr(unsafe.Pointer(off)), uintptr(whence))
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
diff --git a/src/pkg/time/sys_unix.go b/src/pkg/time/sys_unix.go
index 36c214b6b093b99d3df23918807bd654d76eae24..379e13d6a537f7ec87ef818c9881a7212ecdb52d 100644
--- a/src/pkg/time/sys_unix.go
+++ b/src/pkg/time/sys_unix.go
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build darwin dragonfly freebsd linux netbsd openbsd solaris
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris
 
 package time
 
diff --git a/src/pkg/time/zoneinfo_unix.go b/src/pkg/time/zoneinfo_unix.go
index 26159c1aa038f5069e8363ef1f33bb2b87859842..ab7e4612e464d555954eec10ef034745cc577732 100644
--- a/src/pkg/time/zoneinfo_unix.go
+++ b/src/pkg/time/zoneinfo_unix.go
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build darwin dragonfly freebsd linux netbsd openbsd solaris
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris
 
 // Parse "zoneinfo" time zone file.
 // This is a fairly standard file format used on OS X, Linux, BSD, Sun, and others.
diff --git a/test/run.go b/test/run.go
index 9a4d794ad2fb2a7974aa07ce7f24cfa5b1f53185..c6775c01501ce150a7b9e46f5d7bcb7a5ff5ad13 100644
--- a/test/run.go
+++ b/test/run.go
@@ -45,6 +45,8 @@ var (
 
 	// letter is the build.ArchChar
 	letter string
+	
+	goos, goarch string
 
 	// dirs are the directories to look for *.go files in.
 	// TODO(bradfitz): just use all directories?
@@ -74,6 +76,10 @@ func main() {
 		*numParallel = 1
 	}
 
+	goos = os.Getenv("GOOS")
+	goarch = os.Getenv("GOARCH")
+	findExecCmd()
+
 	ratec = make(chan bool, *numParallel)
 	rungatec = make(chan bool, *runoutputLimit)
 	var err error
@@ -413,7 +419,7 @@ func (t *test) run() {
 		t.err = errors.New("double newline not found")
 		return
 	}
-	if ok, why := shouldTest(t.src, runtime.GOOS, runtime.GOARCH); !ok {
+	if ok, why := shouldTest(t.src, goos, goarch); !ok {
 		t.action = "skip"
 		if *showSkips {
 			fmt.Printf("%-20s %-20s: %s\n", t.action, t.goFileName(), why)
@@ -473,8 +479,12 @@ func (t *test) run() {
 	check(err)
 
 	// A few tests (of things like the environment) require these to be set.
-	os.Setenv("GOOS", runtime.GOOS)
-	os.Setenv("GOARCH", runtime.GOARCH)
+	if os.Getenv("GOOS") == "" {
+		os.Setenv("GOOS", runtime.GOOS)
+	}
+	if os.Getenv("GOARCH") == "" {
+		os.Setenv("GOARCH", runtime.GOARCH)
+	}
 
 	useTmp := true
 	runcmd := func(args ...string) ([]byte, error) {
@@ -589,7 +599,11 @@ func (t *test) run() {
 					t.err = err
 					return
 				}
-				out, err := runcmd(append([]string{filepath.Join(t.tempDir, "a.exe")}, args...)...)
+				var cmd []string
+				cmd = append(cmd, findExecCmd()...)
+				cmd = append(cmd, filepath.Join(t.tempDir, "a.exe"))
+				cmd = append(cmd, args...)
+				out, err := runcmd(cmd...)
 				if err != nil {
 					t.err = err
 					return
@@ -671,6 +685,23 @@ func (t *test) run() {
 	}
 }
 
+var execCmd []string
+
+func findExecCmd() []string {
+	if execCmd != nil {
+		return execCmd
+	}
+	execCmd = []string{} // avoid work the second time
+	if goos == runtime.GOOS && goarch == runtime.GOARCH {
+		return execCmd
+	}
+	path, err := exec.LookPath(fmt.Sprintf("go_%s_%s_exec", goos, goarch))
+	if err == nil {
+		execCmd = []string{path}
+	}
+	return execCmd
+}	
+
 func (t *test) String() string {
 	return filepath.Join(t.dir, t.gofile)
 }