summaryrefslogtreecommitdiff
path: root/src/cmd/dist/buildruntime.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/dist/buildruntime.c')
-rw-r--r--src/cmd/dist/buildruntime.c346
1 files changed, 346 insertions, 0 deletions
diff --git a/src/cmd/dist/buildruntime.c b/src/cmd/dist/buildruntime.c
new file mode 100644
index 000000000..a0c62010d
--- /dev/null
+++ b/src/cmd/dist/buildruntime.c
@@ -0,0 +1,346 @@
+// 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"
+#include <stdio.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;
+
+ 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);
+}
+
+// mkzgoarch writes zgoarch_$GOARCH.go:
+//
+// package runtime
+// const theGoarch = <goarch>
+//
+void
+mkzgoarch(char *dir, char *file)
+{
+ Buf b, out;
+
+ 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;
+
+ 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", "windows",
+ "#define get_tls(r) MOVL 0x14(FS), r\n"
+ "#define g(r) 0(r)\n"
+ "#define m(r) 4(r)\n"
+ },
+ {"386", "plan9",
+ "#define get_tls(r) MOVL _tos(SB), r \n"
+ "#define g(r) -8(r)\n"
+ "#define m(r) -4(r)\n"
+ },
+ {"386", "linux",
+ "// On Linux systems, what we call 0(GS) and 4(GS) for g and m\n"
+ "// turn into %gs:-8 and %gs:-4 (using gcc syntax to denote\n"
+ "// what the machine sees as opposed to 8l input).\n"
+ "// 8l rewrites 0(GS) and 4(GS) into these.\n"
+ "//\n"
+ "// On Linux Xen, it is not allowed to use %gs:-8 and %gs:-4\n"
+ "// directly. Instead, we have to store %gs:0 into a temporary\n"
+ "// register and then use -8(%reg) and -4(%reg). This kind\n"
+ "// of addressing is correct even when not running Xen.\n"
+ "//\n"
+ "// 8l can rewrite MOVL 0(GS), CX into the appropriate pair\n"
+ "// of mov instructions, using CX as the intermediate register\n"
+ "// (safe because CX is about to be written to anyway).\n"
+ "// But 8l cannot handle other instructions, like storing into 0(GS),\n"
+ "// which is where these macros come into play.\n"
+ "// get_tls sets up the temporary and then g and r use it.\n"
+ "//\n"
+ "// The final wrinkle is that get_tls needs to read from %gs:0,\n"
+ "// but in 8l input it's called 8(GS), because 8l is going to\n"
+ "// subtract 8 from all the offsets, as described above.\n"
+ "#define get_tls(r) MOVL 8(GS), r\n"
+ "#define g(r) -8(r)\n"
+ "#define m(r) -4(r)\n"
+ },
+ {"386", "",
+ "#define get_tls(r)\n"
+ "#define g(r) 0(GS)\n"
+ "#define m(r) 4(GS)\n"
+ },
+
+ {"amd64", "windows",
+ "#define get_tls(r) MOVQ 0x28(GS), r\n"
+ "#define g(r) 0(r)\n"
+ "#define m(r) 8(r)\n"
+ },
+ {"amd64", "",
+ "// The offsets 0 and 8 are known to:\n"
+ "// ../../cmd/6l/pass.c:/D_GS\n"
+ "// cgo/gcc_linux_amd64.c:/^threadentry\n"
+ "// cgo/gcc_darwin_amd64.c:/^threadentry\n"
+ "//\n"
+ "#define get_tls(r)\n"
+ "#define g(r) 0(GS)\n"
+ "#define m(r) 8(GS)\n"
+ },
+
+ {"arm", "",
+ "#define g R10\n"
+ "#define m R9\n"
+ "#define LR R14\n"
+ },
+};
+
+// 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;
+ Vec argv, lines, fields;
+
+ binit(&in);
+ binit(&b);
+ binit(&out);
+ 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 -DGOOS_goos -DGOARCH_goarch -Iworkdir -a proc.c
+ // to get acid [sic] output.
+ vreset(&argv);
+ vadd(&argv, bpathf(&b, "%s/%sc", tooldir, gochar));
+ vadd(&argv, bprintf(&b, "-DGOOS_%s", goos));
+ vadd(&argv, bprintf(&b, "-DGOARCH_%s", goarch));
+ vadd(&argv, bprintf(&b, "-I%s", workdir));
+ vadd(&argv, "-a");
+ vadd(&argv, "proc.c");
+ runv(&in, dir, CheckExit, &argv);
+
+ // Convert input like
+ // aggr G
+ // {
+ // Gobuf 24 sched;
+ // 'Y' 48 stack0;
+ // }
+ // into output like
+ // #define g_sched 24
+ // #define g_stack0 48
+ //
+ 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], "Gobuf"))
+ aggr = "gobuf";
+ else if(streq(fields.p[1], "WinCall"))
+ aggr = "wincall";
+ }
+ 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]));
+ }
+ }
+
+ // 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);
+ vfree(&argv);
+ vfree(&lines);
+ vfree(&fields);
+}
+
+static char *runtimedefs[] = {
+ "proc.c",
+ "iface.c",
+ "hashmap.c",
+ "chan.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, out;
+ Vec argv, lines, fields, seen;
+
+ binit(&in);
+ binit(&b);
+ 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 -DGOOS_goos -DGOARCH_goarch -Iworkdir -q
+ // on each of the runtimedefs C files.
+ vadd(&argv, bpathf(&b, "%s/%sc", tooldir, gochar));
+ vadd(&argv, bprintf(&b, "-DGOOS_%s", goos));
+ vadd(&argv, bprintf(&b, "-DGOARCH_%s", goarch));
+ vadd(&argv, bprintf(&b, "-I%s", workdir));
+ vadd(&argv, "-q");
+ vadd(&argv, "");
+ p = argv.p[argv.len-1];
+ for(i=0; i<nelem(runtimedefs); i++) {
+ argv.p[argv.len-1] = runtimedefs[i];
+ runv(&b, dir, CheckExit, &argv);
+ 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(&out);
+ vfree(&argv);
+ vfree(&lines);
+ vfree(&fields);
+ vfree(&seen);
+}