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