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(®, 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(®, types[TINT64], D_CX); + nodconst(&r1, types[TINT64], 32); + gins(ASHLQ, &r1, ®); + gins(AORQ, &con, ®); + gins(APUSHQ, ®, N); } else { - gins(APUSHQ, f, N); + nodreg(®, types[TINT64], D_CX); + gmove(f, ®); + gins(APUSHQ, ®, 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(®, types[TINT64], D_CX); gins(APOPQ, N, ®); - gins(APOPQ, N, ®); + if(widthptr == 8) + gins(APOPQ, N, ®); if(proc == 2) { nodreg(®, types[TINT64], D_AX); gins(ATESTQ, ®, ®); @@ -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) }