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  }