summaryrefslogtreecommitdiff
path: root/src/cmd/ld
diff options
context:
space:
mode:
authorMichael Stapelberg <stapelberg@debian.org>2014-06-19 09:22:53 +0200
committerMichael Stapelberg <stapelberg@debian.org>2014-06-19 09:22:53 +0200
commit8a39ee361feb9bf46d728ff1ba4f07ca1d9610b1 (patch)
tree4449f2036cccf162e8417cc5841a35815b3e7ac5 /src/cmd/ld
parentc8bf49ef8a92e2337b69c14b9b88396efe498600 (diff)
downloadgolang-upstream/1.3.tar.gz
Imported Upstream version 1.3upstream/1.3
Diffstat (limited to 'src/cmd/ld')
-rw-r--r--src/cmd/ld/data.c714
-rw-r--r--src/cmd/ld/decodesym.c109
-rw-r--r--src/cmd/ld/doc.go4
-rw-r--r--src/cmd/ld/dwarf.c602
-rw-r--r--src/cmd/ld/dwarf.h8
-rw-r--r--src/cmd/ld/elf.c277
-rw-r--r--src/cmd/ld/elf.h15
-rw-r--r--src/cmd/ld/go.c157
-rw-r--r--src/cmd/ld/ldelf.c64
-rw-r--r--src/cmd/ld/ldmacho.c56
-rw-r--r--src/cmd/ld/ldpe.c60
-rw-r--r--src/cmd/ld/lib.c1625
-rw-r--r--src/cmd/ld/lib.h388
-rw-r--r--src/cmd/ld/macho.c123
-rw-r--r--src/cmd/ld/pass.c104
-rw-r--r--src/cmd/ld/pcln.c244
-rw-r--r--src/cmd/ld/pe.c212
-rw-r--r--src/cmd/ld/pe.h2
-rw-r--r--src/cmd/ld/pobj.c197
-rw-r--r--src/cmd/ld/symtab.c244
-rw-r--r--src/cmd/ld/textflag.h2
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