github.com/rohankumardubey/syslog-redirector-golang@v0.0.0-20140320174030-4859f03d829a/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 // mkzexperiment writes zaexperiment.h (sic): 42 // 43 // #define GOEXPERIMENT "experiment string" 44 // 45 void 46 mkzexperiment(char *dir, char *file) 47 { 48 Buf b, out, exp; 49 50 USED(dir); 51 52 binit(&b); 53 binit(&out); 54 binit(&exp); 55 56 xgetenv(&exp, "GOEXPERIMENT"); 57 bwritestr(&out, bprintf(&b, 58 "// auto generated by go tool dist\n" 59 "\n" 60 "#define GOEXPERIMENT \"%s\"\n", bstr(&exp))); 61 62 writefile(&out, file, 0); 63 64 bfree(&b); 65 bfree(&out); 66 bfree(&exp); 67 } 68 69 // mkzgoarch writes zgoarch_$GOARCH.go: 70 // 71 // package runtime 72 // const theGoarch = <goarch> 73 // 74 void 75 mkzgoarch(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 theGoarch = `%s`\n", goarch)); 90 91 writefile(&out, file, 0); 92 93 bfree(&b); 94 bfree(&out); 95 } 96 97 // mkzgoos writes zgoos_$GOOS.go: 98 // 99 // package runtime 100 // const theGoos = <goos> 101 // 102 void 103 mkzgoos(char *dir, char *file) 104 { 105 Buf b, out; 106 107 USED(dir); 108 109 binit(&b); 110 binit(&out); 111 112 bwritestr(&out, bprintf(&b, 113 "// auto generated by go tool dist\n" 114 "\n" 115 "package runtime\n" 116 "\n" 117 "const theGoos = `%s`\n", goos)); 118 119 writefile(&out, file, 0); 120 121 bfree(&b); 122 bfree(&out); 123 } 124 125 static struct { 126 char *goarch; 127 char *goos; 128 char *hdr; 129 } zasmhdr[] = { 130 {"386", "windows", 131 "#define get_tls(r) MOVL 0x14(FS), r\n" 132 "#define g(r) 0(r)\n" 133 "#define m(r) 4(r)\n" 134 }, 135 {"386", "plan9", 136 "// Plan 9 does not have per-process segment descriptors with\n" 137 "// which to do thread-local storage. Instead, we will use a\n" 138 "// fixed offset from the per-process TOS struct address for\n" 139 "// the local storage. Since the process ID is contained in the\n" 140 "// TOS struct, we specify an offset for that here as well.\n" 141 "#define get_tls(r) MOVL _tos(SB), r \n" 142 "#define g(r) -8(r)\n" 143 "#define m(r) -4(r)\n" 144 "#define procid(r) 48(r)\n" 145 }, 146 {"386", "linux", 147 "// On Linux systems, what we call 0(GS) and 4(GS) for g and m\n" 148 "// turn into %gs:-8 and %gs:-4 (using gcc syntax to denote\n" 149 "// what the machine sees as opposed to 8l input).\n" 150 "// 8l rewrites 0(GS) and 4(GS) into these.\n" 151 "//\n" 152 "// On Linux Xen, it is not allowed to use %gs:-8 and %gs:-4\n" 153 "// directly. Instead, we have to store %gs:0 into a temporary\n" 154 "// register and then use -8(%reg) and -4(%reg). This kind\n" 155 "// of addressing is correct even when not running Xen.\n" 156 "//\n" 157 "// 8l can rewrite MOVL 0(GS), CX into the appropriate pair\n" 158 "// of mov instructions, using CX as the intermediate register\n" 159 "// (safe because CX is about to be written to anyway).\n" 160 "// But 8l cannot handle other instructions, like storing into 0(GS),\n" 161 "// which is where these macros come into play.\n" 162 "// get_tls sets up the temporary and then g and r use it.\n" 163 "//\n" 164 "// Another wrinkle is that get_tls needs to read from %gs:0,\n" 165 "// but in 8l input it's called 8(GS), because 8l is going to\n" 166 "// subtract 8 from all the offsets, as described above.\n" 167 "//\n" 168 "// The final wrinkle is that when generating an ELF .o file for\n" 169 "// external linking mode, we need to be able to relocate the\n" 170 "// -8(r) and -4(r) instructions. Tag them with an extra (GS*1)\n" 171 "// that is ignored by the linker except for that identification.\n" 172 "#define get_tls(r) MOVL 8(GS), r\n" 173 "#define g(r) -8(r)(GS*1)\n" 174 "#define m(r) -4(r)(GS*1)\n" 175 }, 176 {"386", "", 177 "#define get_tls(r)\n" 178 "#define g(r) 0(GS)\n" 179 "#define m(r) 4(GS)\n" 180 }, 181 182 {"amd64", "windows", 183 "#define get_tls(r) MOVQ 0x28(GS), r\n" 184 "#define g(r) 0(r)\n" 185 "#define m(r) 8(r)\n" 186 }, 187 {"amd64", "plan9", 188 "#define get_tls(r)\n" 189 "#define g(r) 0(GS)\n" 190 "#define m(r) 8(GS)\n" 191 "#define procid(r) 16(GS)\n" 192 }, 193 // The TLS accessors here are defined here to use initial exec model. 194 // If the linker is not outputting a shared library, it will reduce 195 // the TLS accessors to the local exec model, effectively removing 196 // get_tls(). 197 {"amd64", "linux", 198 "#define get_tls(r) MOVQ runtime·tlsgm(SB), r\n" 199 "#define g(r) 0(r)(GS*1)\n" 200 "#define m(r) 8(r)(GS*1)\n" 201 }, 202 {"amd64", "", 203 "#define get_tls(r)\n" 204 "#define g(r) 0(GS)\n" 205 "#define m(r) 8(GS)\n" 206 }, 207 {"arm", "", 208 "#define LR R14\n" 209 }, 210 }; 211 212 #define MAXWINCB 2000 /* maximum number of windows callbacks allowed */ 213 214 // mkzasm writes zasm_$GOOS_$GOARCH.h, 215 // which contains struct offsets for use by 216 // assembly files. It also writes a copy to the work space 217 // under the name zasm_GOOS_GOARCH.h (no expansion). 218 // 219 void 220 mkzasm(char *dir, char *file) 221 { 222 int i, n; 223 char *aggr, *p; 224 Buf in, b, out, exp; 225 Vec argv, lines, fields; 226 227 binit(&in); 228 binit(&b); 229 binit(&out); 230 binit(&exp); 231 vinit(&argv); 232 vinit(&lines); 233 vinit(&fields); 234 235 bwritestr(&out, "// auto generated by go tool dist\n\n"); 236 for(i=0; i<nelem(zasmhdr); i++) { 237 if(hasprefix(goarch, zasmhdr[i].goarch) && hasprefix(goos, zasmhdr[i].goos)) { 238 bwritestr(&out, zasmhdr[i].hdr); 239 goto ok; 240 } 241 } 242 fatal("unknown $GOOS/$GOARCH in mkzasm"); 243 ok: 244 245 // Run 6c -D GOOS_goos -D GOARCH_goarch -I workdir -a -n -o workdir/proc.acid proc.c 246 // to get acid [sic] output. 247 vreset(&argv); 248 vadd(&argv, bpathf(&b, "%s/%sc", tooldir, gochar)); 249 vadd(&argv, "-D"); 250 vadd(&argv, bprintf(&b, "GOOS_%s", goos)); 251 vadd(&argv, "-D"); 252 vadd(&argv, bprintf(&b, "GOARCH_%s", goarch)); 253 vadd(&argv, "-I"); 254 vadd(&argv, bprintf(&b, "%s", workdir)); 255 vadd(&argv, "-a"); 256 vadd(&argv, "-n"); 257 vadd(&argv, "-o"); 258 vadd(&argv, bpathf(&b, "%s/proc.acid", workdir)); 259 vadd(&argv, "proc.c"); 260 runv(nil, dir, CheckExit, &argv); 261 readfile(&in, bpathf(&b, "%s/proc.acid", workdir)); 262 263 // Convert input like 264 // aggr G 265 // { 266 // Gobuf 24 sched; 267 // 'Y' 48 stack0; 268 // } 269 // StackMin = 128; 270 // into output like 271 // #define g_sched 24 272 // #define g_stack0 48 273 // #define const_StackMin 128 274 aggr = nil; 275 splitlines(&lines, bstr(&in)); 276 for(i=0; i<lines.len; i++) { 277 splitfields(&fields, lines.p[i]); 278 if(fields.len == 2 && streq(fields.p[0], "aggr")) { 279 if(streq(fields.p[1], "G")) 280 aggr = "g"; 281 else if(streq(fields.p[1], "M")) 282 aggr = "m"; 283 else if(streq(fields.p[1], "P")) 284 aggr = "p"; 285 else if(streq(fields.p[1], "Gobuf")) 286 aggr = "gobuf"; 287 else if(streq(fields.p[1], "WinCall")) 288 aggr = "wincall"; 289 else if(streq(fields.p[1], "WinCallbackContext")) 290 aggr = "cbctxt"; 291 else if(streq(fields.p[1], "SEH")) 292 aggr = "seh"; 293 } 294 if(hasprefix(lines.p[i], "}")) 295 aggr = nil; 296 if(aggr && hasprefix(lines.p[i], "\t") && fields.len >= 2) { 297 n = fields.len; 298 p = fields.p[n-1]; 299 if(p[xstrlen(p)-1] == ';') 300 p[xstrlen(p)-1] = '\0'; 301 bwritestr(&out, bprintf(&b, "#define %s_%s %s\n", aggr, fields.p[n-1], fields.p[n-2])); 302 } 303 if(fields.len == 3 && streq(fields.p[1], "=")) { // generated from enumerated constants 304 p = fields.p[2]; 305 if(p[xstrlen(p)-1] == ';') 306 p[xstrlen(p)-1] = '\0'; 307 bwritestr(&out, bprintf(&b, "#define const_%s %s\n", fields.p[0], p)); 308 } 309 } 310 311 // Some #defines that are used for .c files. 312 if(streq(goos, "windows")) { 313 bwritestr(&out, bprintf(&b, "#define cb_max %d\n", MAXWINCB)); 314 } 315 316 xgetenv(&exp, "GOEXPERIMENT"); 317 bwritestr(&out, bprintf(&b, "#define GOEXPERIMENT \"%s\"\n", bstr(&exp))); 318 319 // Write both to file and to workdir/zasm_GOOS_GOARCH.h. 320 writefile(&out, file, 0); 321 writefile(&out, bprintf(&b, "%s/zasm_GOOS_GOARCH.h", workdir), 0); 322 323 bfree(&in); 324 bfree(&b); 325 bfree(&out); 326 bfree(&exp); 327 vfree(&argv); 328 vfree(&lines); 329 vfree(&fields); 330 } 331 332 // mkzsys writes zsys_$GOOS_$GOARCH.h, 333 // which contains arch or os specific asm code. 334 // 335 void 336 mkzsys(char *dir, char *file) 337 { 338 int i; 339 Buf out; 340 341 USED(dir); 342 343 binit(&out); 344 345 bwritestr(&out, "// auto generated by go tool dist\n\n"); 346 if(streq(goos, "windows")) { 347 bwritef(&out, 348 "// runtime·callbackasm is called by external code to\n" 349 "// execute Go implemented callback function. It is not\n" 350 "// called from the start, instead runtime·compilecallback\n" 351 "// always returns address into runtime·callbackasm offset\n" 352 "// appropriately so different callbacks start with different\n" 353 "// CALL instruction in runtime·callbackasm. This determines\n" 354 "// which Go callback function is executed later on.\n" 355 "TEXT runtime·callbackasm(SB),7,$0\n"); 356 for(i=0; i<MAXWINCB; i++) { 357 bwritef(&out, "\tCALL\truntime·callbackasm1(SB)\n"); 358 } 359 bwritef(&out, "\tRET\n"); 360 } 361 362 writefile(&out, file, 0); 363 364 bfree(&out); 365 } 366 367 static char *runtimedefs[] = { 368 "proc.c", 369 "iface.c", 370 "hashmap.c", 371 "chan.c", 372 "parfor.c", 373 }; 374 375 // mkzruntimedefs writes zruntime_defs_$GOOS_$GOARCH.h, 376 // which contains Go struct definitions equivalent to the C ones. 377 // Mostly we just write the output of 6c -q to the file. 378 // However, we run it on multiple files, so we have to delete 379 // the duplicated definitions, and we don't care about the funcs 380 // and consts, so we delete those too. 381 // 382 void 383 mkzruntimedefs(char *dir, char *file) 384 { 385 int i, skip; 386 char *p; 387 Buf in, b, b1, out; 388 Vec argv, lines, fields, seen; 389 390 binit(&in); 391 binit(&b); 392 binit(&b1); 393 binit(&out); 394 vinit(&argv); 395 vinit(&lines); 396 vinit(&fields); 397 vinit(&seen); 398 399 bwritestr(&out, "// auto generated by go tool dist\n" 400 "\n" 401 "package runtime\n" 402 "import \"unsafe\"\n" 403 "var _ unsafe.Pointer\n" 404 "\n" 405 ); 406 407 408 // Run 6c -D GOOS_goos -D GOARCH_goarch -I workdir -q -n -o workdir/runtimedefs 409 // on each of the runtimedefs C files. 410 vadd(&argv, bpathf(&b, "%s/%sc", tooldir, gochar)); 411 vadd(&argv, "-D"); 412 vadd(&argv, bprintf(&b, "GOOS_%s", goos)); 413 vadd(&argv, "-D"); 414 vadd(&argv, bprintf(&b, "GOARCH_%s", goarch)); 415 vadd(&argv, "-I"); 416 vadd(&argv, bprintf(&b, "%s", workdir)); 417 vadd(&argv, "-q"); 418 vadd(&argv, "-n"); 419 vadd(&argv, "-o"); 420 vadd(&argv, bpathf(&b, "%s/runtimedefs", workdir)); 421 vadd(&argv, ""); 422 p = argv.p[argv.len-1]; 423 for(i=0; i<nelem(runtimedefs); i++) { 424 argv.p[argv.len-1] = runtimedefs[i]; 425 runv(nil, dir, CheckExit, &argv); 426 readfile(&b, bpathf(&b1, "%s/runtimedefs", workdir)); 427 bwriteb(&in, &b); 428 } 429 argv.p[argv.len-1] = p; 430 431 // Process the aggregate output. 432 skip = 0; 433 splitlines(&lines, bstr(&in)); 434 for(i=0; i<lines.len; i++) { 435 p = lines.p[i]; 436 // Drop comment, func, and const lines. 437 if(hasprefix(p, "//") || hasprefix(p, "const") || hasprefix(p, "func")) 438 continue; 439 440 // Note beginning of type or var decl, which can be multiline. 441 // Remove duplicates. The linear check of seen here makes the 442 // whole processing quadratic in aggregate, but there are only 443 // about 100 declarations, so this is okay (and simple). 444 if(hasprefix(p, "type ") || hasprefix(p, "var ")) { 445 splitfields(&fields, p); 446 if(fields.len < 2) 447 continue; 448 if(find(fields.p[1], seen.p, seen.len) >= 0) { 449 if(streq(fields.p[fields.len-1], "{")) 450 skip = 1; // skip until } 451 continue; 452 } 453 vadd(&seen, fields.p[1]); 454 } 455 if(skip) { 456 if(hasprefix(p, "}")) 457 skip = 0; 458 continue; 459 } 460 461 bwritestr(&out, p); 462 } 463 464 writefile(&out, file, 0); 465 466 bfree(&in); 467 bfree(&b); 468 bfree(&b1); 469 bfree(&out); 470 vfree(&argv); 471 vfree(&lines); 472 vfree(&fields); 473 vfree(&seen); 474 }