diff options
Diffstat (limited to 'src/cmd/ld')
-rw-r--r-- | src/cmd/ld/data.c | 714 | ||||
-rw-r--r-- | src/cmd/ld/decodesym.c | 109 | ||||
-rw-r--r-- | src/cmd/ld/doc.go | 4 | ||||
-rw-r--r-- | src/cmd/ld/dwarf.c | 602 | ||||
-rw-r--r-- | src/cmd/ld/dwarf.h | 8 | ||||
-rw-r--r-- | src/cmd/ld/elf.c | 277 | ||||
-rw-r--r-- | src/cmd/ld/elf.h | 15 | ||||
-rw-r--r-- | src/cmd/ld/go.c | 157 | ||||
-rw-r--r-- | src/cmd/ld/ldelf.c | 64 | ||||
-rw-r--r-- | src/cmd/ld/ldmacho.c | 56 | ||||
-rw-r--r-- | src/cmd/ld/ldpe.c | 60 | ||||
-rw-r--r-- | src/cmd/ld/lib.c | 1625 | ||||
-rw-r--r-- | src/cmd/ld/lib.h | 388 | ||||
-rw-r--r-- | src/cmd/ld/macho.c | 123 | ||||
-rw-r--r-- | src/cmd/ld/pass.c | 104 | ||||
-rw-r--r-- | src/cmd/ld/pcln.c | 244 | ||||
-rw-r--r-- | src/cmd/ld/pe.c | 212 | ||||
-rw-r--r-- | src/cmd/ld/pe.h | 2 | ||||
-rw-r--r-- | src/cmd/ld/pobj.c | 197 | ||||
-rw-r--r-- | src/cmd/ld/symtab.c | 244 | ||||
-rw-r--r-- | src/cmd/ld/textflag.h | 2 |
21 files changed, 1967 insertions, 3240 deletions
diff --git a/src/cmd/ld/data.c b/src/cmd/ld/data.c index 30d7c8185..55d020710 100644 --- a/src/cmd/ld/data.c +++ b/src/cmd/ld/data.c @@ -38,15 +38,14 @@ #include "../../pkg/runtime/mgc0.h" void dynreloc(void); -static vlong addaddrplus4(Sym *s, Sym *t, vlong add); /* * divide-and-conquer list-link - * sort of Sym* structures. + * sort of LSym* structures. * Used for the data block. */ int -datcmp(Sym *s1, Sym *s2) +datcmp(LSym *s1, LSym *s2) { if(s1->type != s2->type) return (int)s1->type - (int)s2->type; @@ -58,11 +57,11 @@ datcmp(Sym *s1, Sym *s2) return strcmp(s1->name, s2->name); } -Sym* -listsort(Sym *l, int (*cmp)(Sym*, Sym*), int off) +LSym* +listsort(LSym *l, int (*cmp)(LSym*, LSym*), int off) { - Sym *l1, *l2, *le; - #define NEXT(l) (*(Sym**)((char*)(l)+off)) + LSym *l1, *l2, *le; + #define NEXT(l) (*(LSym**)((char*)(l)+off)) if(l == 0 || NEXT(l) == 0) return l; @@ -128,32 +127,16 @@ listsort(Sym *l, int (*cmp)(Sym*, Sym*), int off) #undef NEXT } -Reloc* -addrel(Sym *s) -{ - if(s->nr >= s->maxr) { - if(s->maxr == 0) - s->maxr = 4; - else - s->maxr <<= 1; - s->r = erealloc(s->r, s->maxr*sizeof s->r[0]); - memset(s->r+s->nr, 0, (s->maxr-s->nr)*sizeof s->r[0]); - } - return &s->r[s->nr++]; -} - void -relocsym(Sym *s) +relocsym(LSym *s) { Reloc *r; - Sym *rs; - Prog p; + LSym *rs; int32 i, off, siz, fl; vlong o; uchar *cast; - cursym = s; - memset(&p, 0, sizeof p); + ctxt->cursym = s; for(r=s->r; r<s->r+s->nr; r++) { r->done = 1; off = r->off; @@ -168,10 +151,12 @@ relocsym(Sym *s) } if(r->type >= 256) continue; + if(r->siz == 0) // informational relocation - no work to do + continue; - if(r->sym != S && r->sym->type == SDYNIMPORT) + // Solaris needs the ability to reference dynimport symbols. + if(HEADTYPE != Hsolaris && r->sym != S && r->sym->type == SDYNIMPORT) diag("unhandled relocation for %s (type %d rtype %d)", r->sym->name, r->sym->type, r->type); - if(r->sym != S && r->sym->type != STLSBSS && !r->sym->reachable) diag("unreachable sym in relocation: %s %s", s->name, r->sym->name); @@ -181,13 +166,56 @@ relocsym(Sym *s) if(archreloc(r, s, &o) < 0) diag("unknown reloc %d", r->type); break; - case D_TLS: + case R_TLS: + if(linkmode == LinkInternal && iself && thechar == '5') { + // On ELF ARM, the thread pointer is 8 bytes before + // the start of the thread-local data block, so add 8 + // to the actual TLS offset (r->sym->value). + // This 8 seems to be a fundamental constant of + // ELF on ARM (or maybe Glibc on ARM); it is not + // related to the fact that our own TLS storage happens + // to take up 8 bytes. + o = 8 + r->sym->value; + break; + } r->done = 0; o = 0; if(thechar != '6') o = r->add; break; - case D_ADDR: + case R_TLS_LE: + if(linkmode == LinkExternal && iself && HEADTYPE != Hopenbsd) { + r->done = 0; + r->sym = ctxt->gmsym; + r->xsym = ctxt->gmsym; + r->xadd = r->add; + o = 0; + if(thechar != '6') + o = r->add; + break; + } + o = ctxt->tlsoffset + r->add; + break; + + case R_TLS_IE: + if(linkmode == LinkExternal && iself && HEADTYPE != Hopenbsd) { + r->done = 0; + r->sym = ctxt->gmsym; + r->xsym = ctxt->gmsym; + r->xadd = r->add; + o = 0; + if(thechar != '6') + o = r->add; + break; + } + if(iself || ctxt->headtype == Hplan9) + o = ctxt->tlsoffset + r->add; + else if(ctxt->headtype == Hwindows) + o = r->add; + else + sysfatal("unexpected R_TLS_IE relocation for %s", headstr(ctxt->headtype)); + break; + case R_ADDR: if(linkmode == LinkExternal && r->sym->type != SCONST) { r->done = 0; @@ -198,7 +226,7 @@ relocsym(Sym *s) r->xadd += symaddr(rs) - symaddr(rs->outer); rs = rs->outer; } - if(rs->type != SHOSTOBJ && rs->sect == nil) + if(rs->type != SHOSTOBJ && rs->type != SDYNIMPORT && rs->sect == nil) diag("missing section for %s", rs->name); r->xsym = rs; @@ -210,15 +238,26 @@ relocsym(Sym *s) if(rs->type != SHOSTOBJ) o += symaddr(rs); } else { - diag("unhandled pcrel relocation for %s", headtype); + diag("unhandled pcrel relocation for %s", headstring); } break; } o = symaddr(r->sym) + r->add; + + // On amd64, 4-byte offsets will be sign-extended, so it is impossible to + // access more than 2GB of static data; fail at link time is better than + // fail at runtime. See http://golang.org/issue/7980. + // Instead of special casing only amd64, we treat this as an error on all + // 64-bit architectures so as to be future-proof. + if((int32)o < 0 && PtrSize > 4 && siz == 4) { + diag("non-pc-relative relocation address is too big: %#llux", o); + errorexit(); + } break; - case D_PCREL: + case R_CALL: + case R_PCREL: // r->sym can be null when CALL $(constant) is transformed from absolute PC to relative PC call. - if(linkmode == LinkExternal && r->sym && r->sym->type != SCONST && r->sym->sect != cursym->sect) { + if(linkmode == LinkExternal && r->sym && r->sym->type != SCONST && r->sym->sect != ctxt->cursym->sect) { r->done = 0; // set up addend for eventual relocation via outer symbol. @@ -229,7 +268,7 @@ relocsym(Sym *s) rs = rs->outer; } r->xadd -= r->siz; // relative to address after the relocated chunk - if(rs->type != SHOSTOBJ && rs->sect == nil) + if(rs->type != SHOSTOBJ && rs->type != SDYNIMPORT && rs->sect == nil) diag("missing section for %s", rs->name); r->xsym = rs; @@ -242,7 +281,7 @@ relocsym(Sym *s) o += symaddr(rs) - rs->sect->vaddr; o -= r->off; // WTF? } else { - diag("unhandled pcrel relocation for %s", headtype); + diag("unhandled pcrel relocation for %s", headstring); } break; } @@ -257,17 +296,21 @@ relocsym(Sym *s) // the standard host compiler (gcc on most other systems). o += r->add - (s->value + r->off + (int32)r->siz); break; - case D_SIZE: + case R_SIZE: o = r->sym->size + r->add; break; } -//print("relocate %s %p %s => %p %p %p %p [%p]\n", s->name, s->value+off, r->sym ? r->sym->name : "<nil>", (void*)symaddr(r->sym), (void*)s->value, (void*)r->off, (void*)r->siz, (void*)o); +//print("relocate %s %#llux (%#llux+%#llux, size %d) => %s %#llux +%#llx [%llx]\n", s->name, (uvlong)(s->value+off), (uvlong)s->value, (uvlong)r->off, r->siz, r->sym ? r->sym->name : "<nil>", (uvlong)symaddr(r->sym), (vlong)r->add, (vlong)o); switch(siz) { default: - cursym = s; + ctxt->cursym = s; diag("bad reloc size %#ux for %s", siz, r->sym->name); + case 1: + // TODO(rsc): Remove. + s->p[off] = (int8)o; + break; case 4: - if(r->type == D_PCREL) { + if(r->type == R_PCREL || r->type == R_CALL) { if(o != (int32)o) diag("pc-relative relocation address is too big: %#llx", o); } else { @@ -291,31 +334,35 @@ relocsym(Sym *s) void reloc(void) { - Sym *s; + LSym *s; if(debug['v']) Bprint(&bso, "%5.2f reloc\n", cputime()); Bflush(&bso); - for(s=textp; s!=S; s=s->next) + for(s=ctxt->textp; s!=S; s=s->next) relocsym(s); for(s=datap; s!=S; s=s->next) relocsym(s); } void -dynrelocsym(Sym *s) +dynrelocsym(LSym *s) { Reloc *r; - + if(HEADTYPE == Hwindows) { - Sym *rel, *targ; + LSym *rel, *targ; - rel = lookup(".rel", 0); + rel = linklookup(ctxt, ".rel", 0); if(s == rel) return; for(r=s->r; r<s->r+s->nr; r++) { targ = r->sym; + if(targ == nil) + continue; + if(!targ->reachable) + diag("internal inconsistency: dynamic symbol %s is not reachable.", targ->name); if(r->sym->plt == -2 && r->sym->got != -2) { // make dynimport JMP table for PE object files. targ->plt = rel->size; r->sym = rel; @@ -323,17 +370,17 @@ dynrelocsym(Sym *s) // jmp *addr if(thechar == '8') { - adduint8(rel, 0xff); - adduint8(rel, 0x25); - addaddr(rel, targ); - adduint8(rel, 0x90); - adduint8(rel, 0x90); + adduint8(ctxt, rel, 0xff); + adduint8(ctxt, rel, 0x25); + addaddr(ctxt, rel, targ); + adduint8(ctxt, rel, 0x90); + adduint8(ctxt, rel, 0x90); } else { - adduint8(rel, 0xff); - adduint8(rel, 0x24); - adduint8(rel, 0x25); - addaddrplus4(rel, targ, 0); - adduint8(rel, 0x90); + adduint8(ctxt, rel, 0xff); + adduint8(ctxt, rel, 0x24); + adduint8(ctxt, rel, 0x25); + addaddrplus4(ctxt, rel, targ, 0); + adduint8(ctxt, rel, 0x90); } } else if(r->sym->plt >= 0) { r->sym = rel; @@ -344,15 +391,18 @@ dynrelocsym(Sym *s) } for(r=s->r; r<s->r+s->nr; r++) { - if(r->sym != S && r->sym->type == SDYNIMPORT || r->type >= 256) + if(r->sym != S && r->sym->type == SDYNIMPORT || r->type >= 256) { + if(r->sym != S && !r->sym->reachable) + diag("internal inconsistency: dynamic symbol %s is not reachable.", r->sym->name); adddynrel(s, r); + } } } void dynreloc(void) { - Sym *s; + LSym *s; // -d suppresses dynamic loader format, so we may as well not // compute these sections or mark their symbols as reachable. @@ -362,7 +412,7 @@ dynreloc(void) Bprint(&bso, "%5.2f reloc\n", cputime()); Bflush(&bso); - for(s=textp; s!=S; s=s->next) + for(s=ctxt->textp; s!=S; s=s->next) dynrelocsym(s); for(s=datap; s!=S; s=s->next) dynrelocsym(s); @@ -370,118 +420,10 @@ dynreloc(void) elfdynhash(); } -void -symgrow(Sym *s, int32 siz) -{ - if(s->np >= siz) - return; - - if(s->np > s->maxp) { - cursym = s; - diag("corrupt symbol data: np=%lld > maxp=%lld", (vlong)s->np, (vlong)s->maxp); - errorexit(); - } - - if(s->maxp < siz) { - if(s->maxp == 0) - s->maxp = 8; - while(s->maxp < siz) - s->maxp <<= 1; - s->p = erealloc(s->p, s->maxp); - memset(s->p+s->np, 0, s->maxp-s->np); - } - s->np = siz; -} - -void -savedata(Sym *s, Prog *p, char *pn) -{ - int32 off, siz, i, fl; - uchar *cast; - vlong o; - Reloc *r; - - off = p->from.offset; - siz = p->datasize; - if(off < 0 || siz < 0 || off >= 1<<30 || siz >= 100) - mangle(pn); - symgrow(s, off+siz); - - switch(p->to.type) { - default: - diag("bad data: %P", p); - break; - - case D_FCONST: - switch(siz) { - default: - case 4: - fl = ieeedtof(&p->to.ieee); - cast = (uchar*)&fl; - for(i=0; i<4; i++) - s->p[off+i] = cast[fnuxi4[i]]; - break; - case 8: - cast = (uchar*)&p->to.ieee; - for(i=0; i<8; i++) - s->p[off+i] = cast[fnuxi8[i]]; - break; - } - break; - - case D_SCONST: - for(i=0; i<siz; i++) - s->p[off+i] = p->to.scon[i]; - break; - - case D_CONST: - if(p->to.sym) - goto Addr; - o = p->to.offset; - fl = o; - cast = (uchar*)&fl; - switch(siz) { - default: - diag("bad nuxi %d\n%P", siz, p); - break; - case 1: - s->p[off] = cast[inuxi1[0]]; - break; - case 2: - for(i=0; i<2; i++) - s->p[off+i] = cast[inuxi2[i]]; - break; - case 4: - for(i=0; i<4; i++) - s->p[off+i] = cast[inuxi4[i]]; - break; - case 8: - cast = (uchar*)&o; - for(i=0; i<8; i++) - s->p[off+i] = cast[inuxi8[i]]; - break; - } - break; - - case D_ADDR: - case D_SIZE: - Addr: - r = addrel(s); - r->off = off; - r->siz = siz; - r->sym = p->to.sym; - r->type = p->to.type; - if(r->type != D_SIZE) - r->type = D_ADDR; - r->add = p->to.offset; - break; - } -} - static void -blk(Sym *start, int32 addr, int32 size) +blk(LSym *start, int32 addr, int32 size) { - Sym *sym; + LSym *sym; int32 eaddr; uchar *p, *ep; @@ -499,7 +441,7 @@ blk(Sym *start, int32 addr, int32 size) diag("phase error: addr=%#llx but sym=%#llx type=%d", (vlong)addr, (vlong)sym->value, sym->type); errorexit(); } - cursym = sym; + ctxt->cursym = sym; for(; addr < sym->value; addr++) cput(0); p = sym->p; @@ -523,21 +465,20 @@ blk(Sym *start, int32 addr, int32 size) void codeblk(int32 addr, int32 size) { - Sym *sym; - int32 eaddr, n, epc; - Prog *p; + LSym *sym; + int32 eaddr, n; uchar *q; if(debug['a']) Bprint(&bso, "codeblk [%#x,%#x) at offset %#llx\n", addr, addr+size, cpos()); - blk(textp, addr, size); + blk(ctxt->textp, addr, size); /* again for printing */ if(!debug['a']) return; - for(sym = textp; sym != nil; sym = sym->next) { + for(sym = ctxt->textp; sym != nil; sym = sym->next) { if(!sym->reachable) continue; if(sym->value >= addr) @@ -557,36 +498,20 @@ codeblk(int32 addr, int32 size) Bprint(&bso, " %.2ux", 0); Bprint(&bso, "\n"); } - p = sym->text; - if(p == nil) { - Bprint(&bso, "%.6llux\t%-20s | foreign text\n", (vlong)addr, sym->name); - n = sym->size; - q = sym->p; - - while(n >= 16) { - Bprint(&bso, "%.6ux\t%-20.16I\n", addr, q); - addr += 16; - q += 16; - n -= 16; - } - if(n > 0) - Bprint(&bso, "%.6ux\t%-20.*I\n", addr, (int)n, q); - addr += n; - continue; - } - Bprint(&bso, "%.6llux\t%-20s | %P\n", (vlong)sym->value, sym->name, p); - for(p = p->link; p != P; p = p->link) { - if(p->link != P) - epc = p->link->pc; - else - epc = sym->value + sym->size; - Bprint(&bso, "%.6llux\t", (uvlong)p->pc); - q = sym->p + p->pc - sym->value; - n = epc - p->pc; - Bprint(&bso, "%-20.*I | %P\n", (int)n, q, p); - addr += n; + Bprint(&bso, "%.6llux\t%-20s\n", (vlong)addr, sym->name); + n = sym->size; + q = sym->p; + + while(n >= 16) { + Bprint(&bso, "%.6ux\t%-20.16I\n", addr, q); + addr += 16; + q += 16; + n -= 16; } + if(n > 0) + Bprint(&bso, "%.6ux\t%-20.*I\n", addr, (int)n, q); + addr += n; } if(addr < eaddr) { @@ -600,7 +525,7 @@ codeblk(int32 addr, int32 size) void datblk(int32 addr, int32 size) { - Sym *sym; + LSym *sym; int32 i, eaddr; uchar *p, *ep; char *typ, *rsname; @@ -648,12 +573,15 @@ datblk(int32 addr, int32 size) rsname = r->sym->name; typ = "?"; switch(r->type) { - case D_ADDR: + case R_ADDR: typ = "addr"; break; - case D_PCREL: + case R_PCREL: typ = "pcrel"; break; + case R_CALL: + typ = "call"; + break; } Bprint(&bso, "\treloc %.8ux/%d %s %s+%#llx [%#llx]\n", (uint)(sym->value+r->off), r->siz, typ, rsname, (vlong)r->add, (vlong)(r->sym->value+r->add)); @@ -682,28 +610,28 @@ strnput(char *s, int n) void addstrdata(char *name, char *value) { - Sym *s, *sp; + LSym *s, *sp; char *p; p = smprint("%s.str", name); - sp = lookup(p, 0); + sp = linklookup(ctxt, p, 0); free(p); addstring(sp, value); - s = lookup(name, 0); + s = linklookup(ctxt, name, 0); s->size = 0; s->dupok = 1; - addaddr(s, sp); - adduint32(s, strlen(value)); + addaddr(ctxt, s, sp); + adduint32(ctxt, s, strlen(value)); if(PtrSize == 8) - adduint32(s, 0); // round struct to pointer width + adduint32(ctxt, s, 0); // round struct to pointer width // in case reachability has already been computed sp->reachable = s->reachable; } vlong -addstring(Sym *s, char *str) +addstring(LSym *s, char *str) { int n; int32 r; @@ -715,230 +643,18 @@ addstring(Sym *s, char *str) n = strlen(str)+1; if(strcmp(s->name, ".shstrtab") == 0) elfsetstring(str, r); - symgrow(s, r+n); + symgrow(ctxt, s, r+n); memmove(s->p+r, str, n); s->size += n; return r; } -vlong -setuintxx(Sym *s, vlong off, uint64 v, vlong wid) -{ - int32 i, fl; - vlong o; - uchar *cast; - - if(s->type == 0) - s->type = SDATA; - s->reachable = 1; - if(s->size < off+wid) { - s->size = off+wid; - symgrow(s, s->size); - } - fl = v; - cast = (uchar*)&fl; - switch(wid) { - case 1: - s->p[off] = cast[inuxi1[0]]; - break; - case 2: - for(i=0; i<2; i++) - s->p[off+i] = cast[inuxi2[i]]; - break; - case 4: - for(i=0; i<4; i++) - s->p[off+i] = cast[inuxi4[i]]; - break; - case 8: - o = v; - cast = (uchar*)&o; - for(i=0; i<8; i++) - s->p[off+i] = cast[inuxi8[i]]; - break; - } - return off+wid; -} - -vlong -adduintxx(Sym *s, uint64 v, int wid) -{ - vlong off; - - off = s->size; - setuintxx(s, off, v, wid); - return off; -} - -vlong -adduint8(Sym *s, uint8 v) -{ - return adduintxx(s, v, 1); -} - -vlong -adduint16(Sym *s, uint16 v) -{ - return adduintxx(s, v, 2); -} - -vlong -adduint32(Sym *s, uint32 v) -{ - return adduintxx(s, v, 4); -} - -vlong -adduint64(Sym *s, uint64 v) -{ - return adduintxx(s, v, 8); -} - -vlong -setuint8(Sym *s, vlong r, uint8 v) -{ - return setuintxx(s, r, v, 1); -} - -vlong -setuint16(Sym *s, vlong r, uint16 v) -{ - return setuintxx(s, r, v, 2); -} - -vlong -setuint32(Sym *s, vlong r, uint32 v) -{ - return setuintxx(s, r, v, 4); -} - -vlong -setuint64(Sym *s, vlong r, uint64 v) -{ - return setuintxx(s, r, v, 8); -} - -vlong -addaddrplus(Sym *s, Sym *t, vlong add) -{ - vlong i; - Reloc *r; - - if(s->type == 0) - s->type = SDATA; - s->reachable = 1; - i = s->size; - s->size += PtrSize; - symgrow(s, s->size); - r = addrel(s); - r->sym = t; - r->off = i; - r->siz = PtrSize; - r->type = D_ADDR; - r->add = add; - return i + r->siz; -} - -static vlong -addaddrplus4(Sym *s, Sym *t, vlong add) -{ - vlong i; - Reloc *r; - - if(s->type == 0) - s->type = SDATA; - s->reachable = 1; - i = s->size; - s->size += 4; - symgrow(s, s->size); - r = addrel(s); - r->sym = t; - r->off = i; - r->siz = 4; - r->type = D_ADDR; - r->add = add; - return i + r->siz; -} - -vlong -addpcrelplus(Sym *s, Sym *t, vlong add) -{ - vlong i; - Reloc *r; - - if(s->type == 0) - s->type = SDATA; - s->reachable = 1; - i = s->size; - s->size += 4; - symgrow(s, s->size); - r = addrel(s); - r->sym = t; - r->off = i; - r->add = add; - r->type = D_PCREL; - r->siz = 4; - return i + r->siz; -} - -vlong -addaddr(Sym *s, Sym *t) -{ - return addaddrplus(s, t, 0); -} - -vlong -setaddrplus(Sym *s, vlong off, Sym *t, vlong add) -{ - Reloc *r; - - if(s->type == 0) - s->type = SDATA; - s->reachable = 1; - if(off+PtrSize > s->size) { - s->size = off + PtrSize; - symgrow(s, s->size); - } - r = addrel(s); - r->sym = t; - r->off = off; - r->siz = PtrSize; - r->type = D_ADDR; - r->add = add; - return off + r->siz; -} - -vlong -setaddr(Sym *s, vlong off, Sym *t) -{ - return setaddrplus(s, off, t, 0); -} - -vlong -addsize(Sym *s, Sym *t) -{ - vlong i; - Reloc *r; - - if(s->type == 0) - s->type = SDATA; - s->reachable = 1; - i = s->size; - s->size += PtrSize; - symgrow(s, s->size); - r = addrel(s); - r->sym = t; - r->off = i; - r->siz = PtrSize; - r->type = D_SIZE; - return i + r->siz; -} - void dosymtype(void) { - Sym *s; + LSym *s; - for(s = allsym; s != nil; s = s->allsym) { + for(s = ctxt->allsym; s != nil; s = s->allsym) { if(s->np > 0) { if(s->type == SBSS) s->type = SDATA; @@ -949,7 +665,7 @@ dosymtype(void) } static int32 -symalign(Sym *s) +symalign(LSym *s) { int32 align; @@ -965,7 +681,7 @@ symalign(Sym *s) } static vlong -aligndatsize(vlong datsize, Sym *s) +aligndatsize(vlong datsize, LSym *s) { return rnd(datsize, symalign(s)); } @@ -973,7 +689,7 @@ aligndatsize(vlong datsize, Sym *s) // maxalign returns the maximum required alignment for // the list of symbols s; the list stops when s->type exceeds type. static int32 -maxalign(Sym *s, int type) +maxalign(LSym *s, int type) { int32 align, max; @@ -987,10 +703,10 @@ maxalign(Sym *s, int type) } static void -gcaddsym(Sym *gc, Sym *s, vlong off) +gcaddsym(LSym *gc, LSym *s, vlong off) { vlong a; - Sym *gotype; + LSym *gotype; if(s->size < PtrSize) return; @@ -1000,22 +716,22 @@ gcaddsym(Sym *gc, Sym *s, vlong off) gotype = s->gotype; if(gotype != nil) { //print("gcaddsym: %s %d %s\n", s->name, s->size, gotype->name); - adduintxx(gc, GC_CALL, PtrSize); - adduintxx(gc, off, PtrSize); - addpcrelplus(gc, decodetype_gc(gotype), 3*PtrSize+4); + adduintxx(ctxt, gc, GC_CALL, PtrSize); + adduintxx(ctxt, gc, off, PtrSize); + addpcrelplus(ctxt, gc, decodetype_gc(gotype), 3*PtrSize+4); if(PtrSize == 8) - adduintxx(gc, 0, 4); + adduintxx(ctxt, gc, 0, 4); } else { //print("gcaddsym: %s %d <unknown type>\n", s->name, s->size); for(a = -off&(PtrSize-1); a+PtrSize<=s->size; a+=PtrSize) { - adduintxx(gc, GC_APTR, PtrSize); - adduintxx(gc, off+a, PtrSize); + adduintxx(ctxt, gc, GC_APTR, PtrSize); + adduintxx(ctxt, gc, off+a, PtrSize); } } } void -growdatsize(vlong *datsizep, Sym *s) +growdatsize(vlong *datsizep, LSym *s) { vlong datsize; @@ -1034,27 +750,30 @@ dodata(void) vlong datsize; Section *sect; Segment *segro; - Sym *s, *last, **l; - Sym *gcdata1, *gcbss1; + LSym *s, *last, **l; + LSym *gcdata1, *gcbss1; if(debug['v']) Bprint(&bso, "%5.2f dodata\n", cputime()); Bflush(&bso); - gcdata1 = lookup("gcdata", 0); - gcbss1 = lookup("gcbss", 0); + gcdata1 = linklookup(ctxt, "gcdata", 0); + gcbss1 = linklookup(ctxt, "gcbss", 0); // size of .data and .bss section. the zero value is later replaced by the actual size of the section. - adduintxx(gcdata1, 0, PtrSize); - adduintxx(gcbss1, 0, PtrSize); + adduintxx(ctxt, gcdata1, 0, PtrSize); + adduintxx(ctxt, gcbss1, 0, PtrSize); last = nil; datap = nil; - for(s=allsym; s!=S; s=s->allsym) { + for(s=ctxt->allsym; s!=S; s=s->allsym) { if(!s->reachable || s->special) continue; if(STEXT < s->type && s->type < SXREF) { + if(s->onlist) + sysfatal("symbol %s listed multiple times", s->name); + s->onlist = 1; if(last == nil) datap = s; else @@ -1092,7 +811,7 @@ dodata(void) } *l = nil; - datap = listsort(datap, datcmp, offsetof(Sym, next)); + datap = listsort(datap, datcmp, offsetof(LSym, next)); /* * allocate sections. list is sorted by type, @@ -1128,8 +847,8 @@ dodata(void) sect->align = maxalign(s, SINITARR-1); datsize = rnd(datsize, sect->align); sect->vaddr = datsize; - lookup("noptrdata", 0)->sect = sect; - lookup("enoptrdata", 0)->sect = sect; + linklookup(ctxt, "noptrdata", 0)->sect = sect; + linklookup(ctxt, "enoptrdata", 0)->sect = sect; for(; s != nil && s->type < SINITARR; s = s->next) { datsize = aligndatsize(datsize, s); s->sect = sect; @@ -1159,11 +878,11 @@ dodata(void) sect->align = maxalign(s, SBSS-1); datsize = rnd(datsize, sect->align); sect->vaddr = datsize; - lookup("data", 0)->sect = sect; - lookup("edata", 0)->sect = sect; + linklookup(ctxt, "data", 0)->sect = sect; + linklookup(ctxt, "edata", 0)->sect = sect; for(; s != nil && s->type < SBSS; s = s->next) { if(s->type == SINITARR) { - cursym = s; + ctxt->cursym = s; diag("unexpected symbol type %d", s->type); } s->sect = sect; @@ -1175,16 +894,16 @@ dodata(void) } sect->len = datsize - sect->vaddr; - adduintxx(gcdata1, GC_END, PtrSize); - setuintxx(gcdata1, 0, sect->len, PtrSize); + adduintxx(ctxt, gcdata1, GC_END, PtrSize); + setuintxx(ctxt, gcdata1, 0, sect->len, PtrSize); /* bss */ sect = addsection(&segdata, ".bss", 06); sect->align = maxalign(s, SNOPTRBSS-1); datsize = rnd(datsize, sect->align); sect->vaddr = datsize; - lookup("bss", 0)->sect = sect; - lookup("ebss", 0)->sect = sect; + linklookup(ctxt, "bss", 0)->sect = sect; + linklookup(ctxt, "ebss", 0)->sect = sect; for(; s != nil && s->type < SNOPTRBSS; s = s->next) { s->sect = sect; datsize = aligndatsize(datsize, s); @@ -1194,16 +913,16 @@ dodata(void) } sect->len = datsize - sect->vaddr; - adduintxx(gcbss1, GC_END, PtrSize); - setuintxx(gcbss1, 0, sect->len, PtrSize); + adduintxx(ctxt, gcbss1, GC_END, PtrSize); + setuintxx(ctxt, gcbss1, 0, sect->len, PtrSize); /* pointer-free bss */ sect = addsection(&segdata, ".noptrbss", 06); sect->align = maxalign(s, SNOPTRBSS); datsize = rnd(datsize, sect->align); sect->vaddr = datsize; - lookup("noptrbss", 0)->sect = sect; - lookup("enoptrbss", 0)->sect = sect; + linklookup(ctxt, "noptrbss", 0)->sect = sect; + linklookup(ctxt, "enoptrbss", 0)->sect = sect; for(; s != nil && s->type == SNOPTRBSS; s = s->next) { datsize = aligndatsize(datsize, s); s->sect = sect; @@ -1211,7 +930,7 @@ dodata(void) growdatsize(&datsize, s); } sect->len = datsize - sect->vaddr; - lookup("end", 0)->sect = sect; + linklookup(ctxt, "end", 0)->sect = sect; // 6g uses 4-byte relocation offsets, so the entire segment must fit in 32 bits. if(datsize != (uint32)datsize) { @@ -1230,10 +949,18 @@ dodata(void) growdatsize(&datsize, s); } sect->len = datsize; + } else { + // Might be internal linking but still using cgo. + // In that case, the only possible STLSBSS symbol is tlsgm. + // Give it offset 0, because it's the only thing here. + if(s != nil && s->type == STLSBSS && strcmp(s->name, "runtime.tlsgm") == 0) { + s->value = 0; + s = s->next; + } } if(s != nil) { - cursym = nil; + ctxt->cursym = nil; diag("unexpected symbol type %d for %s", s->type, s->name); } @@ -1274,8 +1001,8 @@ dodata(void) sect->align = maxalign(s, STYPELINK-1); datsize = rnd(datsize, sect->align); sect->vaddr = 0; - lookup("rodata", 0)->sect = sect; - lookup("erodata", 0)->sect = sect; + linklookup(ctxt, "rodata", 0)->sect = sect; + linklookup(ctxt, "erodata", 0)->sect = sect; for(; s != nil && s->type < STYPELINK; s = s->next) { datsize = aligndatsize(datsize, s); s->sect = sect; @@ -1290,8 +1017,8 @@ dodata(void) sect->align = maxalign(s, STYPELINK); datsize = rnd(datsize, sect->align); sect->vaddr = datsize; - lookup("typelink", 0)->sect = sect; - lookup("etypelink", 0)->sect = sect; + linklookup(ctxt, "typelink", 0)->sect = sect; + linklookup(ctxt, "etypelink", 0)->sect = sect; for(; s != nil && s->type == STYPELINK; s = s->next) { datsize = aligndatsize(datsize, s); s->sect = sect; @@ -1306,8 +1033,8 @@ dodata(void) sect->align = maxalign(s, SPCLNTAB-1); datsize = rnd(datsize, sect->align); sect->vaddr = datsize; - lookup("symtab", 0)->sect = sect; - lookup("esymtab", 0)->sect = sect; + linklookup(ctxt, "symtab", 0)->sect = sect; + linklookup(ctxt, "esymtab", 0)->sect = sect; for(; s != nil && s->type < SPCLNTAB; s = s->next) { datsize = aligndatsize(datsize, s); s->sect = sect; @@ -1322,8 +1049,8 @@ dodata(void) sect->align = maxalign(s, SELFROSECT-1); datsize = rnd(datsize, sect->align); sect->vaddr = datsize; - lookup("pclntab", 0)->sect = sect; - lookup("epclntab", 0)->sect = sect; + linklookup(ctxt, "pclntab", 0)->sect = sect; + linklookup(ctxt, "epclntab", 0)->sect = sect; for(; s != nil && s->type < SELFROSECT; s = s->next) { datsize = aligndatsize(datsize, s); s->sect = sect; @@ -1366,9 +1093,8 @@ void textaddress(void) { uvlong va; - Prog *p; Section *sect; - Sym *sym, *sub; + LSym *sym, *sub; addsection(&segtext, ".text", 05); @@ -1376,28 +1102,24 @@ textaddress(void) // Could parallelize, by assigning to text // and then letting threads copy down, but probably not worth it. sect = segtext.sect; - sect->align = FuncAlign; - lookup("text", 0)->sect = sect; - lookup("etext", 0)->sect = sect; + sect->align = funcalign; + linklookup(ctxt, "text", 0)->sect = sect; + linklookup(ctxt, "etext", 0)->sect = sect; va = INITTEXT; sect->vaddr = va; - for(sym = textp; sym != nil; sym = sym->next) { + for(sym = ctxt->textp; sym != nil; sym = sym->next) { sym->sect = sect; if(sym->type & SSUB) continue; if(sym->align != 0) va = rnd(va, sym->align); - else if(sym->text != P) - va = rnd(va, FuncAlign); + else + va = rnd(va, funcalign); sym->value = 0; - for(sub = sym; sub != S; sub = sub->sub) { + for(sub = sym; sub != S; sub = sub->sub) sub->value += va; - for(p = sub->text; p != P; p = p->link) - p->pc += sub->value; - } - if(sym->size == 0 && sym->sub != S) { - cursym = sym; - } + if(sym->size == 0 && sym->sub != S) + ctxt->cursym = sym; va += sym->size; } sect->len = va - sect->vaddr; @@ -1409,7 +1131,7 @@ address(void) { Section *s, *text, *data, *rodata, *symtab, *pclntab, *noptr, *bss, *noptrbss; Section *typelink; - Sym *sym, *sub; + LSym *sym, *sub; uvlong va; vlong vlen; @@ -1418,13 +1140,14 @@ address(void) segtext.vaddr = va; segtext.fileoff = HEADR; for(s=segtext.sect; s != nil; s=s->next) { -//print("%s at %#llux + %#llux\n", s->name, va, (vlong)s->len); va = rnd(va, s->align); s->vaddr = va; va += s->len; } segtext.len = va - INITTEXT; segtext.filelen = segtext.len; + if(HEADTYPE == Hnacl) + va += 32; // room for the "halt sled" if(segrodata.sect != nil) { // align to page boundary so as not to mix @@ -1451,7 +1174,7 @@ address(void) segdata.filelen = 0; if(HEADTYPE == Hwindows) segdata.fileoff = segtext.fileoff + rnd(segtext.len, PEFILEALIGN); - if(HEADTYPE == Hplan9x64 || HEADTYPE == Hplan9x32) + if(HEADTYPE == Hplan9) segdata.fileoff = segtext.fileoff + segtext.filelen; data = nil; noptr = nil; @@ -1485,8 +1208,9 @@ address(void) pclntab = symtab->next; for(sym = datap; sym != nil; sym = sym->next) { - cursym = sym; - sym->value += sym->sect->vaddr; + ctxt->cursym = sym; + if(sym->sect != nil) + sym->value += sym->sect->vaddr; for(sub = sym->sub; sub != nil; sub = sub->sub) sub->value += sym->value; } @@ -1498,13 +1222,13 @@ address(void) xdefine("typelink", SRODATA, typelink->vaddr); xdefine("etypelink", SRODATA, typelink->vaddr + typelink->len); - sym = lookup("gcdata", 0); + sym = linklookup(ctxt, "gcdata", 0); xdefine("egcdata", SRODATA, symaddr(sym) + sym->size); - lookup("egcdata", 0)->sect = sym->sect; + linklookup(ctxt, "egcdata", 0)->sect = sym->sect; - sym = lookup("gcbss", 0); + sym = linklookup(ctxt, "gcbss", 0); xdefine("egcbss", SRODATA, symaddr(sym) + sym->size); - lookup("egcbss", 0)->sect = sym->sect; + linklookup(ctxt, "egcbss", 0)->sect = sym->sect; xdefine("symtab", SRODATA, symtab->vaddr); xdefine("esymtab", SRODATA, symtab->vaddr + symtab->len); diff --git a/src/cmd/ld/decodesym.c b/src/cmd/ld/decodesym.c index ab3f4fbd5..da48d3786 100644 --- a/src/cmd/ld/decodesym.c +++ b/src/cmd/ld/decodesym.c @@ -11,7 +11,7 @@ // ../gc/reflect.c stuffs in these. static Reloc* -decode_reloc(Sym *s, int32 off) +decode_reloc(LSym *s, int32 off) { int i; @@ -21,8 +21,8 @@ decode_reloc(Sym *s, int32 off) return nil; } -static Sym* -decode_reloc_sym(Sym *s, int32 off) +static LSym* +decode_reloc_sym(LSym *s, int32 off) { Reloc *r; @@ -67,103 +67,109 @@ decode_inuxi(uchar* p, int sz) return l; } +static int +commonsize(void) +{ + return 7*PtrSize + 8; +} + // Type.commonType.kind uint8 -decodetype_kind(Sym *s) +decodetype_kind(LSym *s) { return s->p[1*PtrSize + 7] & ~KindNoPointers; // 0x13 / 0x1f } // Type.commonType.size vlong -decodetype_size(Sym *s) +decodetype_size(LSym *s) { return decode_inuxi(s->p, PtrSize); // 0x8 / 0x10 } // Type.commonType.gc -Sym* -decodetype_gc(Sym *s) +LSym* +decodetype_gc(LSym *s) { return decode_reloc_sym(s, 1*PtrSize + 8 + 1*PtrSize); } // Type.ArrayType.elem and Type.SliceType.Elem -Sym* -decodetype_arrayelem(Sym *s) +LSym* +decodetype_arrayelem(LSym *s) { - return decode_reloc_sym(s, CommonSize); // 0x1c / 0x30 + return decode_reloc_sym(s, commonsize()); // 0x1c / 0x30 } vlong -decodetype_arraylen(Sym *s) +decodetype_arraylen(LSym *s) { - return decode_inuxi(s->p + CommonSize+PtrSize, PtrSize); + return decode_inuxi(s->p + commonsize()+PtrSize, PtrSize); } // Type.PtrType.elem -Sym* -decodetype_ptrelem(Sym *s) +LSym* +decodetype_ptrelem(LSym *s) { - return decode_reloc_sym(s, CommonSize); // 0x1c / 0x30 + return decode_reloc_sym(s, commonsize()); // 0x1c / 0x30 } // Type.MapType.key, elem -Sym* -decodetype_mapkey(Sym *s) +LSym* +decodetype_mapkey(LSym *s) { - return decode_reloc_sym(s, CommonSize); // 0x1c / 0x30 + return decode_reloc_sym(s, commonsize()); // 0x1c / 0x30 } -Sym* -decodetype_mapvalue(Sym *s) +LSym* +decodetype_mapvalue(LSym *s) { - return decode_reloc_sym(s, CommonSize+PtrSize); // 0x20 / 0x38 + return decode_reloc_sym(s, commonsize()+PtrSize); // 0x20 / 0x38 } // Type.ChanType.elem -Sym* -decodetype_chanelem(Sym *s) +LSym* +decodetype_chanelem(LSym *s) { - return decode_reloc_sym(s, CommonSize); // 0x1c / 0x30 + return decode_reloc_sym(s, commonsize()); // 0x1c / 0x30 } // Type.FuncType.dotdotdot int -decodetype_funcdotdotdot(Sym *s) +decodetype_funcdotdotdot(LSym *s) { - return s->p[CommonSize]; + return s->p[commonsize()]; } // Type.FuncType.in.len int -decodetype_funcincount(Sym *s) +decodetype_funcincount(LSym *s) { - return decode_inuxi(s->p + CommonSize+2*PtrSize, IntSize); + return decode_inuxi(s->p + commonsize()+2*PtrSize, IntSize); } int -decodetype_funcoutcount(Sym *s) +decodetype_funcoutcount(LSym *s) { - return decode_inuxi(s->p + CommonSize+3*PtrSize + 2*IntSize, IntSize); + return decode_inuxi(s->p + commonsize()+3*PtrSize + 2*IntSize, IntSize); } -Sym* -decodetype_funcintype(Sym *s, int i) +LSym* +decodetype_funcintype(LSym *s, int i) { Reloc *r; - r = decode_reloc(s, CommonSize + PtrSize); + r = decode_reloc(s, commonsize() + PtrSize); if (r == nil) return nil; return decode_reloc_sym(r->sym, r->add + i * PtrSize); } -Sym* -decodetype_funcouttype(Sym *s, int i) +LSym* +decodetype_funcouttype(LSym *s, int i) { Reloc *r; - r = decode_reloc(s, CommonSize + 2*PtrSize + 2*IntSize); + r = decode_reloc(s, commonsize() + 2*PtrSize + 2*IntSize); if (r == nil) return nil; return decode_reloc_sym(r->sym, r->add + i * PtrSize); @@ -171,22 +177,25 @@ decodetype_funcouttype(Sym *s, int i) // Type.StructType.fields.Slice::len int -decodetype_structfieldcount(Sym *s) +decodetype_structfieldcount(LSym *s) +{ + return decode_inuxi(s->p + commonsize() + PtrSize, IntSize); +} + +static int +structfieldsize(void) { - return decode_inuxi(s->p + CommonSize + PtrSize, IntSize); + return 5*PtrSize; } -enum { - StructFieldSize = 5*PtrSize -}; // Type.StructType.fields[]-> name, typ and offset. char* -decodetype_structfieldname(Sym *s, int i) +decodetype_structfieldname(LSym *s, int i) { Reloc *r; // go.string."foo" 0x28 / 0x40 - s = decode_reloc_sym(s, CommonSize + PtrSize + 2*IntSize + i*StructFieldSize); + s = decode_reloc_sym(s, commonsize() + PtrSize + 2*IntSize + i*structfieldsize()); if (s == nil) // embedded structs have a nil name. return nil; r = decode_reloc(s, 0); // s has a pointer to the string data at offset 0 @@ -195,21 +204,21 @@ decodetype_structfieldname(Sym *s, int i) return (char*) r->sym->p + r->add; // the c-string } -Sym* -decodetype_structfieldtype(Sym *s, int i) +LSym* +decodetype_structfieldtype(LSym *s, int i) { - return decode_reloc_sym(s, CommonSize + PtrSize + 2*IntSize + i*StructFieldSize + 2*PtrSize); + return decode_reloc_sym(s, commonsize() + PtrSize + 2*IntSize + i*structfieldsize() + 2*PtrSize); } vlong -decodetype_structfieldoffs(Sym *s, int i) +decodetype_structfieldoffs(LSym *s, int i) { - return decode_inuxi(s->p + CommonSize + PtrSize + 2*IntSize + i*StructFieldSize + 4*PtrSize, IntSize); + return decode_inuxi(s->p + commonsize() + PtrSize + 2*IntSize + i*structfieldsize() + 4*PtrSize, IntSize); } // InterfaceTYpe.methods.len vlong -decodetype_ifacemethodcount(Sym *s) +decodetype_ifacemethodcount(LSym *s) { - return decode_inuxi(s->p + CommonSize + PtrSize, IntSize); + return decode_inuxi(s->p + commonsize() + PtrSize, IntSize); } diff --git a/src/cmd/ld/doc.go b/src/cmd/ld/doc.go index 2adda25f2..8135bd549 100644 --- a/src/cmd/ld/doc.go +++ b/src/cmd/ld/doc.go @@ -43,6 +43,8 @@ Options new in this version: Write NetBSD ELF binaries (default when $GOOS is netbsd) -H openbsd (only in 6l/8l) Write OpenBSD ELF binaries (default when $GOOS is openbsd) + -H solaris (only in 6l) + Write Solaris ELF binaries (default when $GOOS is solaris) -H windows (only in 6l/8l) Write Windows PE32+ Console binaries (default when $GOOS is windows) -H windowsgui (only in 6l/8l) @@ -58,6 +60,8 @@ Options new in this version: Omit the symbol table and debug information. -V Print the linker version. + -w + Omit the DWARF symbol table. -X symbol value Set the value of an otherwise uninitialized string variable. The symbol name should be of the form importpath.name, diff --git a/src/cmd/ld/dwarf.c b/src/cmd/ld/dwarf.c index c832bcc94..cc77b45cd 100644 --- a/src/cmd/ld/dwarf.c +++ b/src/cmd/ld/dwarf.c @@ -27,19 +27,19 @@ static vlong abbrevo; static vlong abbrevsize; -static Sym* abbrevsym; +static LSym* abbrevsym; static vlong abbrevsympos; static vlong lineo; static vlong linesize; -static Sym* linesym; +static LSym* linesym; static vlong linesympos; static vlong infoo; // also the base for DWDie->offs and reference attributes. static vlong infosize; -static Sym* infosym; +static LSym* infosym; static vlong infosympos; static vlong frameo; static vlong framesize; -static Sym* framesym; +static LSym* framesym; static vlong framesympos; static vlong pubnameso; static vlong pubnamessize; @@ -50,19 +50,19 @@ static vlong arangessize; static vlong gdbscripto; static vlong gdbscriptsize; -static Sym *infosec; +static LSym *infosec; static vlong inforeloco; static vlong inforelocsize; -static Sym *arangessec; +static LSym *arangessec; static vlong arangesreloco; static vlong arangesrelocsize; -static Sym *linesec; +static LSym *linesec; static vlong linereloco; static vlong linerelocsize; -static Sym *framesec; +static LSym *framesec; static vlong framereloco; static vlong framerelocsize; @@ -594,7 +594,7 @@ find_or_diag(DWDie *die, char* name) } static void -adddwarfrel(Sym* sec, Sym* sym, vlong offsetbase, int siz, vlong addend) +adddwarfrel(LSym* sec, LSym* sym, vlong offsetbase, int siz, vlong addend) { Reloc *r; @@ -603,7 +603,7 @@ adddwarfrel(Sym* sec, Sym* sym, vlong offsetbase, int siz, vlong addend) r->xsym = sym; r->off = cpos() - offsetbase; r->siz = siz; - r->type = D_ADDR; + r->type = R_ADDR; r->add = addend; r->xadd = addend; if(iself && thechar == '6') @@ -639,8 +639,8 @@ putattr(int abbrev, int form, int cls, vlong value, char *data) switch(form) { case DW_FORM_addr: // address if(linkmode == LinkExternal) { - value -= ((Sym*)data)->value; - adddwarfrel(infosec, (Sym*)data, infoo, PtrSize, value); + value -= ((LSym*)data)->value; + adddwarfrel(infosec, (LSym*)data, infoo, PtrSize, value); break; } addrput(value); @@ -651,8 +651,8 @@ putattr(int abbrev, int form, int cls, vlong value, char *data) cput(1+PtrSize); cput(DW_OP_addr); if(linkmode == LinkExternal) { - value -= ((Sym*)data)->value; - adddwarfrel(infosec, (Sym*)data, infoo, PtrSize, value); + value -= ((LSym*)data)->value; + adddwarfrel(infosec, (LSym*)data, infoo, PtrSize, value); break; } addrput(value); @@ -847,7 +847,7 @@ newmemberoffsetattr(DWDie *die, int32 offs) // GDB doesn't like DW_FORM_addr for DW_AT_location, so emit a // location expression that evals to a const. static void -newabslocexprattr(DWDie *die, vlong addr, Sym *sym) +newabslocexprattr(DWDie *die, vlong addr, LSym *sym) { newattr(die, DW_AT_location, DW_CLS_ADDRESS, addr, (char*)sym); } @@ -864,12 +864,12 @@ enum { static DWDie* defptrto(DWDie *dwtype); // below // Lookup predefined types -static Sym* +static LSym* lookup_or_diag(char *n) { - Sym *s; + LSym *s; - s = rlookup(n, 0); + s = linkrlookup(ctxt, n, 0); if (s == nil || s->size == 0) { diag("dwarf: missing type: %s", n); errorexit(); @@ -904,10 +904,10 @@ dotypedef(DWDie *parent, char *name, DWDie *def) // Define gotype, for composite ones recurse into constituents. static DWDie* -defgotype(Sym *gotype) +defgotype(LSym *gotype) { DWDie *die, *fld; - Sym *s; + LSym *s; char *name, *f; uint8 kind; vlong bytesize; @@ -1099,21 +1099,29 @@ defptrto(DWDie *dwtype) } // Copies src's children into dst. Copies attributes by value. -// DWAttr.data is copied as pointer only. +// DWAttr.data is copied as pointer only. If except is one of +// the top-level children, it will not be copied. static void -copychildren(DWDie *dst, DWDie *src) +copychildrenexcept(DWDie *dst, DWDie *src, DWDie *except) { DWDie *c; DWAttr *a; for (src = src->child; src != nil; src = src->link) { + if(src == except) + continue; c = newdie(dst, src->abbrev, getattr(src, DW_AT_name)->data); for (a = src->attr; a != nil; a = a->link) newattr(c, a->atr, a->cls, a->value, a->data); - copychildren(c, src); + copychildrenexcept(c, src, nil); } reverselist(&dst->child); } +static void +copychildren(DWDie *dst, DWDie *src) +{ + copychildrenexcept(dst, src, nil); +} // Search children (assumed to have DW_TAG_member) for the one named // field and set its DW_AT_type to dwtype @@ -1253,7 +1261,10 @@ synthesizemaptypes(DWDie *die) mkinternaltypename("bucket", getattr(keytype, DW_AT_name)->data, getattr(valtype, DW_AT_name)->data)); - copychildren(dwhb, bucket); + // Copy over all fields except the field "data" from the generic bucket. + // "data" will be replaced with keys/values below. + copychildrenexcept(dwhb, bucket, find(bucket, "data")); + fld = newdie(dwhb, DW_ABRV_STRUCTFIELD, "keys"); newrefattr(fld, DW_AT_type, dwhk); newmemberoffsetattr(fld, BucketSize + PtrSize); @@ -1335,7 +1346,7 @@ synthesizechantypes(DWDie *die) // For use with pass.c::genasmsym static void -defdwsymb(Sym* sym, char *s, int t, vlong v, vlong size, int ver, Sym *gotype) +defdwsymb(LSym* sym, char *s, int t, vlong v, vlong size, int ver, LSym *gotype) { DWDie *dv, *dt; @@ -1371,284 +1382,37 @@ defdwsymb(Sym* sym, char *s, int t, vlong v, vlong size, int ver, Sym *gotype) newrefattr(dv, DW_AT_type, dt); } -// TODO(lvd) For now, just append them all to the first compilation -// unit (that should be main), in the future distribute them to the -// appropriate compilation units. static void movetomodule(DWDie *parent) { DWDie *die; - for (die = dwroot.child->child; die->link != nil; die = die->link) /* nix */; + die = dwroot.child->child; + while(die->link != nil) + die = die->link; die->link = parent->child; } -/* - * Filename fragments for the line history stack. - */ - -static char **ftab; -static int ftabsize; - -void -dwarfaddfrag(int n, char *frag) -{ - int s; - - if (n >= ftabsize) { - s = ftabsize; - ftabsize = 1 + n + (n >> 2); - ftab = erealloc(ftab, ftabsize * sizeof(ftab[0])); - memset(ftab + s, 0, (ftabsize - s) * sizeof(ftab[0])); - } - - if (*frag == '<') - frag++; - ftab[n] = frag; -} - -// Returns a malloc'ed string, piecewise copied from the ftab. -static char * -decodez(char *s) -{ - int len, o; - char *ss, *f; - char *r, *rb, *re; - - len = 0; - ss = s + 1; // first is 0 - while((o = ((uint8)ss[0] << 8) | (uint8)ss[1]) != 0) { - if (o < 0 || o >= ftabsize) { - diag("dwarf: corrupt z entry"); - return 0; - } - f = ftab[o]; - if (f == nil) { - diag("dwarf: corrupt z entry"); - return 0; - } - len += strlen(f) + 1; // for the '/' - ss += 2; - } - - if (len == 0) - return 0; - - r = malloc(len + 1); - if(r == nil) { - diag("out of memory"); - errorexit(); - } - rb = r; - re = rb + len + 1; - - s++; - while((o = ((uint8)s[0] << 8) | (uint8)s[1]) != 0) { - f = ftab[o]; - if (rb == r || rb[-1] == '/') - rb = seprint(rb, re, "%s", f); - else - rb = seprint(rb, re, "/%s", f); - s += 2; - } - return r; -} - -/* - * The line history itself - */ - -static char **histfile; // [0] holds "<eof>", DW_LNS_set_file arguments must be > 0. -static int histfilesize; -static int histfilecap; - +// If the pcln table contains runtime/string.goc, use that to set gdbscript path. static void -clearhistfile(void) +finddebugruntimepath(LSym *s) { int i; + char *p; + LSym *f; + + if(gdbscript[0] != '\0') + return; - // [0] holds "<eof>" - for (i = 1; i < histfilesize; i++) - free(histfile[i]); - histfilesize = 0; -} - -static int -addhistfile(char *zentry) -{ - char *fname; - - if (histfilesize == histfilecap) { - histfilecap = 2 * histfilecap + 2; - histfile = erealloc(histfile, histfilecap * sizeof(char*)); - } - if (histfilesize == 0) - histfile[histfilesize++] = "<eof>"; - - fname = decodez(zentry); -// print("addhistfile %d: %s\n", histfilesize, fname); - if (fname == 0) - return -1; - - // Don't fill with duplicates (check only top one). - if (strcmp(fname, histfile[histfilesize-1]) == 0) { - free(fname); - return histfilesize - 1; - } - - histfile[histfilesize++] = fname; - return histfilesize - 1; -} - -// if the histfile stack contains ..../runtime/runtime_defs.go -// use that to set gdbscript -static void -finddebugruntimepath(void) -{ - int i, l; - char *c; - - for (i = 1; i < histfilesize; i++) { - if ((c = strstr(histfile[i], "runtime/zruntime_defs")) != nil) { - l = c - histfile[i]; - memmove(gdbscript, histfile[i], l); - memmove(gdbscript + l, "runtime/runtime-gdb.py", strlen("runtime/runtime-gdb.py") + 1); - break; - } - } -} - -// Go's runtime C sources are sane, and Go sources nest only 1 level, -// so a handful would be plenty, if it weren't for the fact that line -// directives can push an unlimited number of them. -static struct { - int file; - vlong line; -} *includestack; -static int includestacksize; -static int includetop; -static vlong absline; - -typedef struct Linehist Linehist; -struct Linehist { - Linehist *link; - vlong absline; - vlong line; - int file; -}; - -static Linehist *linehist; - -static void -checknesting(void) -{ - if (includetop < 0) { - diag("dwarf: corrupt z stack"); - errorexit(); - } - if (includetop >= includestacksize) { - includestacksize += 1; - includestacksize <<= 2; -// print("checknesting: growing to %d\n", includestacksize); - includestack = erealloc(includestack, includestacksize * sizeof *includestack); - } -} - -/* - * Return false if the a->link chain contains no history, otherwise - * returns true and finds z and Z entries in the Auto list (of a - * Prog), and resets the history stack - */ -static int -inithist(Auto *a) -{ - Linehist *lh; - - for (; a; a = a->link) - if (a->type == D_FILE) + for(i=0; i<s->pcln->nfile; i++) { + f = s->pcln->file[i]; + if((p = strstr(f->name, "runtime/string.goc")) != nil) { + *p = '\0'; + snprint(gdbscript, sizeof gdbscript, "%sruntime/runtime-gdb.py", f->name); + *p = 'r'; break; - if (a==nil) - return 0; - - // We have a new history. They are guaranteed to come completely - // at the beginning of the compilation unit. - if (a->aoffset != 1) { - diag("dwarf: stray 'z' with offset %d", a->aoffset); - return 0; - } - - // Clear the history. - clearhistfile(); - includetop = 0; - checknesting(); - includestack[includetop].file = 0; - includestack[includetop].line = -1; - absline = 0; - while (linehist != nil) { - lh = linehist->link; - free(linehist); - linehist = lh; - } - - // Construct the new one. - for (; a; a = a->link) { - if (a->type == D_FILE) { // 'z' - int f = addhistfile(a->asym->name); - if (f < 0) { // pop file - includetop--; - checknesting(); - } else { // pushed a file (potentially same) - includestack[includetop].line += a->aoffset - absline; - includetop++; - checknesting(); - includestack[includetop].file = f; - includestack[includetop].line = 1; - } - absline = a->aoffset; - } else if (a->type == D_FILE1) { // 'Z' - // We could just fixup the current - // linehist->line, but there doesn't appear to - // be a guarantee that every 'Z' is preceded - // by its own 'z', so do the safe thing and - // update the stack and push a new Linehist - // entry - includestack[includetop].line = a->aoffset; - } else - continue; - if (linehist == 0 || linehist->absline != absline) { - Linehist* lh = malloc(sizeof *lh); - if(lh == nil) { - diag("out of memory"); - errorexit(); - } - lh->link = linehist; - lh->absline = absline; - linehist = lh; } - linehist->file = includestack[includetop].file; - linehist->line = includestack[includetop].line; } - return 1; -} - -static Linehist * -searchhist(vlong absline) -{ - Linehist *lh; - - for (lh = linehist; lh; lh = lh->link) - if (lh->absline <= absline) - break; - return lh; -} - -static int -guesslang(char *s) -{ - if(strlen(s) >= 3 && strcmp(s+strlen(s)-3, ".go") == 0) - return DW_LANG_Go; - - return DW_LANG_C; } /* @@ -1659,7 +1423,7 @@ guesslang(char *s) enum { LINE_BASE = -1, LINE_RANGE = 4, - OPCODE_BASE = 5 + OPCODE_BASE = 10 }; static void @@ -1719,7 +1483,7 @@ mkvarname(char* name, int da) // flush previous compilation unit. static void -flushunit(DWDie *dwinfo, vlong pc, Sym *pcsym, vlong unitstart, int32 header_length) +flushunit(DWDie *dwinfo, vlong pc, LSym *pcsym, vlong unitstart, int32 header_length) { vlong here; @@ -1744,147 +1508,129 @@ flushunit(DWDie *dwinfo, vlong pc, Sym *pcsym, vlong unitstart, int32 header_len static void writelines(void) { - Prog *q; - Sym *s, *epcs; + LSym *s, *epcs; Auto *a; vlong unitstart, headerend, offs; - vlong pc, epc, lc, llc, lline; - int currfile; - int i, lang, da, dt; - Linehist *lh; + vlong pc, epc; + int i, lang, da, dt, line, file; DWDie *dwinfo, *dwfunc, *dwvar, **dws; DWDie *varhash[HASHSIZE]; char *n, *nn; + Pciter pcfile, pcline; + LSym **files, *f; if(linesec == S) - linesec = lookup(".dwarfline", 0); + linesec = linklookup(ctxt, ".dwarfline", 0); linesec->nr = 0; unitstart = -1; headerend = -1; - pc = 0; epc = 0; epcs = S; - lc = 1; - llc = 1; - currfile = -1; lineo = cpos(); dwinfo = nil; + + flushunit(dwinfo, epc, epcs, unitstart, headerend - unitstart - 10); + unitstart = cpos(); + + lang = DW_LANG_Go; + + s = ctxt->textp; + + dwinfo = newdie(&dwroot, DW_ABRV_COMPUNIT, estrdup("go")); + newattr(dwinfo, DW_AT_language, DW_CLS_CONSTANT,lang, 0); + newattr(dwinfo, DW_AT_stmt_list, DW_CLS_PTR, unitstart - lineo, 0); + newattr(dwinfo, DW_AT_low_pc, DW_CLS_ADDRESS, s->value, (char*)s); + + // Write .debug_line Line Number Program Header (sec 6.2.4) + // Fields marked with (*) must be changed for 64-bit dwarf + LPUT(0); // unit_length (*), will be filled in by flushunit. + WPUT(2); // dwarf version (appendix F) + LPUT(0); // header_length (*), filled in by flushunit. + // cpos == unitstart + 4 + 2 + 4 + cput(1); // minimum_instruction_length + cput(1); // default_is_stmt + cput(LINE_BASE); // line_base + cput(LINE_RANGE); // line_range + cput(OPCODE_BASE); // opcode_base + cput(0); // standard_opcode_lengths[1] + cput(1); // standard_opcode_lengths[2] + cput(1); // standard_opcode_lengths[3] + cput(1); // standard_opcode_lengths[4] + cput(1); // standard_opcode_lengths[5] + cput(0); // standard_opcode_lengths[6] + cput(0); // standard_opcode_lengths[7] + cput(0); // standard_opcode_lengths[8] + cput(1); // standard_opcode_lengths[9] + cput(0); // include_directories (empty) + + files = emallocz(ctxt->nhistfile*sizeof files[0]); + for(f = ctxt->filesyms; f != nil; f = f->next) + files[f->value-1] = f; + + for(i=0; i<ctxt->nhistfile; i++) { + strnput(files[i]->name, strlen(files[i]->name) + 4); + // 4 zeros: the string termination + 3 fields. + } + + cput(0); // terminate file_names. + headerend = cpos(); + + cput(0); // start extended opcode + uleb128put(1 + PtrSize); + cput(DW_LNE_set_address); + + pc = s->value; + line = 1; + file = 1; + if(linkmode == LinkExternal) + adddwarfrel(linesec, s, lineo, PtrSize, 0); + else + addrput(pc); - for(cursym = textp; cursym != nil; cursym = cursym->next) { - s = cursym; - if(s->text == P) - continue; - - // Look for history stack. If we find one, - // we're entering a new compilation unit - - if (inithist(s->autom)) { - flushunit(dwinfo, epc, epcs, unitstart, headerend - unitstart - 10); - unitstart = cpos(); - - if(debug['v'] > 1) { - print("dwarf writelines found %s\n", histfile[1]); - Linehist* lh; - for (lh = linehist; lh; lh = lh->link) - print("\t%8lld: [%4lld]%s\n", - lh->absline, lh->line, histfile[lh->file]); - } - - lang = guesslang(histfile[1]); - finddebugruntimepath(); - - dwinfo = newdie(&dwroot, DW_ABRV_COMPUNIT, estrdup(histfile[1])); - newattr(dwinfo, DW_AT_language, DW_CLS_CONSTANT,lang, 0); - newattr(dwinfo, DW_AT_stmt_list, DW_CLS_PTR, unitstart - lineo, 0); - newattr(dwinfo, DW_AT_low_pc, DW_CLS_ADDRESS, s->text->pc, (char*)s); - - // Write .debug_line Line Number Program Header (sec 6.2.4) - // Fields marked with (*) must be changed for 64-bit dwarf - LPUT(0); // unit_length (*), will be filled in by flushunit. - WPUT(2); // dwarf version (appendix F) - LPUT(0); // header_length (*), filled in by flushunit. - // cpos == unitstart + 4 + 2 + 4 - cput(1); // minimum_instruction_length - cput(1); // default_is_stmt - cput(LINE_BASE); // line_base - cput(LINE_RANGE); // line_range - cput(OPCODE_BASE); // opcode_base (we only use 1..4) - cput(0); // standard_opcode_lengths[1] - cput(1); // standard_opcode_lengths[2] - cput(1); // standard_opcode_lengths[3] - cput(1); // standard_opcode_lengths[4] - cput(0); // include_directories (empty) - - for (i=1; i < histfilesize; i++) { - strnput(histfile[i], strlen(histfile[i]) + 4); - // 4 zeros: the string termination + 3 fields. - } - - cput(0); // terminate file_names. - headerend = cpos(); - - pc = s->text->pc; - epc = pc; - epcs = s; - currfile = 1; - lc = 1; - llc = 1; - - cput(0); // start extended opcode - uleb128put(1 + PtrSize); - cput(DW_LNE_set_address); - - if(linkmode == LinkExternal) - adddwarfrel(linesec, s, lineo, PtrSize, 0); - else - addrput(pc); - } - if(s->text == nil) - continue; - - if (unitstart < 0) { - diag("dwarf: reachable code before seeing any history: %P", s->text); - continue; - } + for(ctxt->cursym = ctxt->textp; ctxt->cursym != nil; ctxt->cursym = ctxt->cursym->next) { + s = ctxt->cursym; dwfunc = newdie(dwinfo, DW_ABRV_FUNCTION, s->name); newattr(dwfunc, DW_AT_low_pc, DW_CLS_ADDRESS, s->value, (char*)s); epc = s->value + s->size; + epcs = s; newattr(dwfunc, DW_AT_high_pc, DW_CLS_ADDRESS, epc, (char*)s); if (s->version == 0) newattr(dwfunc, DW_AT_external, DW_CLS_FLAG, 1, 0); - if(s->text->link == nil) + if(s->pcln == nil) continue; - for(q = s->text; q != P; q = q->link) { - lh = searchhist(q->line); - if (lh == nil) { - diag("dwarf: corrupt history or bad absolute line: %P", q); + finddebugruntimepath(s); + + pciterinit(ctxt, &pcfile, &s->pcln->pcfile); + pciterinit(ctxt, &pcline, &s->pcln->pcline); + epc = pc; + while(!pcfile.done && !pcline.done) { + if(epc - s->value >= pcfile.nextpc) { + pciternext(&pcfile); continue; } - - if (lh->file < 1) { // 0 is the past-EOF entry. - // diag("instruction with line number past EOF in %s: %P", histfile[1], q); + if(epc - s->value >= pcline.nextpc) { + pciternext(&pcline); continue; } - lline = lh->line + q->line - lh->absline; - if (debug['v'] > 1) - print("%6llux %s[%lld] %P\n", (vlong)q->pc, histfile[lh->file], lline, q); - - if (q->line == lc) - continue; - if (currfile != lh->file) { - currfile = lh->file; + if(file != pcfile.value) { cput(DW_LNS_set_file); - uleb128put(currfile); + uleb128put(pcfile.value); + file = pcfile.value; } - putpclcdelta(q->pc - pc, lline - llc); - pc = q->pc; - lc = q->line; - llc = lline; + putpclcdelta(s->value + pcline.pc - pc, pcline.value - line); + + pc = s->value + pcline.pc; + line = pcline.value; + if(pcfile.nextpc < pcline.nextpc) + epc = pcfile.nextpc; + else + epc = pcline.nextpc; + epc += s->value; } da = 0; @@ -1892,11 +1638,11 @@ writelines(void) memset(varhash, 0, sizeof varhash); for(a = s->autom; a; a = a->link) { switch (a->type) { - case D_AUTO: + case A_AUTO: dt = DW_ABRV_AUTO; offs = a->aoffset - PtrSize; break; - case D_PARAM: + case A_PARAM: dt = DW_ABRV_PARAM; offs = a->aoffset; break; @@ -1970,12 +1716,12 @@ putpccfadelta(vlong deltapc, vlong cfa) static void writeframes(void) { - Prog *p, *q; - Sym *s; - vlong fdeo, fdesize, pad, cfa, pc; + LSym *s; + vlong fdeo, fdesize, pad; + Pciter pcsp; if(framesec == S) - framesec = lookup(".dwarfframe", 0); + framesec = linklookup(ctxt, ".dwarfframe", 0); framesec->nr = 0; frameo = cpos(); @@ -2003,9 +1749,9 @@ writeframes(void) } strnput("", pad); - for(cursym = textp; cursym != nil; cursym = cursym->next) { - s = cursym; - if(s->text == nil) + for(ctxt->cursym = ctxt->textp; ctxt->cursym != nil; ctxt->cursym = ctxt->cursym->next) { + s = ctxt->cursym; + if(s->pcln == nil) continue; fdeo = cpos(); @@ -2015,17 +1761,8 @@ writeframes(void) addrput(0); // initial location addrput(0); // address range - cfa = PtrSize; // CFA starts at sp+PtrSize - p = s->text; - pc = p->pc; - - for(q = p; q->link != P; q = q->link) { - if (q->spadj == 0) - continue; - cfa += q->spadj; - putpccfadelta(q->link->pc - pc, cfa); - pc = q->link->pc; - } + for(pciterinit(ctxt, &pcsp, &s->pcln->pcsp); !pcsp.done; pciternext(&pcsp)) + putpccfadelta(pcsp.nextpc - pcsp.pc, PtrSize + pcsp.value); fdesize = cpos() - fdeo - 4; // exclude the length field. pad = rnd(fdesize, PtrSize) - fdesize; @@ -2041,7 +1778,7 @@ writeframes(void) } else { LPUT(0); - addrput(p->pc); + addrput(s->value); } addrput(s->size); cseek(fdeo + 4 + fdesize); @@ -2067,11 +1804,11 @@ writeinfo(void) fwdcount = 0; if (infosec == S) - infosec = lookup(".dwarfinfo", 0); + infosec = linklookup(ctxt, ".dwarfinfo", 0); infosec->nr = 0; if(arangessec == S) - arangessec = lookup(".dwarfaranges", 0); + arangessec = linklookup(ctxt, ".dwarfaranges", 0); arangessec->nr = 0; for (compunit = dwroot.child; compunit; compunit = compunit->link) { @@ -2204,7 +1941,7 @@ writearanges(void) strnput("", headersize - (4+2+4+1+1)); // align to PtrSize if(linkmode == LinkExternal) - adddwarfrel(arangessec, (Sym*)b->data, sectionstart, PtrSize, b->value-((Sym*)b->data)->value); + adddwarfrel(arangessec, (LSym*)b->data, sectionstart, PtrSize, b->value-((LSym*)b->data)->value); else addrput(b->value); @@ -2239,7 +1976,7 @@ align(vlong size) } static vlong -writedwarfreloc(Sym* s) +writedwarfreloc(LSym* s) { int i; vlong start; @@ -2408,7 +2145,7 @@ enum vlong elfstrdbg[NElfStrDbg]; void -dwarfaddshstrings(Sym *shstrtab) +dwarfaddshstrings(LSym *shstrtab) { if(debug['w']) // disable dwarf return; @@ -2438,16 +2175,16 @@ dwarfaddshstrings(Sym *shstrtab) elfstrdbg[ElfStrRelDebugFrame] = addstring(shstrtab, ".rel.debug_frame"); } - infosym = lookup(".debug_info", 0); + infosym = linklookup(ctxt, ".debug_info", 0); infosym->hide = 1; - abbrevsym = lookup(".debug_abbrev", 0); + abbrevsym = linklookup(ctxt, ".debug_abbrev", 0); abbrevsym->hide = 1; - linesym = lookup(".debug_line", 0); + linesym = linklookup(ctxt, ".debug_line", 0); linesym->hide = 1; - framesym = lookup(".debug_frame", 0); + framesym = linklookup(ctxt, ".debug_frame", 0); framesym->hide = 1; } } @@ -2616,31 +2353,37 @@ dwarfaddmachoheaders(void) ms = newMachoSeg("__DWARF", nsect); ms->fileoffset = fakestart; ms->filesize = abbrevo-fakestart; + ms->vaddr = ms->fileoffset + segdata.vaddr - segdata.fileoff; msect = newMachoSect(ms, "__debug_abbrev", "__DWARF"); msect->off = abbrevo; msect->size = abbrevsize; + msect->addr = msect->off + segdata.vaddr - segdata.fileoff; ms->filesize += msect->size; msect = newMachoSect(ms, "__debug_line", "__DWARF"); msect->off = lineo; msect->size = linesize; + msect->addr = msect->off + segdata.vaddr - segdata.fileoff; ms->filesize += msect->size; msect = newMachoSect(ms, "__debug_frame", "__DWARF"); msect->off = frameo; msect->size = framesize; + msect->addr = msect->off + segdata.vaddr - segdata.fileoff; ms->filesize += msect->size; msect = newMachoSect(ms, "__debug_info", "__DWARF"); msect->off = infoo; msect->size = infosize; + msect->addr = msect->off + segdata.vaddr - segdata.fileoff; ms->filesize += msect->size; if (pubnamessize > 0) { msect = newMachoSect(ms, "__debug_pubnames", "__DWARF"); msect->off = pubnameso; msect->size = pubnamessize; + msect->addr = msect->off + segdata.vaddr - segdata.fileoff; ms->filesize += msect->size; } @@ -2648,6 +2391,7 @@ dwarfaddmachoheaders(void) msect = newMachoSect(ms, "__debug_pubtypes", "__DWARF"); msect->off = pubtypeso; msect->size = pubtypessize; + msect->addr = msect->off + segdata.vaddr - segdata.fileoff; ms->filesize += msect->size; } @@ -2655,6 +2399,7 @@ dwarfaddmachoheaders(void) msect = newMachoSect(ms, "__debug_aranges", "__DWARF"); msect->off = arangeso; msect->size = arangessize; + msect->addr = msect->off + segdata.vaddr - segdata.fileoff; ms->filesize += msect->size; } @@ -2663,6 +2408,7 @@ dwarfaddmachoheaders(void) msect = newMachoSect(ms, "__debug_gdb_scripts", "__DWARF"); msect->off = gdbscripto; msect->size = gdbscriptsize; + msect->addr = msect->off + segdata.vaddr - segdata.fileoff; ms->filesize += msect->size; } } diff --git a/src/cmd/ld/dwarf.h b/src/cmd/ld/dwarf.h index f0df2f9b1..32db36dcd 100644 --- a/src/cmd/ld/dwarf.h +++ b/src/cmd/ld/dwarf.h @@ -3,12 +3,6 @@ // license that can be found in the LICENSE file. /* - * Register 'f' symbol file fragments. Doing this while parsing the - * .6 input saves a pass over the symbol table later. - */ -void dwarfaddfrag(int n, char* frag); - -/* * Emit debug_abbrevs, debug_info and debug_line sections to current * offset in cout. */ @@ -19,7 +13,7 @@ void dwarfemitdebugsections(void); * s[ection]h[eader]str[ing]tab. Prerequisite for * dwarfaddelfheaders(). */ -void dwarfaddshstrings(Sym *shstrtab); +void dwarfaddshstrings(LSym *shstrtab); /* * Add section headers pointing to the sections emitted in diff --git a/src/cmd/ld/elf.c b/src/cmd/ld/elf.c index 6b3638ec5..0555cf46a 100644 --- a/src/cmd/ld/elf.c +++ b/src/cmd/ld/elf.c @@ -55,8 +55,8 @@ elfinit(void) // 32-bit architectures case '5': - // we only use EABI on linux/arm - if(HEADTYPE == Hlinux) + // we use EABI on both linux/arm and freebsd/arm. + if(HEADTYPE == Hlinux || HEADTYPE == Hfreebsd) hdr.flags = 0x5000002; // has entry point, Version5 EABI // fallthrough default: @@ -287,35 +287,35 @@ elfhash(uchar *name) } void -elfwritedynent(Sym *s, int tag, uint64 val) +elfwritedynent(LSym *s, int tag, uint64 val) { if(elf64) { - adduint64(s, tag); - adduint64(s, val); + adduint64(ctxt, s, tag); + adduint64(ctxt, s, val); } else { - adduint32(s, tag); - adduint32(s, val); + adduint32(ctxt, s, tag); + adduint32(ctxt, s, val); } } void -elfwritedynentsym(Sym *s, int tag, Sym *t) +elfwritedynentsym(LSym *s, int tag, LSym *t) { if(elf64) - adduint64(s, tag); + adduint64(ctxt, s, tag); else - adduint32(s, tag); - addaddr(s, t); + adduint32(ctxt, s, tag); + addaddr(ctxt, s, t); } void -elfwritedynentsymsize(Sym *s, int tag, Sym *t) +elfwritedynentsymsize(LSym *s, int tag, LSym *t) { if(elf64) - adduint64(s, tag); + adduint64(ctxt, s, tag); else - adduint32(s, tag); - addsize(s, t); + adduint32(ctxt, s, tag); + addsize(ctxt, s, t); } int @@ -355,7 +355,7 @@ elfnote(ElfShdr *sh, uint64 startva, uint64 resoff, int sz) sh->addralign = 4; sh->addr = startva + resoff - n; sh->off = resoff - n; - sh->size = n; + sh->size = n - resoff % 4; return n; } @@ -388,7 +388,7 @@ elfnetbsdsig(ElfShdr *sh, uint64 startva, uint64 resoff) { int n; - n = ELF_NOTE_NETBSD_NAMESZ + ELF_NOTE_NETBSD_DESCSZ + 1; + n = rnd(ELF_NOTE_NETBSD_NAMESZ, 4) + rnd(ELF_NOTE_NETBSD_DESCSZ, 4); return elfnote(sh, startva, resoff, n); } @@ -561,7 +561,7 @@ haveaux: void elfdynhash(void) { - Sym *s, *sy, *dynstr; + LSym *s, *sy, *dynstr; int i, j, nbucket, b, nfile; uint32 hc, *chain, *buckets; int nsym; @@ -575,7 +575,7 @@ elfdynhash(void) return; nsym = nelfsym; - s = lookup(".hash", 0); + s = linklookup(ctxt, ".hash", 0); s->type = SELFROSECT; s->reachable = 1; @@ -591,14 +591,14 @@ elfdynhash(void) chain = malloc(nsym * sizeof chain[0]); buckets = malloc(nbucket * sizeof buckets[0]); if(need == nil || chain == nil || buckets == nil) { - cursym = nil; + ctxt->cursym = nil; diag("out of memory"); errorexit(); } memset(need, 0, nsym * sizeof need[0]); memset(chain, 0, nsym * sizeof chain[0]); memset(buckets, 0, nbucket * sizeof buckets[0]); - for(sy=allsym; sy!=S; sy=sy->allsym) { + for(sy=ctxt->allsym; sy!=S; sy=sy->allsym) { if (sy->dynid <= 0) continue; @@ -613,70 +613,87 @@ elfdynhash(void) buckets[b] = sy->dynid; } - adduint32(s, nbucket); - adduint32(s, nsym); + adduint32(ctxt, s, nbucket); + adduint32(ctxt, s, nsym); for(i = 0; i<nbucket; i++) - adduint32(s, buckets[i]); + adduint32(ctxt, s, buckets[i]); for(i = 0; i<nsym; i++) - adduint32(s, chain[i]); + adduint32(ctxt, s, chain[i]); free(chain); free(buckets); // version symbols - dynstr = lookup(".dynstr", 0); - s = lookup(".gnu.version_r", 0); + dynstr = linklookup(ctxt, ".dynstr", 0); + s = linklookup(ctxt, ".gnu.version_r", 0); i = 2; nfile = 0; for(l=needlib; l; l=l->next) { nfile++; // header - adduint16(s, 1); // table version + adduint16(ctxt, s, 1); // table version j = 0; for(x=l->aux; x; x=x->next) j++; - adduint16(s, j); // aux count - adduint32(s, addstring(dynstr, l->file)); // file string offset - adduint32(s, 16); // offset from header to first aux + adduint16(ctxt, s, j); // aux count + adduint32(ctxt, s, addstring(dynstr, l->file)); // file string offset + adduint32(ctxt, s, 16); // offset from header to first aux if(l->next) - adduint32(s, 16+j*16); // offset from this header to next + adduint32(ctxt, s, 16+j*16); // offset from this header to next else - adduint32(s, 0); + adduint32(ctxt, s, 0); for(x=l->aux; x; x=x->next) { x->num = i++; // aux struct - adduint32(s, elfhash((uchar*)x->vers)); // hash - adduint16(s, 0); // flags - adduint16(s, x->num); // other - index we refer to this by - adduint32(s, addstring(dynstr, x->vers)); // version string offset + adduint32(ctxt, s, elfhash((uchar*)x->vers)); // hash + adduint16(ctxt, s, 0); // flags + adduint16(ctxt, s, x->num); // other - index we refer to this by + adduint32(ctxt, s, addstring(dynstr, x->vers)); // version string offset if(x->next) - adduint32(s, 16); // offset from this aux to next + adduint32(ctxt, s, 16); // offset from this aux to next else - adduint32(s, 0); + adduint32(ctxt, s, 0); } } // version references - s = lookup(".gnu.version", 0); + s = linklookup(ctxt, ".gnu.version", 0); for(i=0; i<nsym; i++) { if(i == 0) - adduint16(s, 0); // first entry - no symbol + adduint16(ctxt, s, 0); // first entry - no symbol else if(need[i] == nil) - adduint16(s, 1); // global + adduint16(ctxt, s, 1); // global else - adduint16(s, need[i]->num); + adduint16(ctxt, s, need[i]->num); } free(need); - s = lookup(".dynamic", 0); + s = linklookup(ctxt, ".dynamic", 0); elfverneed = nfile; if(elfverneed) { - elfwritedynentsym(s, DT_VERNEED, lookup(".gnu.version_r", 0)); + elfwritedynentsym(s, DT_VERNEED, linklookup(ctxt, ".gnu.version_r", 0)); elfwritedynent(s, DT_VERNEEDNUM, nfile); - elfwritedynentsym(s, DT_VERSYM, lookup(".gnu.version", 0)); + elfwritedynentsym(s, DT_VERSYM, linklookup(ctxt, ".gnu.version", 0)); + } + + if(thechar == '6') { + sy = linklookup(ctxt, ".rela.plt", 0); + if(sy->size > 0) { + elfwritedynent(s, DT_PLTREL, DT_RELA); + elfwritedynentsymsize(s, DT_PLTRELSZ, sy); + elfwritedynentsym(s, DT_JMPREL, sy); + } + } else { + sy = linklookup(ctxt, ".rel.plt", 0); + if(sy->size > 0) { + elfwritedynent(s, DT_PLTREL, DT_REL); + elfwritedynentsymsize(s, DT_PLTRELSZ, sy); + elfwritedynentsym(s, DT_JMPREL, sy); + } } + elfwritedynent(s, DT_NULL, 0); } @@ -797,19 +814,19 @@ elfshreloc(Section *sect) snprint(buf, sizeof buf, "%s%s", prefix, sect->name); sh = elfshname(buf); sh->type = typ; - sh->entsize = PtrSize*(2+(typ==SHT_RELA)); + sh->entsize = RegSize*(2+(typ==SHT_RELA)); sh->link = elfshname(".symtab")->shnum; sh->info = sect->elfsect->shnum; sh->off = sect->reloff; sh->size = sect->rellen; - sh->addralign = PtrSize; + sh->addralign = RegSize; return sh; } void -elfrelocsect(Section *sect, Sym *first) +elfrelocsect(Section *sect, LSym *first) { - Sym *sym; + LSym *sym; int32 eaddr; Reloc *r; @@ -834,7 +851,7 @@ elfrelocsect(Section *sect, Sym *first) continue; if(sym->value >= eaddr) break; - cursym = sym; + ctxt->cursym = sym; for(r = sym->r; r < sym->r+sym->nr; r++) { if(r->done) @@ -861,7 +878,7 @@ elfemitreloc(void) while(cpos()&7) cput(0); - elfrelocsect(segtext.sect, textp); + elfrelocsect(segtext.sect, ctxt->textp); for(sect=segtext.sect->next; sect!=nil; sect=sect->next) elfrelocsect(sect, datap); for(sect=segrodata.sect; sect!=nil; sect=sect->next) @@ -873,13 +890,13 @@ elfemitreloc(void) void doelf(void) { - Sym *s, *shstrtab, *dynstr; + LSym *s, *shstrtab, *dynstr; if(!iself) return; /* predefine strings we need for section headers */ - shstrtab = lookup(".shstrtab", 0); + shstrtab = linklookup(ctxt, ".shstrtab", 0); shstrtab->type = SELFROSECT; shstrtab->reachable = 1; @@ -969,7 +986,7 @@ doelf(void) addstring(shstrtab, ".gnu.version_r"); /* dynamic symbol table - first entry all zeros */ - s = lookup(".dynsym", 0); + s = linklookup(ctxt, ".dynsym", 0); s->type = SELFROSECT; s->reachable = 1; if(thechar == '6') @@ -978,7 +995,7 @@ doelf(void) s->size += ELF32SYMSIZE; /* dynamic string table */ - s = lookup(".dynstr", 0); + s = linklookup(ctxt, ".dynstr", 0); s->type = SELFROSECT; s->reachable = 1; if(s->size == 0) @@ -987,87 +1004,81 @@ doelf(void) /* relocation table */ if(thechar == '6') - s = lookup(".rela", 0); + s = linklookup(ctxt, ".rela", 0); else - s = lookup(".rel", 0); + s = linklookup(ctxt, ".rel", 0); s->reachable = 1; s->type = SELFROSECT; /* global offset table */ - s = lookup(".got", 0); + s = linklookup(ctxt, ".got", 0); s->reachable = 1; s->type = SELFSECT; // writable /* hash */ - s = lookup(".hash", 0); + s = linklookup(ctxt, ".hash", 0); s->reachable = 1; s->type = SELFROSECT; - s = lookup(".got.plt", 0); + s = linklookup(ctxt, ".got.plt", 0); s->reachable = 1; s->type = SELFSECT; // writable - s = lookup(".plt", 0); + s = linklookup(ctxt, ".plt", 0); s->reachable = 1; s->type = SELFRXSECT; elfsetupplt(); if(thechar == '6') - s = lookup(".rela.plt", 0); + s = linklookup(ctxt, ".rela.plt", 0); else - s = lookup(".rel.plt", 0); + s = linklookup(ctxt, ".rel.plt", 0); s->reachable = 1; s->type = SELFROSECT; - s = lookup(".gnu.version", 0); + s = linklookup(ctxt, ".gnu.version", 0); s->reachable = 1; s->type = SELFROSECT; - s = lookup(".gnu.version_r", 0); + s = linklookup(ctxt, ".gnu.version_r", 0); s->reachable = 1; s->type = SELFROSECT; /* define dynamic elf table */ - s = lookup(".dynamic", 0); + s = linklookup(ctxt, ".dynamic", 0); s->reachable = 1; s->type = SELFSECT; // writable /* * .dynamic table */ - elfwritedynentsym(s, DT_HASH, lookup(".hash", 0)); - elfwritedynentsym(s, DT_SYMTAB, lookup(".dynsym", 0)); + elfwritedynentsym(s, DT_HASH, linklookup(ctxt, ".hash", 0)); + elfwritedynentsym(s, DT_SYMTAB, linklookup(ctxt, ".dynsym", 0)); if(thechar == '6') elfwritedynent(s, DT_SYMENT, ELF64SYMSIZE); else elfwritedynent(s, DT_SYMENT, ELF32SYMSIZE); - elfwritedynentsym(s, DT_STRTAB, lookup(".dynstr", 0)); - elfwritedynentsymsize(s, DT_STRSZ, lookup(".dynstr", 0)); + elfwritedynentsym(s, DT_STRTAB, linklookup(ctxt, ".dynstr", 0)); + elfwritedynentsymsize(s, DT_STRSZ, linklookup(ctxt, ".dynstr", 0)); if(thechar == '6') { - elfwritedynentsym(s, DT_RELA, lookup(".rela", 0)); - elfwritedynentsymsize(s, DT_RELASZ, lookup(".rela", 0)); + elfwritedynentsym(s, DT_RELA, linklookup(ctxt, ".rela", 0)); + elfwritedynentsymsize(s, DT_RELASZ, linklookup(ctxt, ".rela", 0)); elfwritedynent(s, DT_RELAENT, ELF64RELASIZE); } else { - elfwritedynentsym(s, DT_REL, lookup(".rel", 0)); - elfwritedynentsymsize(s, DT_RELSZ, lookup(".rel", 0)); + elfwritedynentsym(s, DT_REL, linklookup(ctxt, ".rel", 0)); + elfwritedynentsymsize(s, DT_RELSZ, linklookup(ctxt, ".rel", 0)); elfwritedynent(s, DT_RELENT, ELF32RELSIZE); } if(rpath) elfwritedynent(s, DT_RUNPATH, addstring(dynstr, rpath)); - elfwritedynentsym(s, DT_PLTGOT, lookup(".got.plt", 0)); + elfwritedynentsym(s, DT_PLTGOT, linklookup(ctxt, ".got.plt", 0)); - if(thechar == '6') { - elfwritedynent(s, DT_PLTREL, DT_RELA); - elfwritedynentsymsize(s, DT_PLTRELSZ, lookup(".rela.plt", 0)); - elfwritedynentsym(s, DT_JMPREL, lookup(".rela.plt", 0)); - } else { - elfwritedynent(s, DT_PLTREL, DT_REL); - elfwritedynentsymsize(s, DT_PLTRELSZ, lookup(".rel.plt", 0)); - elfwritedynentsym(s, DT_JMPREL, lookup(".rel.plt", 0)); - } - + // Solaris dynamic linker can't handle an empty .rela.plt if + // DT_JMPREL is emitted so we have to defer generation of DT_PLTREL, + // DT_PLTRELSZ, and DT_JMPREL dynamic entries until after we know the + // size of .rel(a).plt section. elfwritedynent(s, DT_DEBUG, 0); // Do not write DT_NULL. elfdynhash will finish it. @@ -1075,7 +1086,7 @@ doelf(void) } void -shsym(ElfShdr *sh, Sym *s) +shsym(ElfShdr *sh, LSym *s) { vlong addr; addr = symaddr(s); @@ -1152,7 +1163,7 @@ asmbelf(vlong symo) /* program header info */ pph = newElfPhdr(); pph->type = PT_PHDR; - pph->flags = PF_R + PF_X; + pph->flags = PF_R; pph->off = eh->ehsize; pph->vaddr = INITTEXT - HEADR + pph->off; pph->paddr = INITTEXT - HEADR + pph->off; @@ -1161,13 +1172,16 @@ asmbelf(vlong symo) /* * PHDR must be in a loaded segment. Adjust the text * segment boundaries downwards to include it. + * Except on NaCl where it must not be loaded. */ - o = segtext.vaddr - pph->vaddr; - segtext.vaddr -= o; - segtext.len += o; - o = segtext.fileoff - pph->off; - segtext.fileoff -= o; - segtext.filelen += o; + if(HEADTYPE != Hnacl) { + o = segtext.vaddr - pph->vaddr; + segtext.vaddr -= o; + segtext.len += o; + o = segtext.fileoff - pph->off; + segtext.fileoff -= o; + segtext.filelen += o; + } if(!debug['d']) { /* interpreter */ @@ -1192,6 +1206,9 @@ asmbelf(vlong symo) case Hdragonfly: interpreter = dragonflydynld; break; + case Hsolaris: + interpreter = solarisdynld; + break; } } resoff -= elfinterp(sh, startva, resoff, interpreter); @@ -1247,20 +1264,20 @@ asmbelf(vlong symo) sh = elfshname(".dynsym"); sh->type = SHT_DYNSYM; sh->flags = SHF_ALLOC; - if(PtrSize == 8) + if(elf64) sh->entsize = ELF64SYMSIZE; else sh->entsize = ELF32SYMSIZE; - sh->addralign = PtrSize; + sh->addralign = RegSize; sh->link = elfshname(".dynstr")->shnum; // sh->info = index of first non-local symbol (number of local symbols) - shsym(sh, lookup(".dynsym", 0)); + shsym(sh, linklookup(ctxt, ".dynsym", 0)); sh = elfshname(".dynstr"); sh->type = SHT_STRTAB; sh->flags = SHF_ALLOC; sh->addralign = 1; - shsym(sh, lookup(".dynstr", 0)); + shsym(sh, linklookup(ctxt, ".dynstr", 0)); if(elfverneed) { sh = elfshname(".gnu.version"); @@ -1269,15 +1286,15 @@ asmbelf(vlong symo) sh->addralign = 2; sh->link = elfshname(".dynsym")->shnum; sh->entsize = 2; - shsym(sh, lookup(".gnu.version", 0)); + shsym(sh, linklookup(ctxt, ".gnu.version", 0)); sh = elfshname(".gnu.version_r"); sh->type = SHT_GNU_VERNEED; sh->flags = SHF_ALLOC; - sh->addralign = PtrSize; + sh->addralign = RegSize; sh->info = elfverneed; sh->link = elfshname(".dynstr")->shnum; - shsym(sh, lookup(".gnu.version_r", 0)); + shsym(sh, linklookup(ctxt, ".gnu.version_r", 0)); } switch(eh->machine) { @@ -1286,10 +1303,10 @@ asmbelf(vlong symo) sh->type = SHT_RELA; sh->flags = SHF_ALLOC; sh->entsize = ELF64RELASIZE; - sh->addralign = PtrSize; + sh->addralign = RegSize; sh->link = elfshname(".dynsym")->shnum; sh->info = elfshname(".plt")->shnum; - shsym(sh, lookup(".rela.plt", 0)); + shsym(sh, linklookup(ctxt, ".rela.plt", 0)); sh = elfshname(".rela"); sh->type = SHT_RELA; @@ -1297,7 +1314,7 @@ asmbelf(vlong symo) sh->entsize = ELF64RELASIZE; sh->addralign = 8; sh->link = elfshname(".dynsym")->shnum; - shsym(sh, lookup(".rela", 0)); + shsym(sh, linklookup(ctxt, ".rela", 0)); break; default: @@ -1306,7 +1323,7 @@ asmbelf(vlong symo) sh->flags = SHF_ALLOC; sh->entsize = ELF32RELSIZE; sh->link = elfshname(".dynsym")->shnum; - shsym(sh, lookup(".rel.plt", 0)); + shsym(sh, linklookup(ctxt, ".rel.plt", 0)); sh = elfshname(".rel"); sh->type = SHT_REL; @@ -1314,7 +1331,7 @@ asmbelf(vlong symo) sh->entsize = ELF32RELSIZE; sh->addralign = 4; sh->link = elfshname(".dynsym")->shnum; - shsym(sh, lookup(".rel", 0)); + shsym(sh, linklookup(ctxt, ".rel", 0)); break; } @@ -1326,38 +1343,38 @@ asmbelf(vlong symo) else sh->entsize = 4; sh->addralign = 4; - shsym(sh, lookup(".plt", 0)); + shsym(sh, linklookup(ctxt, ".plt", 0)); sh = elfshname(".got"); sh->type = SHT_PROGBITS; sh->flags = SHF_ALLOC+SHF_WRITE; - sh->entsize = PtrSize; - sh->addralign = PtrSize; - shsym(sh, lookup(".got", 0)); + sh->entsize = RegSize; + sh->addralign = RegSize; + shsym(sh, linklookup(ctxt, ".got", 0)); sh = elfshname(".got.plt"); sh->type = SHT_PROGBITS; sh->flags = SHF_ALLOC+SHF_WRITE; - sh->entsize = PtrSize; - sh->addralign = PtrSize; - shsym(sh, lookup(".got.plt", 0)); + sh->entsize = RegSize; + sh->addralign = RegSize; + shsym(sh, linklookup(ctxt, ".got.plt", 0)); sh = elfshname(".hash"); sh->type = SHT_HASH; sh->flags = SHF_ALLOC; sh->entsize = 4; - sh->addralign = PtrSize; + sh->addralign = RegSize; sh->link = elfshname(".dynsym")->shnum; - shsym(sh, lookup(".hash", 0)); + shsym(sh, linklookup(ctxt, ".hash", 0)); /* sh and PT_DYNAMIC for .dynamic section */ sh = elfshname(".dynamic"); sh->type = SHT_DYNAMIC; sh->flags = SHF_ALLOC+SHF_WRITE; - sh->entsize = 2*PtrSize; - sh->addralign = PtrSize; + sh->entsize = 2*RegSize; + sh->addralign = RegSize; sh->link = elfshname(".dynstr")->shnum; - shsym(sh, lookup(".dynamic", 0)); + shsym(sh, linklookup(ctxt, ".dynamic", 0)); ph = newElfPhdr(); ph->type = PT_DYNAMIC; ph->flags = PF_R + PF_W; @@ -1369,12 +1386,12 @@ asmbelf(vlong symo) // Do not emit PT_TLS for OpenBSD since ld.so(1) does // not currently support it. This is handled // appropriately in runtime/cgo. - if(tlsoffset != 0 && HEADTYPE != Hopenbsd) { + if(ctxt->tlsoffset != 0 && HEADTYPE != Hopenbsd) { ph = newElfPhdr(); ph->type = PT_TLS; ph->flags = PF_R; - ph->memsz = -tlsoffset; - ph->align = PtrSize; + ph->memsz = -ctxt->tlsoffset; + ph->align = RegSize; } } @@ -1382,19 +1399,19 @@ asmbelf(vlong symo) ph = newElfPhdr(); ph->type = PT_GNU_STACK; ph->flags = PF_W+PF_R; - ph->align = PtrSize; + ph->align = RegSize; ph = newElfPhdr(); ph->type = PT_PAX_FLAGS; ph->flags = 0x2a00; // mprotect, randexec, emutramp disabled - ph->align = PtrSize; + ph->align = RegSize; } elfobj: sh = elfshname(".shstrtab"); sh->type = SHT_STRTAB; sh->addralign = 1; - shsym(sh, lookup(".shstrtab", 0)); + shsym(sh, linklookup(ctxt, ".shstrtab", 0)); eh->shstrndx = sh->shnum; // put these sections early in the list @@ -1429,8 +1446,8 @@ elfobj: if(linkmode == LinkInternal && !debug['d'] && HEADTYPE != Hopenbsd) { sh = elfshname(".tbss"); sh->type = SHT_NOBITS; - sh->addralign = PtrSize; - sh->size = -tlsoffset; + sh->addralign = RegSize; + sh->size = -ctxt->tlsoffset; sh->flags = SHF_ALLOC | SHF_TLS | SHF_WRITE; } @@ -1439,8 +1456,8 @@ elfobj: sh->type = SHT_SYMTAB; sh->off = symo; sh->size = symsize; - sh->addralign = PtrSize; - sh->entsize = 8+2*PtrSize; + sh->addralign = RegSize; + sh->entsize = 8+2*RegSize; sh->link = elfshname(".strtab")->shnum; sh->info = elfglobalsymndx; @@ -1466,7 +1483,7 @@ elfobj: eh->ident[EI_OSABI] = ELFOSABI_OPENBSD; else if(HEADTYPE == Hdragonfly) eh->ident[EI_OSABI] = ELFOSABI_NONE; - if(PtrSize == 8) + if(elf64) eh->ident[EI_CLASS] = ELFCLASS64; else eh->ident[EI_CLASS] = ELFCLASS32; @@ -1504,5 +1521,5 @@ elfobj: a += elfwritebuildinfo(); } if(a > ELFRESERVE) - diag("ELFRESERVE too small: %d > %d", a, ELFRESERVE); + diag("ELFRESERVE too small: %lld > %d", a, ELFRESERVE); } diff --git a/src/cmd/ld/elf.h b/src/cmd/ld/elf.h index 5b2ff041a..e84d996f2 100644 --- a/src/cmd/ld/elf.h +++ b/src/cmd/ld/elf.h @@ -858,7 +858,7 @@ struct Elf64_Shdr { Elf64_Xword entsize; /* Size of each entry in section. */ int shnum; /* section number, not stored on disk */ - Sym* secsym; /* section symbol, if needed; not on disk */ + LSym* secsym; /* section symbol, if needed; not on disk */ }; /* @@ -968,9 +968,9 @@ ElfPhdr *newElfPhdr(void); uint32 elfwritehdr(void); uint32 elfwritephdrs(void); uint32 elfwriteshdrs(void); -void elfwritedynent(Sym*, int, uint64); -void elfwritedynentsym(Sym*, int, Sym*); -void elfwritedynentsymsize(Sym*, int, Sym*); +void elfwritedynent(LSym*, int, uint64); +void elfwritedynentsym(LSym*, int, LSym*); +void elfwritedynentsymsize(LSym*, int, LSym*); uint32 elfhash(uchar*); uint64 startelf(void); uint64 endelf(void); @@ -994,13 +994,13 @@ ElfShdr* elfshalloc(Section*); ElfShdr* elfshname(char*); ElfShdr* elfshreloc(Section*); void elfsetstring(char*, int); -void elfaddverneed(Sym*); +void elfaddverneed(LSym*); void elfemitreloc(void); -void shsym(ElfShdr*, Sym*); +void shsym(ElfShdr*, LSym*); void phsh(ElfPhdr*, ElfShdr*); void doelf(void); void elfsetupplt(void); -void dwarfaddshstrings(Sym*); +void dwarfaddshstrings(LSym*); void dwarfaddelfsectionsyms(void); void dwarfaddelfheaders(void); void asmbelf(vlong symo); @@ -1010,6 +1010,7 @@ extern char freebsddynld[]; extern char netbsddynld[]; extern char openbsddynld[]; extern char dragonflydynld[]; +extern char solarisdynld[]; int elfreloc1(Reloc*, vlong sectoff); void putelfsectionsyms(void); diff --git a/src/cmd/ld/go.c b/src/cmd/ld/go.c index 39ffa3d87..9c296b740 100644 --- a/src/cmd/ld/go.c +++ b/src/cmd/ld/go.c @@ -151,28 +151,11 @@ ldpkg(Biobuf *f, char *pkg, int64 len, char *filename, int whence) } loadpkgdata(filename, pkg, p0, p1 - p0); } - - // The __.PKGDEF archive summary has no local types. + + // __.PKGDEF has no cgo section - those are in the C compiler-generated object files. if(whence == Pkgdef) return; - // local types begin where exports end. - // skip rest of line after $$ we found above - p0 = p1 + 3; - while(*p0 != '\n' && *p0 != '\0') - p0++; - - // local types end at next \n$$. - p1 = strstr(p0, "\n$$"); - if(p1 == nil) { - fprint(2, "%s: cannot find end of local types in %s\n", argv0, filename); - if(debug['u']) - errorexit(); - return; - } - - loadpkgdata(filename, pkg, p0, p1 - p0); - // look for cgo section p0 = strstr(p1, "\n$$ // cgo"); if(p0 != nil) { @@ -228,39 +211,6 @@ loadpkgdata(char *file, char *pkg, char *data, int len) free(file); } -// replace all "". with pkg. -char* -expandpkg(char *t0, char *pkg) -{ - int n; - char *p; - char *w, *w0, *t; - - n = 0; - for(p=t0; (p=strstr(p, "\"\".")) != nil; p+=3) - n++; - - if(n == 0) - return estrdup(t0); - - // use malloc, not mal, so that caller can free - w0 = malloc(strlen(t0) + strlen(pkg)*n); - if(w0 == nil) { - diag("out of memory"); - errorexit(); - } - w = w0; - for(p=t=t0; (p=strstr(p, "\"\".")) != nil; p=t) { - memmove(w, t, p - t); - w += p-t; - strcpy(w, pkg); - w += strlen(pkg); - t = p+2; - } - strcpy(w, t); - return w0; -} - static int parsepkgdata(char *file, char *pkg, char **pp, char *ep, char **prefixp, char **namep, char **defp) { @@ -413,7 +363,7 @@ loadcgo(char *file, char *pkg, char *p, int n) char *pend, *next, *p0, *q; char *f[10], *local, *remote, *lib; int nf; - Sym *s; + LSym *s; USED(file); pend = p + n; @@ -459,7 +409,7 @@ loadcgo(char *file, char *pkg, char *p, int n) q = strchr(remote, '#'); if(q) *q++ = '\0'; - s = lookup(local, 0); + s = linklookup(ctxt, local, 0); if(local != f[1]) free(local); if(s->type == 0 || s->type == SXREF || s->type == SHOSTOBJ) { @@ -477,7 +427,7 @@ loadcgo(char *file, char *pkg, char *p, int n) if(nf != 2) goto err; local = f[1]; - s = lookup(local, 0); + s = linklookup(ctxt, local, 0); s->type = SHOSTOBJ; s->size = 0; continue; @@ -496,9 +446,9 @@ loadcgo(char *file, char *pkg, char *p, int n) else remote = local; local = expandpkg(local, pkg); - s = lookup(local, 0); + s = linklookup(ctxt, local, 0); - if(flag_shared && s == lookup("main", 0)) + if(flag_shared && s == linklookup(ctxt, "main", 0)) continue; // export overrides import, for openbsd/cgo. @@ -562,11 +512,11 @@ err: nerrors++; } -static Sym *markq; -static Sym *emarkq; +static LSym *markq; +static LSym *emarkq; static void -mark1(Sym *s, Sym *parent) +mark1(LSym *s, LSym *parent) { if(s == S || s->reachable) return; @@ -582,7 +532,7 @@ mark1(Sym *s, Sym *parent) } void -mark(Sym *s) +mark(LSym *s) { mark1(s, nil); } @@ -591,23 +541,22 @@ static void markflood(void) { Auto *a; - Prog *p; - Sym *s; + LSym *s; int i; for(s=markq; s!=S; s=s->queue) { - if(s->text) { + if(s->type == STEXT) { 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); + if(s->pcln) { + for(i=0; i<s->pcln->nfuncdata; i++) + mark1(s->pcln->funcdata[i], s); + } mark1(s->gotype, s); mark1(s->sub, s); mark1(s->outer, s); @@ -639,51 +588,19 @@ markextra[] = "_modu", }; -static int -isz(Auto *a) -{ - for(; a; a=a->link) - if(a->type == D_FILE || a->type == D_FILE1) - return 1; - return 0; -} - -static void -addz(Sym *s, Auto *z) -{ - Auto *a, *last; - - // strip out non-z - last = nil; - for(a = z; a != nil; a = a->link) { - if(a->type == D_FILE || a->type == D_FILE1) { - if(last == nil) - z = a; - else - last->link = a; - last = a; - } - } - if(last) { - last->link = s->autom; - s->autom = z; - } -} - void deadcode(void) { int i; - Sym *s, *last, *p; - Auto *z; + LSym *s, *last, *p; Fmt fmt; if(debug['v']) Bprint(&bso, "%5.2f deadcode\n", cputime()); - mark(lookup(INITENTRY, 0)); + mark(linklookup(ctxt, INITENTRY, 0)); for(i=0; i<nelem(markextra); i++) - mark(lookup(markextra[i], 0)); + mark(linklookup(ctxt, markextra[i], 0)); for(i=0; i<ndynexp; i++) mark(dynexp[i]); @@ -691,37 +608,29 @@ deadcode(void) markflood(); // keep each beginning with 'typelink.' if the symbol it points at is being kept. - for(s = allsym; s != S; s = s->allsym) { + for(s = ctxt->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; - for(s = textp; s != nil; s = s->next) { - if(!s->reachable) { - if(isz(s->autom)) - z = s->autom; + for(s = ctxt->textp; s != nil; s = s->next) { + if(!s->reachable) continue; - } + // NOTE: Removing s from old textp and adding to new, shorter textp. if(last == nil) - textp = s; + ctxt->textp = s; else last->next = s; last = s; - if(z != nil) { - if(!isz(s->autom)) - addz(s, z); - z = nil; - } } if(last == nil) - textp = nil; + ctxt->textp = nil; else last->next = nil; - for(s = allsym; s != S; s = s->allsym) + for(s = ctxt->allsym; s != S; s = s->allsym) if(strncmp(s->name, "go.weak.", 8) == 0) { s->special = 1; // do not lay out in data segment s->reachable = 1; @@ -730,7 +639,7 @@ deadcode(void) // record field tracking references fmtstrinit(&fmt); - for(s = allsym; s != S; s = s->allsym) { + for(s = ctxt->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; @@ -746,7 +655,7 @@ deadcode(void) } if(tracksym == nil) return; - s = lookup(tracksym, 0); + s = linklookup(ctxt, tracksym, 0); if(!s->reachable) return; addstrdata(tracksym, fmtstrflush(&fmt)); @@ -755,13 +664,13 @@ deadcode(void) void doweak(void) { - Sym *s, *t; + LSym *s, *t; // resolve weak references only if // target symbol will be in binary anyway. - for(s = allsym; s != S; s = s->allsym) { + for(s = ctxt->allsym; s != S; s = s->allsym) { if(strncmp(s->name, "go.weak.", 8) == 0) { - t = rlookup(s->name+8, s->version); + t = linkrlookup(ctxt, s->name+8, s->version); if(t && t->type != 0 && t->reachable) { s->value = t->value; s->type = t->type; @@ -784,7 +693,7 @@ addexport(void) return; for(i=0; i<ndynexp; i++) - adddynsym(dynexp[i]); + adddynsym(ctxt, dynexp[i]); } /* %Z from gc, for quoting import paths */ diff --git a/src/cmd/ld/ldelf.c b/src/cmd/ld/ldelf.c index 27041bc47..1d7c4c13e 100644 --- a/src/cmd/ld/ldelf.c +++ b/src/cmd/ld/ldelf.c @@ -258,7 +258,7 @@ struct ElfSect uint64 align; uint64 entsize; uchar *base; - Sym *sym; + LSym *sym; }; struct ElfObj @@ -301,7 +301,7 @@ struct ElfSym uchar type; uchar other; uint16 shndx; - Sym* sym; + LSym* sym; }; uchar ElfMagic[4] = { 0x7F, 'E', 'L', 'F' }; @@ -312,7 +312,7 @@ static int readsym(ElfObj*, int i, ElfSym*, int); static int reltype(char*, int, uchar*); int -valuecmp(Sym *a, Sym *b) +valuecmp(LSym *a, LSym *b) { if(a->value < b->value) return -1; @@ -336,15 +336,15 @@ ldelf(Biobuf *f, char *pkg, int64 len, char *pn) ElfSym sym; Endian *e; Reloc *r, *rp; - Sym *s; - Sym **symbols; + LSym *s; + LSym **symbols; symbols = nil; if(debug['v']) Bprint(&bso, "%5.2f ldelf %s\n", cputime(), pn); - version++; + ctxt->version++; base = Boffset(f); if(Bread(f, hdrbuf, sizeof hdrbuf) != sizeof hdrbuf) @@ -529,7 +529,7 @@ ldelf(Biobuf *f, char *pkg, int64 len, char *pn) goto bad; name = smprint("%s(%s)", pkg, sect->name); - s = lookup(name, version); + s = linklookup(ctxt, name, ctxt->version); free(name); switch((int)sect->flags&(ElfSectFlagAlloc|ElfSectFlagWrite|ElfSectFlagExec)) { default: @@ -601,24 +601,9 @@ ldelf(Biobuf *f, char *pkg, int64 len, char *pn) s->size = sym.size; s->outer = sect->sym; if(sect->sym->type == STEXT) { - Prog *p; - - if(s->text != P) { - if(!s->dupok) + if(s->external && !s->dupok) diag("%s: duplicate definition of %s", pn, s->name); - } else { - // build a TEXT instruction with a unique pc - // just to make the rest of the linker happy. - p = prg(); - p->as = ATEXT; - p->from.type = D_EXTERN; - p->from.sym = s; - p->textflag = 7; - p->to.type = D_CONST; - p->link = nil; - p->pc = pc++; - s->text = p; - } + s->external = 1; } } @@ -629,16 +614,22 @@ ldelf(Biobuf *f, char *pkg, int64 len, char *pn) if(s == S) continue; if(s->sub) - s->sub = listsort(s->sub, valuecmp, offsetof(Sym, sub)); + s->sub = listsort(s->sub, valuecmp, offsetof(LSym, sub)); if(s->type == STEXT) { - if(etextp) - etextp->next = s; + if(s->onlist) + sysfatal("symbol %s listed multiple times", s->name); + s->onlist = 1; + if(ctxt->etextp) + ctxt->etextp->next = s; else - textp = s; - etextp = s; + ctxt->textp = s; + ctxt->etextp = s; for(s = s->sub; s != S; s = s->sub) { - etextp->next = s; - etextp = s; + if(s->onlist) + sysfatal("symbol %s listed multiple times", s->name); + s->onlist = 1; + ctxt->etextp->next = s; + ctxt->etextp = s; } } } @@ -712,6 +703,9 @@ ldelf(Biobuf *f, char *pkg, int64 len, char *pn) else diag("invalid rela size %d", rp->siz); } + if(rp->siz == 4) + rp->add = (int32)rp->add; + //print("rel %s %d %d %s %#llx\n", sect->sym->name, rp->type, rp->siz, rp->sym->name, rp->add); } qsort(r, n, sizeof r[0], rbyoff); // just in case @@ -761,7 +755,7 @@ map(ElfObj *obj, ElfSect *sect) static int readsym(ElfObj *obj, int i, ElfSym *sym, int needSym) { - Sym *s; + LSym *s; if(i >= obj->nsymtab || i < 0) { werrstr("invalid elf symbol index"); @@ -808,7 +802,7 @@ readsym(ElfObj *obj, int i, ElfSym *sym, int needSym) switch(sym->bind) { case ElfSymBindGlobal: if(needSym) { - s = lookup(sym->name, 0); + s = linklookup(ctxt, sym->name, 0); // for global scoped hidden symbols we should insert it into // symbol hash table, but mark them as hidden. // __i686.get_pc_thunk.bx is allowed to be duplicated, to @@ -828,13 +822,13 @@ readsym(ElfObj *obj, int i, ElfSym *sym, int needSym) // local names and hidden visiblity global names are unique // and should only reference by its index, not name, so we // don't bother to add them into hash table - s = newsym(sym->name, version); + s = linknewsym(ctxt, sym->name, ctxt->version); s->type |= SHIDDEN; } break; case ElfSymBindWeak: if(needSym) { - s = newsym(sym->name, 0); + s = linknewsym(ctxt, sym->name, 0); if(sym->other == 2) s->type |= SHIDDEN; } diff --git a/src/cmd/ld/ldmacho.c b/src/cmd/ld/ldmacho.c index e0f5405f6..413dedabd 100644 --- a/src/cmd/ld/ldmacho.c +++ b/src/cmd/ld/ldmacho.c @@ -102,7 +102,7 @@ struct MachoSect uint32 flags; uint32 res1; uint32 res2; - Sym *sym; + LSym *sym; MachoRel *rel; }; @@ -138,7 +138,7 @@ struct MachoSym uint16 desc; char kind; uint64 value; - Sym *sym; + LSym *sym; }; struct MachoDysymtab @@ -432,7 +432,7 @@ ldmacho(Biobuf *f, char *pkg, int64 len, char *pn) int64 base; MachoSect *sect; MachoRel *rel; - Sym *s, *s1, *outer; + LSym *s, *s1, *outer; MachoCmd *c; MachoSymtab *symtab; MachoDysymtab *dsymtab; @@ -440,7 +440,7 @@ ldmacho(Biobuf *f, char *pkg, int64 len, char *pn) Reloc *r, *rp; char *name; - version++; + ctxt->version++; base = Boffset(f); if(Bread(f, hdr, sizeof hdr) != sizeof hdr) goto bad; @@ -507,6 +507,7 @@ ldmacho(Biobuf *f, char *pkg, int64 len, char *pn) c = nil; symtab = nil; dsymtab = nil; + USED(dsymtab); for(i=0; i<ncmd; i++){ ty = e->e32(cmdp); sz = e->e32(cmdp+4); @@ -566,7 +567,7 @@ ldmacho(Biobuf *f, char *pkg, int64 len, char *pn) if(strcmp(sect->name, "__eh_frame") == 0) continue; name = smprint("%s(%s/%s)", pkg, sect->segname, sect->name); - s = lookup(name, version); + s = linklookup(ctxt, name, ctxt->version); if(s->type != 0) { werrstr("duplicate %s/%s", sect->segname, sect->name); goto bad; @@ -609,8 +610,8 @@ ldmacho(Biobuf *f, char *pkg, int64 len, char *pn) name++; v = 0; if(!(sym->type&N_EXT)) - v = version; - s = lookup(name, v); + v = ctxt->version; + s = linklookup(ctxt, name, v); if(!(sym->type&N_EXT)) s->dupok = 1; sym->sym = s; @@ -640,22 +641,9 @@ ldmacho(Biobuf *f, char *pkg, int64 len, char *pn) if(!(s->cgoexport & CgoExportDynamic)) s->dynimplib = nil; // satisfy dynimport if(outer->type == STEXT) { - Prog *p; - - if(s->text != P) - diag("%s sym#%d: duplicate definition of %s", pn, i, s->name); - // build a TEXT instruction with a unique pc - // just to make the rest of the linker happy. - // TODO: this is too 6l-specific ? - p = prg(); - p->as = ATEXT; - p->from.type = D_EXTERN; - p->from.sym = s; - p->textflag = 7; - p->to.type = D_CONST; - p->link = nil; - p->pc = pc++; - s->text = p; + if(s->external && !s->dupok) + diag("%s: duplicate definition of %s", pn, s->name); + s->external = 1; } sym->sym = s; } @@ -667,7 +655,7 @@ ldmacho(Biobuf *f, char *pkg, int64 len, char *pn) if((s = sect->sym) == S) continue; if(s->sub) { - s->sub = listsort(s->sub, valuecmp, offsetof(Sym, sub)); + s->sub = listsort(s->sub, valuecmp, offsetof(LSym, sub)); // assign sizes, now that we know symbols in sorted order. for(s1 = s->sub; s1 != S; s1 = s1->sub) { @@ -678,14 +666,20 @@ ldmacho(Biobuf *f, char *pkg, int64 len, char *pn) } } if(s->type == STEXT) { - if(etextp) - etextp->next = s; + if(s->onlist) + sysfatal("symbol %s listed multiple times", s->name); + s->onlist = 1; + if(ctxt->etextp) + ctxt->etextp->next = s; else - textp = s; - etextp = s; + ctxt->textp = s; + ctxt->etextp = s; for(s1 = s->sub; s1 != S; s1 = s1->sub) { - etextp->next = s1; - etextp = s1; + if(s1->onlist) + sysfatal("symbol %s listed multiple times", s1->name); + s1->onlist = 1; + ctxt->etextp->next = s1; + ctxt->etextp = s1; } } } @@ -743,7 +737,7 @@ ldmacho(Biobuf *f, char *pkg, int64 len, char *pn) // want to make it pc-relative aka relative to rp->off+4 // but the scatter asks for relative to off = (rel+1)->value - sect->addr. // adjust rp->add accordingly. - rp->type = D_PCREL; + rp->type = R_PCREL; rp->add += (rp->off+4) - ((rel+1)->value - sect->addr); // now consider the desired symbol. diff --git a/src/cmd/ld/ldpe.c b/src/cmd/ld/ldpe.c index 6bcda2cb6..f6eda900d 100644 --- a/src/cmd/ld/ldpe.c +++ b/src/cmd/ld/ldpe.c @@ -102,14 +102,14 @@ struct PeSym { uint16 type; uint8 sclass; uint8 aux; - Sym* sym; + LSym* sym; }; struct PeSect { char* name; uchar* base; uint64 size; - Sym* sym; + LSym* sym; IMAGE_SECTION_HEADER sh; }; @@ -141,7 +141,7 @@ ldpe(Biobuf *f, char *pkg, int64 len, char *pn) PeSect *sect, *rsect; IMAGE_SECTION_HEADER sh; uchar symbuf[18]; - Sym *s; + LSym *s; Reloc *r, *rp; PeSym *sym; @@ -150,7 +150,7 @@ ldpe(Biobuf *f, char *pkg, int64 len, char *pn) Bprint(&bso, "%5.2f ldpe %s\n", cputime(), pn); sect = nil; - version++; + ctxt->version++; base = Boffset(f); obj = mal(sizeof *obj); @@ -222,7 +222,7 @@ ldpe(Biobuf *f, char *pkg, int64 len, char *pn) goto bad; name = smprint("%s(%s)", pkg, sect->name); - s = lookup(name, version); + s = linklookup(ctxt, name, ctxt->version); free(name); switch(sect->sh.Characteristics&(IMAGE_SCN_CNT_UNINITIALIZED_DATA|IMAGE_SCN_CNT_INITIALIZED_DATA| IMAGE_SCN_MEM_READ|IMAGE_SCN_MEM_WRITE|IMAGE_SCN_CNT_CODE|IMAGE_SCN_MEM_EXECUTE)) { @@ -290,18 +290,18 @@ ldpe(Biobuf *f, char *pkg, int64 len, char *pn) case IMAGE_REL_AMD64_REL32: case IMAGE_REL_AMD64_ADDR32: // R_X86_64_PC32 case IMAGE_REL_AMD64_ADDR32NB: - rp->type = D_PCREL; + rp->type = R_PCREL; rp->add = (int32)le32(rsect->base+rp->off); break; case IMAGE_REL_I386_DIR32NB: case IMAGE_REL_I386_DIR32: - rp->type = D_ADDR; + rp->type = R_ADDR; // load addend from image - rp->add = le32(rsect->base+rp->off); + rp->add = (int32)le32(rsect->base+rp->off); break; case IMAGE_REL_AMD64_ADDR64: // R_X86_64_64 rp->siz = 8; - rp->type = D_ADDR; + rp->type = R_ADDR; // load addend from image rp->add = le64(rsect->base+rp->off); break; @@ -366,21 +366,9 @@ ldpe(Biobuf *f, char *pkg, int64 len, char *pn) s->size = 4; s->outer = sect->sym; if(sect->sym->type == STEXT) { - Prog *p; - - if(s->text != P) + if(s->external && !s->dupok) diag("%s: duplicate definition of %s", pn, s->name); - // build a TEXT instruction with a unique pc - // just to make the rest of the linker happy. - p = prg(); - p->as = ATEXT; - p->from.type = D_EXTERN; - p->from.sym = s; - p->textflag = 7; - p->to.type = D_CONST; - p->link = nil; - p->pc = pc++; - s->text = p; + s->external = 1; } } @@ -391,16 +379,22 @@ ldpe(Biobuf *f, char *pkg, int64 len, char *pn) if(s == S) continue; if(s->sub) - s->sub = listsort(s->sub, valuecmp, offsetof(Sym, sub)); + s->sub = listsort(s->sub, valuecmp, offsetof(LSym, sub)); if(s->type == STEXT) { - if(etextp) - etextp->next = s; + if(s->onlist) + sysfatal("symbol %s listed multiple times", s->name); + s->onlist = 1; + if(ctxt->etextp) + ctxt->etextp->next = s; else - textp = s; - etextp = s; + ctxt->textp = s; + ctxt->etextp = s; for(s = s->sub; s != S; s = s->sub) { - etextp->next = s; - etextp = s; + if(s->onlist) + sysfatal("symbol %s listed multiple times", s->name); + s->onlist = 1; + ctxt->etextp->next = s; + ctxt->etextp = s; } } } @@ -430,7 +424,7 @@ map(PeObj *obj, PeSect *sect) static int readsym(PeObj *obj, int i, PeSym **y) { - Sym *s; + LSym *s; PeSym *sym; char *name, *p; @@ -464,12 +458,12 @@ readsym(PeObj *obj, int i, PeSym **y) case IMAGE_SYM_DTYPE_NULL: switch(sym->sclass) { case IMAGE_SYM_CLASS_EXTERNAL: //global - s = lookup(name, 0); + s = linklookup(ctxt, name, 0); break; case IMAGE_SYM_CLASS_NULL: case IMAGE_SYM_CLASS_STATIC: case IMAGE_SYM_CLASS_LABEL: - s = lookup(name, version); + s = linklookup(ctxt, name, ctxt->version); s->dupok = 1; break; default: diff --git a/src/cmd/ld/lib.c b/src/cmd/ld/lib.c index da522dc0c..da6194e4f 100644 --- a/src/cmd/ld/lib.c +++ b/src/cmd/ld/lib.c @@ -32,10 +32,14 @@ #include "l.h" #include "lib.h" #include "../ld/elf.h" +#include "../ld/dwarf.h" #include "../../pkg/runtime/stack.h" #include "../../pkg/runtime/funcdata.h" #include <ar.h> +#if !(defined(_WIN32) || defined(PLAN9)) +#include <sys/stat.h> +#endif enum { @@ -48,18 +52,9 @@ int iconv(Fmt*); char symname[] = SYMDEF; char pkgname[] = "__.PKGDEF"; -char** libdir; -int nlibdir = 0; -static int maxlibdir = 0; static int cout = -1; -// symbol version, incremented each time a file is loaded. -// version==1 is reserved for savehist. -enum -{ - HistVersion = 1, -}; -int version = HistVersion; +extern int version; // Set if we see an object compiled by the host compiler that is not // from a package that is known to support internal linking mode. @@ -77,15 +72,32 @@ Lflag(char *arg) { char **p; - if(nlibdir >= maxlibdir) { - if (maxlibdir == 0) - maxlibdir = 8; + if(ctxt->nlibdir >= ctxt->maxlibdir) { + if (ctxt->maxlibdir == 0) + ctxt->maxlibdir = 8; else - maxlibdir *= 2; - p = erealloc(libdir, maxlibdir * sizeof(*p)); - libdir = p; + ctxt->maxlibdir *= 2; + p = erealloc(ctxt->libdir, ctxt->maxlibdir * sizeof(*p)); + ctxt->libdir = p; } - libdir[nlibdir++] = arg; + ctxt->libdir[ctxt->nlibdir++] = arg; +} + +/* + * Unix doesn't like it when we write to a running (or, sometimes, + * recently run) binary, so remove the output file before writing it. + * On Windows 7, remove() can force a subsequent create() to fail. + * S_ISREG() does not exist on Plan 9. + */ +static void +mayberemoveoutfile(void) +{ +#if !(defined(_WIN32) || defined(PLAN9)) + struct stat st; + if(lstat(outfile, &st) == 0 && !S_ISREG(st.st_mode)) + return; +#endif + remove(outfile); } void @@ -93,12 +105,11 @@ libinit(void) { char *suffix, *suffixsep; + funcalign = FuncAlign; fmtinstall('i', iconv); fmtinstall('Y', Yconv); fmtinstall('Z', Zconv); mywhatsys(); // get goroot, goarch, goos - if(strcmp(goarch, thestring) != 0) - print("goarch is not known: %s\n", goarch); // add goroot to the end of the libdir list. suffix = ""; @@ -112,12 +123,7 @@ libinit(void) } Lflag(smprint("%s/pkg/%s_%s%s%s", goroot, goos, goarch, suffixsep, suffix)); - // Unix doesn't like it when we write to a running (or, sometimes, - // recently run) binary, so remove the output file before writing it. - // On Windows 7, remove() can force the following create() to fail. -#ifndef _WIN32 - remove(outfile); -#endif + mayberemoveoutfile(); cout = create(outfile, 1, 0775); if(cout < 0) { diag("cannot create %s: %r", outfile); @@ -132,7 +138,7 @@ libinit(void) sprint(INITENTRY, "_rt0_%s_%s_lib", goarch, goos); } } - lookup(INITENTRY, 0)->type = SXREF; + linklookup(ctxt, INITENTRY, 0)->type = SXREF; } void @@ -140,165 +146,25 @@ errorexit(void) { if(nerrors) { if(cout >= 0) - remove(outfile); + mayberemoveoutfile(); exits("error"); } exits(0); } void -addlib(char *src, char *obj) -{ - char name[1024], pname[1024], comp[256], *p; - int i, search; - - if(histfrogp <= 0) - return; - - search = 0; - if(histfrog[0]->name[1] == '/') { - sprint(name, ""); - i = 1; - } else - if(isalpha((uchar)histfrog[0]->name[1]) && histfrog[0]->name[2] == ':') { - strcpy(name, histfrog[0]->name+1); - i = 1; - } else - if(histfrog[0]->name[1] == '.') { - sprint(name, "."); - i = 0; - } else { - sprint(name, ""); - i = 0; - search = 1; - } - - for(; i<histfrogp; i++) { - snprint(comp, sizeof comp, "%s", histfrog[i]->name+1); - for(;;) { - p = strstr(comp, "$O"); - if(p == 0) - break; - memmove(p+1, p+2, strlen(p+2)+1); - p[0] = thechar; - } - for(;;) { - p = strstr(comp, "$M"); - if(p == 0) - break; - if(strlen(comp)+strlen(thestring)-2+1 >= sizeof comp) { - diag("library component too long"); - return; - } - memmove(p+strlen(thestring), p+2, strlen(p+2)+1); - memmove(p, thestring, strlen(thestring)); - } - if(strlen(name) + strlen(comp) + 3 >= sizeof(name)) { - diag("library component too long"); - return; - } - if(i > 0 || !search) - strcat(name, "/"); - 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. - for(i=0; i<nlibdir; i++) { - snprint(pname, sizeof pname, "%s/%s", libdir[i], name); - if(access(pname, AEXIST) >= 0) - break; - } - }else - strcpy(pname, name); - cleanname(pname); - - /* runtime.a -> runtime */ - if(p != nil) - *p = '\0'; - - if(debug['v'] > 1) - Bprint(&bso, "%5.2f addlib: %s %s pulls in %s\n", cputime(), obj, src, pname); - - addlibpath(src, obj, pname, name); -} - -/* - * add library to library list. - * srcref: src file referring to package - * objref: object file referring to package - * file: object file, e.g., /home/rsc/go/pkg/container/vector.a - * pkg: package import path, e.g. container/vector - */ -void -addlibpath(char *srcref, char *objref, char *file, char *pkg) -{ - int i; - Library *l; - char *p; - - for(i=0; i<libraryp; i++) - if(strcmp(file, library[i].file) == 0) - return; - - if(debug['v'] > 1) - Bprint(&bso, "%5.2f addlibpath: srcref: %s objref: %s file: %s pkg: %s\n", - cputime(), srcref, objref, file, pkg); - - if(libraryp == nlibrary){ - nlibrary = 50 + 2*libraryp; - library = erealloc(library, sizeof library[0] * nlibrary); - } - - l = &library[libraryp++]; - - p = mal(strlen(objref) + 1); - strcpy(p, objref); - l->objref = p; - - p = mal(strlen(srcref) + 1); - strcpy(p, srcref); - l->srcref = p; - - p = mal(strlen(file) + 1); - strcpy(p, file); - l->file = p; - - p = mal(strlen(pkg) + 1); - strcpy(p, pkg); - l->pkg = p; -} - -void loadinternal(char *name) { char pname[1024]; int i, found; found = 0; - for(i=0; i<nlibdir; i++) { - snprint(pname, sizeof pname, "%s/%s.a", libdir[i], name); + for(i=0; i<ctxt->nlibdir; i++) { + snprint(pname, sizeof pname, "%s/%s.a", ctxt->libdir[i], name); if(debug['v']) Bprint(&bso, "searching for %s.a in %s\n", name, pname); if(access(pname, AEXIST) >= 0) { - addlibpath("internal", "internal", pname, name); + addlibpath(ctxt, "internal", "internal", pname, name); found = 1; break; } @@ -311,12 +177,13 @@ void loadlib(void) { int i, w, x; - Sym *s, *gmsym; + LSym *s, *gmsym; + char* cgostrsym; if(flag_shared) { - s = lookup("runtime.islibrary", 0); + s = linklookup(ctxt, "runtime.islibrary", 0); s->dupok = 1; - adduint8(s, 1); + adduint8(ctxt, s, 1); } loadinternal("runtime"); @@ -324,27 +191,36 @@ loadlib(void) loadinternal("math"); if(flag_race) loadinternal("runtime/race"); - if(linkmode == LinkExternal) { + + for(i=0; i<ctxt->libraryp; i++) { + if(debug['v'] > 1) + Bprint(&bso, "%5.2f autolib: %s (from %s)\n", cputime(), ctxt->library[i].file, ctxt->library[i].objref); + iscgo |= strcmp(ctxt->library[i].pkg, "runtime/cgo") == 0; + objfile(ctxt->library[i].file, ctxt->library[i].pkg); + } + + if(linkmode == LinkExternal && !iscgo) { // This indicates a user requested -linkmode=external. // The startup code uses an import of runtime/cgo to decide // whether to initialize the TLS. So give it one. This could // be handled differently but it's an unusual case. loadinternal("runtime/cgo"); + if(i < ctxt->libraryp) + objfile(ctxt->library[i].file, ctxt->library[i].pkg); + // Pretend that we really imported the package. - // This will do no harm if we did in fact import it. - s = lookup("go.importpath.runtime/cgo.", 0); + s = linklookup(ctxt, "go.importpath.runtime/cgo.", 0); s->type = SDATA; s->dupok = 1; s->reachable = 1; - } - for(i=0; i<libraryp; i++) { - if(debug['v'] > 1) - Bprint(&bso, "%5.2f autolib: %s (from %s)\n", cputime(), library[i].file, library[i].objref); - iscgo |= strcmp(library[i].pkg, "runtime/cgo") == 0; - objfile(library[i].file, library[i].pkg); + // Provided by the code that imports the package. + // Since we are simulating the import, we have to provide this string. + cgostrsym = "go.string.\"runtime/cgo\""; + if(linkrlookup(ctxt, cgostrsym, 0) == nil) + addstrdata(cgostrsym, "runtime/cgo"); } - + if(linkmode == LinkAuto) { if(iscgo && externalobj) linkmode = LinkExternal; @@ -355,7 +231,7 @@ loadlib(void) if(linkmode == LinkInternal) { // Drop all the cgo_import_static declarations. // Turns out we won't be needing them. - for(s = allsym; s != S; s = s->allsym) + for(s = ctxt->allsym; s != S; s = s->allsym) if(s->type == SHOSTOBJ) { // If a symbol was marked both // cgo_import_static and cgo_import_dynamic, @@ -368,14 +244,12 @@ loadlib(void) } } - gmsym = lookup("runtime.tlsgm", 0); + gmsym = linklookup(ctxt, "runtime.tlsgm", 0); gmsym->type = STLSBSS; gmsym->size = 2*PtrSize; gmsym->hide = 1; - if(linkmode == LinkExternal && iself && HEADTYPE != Hopenbsd) - gmsym->reachable = 1; - else - gmsym->reachable = 0; + gmsym->reachable = 1; + ctxt->gmsym = gmsym; // Now that we know the link mode, trim the dynexp list. x = CgoExportDynamic; @@ -402,7 +276,9 @@ loadlib(void) // // Exception: on OS X, programs such as Shark only work with dynamic // binaries, so leave it enabled on OS X (Mach-O) binaries. - if(!flag_shared && !havedynamic && HEADTYPE != Hdarwin) + // Also leave it enabled on Solaris which doesn't support + // statically linked binaries. + if(!flag_shared && !havedynamic && HEADTYPE != Hdarwin && HEADTYPE != Hsolaris) debug['d'] = 1; importcycles(); @@ -412,8 +288,8 @@ loadlib(void) * look for the next file in an archive. * adapted from libmach. */ -int -nextar(Biobuf *bp, int off, struct ar_hdr *a) +static vlong +nextar(Biobuf *bp, vlong off, struct ar_hdr *a) { int r; int32 arsize; @@ -443,7 +319,7 @@ nextar(Biobuf *bp, int off, struct ar_hdr *a) void objfile(char *file, char *pkg) { - int32 off, l; + vlong off, l; Biobuf *f; char magbuf[SARMAG]; char pname[150]; @@ -470,25 +346,24 @@ objfile(char *file, char *pkg) return; } - /* skip over __.GOSYMDEF */ + /* skip over optional __.GOSYMDEF and process __.PKGDEF */ off = Boffset(f); - if((l = nextar(f, off, &arhdr)) <= 0) { + l = nextar(f, off, &arhdr); + if(l <= 0) { diag("%s: short read on archive file symbol header", file); goto out; } - if(strncmp(arhdr.name, symname, strlen(symname))) { - diag("%s: first entry not symbol header", file); - goto out; - } - 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, symname, strlen(symname)) == 0) { + off += l; + l = nextar(f, off, &arhdr); + if(l <= 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); + diag("%s: cannot find package header", file); goto out; } off += l; @@ -539,7 +414,7 @@ dowrite(int fd, char *p, int n) while(n > 0) { m = write(fd, p, n); if(m <= 0) { - cursym = S; + ctxt->cursym = S; diag("write error: %r"); errorexit(); } @@ -628,7 +503,7 @@ hostobjs(void) h = &hostobj[i]; f = Bopen(h->file, OREAD); if(f == nil) { - cursym = S; + ctxt->cursym = S; diag("cannot reopen %s: %r", h->pn); errorexit(); } @@ -697,7 +572,7 @@ hostlink(void) p = strchr(p + 1, ' '); } - argv = malloc((13+nhostobj+nldflag+c)*sizeof argv[0]); + argv = malloc((14+nhostobj+nldflag+c)*sizeof argv[0]); argc = 0; if(extld == nil) extld = "gcc"; @@ -720,6 +595,8 @@ hostlink(void) } if(HEADTYPE == Hdarwin) argv[argc++] = "-Wl,-no_pie,-pagezero_size,4000000"; + if(HEADTYPE == Hopenbsd) + argv[argc++] = "-Wl,-nopie"; if(iself && AssumeGoldLinker) argv[argc++] = "-Wl,--rosegment"; @@ -738,13 +615,16 @@ hostlink(void) if(iself) argv[argc++] = "-rdynamic"; + if(strstr(argv[0], "clang") != nil) + argv[argc++] = "-Qunused-arguments"; + // already wrote main object file // copy host objects to temporary directory for(i=0; i<nhostobj; i++) { h = &hostobj[i]; f = Bopen(h->file, OREAD); if(f == nil) { - cursym = S; + ctxt->cursym = S; diag("cannot reopen %s: %r", h->pn); errorexit(); } @@ -753,7 +633,7 @@ hostlink(void) argv[argc++] = p; w = create(p, 1, 0775); if(w < 0) { - cursym = S; + ctxt->cursym = S; diag("cannot create %s: %r", p); errorexit(); } @@ -765,7 +645,7 @@ hostlink(void) len -= n; } if(close(w) < 0) { - cursym = S; + ctxt->cursym = S; diag("cannot write %s: %r", p); errorexit(); } @@ -783,6 +663,20 @@ hostlink(void) if(*p == '\0') break; argv[argc++] = p; + + // clang, unlike GCC, passes -rdynamic to the linker + // even when linking with -static, causing a linker + // error when using GNU ld. So take out -rdynamic if + // we added it. We do it in this order, rather than + // only adding -rdynamic later, so that -extldflags + // can override -rdynamic without using -static. + if(iself && strncmp(p, "-static", 7) == 0 && (p[7]==' ' || p[7]=='\0')) { + for(i=0; i<argc; i++) { + if(strcmp(argv[i], "-rdynamic") == 0) + argv[i] = "-static"; + } + } + p = strchr(p + 1, ' '); } @@ -798,7 +692,7 @@ hostlink(void) } if(runcmd(argv) < 0) { - cursym = S; + ctxt->cursym = S; diag("%s: running %s failed: %r", argv0, argv[0]); errorexit(); } @@ -866,8 +760,8 @@ ldobj(Biobuf *f, char *pkg, int64 len, char *pn, char *file, int whence) return; } - // First, check that the basic goos, string, and version match. - t = smprint("%s %s %s ", goos, thestring, getgoversion()); + // First, check that the basic goos, goarch, and version match. + t = smprint("%s %s %s ", goos, getgoarch(), getgoversion()); line[n] = ' '; if(strncmp(line+10, t, strlen(t)) != 0 && !debug['f']) { line[n] = '\0'; @@ -913,7 +807,7 @@ ldobj(Biobuf *f, char *pkg, int64 len, char *pn, char *file, int whence) ldpkg(f, pkg, import1 - import0 - 2, pn, whence); // -2 for !\n Bseek(f, import1, 0); - ldobj1(f, pkg, eof - Boffset(f), pn); + ldobjfile(ctxt, f, pkg, eof - Boffset(f), pn); free(pn); return; @@ -922,318 +816,12 @@ eof: free(pn); } -Sym* -newsym(char *symb, int v) -{ - Sym *s; - int l; - - l = strlen(symb) + 1; - s = mal(sizeof(*s)); - if(debug['v'] > 1) - Bprint(&bso, "newsym %s\n", symb); - - s->dynid = -1; - s->plt = -1; - s->got = -1; - s->name = mal(l + 1); - memmove(s->name, symb, l); - - s->type = 0; - s->version = v; - s->value = 0; - s->sig = 0; - s->size = 0; - nsymbol++; - - s->allsym = allsym; - allsym = s; - - return s; -} - -static Sym* -_lookup(char *symb, int v, int creat) -{ - Sym *s; - char *p; - uint32 h; - int c; - - h = v; - for(p=symb; c = *p; p++) - h = h+h+h + c; - // 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->hash) - if(strcmp(s->name, symb) == 0) - return s; - if(!creat) - return nil; - - s = newsym(symb, v); - s->extname = s->name; - s->hash = hash[h]; - hash[h] = s; - - return s; -} - -Sym* -lookup(char *name, int v) -{ - return _lookup(name, v, 1); -} - -// read-only lookup -Sym* -rlookup(char *name, int v) -{ - return _lookup(name, v, 0); -} - -void -copyhistfrog(char *buf, int nbuf) -{ - char *p, *ep; - int i; - - p = buf; - ep = buf + nbuf; - for(i=0; i<histfrogp; i++) { - p = seprint(p, ep, "%s", histfrog[i]->name+1); - if(i+1<histfrogp && (p == buf || p[-1] != '/')) - p = seprint(p, ep, "/"); - } -} - -void -addhist(int32 line, int type) -{ - Auto *u; - Sym *s; - int i, j, k; - - u = mal(sizeof(Auto)); - s = mal(sizeof(Sym)); - s->name = mal(2*(histfrogp+1) + 1); - - u->asym = s; - u->type = type; - u->aoffset = line; - u->link = curhist; - curhist = u; - - s->name[0] = 0; - j = 1; - for(i=0; i<histfrogp; i++) { - k = histfrog[i]->value; - s->name[j+0] = k>>8; - s->name[j+1] = k; - j += 2; - } - s->name[j] = 0; - s->name[j+1] = 0; -} - -void -histtoauto(void) -{ - Auto *l; - - while(l = curhist) { - curhist = l->link; - l->link = curauto; - curauto = l; - } -} - -void -collapsefrog(Sym *s) -{ - int i; - - /* - * bad encoding of path components only allows - * MAXHIST components. if there is an overflow, - * first try to collapse xxx/.. - */ - for(i=1; i<histfrogp; i++) - if(strcmp(histfrog[i]->name+1, "..") == 0) { - memmove(histfrog+i-1, histfrog+i+1, - (histfrogp-i-1)*sizeof(histfrog[0])); - histfrogp--; - goto out; - } - - /* - * next try to collapse . - */ - for(i=0; i<histfrogp; i++) - if(strcmp(histfrog[i]->name+1, ".") == 0) { - memmove(histfrog+i, histfrog+i+1, - (histfrogp-i-1)*sizeof(histfrog[0])); - goto out; - } - - /* - * last chance, just truncate from front - */ - memmove(histfrog+0, histfrog+1, - (histfrogp-1)*sizeof(histfrog[0])); - -out: - histfrog[histfrogp-1] = s; -} - -void -nuxiinit(void) -{ - int i, c; - - for(i=0; i<4; i++) { - c = find1(0x04030201L, i+1); - if(i < 2) - inuxi2[i] = c; - if(i < 1) - inuxi1[i] = c; - inuxi4[i] = c; - 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; - } - if(debug['v']) { - Bprint(&bso, "inuxi = "); - for(i=0; i<1; i++) - Bprint(&bso, "%d", inuxi1[i]); - Bprint(&bso, " "); - for(i=0; i<2; i++) - Bprint(&bso, "%d", inuxi2[i]); - Bprint(&bso, " "); - for(i=0; i<4; i++) - Bprint(&bso, "%d", inuxi4[i]); - Bprint(&bso, " "); - for(i=0; i<8; i++) - Bprint(&bso, "%d", inuxi8[i]); - Bprint(&bso, "\nfnuxi = "); - for(i=0; i<4; i++) - Bprint(&bso, "%d", fnuxi4[i]); - Bprint(&bso, " "); - for(i=0; i<8; i++) - Bprint(&bso, "%d", fnuxi8[i]); - Bprint(&bso, "\n"); - } - Bflush(&bso); -} - -int -find1(int32 l, int c) -{ - char *p; - int i; - - p = (char*)&l; - for(i=0; i<4; i++) - if(*p++ == c) - return i; - return 0; -} - -int -find2(int32 l, int c) -{ - union { - int32 l; - short p[2]; - } u; - short *p; - int i; - - u.l = l; - p = u.p; - for(i=0; i<4; i+=2) { - if(((*p >> 8) & 0xff) == c) - return i; - if((*p++ & 0xff) == c) - return i+1; - } - return 0; -} - -int32 -ieeedtof(Ieee *e) -{ - int exp; - int32 v; - - if(e->h == 0) - return 0; - exp = (e->h>>20) & ((1L<<11)-1L); - exp -= (1L<<10) - 2L; - v = (e->h & 0xfffffL) << 3; - v |= (e->l >> 29) & 0x7L; - if((e->l >> 28) & 1) { - v++; - if(v & 0x800000L) { - v = (v & 0x7fffffL) >> 1; - exp++; - } - } - if(-148 <= exp && exp <= -126) { - v |= 1<<23; - v >>= -125 - exp; - exp = -126; - } - else if(exp < -148 || exp >= 130) - diag("double fp to single fp overflow: %.17g", ieeedtod(e)); - v |= ((exp + 126) & 0xffL) << 23; - v |= e->h & 0x80000000L; - return v; -} - -double -ieeedtod(Ieee *ieeep) -{ - Ieee e; - double fr; - int exp; - - if(ieeep->h & (1L<<31)) { - e.h = ieeep->h & ~(1L<<31); - e.l = ieeep->l; - return -ieeedtod(&e); - } - if(ieeep->l == 0 && ieeep->h == 0) - return 0; - exp = (ieeep->h>>20) & ((1L<<11)-1L); - exp -= (1L<<10) - 2L; - fr = ieeep->l & ((1L<<16)-1L); - fr /= 1L<<16; - fr += (ieeep->l>>16) & ((1L<<16)-1L); - fr /= 1L<<16; - if(exp == -(1L<<10) - 2L) { - fr += (ieeep->h & (1L<<20)-1L); - exp++; - } else - fr += (ieeep->h & (1L<<20)-1L) | (1L<<20); - fr /= 1L<<21; - return ldexp(fr, exp); -} - void zerosig(char *sp) { - Sym *s; + LSym *s; - s = lookup(sp, 0); + s = linklookup(ctxt, sp, 0); s->sig = 0; } @@ -1242,7 +830,10 @@ mywhatsys(void) { goroot = getgoroot(); goos = getgoos(); - goarch = thestring; // ignore $GOARCH - we know who we are + goarch = getgoarch(); + + if(strncmp(goarch, thestring, strlen(thestring)) != 0) + sysfatal("cannot use %cc with GOARCH=%s", thechar, goarch); } int @@ -1303,7 +894,8 @@ unmal(void *v, uint32 n) * Invalid bytes turn into %xx. Right now the only bytes that need * escaping are %, ., and ", but we escape all control characters too. * - * Must be same as ../gc/subr.c:/^pathtoprefix. + * If you edit this, edit ../gc/subr.c:/^pathtoprefix too. + * If you edit this, edit ../../pkg/debug/goobj/read.go:/importPathToPrefix too. */ static char* pathtoprefix(char *s) @@ -1357,13 +949,6 @@ 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) { @@ -1381,235 +966,6 @@ addsection(Segment *seg, char *name, int rwx) return sect; } -void -addvarint(Sym *s, uint32 val) -{ - int32 n; - uint32 v; - uchar *p; - - n = 0; - for(v = val; v >= 0x80; v >>= 7) - n++; - n++; - - symgrow(s, s->np+n); - - p = s->p + s->np - n; - for(v = val; v >= 0x80; v >>= 7) - *p++ = v | 0x80; - *p = v; -} - -// funcpctab appends to dst a pc-value table mapping the code in func to the values -// returned by valfunc parameterized by arg. The invocation of valfunc to update the -// current value is, for each p, -// -// val = valfunc(func, val, p, 0, arg); -// record val as value at p->pc; -// val = valfunc(func, val, p, 1, arg); -// -// where func is the function, val is the current value, p is the instruction being -// considered, and arg can be used to further parameterize valfunc. -void -funcpctab(Sym *dst, Sym *func, char *desc, int32 (*valfunc)(Sym*, int32, Prog*, int32, int32), int32 arg) -{ - int dbg, i, start; - int32 oldval, val, started; - uint32 delta; - vlong pc; - Prog *p; - - // To debug a specific function, uncomment second line and change name. - dbg = 0; - //dbg = strcmp(func->name, "main.main") == 0; - - debug['O'] += dbg; - - start = dst->np; - - if(debug['O']) - Bprint(&bso, "funcpctab %s -> %s [valfunc=%s]\n", func->name, dst->name, desc); - - val = -1; - oldval = val; - pc = func->value; - - if(debug['O']) - Bprint(&bso, "%6llux %6d %P\n", pc, val, func->text); - - started = 0; - for(p=func->text; p != P; p = p->link) { - // Update val. If it's not changing, keep going. - val = valfunc(func, val, p, 0, arg); - if(val == oldval && started) { - val = valfunc(func, val, p, 1, arg); - if(debug['O']) - Bprint(&bso, "%6llux %6s %P\n", (vlong)p->pc, "", p); - continue; - } - - // If the pc of the next instruction is the same as the - // pc of this instruction, this instruction is not a real - // instruction. Keep going, so that we only emit a delta - // for a true instruction boundary in the program. - if(p->link && p->link->pc == p->pc) { - val = valfunc(func, val, p, 1, arg); - if(debug['O']) - Bprint(&bso, "%6llux %6s %P\n", (vlong)p->pc, "", p); - continue; - } - - // The table is a sequence of (value, pc) pairs, where each - // pair states that the given value is in effect from the current position - // up to the given pc, which becomes the new current position. - // To generate the table as we scan over the program instructions, - // we emit a "(value" when pc == func->value, and then - // each time we observe a change in value we emit ", pc) (value". - // When the scan is over, we emit the closing ", pc)". - // - // The table is delta-encoded. The value deltas are signed and - // transmitted in zig-zag form, where a complement bit is placed in bit 0, - // and the pc deltas are unsigned. Both kinds of deltas are sent - // as variable-length little-endian base-128 integers, - // where the 0x80 bit indicates that the integer continues. - - if(debug['O']) - Bprint(&bso, "%6llux %6d %P\n", (vlong)p->pc, val, p); - - if(started) { - addvarint(dst, (p->pc - pc) / MINLC); - pc = p->pc; - } - delta = val - oldval; - if(delta>>31) - delta = 1 | ~(delta<<1); - else - delta <<= 1; - addvarint(dst, delta); - oldval = val; - started = 1; - val = valfunc(func, val, p, 1, arg); - } - - if(started) { - if(debug['O']) - Bprint(&bso, "%6llux done\n", (vlong)func->value+func->size); - addvarint(dst, (func->value+func->size - pc) / MINLC); - addvarint(dst, 0); // terminator - } - - if(debug['O']) { - Bprint(&bso, "wrote %d bytes\n", dst->np - start); - for(i=start; i<dst->np; i++) - Bprint(&bso, " %02ux", dst->p[i]); - Bprint(&bso, "\n"); - } - - debug['O'] -= dbg; -} - -// pctofileline computes either the file number (arg == 0) -// or the line number (arg == 1) to use at p. -// Because p->lineno applies to p, phase == 0 (before p) -// takes care of the update. -static int32 -pctofileline(Sym *sym, int32 oldval, Prog *p, int32 phase, int32 arg) -{ - int32 f, l; - - if(p->as == ATEXT || p->as == ANOP || p->as == AUSEFIELD || p->line == 0 || phase == 1) - return oldval; - getline(sym->hist, p->line, &f, &l); - if(f == 0) { - // print("getline failed for %s %P\n", cursym->name, p); - return oldval; - } - if(arg == 0) - return f; - return l; -} - -// pctospadj computes the sp adjustment in effect. -// It is oldval plus any adjustment made by p itself. -// The adjustment by p takes effect only after p, so we -// apply the change during phase == 1. -static int32 -pctospadj(Sym *sym, int32 oldval, Prog *p, int32 phase, int32 arg) -{ - USED(arg); - USED(sym); - - if(oldval == -1) // starting - oldval = 0; - if(phase == 0) - return oldval; - if(oldval + p->spadj < -10000 || oldval + p->spadj > 1100000000) { - diag("overflow in spadj: %d + %d = %d", oldval, p->spadj, oldval + p->spadj); - errorexit(); - } - return oldval + p->spadj; -} - -// pctopcdata computes the pcdata value in effect at p. -// A PCDATA instruction sets the value in effect at future -// non-PCDATA instructions. -// Since PCDATA instructions have no width in the final code, -// it does not matter which phase we use for the update. -static int32 -pctopcdata(Sym *sym, int32 oldval, Prog *p, int32 phase, int32 arg) -{ - USED(sym); - - if(phase == 0 || p->as != APCDATA || p->from.offset != arg) - return oldval; - if((int32)p->to.offset != p->to.offset) { - diag("overflow in PCDATA instruction: %P", p); - errorexit(); - } - return p->to.offset; -} - -#define LOG 5 -void -mkfwd(void) -{ - Prog *p; - int i; - int32 dwn[LOG], cnt[LOG]; - Prog *lst[LOG]; - - 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; - 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) { @@ -1652,7 +1008,7 @@ Endian le = { le16, le32, le64 }; typedef struct Chain Chain; struct Chain { - Sym *sym; + LSym *sym; Chain *up; int limit; // limit on entry to sym }; @@ -1660,67 +1016,87 @@ struct Chain static int stkcheck(Chain*, int); static void stkprint(Chain*, int); static void stkbroke(Chain*, int); -static Sym *morestack; -static Sym *newstack; +static LSym *morestack; +static LSym *newstack; enum { HasLinkRegister = (thechar == '5'), - CallSize = (!HasLinkRegister)*PtrSize, // bytes of stack required for a call }; +// TODO: Record enough information in new object files to +// allow stack checks here. + +static int +callsize(void) +{ + if(thechar == '5') + return 0; + return RegSize; +} + void dostkcheck(void) { Chain ch; - Sym *s; + LSym *s; - morestack = lookup("runtime.morestack", 0); - newstack = lookup("runtime.newstack", 0); - - // First the nosplits on their own. - for(s = textp; s != nil; s = s->next) { - if(s->text == nil || s->text->link == nil || (s->text->textflag & NOSPLIT) == 0) + morestack = linklookup(ctxt, "runtime.morestack", 0); + newstack = linklookup(ctxt, "runtime.newstack", 0); + + // Every splitting function ensures that there are at least StackLimit + // bytes available below SP when the splitting prologue finishes. + // If the splitting function calls F, then F begins execution with + // at least StackLimit - callsize() bytes available. + // Check that every function behaves correctly with this amount + // of stack, following direct calls in order to piece together chains + // of non-splitting functions. + ch.up = nil; + ch.limit = StackLimit - callsize(); + + // Check every function, but do the nosplit functions in a first pass, + // to make the printed failure chains as short as possible. + for(s = ctxt->textp; s != nil; s = s->next) { + // runtime.racesymbolizethunk is called from gcc-compiled C + // code running on the operating system thread stack. + // It uses more than the usual amount of stack but that's okay. + if(strcmp(s->name, "runtime.racesymbolizethunk") == 0) continue; - cursym = s; - ch.up = nil; + + if(s->nosplit) { + ctxt->cursym = s; ch.sym = s; - ch.limit = StackLimit - CallSize; stkcheck(&ch, 0); - s->stkcheck = 1; } - - // Check calling contexts. - // Some nosplits get called a little further down, - // like newproc and deferproc. We could hard-code - // that knowledge but it's more robust to look at - // the actual call sites. - for(s = textp; s != nil; s = s->next) { - if(s->text == nil || s->text->link == nil || (s->text->textflag & NOSPLIT) != 0) - continue; - cursym = s; - ch.up = nil; + } + for(s = ctxt->textp; s != nil; s = s->next) { + if(!s->nosplit) { + ctxt->cursym = s; ch.sym = s; - ch.limit = StackLimit - CallSize; stkcheck(&ch, 0); } } +} static int stkcheck(Chain *up, int depth) { Chain ch, ch1; - Prog *p; - Sym *s; - int limit, prolog; + LSym *s; + int limit; + Reloc *r, *endr; + Pciter pcsp; limit = up->limit; s = up->sym; - p = s->text; - // Small optimization: don't repeat work at top. - if(s->stkcheck && limit == StackLimit-CallSize) + // Don't duplicate work: only need to consider each + // function at top of safe zone once. + if(limit == StackLimit-callsize()) { + if(s->stkcheck) return 0; + s->stkcheck = 1; + } if(depth > 100) { diag("nosplit stack check too deep"); @@ -1728,11 +1104,11 @@ stkcheck(Chain *up, int depth) return -1; } - if(p == nil || p->link == nil) { + if(s->external || s->pcln == nil) { // external function. // should never be called directly. // only diagnose the direct caller. - if(depth == 1) + if(depth == 1 && s->type != SXREF) diag("call to external function %s", s->name); return -1; } @@ -1748,50 +1124,56 @@ stkcheck(Chain *up, int depth) return 0; ch.up = up; - prolog = (s->text->textflag & NOSPLIT) == 0; - for(p = s->text; p != P; p = p->link) { - limit -= p->spadj; - if(prolog && p->spadj != 0) { - // The first stack adjustment in a function with a - // split-checking prologue marks the end of the - // prologue. Assuming the split check is correct, - // after the adjustment there should still be at least - // StackLimit bytes available below the stack pointer. - // If this is not the top call in the chain, no need - // to duplicate effort, so just stop. - if(depth > 0) - return 0; - prolog = 0; - limit = StackLimit; - } - if(limit < 0) { - stkbroke(up, limit); + + // Walk through sp adjustments in function, consuming relocs. + r = s->r; + endr = r + s->nr; + for(pciterinit(ctxt, &pcsp, &s->pcln->pcsp); !pcsp.done; pciternext(&pcsp)) { + // pcsp.value is in effect for [pcsp.pc, pcsp.nextpc). + + // Check stack size in effect for this span. + if(limit - pcsp.value < 0) { + stkbroke(up, limit - pcsp.value); return -1; } - if(iscall(p)) { - limit -= CallSize; - ch.limit = limit; - if(p->to.type == D_BRANCH) { + + // Process calls in this span. + for(; r < endr && r->off < pcsp.nextpc; r++) { + switch(r->type) { + case R_CALL: + case R_CALLARM: // Direct call. - ch.sym = p->to.sym; + ch.limit = limit - pcsp.value - callsize(); + ch.sym = r->sym; if(stkcheck(&ch, depth+1) < 0) return -1; - } else { - // Indirect call. Assume it is a splitting function, + + // If this is a call to morestack, we've just raised our limit back + // to StackLimit beyond the frame size. + if(strncmp(r->sym->name, "runtime.morestack", 17) == 0) { + limit = StackLimit + s->locals; + if(thechar == '5') + limit += 4; // saved LR + } + break; + + case R_CALLIND: + // Indirect call. Assume it is a call to a splitting function, // so we have to make sure it can call morestack. - limit -= CallSize; + // Arrange the data structures to report both calls, so that + // if there is an error, stkprint shows all the steps involved. + ch.limit = limit - pcsp.value - callsize(); ch.sym = nil; - ch1.limit = limit; + ch1.limit = ch.limit - callsize(); // for morestack in called prologue ch1.up = &ch; ch1.sym = morestack; if(stkcheck(&ch1, depth+2) < 0) return -1; - limit += CallSize; + break; } - limit += CallSize; + } } - } return 0; } @@ -1814,7 +1196,7 @@ stkprint(Chain *ch, int limit) if(ch->up == nil) { // top of chain. ch->sym != nil. - if(ch->sym->text->textflag & NOSPLIT) + if(ch->sym->nosplit) print("\t%d\tassumed on entry to %s\n", ch->limit, name); else print("\t%d\tguaranteed after split check in %s\n", ch->limit, name); @@ -1828,52 +1210,14 @@ stkprint(Chain *ch, int limit) } int -headtype(char *name) -{ - int i; - - for(i=0; headers[i].name; i++) - if(strcmp(name, headers[i].name) == 0) { - headstring = headers[i].name; - return headers[i].val; - } - fprint(2, "unknown header type -H %s\n", name); - errorexit(); - return -1; // not reached -} - -char* -headstr(int v) -{ - static char buf[20]; - int i; - - for(i=0; headers[i].name; i++) - if(v == headers[i].val) - return headers[i].name; - snprint(buf, sizeof buf, "%d", v); - return buf; -} - -void -undef(void) -{ - Sym *s; - - for(s = allsym; s != S; s = s->allsym) - if(s->type == SXREF) - diag("%s(%d): not defined", s->name, s->version); -} - -int Yconv(Fmt *fp) { - Sym *s; + LSym *s; Fmt fmt; int i; char *str; - s = va_arg(fp->args, Sym*); + s = va_arg(fp->args, LSym*); if (s == S) { fmtprint(fp, "<nil>"); } else { @@ -1967,6 +1311,14 @@ usage(void) void setheadtype(char *s) { + int h; + + h = headtype(s); + if(h < 0) { + fprint(2, "unknown header type -H %s\n", s); + errorexit(); + } + headstring = s; HEADTYPE = headtype(s); } @@ -1985,22 +1337,22 @@ doversion(void) } void -genasmsym(void (*put)(Sym*, char*, int, vlong, vlong, int, Sym*)) +genasmsym(void (*put)(LSym*, char*, int, vlong, vlong, int, LSym*)) { Auto *a; - Sym *s; + LSym *s; int32 off; // These symbols won't show up in the first loop below because we // skip STEXT symbols. Normal STEXT symbols are emitted by walking textp. - s = lookup("text", 0); + s = linklookup(ctxt, "text", 0); if(s->type == STEXT) put(s, s->name, 'T', s->value, s->size, s->version, 0); - s = lookup("etext", 0); + s = linklookup(ctxt, "etext", 0); if(s->type == STEXT) put(s, s->name, 'T', s->value, s->size, s->version, 0); - for(s=allsym; s!=S; s=s->allsym) { + for(s=ctxt->allsym; s!=S; s=s->allsym) { if(s->hide || (s->name[0] == '.' && s->version == 0 && strcmp(s->name, ".rathole") != 0)) continue; switch(s->type&SMASK) { @@ -2036,20 +1388,20 @@ genasmsym(void (*put)(Sym*, char*, int, vlong, vlong, int, Sym*)) } } - for(s = textp; s != nil; s = s->next) { - if(s->text == nil) - continue; - + for(s = ctxt->textp; s != nil; s = s->next) { put(s, s->name, 'T', s->value, s->size, s->version, s->gotype); + // NOTE(ality): acid can't produce a stack trace without .frame symbols + put(nil, ".frame", 'm', s->locals+PtrSize, 0, 0, 0); + for(a=s->autom; a; a=a->link) { // Emit a or p according to actual offset, even if label is wrong. // This avoids negative offsets, which cannot be encoded. - if(a->type != D_AUTO && a->type != D_PARAM) + if(a->type != A_AUTO && a->type != A_PARAM) continue; // compute offset relative to FP - if(a->type == D_PARAM) + if(a->type == A_PARAM) off = a->aoffset; else off = a->aoffset - PtrSize; @@ -2075,461 +1427,126 @@ genasmsym(void (*put)(Sym*, char*, int, vlong, vlong, int, Sym*)) Bflush(&bso); } -char* -estrdup(char *p) -{ - p = strdup(p); - if(p == nil) { - cursym = S; - diag("out of memory"); - errorexit(); - } - return p; -} - -void* -erealloc(void *p, long n) +vlong +symaddr(LSym *s) { - p = realloc(p, n); - if(p == nil) { - cursym = S; - diag("out of memory"); - errorexit(); - } - return p; + if(!s->reachable) + diag("unreachable symbol in symaddr - %s", s->name); + return s->value; } -// Saved history stacks encountered while reading archives. -// Keeping them allows us to answer virtual lineno -> file:line -// queries. -// -// The history stack is a complex data structure, described best at the -// bottom of http://plan9.bell-labs.com/magic/man2html/6/a.out. -// One of the key benefits of interpreting it here is that the runtime -// does not have to. Perhaps some day the compilers could generate -// a simpler linker input too. - -struct Hist -{ - int32 line; - int32 off; - Sym *file; -}; - -static Hist *histcopy; -static Hist *hist; -static int32 nhist; -static int32 maxhist; -static int32 histdepth; -static int32 nhistfile; -static Sym *filesyms; - -// savehist processes a single line, off history directive -// found in the input object file. void -savehist(int32 line, int32 off) +xdefine(char *p, int t, vlong v) { - char tmp[1024]; - Sym *file; - Hist *h; - - // NOTE(rsc): We used to do the copyhistfrog first and this - // condition was if(tmp[0] != '\0') to check for an empty string, - // implying that histfrogp == 0, implying that this is a history pop. - // However, on Windows in the misc/cgo test, the linker is - // presented with an ANAME corresponding to an empty string, - // that ANAME ends up being the only histfrog, and thus we have - // a situation where histfrogp > 0 (not a pop) but the path we find - // is the empty string. Really that shouldn't happen, but it doesn't - // seem to be bothering anyone yet, and it's easier to fix the condition - // to test histfrogp than to track down where that empty string is - // coming from. Probably it is coming from go tool pack's P command. - if(histfrogp > 0) { - tmp[0] = '\0'; - copyhistfrog(tmp, sizeof tmp); - file = lookup(tmp, HistVersion); - if(file->type != SFILEPATH) { - file->value = ++nhistfile; - file->type = SFILEPATH; - file->next = filesyms; - filesyms = file; - } - } else - file = nil; + LSym *s; - if(file != nil && line == 1 && off == 0) { - // start of new stack - if(histdepth != 0) { - diag("history stack phase error: unexpected start of new stack depth=%d file=%s", histdepth, tmp); - errorexit(); - } - nhist = 0; - histcopy = nil; - } - - if(nhist >= maxhist) { - if(maxhist == 0) - maxhist = 1; - maxhist *= 2; - hist = erealloc(hist, maxhist*sizeof hist[0]); - } - h = &hist[nhist++]; - h->line = line; - h->off = off; - h->file = file; - - if(file != nil) { - if(off == 0) - histdepth++; - } else { - if(off != 0) { - diag("history stack phase error: bad offset in pop"); - errorexit(); - } - histdepth--; - } + s = linklookup(ctxt, p, 0); + s->type = t; + s->value = v; + s->reachable = 1; + s->special = 1; } -// gethist returns the history stack currently in effect. -// The result is valid indefinitely. -Hist* -gethist(void) +vlong +datoff(vlong addr) { - if(histcopy == nil) { - if(nhist == 0) - return nil; - histcopy = mal((nhist+1)*sizeof hist[0]); - memmove(histcopy, hist, nhist*sizeof hist[0]); - histcopy[nhist].line = -1; - } - return histcopy; + if(addr >= segdata.vaddr) + return addr - segdata.vaddr + segdata.fileoff; + if(addr >= segtext.vaddr) + return addr - segtext.vaddr + segtext.fileoff; + diag("datoff %#llx", addr); + return 0; } -typedef struct Hstack Hstack; -struct Hstack -{ - Hist *h; - int delta; -}; - -// getline sets *f to the file number and *l to the line number -// of the virtual line number line according to the history stack h. -void -getline(Hist *h, int32 line, int32 *f, int32 *l) +vlong +entryvalue(void) { - Hstack stk[100]; - int nstk, start; - Hist *top, *h0; - static Hist *lasth; - static int32 laststart, lastend, lastdelta, lastfile; - - h0 = h; - *f = 0; - *l = 0; - start = 0; - if(h == nil || line == 0) { - print("%s: getline: h=%p line=%d\n", cursym->name, h, line); - return; - } - - // Cache span used during last lookup, so that sequential - // translation of line numbers in compiled code is efficient. - if(!debug['O'] && lasth == h && laststart <= line && line < lastend) { - *f = lastfile; - *l = line - lastdelta; - return; - } - - if(debug['O']) - print("getline %d laststart=%d lastend=%d\n", line, laststart, lastend); - - nstk = 0; - for(; h->line != -1; h++) { - if(debug['O']) - print("\t%s %d %d\n", h->file ? h->file->name : "?", h->line, h->off); - - if(h->line > line) { - if(nstk == 0) { - diag("history stack phase error: empty stack at line %d", (int)line); - errorexit(); - } - top = stk[nstk-1].h; - lasth = h; - lastfile = top->file->value; - laststart = start; - lastend = h->line; - lastdelta = stk[nstk-1].delta; - *f = lastfile; - *l = line - lastdelta; - if(debug['O']) - print("\tgot %d %d [%d %d %d]\n", *f, *l, laststart, lastend, lastdelta); - return; - } - if(h->file == nil) { - // pop included file - if(nstk == 0) { - diag("history stack phase error: stack underflow"); - errorexit(); - } - nstk--; - if(nstk > 0) - stk[nstk-1].delta += h->line - stk[nstk].h->line; - start = h->line; - } else if(h->off == 0) { - // push included file - if(nstk >= nelem(stk)) { - diag("history stack phase error: stack overflow"); - errorexit(); - } - start = h->line; - stk[nstk].h = h; - stk[nstk].delta = h->line - 1; - nstk++; - } else { - // #line directive - if(nstk == 0) { - diag("history stack phase error: stack underflow"); - errorexit(); - } - stk[nstk-1].h = h; - stk[nstk-1].delta = h->line - h->off; - start = h->line; - } - if(debug['O']) - print("\t\tnstk=%d delta=%d\n", nstk, stk[nstk].delta); - } + char *a; + LSym *s; - diag("history stack phase error: cannot find line for %d", line); - nstk = 0; - for(h = h0; h->line != -1; h++) { - print("\t%d %d %s\n", h->line, h->off, h->file ? h->file->name : ""); - if(h->file == nil) - nstk--; - else if(h->off == 0) - nstk++; - } + a = INITENTRY; + if(*a >= '0' && *a <= '9') + return atolwhex(a); + s = linklookup(ctxt, a, 0); + if(s->type == 0) + return INITTEXT; + if(s->type != STEXT) + diag("entry not text: %s", s->name); + return s->value; } -// defgostring returns a symbol for the Go string containing text. -Sym* -defgostring(char *text) +static void +undefsym(LSym *s) { - char *p; - Sym *s; - int32 n; - - n = strlen(text); - p = smprint("go.string.\"%Z\"", text); - s = lookup(p, 0); - if(s->size == 0) { - s->type = SGOSTRING; - s->reachable = 1; - s->size = 2*PtrSize+n; - symgrow(s, 2*PtrSize+n); - setaddrplus(s, 0, s, 2*PtrSize); - setuintxx(s, PtrSize, n, PtrSize); - memmove(s->p+2*PtrSize, text, n); - } - s->reachable = 1; - return s; -} + int i; + Reloc *r; -// addpctab appends to f a pc-value table, storing its offset at off. -// The pc-value table is for func and reports the value of valfunc -// parameterized by arg. -static int32 -addpctab(Sym *f, int32 off, Sym *func, char *desc, int32 (*valfunc)(Sym*, int32, Prog*, int32, int32), int32 arg) -{ - int32 start; - - start = f->np; - funcpctab(f, func, desc, valfunc, arg); - if(start == f->np) { - // no table - return setuint32(f, off, 0); - } - if((int32)start > (int32)f->np) { - diag("overflow adding pc-table: symbol too large"); - errorexit(); + ctxt->cursym = s; + for(i=0; i<s->nr; i++) { + r = &s->r[i]; + if(r->sym == nil) // happens for some external ARM relocs + continue; + if(r->sym->type == Sxxx || r->sym->type == SXREF) + diag("undefined: %s", r->sym->name); + if(!r->sym->reachable) + diag("use of unreachable symbol: %s", r->sym->name); } - return setuint32(f, off, start); } -static int32 -ftabaddstring(Sym *ftab, char *s) +void +undef(void) { - int32 n, start; + LSym *s; - n = strlen(s)+1; - start = ftab->np; - symgrow(ftab, start+n+1); - strcpy((char*)ftab->p + start, s); - return start; + for(s = ctxt->textp; s != nil; s = s->next) + undefsym(s); + for(s = datap; s != nil; s = s->next) + undefsym(s); + if(nerrors > 0) + errorexit(); } -// pclntab initializes the pclntab symbol with -// runtime function and file name information. void -pclntab(void) +callgraph(void) { - Prog *p; - int32 i, n, nfunc, start, funcstart; - uint32 *havepc, *havefunc; - Sym *ftab, *s; - int32 npcdata, nfuncdata, off, end; - int64 funcdata_bytes; - - funcdata_bytes = 0; - ftab = lookup("pclntab", 0); - ftab->type = SPCLNTAB; - ftab->reachable = 1; - - // See golang.org/s/go12symtab for the format. Briefly: - // 8-byte header - // nfunc [PtrSize bytes] - // function table, alternating PC and offset to func struct [each entry PtrSize bytes] - // end PC [PtrSize bytes] - // offset to file table [4 bytes] - nfunc = 0; - for(cursym = textp; cursym != nil; cursym = cursym->next) - nfunc++; - symgrow(ftab, 8+PtrSize+nfunc*2*PtrSize+PtrSize+4); - setuint32(ftab, 0, 0xfffffffb); - setuint8(ftab, 6, MINLC); - setuint8(ftab, 7, PtrSize); - setuintxx(ftab, 8, nfunc, PtrSize); - - nfunc = 0; - for(cursym = textp; cursym != nil; cursym = cursym->next, nfunc++) { - funcstart = ftab->np; - funcstart += -ftab->np & (PtrSize-1); - - setaddr(ftab, 8+PtrSize+nfunc*2*PtrSize, cursym); - setuintxx(ftab, 8+PtrSize+nfunc*2*PtrSize+PtrSize, funcstart, PtrSize); - - npcdata = 0; - nfuncdata = 0; - for(p = cursym->text; p != P; p = p->link) { - if(p->as == APCDATA && p->from.offset >= npcdata) - npcdata = p->from.offset+1; - if(p->as == AFUNCDATA && p->from.offset >= nfuncdata) - nfuncdata = p->from.offset+1; - } - - // fixed size of struct, checked below - off = funcstart; - end = funcstart + PtrSize + 3*4 + 5*4 + npcdata*4 + nfuncdata*PtrSize; - if(nfuncdata > 0 && (end&(PtrSize-1))) - end += 4; - symgrow(ftab, end); - - // entry uintptr - off = setaddr(ftab, off, cursym); - - // name int32 - off = setuint32(ftab, off, ftabaddstring(ftab, cursym->name)); - - // args int32 - // TODO: Move into funcinfo. - if(cursym->text == nil) - off = setuint32(ftab, off, ArgsSizeUnknown); - else - off = setuint32(ftab, off, cursym->args); - - // frame int32 - // TODO: Remove entirely. The pcsp table is more precise. - // This is only used by a fallback case during stack walking - // when a called function doesn't have argument information. - // We need to make sure everything has argument information - // and then remove this. - if(cursym->text == nil) - off = setuint32(ftab, off, 0); - else - off = setuint32(ftab, off, (uint32)cursym->text->to.offset+PtrSize); - - // pcsp table (offset int32) - off = addpctab(ftab, off, cursym, "pctospadj", pctospadj, 0); - - // pcfile table (offset int32) - off = addpctab(ftab, off, cursym, "pctofileline file", pctofileline, 0); + LSym *s; + Reloc *r; + int i; - // pcln table (offset int32) - off = addpctab(ftab, off, cursym, "pctofileline line", pctofileline, 1); - - // npcdata int32 - off = setuint32(ftab, off, npcdata); - - // nfuncdata int32 - off = setuint32(ftab, off, nfuncdata); - - // tabulate which pc and func data we have. - n = ((npcdata+31)/32 + (nfuncdata+31)/32)*4; - havepc = mal(n); - havefunc = havepc + (npcdata+31)/32; - for(p = cursym->text; p != P; p = p->link) { - if(p->as == AFUNCDATA) { - if((havefunc[p->from.offset/32]>>(p->from.offset%32))&1) - diag("multiple definitions for FUNCDATA $%d", p->from.offset); - havefunc[p->from.offset/32] |= 1<<(p->from.offset%32); - } - if(p->as == APCDATA) - havepc[p->from.offset/32] |= 1<<(p->from.offset%32); - } + if(!debug['c']) + return; - // pcdata. - for(i=0; i<npcdata; i++) { - if(!(havepc[i/32]>>(i%32))&1) { - off = setuint32(ftab, off, 0); + for(s = ctxt->textp; s != nil; s = s->next) { + for(i=0; i<s->nr; i++) { + r = &s->r[i]; + if(r->sym == nil) continue; - } - off = addpctab(ftab, off, cursym, "pctopcdata", pctopcdata, i); - } - - unmal(havepc, n); - - // funcdata, must be pointer-aligned and we're only int32-aligned. - // Unlike pcdata, can gather in a single pass. - // Missing funcdata will be 0 (nil pointer). - if(nfuncdata > 0) { - if(off&(PtrSize-1)) - off += 4; - for(p = cursym->text; p != P; p = p->link) { - if(p->as == AFUNCDATA) { - i = p->from.offset; - if(p->to.type == D_CONST) - setuintxx(ftab, off+PtrSize*i, p->to.offset, PtrSize); - else { - // TODO: Dedup. - funcdata_bytes += p->to.sym->size; - setaddrplus(ftab, off+PtrSize*i, p->to.sym, p->to.offset); - } - } - } - off += nfuncdata*PtrSize; - } - - if(off != end) { - diag("bad math in functab: funcstart=%d off=%d but end=%d (npcdata=%d nfuncdata=%d)", funcstart, off, end, npcdata, nfuncdata); - errorexit(); + if((r->type == R_CALL || r->type == R_CALLARM) && r->sym->type == STEXT) + Bprint(&bso, "%s calls %s\n", s->name, r->sym->name); } - - // Final entry of table is just end pc. - if(cursym->next == nil) - setaddrplus(ftab, 8+PtrSize+(nfunc+1)*2*PtrSize, cursym, cursym->size); } - - // Start file table. - start = ftab->np; - start += -ftab->np & (PtrSize-1); - setuint32(ftab, 8+PtrSize+nfunc*2*PtrSize+PtrSize, start); +} - symgrow(ftab, start+(nhistfile+1)*4); - setuint32(ftab, start, nhistfile); - for(s = filesyms; s != S; s = s->next) - setuint32(ftab, start + s->value*4, ftabaddstring(ftab, s->name)); +void +diag(char *fmt, ...) +{ + char buf[1024], *tn, *sep; + va_list arg; - ftab->size = ftab->np; - - if(debug['v']) - Bprint(&bso, "%5.2f pclntab=%lld bytes, funcdata total %lld bytes\n", cputime(), (vlong)ftab->size, (vlong)funcdata_bytes); -} + tn = ""; + sep = ""; + if(ctxt->cursym != S) { + tn = ctxt->cursym->name; + sep = ": "; + } + va_start(arg, fmt); + vseprint(buf, buf+sizeof(buf), fmt, arg); + va_end(arg); + print("%s%s%s\n", tn, sep, buf); + + nerrors++; + if(nerrors > 20) { + print("too many errors\n"); + errorexit(); + } +} diff --git a/src/cmd/ld/lib.h b/src/cmd/ld/lib.h index be95bb46e..7267c6371 100644 --- a/src/cmd/ld/lib.h +++ b/src/cmd/ld/lib.h @@ -28,68 +28,6 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. -enum -{ - Sxxx, - - /* order here is order in output file */ - /* readonly, executable */ - STEXT, - SELFRXSECT, - - /* readonly, non-executable */ - STYPE, - SSTRING, - SGOSTRING, - SGOFUNC, - SRODATA, - SFUNCTAB, - STYPELINK, - SSYMTAB, // TODO: move to unmapped section - SPCLNTAB, - SELFROSECT, - - /* writable, non-executable */ - SMACHOPLT, - SELFSECT, - SMACHO, /* Mach-O __nl_symbol_ptr */ - SMACHOGOT, - SNOPTRDATA, - SINITARR, - SDATA, - SWINDOWS, - SBSS, - SNOPTRBSS, - STLSBSS, - - /* not mapped */ - SXREF, - SMACHOSYMSTR, - SMACHOSYMTAB, - SMACHOINDIRECTPLT, - SMACHOINDIRECTGOT, - SFILE, - SFILEPATH, - SCONST, - SDYNIMPORT, - SHOSTOBJ, - - SSUB = 1<<8, /* sub-symbol, linked from parent via ->sub list */ - SMASK = SSUB - 1, - SHIDDEN = 1<<9, // hidden or local symbol - - NHASH = 100003, -}; - -typedef struct Library Library; -struct Library -{ - char *objref; // object where we found the reference - char *srcref; // src file where we found the reference - char *file; // object file - char *pkg; // import path -}; - // Terrible but standard terminology. // A segment describes a block of file to load into memory. // A section further describes the pieces of that block for @@ -125,39 +63,18 @@ struct Section uvlong rellen; }; -typedef struct Hist Hist; - -#pragma incomplete struct Hist - extern char symname[]; -extern char **libdir; -extern int nlibdir; -extern int version; EXTERN char* INITENTRY; -EXTERN char* thestring; -EXTERN Library* library; -EXTERN int libraryp; -EXTERN int nlibrary; -EXTERN Sym* hash[NHASH]; -EXTERN Sym* allsym; -EXTERN Sym* histfrog[MAXHIST]; -EXTERN uchar fnuxi8[8]; -EXTERN uchar fnuxi4[4]; -EXTERN int histfrogp; -EXTERN int histgen; -EXTERN uchar inuxi1[1]; -EXTERN uchar inuxi2[2]; -EXTERN uchar inuxi4[4]; -EXTERN uchar inuxi8[8]; +extern char* thestring; +extern LinkArch* thelinkarch; EXTERN char* outfile; -EXTERN int32 nsymbol; -EXTERN char* thestring; EXTERN int ndynexp; -EXTERN Sym** dynexp; +EXTERN LSym** dynexp; EXTERN int nldflag; EXTERN char** ldflag; EXTERN int havedynamic; +EXTERN int funcalign; EXTERN int iscgo; EXTERN int elfglobalsymndx; EXTERN char* flag_installsuffix; @@ -169,16 +86,21 @@ EXTERN char* tmpdir; EXTERN char* extld; EXTERN char* extldflags; EXTERN int debug_s; // backup old value of debug['s'] +EXTERN Link* ctxt; +EXTERN int32 HEADR; +EXTERN int32 HEADTYPE; +EXTERN int32 INITRND; +EXTERN int64 INITTEXT; +EXTERN int64 INITDAT; +EXTERN char* INITENTRY; /* entry point */ +EXTERN char* noname; +EXTERN char* paramspace; +EXTERN int nerrors; -enum -{ - LinkAuto = 0, - LinkInternal, - LinkExternal, -}; EXTERN int linkmode; +EXTERN int64 liveness; -// for dynexport field of Sym +// for dynexport field of LSym enum { CgoExportDynamic = 1<<0, @@ -190,119 +112,6 @@ EXTERN Segment segrodata; EXTERN Segment segdata; EXTERN Segment segdwarf; -void setlinkmode(char*); -void addlib(char *src, char *obj); -void addlibpath(char *srcref, char *objref, char *file, char *pkg); -Section* addsection(Segment*, char*, int); -void copyhistfrog(char *buf, int nbuf); -void addhist(int32 line, int type); -void savehist(int32 line, int32 off); -Hist* gethist(void); -void getline(Hist*, int32 line, int32 *f, int32 *l); -void asmlc(void); -void histtoauto(void); -void collapsefrog(Sym *s); -Sym* newsym(char *symb, int v); -Sym* lookup(char *symb, int v); -Sym* rlookup(char *symb, int v); -void nuxiinit(void); -int find1(int32 l, int c); -int find2(int32 l, int c); -int32 ieeedtof(Ieee *e); -double ieeedtod(Ieee *e); -void undefsym(Sym *s); -void zerosig(char *sp); -void readundefs(char *f, int t); -void loadlib(void); -void errorexit(void); -void mangle(char*); -void objfile(char *file, char *pkg); -void libinit(void); -void pclntab(void); -void symtab(void); -void Lflag(char *arg); -void usage(void); -void adddynrel(Sym*, Reloc*); -void adddynrela(Sym*, Sym*, Reloc*); -void ldobj1(Biobuf *f, char*, int64 len, char *pn); -void ldobj(Biobuf*, char*, int64, char*, char*, int); -void ldelf(Biobuf*, char*, int64, char*); -void ldmacho(Biobuf*, char*, int64, char*); -void ldpe(Biobuf*, char*, int64, char*); -void ldpkg(Biobuf*, char*, int64, char*, int); -void mark(Sym *s); -void mkfwd(void); -char* expandpkg(char*, char*); -void deadcode(void); -Reloc* addrel(Sym*); -void codeblk(int32, int32); -void datblk(int32, int32); -void reloc(void); -void relocsym(Sym*); -void savedata(Sym*, Prog*, char*); -void symgrow(Sym*, int32); -void addstrdata(char*, char*); -vlong addstring(Sym*, char*); -vlong adduint8(Sym*, uint8); -vlong adduint16(Sym*, uint16); -vlong adduint32(Sym*, uint32); -vlong adduint64(Sym*, uint64); -vlong adduintxx(Sym*, uint64, int); -vlong addaddr(Sym*, Sym*); -vlong addaddrplus(Sym*, Sym*, vlong); -vlong addpcrelplus(Sym*, Sym*, vlong); -vlong addsize(Sym*, Sym*); -vlong setaddrplus(Sym*, vlong, Sym*, vlong); -vlong setaddr(Sym*, vlong, Sym*); -vlong setuint8(Sym*, vlong, uint8); -vlong setuint16(Sym*, vlong, uint16); -vlong setuint32(Sym*, vlong, uint32); -vlong setuint64(Sym*, vlong, uint64); -vlong setuintxx(Sym*, vlong, uint64, vlong); -void asmsym(void); -void asmelfsym(void); -void asmplan9sym(void); -void putelfsectionsym(Sym*, int); -void putelfsymshndx(vlong, int); -void strnput(char*, int); -void dodata(void); -void dosymtype(void); -void address(void); -void textaddress(void); -void genasmsym(void (*put)(Sym*, char*, int, vlong, vlong, int, Sym*)); -vlong datoff(vlong); -void adddynlib(char*); -int archreloc(Reloc*, Sym*, vlong*); -void adddynsym(Sym*); -void addexport(void); -void dostkcheck(void); -void undef(void); -void doweak(void); -void setpersrc(Sym*); -void doversion(void); -void usage(void); -void setinterp(char*); -Sym* listsort(Sym*, int(*cmp)(Sym*, Sym*), int); -int valuecmp(Sym*, Sym*); -void hostobjs(void); -void hostlink(void); -char* estrdup(char*); -void* erealloc(void*, long); -Sym* defgostring(char*); - -int pathchar(void); -void* mal(uint32); -void unmal(void*, uint32); -void mywhatsys(void); -int rbyoff(const void*, const void*); - -uint16 le16(uchar*); -uint32 le32(uchar*); -uint64 le64(uchar*); -uint16 be16(uchar*); -uint32 be32(uchar*); -uint64 be64(uchar*); - typedef struct Endian Endian; struct Endian { @@ -325,28 +134,6 @@ enum { Pkgdef }; -/* executable header types */ -enum { - Hgarbunix = 0, // garbage unix - Hnoheader, // no header - Hunixcoff, // unix coff - Hrisc, // aif for risc os - Hplan9x32, // plan 9 32-bit format - Hplan9x64, // plan 9 64-bit format - Hmsdoscom, // MS-DOS .COM - Hnetbsd, // NetBSD - Hmsdosexe, // fake MS-DOS .EXE - Hixp1200, // IXP1200 (raw) - Helf, // ELF32 - Hipaq, // ipaq - Hdarwin, // Apple Mach-O - Hlinux, // Linux ELF - Hfreebsd, // FreeBSD ELF - Hwindows, // MS Windows PE - Hopenbsd, // OpenBSD ELF - Hdragonfly, // DragonFly ELF -}; - typedef struct Header Header; struct Header { char *name; @@ -356,14 +143,9 @@ struct Header { EXTERN char* headstring; extern Header headers[]; -int headtype(char*); -char* headstr(int); -void setheadtype(char*); - -int Yconv(Fmt*); - -#pragma varargck type "O" int -#pragma varargck type "Y" Sym* +#pragma varargck type "Y" LSym* +#pragma varargck type "Z" char* +#pragma varargck type "i" char* // buffered output @@ -383,29 +165,117 @@ EXTERN char* cbpmax; if(--cbc <= 0)\ cflush(); } +void Lflag(char *arg); +int Yconv(Fmt *fp); +int Zconv(Fmt *fp); +void addexport(void); +void address(void); +Section*addsection(Segment *seg, char *name, int rwx); +void addstrdata(char *name, char *value); +vlong addstring(LSym *s, char *str); +void asmelfsym(void); +void asmplan9sym(void); +uint16 be16(uchar *b); +uint32 be32(uchar *b); +uint64 be64(uchar *b); +void callgraph(void); void cflush(void); +void codeblk(int32 addr, int32 size); vlong cpos(void); -void cseek(vlong); -void cwrite(void*, int); +void cseek(vlong p); +void cwrite(void *buf, int n); +void datblk(int32 addr, int32 size); +int datcmp(LSym *s1, LSym *s2); +vlong datoff(vlong addr); +void deadcode(void); +LSym* decodetype_arrayelem(LSym *s); +vlong decodetype_arraylen(LSym *s); +LSym* decodetype_chanelem(LSym *s); +int decodetype_funcdotdotdot(LSym *s); +int decodetype_funcincount(LSym *s); +LSym* decodetype_funcintype(LSym *s, int i); +int decodetype_funcoutcount(LSym *s); +LSym* decodetype_funcouttype(LSym *s, int i); +LSym* decodetype_gc(LSym *s); +vlong decodetype_ifacemethodcount(LSym *s); +uint8 decodetype_kind(LSym *s); +LSym* decodetype_mapkey(LSym *s); +LSym* decodetype_mapvalue(LSym *s); +LSym* decodetype_ptrelem(LSym *s); +vlong decodetype_size(LSym *s); +int decodetype_structfieldcount(LSym *s); +char* decodetype_structfieldname(LSym *s, int i); +vlong decodetype_structfieldoffs(LSym *s, int i); +LSym* decodetype_structfieldtype(LSym *s, int i); +void dodata(void); +void dostkcheck(void); +void dostkoff(void); +void dosymtype(void); +void doversion(void); +void doweak(void); +void dynreloc(void); +void dynrelocsym(LSym *s); +vlong entryvalue(void); +void errorexit(void); +void follow(void); +void genasmsym(void (*put)(LSym*, char*, int, vlong, vlong, int, LSym*)); +void growdatsize(vlong *datsizep, LSym *s); +char* headstr(int v); +int headtype(char *name); +void hostlink(void); +void hostobjs(void); +int iconv(Fmt *fp); void importcycles(void); -int Zconv(Fmt*); +void linkarchinit(void); +void ldelf(Biobuf *f, char *pkg, int64 len, char *pn); +void ldhostobj(void (*ld)(Biobuf*, char*, int64, char*), Biobuf *f, char *pkg, int64 len, char *pn, char *file); +void ldmacho(Biobuf *f, char *pkg, int64 len, char *pn); +void ldobj(Biobuf *f, char *pkg, int64 len, char *pn, char *file, int whence); +void ldpe(Biobuf *f, char *pkg, int64 len, char *pn); +void ldpkg(Biobuf *f, char *pkg, int64 len, char *filename, int whence); +uint16 le16(uchar *b); +uint32 le32(uchar *b); +uint64 le64(uchar *b); +void libinit(void); +LSym* listsort(LSym *l, int (*cmp)(LSym*, LSym*), int off); +void loadinternal(char *name); +void loadlib(void); +void lputb(int32 l); +void lputl(int32 l); +void* mal(uint32 n); +void mark(LSym *s); +void mywhatsys(void); +struct ar_hdr; +void objfile(char *file, char *pkg); +void patch(void); +int pathchar(void); +void pcln(void); +void pclntab(void); +void putelfsectionsym(LSym* s, int shndx); +void putelfsymshndx(vlong sympos, int shndx); +void putsymb(LSym *s, char *name, int t, vlong v, vlong size, int ver, LSym *typ); +int rbyoff(const void *va, const void *vb); +void reloc(void); +void relocsym(LSym *s); +void setheadtype(char *s); +void setinterp(char *s); +void setlinkmode(char *arg); +void span(void); +void strnput(char *s, int n); +vlong symaddr(LSym *s); +void symtab(void); +void textaddress(void); +void undef(void); +void unmal(void *v, uint32 n); +void usage(void); +void vputb(uint64 v); +int valuecmp(LSym *a, LSym *b); +void vputl(uint64 v); +void wputb(ushort w); +void wputl(ushort w); +void xdefine(char *p, int t, vlong v); +void zerosig(char *sp); +void archinit(void); +void diag(char *fmt, ...); -uint8 decodetype_kind(Sym*); -vlong decodetype_size(Sym*); -Sym* decodetype_gc(Sym*); -Sym* decodetype_arrayelem(Sym*); -vlong decodetype_arraylen(Sym*); -Sym* decodetype_ptrelem(Sym*); -Sym* decodetype_mapkey(Sym*); -Sym* decodetype_mapvalue(Sym*); -Sym* decodetype_chanelem(Sym*); -int decodetype_funcdotdotdot(Sym*); -int decodetype_funcincount(Sym*); -int decodetype_funcoutcount(Sym*); -Sym* decodetype_funcintype(Sym*, int); -Sym* decodetype_funcouttype(Sym*, int); -int decodetype_structfieldcount(Sym*); -char* decodetype_structfieldname(Sym*, int); -Sym* decodetype_structfieldtype(Sym*, int); -vlong decodetype_structfieldoffs(Sym*, int); -vlong decodetype_ifacemethodcount(Sym*); +#pragma varargck argpos diag 1 diff --git a/src/cmd/ld/macho.c b/src/cmd/ld/macho.c index d135a92da..61306bb7c 100644 --- a/src/cmd/ld/macho.c +++ b/src/cmd/ld/macho.c @@ -25,7 +25,7 @@ enum }; static int nkind[NumSymKind]; -static Sym** sortsym; +static LSym** sortsym; static int nsortsym; // Amount of space left for adding load commands @@ -232,37 +232,37 @@ machowrite(void) void domacho(void) { - Sym *s; + LSym *s; if(debug['d']) return; // empirically, string table must begin with " \x00". - s = lookup(".machosymstr", 0); + s = linklookup(ctxt, ".machosymstr", 0); s->type = SMACHOSYMSTR; s->reachable = 1; - adduint8(s, ' '); - adduint8(s, '\0'); + adduint8(ctxt, s, ' '); + adduint8(ctxt, s, '\0'); - s = lookup(".machosymtab", 0); + s = linklookup(ctxt, ".machosymtab", 0); s->type = SMACHOSYMTAB; s->reachable = 1; if(linkmode != LinkExternal) { - s = lookup(".plt", 0); // will be __symbol_stub + s = linklookup(ctxt, ".plt", 0); // will be __symbol_stub s->type = SMACHOPLT; s->reachable = 1; - s = lookup(".got", 0); // will be __nl_symbol_ptr + s = linklookup(ctxt, ".got", 0); // will be __nl_symbol_ptr s->type = SMACHOGOT; s->reachable = 1; s->align = 4; - s = lookup(".linkedit.plt", 0); // indirect table for .plt + s = linklookup(ctxt, ".linkedit.plt", 0); // indirect table for .plt s->type = SMACHOINDIRECTPLT; s->reachable = 1; - s = lookup(".linkedit.got", 0); // indirect table for .got + s = linklookup(ctxt, ".linkedit.got", 0); // indirect table for .got s->type = SMACHOINDIRECTGOT; s->reachable = 1; } @@ -334,7 +334,7 @@ machoshbits(MachoSeg *mseg, Section *sect, char *segname) if(strcmp(sect->name, ".got") == 0) { msect->name = "__nl_symbol_ptr"; msect->flag = 6; /* section with nonlazy symbol pointers */ - msect->res1 = lookup(".linkedit.plt", 0)->size / 4; /* offset into indirect symbol table */ + msect->res1 = linklookup(ctxt, ".linkedit.plt", 0)->size / 4; /* offset into indirect symbol table */ } } @@ -432,13 +432,13 @@ asmbmacho(void) } if(!debug['d']) { - Sym *s1, *s2, *s3, *s4; + LSym *s1, *s2, *s3, *s4; // must match domacholink below - s1 = lookup(".machosymtab", 0); - s2 = lookup(".linkedit.plt", 0); - s3 = lookup(".linkedit.got", 0); - s4 = lookup(".machosymstr", 0); + s1 = linklookup(ctxt, ".machosymtab", 0); + s2 = linklookup(ctxt, ".linkedit.plt", 0); + s3 = linklookup(ctxt, ".linkedit.got", 0); + s4 = linklookup(ctxt, ".machosymstr", 0); if(linkmode != LinkExternal) { ms = newMachoSeg("__LINKEDIT", 0); @@ -484,7 +484,7 @@ asmbmacho(void) } static int -symkind(Sym *s) +symkind(LSym *s) { if(s->type == SDYNIMPORT) return SymKindUndef; @@ -494,7 +494,7 @@ symkind(Sym *s) } static void -addsym(Sym *s, char *name, int type, vlong addr, vlong size, int ver, Sym *gotype) +addsym(LSym *s, char *name, int type, vlong addr, vlong size, int ver, LSym *gotype) { USED(name); USED(addr); @@ -524,11 +524,11 @@ addsym(Sym *s, char *name, int type, vlong addr, vlong size, int ver, Sym *gotyp static int scmp(const void *p1, const void *p2) { - Sym *s1, *s2; + LSym *s1, *s2; int k1, k2; - s1 = *(Sym**)p1; - s2 = *(Sym**)p2; + s1 = *(LSym**)p1; + s2 = *(LSym**)p2; k1 = symkind(s1); k2 = symkind(s2); @@ -539,12 +539,12 @@ scmp(const void *p1, const void *p2) } static void -machogenasmsym(void (*put)(Sym*, char*, int, vlong, vlong, int, Sym*)) +machogenasmsym(void (*put)(LSym*, char*, int, vlong, vlong, int, LSym*)) { - Sym *s; + LSym *s; genasmsym(put); - for(s=allsym; s; s=s->allsym) + for(s=ctxt->allsym; s; s=s->allsym) if(s->type == SDYNIMPORT || s->type == SHOSTOBJ) if(s->reachable) put(s, nil, 'D', 0, 0, 0, nil); @@ -573,39 +573,54 @@ static void machosymtab(void) { int i; - Sym *symtab, *symstr, *s, *o; + LSym *symtab, *symstr, *s, *o; + char *p; - symtab = lookup(".machosymtab", 0); - symstr = lookup(".machosymstr", 0); + symtab = linklookup(ctxt, ".machosymtab", 0); + symstr = linklookup(ctxt, ".machosymstr", 0); for(i=0; i<nsortsym; i++) { s = sortsym[i]; - adduint32(symtab, symstr->size); + adduint32(ctxt, symtab, symstr->size); // Only add _ to C symbols. Go symbols have dot in the name. if(strstr(s->extname, ".") == nil) - adduint8(symstr, '_'); - addstring(symstr, s->extname); + adduint8(ctxt, symstr, '_'); + // replace "·" as ".", because DTrace cannot handle it. + if(strstr(s->extname, "·") == nil) { + addstring(symstr, s->extname); + } else { + p = s->extname; + while (*p++ != '\0') { + if((uchar)*p == 0xc2 && (uchar)*(p+1) == 0xb7) { + adduint8(ctxt, symstr, '.'); + p++; + } else { + adduint8(ctxt, symstr, *p); + } + } + adduint8(ctxt, symstr, '\0'); + } if(s->type == SDYNIMPORT || s->type == SHOSTOBJ) { - adduint8(symtab, 0x01); // type N_EXT, external symbol - adduint8(symtab, 0); // no section - adduint16(symtab, 0); // desc - adduintxx(symtab, 0, PtrSize); // no value + adduint8(ctxt, symtab, 0x01); // type N_EXT, external symbol + adduint8(ctxt, symtab, 0); // no section + adduint16(ctxt, symtab, 0); // desc + adduintxx(ctxt, symtab, 0, PtrSize); // no value } else { if(s->cgoexport) - adduint8(symtab, 0x0f); + adduint8(ctxt, symtab, 0x0f); else - adduint8(symtab, 0x0e); + adduint8(ctxt, symtab, 0x0e); o = s; while(o->outer != nil) o = o->outer; if(o->sect == nil) { diag("missing section for %s", s->name); - adduint8(symtab, 0); + adduint8(ctxt, symtab, 0); } else - adduint8(symtab, o->sect->extnum); - adduint16(symtab, 0); // desc - adduintxx(symtab, symaddr(s), PtrSize); + adduint8(ctxt, symtab, o->sect->extnum); + adduint16(ctxt, symtab, 0); // desc + adduintxx(ctxt, symtab, symaddr(s), PtrSize); } } } @@ -615,7 +630,7 @@ machodysymtab(void) { int n; MachoLoad *ml; - Sym *s1, *s2, *s3; + LSym *s1, *s2, *s3; ml = newMachoLoad(11, 18); /* LC_DYSYMTAB */ @@ -639,9 +654,9 @@ machodysymtab(void) ml->data[11] = 0; /* nextrefsyms */ // must match domacholink below - s1 = lookup(".machosymtab", 0); - s2 = lookup(".linkedit.plt", 0); - s3 = lookup(".linkedit.got", 0); + s1 = linklookup(ctxt, ".machosymtab", 0); + s2 = linklookup(ctxt, ".linkedit.plt", 0); + s3 = linklookup(ctxt, ".linkedit.got", 0); ml->data[12] = linkoff + s1->size; /* indirectsymoff */ ml->data[13] = (s2->size + s3->size) / 4; /* nindirectsyms */ @@ -655,15 +670,15 @@ vlong domacholink(void) { int size; - Sym *s1, *s2, *s3, *s4; + LSym *s1, *s2, *s3, *s4; machosymtab(); // write data that will be linkedit section - s1 = lookup(".machosymtab", 0); - s2 = lookup(".linkedit.plt", 0); - s3 = lookup(".linkedit.got", 0); - s4 = lookup(".machosymstr", 0); + s1 = linklookup(ctxt, ".machosymtab", 0); + s2 = linklookup(ctxt, ".linkedit.plt", 0); + s3 = linklookup(ctxt, ".linkedit.got", 0); + s4 = linklookup(ctxt, ".machosymstr", 0); // Force the linkedit section to end on a 16-byte // boundary. This allows pure (non-cgo) Go binaries @@ -683,7 +698,7 @@ domacholink(void) // any alignment padding itself, working around the // issue. while(s4->size%16) - adduint8(s4, 0); + adduint8(ctxt, s4, 0); size = s1->size + s2->size + s3->size + s4->size; @@ -702,9 +717,9 @@ domacholink(void) void -machorelocsect(Section *sect, Sym *first) +machorelocsect(Section *sect, LSym *first) { - Sym *sym; + LSym *sym; int32 eaddr; Reloc *r; @@ -726,7 +741,7 @@ machorelocsect(Section *sect, Sym *first) continue; if(sym->value >= eaddr) break; - cursym = sym; + ctxt->cursym = sym; for(r = sym->r; r < sym->r+sym->nr; r++) { if(r->done) @@ -747,7 +762,7 @@ machoemitreloc(void) while(cpos()&7) cput(0); - machorelocsect(segtext.sect, textp); + machorelocsect(segtext.sect, ctxt->textp); for(sect=segtext.sect->next; sect!=nil; sect=sect->next) machorelocsect(sect, datap); for(sect=segdata.sect; sect!=nil; sect=sect->next) diff --git a/src/cmd/ld/pass.c b/src/cmd/ld/pass.c new file mode 100644 index 000000000..788b7c75a --- /dev/null +++ b/src/cmd/ld/pass.c @@ -0,0 +1,104 @@ +// Inferno utils/6l/pass.c +// http://code.google.com/p/inferno-os/source/browse/utils/6l/pass.c +// +// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. +// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) +// Portions Copyright © 1997-1999 Vita Nuova Limited +// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) +// Portions Copyright © 2004,2006 Bruce Ellis +// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) +// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others +// Portions Copyright © 2009 The Go Authors. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +// Code and data passes. + +#include "l.h" +#include "../ld/lib.h" +#include "../../pkg/runtime/stack.h" + +void +follow(void) +{ + LSym *s; + + if(debug['v']) + Bprint(&bso, "%5.2f follow\n", cputime()); + Bflush(&bso); + + for(s = ctxt->textp; s != nil; s = s->next) + ctxt->arch->follow(ctxt, s); +} + +void +patch(void) +{ + LSym *s; + + if(debug['v']) + Bprint(&bso, "%5.2f mkfwd\n", cputime()); + Bflush(&bso); + for(s = ctxt->textp; s != nil; s = s->next) + mkfwd(s); + if(debug['v']) + Bprint(&bso, "%5.2f patch\n", cputime()); + Bflush(&bso); + + if(flag_shared) { + s = linklookup(ctxt, "init_array", 0); + s->type = SINITARR; + s->reachable = 1; + s->hide = 1; + addaddr(ctxt, s, linklookup(ctxt, INITENTRY, 0)); + } + + for(s = ctxt->textp; s != nil; s = s->next) + linkpatch(ctxt, s); +} + +void +dostkoff(void) +{ + LSym *s; + + for(s = ctxt->textp; s != nil; s = s->next) + ctxt->arch->addstacksplit(ctxt, s); +} + +void +span(void) +{ + LSym *s; + + if(debug['v']) + Bprint(&bso, "%5.2f span\n", cputime()); + + for(s = ctxt->textp; s != nil; s = s->next) + ctxt->arch->assemble(ctxt, s); +} + +void +pcln(void) +{ + LSym *s; + + for(s = ctxt->textp; s != nil; s = s->next) + linkpcln(ctxt, s); +} diff --git a/src/cmd/ld/pcln.c b/src/cmd/ld/pcln.c new file mode 100644 index 000000000..4c2ffa78e --- /dev/null +++ b/src/cmd/ld/pcln.c @@ -0,0 +1,244 @@ +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +#include "l.h" +#include "lib.h" +#include "../../pkg/runtime/funcdata.h" + +static void +addvarint(Pcdata *d, uint32 val) +{ + int32 n; + uint32 v; + uchar *p; + + n = 0; + for(v = val; v >= 0x80; v >>= 7) + n++; + n++; + + if(d->n + n > d->m) { + d->m = (d->n + n)*2; + d->p = erealloc(d->p, d->m); + } + + p = d->p + d->n; + for(v = val; v >= 0x80; v >>= 7) + *p++ = v | 0x80; + *p = v; + d->n += n; +} + +static int32 +addpctab(LSym *ftab, int32 off, Pcdata *d) +{ + int32 start; + + start = ftab->np; + symgrow(ctxt, ftab, start + d->n); + memmove(ftab->p + start, d->p, d->n); + + return setuint32(ctxt, ftab, off, start); +} + +static int32 +ftabaddstring(LSym *ftab, char *s) +{ + int32 n, start; + + n = strlen(s)+1; + start = ftab->np; + symgrow(ctxt, ftab, start+n+1); + strcpy((char*)ftab->p + start, s); + return start; +} + +static void +renumberfiles(Link *ctxt, LSym **files, int nfiles, Pcdata *d) +{ + int i; + LSym *f; + Pcdata out; + Pciter it; + uint32 v; + int32 oldval, newval, val, dv; + + // Give files numbers. + for(i=0; i<nfiles; i++) { + f = files[i]; + if(f->type != SFILEPATH) { + f->value = ++ctxt->nhistfile; + f->type = SFILEPATH; + f->next = ctxt->filesyms; + ctxt->filesyms = f; + } + } + + newval = -1; + memset(&out, 0, sizeof out); + + for(pciterinit(ctxt, &it, d); !it.done; pciternext(&it)) { + // value delta + oldval = it.value; + if(oldval == -1) + val = -1; + else { + if(oldval < 0 || oldval >= nfiles) + sysfatal("bad pcdata %d", oldval); + val = files[oldval]->value; + } + dv = val - newval; + newval = val; + v = (uint32)(dv<<1) ^ (uint32)(int32)(dv>>31); + addvarint(&out, v); + + // pc delta + addvarint(&out, (it.nextpc - it.pc) / it.pcscale); + } + + // terminating value delta + addvarint(&out, 0); + + free(d->p); + *d = out; +} + + +// pclntab initializes the pclntab symbol with +// runtime function and file name information. +void +pclntab(void) +{ + int32 i, nfunc, start, funcstart; + LSym *ftab, *s; + int32 off, end, frameptrsize; + int64 funcdata_bytes; + Pcln *pcln; + Pciter it; + static Pcln zpcln; + + funcdata_bytes = 0; + ftab = linklookup(ctxt, "pclntab", 0); + ftab->type = SPCLNTAB; + ftab->reachable = 1; + + // See golang.org/s/go12symtab for the format. Briefly: + // 8-byte header + // nfunc [PtrSize bytes] + // function table, alternating PC and offset to func struct [each entry PtrSize bytes] + // end PC [PtrSize bytes] + // offset to file table [4 bytes] + nfunc = 0; + for(ctxt->cursym = ctxt->textp; ctxt->cursym != nil; ctxt->cursym = ctxt->cursym->next) + nfunc++; + symgrow(ctxt, ftab, 8+PtrSize+nfunc*2*PtrSize+PtrSize+4); + setuint32(ctxt, ftab, 0, 0xfffffffb); + setuint8(ctxt, ftab, 6, MINLC); + setuint8(ctxt, ftab, 7, PtrSize); + setuintxx(ctxt, ftab, 8, nfunc, PtrSize); + + nfunc = 0; + for(ctxt->cursym = ctxt->textp; ctxt->cursym != nil; ctxt->cursym = ctxt->cursym->next, nfunc++) { + pcln = ctxt->cursym->pcln; + if(pcln == nil) + pcln = &zpcln; + + funcstart = ftab->np; + funcstart += -ftab->np & (PtrSize-1); + + setaddr(ctxt, ftab, 8+PtrSize+nfunc*2*PtrSize, ctxt->cursym); + setuintxx(ctxt, ftab, 8+PtrSize+nfunc*2*PtrSize+PtrSize, funcstart, PtrSize); + + // fixed size of struct, checked below + off = funcstart; + end = funcstart + PtrSize + 3*4 + 5*4 + pcln->npcdata*4 + pcln->nfuncdata*PtrSize; + if(pcln->nfuncdata > 0 && (end&(PtrSize-1))) + end += 4; + symgrow(ctxt, ftab, end); + + // entry uintptr + off = setaddr(ctxt, ftab, off, ctxt->cursym); + + // name int32 + off = setuint32(ctxt, ftab, off, ftabaddstring(ftab, ctxt->cursym->name)); + + // args int32 + // TODO: Move into funcinfo. + off = setuint32(ctxt, ftab, off, ctxt->cursym->args); + + // frame int32 + // TODO: Remove entirely. The pcsp table is more precise. + // This is only used by a fallback case during stack walking + // when a called function doesn't have argument information. + // We need to make sure everything has argument information + // and then remove this. + frameptrsize = PtrSize; + if(ctxt->cursym->leaf) + frameptrsize = 0; + off = setuint32(ctxt, ftab, off, ctxt->cursym->locals + frameptrsize); + + if(pcln != &zpcln) { + renumberfiles(ctxt, pcln->file, pcln->nfile, &pcln->pcfile); + if(0) { + // Sanity check the new numbering + for(pciterinit(ctxt, &it, &pcln->pcfile); !it.done; pciternext(&it)) { + if(it.value < 1 || it.value > ctxt->nhistfile) { + diag("bad file number in pcfile: %d not in range [1, %d]\n", it.value, ctxt->nhistfile); + errorexit(); + } + } + } + } + + // pcdata + off = addpctab(ftab, off, &pcln->pcsp); + off = addpctab(ftab, off, &pcln->pcfile); + off = addpctab(ftab, off, &pcln->pcline); + off = setuint32(ctxt, ftab, off, pcln->npcdata); + off = setuint32(ctxt, ftab, off, pcln->nfuncdata); + for(i=0; i<pcln->npcdata; i++) + off = addpctab(ftab, off, &pcln->pcdata[i]); + + // funcdata, must be pointer-aligned and we're only int32-aligned. + // Missing funcdata will be 0 (nil pointer). + if(pcln->nfuncdata > 0) { + if(off&(PtrSize-1)) + off += 4; + for(i=0; i<pcln->nfuncdata; i++) { + if(pcln->funcdata[i] == nil) + setuintxx(ctxt, ftab, off+PtrSize*i, pcln->funcdataoff[i], PtrSize); + else { + // TODO: Dedup. + funcdata_bytes += pcln->funcdata[i]->size; + setaddrplus(ctxt, ftab, off+PtrSize*i, pcln->funcdata[i], pcln->funcdataoff[i]); + } + } + off += pcln->nfuncdata*PtrSize; + } + + if(off != end) { + diag("bad math in functab: funcstart=%d off=%d but end=%d (npcdata=%d nfuncdata=%d ptrsize=%d)", funcstart, off, end, pcln->npcdata, pcln->nfuncdata, PtrSize); + errorexit(); + } + + // Final entry of table is just end pc. + if(ctxt->cursym->next == nil) + setaddrplus(ctxt, ftab, 8+PtrSize+(nfunc+1)*2*PtrSize, ctxt->cursym, ctxt->cursym->size); + } + + // Start file table. + start = ftab->np; + start += -ftab->np & (PtrSize-1); + setuint32(ctxt, ftab, 8+PtrSize+nfunc*2*PtrSize+PtrSize, start); + + symgrow(ctxt, ftab, start+(ctxt->nhistfile+1)*4); + setuint32(ctxt, ftab, start, ctxt->nhistfile); + for(s = ctxt->filesyms; s != S; s = s->next) + setuint32(ctxt, ftab, start + s->value*4, ftabaddstring(ftab, s->name)); + + ftab->size = ftab->np; + + if(debug['v']) + Bprint(&bso, "%5.2f pclntab=%lld bytes, funcdata total %lld bytes\n", cputime(), (vlong)ftab->size, (vlong)funcdata_bytes); +} diff --git a/src/cmd/ld/pe.c b/src/cmd/ld/pe.c index 7b9a596fc..c26cd5264 100644 --- a/src/cmd/ld/pe.c +++ b/src/cmd/ld/pe.c @@ -32,15 +32,11 @@ static char dosstub[] = 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; -// Note: currently only up to 8 chars plus \0. -static char *symlabels[] = { - "symtab", "esymtab", "pclntab", "epclntab" -}; - -static Sym *rsrcsym; +static LSym *rsrcsym; -static char symnames[256]; -static int nextsymoff; +static char* strtbl; +static int strtblnextoff; +static int strtblsize; int32 PESECTHEADR; int32 PEFILEHEADR; @@ -50,6 +46,7 @@ static int nsect; static int nextsectoff; static int nextfileoff; static int textsect; +static int datasect; static IMAGE_FILE_HEADER fh; static IMAGE_OPTIONAL_HEADER oh; @@ -62,7 +59,7 @@ static IMAGE_DATA_DIRECTORY* dd; typedef struct Imp Imp; struct Imp { - Sym* s; + LSym* s; uvlong off; Imp* next; }; @@ -78,9 +75,21 @@ struct Dll { static Dll* dr; -static Sym *dexport[1024]; +static LSym *dexport[1024]; static int nexport; +typedef struct COFFSym COFFSym; +struct COFFSym +{ + LSym* sym; + int strtbloff; + int sect; + vlong value; +}; + +static COFFSym* coffsym; +static int ncoffsym; + static IMAGE_SECTION_HEADER* addpesection(char *name, int sectsize, int filesize) { @@ -191,11 +200,11 @@ initdynimport(void) { Imp *m; Dll *d; - Sym *s, *dynamic; + LSym *s, *dynamic; dr = nil; m = nil; - for(s = allsym; s != S; s = s->allsym) { + for(s = ctxt->allsym; s != S; s = s->allsym) { if(!s->reachable || s->type != SDYNIMPORT) continue; for(d = dr; d != nil; d = d->next) { @@ -216,7 +225,7 @@ initdynimport(void) d->ms = m; } - dynamic = lookup(".windynamic", 0); + dynamic = linklookup(ctxt, ".windynamic", 0); dynamic->reachable = 1; dynamic->type = SWINDOWS; for(d = dr; d != nil; d = d->next) { @@ -241,10 +250,10 @@ addimports(IMAGE_SECTION_HEADER *datsect) vlong startoff, endoff; Imp *m; Dll *d; - Sym* dynamic; + LSym* dynamic; startoff = cpos(); - dynamic = lookup(".windynamic", 0); + dynamic = linklookup(ctxt, ".windynamic", 0); // skip import descriptor table (will write it later) n = 0; @@ -322,20 +331,20 @@ addimports(IMAGE_SECTION_HEADER *datsect) static int scmp(const void *p1, const void *p2) { - Sym *s1, *s2; + LSym *s1, *s2; - s1 = *(Sym**)p1; - s2 = *(Sym**)p2; + s1 = *(LSym**)p1; + s2 = *(LSym**)p2; return strcmp(s1->extname, s2->extname); } static void initdynexport(void) { - Sym *s; + LSym *s; nexport = 0; - for(s = allsym; s != S; s = s->allsym) { + for(s = ctxt->allsym; s != S; s = s->allsym) { if(!s->reachable || !(s->cgoexport & CgoExportDynamic)) continue; if(nexport+1 > sizeof(dexport)/sizeof(dexport[0])) { @@ -410,10 +419,10 @@ addexports(void) void dope(void) { - Sym *rel; + LSym *rel; /* relocation table */ - rel = lookup(".rel", 0); + rel = linklookup(ctxt, ".rel", 0); rel->reachable = 1; rel->type = SELFROSECT; @@ -421,6 +430,24 @@ dope(void) initdynexport(); } +static int +strtbladd(char *name) +{ + int newsize, thisoff; + + newsize = strtblnextoff + strlen(name) + 1; + if(newsize > strtblsize) { + strtblsize = 2 * (newsize + (1<<18)); + strtbl = realloc(strtbl, strtblsize); + } + thisoff = strtblnextoff+4; // first string starts at offset=4 + strcpy(&strtbl[strtblnextoff], name); + strtblnextoff += strlen(name); + strtbl[strtblnextoff] = 0; + strtblnextoff++; + return thisoff; +} + /* * For more than 8 characters section names, name contains a slash (/) that is * followed by an ASCII representation of a decimal number that is an offset into @@ -433,20 +460,13 @@ newPEDWARFSection(char *name, vlong size) { IMAGE_SECTION_HEADER *h; char s[8]; + int off; if(size == 0) return nil; - if(nextsymoff+strlen(name)+1 > sizeof(symnames)) { - diag("pe string table is full"); - errorexit(); - } - - strcpy(&symnames[nextsymoff], name); - sprint(s, "/%d\0", nextsymoff+4); - nextsymoff += strlen(name); - symnames[nextsymoff] = 0; - nextsymoff ++; + off = strtbladd(name); + sprint(s, "/%d\0", off); h = addpesection(s, size, size); h->Characteristics = IMAGE_SCN_MEM_READ| IMAGE_SCN_MEM_DISCARDABLE; @@ -455,40 +475,97 @@ newPEDWARFSection(char *name, vlong size) } static void +addsym(LSym *s, char *name, int type, vlong addr, vlong size, int ver, LSym *gotype) +{ + COFFSym *cs; + USED(name); + USED(addr); + USED(size); + USED(ver); + USED(gotype); + + if(s == nil) + return; + + if(s->sect == nil) + return; + + switch(type) { + default: + return; + case 'D': + case 'B': + case 'T': + break; + } + + if(coffsym) { + cs = &coffsym[ncoffsym]; + cs->sym = s; + if(strlen(s->name) > 8) + cs->strtbloff = strtbladd(s->name); + if(s->value >= segdata.vaddr) { + cs->value = s->value - segdata.vaddr; + cs->sect = datasect; + } else if(s->value >= segtext.vaddr) { + cs->value = s->value - segtext.vaddr; + cs->sect = textsect; + } else { + cs->value = 0; + cs->sect = 0; + diag("addsym %#llx", addr); + } + } + ncoffsym++; +} + +static void addsymtable(void) { IMAGE_SECTION_HEADER *h; int i, size; - Sym *s; - - fh.NumberOfSymbols = sizeof(symlabels)/sizeof(symlabels[0]); - size = nextsymoff + 4 + 18*fh.NumberOfSymbols; + COFFSym *s; + + if(!debug['s']) { + genasmsym(addsym); + coffsym = mal(ncoffsym * sizeof coffsym[0]); + ncoffsym = 0; + genasmsym(addsym); + } + + size = strtblnextoff + 4 + 18*ncoffsym; h = addpesection(".symtab", size, size); h->Characteristics = IMAGE_SCN_MEM_READ| IMAGE_SCN_MEM_DISCARDABLE; chksectoff(h, cpos()); fh.PointerToSymbolTable = cpos(); + fh.NumberOfSymbols = ncoffsym; // put COFF symbol table - for (i=0; i<fh.NumberOfSymbols; i++) { - s = rlookup(symlabels[i], 0); - strnput(s->name, 8); - lputl(datoff(s->value)); - wputl(textsect); + for (i=0; i<ncoffsym; i++) { + s = &coffsym[i]; + if(s->strtbloff == 0) + strnput(s->sym->name, 8); + else { + lputl(0); + lputl(s->strtbloff); + } + lputl(s->value); + wputl(s->sect); wputl(0x0308); // "array of structs" cput(2); // storage class: external cput(0); // no aux entries } // put COFF string table - lputl(nextsymoff + 4); - for (i=0; i<nextsymoff; i++) - cput(symnames[i]); + lputl(strtblnextoff + 4); + for (i=0; i<strtblnextoff; i++) + cput(strtbl[i]); strnput("", h->SizeOfRawData - size); } void -setpersrc(Sym *sym) +setpersrc(LSym *sym) { if(rsrcsym != nil) diag("too many .rsrc sections"); @@ -529,49 +606,6 @@ addpersrc(void) dd[IMAGE_DIRECTORY_ENTRY_RESOURCE].Size = h->VirtualSize; } -static void -addexcept(IMAGE_SECTION_HEADER *text) -{ - IMAGE_SECTION_HEADER *pdata, *xdata; - vlong startoff; - uvlong n; - Sym *sym; - - USED(text); - if(thechar != '6') - return; - - // write unwind info - sym = lookup("runtime.sigtramp", 0); - startoff = cpos(); - lputl(9); // version=1, flags=UNW_FLAG_EHANDLER, rest 0 - lputl(sym->value - PEBASE); - lputl(0); - - n = cpos() - startoff; - xdata = addpesection(".xdata", n, n); - xdata->Characteristics = IMAGE_SCN_MEM_READ| - IMAGE_SCN_CNT_INITIALIZED_DATA; - chksectoff(xdata, startoff); - strnput("", xdata->SizeOfRawData - n); - - // write a function table entry for the whole text segment - startoff = cpos(); - lputl(text->VirtualAddress); - lputl(text->VirtualAddress + text->VirtualSize); - lputl(xdata->VirtualAddress); - - n = cpos() - startoff; - pdata = addpesection(".pdata", n, n); - pdata->Characteristics = IMAGE_SCN_MEM_READ| - IMAGE_SCN_CNT_INITIALIZED_DATA; - chksectoff(pdata, startoff); - strnput("", pdata->SizeOfRawData - n); - - dd[IMAGE_DIRECTORY_ENTRY_EXCEPTION].VirtualAddress = pdata->VirtualAddress; - dd[IMAGE_DIRECTORY_ENTRY_EXCEPTION].Size = pdata->VirtualSize; -} - void asmbpe(void) { @@ -600,6 +634,7 @@ asmbpe(void) d->Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA| IMAGE_SCN_MEM_READ|IMAGE_SCN_MEM_WRITE; chksectseg(d, &segdata); + datasect = nsect; if(!debug['s']) dwarfaddpeheaders(); @@ -609,7 +644,6 @@ asmbpe(void) addexports(); addsymtable(); addpersrc(); - addexcept(t); fh.NumberOfSections = nsect; fh.TimeDateStamp = time(0); diff --git a/src/cmd/ld/pe.h b/src/cmd/ld/pe.h index 7aa938829..03ed8d830 100644 --- a/src/cmd/ld/pe.h +++ b/src/cmd/ld/pe.h @@ -176,4 +176,4 @@ typedef struct { IMAGE_DATA_DIRECTORY DataDirectory[16]; } PE64_IMAGE_OPTIONAL_HEADER; -void setpersrc(Sym *sym); +void setpersrc(LSym *sym); diff --git a/src/cmd/ld/pobj.c b/src/cmd/ld/pobj.c new file mode 100644 index 000000000..819c37954 --- /dev/null +++ b/src/cmd/ld/pobj.c @@ -0,0 +1,197 @@ +// Inferno utils/6l/obj.c +// http://code.google.com/p/inferno-os/source/browse/utils/6l/obj.c +// +// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. +// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) +// Portions Copyright © 1997-1999 Vita Nuova Limited +// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) +// Portions Copyright © 2004,2006 Bruce Ellis +// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) +// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others +// Portions Copyright © 2009 The Go Authors. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +// Reading object files. + +#define EXTERN +#include "l.h" +#include "../ld/lib.h" +#include "../ld/elf.h" +#include "../ld/macho.h" +#include "../ld/dwarf.h" +#include "../ld/pe.h" +#include <ar.h> + +char *noname = "<none>"; +char* paramspace = "FP"; + +void +main(int argc, char *argv[]) +{ + linkarchinit(); + ctxt = linknew(thelinkarch); + ctxt->thechar = thechar; + ctxt->thestring = thestring; + ctxt->diag = diag; + ctxt->bso = &bso; + + Binit(&bso, 1, OWRITE); + listinit(); + memset(debug, 0, sizeof(debug)); + nerrors = 0; + outfile = nil; + HEADTYPE = -1; + INITTEXT = -1; + INITDAT = -1; + INITRND = -1; + INITENTRY = 0; + linkmode = LinkAuto; + nuxiinit(); + + if(thechar == '5' && ctxt->goarm == 5) + debug['F'] = 1; + + flagcount("1", "use alternate profiling code", &debug['1']); + if(thechar == '6') + flagcount("8", "assume 64-bit addresses", &debug['8']); + flagfn1("B", "info: define ELF NT_GNU_BUILD_ID note", addbuildinfo); + flagint64("D", "addr: data address", &INITDAT); + flagstr("E", "sym: entry symbol", &INITENTRY); + if(thechar == '5') + flagcount("G", "debug pseudo-ops", &debug['G']); + flagfn1("I", "interp: set ELF interp", setinterp); + flagfn1("L", "dir: add dir to library path", Lflag); + flagfn1("H", "head: header type", setheadtype); + flagcount("K", "add stack underflow checks", &debug['K']); + if(thechar == '5') + flagcount("M", "disable software div/mod", &debug['M']); + flagcount("O", "print pc-line tables", &debug['O']); + flagcount("Q", "debug byte-register code gen", &debug['Q']); + if(thechar == '5') + flagcount("P", "debug code generation", &debug['P']); + flagint32("R", "rnd: address rounding", &INITRND); + flagcount("S", "check type signatures", &debug['S']); + flagint64("T", "addr: text address", &INITTEXT); + flagfn0("V", "print version and exit", doversion); + flagcount("W", "disassemble input", &debug['W']); + flagfn2("X", "name value: define string data", addstrdata); + flagcount("Z", "clear stack frame on entry", &debug['Z']); + flagcount("a", "disassemble output", &debug['a']); + flagcount("c", "dump call graph", &debug['c']); + flagcount("d", "disable dynamic executable", &debug['d']); + flagstr("extld", "linker to run in external mode", &extld); + flagstr("extldflags", "flags for external linker", &extldflags); + flagcount("f", "ignore version mismatch", &debug['f']); + flagcount("g", "disable go package data checks", &debug['g']); + flagstr("installsuffix", "pkg directory suffix", &flag_installsuffix); + flagstr("k", "sym: set field tracking symbol", &tracksym); + flagfn1("linkmode", "mode: set link mode (internal, external, auto)", setlinkmode); + flagcount("n", "dump symbol table", &debug['n']); + flagstr("o", "outfile: set output file", &outfile); + flagstr("r", "dir1:dir2:...: set ELF dynamic linker search path", &rpath); + flagcount("race", "enable race detector", &flag_race); + flagcount("s", "disable symbol table", &debug['s']); + if(thechar == '5' || thechar == '6') + flagcount("shared", "generate shared object (implies -linkmode external)", &flag_shared); + flagstr("tmpdir", "leave temporary files in this directory", &tmpdir); + flagcount("u", "reject unsafe packages", &debug['u']); + flagcount("v", "print link trace", &debug['v']); + flagcount("w", "disable DWARF generation", &debug['w']); + + flagparse(&argc, &argv, usage); + ctxt->bso = &bso; + ctxt->debugdivmod = debug['M']; + ctxt->debugfloat = debug['F']; + ctxt->debughist = debug['O']; + ctxt->debugpcln = debug['O']; + ctxt->debugread = debug['W']; + ctxt->debugstack = debug['K']; + ctxt->debugvlog = debug['v']; + + if(argc != 1) + usage(); + + if(outfile == nil) { + if(HEADTYPE == Hwindows) + outfile = smprint("%c.out.exe", thechar); + else + outfile = smprint("%c.out", thechar); + } + libinit(); // creates outfile + + if(HEADTYPE == -1) + HEADTYPE = headtype(goos); + ctxt->headtype = HEADTYPE; + if (headstring == nil) + headstring = headstr(HEADTYPE); + + archinit(); + ctxt->debugfloat = debug['F']; + + if(debug['v']) + Bprint(&bso, "HEADER = -H%d -T0x%llux -D0x%llux -R0x%ux\n", + HEADTYPE, INITTEXT, INITDAT, INITRND); + Bflush(&bso); + + cbp = buf.cbuf; + cbc = sizeof(buf.cbuf); + + addlibpath(ctxt, "command line", "command line", argv[0], "main"); + loadlib(); + + if(thechar == '5') { + // mark some functions that are only referenced after linker code editing + if(debug['F']) + mark(linkrlookup(ctxt, "_sfloat", 0)); + mark(linklookup(ctxt, "runtime.read_tls_fallback", 0)); + } + + deadcode(); + callgraph(); + paramspace = "SP"; /* (FP) now (SP) on output */ + + doelf(); + if(HEADTYPE == Hdarwin) + domacho(); + dostkcheck(); + if(HEADTYPE == Hwindows) + dope(); + addexport(); + textaddress(); + pclntab(); + symtab(); + dodata(); + address(); + doweak(); + reloc(); + asmb(); + undef(); + hostlink(); + if(debug['v']) { + Bprint(&bso, "%5.2f cpu time\n", cputime()); + Bprint(&bso, "%d symbols\n", ctxt->nsymbol); + Bprint(&bso, "%d sizeof adr\n", sizeof(Addr)); + Bprint(&bso, "%d sizeof prog\n", sizeof(Prog)); + Bprint(&bso, "%lld liveness data\n", liveness); + } + Bflush(&bso); + + errorexit(); +} diff --git a/src/cmd/ld/symtab.c b/src/cmd/ld/symtab.c index c9b4657f7..6d321c0bb 100644 --- a/src/cmd/ld/symtab.c +++ b/src/cmd/ld/symtab.c @@ -40,6 +40,7 @@ static int putelfstr(char *s) { int off, n; + char *p, *q; if(elfstrsize == 0 && s[0] != 0) { // first entry must be empty string @@ -54,6 +55,21 @@ putelfstr(char *s) off = elfstrsize; elfstrsize += n; memmove(elfstrdat+off, s, n); + // replace "·" as ".", because DTrace cannot handle it. + p = strstr(s, "·"); + if(p != nil) { + p = q = elfstrdat+off; + while (*q != '\0') { + if((uchar)*q == 0xc2 && (uchar)*(q+1) == 0xb7) { + q += 2; + *p++ = '.'; + elfstrsize--; + } else { + *p++ = *q++; + } + } + *p = '\0'; + } return off; } @@ -86,10 +102,10 @@ static int numelfsym = 1; // 0 is reserved static int elfbind; static void -putelfsym(Sym *x, char *s, int t, vlong addr, vlong size, int ver, Sym *go) +putelfsym(LSym *x, char *s, int t, vlong addr, vlong size, int ver, LSym *go) { int bind, type, off; - Sym *xo; + LSym *xo; USED(go); switch(t) { @@ -109,12 +125,12 @@ putelfsym(Sym *x, char *s, int t, vlong addr, vlong size, int ver, Sym *go) while(xo->outer != nil) xo = xo->outer; if(xo->sect == nil) { - cursym = x; + ctxt->cursym = x; diag("missing section in putelfsym"); return; } if(xo->sect->elfsect == nil) { - cursym = x; + ctxt->cursym = x; diag("missing ELF section in putelfsym"); return; } @@ -143,7 +159,7 @@ putelfsym(Sym *x, char *s, int t, vlong addr, vlong size, int ver, Sym *go) } void -putelfsectionsym(Sym* s, int shndx) +putelfsectionsym(LSym* s, int shndx) { putelfsyment(0, 0, 0, (STB_LOCAL<<4)|STT_SECTION, shndx, 0); s->elfsym = numelfsym++; @@ -170,7 +186,8 @@ putelfsymshndx(vlong sympos, int shndx) void asmelfsym(void) { - Sym *s; + LSym *s; + char *name; // the first symbol entry is reserved putelfsyment(0, 0, 0, (STB_LOCAL<<4)|STT_NOTYPE, 0, 0); @@ -181,9 +198,9 @@ asmelfsym(void) genasmsym(putelfsym); if(linkmode == LinkExternal && HEADTYPE != Hopenbsd) { - s = lookup("runtime.tlsgm", 0); + s = linklookup(ctxt, "runtime.tlsgm", 0); if(s->sect == nil) { - cursym = nil; + ctxt->cursym = nil; diag("missing section for %s", s->name); errorexit(); } @@ -195,16 +212,20 @@ asmelfsym(void) elfglobalsymndx = numelfsym; genasmsym(putelfsym); - for(s=allsym; s!=S; s=s->allsym) { - if(s->type != SHOSTOBJ) + for(s=ctxt->allsym; s!=S; s=s->allsym) { + if(s->type != SHOSTOBJ && !(s->type == SDYNIMPORT && s->reachable)) continue; - putelfsyment(putelfstr(s->name), 0, 0, (STB_GLOBAL<<4)|STT_NOTYPE, 0, 0); + if(s->type == SDYNIMPORT) + name = s->extname; + else + name = s->name; + putelfsyment(putelfstr(name), 0, 0, (STB_GLOBAL<<4)|STT_NOTYPE, 0, 0); s->elfsym = numelfsym++; } } static void -putplan9sym(Sym *x, char *s, int t, vlong addr, vlong size, int ver, Sym *go) +putplan9sym(LSym *x, char *s, int t, vlong addr, vlong size, int ver, LSym *go) { int i, l; @@ -226,7 +247,7 @@ putplan9sym(Sym *x, char *s, int t, vlong addr, vlong size, int ver, Sym *go) case 'Z': case 'm': l = 4; - if(HEADTYPE == Hplan9x64 && !debug['8']) { + if(HEADTYPE == Hplan9 && thechar == '6' && !debug['8']) { lputb(addr>>32); l = 8; } @@ -263,48 +284,7 @@ asmplan9sym(void) genasmsym(putplan9sym); } -static Sym *symt; - -static void -scput(int b) -{ - uchar *p; - - symgrow(symt, symt->size+1); - p = symt->p + symt->size; - *p = b; - symt->size++; -} - -static void -slputb(int32 v) -{ - uchar *p; - - symgrow(symt, symt->size+4); - p = symt->p + symt->size; - *p++ = v>>24; - *p++ = v>>16; - *p++ = v>>8; - *p = v; - symt->size += 4; -} - -static void -slputl(int32 v) -{ - uchar *p; - - symgrow(symt, symt->size+4); - p = symt->p + symt->size; - *p++ = v; - *p++ = v>>8; - *p++ = v>>16; - *p = v>>24; - symt->size += 4; -} - -static void (*slput)(int32); +static LSym *symt; void wputl(ushort w) @@ -352,112 +332,10 @@ vputl(uint64 v) lputl(v >> 32); } -// Emit symbol table entry. -// The table format is described at the top of ../../pkg/runtime/symtab.c. -void -putsymb(Sym *s, char *name, int t, vlong v, vlong size, int ver, Sym *typ) -{ - int i, f, c; - vlong v1; - Reloc *rel; - - USED(size); - - // type byte - if('A' <= t && t <= 'Z') - c = t - 'A' + (ver ? 26 : 0); - else if('a' <= t && t <= 'z') - c = t - 'a' + 26; - else { - diag("invalid symbol table type %c", t); - errorexit(); - return; - } - - if(s != nil) - c |= 0x40; // wide value - if(typ != nil) - c |= 0x80; // has go type - scput(c); - - // value - if(s != nil) { - // full width - rel = addrel(symt); - rel->siz = PtrSize; - rel->sym = s; - rel->type = D_ADDR; - rel->off = symt->size; - if(PtrSize == 8) - slput(0); - slput(0); - } else { - // varint - if(v < 0) { - diag("negative value in symbol table: %s %lld", name, v); - errorexit(); - } - v1 = v; - while(v1 >= 0x80) { - scput(v1 | 0x80); - v1 >>= 7; - } - scput(v1); - } - - // go type if present - if(typ != nil) { - if(!typ->reachable) - diag("unreachable type %s", typ->name); - rel = addrel(symt); - rel->siz = PtrSize; - rel->sym = typ; - rel->type = D_ADDR; - rel->off = symt->size; - if(PtrSize == 8) - slput(0); - slput(0); - } - - // name - if(t == 'f') - name++; - - if(t == 'Z' || t == 'z') { - scput(name[0]); - for(i=1; name[i] != 0 || name[i+1] != 0; i += 2) { - scput(name[i]); - scput(name[i+1]); - } - scput(0); - scput(0); - } else { - for(i=0; name[i]; i++) - scput(name[i]); - scput(0); - } - - if(debug['n']) { - if(t == 'z' || t == 'Z') { - Bprint(&bso, "%c %.8llux ", t, v); - for(i=1; name[i] != 0 || name[i+1] != 0; i+=2) { - f = ((name[i]&0xff) << 8) | (name[i+1]&0xff); - Bprint(&bso, "/%x", f); - } - Bprint(&bso, "\n"); - return; - } - if(ver) - Bprint(&bso, "%c %.8llux %s<%d> %s\n", t, v, name, ver, typ ? typ->name : ""); - else - Bprint(&bso, "%c %.8llux %s %s\n", t, v, name, typ ? typ->name : ""); - } -} - void symtab(void) { - Sym *s, *symtype, *symtypelink, *symgostring, *symgofunc; + LSym *s, *symtype, *symtypelink, *symgostring, *symgofunc; dosymtype(); @@ -482,40 +360,40 @@ symtab(void) xdefine("esymtab", SRODATA, 0); // garbage collection symbols - s = lookup("gcdata", 0); + s = linklookup(ctxt, "gcdata", 0); s->type = SRODATA; s->size = 0; s->reachable = 1; xdefine("egcdata", SRODATA, 0); - s = lookup("gcbss", 0); + s = linklookup(ctxt, "gcbss", 0); s->type = SRODATA; s->size = 0; s->reachable = 1; xdefine("egcbss", SRODATA, 0); // pseudo-symbols to mark locations of type, string, and go string data. - s = lookup("type.*", 0); + s = linklookup(ctxt, "type.*", 0); s->type = STYPE; s->size = 0; s->reachable = 1; symtype = s; - s = lookup("go.string.*", 0); + s = linklookup(ctxt, "go.string.*", 0); s->type = SGOSTRING; s->size = 0; s->reachable = 1; symgostring = s; - s = lookup("go.func.*", 0); + s = linklookup(ctxt, "go.func.*", 0); s->type = SGOFUNC; s->size = 0; s->reachable = 1; symgofunc = s; - symtypelink = lookup("typelink", 0); + symtypelink = linklookup(ctxt, "typelink", 0); - symt = lookup("symtab", 0); + symt = linklookup(ctxt, "symtab", 0); symt->type = SSYMTAB; symt->size = 0; symt->reachable = 1; @@ -524,7 +402,7 @@ symtab(void) // within a type they sort by size, so the .* symbols // just defined above will be first. // hide the specific symbols. - for(s = allsym; s != S; s = s->allsym) { + for(s = ctxt->allsym; s != S; s = s->allsym) { if(!s->reachable || s->special || s->type != SRODATA) continue; if(strncmp(s->name, "type.", 5) == 0) { @@ -547,32 +425,12 @@ symtab(void) s->hide = 1; s->outer = symgofunc; } + if(strncmp(s->name, "gcargs.", 7) == 0 || strncmp(s->name, "gclocals.", 9) == 0 || strncmp(s->name, "gclocals·", 10) == 0) { + s->type = SGOFUNC; + s->hide = 1; + s->outer = symgofunc; + s->align = 4; + liveness += (s->size+s->align-1)&~(s->align-1); + } } - - if(debug['s']) - return; - - switch(thechar) { - default: - diag("unknown architecture %c", thechar); - errorexit(); - case '5': - case '6': - case '8': - // little-endian symbol table - slput = slputl; - break; - case 'v': - // big-endian symbol table - slput = slputb; - break; - } - // new symbol table header. - slput(0xfffffffd); - scput(0); - scput(0); - scput(0); - scput(PtrSize); - - genasmsym(putsymb); } diff --git a/src/cmd/ld/textflag.h b/src/cmd/ld/textflag.h index 1d62db736..2a76e76c2 100644 --- a/src/cmd/ld/textflag.h +++ b/src/cmd/ld/textflag.h @@ -19,3 +19,5 @@ #define NOPTR 16 // This is a wrapper function and should not count as disabling 'recover'. #define WRAPPER 32 +// This function uses its incoming context register. +#define NEEDCTXT 64 |