From b87e3e8b7f37a97c383ae5bbfadb401ec6fc243c Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Tue, 31 Mar 2009 00:20:07 -0700 Subject: [PATCH] * move go-specific loader code into gc directory, where it gets included as ../gc/ldbody this is similar to the assemblers including ../cc/lexbody and ../cc/macbody. * hook go-specific loader code into 8l. * make current 8.out.h and 6.out.h backward compatible with plan 9's versions. i had added some constants in the middle of enums and have now moved them to the end. this keeps us from invalidating old .8 and .6 files. not sure how much it really matters, but easy to do. R=r DELTA=1314 (667 added, 623 deleted, 24 changed) OCL=26938 CL=26941 --- src/cmd/6l/6.out.h | 4 +- src/cmd/6l/Makefile | 2 + src/cmd/6l/go.c | 600 +------------------------------------------- src/cmd/6l/l.h | 1 - src/cmd/8l/8.out.h | 11 +- src/cmd/8l/Makefile | 4 + src/cmd/8l/l.h | 23 +- src/cmd/8l/list.c | 2 +- src/cmd/8l/obj.c | 34 +-- src/cmd/8l/optab.c | 9 +- src/cmd/8l/pass.c | 26 +- src/cmd/8l/span.c | 33 ++- src/cmd/ld/go.c | 587 +++++++++++++++++++++++++++++++++++++++++++ 13 files changed, 692 insertions(+), 644 deletions(-) create mode 100644 src/cmd/ld/go.c diff --git a/src/cmd/6l/6.out.h b/src/cmd/6l/6.out.h index 0c22944fa9..15815f4e0d 100644 --- a/src/cmd/6l/6.out.h +++ b/src/cmd/6l/6.out.h @@ -820,10 +820,10 @@ enum D_FILE, D_FILE1, - D_SBIG, /* internal use by 6l only */ - D_INDIR, /* additive */ + D_SBIG = D_INDIR + D_INDIR, + T_TYPE = 1<<0, T_INDEX = 1<<1, T_OFFSET = 1<<2, diff --git a/src/cmd/6l/Makefile b/src/cmd/6l/Makefile index 5db1ba8bd2..eba976c638 100644 --- a/src/cmd/6l/Makefile +++ b/src/cmd/6l/Makefile @@ -36,3 +36,5 @@ clean: install: $(TARG) cp $(TARG) $(BIN)/$(TARG) + +go.o: ../ld/go.c diff --git a/src/cmd/6l/go.c b/src/cmd/6l/go.c index 961a3320b0..82a216520f 100644 --- a/src/cmd/6l/go.c +++ b/src/cmd/6l/go.c @@ -2,603 +2,5 @@ // 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. -// define gotypesigs 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; -} - -char* -gotypefor(char *name) -{ - Import *x; - char *s, *p; - - s = strdup(name); - p = utfrune(s, 0xB7); // center dot - if(p == nil) - return nil; - *p++ = '.'; - memmove(p, p+1, strlen(p)); - x = ilookup(s); - free(s); - if(x == nil || x->prefix == nil) - return nil; - if(strcmp(x->prefix, "var") != 0 && strcmp(x->prefix, "func") != 0) - return nil; - return x->def; -} - -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; - } - - // first \n$$ marks beginning of exports - skip rest of line - p0 = strstr(data, "\n$$"); - if(p0 == nil) - return; - p0 += 3; - while(*p0 != '\n' && *p0 != '\0') - p0++; - - // second marks end of exports / beginning of local data - p1 = strstr(p0, "\n$$"); - if(p1 == nil) { - fprint(2, "6l: cannot find end of exports 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); - - // local types begin where exports end. - // skip rest of line after $$ we found above - p0 = p1 + 3; - while(*p0 != '\n' && *p0 != '\0') - p0++; - - // local types end at next \n$$. - p1 = strstr(p0, "\n$$"); - if(p1 == nil) { - fprint(2, "6l: cannot find end of local types in %s\n", filename); - return; - } - - 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|package ] - *exportp = 0; - if(p + 7 <= ep && strncmp(p, "export ", 7) == 0) { - *exportp = 1; - p += 7; - } - else if(p + 8 <= ep && strncmp(p, "package ", 8) == 0) { - *exportp = 2; - p += 8; - } - - // 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, "6l: 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, "6l: 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); -} - -static int -symcmp(const void *va, const void *vb) -{ - Sym *a, *b; - - a = *(Sym**)va; - b = *(Sym**)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, w; - 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; i n - i) - w = n - i; - prog = newdata(s, i, w, D_EXTERN); - prog->to.type = D_SBIG; - prog->to.sbig = p + i; - } - - if(debug['v']) - Bprint(&bso, "%5.2f typestrings %d\n", cputime(), n); -} - -// if there is an undefined reference to gotypesigs, create it. -// c declaration is -// extern Sigt *gotypesigs[]; -// extern int ngotypesigs; -// used by sys.unreflect runtime. -void -definetypesigs(void) -{ - int i, j, n; - Sym **all, *s, *x; - Prog *prog; - - if(debug['g']) - return; - - if(debug['v']) - Bprint(&bso, "%5.2f definetypesigs\n", cputime()); - - s = lookup("gotypesigs", 0); - if(s->type == 0) - return; - if(s->type != SXREF) { - diag("gotypesigs already defined"); - return; - } - s->type = SDATA; - - // make a list of all the sigt symbols. - n = 0; - for(i=0; ilink) - if(memcmp(x->name, "sigt·", 6) == 0 && x->type != Sxxx) - n++; - all = mal(n*sizeof all[0]); - j = 0; - for(i=0; ilink) - if(memcmp(x->name, "sigt·", 6) == 0 && x->type != Sxxx) - all[j++] = x; - - // sort them by name - qsort(all, n, sizeof all[0], symcmp); - - // emit array as sequence of references. - enum { PtrSize = 8 }; - for(i=0; ito.type = D_ADDR; - prog->to.index = D_EXTERN; - prog->to.sym = all[i]; - } - s->value = PtrSize*n; - if(n == 0) - s->value = 1; // must have non-zero size or 6l complains - - // emit count - s = lookup("ngotypesigs", 0); - s->type = SDATA; - s->value = sizeof(int32); - prog = newdata(s, 0, sizeof(int32), D_EXTERN); - prog->to.offset = n; - - if(debug['v']) - Bprint(&bso, "%5.2f typesigs %d\n", cputime(), n); -} - -int -isinitfunc(Sym *s) -{ - char *p; - - p = utfrune(s->name, 0xb7); // 0xb7 = '·' - if(p == nil) - return 0; - if(memcmp(p, "·Init·", 8) == 0 || memcmp(p, "·init·", 8) == 0) - return 1; - return 0; -} - -static void mark(Sym*); -static int markdepth; - -static void -markdata(Prog *p, Sym *s) -{ - markdepth++; - if(p != P && debug['v'] > 1) - Bprint(&bso, "%d markdata %s\n", markdepth, s->name); - for(; p != P; p=p->dlink) - if(p->to.sym) - mark(p->to.sym); - markdepth--; -} - -static void -marktext(Prog *p) -{ - if(p == P) - return; - if(p->as != ATEXT) { - diag("marktext: %P", p); - return; - } - markdepth++; - if(debug['v'] > 1) - Bprint(&bso, "%d marktext %s\n", markdepth, p->from.sym->name); - for(p=p->link; p != P; p=p->link) { - if(p->as == ATEXT || p->as == ADATA || p->as == AGLOBL) - break; - if(p->from.sym) - mark(p->from.sym); - if(p->to.sym) - mark(p->to.sym); - } - markdepth--; -} - -static void -mark(Sym *s) -{ - if(s == S || s->reachable) - return; - s->reachable = 1; - if(s->text) - marktext(s->text); - if(s->data) - markdata(s->data, s); -} - -static void -sweeplist(Prog **first, Prog **last) -{ - int reachable; - Prog *p, *q; - - reachable = 1; - q = P; - for(p=*first; p != P; p=p->link) { - switch(p->as) { - case ATEXT: - case ADATA: - case AGLOBL: - reachable = p->from.sym->reachable; - if(!reachable) { - if(debug['v'] > 1) - Bprint(&bso, "discard %s\n", p->from.sym->name); - p->from.sym->type = Sxxx; - } - break; - } - if(reachable) { - if(q == P) - *first = p; - else - q->link = p; - q = p; - } - } - if(q == P) - *first = P; - else - q->link = P; - *last = q; -} - -void -deadcode(void) -{ - if(debug['v']) - Bprint(&bso, "%5.2f deadcode\n", cputime()); - - mark(lookup(INITENTRY, 0)); - mark(lookup("sys·morestack", 0)); - - sweeplist(&firstp, &lastp); - sweeplist(&datap, &edatap); -} - +#include "../ld/go.c" diff --git a/src/cmd/6l/l.h b/src/cmd/6l/l.h index 83c28bd4b7..2d3cd535a1 100644 --- a/src/cmd/6l/l.h +++ b/src/cmd/6l/l.h @@ -441,7 +441,6 @@ void xdefine(char*, int, vlong); void xfol(Prog*); void zaddr(Biobuf*, Adr*, Sym*[]); void zerosig(char*); -int isinitfunc(Sym*); void machseg(char*, vlong, vlong, vlong, vlong, uint32, uint32, uint32, uint32); void machsymseg(uint32, uint32); diff --git a/src/cmd/8l/8.out.h b/src/cmd/8l/8.out.h index f7750129d8..1b9c88b1d9 100644 --- a/src/cmd/8l/8.out.h +++ b/src/cmd/8l/8.out.h @@ -79,9 +79,6 @@ enum as ACMPSB, ACMPSL, ACMPSW, - ACMPXCHGB, - ACMPXCHGL, - ACMPXCHGW, ADAA, ADAS, ADATA, @@ -387,6 +384,10 @@ enum as ASIGNAME, + ACMPXCHGB, + ACMPXCHGL, + ACMPXCHGW, + ALAST }; @@ -441,13 +442,15 @@ enum D_FCONST = 66, D_SCONST = 67, D_ADDR = 68, - D_CONST2 = 69, D_FILE, D_FILE1, D_INDIR, /* additive */ + D_SBIG = D_INDIR + D_INDIR, + D_CONST2, + T_TYPE = 1<<0, T_INDEX = 1<<1, T_OFFSET = 1<<2, diff --git a/src/cmd/8l/Makefile b/src/cmd/8l/Makefile index e11b6687a9..6b8c73ae2e 100644 --- a/src/cmd/8l/Makefile +++ b/src/cmd/8l/Makefile @@ -16,6 +16,7 @@ OFILES=\ optab.$O\ pass.$O\ span.$O\ + go.$O\ HFILES=\ l.h\ @@ -35,3 +36,6 @@ clean: install: $(TARG) cp $(TARG) $(BIN)/$(TARG) + +go.o: ../ld/go.c + diff --git a/src/cmd/8l/l.h b/src/cmd/8l/l.h index 114c663690..9afd78faa2 100644 --- a/src/cmd/8l/l.h +++ b/src/cmd/8l/l.h @@ -58,6 +58,7 @@ struct Adr char u0scon[8]; Prog *u0cond; /* not used, but should be D_BRANCH */ Ieee u0ieee; + char *u0sbig; } u0; union { @@ -74,6 +75,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 @@ -84,6 +86,7 @@ struct Prog Adr to; Prog *forwd; Prog* link; + Prog* dlink; Prog* pcond; /* work on this */ int32 pc; int32 line; @@ -108,10 +111,14 @@ struct Sym short become; short frame; uchar subtype; + uchar dupok; + uchar reachable; ushort file; int32 value; int32 sig; Sym* link; + Prog* text; + Prog* data; }; struct Optab { @@ -123,7 +130,9 @@ struct Optab enum { - STEXT = 1, + Sxxx, + + STEXT, SDATA, SBSS, SDATA1, @@ -352,6 +361,8 @@ void lputl(int32); void main(int, char*[]); void mkfwd(void); void* mal(uint32); +Prog* newdata(Sym*, int, int, int); +Prog* newtext(Prog*, Sym*); void nuxiinit(void); void objfile(char*); int opsize(Prog*); @@ -375,6 +386,16 @@ uint32 machheadr(void); uint32 elfheadr(void); void whatsys(void); +/* + * go.c + */ +void deadcode(void); +void definetypestrings(void); +void definetypesigs(void); +char* gotypefor(char *name); +void ldpkg(Biobuf *f, int64 len, char *filename); + + /* set by call to whatsys() */ extern char* goroot; extern char* goarch; diff --git a/src/cmd/8l/list.c b/src/cmd/8l/list.c index 873f7c1f85..79777d8b1f 100644 --- a/src/cmd/8l/list.c +++ b/src/cmd/8l/list.c @@ -99,7 +99,7 @@ Dconv(Fmt *fp) a = va_arg(fp->args, Adr*); i = a->type; - if(i >= D_INDIR) { + if(i >= D_INDIR && i < 2*D_INDIR) { if(a->offset) sprint(str, "%ld(%R)", a->offset, i-D_INDIR); else diff --git a/src/cmd/8l/obj.c b/src/cmd/8l/obj.c index c4aa3486be..a14f52d6f7 100644 --- a/src/cmd/8l/obj.c +++ b/src/cmd/8l/obj.c @@ -333,6 +333,10 @@ main(int argc, char *argv[]) sprint(a, "%s/lib/lib_%s_%s.a", goroot, goarch, goos); objfile(a); } + definetypestrings(); + definetypesigs(); + deadcode(); + firstp = firstp->link; if(firstp == P) errorexit(); @@ -848,7 +852,7 @@ ldobj(Biobuf *f, int32 len, char *pn) import1 = Boffset(f); Bseek(f, import0, 0); -// ldpkg(f, import1 - import0 - 2, pn); // -2 for !\n + ldpkg(f, import1 - import0 - 2, pn); // -2 for !\n Bseek(f, import1, 0); newloop: @@ -1017,6 +1021,20 @@ loop: case ADATA: data: + // Assume that AGLOBL comes after ADATA. + // If we've seen an AGLOBL that said this sym was DUPOK, + // ignore any more ADATA we see, which must be + // redefinitions. + s = p->from.sym; + if(s != S && s->dupok) { + if(debug['v']) + Bprint(&bso, "skipping %s in %s: dupok", s->name, pn); + goto loop; + } + if(s != S) { + p->dlink = s->data; + s->data = p; + } if(edatap == P) datap = p; else @@ -1056,19 +1074,7 @@ loop: } diag("%s: redefinition: %s\n%P", pn, s->name, p); } - s->type = STEXT; - s->value = pc; - lastp->link = p; - lastp = p; - p->pc = pc; - pc++; - if(textp == P) { - textp = p; - etextp = p; - goto loop; - } - etextp->pcond = p; - etextp = p; + newtext(p, s); goto loop; case AFMOVF: diff --git a/src/cmd/8l/optab.c b/src/cmd/8l/optab.c index 934f14e9bc..df5ba629fc 100644 --- a/src/cmd/8l/optab.c +++ b/src/cmd/8l/optab.c @@ -388,9 +388,6 @@ Optab optab[] = { ACMPSB, ynone, Pb, 0xa6 }, { ACMPSL, ynone, Px, 0xa7 }, { ACMPSW, ynone, Pe, 0xa7 }, - { ACMPXCHGB, yrb_mb, Pm, 0xb0 }, - { ACMPXCHGL, yrl_ml, Pm, 0xb1 }, - { ACMPXCHGW, yrl_ml, Pm, 0xb1 }, { ADAA, ynone, Px, 0x27 }, { ADAS, ynone, Px, 0x2f }, { ADATA }, @@ -688,5 +685,11 @@ Optab optab[] = { AFYL2X, ynone, Px, 0xd9, 0xf1 }, { AFYL2XP1, ynone, Px, 0xd9, 0xf9 }, { AEND }, + { ADYNT }, + { AINIT }, + { ASIGNAME }, + { ACMPXCHGB, yrb_mb, Pm, 0xb0 }, + { ACMPXCHGL, yrl_ml, Pm, 0xb1 }, + { ACMPXCHGW, yrl_ml, Pm, 0xb1 }, 0 }; diff --git a/src/cmd/8l/pass.c b/src/cmd/8l/pass.c index 0726d1ea8f..2e52edc0cc 100644 --- a/src/cmd/8l/pass.c +++ b/src/cmd/8l/pass.c @@ -802,7 +802,7 @@ ckoff(Sym *s, int32 v) diag("relocation offset %ld for %s out of range", v, s->name); } -static Prog* +Prog* newdata(Sym *s, int o, int w, int t) { Prog *p; @@ -820,6 +820,30 @@ newdata(Sym *s, int o, int w, int t) p->from.sym = s; p->from.offset = o; p->to.type = D_CONST; + p->dlink = s->data; + s->data = p; + return p; +} + +Prog* +newtext(Prog *p, Sym *s) +{ + if(p == P) { + p = prg(); + p->as = ATEXT; + p->from.sym = s; + } + s->type = STEXT; + s->text = p; + s->value = pc; + lastp->link = p; + lastp = p; + p->pc = pc++; + if(textp == P) + textp = p; + else + etextp->pcond = p; + etextp = p; return p; } diff --git a/src/cmd/8l/span.c b/src/cmd/8l/span.c index 81703d3046..6adf5295ab 100644 --- a/src/cmd/8l/span.c +++ b/src/cmd/8l/span.c @@ -146,12 +146,9 @@ xdefine(char *p, int t, int32 v) } void -putsymb(char *s, int t, int32 v, int ver) +putsymb(char *s, int t, int32 v, int ver, char *go) { int i, j, f; - char *go; - - go = nil; // TODO if(t == 'f') s++; @@ -211,25 +208,25 @@ asmsym(void) s = lookup("etext", 0); if(s->type == STEXT) - putsymb(s->name, 'T', s->value, s->version); + putsymb(s->name, 'T', s->value, s->version, nil); for(h=0; hlink) switch(s->type) { case SCONST: - putsymb(s->name, 'D', s->value, s->version); + putsymb(s->name, 'D', s->value, s->version, gotypefor(s->name)); continue; case SDATA: - putsymb(s->name, 'D', s->value+INITDAT, s->version); + putsymb(s->name, 'D', s->value+INITDAT, s->version, gotypefor(s->name)); continue; case SBSS: - putsymb(s->name, 'B', s->value+INITDAT, s->version); + putsymb(s->name, 'B', s->value+INITDAT, s->version, gotypefor(s->name)); continue; case SFILE: - putsymb(s->name, 'f', s->value, s->version); + putsymb(s->name, 'f', s->value, s->version, nil); continue; } @@ -241,22 +238,22 @@ asmsym(void) /* filenames first */ for(a=p->to.autom; a; a=a->link) if(a->type == D_FILE) - putsymb(a->asym->name, 'z', a->aoffset, 0); + putsymb(a->asym->name, 'z', a->aoffset, 0, nil); else if(a->type == D_FILE1) - putsymb(a->asym->name, 'Z', a->aoffset, 0); + putsymb(a->asym->name, 'Z', a->aoffset, 0, nil); - putsymb(s->name, 'T', s->value, s->version); + putsymb(s->name, 'T', s->value, s->version, gotypefor(s->name)); /* frame, auto and param after */ - putsymb(".frame", 'm', p->to.offset+4, 0); + putsymb(".frame", 'm', p->to.offset+4, 0, nil); for(a=p->to.autom; a; a=a->link) if(a->type == D_AUTO) - putsymb(a->asym->name, 'a', -a->aoffset, 0); + putsymb(a->asym->name, 'a', -a->aoffset, 0, nil); else if(a->type == D_PARAM) - putsymb(a->asym->name, 'p', a->aoffset, 0); + putsymb(a->asym->name, 'p', a->aoffset, 0, nil); } if(debug['v'] || debug['n']) Bprint(&bso, "symsize = %lud\n", symsize); @@ -366,7 +363,7 @@ oclass(Adr *a) { int32 v; - if(a->type >= D_INDIR || a->index != D_NONE) { + if((a->type >= D_INDIR && a->type < 2*D_INDIR) || a->index != D_NONE) { if(a->index != D_NONE && a->scale == 0) { if(a->type == D_ADDR) { switch(a->index) { @@ -615,7 +612,7 @@ asmand(Adr *a, int r) v = a->offset; t = a->type; if(a->index != D_NONE) { - if(t >= D_INDIR) { + if(t >= D_INDIR && t < 2*D_INDIR) { t -= D_INDIR; if(t == D_NONE) { *andptr++ = (0 << 6) | (4 << 0) | (r << 3); @@ -663,7 +660,7 @@ asmand(Adr *a, int r) *andptr++ = (3 << 6) | (reg[t] << 0) | (r << 3); return; } - if(t >= D_INDIR) { + if(t >= D_INDIR && t < 2*D_INDIR) { t -= D_INDIR; if(t == D_NONE || (D_CS <= t && t <= D_GS)) { *andptr++ = (0 << 6) | (5 << 0) | (r << 3); diff --git a/src/cmd/ld/go.c b/src/cmd/ld/go.c new file mode 100644 index 0000000000..e8366e8252 --- /dev/null +++ b/src/cmd/ld/go.c @@ -0,0 +1,587 @@ +// 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 code shared across loaders (5l, 6l, 8l). + +// accumulate all type information from .6 files. +// check for inconsistencies. +// define gotypestrings variable if needed. +// define gotypesigs 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. + +/* + * 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; +} + +char* +gotypefor(char *name) +{ + Import *x; + char *s, *p; + + s = strdup(name); + p = utfrune(s, 0xB7); // center dot + if(p == nil) + return nil; + *p++ = '.'; + memmove(p, p+1, strlen(p)); + x = ilookup(s); + free(s); + if(x == nil || x->prefix == nil) + return nil; + if(strcmp(x->prefix, "var") != 0 && strcmp(x->prefix, "func") != 0) + return nil; + return x->def; +} + +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; + } + + // first \n$$ marks beginning of exports - skip rest of line + p0 = strstr(data, "\n$$"); + if(p0 == nil) + return; + p0 += 3; + while(*p0 != '\n' && *p0 != '\0') + p0++; + + // second marks end of exports / beginning of local data + p1 = strstr(p0, "\n$$"); + if(p1 == nil) { + fprint(2, "6l: cannot find end of exports 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); + + // local types begin where exports end. + // skip rest of line after $$ we found above + p0 = p1 + 3; + while(*p0 != '\n' && *p0 != '\0') + p0++; + + // local types end at next \n$$. + p1 = strstr(p0, "\n$$"); + if(p1 == nil) { + fprint(2, "6l: cannot find end of local types in %s\n", filename); + return; + } + + 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|package ] + *exportp = 0; + if(p + 7 <= ep && strncmp(p, "export ", 7) == 0) { + *exportp = 1; + p += 7; + } + else if(p + 8 <= ep && strncmp(p, "package ", 8) == 0) { + *exportp = 2; + p += 8; + } + + // 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, "6l: 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, "6l: 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); +} + +static int +symcmp(const void *va, const void *vb) +{ + Sym *a, *b; + + a = *(Sym**)va; + b = *(Sym**)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, w; + 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; i n - i) + w = n - i; + prog = newdata(s, i, w, D_EXTERN); + prog->to.type = D_SBIG; + prog->to.sbig = p + i; + } + + if(debug['v']) + Bprint(&bso, "%5.2f typestrings %d\n", cputime(), n); +} + +// if there is an undefined reference to gotypesigs, create it. +// c declaration is +// extern Sigt *gotypesigs[]; +// extern int ngotypesigs; +// used by sys.unreflect runtime. +void +definetypesigs(void) +{ + int i, j, n; + Sym **all, *s, *x; + Prog *prog; + + if(debug['g']) + return; + + if(debug['v']) + Bprint(&bso, "%5.2f definetypesigs\n", cputime()); + + s = lookup("gotypesigs", 0); + if(s->type == 0) + return; + if(s->type != SXREF) { + diag("gotypesigs already defined"); + return; + } + s->type = SDATA; + + // make a list of all the sigt symbols. + n = 0; + for(i=0; ilink) + if(memcmp(x->name, "sigt·", 6) == 0 && x->type != Sxxx) + n++; + all = mal(n*sizeof all[0]); + j = 0; + for(i=0; ilink) + if(memcmp(x->name, "sigt·", 6) == 0 && x->type != Sxxx) + all[j++] = x; + + // sort them by name + qsort(all, n, sizeof all[0], symcmp); + + // emit array as sequence of references. + enum { PtrSize = 8 }; + for(i=0; ito.type = D_ADDR; + prog->to.index = D_EXTERN; + prog->to.sym = all[i]; + } + s->value = PtrSize*n; + if(n == 0) + s->value = 1; // must have non-zero size or 6l complains + + // emit count + s = lookup("ngotypesigs", 0); + s->type = SDATA; + s->value = sizeof(int32); + prog = newdata(s, 0, sizeof(int32), D_EXTERN); + prog->to.offset = n; + + if(debug['v']) + Bprint(&bso, "%5.2f typesigs %d\n", cputime(), n); +} + +static void mark(Sym*); +static int markdepth; + +static void +markdata(Prog *p, Sym *s) +{ + markdepth++; + if(p != P && debug['v'] > 1) + Bprint(&bso, "%d markdata %s\n", markdepth, s->name); + for(; p != P; p=p->dlink) + if(p->to.sym) + mark(p->to.sym); + markdepth--; +} + +static void +marktext(Prog *p) +{ + if(p == P) + return; + if(p->as != ATEXT) { + diag("marktext: %P", p); + return; + } + markdepth++; + if(debug['v'] > 1) + Bprint(&bso, "%d marktext %s\n", markdepth, p->from.sym->name); + for(p=p->link; p != P; p=p->link) { + if(p->as == ATEXT || p->as == ADATA || p->as == AGLOBL) + break; + if(p->from.sym) + mark(p->from.sym); + if(p->to.sym) + mark(p->to.sym); + } + markdepth--; +} + +static void +mark(Sym *s) +{ + if(s == S || s->reachable) + return; + s->reachable = 1; + if(s->text) + marktext(s->text); + if(s->data) + markdata(s->data, s); +} + +static void +sweeplist(Prog **first, Prog **last) +{ + int reachable; + Prog *p, *q; + + reachable = 1; + q = P; + for(p=*first; p != P; p=p->link) { + switch(p->as) { + case ATEXT: + case ADATA: + case AGLOBL: + reachable = p->from.sym->reachable; + if(!reachable) { + if(debug['v'] > 1) + Bprint(&bso, "discard %s\n", p->from.sym->name); + p->from.sym->type = Sxxx; + } + break; + } + if(reachable) { + if(q == P) + *first = p; + else + q->link = p; + q = p; + } + } + if(q == P) + *first = P; + else + q->link = P; + *last = q; +} + +void +deadcode(void) +{ + if(debug['v']) + Bprint(&bso, "%5.2f deadcode\n", cputime()); + + mark(lookup(INITENTRY, 0)); + mark(lookup("sys·morestack", 0)); + +// sweeplist(&firstp, &lastp); +// sweeplist(&datap, &edatap); +} + -- 2.48.1