summaryrefslogtreecommitdiff
path: root/src/cmd/ld/go.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/ld/go.c')
-rw-r--r--src/cmd/ld/go.c380
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
+ }
+}