diff options
Diffstat (limited to 'src/cmd/ld/lib.c')
-rw-r--r-- | src/cmd/ld/lib.c | 546 |
1 files changed, 357 insertions, 189 deletions
diff --git a/src/cmd/ld/lib.c b/src/cmd/ld/lib.c index 1af9f7a41..ae77247c3 100644 --- a/src/cmd/ld/lib.c +++ b/src/cmd/ld/lib.c @@ -1,5 +1,6 @@ -// Derived from Inferno utils/6l/obj.c +// Derived from Inferno utils/6l/obj.c and utils/6l/span.c // http://code.google.com/p/inferno-os/source/browse/utils/6l/obj.c +// http://code.google.com/p/inferno-os/source/browse/utils/6l/span.c // // Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. // Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) @@ -118,7 +119,7 @@ addlib(char *src, char *obj) } for(; i<histfrogp; i++) { - snprint(comp, sizeof comp, histfrog[i]->name+1); + snprint(comp, sizeof comp, "%s", histfrog[i]->name+1); for(;;) { p = strstr(comp, "$O"); if(p == 0) @@ -146,6 +147,22 @@ addlib(char *src, char *obj) strcat(name, comp); } 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) { // try dot, -L "libdir", and then goroot. @@ -159,8 +176,8 @@ addlib(char *src, char *obj) cleanname(pname); /* runtime.a -> runtime */ - if(strlen(name) > 2 && name[strlen(name)-2] == '.') - name[strlen(name)-2] = '\0'; + if(p != nil) + *p = '\0'; if(debug['v']) Bprint(&bso, "%5.2f addlib: %s %s pulls in %s\n", cputime(), obj, src, pname); @@ -186,9 +203,9 @@ addlibpath(char *srcref, char *objref, char *file, char *pkg) if(strcmp(file, library[i].file) == 0) return; - if(debug['v']) + if(debug['v'] > 1) 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){ nlibrary = 50 + 2*libraryp; @@ -219,8 +236,6 @@ loadlib(void) { char pname[1024]; int i, found; - int32 h; - Sym *s; found = 0; for(i=0; i<nlibdir; i++) { @@ -233,47 +248,51 @@ loadlib(void) 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++) { if(debug['v']) Bprint(&bso, "%5.2f autolib: %s (from %s)\n", cputime(), library[i].file, library[i].objref); objfile(library[i].file, library[i].pkg); } +} - if(xrefresolv) - for(h=0; h<nelem(hash); h++) - for(s = hash[h]; s != S; s = s->link) - if(s->type == SXREF) - goto loop; - +/* + * look for the next file in an archive. + * adapted from libmach. + */ +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 objfile(char *file, char *pkg) { - int32 off, esym, cnt, l; - int work; + int32 off, l; Biobuf *f; - Sym *s; char magbuf[SARMAG]; - char name[100], pname[150]; + char pname[150]; struct ar_hdr arhdr; - char *e, *start, *stop, *x; 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']) Bprint(&bso, "%5.2f ldobj: %s (%s)\n", cputime(), file, pkg); Bflush(&bso); @@ -291,9 +310,10 @@ objfile(char *file, char *pkg) Bterm(f); return; } - - l = Bread(f, &arhdr, SAR_HDR); - if(l != SAR_HDR) { + + /* skip over __.SYMDEF */ + off = Boffset(f); + if((l = nextar(f, off, &arhdr)) <= 0) { diag("%s: short read on archive file symbol header", file); goto out; } @@ -301,88 +321,52 @@ objfile(char *file, char *pkg) diag("%s: first entry not symbol header", file); goto out; } - - esym = SARMAG + SAR_HDR + atolwhex(arhdr.size); - off = SARMAG + SAR_HDR; - - if(debug['u']) { - struct ar_hdr pkghdr; - 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); + off += l; + + /* skip over (or process) __.PKGDEF */ + if((l = nextar(f, off, &arhdr)) <= 0) { + diag("%s: short read on archive file symbol header", file); + goto out; } + 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); - cnt = esym - off; - start = mal(cnt + 10); - cnt = Bread(f, start, cnt); - if(cnt <= 0){ - Bterm(f); - return; - } - 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; + for(;;) { + l = nextar(f, off, &arhdr); + if(l == 0) + break; + if(l < 0) { + diag("%s: malformed archive", file); + goto out; } + 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: Bterm(f); } @@ -390,32 +374,38 @@ out: void ldobj(Biobuf *f, char *pkg, int64 len, char *pn, int whence) { - static int files; - static char **filen; - char **nfilen, *line; - int i, n, c1, c2, c3; + char *line; + int n, c1, c2, c3, c4; + uint32 magic; vlong import0, import1, eof; char src[1024]; eof = Boffset(f) + len; src[0] = '\0'; - // don't load individual object more than once. - // happens with import of .6 files because of loop in xresolv. - // doesn't happen with .a because SYMDEF is consulted - // first to decide whether each individual object file is needed. - for(i=0; i<files; i++) - if(strcmp(filen[i], pn) == 0) - return; + pn = strdup(pn); + + USED(c4); + USED(magic); - if((files&15) == 0){ - nfilen = malloc((files+16)*sizeof(char*)); - memmove(nfilen, filen, files*sizeof(char*)); - free(filen); - filen = nfilen; + c1 = Bgetc(f); + c2 = Bgetc(f); + c3 = Bgetc(f); + c4 = Bgetc(f); + Bungetc(f); + Bungetc(f); + Bungetc(f); + Bungetc(f); + + magic = c1<<24 | c2<<16 | c3<<8 | c4; + if(magic == 0x7f454c46) { // \x7F E L F + ldelf(f, pkg, len, pn); + return; + } + if((magic&~1) == 0xfeedface || (magic&~0x01000000) == 0xcefaedfe) { + ldmacho(f, pkg, len, pn); + return; } - pn = strdup(pn); - filen[files++] = pn; /* check the header */ line = Brdline(f, '\n'); @@ -478,7 +468,7 @@ lookup(char *symb, int v) // not if(h < 0) h = ~h, because gcc 4.3 -O2 miscompiles it. h &= 0xffffff; h %= NHASH; - for(s = hash[h]; s != S; s = s->link) + for(s = hash[h]; s != S; s = s->hash) if(s->version == v) if(memcmp(s->name, symb, l) == 0) return s; @@ -487,14 +477,18 @@ lookup(char *symb, int v) if(debug['v'] > 1) Bprint(&bso, "lookup %s\n", symb); + s->dynid = -1; + s->plt = -1; + s->got = -1; s->name = mal(l + 1); memmove(s->name, symb, l); - s->link = hash[h]; + s->hash = hash[h]; s->type = 0; s->version = v; s->value = 0; s->sig = 0; + s->size = 0; hash[h] = s; nsymbol++; return s; @@ -607,8 +601,13 @@ nuxiinit(void) if(i < 1) inuxi1[i] = c; inuxi4[i] = c; - inuxi8[i] = c; - inuxi8[i+4] = c+4; + if(c == i) { + inuxi8[i] = c; + inuxi8[i+4] = c+4; + } else { + inuxi8[i] = c+4; + inuxi8[i+4] = c; + } fnuxi4[i] = c; fnuxi8[i] = c; fnuxi8[i+4] = c+4; @@ -732,21 +731,6 @@ ieeedtod(Ieee *ieeep) } void -undefsym(Sym *s) -{ - int n; - - n = imports; - if(s->value != 0) - diag("value != 0 on SXREF"); - if(n >= 1<<Rindex) - diag("import index %d out of range", n); - s->value = n<<Roffset; - s->type = SUNDEF; - imports++; -} - -void zerosig(char *sp) { Sym *s; @@ -755,47 +739,6 @@ zerosig(char *sp) s->sig = 0; } -void -readundefs(char *f, int t) -{ - int i, n; - Sym *s; - Biobuf *b; - char *l, buf[256], *fields[64]; - - if(f == nil) - return; - b = Bopen(f, OREAD); - if(b == nil){ - diag("could not open %s: %r", f); - errorexit(); - } - while((l = Brdline(b, '\n')) != nil){ - n = Blinelen(b); - if(n >= sizeof(buf)){ - diag("%s: line too long", f); - errorexit(); - } - memmove(buf, l, n); - buf[n-1] = '\0'; - n = getfields(buf, fields, nelem(fields), 1, " \t\r\n"); - if(n == nelem(fields)){ - diag("%s: bad format", f); - errorexit(); - } - for(i = 0; i < n; i++){ - s = lookup(fields[i], 0); - s->type = SXREF; - s->subtype = t; - if(t == SIMPORT) - nimports++; - else - nexports++; - } - } - Bterm(b); -} - int32 Bget4(Biobuf *f) { @@ -829,15 +772,22 @@ mal(uint32 n) { void *v; - while(n & 7) - n++; + n = (n+7)&~7; if(n > NHUNK) { v = malloc(n); + if(v == nil) { + diag("out of memory"); + errorexit(); + } memset(v, 0, n); return v; } if(n > nhunk) { hunk = malloc(NHUNK); + if(hunk == nil) { + diag("out of memory"); + errorexit(); + } nhunk = NHUNK; } @@ -849,6 +799,16 @@ mal(uint32 n) return v; } +void +unmal(void *v, uint32 n) +{ + n = (n+7)&~7; + if(hunk - n == v) { + hunk -= n; + nhunk += n; + } +} + // Copied from ../gc/subr.c:/^pathtoprefix; must stay in sync. /* * Convert raw string to the prefix that will be used in the symbol table. @@ -901,3 +861,211 @@ iconv(Fmt *fp) return 0; } +void +mangle(char *file) +{ + fprint(2, "%s: mangled input file\n", file); + errorexit(); +} + +Section* +addsection(Segment *seg, char *name, int rwx) +{ + Section **l; + Section *sect; + + for(l=&seg->sect; *l; l=&(*l)->next) + ; + sect = mal(sizeof *sect); + sect->rwx = rwx; + sect->name = name; + sect->seg = seg; + *l = sect; + return sect; +} + +void +ewrite(int fd, void *buf, int n) +{ + if(write(fd, buf, n) < 0) { + diag("write error: %r"); + errorexit(); + } +} + +void +pclntab(void) +{ + vlong oldpc; + Prog *p; + int32 oldlc, v, s; + Sym *sym; + uchar *bp; + + sym = lookup("pclntab", 0); + sym->type = SRODATA; + sym->reachable = 1; + if(debug['s']) + return; + + oldpc = INITTEXT; + oldlc = 0; + for(cursym = textp; cursym != nil; cursym = cursym->next) { + for(p = cursym->text; p != P; p = p->link) { + if(p->line == oldlc || p->as == ATEXT || p->as == ANOP) { + if(debug['O']) + Bprint(&bso, "%6llux %P\n", + (vlong)p->pc, p); + continue; + } + if(debug['O']) + Bprint(&bso, "\t\t%6d", lcsize); + v = (p->pc - oldpc) / MINLC; + while(v) { + s = 127; + if(v < 127) + s = v; + symgrow(sym, lcsize+1); + bp = sym->p + lcsize; + *bp = s+128; /* 129-255 +pc */ + if(debug['O']) + Bprint(&bso, " pc+%d*%d(%d)", s, MINLC, s+128); + v -= s; + lcsize++; + } + s = p->line - oldlc; + oldlc = p->line; + oldpc = p->pc + MINLC; + if(s > 64 || s < -64) { + symgrow(sym, lcsize+5); + bp = sym->p + lcsize; + *bp++ = 0; /* 0 vv +lc */ + *bp++ = s>>24; + *bp++ = s>>16; + *bp++ = s>>8; + *bp = s; + if(debug['O']) { + if(s > 0) + Bprint(&bso, " lc+%d(%d,%d)\n", + s, 0, s); + else + Bprint(&bso, " lc%d(%d,%d)\n", + s, 0, s); + Bprint(&bso, "%6llux %P\n", + (vlong)p->pc, p); + } + lcsize += 5; + continue; + } + symgrow(sym, lcsize+1); + bp = sym->p + lcsize; + if(s > 0) { + *bp = 0+s; /* 1-64 +lc */ + if(debug['O']) { + Bprint(&bso, " lc+%d(%d)\n", s, 0+s); + Bprint(&bso, "%6llux %P\n", + (vlong)p->pc, p); + } + } else { + *bp = 64-s; /* 65-128 -lc */ + if(debug['O']) { + Bprint(&bso, " lc%d(%d)\n", s, 64-s); + Bprint(&bso, "%6llux %P\n", + (vlong)p->pc, p); + } + } + lcsize++; + } + } + if(lcsize & 1) { + symgrow(sym, lcsize+1); + sym->p[lcsize] = 129; + lcsize++; + } + sym->size = lcsize; + lcsize = 0; + + if(debug['v'] || debug['O']) + Bprint(&bso, "lcsize = %d\n", lcsize); + Bflush(&bso); +} + +#define LOG 5 +void +mkfwd(void) +{ + Prog *p; + int i; + int32 dwn[LOG], cnt[LOG]; + Prog *lst[LOG], *last; + + for(i=0; i<LOG; i++) { + if(i == 0) + cnt[i] = 1; + else + cnt[i] = LOG * cnt[i-1]; + dwn[i] = 1; + lst[i] = P; + } + i = 0; + last = nil; + for(cursym = textp; cursym != nil; cursym = cursym->next) { + for(p = cursym->text; p != P; p = p->link) { + if(p->link == P) { + if(cursym->next) + p->forwd = cursym->next->text; + break; + } + i--; + if(i < 0) + i = LOG-1; + p->forwd = P; + dwn[i]--; + if(dwn[i] <= 0) { + dwn[i] = cnt[i]; + if(lst[i] != P) + lst[i]->forwd = p; + lst[i] = p; + } + } + } +} + +uint16 +le16(uchar *b) +{ + return b[0] | b[1]<<8; +} + +uint32 +le32(uchar *b) +{ + return b[0] | b[1]<<8 | b[2]<<16 | b[3]<<24; +} + +uint64 +le64(uchar *b) +{ + return le32(b) | (uint64)le32(b+4)<<32; +} + +uint16 +be16(uchar *b) +{ + return b[0]<<8 | b[1]; +} + +uint32 +be32(uchar *b) +{ + return b[0]<<24 | b[1]<<16 | b[2]<<8 | b[3]; +} + +uint64 +be64(uchar *b) +{ + return (uvlong)be32(b)<<32 | be32(b+4); +} + +Endian be = { be16, be32, be64 }; +Endian le = { le16, le32, le64 }; |