github.com/varialus/godfly@v0.0.0-20130904042352-1934f9f095ab/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 // The TLS accessors here are defined here to use initial exec model. 166 // If the linker is not outputting a shared library, it will reduce 167 // the TLS accessors to the local exec model, effectively removing 168 // get_tls(). 169 {"amd64", "linux", 170 "#define get_tls(r) MOVQ runtime·tlsgm(SB), r\n" 171 "#define g(r) 0(r)(GS*1)\n" 172 "#define m(r) 8(r)(GS*1)\n" 173 }, 174 {"amd64", "", 175 "#define get_tls(r)\n" 176 "#define g(r) 0(GS)\n" 177 "#define m(r) 8(GS)\n" 178 }, 179 {"arm", "", 180 "#define LR R14\n" 181 }, 182 }; 183 184 #define MAXWINCB 2000 /* maximum number of windows callbacks allowed */ 185 186 // mkzasm writes zasm_$GOOS_$GOARCH.h, 187 // which contains struct offsets for use by 188 // assembly files. It also writes a copy to the work space 189 // under the name zasm_GOOS_GOARCH.h (no expansion). 190 // 191 void 192 mkzasm(char *dir, char *file) 193 { 194 int i, n; 195 char *aggr, *p; 196 Buf in, b, out; 197 Vec argv, lines, fields; 198 199 binit(&in); 200 binit(&b); 201 binit(&out); 202 vinit(&argv); 203 vinit(&lines); 204 vinit(&fields); 205 206 bwritestr(&out, "// auto generated by go tool dist\n\n"); 207 for(i=0; i<nelem(zasmhdr); i++) { 208 if(hasprefix(goarch, zasmhdr[i].goarch) && hasprefix(goos, zasmhdr[i].goos)) { 209 bwritestr(&out, zasmhdr[i].hdr); 210 goto ok; 211 } 212 } 213 fatal("unknown $GOOS/$GOARCH in mkzasm"); 214 ok: 215 216 // Run 6c -D GOOS_goos -D GOARCH_goarch -I workdir -a -n -o workdir/proc.acid proc.c 217 // to get acid [sic] output. 218 vreset(&argv); 219 vadd(&argv, bpathf(&b, "%s/%sc", tooldir, gochar)); 220 vadd(&argv, "-D"); 221 vadd(&argv, bprintf(&b, "GOOS_%s", goos)); 222 vadd(&argv, "-D"); 223 vadd(&argv, bprintf(&b, "GOARCH_%s", goarch)); 224 vadd(&argv, "-I"); 225 vadd(&argv, bprintf(&b, "%s", workdir)); 226 vadd(&argv, "-a"); 227 vadd(&argv, "-n"); 228 vadd(&argv, "-o"); 229 vadd(&argv, bpathf(&b, "%s/proc.acid", workdir)); 230 vadd(&argv, "proc.c"); 231 runv(nil, dir, CheckExit, &argv); 232 readfile(&in, bpathf(&b, "%s/proc.acid", workdir)); 233 234 // Convert input like 235 // aggr G 236 // { 237 // Gobuf 24 sched; 238 // 'Y' 48 stack0; 239 // } 240 // StackMin = 128; 241 // into output like 242 // #define g_sched 24 243 // #define g_stack0 48 244 // #define const_StackMin 128 245 aggr = nil; 246 splitlines(&lines, bstr(&in)); 247 for(i=0; i<lines.len; i++) { 248 splitfields(&fields, lines.p[i]); 249 if(fields.len == 2 && streq(fields.p[0], "aggr")) { 250 if(streq(fields.p[1], "G")) 251 aggr = "g"; 252 else if(streq(fields.p[1], "M")) 253 aggr = "m"; 254 else if(streq(fields.p[1], "P")) 255 aggr = "p"; 256 else if(streq(fields.p[1], "Gobuf")) 257 aggr = "gobuf"; 258 else if(streq(fields.p[1], "WinCall")) 259 aggr = "wincall"; 260 else if(streq(fields.p[1], "WinCallbackContext")) 261 aggr = "cbctxt"; 262 else if(streq(fields.p[1], "SEH")) 263 aggr = "seh"; 264 } 265 if(hasprefix(lines.p[i], "}")) 266 aggr = nil; 267 if(aggr && hasprefix(lines.p[i], "\t") && fields.len >= 2) { 268 n = fields.len; 269 p = fields.p[n-1]; 270 if(p[xstrlen(p)-1] == ';') 271 p[xstrlen(p)-1] = '\0'; 272 bwritestr(&out, bprintf(&b, "#define %s_%s %s\n", aggr, fields.p[n-1], fields.p[n-2])); 273 } 274 if(fields.len == 3 && streq(fields.p[1], "=")) { // generated from enumerated constants 275 p = fields.p[2]; 276 if(p[xstrlen(p)-1] == ';') 277 p[xstrlen(p)-1] = '\0'; 278 bwritestr(&out, bprintf(&b, "#define const_%s %s\n", fields.p[0], p)); 279 } 280 } 281 282 // Some #defines that are used for .c files. 283 if(streq(goos, "windows")) { 284 bwritestr(&out, bprintf(&b, "#define cb_max %d\n", MAXWINCB)); 285 } 286 287 // Write both to file and to workdir/zasm_GOOS_GOARCH.h. 288 writefile(&out, file, 0); 289 writefile(&out, bprintf(&b, "%s/zasm_GOOS_GOARCH.h", workdir), 0); 290 291 bfree(&in); 292 bfree(&b); 293 bfree(&out); 294 vfree(&argv); 295 vfree(&lines); 296 vfree(&fields); 297 } 298 299 // mkzsys writes zsys_$GOOS_$GOARCH.h, 300 // which contains arch or os specific asm code. 301 // 302 void 303 mkzsys(char *dir, char *file) 304 { 305 int i; 306 Buf out; 307 308 USED(dir); 309 310 binit(&out); 311 312 bwritestr(&out, "// auto generated by go tool dist\n\n"); 313 if(streq(goos, "windows")) { 314 bwritef(&out, 315 "// runtime·callbackasm is called by external code to\n" 316 "// execute Go implemented callback function. It is not\n" 317 "// called from the start, instead runtime·compilecallback\n" 318 "// always returns address into runtime·callbackasm offset\n" 319 "// appropriately so different callbacks start with different\n" 320 "// CALL instruction in runtime·callbackasm. This determines\n" 321 "// which Go callback function is executed later on.\n" 322 "TEXT runtime·callbackasm(SB),7,$0\n"); 323 for(i=0; i<MAXWINCB; i++) { 324 bwritef(&out, "\tCALL\truntime·callbackasm1(SB)\n"); 325 } 326 bwritef(&out, "\tRET\n"); 327 } 328 329 writefile(&out, file, 0); 330 331 bfree(&out); 332 } 333 334 static char *runtimedefs[] = { 335 "proc.c", 336 "iface.c", 337 "hashmap.c", 338 "chan.c", 339 "parfor.c", 340 }; 341 342 // mkzruntimedefs writes zruntime_defs_$GOOS_$GOARCH.h, 343 // which contains Go struct definitions equivalent to the C ones. 344 // Mostly we just write the output of 6c -q to the file. 345 // However, we run it on multiple files, so we have to delete 346 // the duplicated definitions, and we don't care about the funcs 347 // and consts, so we delete those too. 348 // 349 void 350 mkzruntimedefs(char *dir, char *file) 351 { 352 int i, skip; 353 char *p; 354 Buf in, b, b1, out; 355 Vec argv, lines, fields, seen; 356 357 binit(&in); 358 binit(&b); 359 binit(&b1); 360 binit(&out); 361 vinit(&argv); 362 vinit(&lines); 363 vinit(&fields); 364 vinit(&seen); 365 366 bwritestr(&out, "// auto generated by go tool dist\n" 367 "\n" 368 "package runtime\n" 369 "import \"unsafe\"\n" 370 "var _ unsafe.Pointer\n" 371 "\n" 372 ); 373 374 375 // Run 6c -D GOOS_goos -D GOARCH_goarch -I workdir -q -n -o workdir/runtimedefs 376 // on each of the runtimedefs C files. 377 vadd(&argv, bpathf(&b, "%s/%sc", tooldir, gochar)); 378 vadd(&argv, "-D"); 379 vadd(&argv, bprintf(&b, "GOOS_%s", goos)); 380 vadd(&argv, "-D"); 381 vadd(&argv, bprintf(&b, "GOARCH_%s", goarch)); 382 vadd(&argv, "-I"); 383 vadd(&argv, bprintf(&b, "%s", workdir)); 384 vadd(&argv, "-q"); 385 vadd(&argv, "-n"); 386 vadd(&argv, "-o"); 387 vadd(&argv, bpathf(&b, "%s/runtimedefs", workdir)); 388 vadd(&argv, ""); 389 p = argv.p[argv.len-1]; 390 for(i=0; i<nelem(runtimedefs); i++) { 391 argv.p[argv.len-1] = runtimedefs[i]; 392 runv(nil, dir, CheckExit, &argv); 393 readfile(&b, bpathf(&b1, "%s/runtimedefs", workdir)); 394 bwriteb(&in, &b); 395 } 396 argv.p[argv.len-1] = p; 397 398 // Process the aggregate output. 399 skip = 0; 400 splitlines(&lines, bstr(&in)); 401 for(i=0; i<lines.len; i++) { 402 p = lines.p[i]; 403 // Drop comment, func, and const lines. 404 if(hasprefix(p, "//") || hasprefix(p, "const") || hasprefix(p, "func")) 405 continue; 406 407 // Note beginning of type or var decl, which can be multiline. 408 // Remove duplicates. The linear check of seen here makes the 409 // whole processing quadratic in aggregate, but there are only 410 // about 100 declarations, so this is okay (and simple). 411 if(hasprefix(p, "type ") || hasprefix(p, "var ")) { 412 splitfields(&fields, p); 413 if(fields.len < 2) 414 continue; 415 if(find(fields.p[1], seen.p, seen.len) >= 0) { 416 if(streq(fields.p[fields.len-1], "{")) 417 skip = 1; // skip until } 418 continue; 419 } 420 vadd(&seen, fields.p[1]); 421 } 422 if(skip) { 423 if(hasprefix(p, "}")) 424 skip = 0; 425 continue; 426 } 427 428 bwritestr(&out, p); 429 } 430 431 writefile(&out, file, 0); 432 433 bfree(&in); 434 bfree(&b); 435 bfree(&b1); 436 bfree(&out); 437 vfree(&argv); 438 vfree(&lines); 439 vfree(&fields); 440 vfree(&seen); 441 }