| // 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 "a.h" | |
| /* | |
| * Helpers for building pkg/runtime. | |
| */ | |
| // mkzversion writes zversion.go: | |
| // | |
| // package runtime | |
| // const defaultGoroot = <goroot> | |
| // const theVersion = <version> | |
| // | |
| void | |
| mkzversion(char *dir, char *file) | |
| { | |
| Buf b, out; | |
| USED(dir); | |
| binit(&b); | |
| binit(&out); | |
| bwritestr(&out, bprintf(&b, | |
| "// auto generated by go tool dist\n" | |
| "\n" | |
| "package runtime\n" | |
| "\n" | |
| "const defaultGoroot = `%s`\n" | |
| "const theVersion = `%s`\n", goroot_final, goversion)); | |
| writefile(&out, file, 0); | |
| bfree(&b); | |
| bfree(&out); | |
| } | |
| // mkzexperiment writes zaexperiment.h (sic): | |
| // | |
| // #define GOEXPERIMENT "experiment string" | |
| // | |
| void | |
| mkzexperiment(char *dir, char *file) | |
| { | |
| Buf b, out, exp; | |
| USED(dir); | |
| binit(&b); | |
| binit(&out); | |
| binit(&exp); | |
| xgetenv(&exp, "GOEXPERIMENT"); | |
| bwritestr(&out, bprintf(&b, | |
| "// auto generated by go tool dist\n" | |
| "\n" | |
| "#define GOEXPERIMENT \"%s\"\n", bstr(&exp))); | |
| writefile(&out, file, 0); | |
| bfree(&b); | |
| bfree(&out); | |
| bfree(&exp); | |
| } | |
| // mkzgoarch writes zgoarch_$GOARCH.go: | |
| // | |
| // package runtime | |
| // const theGoarch = <goarch> | |
| // | |
| void | |
| mkzgoarch(char *dir, char *file) | |
| { | |
| Buf b, out; | |
| USED(dir); | |
| binit(&b); | |
| binit(&out); | |
| bwritestr(&out, bprintf(&b, | |
| "// auto generated by go tool dist\n" | |
| "\n" | |
| "package runtime\n" | |
| "\n" | |
| "const theGoarch = `%s`\n", goarch)); | |
| writefile(&out, file, 0); | |
| bfree(&b); | |
| bfree(&out); | |
| } | |
| // mkzgoos writes zgoos_$GOOS.go: | |
| // | |
| // package runtime | |
| // const theGoos = <goos> | |
| // | |
| void | |
| mkzgoos(char *dir, char *file) | |
| { | |
| Buf b, out; | |
| USED(dir); | |
| binit(&b); | |
| binit(&out); | |
| bwritestr(&out, bprintf(&b, | |
| "// auto generated by go tool dist\n" | |
| "\n" | |
| "package runtime\n" | |
| "\n" | |
| "const theGoos = `%s`\n", goos)); | |
| writefile(&out, file, 0); | |
| bfree(&b); | |
| bfree(&out); | |
| } | |
| static struct { | |
| char *goarch; | |
| char *goos; | |
| char *hdr; | |
| } zasmhdr[] = { | |
| {"386", "", | |
| "#define get_tls(r) MOVL TLS, r\n" | |
| "#define g(r) 0(r)(TLS*1)\n" | |
| "#define m(r) 4(r)(TLS*1)\n" | |
| }, | |
| {"amd64p32", "", | |
| "#define get_tls(r) MOVL TLS, r\n" | |
| "#define g(r) 0(r)(TLS*1)\n" | |
| "#define m(r) 4(r)(TLS*1)\n" | |
| }, | |
| {"amd64", "", | |
| "#define get_tls(r) MOVQ TLS, r\n" | |
| "#define g(r) 0(r)(TLS*1)\n" | |
| "#define m(r) 8(r)(TLS*1)\n" | |
| }, | |
| {"arm", "", | |
| "#define LR R14\n" | |
| }, | |
| }; | |
| #define MAXWINCB 2000 /* maximum number of windows callbacks allowed */ | |
| // mkzasm writes zasm_$GOOS_$GOARCH.h, | |
| // which contains struct offsets for use by | |
| // assembly files. It also writes a copy to the work space | |
| // under the name zasm_GOOS_GOARCH.h (no expansion). | |
| // | |
| void | |
| mkzasm(char *dir, char *file) | |
| { | |
| int i, n; | |
| char *aggr, *p; | |
| Buf in, b, out, exp; | |
| Vec argv, lines, fields; | |
| binit(&in); | |
| binit(&b); | |
| binit(&out); | |
| binit(&exp); | |
| vinit(&argv); | |
| vinit(&lines); | |
| vinit(&fields); | |
| bwritestr(&out, "// auto generated by go tool dist\n\n"); | |
| for(i=0; i<nelem(zasmhdr); i++) { | |
| if(hasprefix(goarch, zasmhdr[i].goarch) && hasprefix(goos, zasmhdr[i].goos)) { | |
| bwritestr(&out, zasmhdr[i].hdr); | |
| goto ok; | |
| } | |
| } | |
| fatal("unknown $GOOS/$GOARCH in mkzasm"); | |
| ok: | |
| // Run 6c -D GOOS_goos -D GOARCH_goarch -I workdir -a -n -o workdir/proc.acid proc.c | |
| // to get acid [sic] output. Run once without the -a -o workdir/proc.acid in order to | |
| // report compilation failures (the -o redirects all messages, unfortunately). | |
| vreset(&argv); | |
| vadd(&argv, bpathf(&b, "%s/%sc", tooldir, gochar)); | |
| vadd(&argv, "-D"); | |
| vadd(&argv, bprintf(&b, "GOOS_%s", goos)); | |
| vadd(&argv, "-D"); | |
| vadd(&argv, bprintf(&b, "GOARCH_%s", goarch)); | |
| vadd(&argv, "-I"); | |
| vadd(&argv, bprintf(&b, "%s", workdir)); | |
| vadd(&argv, "-n"); | |
| vadd(&argv, "-a"); | |
| vadd(&argv, "-o"); | |
| vadd(&argv, bpathf(&b, "%s/proc.acid", workdir)); | |
| vadd(&argv, "proc.c"); | |
| runv(nil, dir, CheckExit, &argv); | |
| readfile(&in, bpathf(&b, "%s/proc.acid", workdir)); | |
| // Convert input like | |
| // aggr G | |
| // { | |
| // Gobuf 24 sched; | |
| // 'Y' 48 stack0; | |
| // } | |
| // StackMin = 128; | |
| // into output like | |
| // #define g_sched 24 | |
| // #define g_stack0 48 | |
| // #define const_StackMin 128 | |
| aggr = nil; | |
| splitlines(&lines, bstr(&in)); | |
| for(i=0; i<lines.len; i++) { | |
| splitfields(&fields, lines.p[i]); | |
| if(fields.len == 2 && streq(fields.p[0], "aggr")) { | |
| if(streq(fields.p[1], "G")) | |
| aggr = "g"; | |
| else if(streq(fields.p[1], "M")) | |
| aggr = "m"; | |
| else if(streq(fields.p[1], "P")) | |
| aggr = "p"; | |
| else if(streq(fields.p[1], "Gobuf")) | |
| aggr = "gobuf"; | |
| else if(streq(fields.p[1], "LibCall")) | |
| aggr = "libcall"; | |
| else if(streq(fields.p[1], "WinCallbackContext")) | |
| aggr = "cbctxt"; | |
| else if(streq(fields.p[1], "SEH")) | |
| aggr = "seh"; | |
| } | |
| if(hasprefix(lines.p[i], "}")) | |
| aggr = nil; | |
| if(aggr && hasprefix(lines.p[i], "\t") && fields.len >= 2) { | |
| n = fields.len; | |
| p = fields.p[n-1]; | |
| if(p[xstrlen(p)-1] == ';') | |
| p[xstrlen(p)-1] = '\0'; | |
| bwritestr(&out, bprintf(&b, "#define %s_%s %s\n", aggr, fields.p[n-1], fields.p[n-2])); | |
| } | |
| if(fields.len == 3 && streq(fields.p[1], "=")) { // generated from enumerated constants | |
| p = fields.p[2]; | |
| if(p[xstrlen(p)-1] == ';') | |
| p[xstrlen(p)-1] = '\0'; | |
| bwritestr(&out, bprintf(&b, "#define const_%s %s\n", fields.p[0], p)); | |
| } | |
| } | |
| // Some #defines that are used for .c files. | |
| if(streq(goos, "windows")) { | |
| bwritestr(&out, bprintf(&b, "#define cb_max %d\n", MAXWINCB)); | |
| } | |
| xgetenv(&exp, "GOEXPERIMENT"); | |
| bwritestr(&out, bprintf(&b, "#define GOEXPERIMENT \"%s\"\n", bstr(&exp))); | |
| // Write both to file and to workdir/zasm_GOOS_GOARCH.h. | |
| writefile(&out, file, 0); | |
| writefile(&out, bprintf(&b, "%s/zasm_GOOS_GOARCH.h", workdir), 0); | |
| bfree(&in); | |
| bfree(&b); | |
| bfree(&out); | |
| bfree(&exp); | |
| vfree(&argv); | |
| vfree(&lines); | |
| vfree(&fields); | |
| } | |
| // mkzsys writes zsys_$GOOS_$GOARCH.s, | |
| // which contains arch or os specific asm code. | |
| // | |
| void | |
| mkzsys(char *dir, char *file) | |
| { | |
| int i; | |
| Buf out; | |
| USED(dir); | |
| binit(&out); | |
| bwritestr(&out, "// auto generated by go tool dist\n\n"); | |
| if(streq(goos, "windows")) { | |
| bwritef(&out, | |
| "// runtime·callbackasm is called by external code to\n" | |
| "// execute Go implemented callback function. It is not\n" | |
| "// called from the start, instead runtime·compilecallback\n" | |
| "// always returns address into runtime·callbackasm offset\n" | |
| "// appropriately so different callbacks start with different\n" | |
| "// CALL instruction in runtime·callbackasm. This determines\n" | |
| "// which Go callback function is executed later on.\n" | |
| "TEXT runtime·callbackasm(SB),7,$0\n"); | |
| for(i=0; i<MAXWINCB; i++) { | |
| bwritef(&out, "\tCALL\truntime·callbackasm1(SB)\n"); | |
| } | |
| bwritef(&out, "\tRET\n"); | |
| } | |
| writefile(&out, file, 0); | |
| bfree(&out); | |
| } | |
| static char *runtimedefs[] = { | |
| "defs.c", | |
| "proc.c", | |
| "parfor.c", | |
| }; | |
| // mkzruntimedefs writes zruntime_defs_$GOOS_$GOARCH.h, | |
| // which contains Go struct definitions equivalent to the C ones. | |
| // Mostly we just write the output of 6c -q to the file. | |
| // However, we run it on multiple files, so we have to delete | |
| // the duplicated definitions, and we don't care about the funcs | |
| // and consts, so we delete those too. | |
| // | |
| void | |
| mkzruntimedefs(char *dir, char *file) | |
| { | |
| int i, skip; | |
| char *p; | |
| Buf in, b, b1, out; | |
| Vec argv, lines, fields, seen; | |
| binit(&in); | |
| binit(&b); | |
| binit(&b1); | |
| binit(&out); | |
| vinit(&argv); | |
| vinit(&lines); | |
| vinit(&fields); | |
| vinit(&seen); | |
| bwritestr(&out, "// auto generated by go tool dist\n" | |
| "\n" | |
| "package runtime\n" | |
| "import \"unsafe\"\n" | |
| "var _ unsafe.Pointer\n" | |
| "\n" | |
| ); | |
| // Run 6c -D GOOS_goos -D GOARCH_goarch -I workdir -q -n -o workdir/runtimedefs | |
| // on each of the runtimedefs C files. | |
| vadd(&argv, bpathf(&b, "%s/%sc", tooldir, gochar)); | |
| vadd(&argv, "-D"); | |
| vadd(&argv, bprintf(&b, "GOOS_%s", goos)); | |
| vadd(&argv, "-D"); | |
| vadd(&argv, bprintf(&b, "GOARCH_%s", goarch)); | |
| vadd(&argv, "-I"); | |
| vadd(&argv, bprintf(&b, "%s", workdir)); | |
| vadd(&argv, "-q"); | |
| vadd(&argv, "-n"); | |
| vadd(&argv, "-o"); | |
| vadd(&argv, bpathf(&b, "%s/runtimedefs", workdir)); | |
| vadd(&argv, ""); | |
| p = argv.p[argv.len-1]; | |
| for(i=0; i<nelem(runtimedefs); i++) { | |
| argv.p[argv.len-1] = runtimedefs[i]; | |
| runv(nil, dir, CheckExit, &argv); | |
| readfile(&b, bpathf(&b1, "%s/runtimedefs", workdir)); | |
| bwriteb(&in, &b); | |
| } | |
| argv.p[argv.len-1] = p; | |
| // Process the aggregate output. | |
| skip = 0; | |
| splitlines(&lines, bstr(&in)); | |
| for(i=0; i<lines.len; i++) { | |
| p = lines.p[i]; | |
| // Drop comment, func, and const lines. | |
| if(hasprefix(p, "//") || hasprefix(p, "const") || hasprefix(p, "func")) | |
| continue; | |
| // Note beginning of type or var decl, which can be multiline. | |
| // Remove duplicates. The linear check of seen here makes the | |
| // whole processing quadratic in aggregate, but there are only | |
| // about 100 declarations, so this is okay (and simple). | |
| if(hasprefix(p, "type ") || hasprefix(p, "var ")) { | |
| splitfields(&fields, p); | |
| if(fields.len < 2) | |
| continue; | |
| if(find(fields.p[1], seen.p, seen.len) >= 0) { | |
| if(streq(fields.p[fields.len-1], "{")) | |
| skip = 1; // skip until } | |
| continue; | |
| } | |
| vadd(&seen, fields.p[1]); | |
| } | |
| if(skip) { | |
| if(hasprefix(p, "}")) | |
| skip = 0; | |
| continue; | |
| } | |
| bwritestr(&out, p); | |
| } | |
| writefile(&out, file, 0); | |
| bfree(&in); | |
| bfree(&b); | |
| bfree(&b1); | |
| bfree(&out); | |
| vfree(&argv); | |
| vfree(&lines); | |
| vfree(&fields); | |
| vfree(&seen); | |
| } |