From: Dave Cheney Date: Tue, 25 Feb 2014 14:47:42 +0000 (-0500) Subject: all: merge NaCl branch (part 1) X-Git-Tag: go1.3beta1~583 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=7c8280c9efcd24b882e441d359b6880c1a456ad8;p=gostls13.git all: merge NaCl branch (part 1) See golang.org/s/go13nacl for design overview. This CL is the mostly mechanical changes from rsc's Go 1.2 based NaCl branch, specifically 39cb35750369 to 500771b477cf from https://code.google.com/r/rsc-go13nacl. This CL does not include working NaCl support, there are probably two or three more large merges to come. CL 15750044 is not included as it involves more invasive changes to the linker which will need to be merged separately. The exact change lists included are 15050047: syscall: support for Native Client 15360044: syscall: unzip implementation for Native Client 15370044: syscall: Native Client SRPC implementation 15400047: cmd/dist, cmd/go, go/build, test: support for Native Client 15410048: runtime: support for Native Client 15410049: syscall: file descriptor table for Native Client 15410050: syscall: in-memory file system for Native Client 15440048: all: update +build lines for Native Client port 15540045: cmd/6g, cmd/8g, cmd/gc: support for Native Client 15570045: os: support for Native Client 15680044: crypto/..., hash/crc32, reflect, sync/atomic: support for amd64p32 15690044: net: support for Native Client 15690048: runtime: support for fake time like on Go Playground 15690051: build: disable various tests on Native Client LGTM=rsc R=rsc CC=golang-codereviews https://golang.org/cl/68150047 --- diff --git a/src/cmd/5g/galign.c b/src/cmd/5g/galign.c index 62f435e0e3..14d323fa7e 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 5afa25e403..e1b5d1140e 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 3ea57d7616..ec37ceb233 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 a3c5faf6c4..0bc8885cf3 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 b5c28bb089..8b0c287400 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 f4861ceecf..e8a62fb8a6 100644 --- a/src/cmd/6g/gsubr.c +++ b/src/cmd/6g/gsubr.c @@ -296,6 +296,11 @@ ginit(void) for(i=0; i= 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= 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 76c9be14fc..8fe759d79a 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 45bc4a2670..eadd1cadc2 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 f8197c895f..439e741553 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 3830f31d93..8a2fcb6772 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 b3e2665ca4..f761fa6b03 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 dff0a6e11d..e79b7188e0 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 8e9677e75b..b809640e42 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 4955231c20..1f4aed5baa 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 e5d12a8345..68ec37bee3 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 2a817f3d9a..90def10b82 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 635a30d402..c7315e0f76 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 62153cb524..1048a62cc8 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 68b2177245..88ef57f409 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 c65365f55a..9ea4a79fd3 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 068e38cf3b..717c771336 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 dcc24d99c4..6c9b9f7e50 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 8d42622b86..b6449713df 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 8faa7efa76..e86cd46523 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 26b7f87f48..2da63ef04a 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 aea81d8f83..69c33d39e6 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 0000000000..a78a3f6100 --- /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 +// 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 c4d6aaaf03..d7956a6d20 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 0fbd7eaf57..1e741fda19 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 0000000000..27d8495071 --- /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 +** 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 c582a4488b..fc71b9a6fa 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 bdf5e1db2d..1ecce1a7fb 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 0000000000..3c589d94fe --- /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 b2c68f0e8b..2331deb3a9 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 a5bd19e821..11ad3c440d 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 98ec5ea5ed..8a390762dc 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 3e7ae22a82..7421e144f1 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 f4702d0dc4..5c42b946b0 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 0000000000..e34f208677 --- /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 b5bc6d3cf0..b7e359930a 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 0cbfa9011b..1c7588e365 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 760a5c7d1e..24a460f6d9 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 28a294af96..f6d2f1b7a3 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 d949ba3f3e..1d394315a4 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 7250dcb85a..78aaa130df 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 7840d4eebb..2211e2190c 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 656b270f18..af288253e0 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 0000000000..a3701f8764 --- /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 f96dbf975d..54aeaeb198 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 e4615b74fc..09d1f4dcc0 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 214a4196c8..c674b9b320 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 31f6ee3e1c..c38fb7f765 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 1408b065d3..51a1b2c2fe 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 517bea21f3..ff6c768481 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 486c3f2b9a..d2f45060f9 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 a54578456d..b1d2f8f31a 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 0f313cc4cb..63dbce88e9 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 c9fb433ec9..93eb8659ea 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 a1beb840d5..5b803e6100 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 d7401e274d..03426ef0df 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 6c37109f5e..48fb785275 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 290596247e..a6ef874c9f 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 ef6eb85053..c0255f1644 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 1654d1b85e..921918c37f 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 0fa74718a6..c6b339fa5a 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 f38bb4f040..2aea6830b1 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 cdc669b621..19ba0fc00c 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 3727e470e6..cbae7f3c62 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 0abf3f97f6..6484bad4b4 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 89d9143b52..15d4fd9651 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 11f9621dc3..d81c253568 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 5f1503acab..83f7c3f979 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 67c390283c..d353e405e5 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 f281495e6b..f2aabbb45c 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 7b9dec7e8b..3f895d5b3b 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 8a4d019d2f..fb9d291e66 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 3c05b8f080..848a5de8f9 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 441ad5384d..b3466b15cc 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 cfe0c1c2f8..f6d76f289d 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 bdf9fe6421..0211107ddf 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 0ea8e4b1f8..3b81ed20f1 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 888823cf45..f860924aa0 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 80dc4304aa..94b8ab3ddb 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 0000000000..a503b59fa3 --- /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 9ad2f8546b..8ad5e21837 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 2be675c3af..7aba0ab5b9 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 0000000000..75413c7521 --- /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 51fdc1ecad..3b4fe2190e 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 ebdb3ff4e2..5c0a54f8c0 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 171839481b..88b68cc6df 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 0000000000..88b68cc6df --- /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 e5da01c603..b9711289f4 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 b0f2956335..2786ad70f6 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 0000000000..993d194dd5 --- /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 95c3e83151..8d91a6db2e 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 ba46b6404e..d89512d3f1 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 0000000000..47fb7bd88b --- /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 9cc5eb5a36..77ddde9d60 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 0000000000..b75753a23b --- /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 0000000000..3c5e487ad1 --- /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 0000000000..7c9d9c242f --- /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 c9887b6637..0069d5a774 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 553ea87e49..9f3f52179c 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 0000000000..c9481b5f4f --- /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 0000000000..c58593a291 --- /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 0000000000..229b585902 --- /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 f24337eac7..a450b3e584 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 0000000000..b33852ec8d --- /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 fa46d547a8..bd431be224 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 8d965c086e..ace1beb4cc 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 219163c60f..9606e16076 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 0000000000..4c602ab594 --- /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 e10effe7e6..c702158e8c 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 0000000000..7f330d3d6c --- /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 0000000000..0ff6ece3d4 --- /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 76663c6c41..ad354ed057 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 0000000000..cbc8315e44 --- /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 0000000000..ac9239483b --- /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 79a3bc889e..1bd6ccb021 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 b4ece9a542..6d35fa6892 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 0000000000..dd07373d1a --- /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 0000000000..c2788b20ab --- /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 0000000000..d12f8e2d6d --- /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 0000000000..d12f8e2d6d --- /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 0000000000..08f4ced539 --- /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 0000000000..b5a22d31b5 --- /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 0000000000..b5a22d31b5 --- /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 0000000000..5845e44f01 --- /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 + 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 + 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 + 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<>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 0000000000..32eed339af --- /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 0000000000..8bc81fac9e --- /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 36c214b6b0..379e13d6a5 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 26159c1aa0..ab7e4612e4 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 9a4d794ad2..c6775c0150 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) }