github.com/xushiwei/go@v0.0.0-20130601165731-2b9d83f45bc9/src/cmd/dist/buildruntime.c (about) 1 // Copyright 2012 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 #include "a.h" 6 7 /* 8 * Helpers for building pkg/runtime. 9 */ 10 11 // mkzversion writes zversion.go: 12 // 13 // package runtime 14 // const defaultGoroot = <goroot> 15 // const theVersion = <version> 16 // 17 void 18 mkzversion(char *dir, char *file) 19 { 20 Buf b, out; 21 22 USED(dir); 23 24 binit(&b); 25 binit(&out); 26 27 bwritestr(&out, bprintf(&b, 28 "// auto generated by go tool dist\n" 29 "\n" 30 "package runtime\n" 31 "\n" 32 "const defaultGoroot = `%s`\n" 33 "const theVersion = `%s`\n", goroot_final, goversion)); 34 35 writefile(&out, file, 0); 36 37 bfree(&b); 38 bfree(&out); 39 } 40 41 // mkzgoarch writes zgoarch_$GOARCH.go: 42 // 43 // package runtime 44 // const theGoarch = <goarch> 45 // 46 void 47 mkzgoarch(char *dir, char *file) 48 { 49 Buf b, out; 50 51 USED(dir); 52 53 binit(&b); 54 binit(&out); 55 56 bwritestr(&out, bprintf(&b, 57 "// auto generated by go tool dist\n" 58 "\n" 59 "package runtime\n" 60 "\n" 61 "const theGoarch = `%s`\n", goarch)); 62 63 writefile(&out, file, 0); 64 65 bfree(&b); 66 bfree(&out); 67 } 68 69 // mkzgoos writes zgoos_$GOOS.go: 70 // 71 // package runtime 72 // const theGoos = <goos> 73 // 74 void 75 mkzgoos(char *dir, char *file) 76 { 77 Buf b, out; 78 79 USED(dir); 80 81 binit(&b); 82 binit(&out); 83 84 bwritestr(&out, bprintf(&b, 85 "// auto generated by go tool dist\n" 86 "\n" 87 "package runtime\n" 88 "\n" 89 "const theGoos = `%s`\n", goos)); 90 91 writefile(&out, file, 0); 92 93 bfree(&b); 94 bfree(&out); 95 } 96 97 static struct { 98 char *goarch; 99 char *goos; 100 char *hdr; 101 } zasmhdr[] = { 102 {"386", "windows", 103 "#define get_tls(r) MOVL 0x14(FS), r\n" 104 "#define g(r) 0(r)\n" 105 "#define m(r) 4(r)\n" 106 }, 107 {"386", "plan9", 108 "// Plan 9 does not have per-process segment descriptors with\n" 109 "// which to do thread-local storage. Instead, we will use a\n" 110 "// fixed offset from the per-process TOS struct address for\n" 111 "// the local storage. Since the process ID is contained in the\n" 112 "// TOS struct, we specify an offset for that here as well.\n" 113 "#define get_tls(r) MOVL _tos(SB), r \n" 114 "#define g(r) -8(r)\n" 115 "#define m(r) -4(r)\n" 116 "#define procid(r) 48(r)\n" 117 }, 118 {"386", "linux", 119 "// On Linux systems, what we call 0(GS) and 4(GS) for g and m\n" 120 "// turn into %gs:-8 and %gs:-4 (using gcc syntax to denote\n" 121 "// what the machine sees as opposed to 8l input).\n" 122 "// 8l rewrites 0(GS) and 4(GS) into these.\n" 123 "//\n" 124 "// On Linux Xen, it is not allowed to use %gs:-8 and %gs:-4\n" 125 "// directly. Instead, we have to store %gs:0 into a temporary\n" 126 "// register and then use -8(%reg) and -4(%reg). This kind\n" 127 "// of addressing is correct even when not running Xen.\n" 128 "//\n" 129 "// 8l can rewrite MOVL 0(GS), CX into the appropriate pair\n" 130 "// of mov instructions, using CX as the intermediate register\n" 131 "// (safe because CX is about to be written to anyway).\n" 132 "// But 8l cannot handle other instructions, like storing into 0(GS),\n" 133 "// which is where these macros come into play.\n" 134 "// get_tls sets up the temporary and then g and r use it.\n" 135 "//\n" 136 "// Another wrinkle is that get_tls needs to read from %gs:0,\n" 137 "// but in 8l input it's called 8(GS), because 8l is going to\n" 138 "// subtract 8 from all the offsets, as described above.\n" 139 "//\n" 140 "// The final wrinkle is that when generating an ELF .o file for\n" 141 "// external linking mode, we need to be able to relocate the\n" 142 "// -8(r) and -4(r) instructions. Tag them with an extra (GS*1)\n" 143 "// that is ignored by the linker except for that identification.\n" 144 "#define get_tls(r) MOVL 8(GS), r\n" 145 "#define g(r) -8(r)(GS*1)\n" 146 "#define m(r) -4(r)(GS*1)\n" 147 }, 148 {"386", "", 149 "#define get_tls(r)\n" 150 "#define g(r) 0(GS)\n" 151 "#define m(r) 4(GS)\n" 152 }, 153 154 {"amd64", "windows", 155 "#define get_tls(r) MOVQ 0x28(GS), r\n" 156 "#define g(r) 0(r)\n" 157 "#define m(r) 8(r)\n" 158 }, 159 {"amd64", "plan9", 160 "#define get_tls(r)\n" 161 "#define g(r) 0(GS)\n" 162 "#define m(r) 8(GS)\n" 163 "#define procid(r) 16(GS)\n" 164 }, 165 {"amd64", "", 166 "// The offsets 0 and 8 are known to:\n" 167 "// ../../cmd/6l/pass.c:/D_GS\n" 168 "// cgo/gcc_linux_amd64.c:/^threadentry\n" 169 "// cgo/gcc_darwin_amd64.c:/^threadentry\n" 170 "//\n" 171 "#define get_tls(r)\n" 172 "#define g(r) 0(GS)\n" 173 "#define m(r) 8(GS)\n" 174 }, 175 176 {"arm", "", 177 "#define g R10\n" 178 "#define m R9\n" 179 "#define LR R14\n" 180 }, 181 }; 182 183 // mkzasm writes zasm_$GOOS_$GOARCH.h, 184 // which contains struct offsets for use by 185 // assembly files. It also writes a copy to the work space 186 // under the name zasm_GOOS_GOARCH.h (no expansion). 187 // 188 void 189 mkzasm(char *dir, char *file) 190 { 191 int i, n; 192 char *aggr, *p; 193 Buf in, b, out; 194 Vec argv, lines, fields; 195 196 binit(&in); 197 binit(&b); 198 binit(&out); 199 vinit(&argv); 200 vinit(&lines); 201 vinit(&fields); 202 203 bwritestr(&out, "// auto generated by go tool dist\n\n"); 204 for(i=0; i<nelem(zasmhdr); i++) { 205 if(hasprefix(goarch, zasmhdr[i].goarch) && hasprefix(goos, zasmhdr[i].goos)) { 206 bwritestr(&out, zasmhdr[i].hdr); 207 goto ok; 208 } 209 } 210 fatal("unknown $GOOS/$GOARCH in mkzasm"); 211 ok: 212 213 // Run 6c -D GOOS_goos -D GOARCH_goarch -I workdir -a -n -o workdir/proc.acid proc.c 214 // to get acid [sic] output. 215 vreset(&argv); 216 vadd(&argv, bpathf(&b, "%s/%sc", tooldir, gochar)); 217 vadd(&argv, "-D"); 218 vadd(&argv, bprintf(&b, "GOOS_%s", goos)); 219 vadd(&argv, "-D"); 220 vadd(&argv, bprintf(&b, "GOARCH_%s", goarch)); 221 vadd(&argv, "-I"); 222 vadd(&argv, bprintf(&b, "%s", workdir)); 223 vadd(&argv, "-a"); 224 vadd(&argv, "-n"); 225 vadd(&argv, "-o"); 226 vadd(&argv, bpathf(&b, "%s/proc.acid", workdir)); 227 vadd(&argv, "proc.c"); 228 runv(nil, dir, CheckExit, &argv); 229 readfile(&in, bpathf(&b, "%s/proc.acid", workdir)); 230 231 // Convert input like 232 // aggr G 233 // { 234 // Gobuf 24 sched; 235 // 'Y' 48 stack0; 236 // } 237 // into output like 238 // #define g_sched 24 239 // #define g_stack0 48 240 // 241 aggr = nil; 242 splitlines(&lines, bstr(&in)); 243 for(i=0; i<lines.len; i++) { 244 splitfields(&fields, lines.p[i]); 245 if(fields.len == 2 && streq(fields.p[0], "aggr")) { 246 if(streq(fields.p[1], "G")) 247 aggr = "g"; 248 else if(streq(fields.p[1], "M")) 249 aggr = "m"; 250 else if(streq(fields.p[1], "Gobuf")) 251 aggr = "gobuf"; 252 else if(streq(fields.p[1], "WinCall")) 253 aggr = "wincall"; 254 else if(streq(fields.p[1], "SEH")) 255 aggr = "seh"; 256 } 257 if(hasprefix(lines.p[i], "}")) 258 aggr = nil; 259 if(aggr && hasprefix(lines.p[i], "\t") && fields.len >= 2) { 260 n = fields.len; 261 p = fields.p[n-1]; 262 if(p[xstrlen(p)-1] == ';') 263 p[xstrlen(p)-1] = '\0'; 264 bwritestr(&out, bprintf(&b, "#define %s_%s %s\n", aggr, fields.p[n-1], fields.p[n-2])); 265 } 266 } 267 268 // Write both to file and to workdir/zasm_GOOS_GOARCH.h. 269 writefile(&out, file, 0); 270 writefile(&out, bprintf(&b, "%s/zasm_GOOS_GOARCH.h", workdir), 0); 271 272 bfree(&in); 273 bfree(&b); 274 bfree(&out); 275 vfree(&argv); 276 vfree(&lines); 277 vfree(&fields); 278 } 279 280 static char *runtimedefs[] = { 281 "proc.c", 282 "iface.c", 283 "hashmap.c", 284 "chan.c", 285 "parfor.c", 286 }; 287 288 // mkzruntimedefs writes zruntime_defs_$GOOS_$GOARCH.h, 289 // which contains Go struct definitions equivalent to the C ones. 290 // Mostly we just write the output of 6c -q to the file. 291 // However, we run it on multiple files, so we have to delete 292 // the duplicated definitions, and we don't care about the funcs 293 // and consts, so we delete those too. 294 // 295 void 296 mkzruntimedefs(char *dir, char *file) 297 { 298 int i, skip; 299 char *p; 300 Buf in, b, b1, out; 301 Vec argv, lines, fields, seen; 302 303 binit(&in); 304 binit(&b); 305 binit(&b1); 306 binit(&out); 307 vinit(&argv); 308 vinit(&lines); 309 vinit(&fields); 310 vinit(&seen); 311 312 bwritestr(&out, "// auto generated by go tool dist\n" 313 "\n" 314 "package runtime\n" 315 "import \"unsafe\"\n" 316 "var _ unsafe.Pointer\n" 317 "\n" 318 ); 319 320 321 // Run 6c -D GOOS_goos -D GOARCH_goarch -I workdir -q -n -o workdir/runtimedefs 322 // on each of the runtimedefs C files. 323 vadd(&argv, bpathf(&b, "%s/%sc", tooldir, gochar)); 324 vadd(&argv, "-D"); 325 vadd(&argv, bprintf(&b, "GOOS_%s", goos)); 326 vadd(&argv, "-D"); 327 vadd(&argv, bprintf(&b, "GOARCH_%s", goarch)); 328 vadd(&argv, "-I"); 329 vadd(&argv, bprintf(&b, "%s", workdir)); 330 vadd(&argv, "-q"); 331 vadd(&argv, "-n"); 332 vadd(&argv, "-o"); 333 vadd(&argv, bpathf(&b, "%s/runtimedefs", workdir)); 334 vadd(&argv, ""); 335 p = argv.p[argv.len-1]; 336 for(i=0; i<nelem(runtimedefs); i++) { 337 argv.p[argv.len-1] = runtimedefs[i]; 338 runv(nil, dir, CheckExit, &argv); 339 readfile(&b, bpathf(&b1, "%s/runtimedefs", workdir)); 340 bwriteb(&in, &b); 341 } 342 argv.p[argv.len-1] = p; 343 344 // Process the aggregate output. 345 skip = 0; 346 splitlines(&lines, bstr(&in)); 347 for(i=0; i<lines.len; i++) { 348 p = lines.p[i]; 349 // Drop comment, func, and const lines. 350 if(hasprefix(p, "//") || hasprefix(p, "const") || hasprefix(p, "func")) 351 continue; 352 353 // Note beginning of type or var decl, which can be multiline. 354 // Remove duplicates. The linear check of seen here makes the 355 // whole processing quadratic in aggregate, but there are only 356 // about 100 declarations, so this is okay (and simple). 357 if(hasprefix(p, "type ") || hasprefix(p, "var ")) { 358 splitfields(&fields, p); 359 if(fields.len < 2) 360 continue; 361 if(find(fields.p[1], seen.p, seen.len) >= 0) { 362 if(streq(fields.p[fields.len-1], "{")) 363 skip = 1; // skip until } 364 continue; 365 } 366 vadd(&seen, fields.p[1]); 367 } 368 if(skip) { 369 if(hasprefix(p, "}")) 370 skip = 0; 371 continue; 372 } 373 374 bwritestr(&out, p); 375 } 376 377 writefile(&out, file, 0); 378 379 bfree(&in); 380 bfree(&b); 381 bfree(&b1); 382 bfree(&out); 383 vfree(&argv); 384 vfree(&lines); 385 vfree(&fields); 386 vfree(&seen); 387 }