diff options
Diffstat (limited to 'src/cmd/dist/buildruntime.c')
-rw-r--r-- | src/cmd/dist/buildruntime.c | 346 |
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); +} |