// 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 = // const theVersion = // 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 = // 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 = // 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", "windows", "#define get_tls(r) MOVL 0x14(FS), r\n" "#define g(r) 0(r)\n" "#define m(r) 4(r)\n" }, {"386", "plan9", "// Plan 9 does not have per-process segment descriptors with\n" "// which to do thread-local storage. Instead, we will use a\n" "// fixed offset from the per-process TOS struct address for\n" "// the local storage. Since the process ID is contained in the\n" "// TOS struct, we specify an offset for that here as well.\n" "#define get_tls(r) MOVL _tos(SB), r \n" "#define g(r) -8(r)\n" "#define m(r) -4(r)\n" "#define procid(r) 48(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" "// Another 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" "//\n" "// The final wrinkle is that when generating an ELF .o file for\n" "// external linking mode, we need to be able to relocate the\n" "// -8(r) and -4(r) instructions. Tag them with an extra (GS*1)\n" "// that is ignored by the linker except for that identification.\n" "#define get_tls(r) MOVL 8(GS), r\n" "#define g(r) -8(r)(GS*1)\n" "#define m(r) -4(r)(GS*1)\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", "plan9", "#define get_tls(r)\n" "#define g(r) 0(GS)\n" "#define m(r) 8(GS)\n" "#define procid(r) 16(GS)\n" }, // The TLS accessors here are defined here to use initial exec model. // If the linker is not outputting a shared library, it will reduce // the TLS accessors to the local exec model, effectively removing // get_tls(). {"amd64", "linux", "#define get_tls(r) MOVQ runtime·tlsgm(SB), r\n" "#define g(r) 0(r)(GS*1)\n" "#define m(r) 8(r)(GS*1)\n" }, {"amd64", "", "#define get_tls(r)\n" "#define g(r) 0(GS)\n" "#define m(r) 8(GS)\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= 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.h, // 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= 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); }