Commit 49084db3 authored by Russ Cox's avatar Russ Cox

ld: abandon symbol-driven archive loading

Load the entire archive file instead.
Reduces I/O by avoiding additional passes
through libraries to resolve symbols.
Go packages always need all the files anyway
(most often, all 1 of them).

R=ken2
CC=golang-dev
https://golang.org/cl/2613042
parent 1451695f
...@@ -320,7 +320,6 @@ EXTERN int32 elfdatsize; ...@@ -320,7 +320,6 @@ EXTERN int32 elfdatsize;
EXTERN char debug[128]; EXTERN char debug[128];
EXTERN Sym* etextp; EXTERN Sym* etextp;
EXTERN char* noname; EXTERN char* noname;
EXTERN int xrefresolv;
EXTERN Prog* lastp; EXTERN Prog* lastp;
EXTERN int32 lcsize; EXTERN int32 lcsize;
EXTERN char literal[32]; EXTERN char literal[32];
......
...@@ -328,7 +328,6 @@ EXTERN char debug[128]; ...@@ -328,7 +328,6 @@ EXTERN char debug[128];
EXTERN char literal[32]; EXTERN char literal[32];
EXTERN Sym* textp; EXTERN Sym* textp;
EXTERN Sym* etextp; EXTERN Sym* etextp;
EXTERN int xrefresolv;
EXTERN char ycover[Ymax*Ymax]; EXTERN char ycover[Ymax*Ymax];
EXTERN uchar* andptr; EXTERN uchar* andptr;
EXTERN uchar* rexptr; EXTERN uchar* rexptr;
......
...@@ -292,7 +292,6 @@ EXTERN char debug[128]; ...@@ -292,7 +292,6 @@ EXTERN char debug[128];
EXTERN char literal[32]; EXTERN char literal[32];
EXTERN Sym* etextp; EXTERN Sym* etextp;
EXTERN Prog* firstp; EXTERN Prog* firstp;
EXTERN int xrefresolv;
EXTERN uchar ycover[Ymax*Ymax]; EXTERN uchar ycover[Ymax*Ymax];
EXTERN uchar* andptr; EXTERN uchar* andptr;
EXTERN uchar and[100]; EXTERN uchar and[100];
......
...@@ -147,6 +147,22 @@ addlib(char *src, char *obj) ...@@ -147,6 +147,22 @@ addlib(char *src, char *obj)
strcat(name, comp); strcat(name, comp);
} }
cleanname(name); cleanname(name);
// runtime.a -> runtime
p = nil;
if(strlen(name) > 2 && name[strlen(name)-2] == '.') {
p = name+strlen(name)-2;
*p = '\0';
}
// already loaded?
for(i=0; i<libraryp; i++)
if(strcmp(library[i].pkg, name) == 0)
return;
// runtime -> runtime.a for search
if(p != nil)
*p = '.';
if(search) { if(search) {
// try dot, -L "libdir", and then goroot. // try dot, -L "libdir", and then goroot.
...@@ -160,8 +176,8 @@ addlib(char *src, char *obj) ...@@ -160,8 +176,8 @@ addlib(char *src, char *obj)
cleanname(pname); cleanname(pname);
/* runtime.a -> runtime */ /* runtime.a -> runtime */
if(strlen(name) > 2 && name[strlen(name)-2] == '.') if(p != nil)
name[strlen(name)-2] = '\0'; *p = '\0';
if(debug['v']) if(debug['v'])
Bprint(&bso, "%5.2f addlib: %s %s pulls in %s\n", cputime(), obj, src, pname); Bprint(&bso, "%5.2f addlib: %s %s pulls in %s\n", cputime(), obj, src, pname);
...@@ -187,9 +203,9 @@ addlibpath(char *srcref, char *objref, char *file, char *pkg) ...@@ -187,9 +203,9 @@ addlibpath(char *srcref, char *objref, char *file, char *pkg)
if(strcmp(file, library[i].file) == 0) if(strcmp(file, library[i].file) == 0)
return; return;
if(debug['v']) if(debug['v'] > 1)
Bprint(&bso, "%5.2f addlibpath: srcref: %s objref: %s file: %s pkg: %s\n", Bprint(&bso, "%5.2f addlibpath: srcref: %s objref: %s file: %s pkg: %s\n",
cputime(), srcref, objref, file, pkg); cputime(), srcref, objref, file, pkg);
if(libraryp == nlibrary){ if(libraryp == nlibrary){
nlibrary = 50 + 2*libraryp; nlibrary = 50 + 2*libraryp;
...@@ -220,8 +236,6 @@ loadlib(void) ...@@ -220,8 +236,6 @@ loadlib(void)
{ {
char pname[1024]; char pname[1024];
int i, found; int i, found;
int32 h;
Sym *s;
found = 0; found = 0;
for(i=0; i<nlibdir; i++) { for(i=0; i<nlibdir; i++) {
...@@ -234,47 +248,51 @@ loadlib(void) ...@@ -234,47 +248,51 @@ loadlib(void)
break; break;
} }
} }
if(!found) Bprint(&bso, "warning: unable to find runtime.a\n"); if(!found)
Bprint(&bso, "warning: unable to find runtime.a\n");
loop:
xrefresolv = 0;
for(i=0; i<libraryp; i++) { for(i=0; i<libraryp; i++) {
if(debug['v']) if(debug['v'])
Bprint(&bso, "%5.2f autolib: %s (from %s)\n", cputime(), library[i].file, library[i].objref); Bprint(&bso, "%5.2f autolib: %s (from %s)\n", cputime(), library[i].file, library[i].objref);
objfile(library[i].file, library[i].pkg); objfile(library[i].file, library[i].pkg);
} }
}
if(xrefresolv) /*
for(h=0; h<nelem(hash); h++) * look for the next file in an archive.
for(s = hash[h]; s != S; s = s->hash) * adapted from libmach.
if(s->type == SXREF) */
goto loop; int
nextar(Biobuf *bp, int off, struct ar_hdr *a)
{
int r;
int32 arsize;
if (off&01)
off++;
Bseek(bp, off, 0);
r = Bread(bp, a, SAR_HDR);
if(r != SAR_HDR)
return 0;
if(strncmp(a->fmag, ARFMAG, sizeof(a->fmag)))
return -1;
arsize = strtol(a->size, 0, 0);
if (arsize&1)
arsize++;
return arsize + SAR_HDR;
} }
void void
objfile(char *file, char *pkg) objfile(char *file, char *pkg)
{ {
int32 off, esym, cnt, l; int32 off, l;
int work;
Biobuf *f; Biobuf *f;
Sym *s;
char magbuf[SARMAG]; char magbuf[SARMAG];
char name[100], pname[150]; char pname[150];
struct ar_hdr arhdr; struct ar_hdr arhdr;
char *e, *start, *stop, *x;
pkg = smprint("%i", pkg); pkg = smprint("%i", pkg);
if(file[0] == '-' && file[1] == 'l') { // TODO: fix this
if(debug['9'])
sprint(name, "/%s/lib/lib", thestring);
else
sprint(name, "/usr/%clib/lib", thechar);
strcat(name, file+2);
strcat(name, ".a");
file = name;
}
if(debug['v']) if(debug['v'])
Bprint(&bso, "%5.2f ldobj: %s (%s)\n", cputime(), file, pkg); Bprint(&bso, "%5.2f ldobj: %s (%s)\n", cputime(), file, pkg);
Bflush(&bso); Bflush(&bso);
...@@ -292,9 +310,10 @@ objfile(char *file, char *pkg) ...@@ -292,9 +310,10 @@ objfile(char *file, char *pkg)
Bterm(f); Bterm(f);
return; return;
} }
l = Bread(f, &arhdr, SAR_HDR); /* skip over __.SYMDEF */
if(l != SAR_HDR) { off = Boffset(f);
if((l = nextar(f, off, &arhdr)) <= 0) {
diag("%s: short read on archive file symbol header", file); diag("%s: short read on archive file symbol header", file);
goto out; goto out;
} }
...@@ -302,88 +321,52 @@ objfile(char *file, char *pkg) ...@@ -302,88 +321,52 @@ objfile(char *file, char *pkg)
diag("%s: first entry not symbol header", file); diag("%s: first entry not symbol header", file);
goto out; goto out;
} }
off += l;
esym = SARMAG + SAR_HDR + atolwhex(arhdr.size);
off = SARMAG + SAR_HDR; /* skip over (or process) __.PKGDEF */
if((l = nextar(f, off, &arhdr)) <= 0) {
if(debug['u']) { diag("%s: short read on archive file symbol header", file);
struct ar_hdr pkghdr; goto out;
int n;
// Read next ar header to check for package safe bit.
Bseek(f, esym+(esym&1), 0);
l = Bread(f, &pkghdr, SAR_HDR);
if(l != SAR_HDR) {
diag("%s: short read on second archive header", file);
goto out;
}
if(strncmp(pkghdr.name, pkgname, strlen(pkgname))) {
diag("%s: second entry not package header", file);
goto out;
}
n = atolwhex(pkghdr.size);
ldpkg(f, pkg, n, file, Pkgdef);
} }
if(strncmp(arhdr.name, pkgname, strlen(pkgname))) {
diag("%s: second entry not package header", file);
goto out;
}
off += l;
if(debug['u'])
ldpkg(f, pkg, atolwhex(arhdr.size), file, Pkgdef);
/* /*
* just bang the whole symbol file into memory * load all the object files from the archive now.
* this gives us sequential file access and keeps us
* from needing to come back later to pick up more
* objects. it breaks the usual C archive model, but
* this is Go, not C. the common case in Go is that
* we need to load all the objects, and then we throw away
* the individual symbols that are unused.
*
* loading every object will also make it possible to
* load foreign objects not referenced by __.SYMDEF.
*/ */
Bseek(f, off, 0); for(;;) {
cnt = esym - off; l = nextar(f, off, &arhdr);
start = mal(cnt + 10); if(l == 0)
cnt = Bread(f, start, cnt); break;
if(cnt <= 0){ if(l < 0) {
Bterm(f); diag("%s: malformed archive", file);
return; goto out;
}
stop = &start[cnt];
memset(stop, 0, 10);
work = 1;
while(work) {
if(debug['v'])
Bprint(&bso, "%5.2f library pass: %s\n", cputime(), file);
Bflush(&bso);
work = 0;
for(e = start; e < stop; e = strchr(e+5, 0) + 1) {
x = expandpkg(e+5, pkg);
s = lookup(x, 0);
if(x != e+5)
free(x);
if(s->type != SXREF)
continue;
sprint(pname, "%s(%s)", file, s->name);
if(debug['v'])
Bprint(&bso, "%5.2f library: %s\n", cputime(), pname);
Bflush(&bso);
l = e[1] & 0xff;
l |= (e[2] & 0xff) << 8;
l |= (e[3] & 0xff) << 16;
l |= (e[4] & 0xff) << 24;
Bseek(f, l, 0);
l = Bread(f, &arhdr, SAR_HDR);
if(l != SAR_HDR)
goto bad;
if(strncmp(arhdr.fmag, ARFMAG, sizeof(arhdr.fmag)))
goto bad;
l = SARNAME;
while(l > 0 && arhdr.name[l-1] == ' ')
l--;
sprint(pname, "%s(%.*s)", file, l, arhdr.name);
l = atolwhex(arhdr.size);
ldobj(f, pkg, l, pname, ArchiveObj);
if(s->type == SXREF) {
diag("%s: failed to load: %s", file, s->name);
errorexit();
}
work = 1;
xrefresolv = 1;
} }
off += l;
l = SARNAME;
while(l > 0 && arhdr.name[l-1] == ' ')
l--;
snprint(pname, sizeof pname, "%s(%.*s)", file, utfnlen(arhdr.name, l), arhdr.name);
l = atolwhex(arhdr.size);
ldobj(f, pkg, l, pname, ArchiveObj);
} }
return;
bad:
diag("%s: bad or out of date archive", file);
out: out:
Bterm(f); Bterm(f);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment