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  }