From 0532f89b1fddf2a2522d2dac73140733e66f9ac5 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Tue, 21 Oct 2008 10:40:16 -0700 Subject: [PATCH] 6l: invent gotypestrings if needed R=r DELTA=419 (409 added, 5 deleted, 5 changed) OCL=17524 CL=17530 --- src/cmd/6l/6.out.h | 2 + src/cmd/6l/Makefile | 7 +- src/cmd/6l/asm.c | 18 ++- src/cmd/6l/go.c | 384 ++++++++++++++++++++++++++++++++++++++++++++ src/cmd/6l/l.h | 6 +- src/cmd/6l/obj.c | 13 +- 6 files changed, 419 insertions(+), 11 deletions(-) create mode 100644 src/cmd/6l/go.c diff --git a/src/cmd/6l/6.out.h b/src/cmd/6l/6.out.h index 89e56f6805f..4abbbf057f9 100644 --- a/src/cmd/6l/6.out.h +++ b/src/cmd/6l/6.out.h @@ -821,6 +821,8 @@ enum D_FILE, D_FILE1, + D_SBIG, /* internal use by 6l only */ + D_INDIR, /* additive */ T_TYPE = 1<<0, diff --git a/src/cmd/6l/Makefile b/src/cmd/6l/Makefile index c15f4ff1bda..5db1ba8bd20 100644 --- a/src/cmd/6l/Makefile +++ b/src/cmd/6l/Makefile @@ -9,13 +9,14 @@ TARG=\ OFILES=\ asm.$O\ + compat.$O\ + enam.$O\ + go.$O\ + list.$O\ obj.$O\ optab.$O\ pass.$O\ span.$O\ - list.$O\ - compat.$O\ - enam.$O\ HFILES=\ l.h\ diff --git a/src/cmd/6l/asm.c b/src/cmd/6l/asm.c index a6f3587a666..0c4c15fbf3d 100644 --- a/src/cmd/6l/asm.c +++ b/src/cmd/6l/asm.c @@ -546,7 +546,7 @@ asmb(void) 0, /* info */ 1, /* align */ 24); /* entsize */ - + fo += w; w = lcsize; @@ -612,10 +612,8 @@ datblk(int32 s, int32 n) if(l < 0) { if(l+c <= 0) continue; - while(l < 0) { - l++; - i++; - } + i = -l; + l = 0; } if(l >= n) continue; @@ -662,6 +660,16 @@ datblk(int32 s, int32 n) l++; } break; + + case D_SBIG: + if(debug['a'] && i == 0) + outa(c, (uchar*)p->to.sbig, nil, l+s+INITDAT); + for(; ito.sbig[i]; + l++; + } + break; + default: o = p->to.offset; if(p->to.type == D_ADDR) { diff --git a/src/cmd/6l/go.c b/src/cmd/6l/go.c new file mode 100644 index 00000000000..2d17bbe9643 --- /dev/null +++ b/src/cmd/6l/go.c @@ -0,0 +1,384 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// go-specific + +// accumulate all type information from .6 files. +// check for inconsistencies. +// define gotypestrings variable if needed. + +// TODO: +// include type info for non-exported types. +// generate debugging section in binary. +// once the dust settles, try to move some code to +// libmach, so that other linkers and ar can share. +// try to make this completely portable and shared +// across linkers + +#include "l.h" + +/* + * package import data + */ +typedef struct Import Import; +struct Import +{ + Import *hash; // next in hash table + int export; // marked as export? + char *prefix; // "type", "var", "func", "const" + char *name; + char *def; + char *file; +}; +enum { + NIHASH = 1024 +}; +static Import *ihash[NIHASH]; +static int nimport; + +static int +hashstr(char *name) +{ + int h; + char *cp; + + h = 0; + for(cp = name; *cp; h += *cp++) + h *= 1119; + if(h < 0) + h = ~h; + return h; +} + +static Import * +ilookup(char *name) +{ + int h; + Import *x; + + h = hashstr(name) % NIHASH; + for(x=ihash[h]; x; x=x->hash) + if(x->name[0] == name[0] && strcmp(x->name, name) == 0) + return x; + x = mal(sizeof *x); + x->name = name; + x->hash = ihash[h]; + ihash[h] = x; + nimport++; + return x; +} + +static void loadpkgdata(char*, char*, int); +static int parsemethod(char**, char*, char**); +static int parsepkgdata(char*, char**, char*, int*, char**, char**, char**); + +void +ldpkg(Biobuf *f, int64 len, char *filename) +{ + char *data, *p0, *p1; + + if(debug['g']) + return; + + if((int)len != len) { + fprint(2, "6l: too much pkg data in %s\n", filename); + return; + } + data = mal(len); + if(Bread(f, data, len) != len) { + fprint(2, "6l: short pkg read %s\n", filename); + return; + } + p0 = strstr(data, "$$"); + if(p0 == nil) + return; + p0 += 2; + while(*p0 != '\n' && *p0 != '\0') + p0++; + + p1 = strstr(p0, "$$"); + if(p1 == nil) { + fprint(2, "6l: cannot find end of imports in %s\n", filename); + return; + } + while(*p0 == ' ' || *p0 == '\t' || *p0 == '\n') + p0++; + if(strncmp(p0, "package ", 8) != 0) { + fprint(2, "6l: bad package section in %s\n", filename); + return; + } + p0 += 8; + while(*p0 == ' ' || *p0 == '\t' || *p0 == '\n') + p0++; + while(*p0 != ' ' && *p0 != '\t' && *p0 != '\n') + p0++; + + loadpkgdata(filename, p0, p1 - p0); +} + +static void +loadpkgdata(char *file, char *data, int len) +{ + int export; + char *p, *ep, *prefix, *name, *def; + Import *x; + + file = strdup(file); + p = data; + ep = data + len; + while(parsepkgdata(file, &p, ep, &export, &prefix, &name, &def) > 0) { + x = ilookup(name); + if(x->prefix == nil) { + x->prefix = prefix; + x->def = def; + x->file = file; + x->export = export; + } else { + if(strcmp(x->prefix, prefix) != 0) { + fprint(2, "6l: conflicting definitions for %s\n", name); + fprint(2, "%s:\t%s %s ...\n", x->file, x->prefix, name); + fprint(2, "%s:\t%s %s ...\n", file, prefix, name); + nerrors++; + } + else if(strcmp(x->def, def) != 0) { + fprint(2, "6l: conflicting definitions for %s\n", name); + fprint(2, "%s:\t%s %s %s\n", x->file, x->prefix, name, x->def); + fprint(2, "%s:\t%s %s %s\n", file, prefix, name, def); + nerrors++; + } + + // okay if some .6 say export and others don't. + // all it takes is one. + if(export) + x->export = 1; + } + } +} + +static int +parsepkgdata(char *file, char **pp, char *ep, int *exportp, char **prefixp, char **namep, char **defp) +{ + char *p, *prefix, *name, *def, *edef, *meth; + int n; + + // skip white space + p = *pp; + while(p < ep && (*p == ' ' || *p == '\t' || *p == '\n')) + p++; + if(p == ep || strncmp(p, "$$\n", 3) == 0) + return 0; + + // [export ] + *exportp = 0; + if(p + 7 <= ep && strncmp(p, "export ", 7) == 0) { + *exportp = 1; + p += 7; + } + + // prefix: (var|type|func|const) + prefix = p; + + prefix = p; + if(p + 6 > ep) + return -1; + if(strncmp(p, "var ", 4) == 0) + p += 4; + else if(strncmp(p, "type ", 5) == 0) + p += 5; + else if(strncmp(p, "func ", 5) == 0) + p += 5; + else if(strncmp(p, "const ", 6) == 0) + p += 6; + else{ + fprint(2, "ar: confused in pkg data near <<%.20s>>\n", p); + nerrors++; + return -1; + } + p[-1] = '\0'; + + // name: a.b followed by space + name = p; + while(p < ep && *p != ' ') + p++; + if(p >= ep) + return -1; + *p++ = '\0'; + + // def: free form to new line + def = p; + while(p < ep && *p != '\n') + p++; + if(p >= ep) + return -1; + edef = p; + *p++ = '\0'; + + // include methods on successive lines in def of named type + while(parsemethod(&p, ep, &meth) > 0) { + *edef++ = '\n'; // overwrites '\0' + if(edef+1 > meth) { + // We want to indent methods with a single \t. + // 6g puts at least one char of indent before all method defs, + // so there will be room for the \t. If the method def wasn't + // indented we could do something more complicated, + // but for now just diagnose the problem and assume + // 6g will keep indenting for us. + fprint(2, "6l: %s: expected methods to be indented %p %p %.10s\n", + file, edef, meth, meth); + nerrors++; + return -1; + } + *edef++ = '\t'; + n = strlen(meth); + memmove(edef, meth, n); + edef += n; + } + + // done + *pp = p; + *prefixp = prefix; + *namep = name; + *defp = def; + return 1; +} + +static int +parsemethod(char **pp, char *ep, char **methp) +{ + char *p; + + // skip white space + p = *pp; + while(p < ep && (*p == ' ' || *p == '\t')) + p++; + if(p == ep) + return 0; + + // if it says "func (", it's a method + if(p + 6 >= ep || strncmp(p, "func (", 6) != 0) + return 0; + + // definition to end of line + *methp = p; + while(p < ep && *p != '\n') + p++; + if(p >= ep) { + fprint(2, "ar: lost end of line in method definition\n"); + *pp = ep; + return -1; + } + *p++ = '\0'; + *pp = p; + return 1; +} + +static int +importcmp(const void *va, const void *vb) +{ + Import *a, *b; + + a = *(Import**)va; + b = *(Import**)vb; + return strcmp(a->name, b->name); +} + +// if there is an undefined reference to gotypestrings, +// create it. c declaration is +// extern char gotypestrings[]; +// ironically, gotypestrings is a c variable, because there +// is no way to forward declare a string in go. +void +definetypestrings(void) +{ + int i, j, len, n; + char *p; + Import **all, *x; + Fmt f; + Prog *prog; + Sym *s; + + if(debug['g']) + return; + + if(debug['v']) + Bprint(&bso, "%5.2f definetypestrings\n", cputime()); + + s = lookup("gotypestrings", 0); + if(s->type == 0) + return; + if(s->type != SXREF) { + diag("gotypestrings already defined"); + return; + } + s->type = SDATA; + + // make a list of all the type exports + n = 0; + for(i=0; ihash) + if(strcmp(x->prefix, "type") == 0) + n++; + all = mal(n*sizeof all[0]); + j = 0; + for(i=0; ihash) + if(strcmp(x->prefix, "type") == 0) + all[j++] = x; + + // sort them by name + qsort(all, n, sizeof all[0], importcmp); + + // make a big go string containing all the types + fmtstrinit(&f); + fmtprint(&f, "xxxx"); // 4-byte length + for(i=0; idef, '\n'); + if(p) + len = p - all[i]->def; + else + len = strlen(all[i]->def); + fmtprint(&f, "%s %.*s\n", all[i]->name, utfnlen(all[i]->def, len), all[i]->def); + } + p = fmtstrflush(&f); + n = strlen(p); + s->value = n; + + // go strings begin with 4-byte length. + // amd64 is little-endian. + len = n - 4; + p[0] = len; + p[1] = len >> 8; + p[2] = len >> 16; + p[3] = len >> 24; + + // have data, need to create linker representation. + // linker stores big data as sequence of pieces + // with int8 length, so break p into 100-byte chunks. + // (had to add D_SBIG even to do that; the compiler + // would have generated 8-byte chunks.) + for(i=0; ias = ADATA; + prog->width = 100; + if(prog->width > n - i) + prog->width = n - i; + prog->from.scale = prog->width; + prog->from.type = D_EXTERN; + prog->from.sym = s; + prog->from.offset = i; + prog->to.type = D_SBIG; + prog->to.sbig = p + i; + + if(edatap == P) + datap = prog; + else + edatap->link = prog; + edatap = prog; + prog->link = P; + } + + if(debug['v']) + Bprint(&bso, "%5.2f typestrings %d\n", cputime(), n); +} + diff --git a/src/cmd/6l/l.h b/src/cmd/6l/l.h index 0bd3d658085..a3c59284cbb 100644 --- a/src/cmd/6l/l.h +++ b/src/cmd/6l/l.h @@ -61,6 +61,7 @@ struct Adr char u0scon[8]; Prog *u0cond; /* not used, but should be D_BRANCH */ Ieee u0ieee; + char *u0sbig; } u0; union { @@ -76,6 +77,7 @@ struct Adr #define scon u0.u0scon #define cond u0.u0cond #define ieee u0.u0ieee +#define sbig u0.u0sbig #define autom u1.u1autom #define sym u1.u1sym @@ -377,6 +379,7 @@ void ckoff(Sym*, int32); Prog* copyp(Prog*); double cputime(void); void datblk(int32, int32); +void definetypestrings(void); void diag(char*, ...); void dodata(void); void doinit(void); @@ -396,7 +399,8 @@ void histtoauto(void); double ieeedtod(Ieee*); int32 ieeedtof(Ieee*); void import(void); -void ldobj(Biobuf*, int32, char*); +void ldobj(Biobuf*, int64, char*); +void ldpkg(Biobuf*, int64, char*); void loadlib(void); void listinit(void); Sym* lookup(char*, int); diff --git a/src/cmd/6l/obj.c b/src/cmd/6l/obj.c index a12d4da867a..eeb84573513 100644 --- a/src/cmd/6l/obj.c +++ b/src/cmd/6l/obj.c @@ -368,6 +368,7 @@ main(int argc, char *argv[]) sprint(a, "%s/lib/lib_%s_%s.a", goroot, goarch, goos); objfile(a); } + definetypestrings(); firstp = firstp->link; if(firstp == P) @@ -785,7 +786,7 @@ nopout(Prog *p) } void -ldobj(Biobuf *f, int32 len, char *pn) +ldobj(Biobuf *f, int64 len, char *pn) { vlong ipc; Prog *p, *t; @@ -797,6 +798,7 @@ ldobj(Biobuf *f, int32 len, char *pn) char **nfilen, *line, *name; int ntext, n, c1, c2, c3; vlong eof; + vlong import0, import1; eof = Boffset(f) + len; @@ -808,7 +810,8 @@ ldobj(Biobuf *f, int32 len, char *pn) free(filen); filen = nfilen; } - filen[files++] = strdup(pn); + pn = strdup(pn); + filen[files++] = pn; di = S; @@ -830,6 +833,7 @@ ldobj(Biobuf *f, int32 len, char *pn) } /* skip over exports and other info -- ends with \n!\n */ + import0 = Boffset(f); c1 = '\n'; // the last line ended in \n c2 = Bgetc(f); c3 = Bgetc(f); @@ -840,6 +844,11 @@ ldobj(Biobuf *f, int32 len, char *pn) if(c3 == Beof) goto eof; } + import1 = Boffset(f); + + Bseek(f, import0, 0); + ldpkg(f, import1 - import0 - 2, pn); // -2 for !\n + Bseek(f, import1, 0); newloop: memset(h, 0, sizeof(h));