diff options
Diffstat (limited to 'src/cmd/ld/go.c')
-rw-r--r-- | src/cmd/ld/go.c | 380 |
1 files changed, 216 insertions, 164 deletions
diff --git a/src/cmd/ld/go.c b/src/cmd/ld/go.c index 3271be1f5..b2527b13e 100644 --- a/src/cmd/ld/go.c +++ b/src/cmd/ld/go.c @@ -67,8 +67,7 @@ ilookup(char *name) } static void loadpkgdata(char*, char*, char*, int); -static void loaddynimport(char*, char*, char*, int); -static void loaddynexport(char*, char*, char*, int); +static void loadcgo(char*, char*, char*, int); static int parsemethod(char**, char*, char**); static int parsepkgdata(char*, char*, char**, char*, char**, char**, char**); @@ -177,12 +176,12 @@ ldpkg(Biobuf *f, char *pkg, int64 len, char *filename, int whence) loadpkgdata(filename, pkg, p0, p1 - p0); - // look for dynimport section - p0 = strstr(p1, "\n$$ // dynimport"); + // look for cgo section + p0 = strstr(p1, "\n$$ // cgo"); if(p0 != nil) { p0 = strchr(p0+1, '\n'); if(p0 == nil) { - fprint(2, "%s: found $$ // dynimport but no newline in %s\n", argv0, filename); + fprint(2, "%s: found $$ // cgo but no newline in %s\n", argv0, filename); if(debug['u']) errorexit(); return; @@ -191,34 +190,12 @@ ldpkg(Biobuf *f, char *pkg, int64 len, char *filename, int whence) if(p1 == nil) p1 = strstr(p0, "\n!\n"); if(p1 == nil) { - fprint(2, "%s: cannot find end of // dynimport section in %s\n", argv0, filename); + fprint(2, "%s: cannot find end of // cgo section in %s\n", argv0, filename); if(debug['u']) errorexit(); return; } - loaddynimport(filename, pkg, p0 + 1, p1 - (p0+1)); - } - - // look for dynexp section - p0 = strstr(p1, "\n$$ // dynexport"); - if(p0 != nil) { - p0 = strchr(p0+1, '\n'); - if(p0 == nil) { - fprint(2, "%s: found $$ // dynexporg but no newline in %s\n", argv0, filename); - if(debug['u']) - errorexit(); - return; - } - p1 = strstr(p0, "\n$$"); - if(p1 == nil) - p1 = strstr(p0, "\n!\n"); - if(p1 == nil) { - fprint(2, "%s: cannot find end of // dynexporg section in %s\n", argv0, filename); - if(debug['u']) - errorexit(); - return; - } - loaddynexport(filename, pkg, p0 + 1, p1 - (p0+1)); + loadcgo(filename, pkg, p0 + 1, p1 - (p0+1)); } } @@ -409,10 +386,16 @@ parsemethod(char **pp, char *ep, char **methp) if(p == ep) return 0; + // might be a comment about the method + if(p + 2 < ep && strncmp(p, "//", 2) == 0) + goto useline; + // if it says "func (", it's a method - if(p + 6 >= ep || strncmp(p, "func (", 6) != 0) - return 0; + if(p + 6 < ep && strncmp(p, "func (", 6) == 0) + goto useline; + return 0; +useline: // definition to end of line *methp = p; while(p < ep && *p != '\n') @@ -428,173 +411,182 @@ parsemethod(char **pp, char *ep, char **methp) } static void -loaddynimport(char *file, char *pkg, char *p, int n) +loadcgo(char *file, char *pkg, char *p, int n) { - char *pend, *next, *name, *def, *p0, *lib, *q; + char *pend, *next, *p0, *q; + char *f[10], *local, *remote, *lib; + int nf; Sym *s; USED(file); pend = p + n; + p0 = nil; for(; p<pend; p=next) { next = strchr(p, '\n'); if(next == nil) next = ""; else *next++ = '\0'; - p0 = p; - if(strncmp(p, "dynimport ", 10) != 0) - goto err; - p += 10; - name = p; - p = strchr(name, ' '); - if(p == nil) - goto err; - while(*p == ' ') - p++; - def = p; - p = strchr(def, ' '); - if(p == nil) - goto err; - while(*p == ' ') - p++; - lib = p; - // successful parse: now can edit the line - *strchr(name, ' ') = 0; - *strchr(def, ' ') = 0; + free(p0); + p0 = strdup(p); // save for error message + nf = tokenize(p, f, nelem(f)); - if(debug['d']) { - fprint(2, "%s: %s: cannot use dynamic imports with -d flag\n", argv0, file); - nerrors++; - return; - } + if(strcmp(f[0], "cgo_import_dynamic") == 0) { + if(nf < 2 || nf > 4) + goto err; + + local = f[1]; + remote = local; + if(nf > 2) + remote = f[2]; + lib = ""; + if(nf > 3) + lib = f[3]; + + if(debug['d']) { + fprint(2, "%s: %s: cannot use dynamic imports with -d flag\n", argv0, file); + nerrors++; + return; + } - if(strcmp(name, "_") == 0 && strcmp(def, "_") == 0) { - // allow #pragma dynimport _ _ "foo.so" - // to force a link of foo.so. - havedynamic = 1; - adddynlib(lib); + if(strcmp(local, "_") == 0 && strcmp(remote, "_") == 0) { + // allow #pragma dynimport _ _ "foo.so" + // to force a link of foo.so. + havedynamic = 1; + adddynlib(lib); + continue; + } + + local = expandpkg(local, pkg); + q = strchr(remote, '#'); + if(q) + *q++ = '\0'; + s = lookup(local, 0); + if(local != f[1]) + free(local); + if(s->type == 0 || s->type == SXREF) { + s->dynimplib = lib; + s->dynimpname = remote; + s->dynimpvers = q; + s->type = SDYNIMPORT; + havedynamic = 1; + } continue; } - - name = expandpkg(name, pkg); - q = strchr(def, '@'); - if(q) - *q++ = '\0'; - s = lookup(name, 0); - free(name); - if(s->type == 0 || s->type == SXREF) { - s->dynimplib = lib; - s->dynimpname = def; - s->dynimpvers = q; - s->type = SDYNIMPORT; - havedynamic = 1; + + if(strcmp(f[0], "cgo_import_static") == 0) { + if(nf != 2) + goto err; + if(isobj) { + local = f[1]; + s = lookup(local, 0); + s->type = SHOSTOBJ; + s->size = 0; + } + continue; } - } - return; -err: - fprint(2, "%s: %s: invalid dynimport line: %s\n", argv0, file, p0); - nerrors++; -} - -static void -loaddynexport(char *file, char *pkg, char *p, int n) -{ - char *pend, *next, *local, *elocal, *remote, *p0; - Sym *s; - - USED(file); - pend = p + n; - for(; p<pend; p=next) { - next = strchr(p, '\n'); - if(next == nil) - next = ""; - else - *next++ = '\0'; - p0 = p; - if(strncmp(p, "dynexport ", 10) != 0) - goto err; - p += 10; - local = p; - p = strchr(local, ' '); - if(p == nil) - goto err; - while(*p == ' ') - p++; - remote = p; - - // successful parse: now can edit the line - *strchr(local, ' ') = 0; + if(strcmp(f[0], "cgo_export") == 0) { + if(nf < 2 || nf > 3) + goto err; + local = f[1]; + if(nf > 2) + remote = f[2]; + else + remote = local; + local = expandpkg(local, pkg); + s = lookup(local, 0); + if(s->dynimplib != nil) { + fprint(2, "%s: symbol is both imported and exported: %s\n", argv0, local); + nerrors++; + } + s->dynimpname = remote; + s->dynexport = 1; - elocal = expandpkg(local, pkg); + if(ndynexp%32 == 0) + dynexp = realloc(dynexp, (ndynexp+32)*sizeof dynexp[0]); + dynexp[ndynexp++] = s; - s = lookup(elocal, 0); - if(s->dynimplib != nil) { - fprint(2, "%s: symbol is both dynimport and dynexport %s\n", argv0, local); - nerrors++; + if(local != f[1]) + free(local); + continue; + } + + if(strcmp(f[0], "cgo_dynamic_linker") == 0) { + if(nf != 2) + goto err; + + if(!debug['I']) { // not overridden by command line + if(interpreter != nil && strcmp(interpreter, f[1]) != 0) { + fprint(2, "%s: conflict dynlinker: %s and %s\n", argv0, interpreter, f[1]); + nerrors++; + return; + } + free(interpreter); + interpreter = strdup(f[1]); + } + continue; } - s->dynimpname = remote; - s->dynexport = 1; - - if(ndynexp%32 == 0) - dynexp = realloc(dynexp, (ndynexp+32)*sizeof dynexp[0]); - dynexp[ndynexp++] = s; - - if (elocal != local) - free(elocal); } + free(p0); return; err: - fprint(2, "%s: invalid dynexport line: %s\n", argv0, p0); + fprint(2, "%s: %s: invalid dynimport line: %s\n", argv0, file, p0); nerrors++; } -static int markdepth; +static Sym *markq; +static Sym *emarkq; static void -marktext(Sym *s) +mark1(Sym *s, Sym *parent) { - Auto *a; - Prog *p; - - if(s == S) + if(s == S || s->reachable) return; - markdepth++; - if(debug['v'] > 1) - Bprint(&bso, "%d marktext %s\n", markdepth, s->name); - for(a=s->autom; a; a=a->link) - mark(a->gotype); - for(p=s->text; p != P; p=p->link) { - if(p->from.sym) - mark(p->from.sym); - if(p->to.sym) - mark(p->to.sym); - } - markdepth--; + if(strncmp(s->name, "go.weak.", 8) == 0) + return; + s->reachable = 1; + s->reachparent = parent; + if(markq == nil) + markq = s; + else + emarkq->queue = s; + emarkq = s; } void mark(Sym *s) { - int i; + mark1(s, nil); +} - if(s == S || s->reachable) - return; - if(strncmp(s->name, "weak.", 5) == 0) - return; - s->reachable = 1; - if(s->text) - marktext(s); - for(i=0; i<s->nr; i++) - mark(s->r[i].sym); - if(s->gotype) - mark(s->gotype); - if(s->sub) - mark(s->sub); - if(s->outer) - mark(s->outer); +static void +markflood(void) +{ + Auto *a; + Prog *p; + Sym *s; + int i; + + for(s=markq; s!=S; s=s->queue) { + if(s->text) { + if(debug['v'] > 1) + Bprint(&bso, "marktext %s\n", s->name); + for(a=s->autom; a; a=a->link) + mark1(a->gotype, s); + for(p=s->text; p != P; p=p->link) { + mark1(p->from.sym, s); + mark1(p->to.sym, s); + } + } + for(i=0; i<s->nr; i++) + mark1(s->r[i].sym, s); + mark1(s->gotype, s); + mark1(s->sub, s); + mark1(s->outer, s); + } } static char* @@ -651,19 +643,30 @@ void deadcode(void) { int i; - Sym *s, *last; + Sym *s, *last, *p; Auto *z; + Fmt fmt; if(debug['v']) Bprint(&bso, "%5.2f deadcode\n", cputime()); mark(lookup(INITENTRY, 0)); + if(flag_shared) + mark(lookup(LIBINITENTRY, 0)); for(i=0; i<nelem(morename); i++) mark(lookup(morename[i], 0)); for(i=0; i<ndynexp; i++) mark(dynexp[i]); + + markflood(); + // keep each beginning with 'typelink.' if the symbol it points at is being kept. + for(s = allsym; s != S; s = s->allsym) { + if(strncmp(s->name, "go.typelink.", 12) == 0) + s->reachable = s->nr==1 && s->r[0].sym->reachable; + } + // remove dead text but keep file information (z symbols). last = nil; z = nil; @@ -690,11 +693,34 @@ deadcode(void) last->next = nil; for(s = allsym; s != S; s = s->allsym) - if(strncmp(s->name, "weak.", 5) == 0) { + if(strncmp(s->name, "go.weak.", 8) == 0) { s->special = 1; // do not lay out in data segment s->reachable = 1; s->hide = 1; } + + // record field tracking references + fmtstrinit(&fmt); + for(s = allsym; s != S; s = s->allsym) { + if(strncmp(s->name, "go.track.", 9) == 0) { + s->special = 1; // do not lay out in data segment + s->hide = 1; + if(s->reachable) { + fmtprint(&fmt, "%s", s->name+9); + for(p=s->reachparent; p; p=p->reachparent) + fmtprint(&fmt, "\t%s", p->name); + fmtprint(&fmt, "\n"); + } + s->type = SCONST; + s->value = 0; + } + } + if(tracksym == nil) + return; + s = lookup(tracksym, 0); + if(!s->reachable) + return; + addstrdata(tracksym, fmtstrflush(&fmt)); } void @@ -705,11 +731,12 @@ doweak(void) // resolve weak references only if // target symbol will be in binary anyway. for(s = allsym; s != S; s = s->allsym) { - if(strncmp(s->name, "weak.", 5) == 0) { - t = rlookup(s->name+5, s->version); + if(strncmp(s->name, "go.weak.", 8) == 0) { + t = rlookup(s->name+8, s->version); if(t && t->type != 0 && t->reachable) { s->value = t->value; s->type = t->type; + s->outer = t; } else { s->type = SCONST; s->value = 0; @@ -871,3 +898,28 @@ importcycles(void) for(p=pkgall; p; p=p->all) cycle(p); } + +static int +scmp(const void *p1, const void *p2) +{ + Sym *s1, *s2; + + s1 = *(Sym**)p1; + s2 = *(Sym**)p2; + return strcmp(s1->dynimpname, s2->dynimpname); +} +void +sortdynexp(void) +{ + int i; + + // On Mac OS X Mountain Lion, we must sort exported symbols + // So we sort them here and pre-allocate dynid for them + // See http://golang.org/issue/4029 + if(HEADTYPE != Hdarwin) + return; + qsort(dynexp, ndynexp, sizeof dynexp[0], scmp); + for(i=0; i<ndynexp; i++) { + dynexp[i]->dynid = -i-100; // also known to [68]l/asm.c:^adddynsym + } +} |