summaryrefslogtreecommitdiff
path: root/src/cmd/ld
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/ld')
-rw-r--r--src/cmd/ld/data.c334
-rw-r--r--src/cmd/ld/dwarf.c294
-rw-r--r--src/cmd/ld/dwarf_defs.h1
-rw-r--r--src/cmd/ld/elf.c54
-rw-r--r--src/cmd/ld/elf.h2
-rw-r--r--src/cmd/ld/go.c107
-rw-r--r--src/cmd/ld/ldelf.c4
-rw-r--r--src/cmd/ld/ldmacho.c4
-rw-r--r--src/cmd/ld/ldpe.c10
-rw-r--r--src/cmd/ld/lib.c334
-rw-r--r--src/cmd/ld/lib.h47
-rw-r--r--src/cmd/ld/macho.c592
-rw-r--r--src/cmd/ld/macho.h13
-rw-r--r--src/cmd/ld/pe.c14
-rw-r--r--src/cmd/ld/symtab.c20
15 files changed, 1217 insertions, 613 deletions
diff --git a/src/cmd/ld/data.c b/src/cmd/ld/data.c
index 6c6b1be43..b70d4636c 100644
--- a/src/cmd/ld/data.c
+++ b/src/cmd/ld/data.c
@@ -33,6 +33,7 @@
#include "l.h"
#include "../ld/lib.h"
#include "../ld/elf.h"
+#include "../ld/macho.h"
#include "../ld/pe.h"
#include "../../pkg/runtime/mgc0.h"
@@ -135,11 +136,7 @@ addrel(Sym *s)
s->maxr = 4;
else
s->maxr <<= 1;
- s->r = realloc(s->r, s->maxr*sizeof s->r[0]);
- if(s->r == 0) {
- diag("out of memory");
- errorexit();
- }
+ 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++];
@@ -158,6 +155,7 @@ relocsym(Sym *s)
cursym = s;
memset(&p, 0, sizeof p);
for(r=s->r; r<s->r+s->nr; r++) {
+ r->done = 1;
off = r->off;
siz = r->siz;
if(off < 0 || off+siz > s->np) {
@@ -180,35 +178,72 @@ relocsym(Sym *s)
switch(r->type) {
default:
o = 0;
- if(isobj || archreloc(r, s, &o) < 0)
+ if(linkmode == LinkExternal || archreloc(r, s, &o) < 0)
diag("unknown reloc %d", r->type);
break;
case D_ADDR:
- o = symaddr(r->sym) + r->add;
- if(isobj && r->sym->type != SCONST) {
- if(thechar == '6')
- o = 0;
- else {
- // set up addend for eventual relocation via outer symbol
- rs = r->sym;
- while(rs->outer != nil)
- rs = rs->outer;
- o -= symaddr(rs);
+ if(linkmode == LinkExternal && r->sym->type != SCONST) {
+ r->done = 0;
+
+ // set up addend for eventual relocation via outer symbol.
+ rs = r->sym;
+ r->xadd = r->add;
+ while(rs->outer != nil) {
+ r->xadd += symaddr(rs) - symaddr(rs->outer);
+ rs = rs->outer;
+ }
+ if(rs->type != SHOSTOBJ && rs->sect == nil)
+ diag("missing section for %s", rs->name);
+ r->xsym = rs;
+
+ o = r->xadd;
+ if(iself) {
+ if(thechar == '6')
+ o = 0;
+ } else if(HEADTYPE == Hdarwin) {
+ if(rs->type != SHOSTOBJ)
+ o += symaddr(rs);
+ } else {
+ diag("unhandled pcrel relocation for %s", headtype);
}
+ break;
}
+ o = symaddr(r->sym) + r->add;
break;
case D_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) {
+ r->done = 0;
+
+ // set up addend for eventual relocation via outer symbol.
+ rs = r->sym;
+ r->xadd = r->add;
+ while(rs->outer != nil) {
+ r->xadd += symaddr(rs) - symaddr(rs->outer);
+ rs = rs->outer;
+ }
+ r->xadd -= r->siz; // relative to address after the relocated chunk
+ if(rs->type != SHOSTOBJ && rs->sect == nil)
+ diag("missing section for %s", rs->name);
+ r->xsym = rs;
+
+ o = r->xadd;
+ if(iself) {
+ if(thechar == '6')
+ o = 0;
+ } else if(HEADTYPE == Hdarwin) {
+ if(rs->type != SHOSTOBJ)
+ o += symaddr(rs) - rs->sect->vaddr;
+ o -= r->off; // WTF?
+ } else {
+ diag("unhandled pcrel relocation for %s", headtype);
+ }
+ break;
+ }
o = 0;
if(r->sym)
o += symaddr(r->sym);
o += r->add - (s->value + r->off + r->siz);
- if(isobj && r->sym->type != SCONST) {
- if(thechar == '6')
- o = 0;
- else
- o = r->add - r->siz;
- }
break;
case D_SIZE:
o = r->sym->size + r->add;
@@ -300,7 +335,7 @@ dynrelocsym(Sym *s)
for(r=s->r; r<s->r+s->nr; r++) {
if(r->sym != S && r->sym->type == SDYNIMPORT || r->type >= 256)
adddynrel(s, r);
- if(flag_shared && r->sym != S && (r->sym->dynimpname == nil || r->sym->dynexport) && r->type == D_ADDR
+ if(flag_shared && r->sym != S && s->type != SDYNIMPORT && r->type == D_ADDR
&& (s == got || s->type == SDATA || s->type == SGOSTRING || s->type == STYPE || s->type == SRODATA)) {
// Create address based RELATIVE relocation
adddynrela(rel, s, r);
@@ -342,11 +377,7 @@ symgrow(Sym *s, int32 siz)
s->maxp = 8;
while(s->maxp < siz)
s->maxp <<= 1;
- s->p = realloc(s->p, s->maxp);
- if(s->p == nil) {
- diag("out of memory");
- errorexit();
- }
+ s->p = erealloc(s->p, s->maxp);
memset(s->p+s->np, 0, s->maxp-s->np);
}
s->np = siz;
@@ -560,8 +591,10 @@ void
datblk(int32 addr, int32 size)
{
Sym *sym;
- int32 eaddr;
+ int32 i, eaddr;
uchar *p, *ep;
+ char *typ, *rsname;
+ Reloc *r;
if(debug['a'])
Bprint(&bso, "datblk [%#x,%#x) at offset %#llx\n", addr, addr+size, cpos());
@@ -581,23 +614,46 @@ datblk(int32 addr, int32 size)
if(sym->value >= eaddr)
break;
if(addr < sym->value) {
- Bprint(&bso, "%-20s %.8ux| 00 ...\n", "(pre-pad)", addr);
+ Bprint(&bso, "\t%.8ux| 00 ...\n", addr);
addr = sym->value;
}
- Bprint(&bso, "%-20s %.8ux|", sym->name, (uint)addr);
+ Bprint(&bso, "%s\n\t%.8ux|", sym->name, (uint)addr);
p = sym->p;
ep = p + sym->np;
- while(p < ep)
+ while(p < ep) {
+ if(p > sym->p && (int)(p-sym->p)%16 == 0)
+ Bprint(&bso, "\n\t%.8ux|", (uint)(addr+(p-sym->p)));
Bprint(&bso, " %.2ux", *p++);
+ }
addr += sym->np;
for(; addr < sym->value+sym->size; addr++)
Bprint(&bso, " %.2ux", 0);
Bprint(&bso, "\n");
+
+ if(linkmode == LinkExternal) {
+ for(i=0; i<sym->nr; i++) {
+ r = &sym->r[i];
+ rsname = "";
+ if(r->sym)
+ rsname = r->sym->name;
+ typ = "?";
+ switch(r->type) {
+ case D_ADDR:
+ typ = "addr";
+ break;
+ case D_PCREL:
+ typ = "pcrel";
+ break;
+ }
+ Bprint(&bso, "\treloc %.8ux/%d %s %s+%#llx [%#llx]\n",
+ (uint)(sym->value+r->off), r->siz, typ, rsname, r->add, r->sym->value+r->add);
+ }
+ }
}
if(addr < eaddr)
- Bprint(&bso, "%-20s %.8ux| 00 ...\n", "(post-pad)", (uint)addr);
- Bprint(&bso, "%-20s %.8ux|\n", "", (uint)eaddr);
+ Bprint(&bso, "\t%.8ux| 00 ...\n", (uint)addr);
+ Bprint(&bso, "\t%.8ux|\n", (uint)eaddr);
}
void
@@ -883,36 +939,41 @@ dosymtype(void)
}
static int32
-alignsymsize(int32 s)
+symalign(Sym *s)
{
- if(s >= 8)
- s = rnd(s, 8);
- else if(s >= PtrSize)
- s = rnd(s, PtrSize);
- else if(s > 2)
- s = rnd(s, 4);
- return s;
-}
+ int32 align;
+
+ if(s->align != 0)
+ return s->align;
+ align = MaxAlign;
+ while(align > s->size && align > 1)
+ align >>= 1;
+ if(align < s->align)
+ align = s->align;
+ return align;
+}
+
static int32
aligndatsize(int32 datsize, Sym *s)
{
- int32 t;
+ return rnd(datsize, symalign(s));
+}
- if(s->align != 0) {
- datsize = rnd(datsize, s->align);
- } else {
- t = alignsymsize(s->size);
- if(t & 1) {
- ;
- } else if(t & 2)
- datsize = rnd(datsize, 2);
- else if(t & 4)
- datsize = rnd(datsize, 4);
- else
- datsize = rnd(datsize, 8);
+// 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)
+{
+ int32 align, max;
+
+ max = 0;
+ for(; s != S && s->type <= type; s = s->next) {
+ align = symalign(s);
+ if(max < align)
+ max = align;
}
- return datsize;
+ return max;
}
static void
@@ -946,7 +1007,7 @@ gcaddsym(Sym *gc, Sym *s, int32 off)
void
dodata(void)
{
- int32 t, datsize;
+ int32 n, datsize;
Section *sect;
Sym *s, *last, **l;
Sym *gcdata1, *gcbss1;
@@ -956,11 +1017,11 @@ dodata(void)
Bflush(&bso);
// define garbage collection symbols
- gcdata1 = lookup("gcdata1", 0);
- gcdata1->type = SGCDATA;
+ gcdata1 = lookup("gcdata", 0);
+ gcdata1->type = STYPE;
gcdata1->reachable = 1;
- gcbss1 = lookup("gcbss1", 0);
- gcbss1->type = SGCBSS;
+ gcbss1 = lookup("gcbss", 0);
+ gcbss1->type = STYPE;
gcbss1->reachable = 1;
// size of .data and .bss section. the zero value is later replaced by the actual size of the section.
@@ -995,7 +1056,11 @@ dodata(void)
* to assign addresses, record all the necessary
* dynamic relocations. these will grow the relocation
* symbol, which is itself data.
+ *
+ * on darwin, we need the symbol table numbers for dynreloc.
*/
+ if(HEADTYPE == Hdarwin)
+ machosymorder();
dynreloc();
/* some symbols may no longer belong in datap (Mach-O) */
@@ -1034,52 +1099,54 @@ dodata(void)
datsize = 0;
for(; s != nil && s->type < SNOPTRDATA; s = s->next) {
sect = addsection(&segdata, s->name, 06);
- if(s->align != 0)
- datsize = rnd(datsize, s->align);
+ sect->align = symalign(s);
+ datsize = rnd(datsize, sect->align);
sect->vaddr = datsize;
s->sect = sect;
s->type = SDATA;
s->value = datsize;
- datsize += rnd(s->size, PtrSize);
+ datsize += s->size;
sect->len = datsize - sect->vaddr;
}
/* pointer-free data */
sect = addsection(&segdata, ".noptrdata", 06);
+ sect->align = maxalign(s, SDATARELRO-1);
+ datsize = rnd(datsize, sect->align);
sect->vaddr = datsize;
lookup("noptrdata", 0)->sect = sect;
lookup("enoptrdata", 0)->sect = sect;
for(; s != nil && s->type < SDATARELRO; s = s->next) {
+ datsize = aligndatsize(datsize, s);
s->sect = sect;
s->type = SDATA;
- t = alignsymsize(s->size);
- datsize = aligndatsize(datsize, s);
s->value = datsize;
- datsize += t;
+ datsize += s->size;
}
sect->len = datsize - sect->vaddr;
- datsize = rnd(datsize, PtrSize);
/* dynamic relocated rodata */
if(flag_shared) {
sect = addsection(&segdata, ".data.rel.ro", 06);
+ sect->align = maxalign(s, SDATARELRO);
+ datsize = rnd(datsize, sect->align);
sect->vaddr = datsize;
lookup("datarelro", 0)->sect = sect;
lookup("edatarelro", 0)->sect = sect;
for(; s != nil && s->type == SDATARELRO; s = s->next) {
- if(s->align != 0)
- datsize = rnd(datsize, s->align);
+ datsize = aligndatsize(datsize, s);
s->sect = sect;
s->type = SDATA;
s->value = datsize;
- datsize += rnd(s->size, PtrSize);
+ datsize += s->size;
}
sect->len = datsize - sect->vaddr;
- datsize = rnd(datsize, PtrSize);
}
/* data */
sect = addsection(&segdata, ".data", 06);
+ sect->align = maxalign(s, SBSS-1);
+ datsize = rnd(datsize, sect->align);
sect->vaddr = datsize;
lookup("data", 0)->sect = sect;
lookup("edata", 0)->sect = sect;
@@ -1090,39 +1157,39 @@ dodata(void)
}
s->sect = sect;
s->type = SDATA;
- t = alignsymsize(s->size);
datsize = aligndatsize(datsize, s);
s->value = datsize;
gcaddsym(gcdata1, s, datsize - sect->vaddr); // gc
- datsize += t;
+ datsize += s->size;
}
sect->len = datsize - sect->vaddr;
- datsize = rnd(datsize, PtrSize);
adduintxx(gcdata1, GC_END, PtrSize);
setuintxx(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;
for(; s != nil && s->type < SNOPTRBSS; s = s->next) {
s->sect = sect;
- t = alignsymsize(s->size);
datsize = aligndatsize(datsize, s);
s->value = datsize;
gcaddsym(gcbss1, s, datsize - sect->vaddr); // gc
- datsize += t;
+ datsize += s->size;
}
sect->len = datsize - sect->vaddr;
- datsize = rnd(datsize, PtrSize);
adduintxx(gcbss1, GC_END, PtrSize);
setuintxx(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;
@@ -1131,117 +1198,101 @@ dodata(void)
cursym = s;
diag("unexpected symbol type %d", s->type);
}
- s->sect = sect;
- t = alignsymsize(s->size);
datsize = aligndatsize(datsize, s);
+ s->sect = sect;
s->value = datsize;
- datsize += t;
+ datsize += s->size;
}
sect->len = datsize - sect->vaddr;
lookup("end", 0)->sect = sect;
/* we finished segdata, begin segtext */
+ s = datap;
+ datsize = 0;
/* read-only data */
sect = addsection(&segtext, ".rodata", 04);
+ sect->align = maxalign(s, STYPELINK-1);
sect->vaddr = 0;
lookup("rodata", 0)->sect = sect;
lookup("erodata", 0)->sect = sect;
datsize = 0;
- s = datap;
for(; s != nil && s->type < STYPELINK; s = s->next) {
+ datsize = aligndatsize(datsize, s);
s->sect = sect;
- if(s->align != 0)
- datsize = rnd(datsize, s->align);
s->type = SRODATA;
s->value = datsize;
- datsize += rnd(s->size, PtrSize);
+ datsize += s->size;
}
sect->len = datsize - sect->vaddr;
- datsize = rnd(datsize, PtrSize);
- /* type */
+ /* typelink */
sect = addsection(&segtext, ".typelink", 04);
+ sect->align = maxalign(s, STYPELINK);
+ datsize = rnd(datsize, sect->align);
sect->vaddr = datsize;
lookup("typelink", 0)->sect = sect;
lookup("etypelink", 0)->sect = sect;
for(; s != nil && s->type == STYPELINK; s = s->next) {
+ datsize = aligndatsize(datsize, s);
s->sect = sect;
s->type = SRODATA;
s->value = datsize;
datsize += s->size;
}
sect->len = datsize - sect->vaddr;
- datsize = rnd(datsize, PtrSize);
-
- /* gcdata */
- sect = addsection(&segtext, ".gcdata", 04);
- sect->vaddr = datsize;
- lookup("gcdata", 0)->sect = sect;
- lookup("egcdata", 0)->sect = sect;
- for(; s != nil && s->type == SGCDATA; s = s->next) {
- s->sect = sect;
- s->type = SRODATA;
- s->value = datsize;
- datsize += s->size;
- }
- sect->len = datsize - sect->vaddr;
- datsize = rnd(datsize, PtrSize);
-
- /* gcbss */
- sect = addsection(&segtext, ".gcbss", 04);
- sect->vaddr = datsize;
- lookup("gcbss", 0)->sect = sect;
- lookup("egcbss", 0)->sect = sect;
- for(; s != nil && s->type == SGCBSS; s = s->next) {
- s->sect = sect;
- s->type = SRODATA;
- s->value = datsize;
- datsize += s->size;
- }
- sect->len = datsize - sect->vaddr;
- datsize = rnd(datsize, PtrSize);
/* gosymtab */
sect = addsection(&segtext, ".gosymtab", 04);
+ sect->align = maxalign(s, SPCLNTAB-1);
+ datsize = rnd(datsize, sect->align);
sect->vaddr = datsize;
lookup("symtab", 0)->sect = sect;
lookup("esymtab", 0)->sect = sect;
for(; s != nil && s->type < SPCLNTAB; s = s->next) {
+ datsize = aligndatsize(datsize, s);
s->sect = sect;
s->type = SRODATA;
s->value = datsize;
datsize += s->size;
}
sect->len = datsize - sect->vaddr;
- datsize = rnd(datsize, PtrSize);
/* gopclntab */
sect = addsection(&segtext, ".gopclntab", 04);
+ sect->align = maxalign(s, SELFROSECT-1);
+ datsize = rnd(datsize, sect->align);
sect->vaddr = datsize;
lookup("pclntab", 0)->sect = sect;
lookup("epclntab", 0)->sect = sect;
for(; s != nil && s->type < SELFROSECT; s = s->next) {
+ datsize = aligndatsize(datsize, s);
s->sect = sect;
s->type = SRODATA;
s->value = datsize;
datsize += s->size;
}
sect->len = datsize - sect->vaddr;
- datsize = rnd(datsize, PtrSize);
- /* read-only ELF sections */
+ /* read-only ELF, Mach-O sections */
for(; s != nil && s->type < SELFSECT; s = s->next) {
sect = addsection(&segtext, s->name, 04);
- if(s->align != 0)
- datsize = rnd(datsize, s->align);
+ sect->align = symalign(s);
+ datsize = rnd(datsize, sect->align);
sect->vaddr = datsize;
s->sect = sect;
s->type = SRODATA;
s->value = datsize;
- datsize += rnd(s->size, PtrSize);
+ datsize += s->size;
sect->len = datsize - sect->vaddr;
}
+
+ /* number the sections */
+ n = 1;
+ for(sect = segtext.sect; sect != nil; sect = sect->next)
+ sect->extnum = n++;
+ for(sect = segdata.sect; sect != nil; sect = sect->next)
+ sect->extnum = n++;
}
// assign addresses to text
@@ -1259,6 +1310,7 @@ 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;
va = INITTEXT;
@@ -1282,11 +1334,6 @@ textaddress(void)
}
va += sym->size;
}
-
- // Align end of code so that rodata starts aligned.
- // 128 bytes is likely overkill but definitely cheap.
- va = rnd(va, 128);
-
sect->len = va - sect->vaddr;
}
@@ -1295,17 +1342,19 @@ void
address(void)
{
Section *s, *text, *data, *rodata, *symtab, *pclntab, *noptr, *bss, *noptrbss, *datarelro;
- Section *gcdata, *gcbss, *typelink;
+ Section *typelink;
Sym *sym, *sub;
uvlong va;
+ vlong vlen;
va = INITTEXT;
segtext.rwx = 05;
segtext.vaddr = va;
segtext.fileoff = HEADR;
for(s=segtext.sect; s != nil; s=s->next) {
+ va = rnd(va, s->align);
s->vaddr = va;
- va += rnd(s->len, PtrSize);
+ va += s->len;
}
segtext.len = va - INITTEXT;
segtext.filelen = segtext.len;
@@ -1326,9 +1375,11 @@ address(void)
noptrbss = nil;
datarelro = nil;
for(s=segdata.sect; s != nil; s=s->next) {
+ vlen = s->len;
+ if(s->next)
+ vlen = s->next->vaddr - s->vaddr;
s->vaddr = va;
- va += s->len;
- segdata.filelen += s->len;
+ va += vlen;
segdata.len = va - segdata.vaddr;
if(strcmp(s->name, ".data") == 0)
data = s;
@@ -1341,14 +1392,12 @@ address(void)
if(strcmp(s->name, ".data.rel.ro") == 0)
datarelro = s;
}
- segdata.filelen -= bss->len + noptrbss->len; // deduct .bss
+ segdata.filelen = bss->vaddr - segdata.vaddr;
text = segtext.sect;
rodata = text->next;
typelink = rodata->next;
- gcdata = typelink->next;
- gcbss = gcdata->next;
- symtab = gcbss->next;
+ symtab = typelink->next;
pclntab = symtab->next;
for(sym = datap; sym != nil; sym = sym->next) {
@@ -1371,10 +1420,15 @@ address(void)
xdefine("datarelro", SRODATA, datarelro->vaddr);
xdefine("edatarelro", SRODATA, datarelro->vaddr + datarelro->len);
}
- xdefine("gcdata", SGCDATA, gcdata->vaddr);
- xdefine("egcdata", SGCDATA, gcdata->vaddr + gcdata->len);
- xdefine("gcbss", SGCBSS, gcbss->vaddr);
- xdefine("egcbss", SGCBSS, gcbss->vaddr + gcbss->len);
+
+ sym = lookup("gcdata", 0);
+ xdefine("egcdata", STYPE, symaddr(sym) + sym->size);
+ lookup("egcdata", 0)->sect = sym->sect;
+
+ sym = lookup("gcbss", 0);
+ xdefine("egcbss", STYPE, symaddr(sym) + sym->size);
+ lookup("egcbss", 0)->sect = sym->sect;
+
xdefine("symtab", SRODATA, symtab->vaddr);
xdefine("esymtab", SRODATA, symtab->vaddr + symtab->len);
xdefine("pclntab", SRODATA, pclntab->vaddr);
diff --git a/src/cmd/ld/dwarf.c b/src/cmd/ld/dwarf.c
index d6a357e49..4bf788e64 100644
--- a/src/cmd/ld/dwarf.c
+++ b/src/cmd/ld/dwarf.c
@@ -41,9 +41,13 @@ static vlong arangeso;
static vlong arangessize;
static vlong gdbscripto;
static vlong gdbscriptsize;
+static vlong inforeloco;
+static vlong inforelocsize;
static char gdbscript[1024];
+static Sym *dsym;
+
/*
* Basic I/O
*/
@@ -150,6 +154,7 @@ enum
DW_ABRV_IFACETYPE,
DW_ABRV_MAPTYPE,
DW_ABRV_PTRTYPE,
+ DW_ABRV_BARE_PTRTYPE, // only for void*, no DW_AT_type attr to please gdb 6.
DW_ABRV_SLICETYPE,
DW_ABRV_STRINGTYPE,
DW_ABRV_STRUCTTYPE,
@@ -303,6 +308,12 @@ static struct DWAbbrev {
DW_AT_type, DW_FORM_ref_addr,
0, 0
},
+ /* BARE_PTRTYPE */
+ {
+ DW_TAG_pointer_type, DW_CHILDREN_no,
+ DW_AT_name, DW_FORM_string,
+ 0, 0
+ },
/* SLICETYPE */
{
@@ -485,26 +496,43 @@ mkindex(DWDie *die)
die->hash = mal(HASHSIZE * sizeof(DWDie*));
}
+static DWDie*
+walktypedef(DWDie *die)
+{
+ DWAttr *attr;
+
+ // Resolve typedef if present.
+ if (die->abbrev == DW_ABRV_TYPEDECL) {
+ for (attr = die->attr; attr; attr = attr->link) {
+ if (attr->atr == DW_AT_type && attr->cls == DW_CLS_REFERENCE && attr->data != nil) {
+ return (DWDie*)attr->data;
+ }
+ }
+ }
+ return die;
+}
+
// Find child by AT_name using hashtable if available or linear scan
// if not.
static DWDie*
find(DWDie *die, char* name)
{
- DWDie *a, *b;
+ DWDie *a, *b, *die2;
int h;
+top:
if (die->hash == nil) {
for (a = die->child; a != nil; a = a->link)
if (strcmp(name, getattr(a, DW_AT_name)->data) == 0)
return a;
- return nil;
+ goto notfound;
}
h = hashstr(name);
a = die->hash[h];
if (a == nil)
- return nil;
+ goto notfound;
if (strcmp(name, getattr(a, DW_AT_name)->data) == 0)
@@ -522,6 +550,14 @@ find(DWDie *die, char* name)
a = b;
b = b->hlink;
}
+
+notfound:
+ die2 = walktypedef(die);
+ if(die2 != die) {
+ die = die2;
+ goto top;
+ }
+
return nil;
}
@@ -531,7 +567,7 @@ find_or_diag(DWDie *die, char* name)
DWDie *r;
r = find(die, name);
if (r == nil) {
- diag("dwarf find: %s has no %s", getattr(die, DW_AT_name)->data, name);
+ diag("dwarf find: %s %p has no %s", getattr(die, DW_AT_name)->data, die, name);
errorexit();
}
return r;
@@ -548,14 +584,33 @@ newrefattr(DWDie *die, uint8 attr, DWDie* ref)
static int fwdcount;
static void
-putattr(int form, int cls, vlong value, char *data)
+putattr(int abbrev, int form, int cls, vlong value, char *data)
{
+ Reloc *r;
+
switch(form) {
case DW_FORM_addr: // address
addrput(value);
break;
case DW_FORM_block1: // block
+ if(cls == DW_CLS_ADDRESS) {
+ cput(1+PtrSize);
+ cput(DW_OP_addr);
+ if(linkmode == LinkExternal) {
+ r = addrel(dsym);
+ r->sym = (Sym*)data;
+ r->xsym = r->sym;
+ r->off = cpos() - infoo;
+ r->siz = PtrSize;
+ r->type = D_ADDR;
+ r->add = value - r->sym->value;
+ r->xadd = r->add;
+ value = r->add;
+ }
+ addrput(value);
+ break;
+ }
value &= 0xff;
cput(value);
while(value--)
@@ -615,13 +670,23 @@ putattr(int form, int cls, vlong value, char *data)
break;
case DW_FORM_ref_addr: // reference to a DIE in the .info section
+ // In DWARF 2 (which is what we claim to generate),
+ // the ref_addr is the same size as a normal address.
+ // In DWARF 3 it is always 32 bits, unless emitting a large
+ // (> 4 GB of debug info aka "64-bit") unit, which we don't implement.
if (data == nil) {
- diag("dwarf: null reference");
- LPUT(0); // invalid dwarf, gdb will complain.
+ diag("dwarf: null reference in %d", abbrev);
+ if(PtrSize == 8)
+ VPUT(0); // invalid dwarf, gdb will complain.
+ else
+ LPUT(0); // invalid dwarf, gdb will complain.
} else {
if (((DWDie*)data)->offs == 0)
fwdcount++;
- LPUT(((DWDie*)data)->offs);
+ if(PtrSize == 8)
+ VPUT(((DWDie*)data)->offs);
+ else
+ LPUT(((DWDie*)data)->offs);
}
break;
@@ -654,12 +719,12 @@ putattrs(int abbrev, DWAttr* attr)
for(af = abbrevs[abbrev].attr; af->attr; af++)
if (attrs[af->attr])
- putattr(af->form,
+ putattr(abbrev, af->form,
attrs[af->attr]->cls,
attrs[af->attr]->value,
attrs[af->attr]->data);
else
- putattr(af->form, 0, 0, 0);
+ putattr(abbrev, af->form, 0, 0, nil);
}
static void putdie(DWDie* die);
@@ -729,16 +794,9 @@ 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)
+newabslocexprattr(DWDie *die, vlong addr, Sym *sym)
{
- char block[10];
- int i;
-
- i = 0;
- block[i++] = DW_OP_constu;
- i += uleb128enc(addr, block+i);
- newattr(die, DW_AT_location, DW_CLS_BLOCK, i, mal(i));
- memmove(die->attr->data, block, i);
+ newattr(die, DW_AT_location, DW_CLS_ADDRESS, addr, (char*)sym);
}
@@ -766,6 +824,31 @@ lookup_or_diag(char *n)
return s;
}
+static void
+dotypedef(DWDie *parent, char *name, DWDie *def)
+{
+ DWDie *die;
+
+ // Only emit typedefs for real names.
+ if(strncmp(name, "map[", 4) == 0)
+ return;
+ if(strncmp(name, "struct {", 8) == 0)
+ return;
+ if(strncmp(name, "chan ", 5) == 0)
+ return;
+ if(*name == '[' || *name == '*')
+ return;
+ if(def == nil)
+ diag("dwarf: bad def in dotypedef");
+
+ // The typedef entry must be created after the def,
+ // so that future lookups will find the typedef instead
+ // of the real definition. This hooks the typedef into any
+ // circular definition loops, so that gdb can understand them.
+ die = newdie(parent, DW_ABRV_TYPEDECL, name);
+ newrefattr(die, DW_AT_type, def);
+}
+
// Define gotype, for composite ones recurse into constituents.
static DWDie*
defgotype(Sym *gotype)
@@ -840,6 +923,7 @@ defgotype(Sym *gotype)
case KindArray:
die = newdie(&dwtypes, DW_ABRV_ARRAYTYPE, name);
+ dotypedef(&dwtypes, name, die);
newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0);
s = decodetype_arrayelem(gotype);
newrefattr(die, DW_AT_type, defgotype(s));
@@ -857,6 +941,7 @@ defgotype(Sym *gotype)
case KindFunc:
die = newdie(&dwtypes, DW_ABRV_FUNCTYPE, name);
+ dotypedef(&dwtypes, name, die);
newrefattr(die, DW_AT_type, find_or_diag(&dwtypes, "void"));
nfields = decodetype_funcincount(gotype);
for (i = 0; i < nfields; i++) {
@@ -876,6 +961,7 @@ defgotype(Sym *gotype)
case KindInterface:
die = newdie(&dwtypes, DW_ABRV_IFACETYPE, name);
+ dotypedef(&dwtypes, name, die);
newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0);
nfields = decodetype_ifacemethodcount(gotype);
if (nfields == 0)
@@ -895,12 +981,14 @@ defgotype(Sym *gotype)
case KindPtr:
die = newdie(&dwtypes, DW_ABRV_PTRTYPE, name);
+ dotypedef(&dwtypes, name, die);
s = decodetype_ptrelem(gotype);
newrefattr(die, DW_AT_type, defgotype(s));
break;
case KindSlice:
die = newdie(&dwtypes, DW_ABRV_SLICETYPE, name);
+ dotypedef(&dwtypes, name, die);
newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0);
s = decodetype_arrayelem(gotype);
newrefattr(die, DW_AT_internal_elem_type, defgotype(s));
@@ -913,6 +1001,7 @@ defgotype(Sym *gotype)
case KindStruct:
die = newdie(&dwtypes, DW_ABRV_STRUCTTYPE, name);
+ dotypedef(&dwtypes, name, die);
newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0);
nfields = decodetype_structfieldcount(gotype);
for (i = 0; i < nfields; i++) {
@@ -927,8 +1016,7 @@ defgotype(Sym *gotype)
break;
case KindUnsafePointer:
- die = newdie(&dwtypes, DW_ABRV_PTRTYPE, name);
- newrefattr(die, DW_AT_type, find(&dwtypes, "void"));
+ die = newdie(&dwtypes, DW_ABRV_BARE_PTRTYPE, name);
break;
default:
@@ -998,7 +1086,7 @@ synthesizestringtypes(DWDie* die)
{
DWDie *prototype;
- prototype = defgotype(lookup_or_diag("type.runtime._string"));
+ prototype = walktypedef(defgotype(lookup_or_diag("type.runtime._string")));
if (prototype == nil)
return;
@@ -1014,7 +1102,7 @@ synthesizeslicetypes(DWDie *die)
{
DWDie *prototype, *elem;
- prototype = defgotype(lookup_or_diag("type.runtime.slice"));
+ prototype = walktypedef(defgotype(lookup_or_diag("type.runtime.slice")));
if (prototype == nil)
return;
@@ -1043,33 +1131,17 @@ mkinternaltypename(char *base, char *arg1, char *arg2)
}
-// synthesizemaptypes is way too closely married to runtime/hashmap.c
-enum {
- MaxValsize = 256 - 64
-};
-
static void
synthesizemaptypes(DWDie *die)
{
- DWDie *hash, *hash_subtable, *hash_entry,
- *dwh, *dwhs, *dwhe, *dwhash, *keytype, *valtype, *fld;
- int hashsize, keysize, valsize, datsize, valsize_in_hash, datavo;
- DWAttr *a;
+ DWDie *hash, *dwh, *keytype, *valtype;
hash = defgotype(lookup_or_diag("type.runtime.hmap"));
- hash_subtable = defgotype(lookup_or_diag("type.runtime.hash_subtable"));
- hash_entry = defgotype(lookup_or_diag("type.runtime.hash_entry"));
- if (hash == nil || hash_subtable == nil || hash_entry == nil)
+ if (hash == nil)
return;
- dwhash = (DWDie*)getattr(find_or_diag(hash_entry, "hash"), DW_AT_type)->data;
- if (dwhash == nil)
- return;
-
- hashsize = getattr(dwhash, DW_AT_byte_size)->value;
-
for (; die != nil; die = die->link) {
if (die->abbrev != DW_ABRV_MAPTYPE)
continue;
@@ -1077,63 +1149,12 @@ synthesizemaptypes(DWDie *die)
keytype = (DWDie*) getattr(die, DW_AT_internal_key_type)->data;
valtype = (DWDie*) getattr(die, DW_AT_internal_val_type)->data;
- a = getattr(keytype, DW_AT_byte_size);
- keysize = a ? a->value : PtrSize; // We don't store size with Pointers
-
- a = getattr(valtype, DW_AT_byte_size);
- valsize = a ? a->value : PtrSize;
-
- // This is what happens in hash_init and makemap_c
- valsize_in_hash = valsize;
- if (valsize > MaxValsize)
- valsize_in_hash = PtrSize;
- datavo = keysize;
- if (valsize_in_hash >= PtrSize)
- datavo = rnd(keysize, PtrSize);
- datsize = datavo + valsize_in_hash;
- if (datsize < PtrSize)
- datsize = PtrSize;
- datsize = rnd(datsize, PtrSize);
-
- // Construct struct hash_entry<K,V>
- dwhe = newdie(&dwtypes, DW_ABRV_STRUCTTYPE,
- mkinternaltypename("hash_entry",
- getattr(keytype, DW_AT_name)->data,
- getattr(valtype, DW_AT_name)->data));
-
- fld = newdie(dwhe, DW_ABRV_STRUCTFIELD, "hash");
- newrefattr(fld, DW_AT_type, dwhash);
- newmemberoffsetattr(fld, 0);
-
- fld = newdie(dwhe, DW_ABRV_STRUCTFIELD, "key");
- newrefattr(fld, DW_AT_type, keytype);
- newmemberoffsetattr(fld, hashsize);
-
- fld = newdie(dwhe, DW_ABRV_STRUCTFIELD, "val");
- if (valsize > MaxValsize)
- valtype = defptrto(valtype);
- newrefattr(fld, DW_AT_type, valtype);
- newmemberoffsetattr(fld, hashsize + datavo);
- newattr(dwhe, DW_AT_byte_size, DW_CLS_CONSTANT, hashsize + datsize, nil);
-
- // Construct hash_subtable<hash_entry<K,V>>
- dwhs = newdie(&dwtypes, DW_ABRV_STRUCTTYPE,
- mkinternaltypename("hash_subtable",
- getattr(keytype, DW_AT_name)->data,
- getattr(valtype, DW_AT_name)->data));
- copychildren(dwhs, hash_subtable);
- substitutetype(dwhs, "last", defptrto(dwhe));
- substitutetype(dwhs, "entry", dwhe); // todo: []hash_entry with dynamic size
- newattr(dwhs, DW_AT_byte_size, DW_CLS_CONSTANT,
- getattr(hash_subtable, DW_AT_byte_size)->value, nil);
-
// Construct hash<K,V>
dwh = newdie(&dwtypes, DW_ABRV_STRUCTTYPE,
mkinternaltypename("hash",
getattr(keytype, DW_AT_name)->data,
getattr(valtype, DW_AT_name)->data));
copychildren(dwh, hash);
- substitutetype(dwh, "st", defptrto(dwhs));
newattr(dwh, DW_AT_byte_size, DW_CLS_CONSTANT,
getattr(hash, DW_AT_byte_size)->value, nil);
@@ -1149,9 +1170,9 @@ synthesizechantypes(DWDie *die)
DWAttr *a;
int elemsize, sudogsize;
- sudog = defgotype(lookup_or_diag("type.runtime.sudog"));
- waitq = defgotype(lookup_or_diag("type.runtime.waitq"));
- hchan = defgotype(lookup_or_diag("type.runtime.hchan"));
+ sudog = walktypedef(defgotype(lookup_or_diag("type.runtime.sudog")));
+ waitq = walktypedef(defgotype(lookup_or_diag("type.runtime.waitq")));
+ hchan = walktypedef(defgotype(lookup_or_diag("type.runtime.hchan")));
if (sudog == nil || waitq == nil || hchan == nil)
return;
@@ -1220,7 +1241,7 @@ defdwsymb(Sym* sym, char *s, int t, vlong v, vlong size, int ver, Sym *gotype)
case 'D':
case 'B':
dv = newdie(&dwglobals, DW_ABRV_VARIABLE, s);
- newabslocexprattr(dv, v);
+ newabslocexprattr(dv, v, sym);
if (ver == 0)
newattr(dv, DW_AT_external, DW_CLS_FLAG, 1, 0);
// fallthrough
@@ -1260,7 +1281,7 @@ dwarfaddfrag(int n, char *frag)
if (n >= ftabsize) {
s = ftabsize;
ftabsize = 1 + n + (n >> 2);
- ftab = realloc(ftab, ftabsize * sizeof(ftab[0]));
+ ftab = erealloc(ftab, ftabsize * sizeof(ftab[0]));
memset(ftab + s, 0, (ftabsize - s) * sizeof(ftab[0]));
}
@@ -1342,7 +1363,7 @@ addhistfile(char *zentry)
if (histfilesize == histfilecap) {
histfilecap = 2 * histfilecap + 2;
- histfile = realloc(histfile, histfilecap * sizeof(char*));
+ histfile = erealloc(histfile, histfilecap * sizeof(char*));
}
if (histfilesize == 0)
histfile[histfilesize++] = "<eof>";
@@ -1412,7 +1433,7 @@ checknesting(void)
includestacksize += 1;
includestacksize <<= 2;
// print("checknesting: growing to %d\n", includestacksize);
- includestack = realloc(includestack, includestacksize * sizeof *includestack);
+ includestack = erealloc(includestack, includestacksize * sizeof *includestack);
}
}
@@ -1581,12 +1602,12 @@ mkvarname(char* name, int da)
// flush previous compilation unit.
static void
-flushunit(DWDie *dwinfo, vlong pc, vlong unitstart, int32 header_length)
+flushunit(DWDie *dwinfo, vlong pc, Sym *pcsym, vlong unitstart, int32 header_length)
{
vlong here;
if (dwinfo != nil && pc != 0) {
- newattr(dwinfo, DW_AT_high_pc, DW_CLS_ADDRESS, pc+1, 0);
+ newattr(dwinfo, DW_AT_high_pc, DW_CLS_ADDRESS, pc+1, (char*)pcsym);
}
if (unitstart >= 0) {
@@ -1597,7 +1618,7 @@ flushunit(DWDie *dwinfo, vlong pc, vlong unitstart, int32 header_length)
here = cpos();
cseek(unitstart);
LPUT(here - unitstart - sizeof(int32)); // unit_length
- WPUT(3); // dwarf version
+ WPUT(2); // dwarf version
LPUT(header_length); // header length starting here
cseek(here);
}
@@ -1607,7 +1628,7 @@ static void
writelines(void)
{
Prog *q;
- Sym *s;
+ Sym *s, *epcs;
Auto *a;
vlong unitstart, headerend, offs;
vlong pc, epc, lc, llc, lline;
@@ -1622,6 +1643,7 @@ writelines(void)
headerend = -1;
pc = 0;
epc = 0;
+ epcs = S;
lc = 1;
llc = 1;
currfile = -1;
@@ -1637,7 +1659,7 @@ writelines(void)
// we're entering a new compilation unit
if (inithist(s->autom)) {
- flushunit(dwinfo, epc, unitstart, headerend - unitstart - 10);
+ flushunit(dwinfo, epc, epcs, unitstart, headerend - unitstart - 10);
unitstart = cpos();
if(debug['v'] > 1) {
@@ -1651,15 +1673,15 @@ writelines(void)
lang = guesslang(histfile[1]);
finddebugruntimepath();
- dwinfo = newdie(&dwroot, DW_ABRV_COMPUNIT, strdup(histfile[1]));
+ 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, 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(3); // dwarf version (appendix F)
+ WPUT(2); // dwarf version (appendix F)
LPUT(0); // header_length (*), filled in by flushunit.
// cpos == unitstart + 4 + 2 + 4
cput(1); // minimum_instruction_length
@@ -1683,6 +1705,7 @@ writelines(void)
pc = s->text->pc;
epc = pc;
+ epcs = s;
currfile = 1;
lc = 1;
llc = 1;
@@ -1701,9 +1724,9 @@ writelines(void)
}
dwfunc = newdie(dwinfo, DW_ABRV_FUNCTION, s->name);
- newattr(dwfunc, DW_AT_low_pc, DW_CLS_ADDRESS, s->value, 0);
+ newattr(dwfunc, DW_AT_low_pc, DW_CLS_ADDRESS, s->value, (char*)s);
epc = s->value + s->size;
- newattr(dwfunc, DW_AT_high_pc, DW_CLS_ADDRESS, epc, 0);
+ 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);
@@ -1785,7 +1808,7 @@ writelines(void)
dwfunc->hash = nil;
}
- flushunit(dwinfo, epc, unitstart, headerend - unitstart - 10);
+ flushunit(dwinfo, epc, epcs, unitstart, headerend - unitstart - 10);
linesize = cpos() - lineo;
}
@@ -1909,6 +1932,9 @@ writeinfo(void)
vlong unitstart, here;
fwdcount = 0;
+ if (dsym == S)
+ dsym = lookup(".dwarfinfo", 0);
+ dsym->nr = 0;
for (compunit = dwroot.child; compunit; compunit = compunit->link) {
unitstart = cpos();
@@ -1917,7 +1943,7 @@ writeinfo(void)
// Fields marked with (*) must be changed for 64-bit dwarf
// This must match COMPUNITHEADERSIZE above.
LPUT(0); // unit_length (*), will be filled in later.
- WPUT(3); // dwarf version (appendix F)
+ WPUT(2); // dwarf version (appendix F)
LPUT(0); // debug_abbrev_offset (*)
cput(PtrSize); // address_size
@@ -2057,6 +2083,27 @@ align(vlong size)
strnput("", rnd(size, PEFILEALIGN) - size);
}
+static vlong
+writeinforeloc(void)
+{
+ int i;
+ vlong start;
+ Reloc *r;
+
+ start = cpos();
+ for(r = dsym->r; r < dsym->r+dsym->nr; r++) {
+ if(iself)
+ i = elfreloc1(r, r->off);
+ else if(HEADTYPE == Hdarwin)
+ i = machoreloc1(r, r->off);
+ else
+ i = -1;
+ if(i < 0)
+ diag("unsupported obj reloc %d/%d to %s", r->type, r->siz, r->sym->name);
+ }
+ return start;
+}
+
/*
* This is the main entry point for generating dwarf. After emitting
* the mandatory debug_abbrev section, it calls writelines() to set up
@@ -2085,8 +2132,7 @@ dwarfemitdebugsections(void)
// Some types that must exist to define other ones.
newdie(&dwtypes, DW_ABRV_NULLTYPE, "<unspecified>");
newdie(&dwtypes, DW_ABRV_NULLTYPE, "void");
- newrefattr(newdie(&dwtypes, DW_ABRV_PTRTYPE, "unsafe.Pointer"),
- DW_AT_type, find(&dwtypes, "void"));
+ newdie(&dwtypes, DW_ABRV_BARE_PTRTYPE, "unsafe.Pointer");
die = newdie(&dwtypes, DW_ABRV_BASETYPE, "uintptr"); // needed for array size
newattr(die, DW_AT_encoding, DW_CLS_CONSTANT, DW_ATE_unsigned, 0);
newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, PtrSize, 0);
@@ -2157,6 +2203,10 @@ dwarfemitdebugsections(void)
gdbscripto = writegdbscript();
gdbscriptsize = cpos() - gdbscripto;
align(gdbscriptsize);
+
+ inforeloco = writeinforeloc();
+ inforelocsize = cpos() - inforeloco;
+ align(inforelocsize);
}
/*
@@ -2298,42 +2348,44 @@ dwarfaddmachoheaders(void)
ms->fileoffset = fakestart;
ms->filesize = abbrevo-fakestart;
- msect = newMachoSect(ms, "__debug_abbrev");
+ msect = newMachoSect(ms, "__debug_abbrev", "__DWARF");
msect->off = abbrevo;
msect->size = abbrevsize;
ms->filesize += msect->size;
- msect = newMachoSect(ms, "__debug_line");
+ msect = newMachoSect(ms, "__debug_line", "__DWARF");
msect->off = lineo;
msect->size = linesize;
ms->filesize += msect->size;
- msect = newMachoSect(ms, "__debug_frame");
+ msect = newMachoSect(ms, "__debug_frame", "__DWARF");
msect->off = frameo;
msect->size = framesize;
ms->filesize += msect->size;
- msect = newMachoSect(ms, "__debug_info");
+ msect = newMachoSect(ms, "__debug_info", "__DWARF");
msect->off = infoo;
msect->size = infosize;
+ msect->reloc = inforeloco;
+ msect->nreloc = inforelocsize / 8;
ms->filesize += msect->size;
if (pubnamessize > 0) {
- msect = newMachoSect(ms, "__debug_pubnames");
+ msect = newMachoSect(ms, "__debug_pubnames", "__DWARF");
msect->off = pubnameso;
msect->size = pubnamessize;
ms->filesize += msect->size;
}
if (pubtypessize > 0) {
- msect = newMachoSect(ms, "__debug_pubtypes");
+ msect = newMachoSect(ms, "__debug_pubtypes", "__DWARF");
msect->off = pubtypeso;
msect->size = pubtypessize;
ms->filesize += msect->size;
}
if (arangessize > 0) {
- msect = newMachoSect(ms, "__debug_aranges");
+ msect = newMachoSect(ms, "__debug_aranges", "__DWARF");
msect->off = arangeso;
msect->size = arangessize;
ms->filesize += msect->size;
@@ -2341,7 +2393,7 @@ dwarfaddmachoheaders(void)
// TODO(lvd) fix gdb/python to load MachO (16 char section name limit)
if (gdbscriptsize > 0) {
- msect = newMachoSect(ms, "__debug_gdb_scripts");
+ msect = newMachoSect(ms, "__debug_gdb_scripts", "__DWARF");
msect->off = gdbscripto;
msect->size = gdbscriptsize;
ms->filesize += msect->size;
diff --git a/src/cmd/ld/dwarf_defs.h b/src/cmd/ld/dwarf_defs.h
index eed143dff..93e99ff74 100644
--- a/src/cmd/ld/dwarf_defs.h
+++ b/src/cmd/ld/dwarf_defs.h
@@ -93,6 +93,7 @@ enum
DW_CLS_FLAG,
DW_CLS_PTR, // lineptr, loclistptr, macptr, rangelistptr
DW_CLS_REFERENCE,
+ DW_CLS_ADDRLOC,
DW_CLS_STRING
};
diff --git a/src/cmd/ld/elf.c b/src/cmd/ld/elf.c
index 630906653..f5cce9c52 100644
--- a/src/cmd/ld/elf.c
+++ b/src/cmd/ld/elf.c
@@ -605,9 +605,7 @@ elfdynhash(void)
if(sy->dynimpvers)
need[sy->dynid] = addelflib(&needlib, sy->dynimplib, sy->dynimpvers);
- name = sy->dynimpname;
- if(name == nil)
- name = sy->name;
+ name = sy->extname;
hc = elfhash((uchar*)name);
b = hc % nbucket;
@@ -760,9 +758,9 @@ elfshbits(Section *sect)
sh->flags |= SHF_EXECINSTR;
if(sect->rwx & 2)
sh->flags |= SHF_WRITE;
- if(!isobj)
+ if(linkmode != LinkExternal)
sh->addr = sect->vaddr;
- sh->addralign = PtrSize;
+ sh->addralign = sect->align;
sh->size = sect->len;
sh->off = sect->seg->fileoff + sect->vaddr - sect->seg->vaddr;
@@ -807,10 +805,9 @@ elfshreloc(Section *sect)
void
elfrelocsect(Section *sect, Sym *first)
{
- Sym *sym, *rs;
+ Sym *sym;
int32 eaddr;
Reloc *r;
- int64 add;
// If main section is SHT_NOBITS, nothing to relocate.
// Also nothing to relocate in .shstrtab.
@@ -836,28 +833,15 @@ elfrelocsect(Section *sect, Sym *first)
cursym = sym;
for(r = sym->r; r < sym->r+sym->nr; r++) {
- // Ignore relocations handled by reloc already.
- switch(r->type) {
- case D_SIZE:
+ if(r->done)
+ continue;
+ if(r->xsym == nil) {
+ diag("missing xsym in relocation");
continue;
- case D_ADDR:
- case D_PCREL:
- if(r->sym->type == SCONST)
- continue;
- break;
- }
-
- add = r->add;
- rs = r->sym;
- while(rs->outer != nil) {
- add += rs->value - rs->outer->value;
- rs = rs->outer;
}
-
- if(rs->elfsym == 0)
- diag("reloc %d to non-elf symbol %s (rs=%s) %d", r->type, r->sym->name, rs->name, rs->type);
-
- if(elfreloc1(r, sym->value - sect->vaddr + r->off, rs->elfsym, add) < 0)
+ if(r->xsym->elfsym == 0)
+ diag("reloc %d to non-elf symbol %s (outer=%s) %d", r->type, r->sym->name, r->xsym->name, r->sym->type);
+ if(elfreloc1(r, sym->value+r->off - sect->vaddr) < 0)
diag("unsupported obj reloc %d/%d to %s", r->type, r->siz, r->sym->name);
}
}
@@ -915,7 +899,7 @@ doelf(void)
addstring(shstrtab, ".gosymtab");
addstring(shstrtab, ".gopclntab");
- if(isobj) {
+ if(linkmode == LinkExternal) {
debug['s'] = 0;
debug['d'] = 1;
@@ -1147,7 +1131,7 @@ asmbelf(vlong symo)
resoff = ELFRESERVE;
pph = nil;
- if(isobj) {
+ if(linkmode == LinkExternal) {
/* skip program headers */
eh->phoff = 0;
eh->phentsize = 0;
@@ -1408,7 +1392,7 @@ elfobj:
for(sect=segdata.sect; sect!=nil; sect=sect->next)
elfshbits(sect);
- if(isobj) {
+ if(linkmode == LinkExternal) {
for(sect=segtext.sect; sect!=nil; sect=sect->next)
elfshreloc(sect);
for(sect=segdata.sect; sect!=nil; sect=sect->next)
@@ -1431,8 +1415,8 @@ elfobj:
sh->size = elfstrsize;
sh->addralign = 1;
- // TODO(rsc): Enable for isobj too, once we know it works.
- if(!isobj)
+ // TODO(rsc): Enable for linkmode == LinkExternal too, once we know it works.
+ if(linkmode != LinkExternal)
dwarfaddelfheaders();
}
@@ -1456,12 +1440,12 @@ elfobj:
if(flag_shared)
eh->type = ET_DYN;
- else if(isobj)
+ else if(linkmode == LinkExternal)
eh->type = ET_REL;
else
eh->type = ET_EXEC;
- if(!isobj)
+ if(linkmode != LinkExternal)
eh->entry = entryvalue();
eh->version = EV_CURRENT;
@@ -1478,7 +1462,7 @@ elfobj:
a += elfwriteshdrs();
if(!debug['d'])
a += elfwriteinterp();
- if(!isobj) {
+ if(linkmode != LinkExternal) {
if(HEADTYPE == Hnetbsd)
a += elfwritenetbsdsig();
if(HEADTYPE == Hopenbsd)
diff --git a/src/cmd/ld/elf.h b/src/cmd/ld/elf.h
index 3e22125b2..336fab4b4 100644
--- a/src/cmd/ld/elf.h
+++ b/src/cmd/ld/elf.h
@@ -1005,7 +1005,7 @@ extern char linuxdynld[];
extern char freebsddynld[];
extern char netbsddynld[];
extern char openbsddynld[];
-int elfreloc1(Reloc*, vlong off, int32 elfsym, vlong add);
+int elfreloc1(Reloc*, vlong sectoff);
EXTERN int elfstrsize;
EXTERN char* elfstrdat;
diff --git a/src/cmd/ld/go.c b/src/cmd/ld/go.c
index b2527b13e..f933cbba3 100644
--- a/src/cmd/ld/go.c
+++ b/src/cmd/ld/go.c
@@ -59,7 +59,7 @@ ilookup(char *name)
if(x->name[0] == name[0] && strcmp(x->name, name) == 0)
return x;
x = mal(sizeof *x);
- x->name = strdup(name);
+ x->name = estrdup(name);
x->hash = ihash[h];
ihash[h] = x;
nimport++;
@@ -71,8 +71,6 @@ static void loadcgo(char*, char*, char*, int);
static int parsemethod(char**, char*, char**);
static int parsepkgdata(char*, char*, char**, char*, char**, char**, char**);
-static Sym **dynexp;
-
void
ldpkg(Biobuf *f, char *pkg, int64 len, char *filename, int whence)
{
@@ -205,14 +203,14 @@ loadpkgdata(char *file, char *pkg, char *data, int len)
char *p, *ep, *prefix, *name, *def;
Import *x;
- file = strdup(file);
+ file = estrdup(file);
p = data;
ep = data + len;
while(parsepkgdata(file, pkg, &p, ep, &prefix, &name, &def) > 0) {
x = ilookup(name);
if(x->prefix == nil) {
x->prefix = prefix;
- x->def = strdup(def);
+ x->def = estrdup(def);
x->file = file;
} else if(strcmp(x->prefix, prefix) != 0) {
fprint(2, "%s: conflicting definitions for %s\n", argv0, name);
@@ -244,7 +242,7 @@ expandpkg(char *t0, char *pkg)
n++;
if(n == 0)
- return strdup(t0);
+ return estrdup(t0);
// use malloc, not mal, so that caller can free
w0 = malloc(strlen(t0) + strlen(pkg)*n);
@@ -429,7 +427,7 @@ loadcgo(char *file, char *pkg, char *p, int n)
*next++ = '\0';
free(p0);
- p0 = strdup(p); // save for error message
+ p0 = estrdup(p); // save for error message
nf = tokenize(p, f, nelem(f));
if(strcmp(f[0], "cgo_import_dynamic") == 0) {
@@ -467,7 +465,7 @@ loadcgo(char *file, char *pkg, char *p, int n)
free(local);
if(s->type == 0 || s->type == SXREF) {
s->dynimplib = lib;
- s->dynimpname = remote;
+ s->extname = remote;
s->dynimpvers = q;
s->type = SDYNIMPORT;
havedynamic = 1;
@@ -478,16 +476,18 @@ loadcgo(char *file, char *pkg, char *p, int n)
if(strcmp(f[0], "cgo_import_static") == 0) {
if(nf != 2)
goto err;
- if(isobj) {
- local = f[1];
- s = lookup(local, 0);
- s->type = SHOSTOBJ;
- s->size = 0;
- }
+ local = f[1];
+ s = lookup(local, 0);
+ s->type = SHOSTOBJ;
+ s->size = 0;
continue;
}
- if(strcmp(f[0], "cgo_export") == 0) {
+ if(strcmp(f[0], "cgo_export_static") == 0 || strcmp(f[0], "cgo_export_dynamic") == 0) {
+ // TODO: Remove once we know Windows is okay.
+ if(strcmp(f[0], "cgo_export_static") == 0 && HEADTYPE == Hwindows)
+ continue;
+
if(nf < 2 || nf > 3)
goto err;
local = f[1];
@@ -497,17 +497,30 @@ loadcgo(char *file, char *pkg, char *p, int n)
remote = local;
local = expandpkg(local, pkg);
s = lookup(local, 0);
+
+ // export overrides import, for openbsd/cgo.
+ // see issue 4878.
if(s->dynimplib != nil) {
- fprint(2, "%s: symbol is both imported and exported: %s\n", argv0, local);
- nerrors++;
+ s->dynimplib = nil;
+ s->extname = nil;
+ s->dynimpvers = nil;
+ s->type = 0;
}
- s->dynimpname = remote;
- s->dynexport = 1;
-
- if(ndynexp%32 == 0)
- dynexp = realloc(dynexp, (ndynexp+32)*sizeof dynexp[0]);
- dynexp[ndynexp++] = s;
+ if(s->cgoexport == 0) {
+ if(strcmp(f[0], "cgo_export_static") == 0)
+ s->cgoexport |= CgoExportStatic;
+ else
+ s->cgoexport |= CgoExportDynamic;
+ s->extname = remote;
+ if(ndynexp%32 == 0)
+ dynexp = erealloc(dynexp, (ndynexp+32)*sizeof dynexp[0]);
+ dynexp[ndynexp++] = s;
+ } else if(strcmp(s->extname, remote) != 0) {
+ fprint(2, "%s: conflicting cgo_export directives: %s as %s and %s\n", argv0, s->name, s->extname, remote);
+ nerrors++;
+ return;
+ }
if(local != f[1])
free(local);
continue;
@@ -524,10 +537,19 @@ loadcgo(char *file, char *pkg, char *p, int n)
return;
}
free(interpreter);
- interpreter = strdup(f[1]);
+ interpreter = estrdup(f[1]);
}
continue;
}
+
+ if(strcmp(f[0], "cgo_ldflag") == 0) {
+ if(nf != 2)
+ goto err;
+ if(nldflag%32 == 0)
+ ldflag = erealloc(ldflag, (nldflag+32)*sizeof ldflag[0]);
+ ldflag[nldflag++] = estrdup(f[1]);
+ continue;
+ }
}
free(p0);
return;
@@ -751,6 +773,9 @@ addexport(void)
{
int i;
+ if(HEADTYPE == Hdarwin)
+ return;
+
for(i=0; i<ndynexp; i++)
adddynsym(dynexp[i]);
}
@@ -829,7 +854,7 @@ getpkg(char *path)
if(strcmp(p->path, path) == 0)
return p;
p = mal(sizeof *p);
- p->path = strdup(path);
+ p->path = estrdup(path);
p->next = phash[h];
phash[h] = p;
p->all = pkgall;
@@ -853,7 +878,7 @@ imported(char *pkg, char *import)
i->mimpby *= 2;
if(i->mimpby == 0)
i->mimpby = 16;
- i->impby = realloc(i->impby, i->mimpby*sizeof i->impby[0]);
+ i->impby = erealloc(i->impby, i->mimpby*sizeof i->impby[0]);
}
i->impby[i->nimpby++] = p;
free(pkg);
@@ -899,27 +924,17 @@ importcycles(void)
cycle(p);
}
-static int
-scmp(const void *p1, const void *p2)
-{
- Sym *s1, *s2;
-
- s1 = *(Sym**)p1;
- s2 = *(Sym**)p2;
- return strcmp(s1->dynimpname, s2->dynimpname);
-}
void
-sortdynexp(void)
+setlinkmode(char *arg)
{
- int i;
-
- // On Mac OS X Mountain Lion, we must sort exported symbols
- // So we sort them here and pre-allocate dynid for them
- // See http://golang.org/issue/4029
- if(HEADTYPE != Hdarwin)
- return;
- qsort(dynexp, ndynexp, sizeof dynexp[0], scmp);
- for(i=0; i<ndynexp; i++) {
- dynexp[i]->dynid = -i-100; // also known to [68]l/asm.c:^adddynsym
+ if(strcmp(arg, "internal") == 0)
+ linkmode = LinkInternal;
+ else if(strcmp(arg, "external") == 0)
+ linkmode = LinkExternal;
+ else if(strcmp(arg, "auto") == 0)
+ linkmode = LinkAuto;
+ else {
+ fprint(2, "unknown link mode -linkmode %s\n", arg);
+ errorexit();
}
}
diff --git a/src/cmd/ld/ldelf.c b/src/cmd/ld/ldelf.c
index 2bbf4f83e..27041bc47 100644
--- a/src/cmd/ld/ldelf.c
+++ b/src/cmd/ld/ldelf.c
@@ -595,10 +595,8 @@ ldelf(Biobuf *f, char *pkg, int64 len, char *pn)
s->sub = sect->sym->sub;
sect->sym->sub = s;
s->type = sect->sym->type | (s->type&~SMASK) | SSUB;
- if(!s->dynexport) {
+ if(!(s->cgoexport & CgoExportDynamic))
s->dynimplib = nil; // satisfy dynimport
- s->dynimpname = nil; // satisfy dynimport
- }
s->value = sym.value;
s->size = sym.size;
s->outer = sect->sym;
diff --git a/src/cmd/ld/ldmacho.c b/src/cmd/ld/ldmacho.c
index 41852f17c..098cb7bef 100644
--- a/src/cmd/ld/ldmacho.c
+++ b/src/cmd/ld/ldmacho.c
@@ -639,10 +639,8 @@ ldmacho(Biobuf *f, char *pkg, int64 len, char *pn)
s->size = (sym+1)->value - sym->value;
else
s->size = sect->addr + sect->size - sym->value;
- if(!s->dynexport) {
+ if(!(s->cgoexport & CgoExportDynamic))
s->dynimplib = nil; // satisfy dynimport
- s->dynimpname = nil; // satisfy dynimport
- }
if(outer->type == STEXT) {
Prog *p;
diff --git a/src/cmd/ld/ldpe.c b/src/cmd/ld/ldpe.c
index 39c15e6a1..98923bfbf 100644
--- a/src/cmd/ld/ldpe.c
+++ b/src/cmd/ld/ldpe.c
@@ -135,7 +135,8 @@ ldpe(Biobuf *f, char *pkg, int64 len, char *pn)
{
char *name;
int32 base;
- int i, j, l, numaux;
+ uint32 l;
+ int i, j, numaux;
PeObj *obj;
PeSect *sect, *rsect;
IMAGE_SECTION_HEADER sh;
@@ -170,11 +171,12 @@ ldpe(Biobuf *f, char *pkg, int64 len, char *pn)
// TODO return error if found .cormeta
}
// load string table
- Bseek(f, base+obj->fh.PointerToSymbolTable+18*obj->fh.NumberOfSymbols, 0);
- if(Bread(f, &l, sizeof l) != sizeof l)
+ Bseek(f, base+obj->fh.PointerToSymbolTable+sizeof(symbuf)*obj->fh.NumberOfSymbols, 0);
+ if(Bread(f, symbuf, 4) != 4)
goto bad;
+ l = le32(symbuf);
obj->snames = mal(l);
- Bseek(f, base+obj->fh.PointerToSymbolTable+18*obj->fh.NumberOfSymbols, 0);
+ Bseek(f, base+obj->fh.PointerToSymbolTable+sizeof(symbuf)*obj->fh.NumberOfSymbols, 0);
if(Bread(f, obj->snames, l) != l)
goto bad;
// read symbols
diff --git a/src/cmd/ld/lib.c b/src/cmd/ld/lib.c
index 26fa4f2ac..18cae3175 100644
--- a/src/cmd/ld/lib.c
+++ b/src/cmd/ld/lib.c
@@ -44,6 +44,8 @@ int nlibdir = 0;
static int maxlibdir = 0;
static int cout = -1;
+static void hostlinksetup(void);
+
char* goroot;
char* goarch;
char* goos;
@@ -59,11 +61,7 @@ Lflag(char *arg)
maxlibdir = 8;
else
maxlibdir *= 2;
- p = realloc(libdir, maxlibdir * sizeof(*p));
- if (p == nil) {
- print("too many -L's: %d\n", nlibdir);
- usage();
- }
+ p = erealloc(libdir, maxlibdir * sizeof(*p));
libdir = p;
}
libdir[nlibdir++] = arg;
@@ -95,7 +93,7 @@ libinit(void)
#endif
cout = create(outfile, 1, 0775);
if(cout < 0) {
- diag("cannot create %s", outfile);
+ diag("cannot create %s: %r", outfile);
errorexit();
}
@@ -242,7 +240,7 @@ addlibpath(char *srcref, char *objref, char *file, char *pkg)
if(libraryp == nlibrary){
nlibrary = 50 + 2*libraryp;
- library = realloc(library, sizeof library[0] * nlibrary);
+ library = erealloc(library, sizeof library[0] * nlibrary);
}
l = &library[libraryp++];
@@ -288,7 +286,8 @@ loadinternal(char *name)
void
loadlib(void)
{
- int i;
+ int i, w, x;
+ Sym *s;
loadinternal("runtime");
if(thechar == '5')
@@ -303,6 +302,37 @@ loadlib(void)
objfile(library[i].file, library[i].pkg);
}
+ if(linkmode == LinkExternal && !iscgo)
+ linkmode = LinkInternal;
+
+ // If we got this far in automatic mode, there were no
+ // cgo uses that suggest we need external mode.
+ // Switch to internal.
+ if(linkmode == LinkAuto) {
+ 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)
+ if(s->type == SHOSTOBJ)
+ s->type = 0;
+ }
+
+ // Now that we know the link mode, trim the dynexp list.
+ x = CgoExportDynamic;
+ if(linkmode == LinkExternal)
+ x = CgoExportStatic;
+ w = 0;
+ for(i=0; i<ndynexp; i++)
+ if(dynexp[i]->cgoexport & x)
+ dynexp[w++] = dynexp[i];
+ ndynexp = w;
+
+ // In internal link mode, read the host object files.
+ if(linkmode == LinkInternal)
+ hostobjs();
+ else
+ hostlinksetup();
+
// We've loaded all the code now.
// If there are no dynamic libraries needed, gcc disables dynamic linking.
// Because of this, glibc's dynamic ELF loader occasionally (like in version 2.13)
@@ -316,7 +346,6 @@ loadlib(void)
debug['d'] = 1;
importcycles();
- sortdynexp();
}
/*
@@ -375,7 +404,7 @@ objfile(char *file, char *pkg)
/* load it as a regular file */
l = Bseek(f, 0L, 2);
Bseek(f, 0L, 0);
- ldobj(f, pkg, l, file, FileObj);
+ ldobj(f, pkg, l, file, file, FileObj);
Bterm(f);
free(pkg);
return;
@@ -434,7 +463,7 @@ objfile(char *file, char *pkg)
l--;
snprint(pname, sizeof pname, "%s(%.*s)", file, utfnlen(arhdr.name, l), arhdr.name);
l = atolwhex(arhdr.size);
- ldobj(f, pkg, l, pname, ArchiveObj);
+ ldobj(f, pkg, l, pname, file, ArchiveObj);
}
out:
@@ -442,8 +471,229 @@ out:
free(pkg);
}
+static void
+dowrite(int fd, char *p, int n)
+{
+ int m;
+
+ while(n > 0) {
+ m = write(fd, p, n);
+ if(m <= 0) {
+ cursym = S;
+ diag("write error: %r");
+ errorexit();
+ }
+ n -= m;
+ p += m;
+ }
+}
+
+typedef struct Hostobj Hostobj;
+
+struct Hostobj
+{
+ void (*ld)(Biobuf*, char*, int64, char*);
+ char *pkg;
+ char *pn;
+ char *file;
+ int64 off;
+ int64 len;
+};
+
+Hostobj *hostobj;
+int nhostobj;
+int mhostobj;
+
+// These packages can use internal linking mode.
+// Others trigger external mode.
+const char *internalpkg[] = {
+ "crypto/x509",
+ "net",
+ "os/user",
+ "runtime/cgo",
+ "runtime/race"
+};
+
+void
+ldhostobj(void (*ld)(Biobuf*, char*, int64, char*), Biobuf *f, char *pkg, int64 len, char *pn, char *file)
+{
+ int i, isinternal;
+ Hostobj *h;
+
+ isinternal = 0;
+ for(i=0; i<nelem(internalpkg); i++) {
+ if(strcmp(pkg, internalpkg[i]) == 0) {
+ isinternal = 1;
+ break;
+ }
+ }
+
+ if(!isinternal && linkmode == LinkAuto)
+ linkmode = LinkExternal;
+
+ if(nhostobj >= mhostobj) {
+ if(mhostobj == 0)
+ mhostobj = 16;
+ else
+ mhostobj *= 2;
+ hostobj = erealloc(hostobj, mhostobj*sizeof hostobj[0]);
+ }
+ h = &hostobj[nhostobj++];
+ h->ld = ld;
+ h->pkg = estrdup(pkg);
+ h->pn = estrdup(pn);
+ h->file = estrdup(file);
+ h->off = Boffset(f);
+ h->len = len;
+}
+
+void
+hostobjs(void)
+{
+ int i;
+ Biobuf *f;
+ Hostobj *h;
+
+ for(i=0; i<nhostobj; i++) {
+ h = &hostobj[i];
+ f = Bopen(h->file, OREAD);
+ if(f == nil) {
+ cursym = S;
+ diag("cannot reopen %s: %r", h->pn);
+ errorexit();
+ }
+ Bseek(f, h->off, 0);
+ h->ld(f, h->pkg, h->len, h->pn);
+ Bterm(f);
+ }
+}
+
+// provided by lib9
+int runcmd(char**);
+char* mktempdir(void);
+void removeall(char*);
+
+static void
+rmtemp(void)
+{
+ removeall(tmpdir);
+}
+
+static void
+hostlinksetup(void)
+{
+ char *p;
+
+ if(linkmode != LinkExternal)
+ return;
+
+ // create temporary directory and arrange cleanup
+ if(tmpdir == nil) {
+ tmpdir = mktempdir();
+ atexit(rmtemp);
+ }
+
+ // change our output to temporary object file
+ close(cout);
+ p = smprint("%s/go.o", tmpdir);
+ cout = create(p, 1, 0775);
+ if(cout < 0) {
+ diag("cannot create %s: %r", p);
+ errorexit();
+ }
+ free(p);
+}
+
void
-ldobj(Biobuf *f, char *pkg, int64 len, char *pn, int whence)
+hostlink(void)
+{
+ char *p, **argv;
+ int i, w, n, argc, len;
+ Hostobj *h;
+ Biobuf *f;
+ static char buf[64<<10];
+
+ if(linkmode != LinkExternal || nerrors > 0)
+ return;
+
+ argv = malloc((10+nhostobj+nldflag)*sizeof argv[0]);
+ argc = 0;
+ // TODO: Add command-line flag to override gcc path and specify additional leading options.
+ // TODO: Add command-line flag to specify additional trailing options.
+ argv[argc++] = "gcc";
+ switch(thechar){
+ case '8':
+ argv[argc++] = "-m32";
+ break;
+ case '6':
+ argv[argc++] = "-m64";
+ break;
+ }
+ if(!debug['s'])
+ argv[argc++] = "-gdwarf-2";
+ if(HEADTYPE == Hdarwin)
+ argv[argc++] = "-Wl,-no_pie,-pagezero_size,4000000";
+ argv[argc++] = "-o";
+ argv[argc++] = outfile;
+
+ // Force global symbols to be exported for dlopen, etc.
+ // NOTE: May not work on OS X or Windows. We'll see.
+ argv[argc++] = "-rdynamic";
+
+ // 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;
+ diag("cannot reopen %s: %r", h->pn);
+ errorexit();
+ }
+ Bseek(f, h->off, 0);
+ p = smprint("%s/%06d.o", tmpdir, i);
+ argv[argc++] = p;
+ w = create(p, 1, 0775);
+ if(w < 0) {
+ diag("cannot create %s: %r", p);
+ errorexit();
+ }
+ len = h->len;
+ while(len > 0 && (n = Bread(f, buf, sizeof buf)) > 0){
+ if(n > len)
+ n = len;
+ dowrite(w, buf, n);
+ len -= n;
+ }
+ if(close(w) < 0) {
+ diag("cannot write %s: %r", p);
+ errorexit();
+ }
+ Bterm(f);
+ }
+
+ argv[argc++] = smprint("%s/go.o", tmpdir);
+ for(i=0; i<nldflag; i++)
+ argv[argc++] = ldflag[i];
+ argv[argc] = nil;
+
+ quotefmtinstall();
+ if(debug['v']) {
+ Bprint(&bso, "host link:");
+ for(i=0; i<argc; i++)
+ Bprint(&bso, " %q", argv[i]);
+ Bprint(&bso, "\n");
+ Bflush(&bso);
+ }
+
+ if(runcmd(argv) < 0) {
+ diag("%s: running %s failed: %r", argv0, argv[0]);
+ errorexit();
+ }
+}
+
+void
+ldobj(Biobuf *f, char *pkg, int64 len, char *pn, char *file, int whence)
{
char *line;
int n, c1, c2, c3, c4;
@@ -453,7 +703,7 @@ ldobj(Biobuf *f, char *pkg, int64 len, char *pn, int whence)
eof = Boffset(f) + len;
- pn = strdup(pn);
+ pn = estrdup(pn);
c1 = Bgetc(f);
c2 = Bgetc(f);
@@ -466,18 +716,15 @@ ldobj(Biobuf *f, char *pkg, int64 len, char *pn, int whence)
magic = c1<<24 | c2<<16 | c3<<8 | c4;
if(magic == 0x7f454c46) { // \x7F E L F
- ldelf(f, pkg, len, pn);
- free(pn);
+ ldhostobj(ldelf, f, pkg, len, pn, file);
return;
}
if((magic&~1) == 0xfeedface || (magic&~0x01000000) == 0xcefaedfe) {
- ldmacho(f, pkg, len, pn);
- free(pn);
+ ldhostobj(ldmacho, f, pkg, len, pn, file);
return;
}
if(c1 == 0x4c && c2 == 0x01 || c1 == 0x64 && c2 == 0x86) {
- ldpe(f, pkg, len, pn);
- free(pn);
+ ldhostobj(ldpe, f, pkg, len, pn, file);
return;
}
@@ -524,7 +771,7 @@ ldobj(Biobuf *f, char *pkg, int64 len, char *pn, int whence)
line[n] = '\0';
if(n-10 > strlen(t)) {
if(theline == nil)
- theline = strdup(line+10);
+ theline = estrdup(line+10);
else if(strcmp(theline, line+10) != 0) {
line[n] = '\0';
diag("%s: object is [%s] expected [%s]", pn, line+10, theline);
@@ -615,6 +862,7 @@ _lookup(char *symb, int v, int creat)
return nil;
s = newsym(symb, v);
+ s->extname = s->name;
s->hash = hash[h];
hash[h] = s;
@@ -1027,6 +1275,7 @@ addsection(Segment *seg, char *name, int rwx)
sect->rwx = rwx;
sect->name = name;
sect->seg = seg;
+ sect->align = PtrSize; // everything is at least pointer-aligned
*l = sect;
return sect;
}
@@ -1460,23 +1709,6 @@ Yconv(Fmt *fp)
vlong coutpos;
-static void
-dowrite(int fd, char *p, int n)
-{
- int m;
-
- while(n > 0) {
- m = write(fd, p, n);
- if(m <= 0) {
- cursym = S;
- diag("write error: %r");
- errorexit();
- }
- n -= m;
- p += m;
- }
-}
-
void
cflush(void)
{
@@ -1576,7 +1808,7 @@ genasmsym(void (*put)(Sym*, char*, int, vlong, vlong, int, Sym*))
put(s, s->name, 'T', s->value, s->size, s->version, 0);
for(s=allsym; s!=S; s=s->allsym) {
- if(s->hide)
+ if(s->hide || (s->name[0] == '.' && s->version == 0 && strcmp(s->name, ".rathole") != 0))
continue;
switch(s->type&SMASK) {
case SCONST:
@@ -1591,8 +1823,6 @@ genasmsym(void (*put)(Sym*, char*, int, vlong, vlong, int, Sym*))
case SSTRING:
case SGOSTRING:
case SWINDOWS:
- case SGCDATA:
- case SGCBSS:
if(!s->reachable)
continue;
put(s, s->name, 'D', symaddr(s), s->size, s->version, s->gotype);
@@ -1664,3 +1894,27 @@ genasmsym(void (*put)(Sym*, char*, int, vlong, vlong, int, Sym*))
Bprint(&bso, "symsize = %ud\n", symsize);
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)
+{
+ p = realloc(p, n);
+ if(p == nil) {
+ cursym = S;
+ diag("out of memory");
+ errorexit();
+ }
+ return p;
+}
diff --git a/src/cmd/ld/lib.h b/src/cmd/ld/lib.h
index 94ad76ecc..a5ca7d3c3 100644
--- a/src/cmd/ld/lib.h
+++ b/src/cmd/ld/lib.h
@@ -34,30 +34,28 @@ enum
/* order here is order in output file */
STEXT,
- SMACHOPLT,
STYPE,
SSTRING,
SGOSTRING,
SRODATA,
STYPELINK,
- SGCDATA,
- SGCBSS,
SSYMTAB,
SPCLNTAB,
SELFROSECT,
+ SMACHOPLT,
SELFSECT,
+ SMACHO, /* Mach-O __nl_symbol_ptr */
+ SMACHOGOT,
SNOPTRDATA,
SDATARELRO,
SDATA,
- SMACHO, /* Mach-O __nl_symbol_ptr */
- SMACHOGOT,
SWINDOWS,
SBSS,
SNOPTRBSS,
SXREF,
- SMACHODYNSTR,
- SMACHODYNSYM,
+ SMACHOSYMSTR,
+ SMACHOSYMTAB,
SMACHOINDIRECTPLT,
SMACHOINDIRECTGOT,
SFILE,
@@ -104,6 +102,8 @@ struct Segment
struct Section
{
uchar rwx;
+ int16 extnum;
+ int32 align;
char *name;
uvlong vaddr;
uvlong len;
@@ -138,20 +138,38 @@ EXTERN char* outfile;
EXTERN int32 nsymbol;
EXTERN char* thestring;
EXTERN int ndynexp;
+EXTERN Sym** dynexp;
+EXTERN int nldflag;
+EXTERN char** ldflag;
EXTERN int havedynamic;
EXTERN int iscgo;
-EXTERN int isobj;
EXTERN int elfglobalsymndx;
EXTERN int flag_race;
EXTERN int flag_shared;
EXTERN char* tracksym;
EXTERN char* interpreter;
+EXTERN char* tmpdir;
+
+enum
+{
+ LinkAuto = 0,
+ LinkInternal,
+ LinkExternal,
+};
+EXTERN int linkmode;
+
+// for dynexport field of Sym
+enum
+{
+ CgoExportDynamic = 1<<0,
+ CgoExportStatic = 1<<1,
+};
EXTERN Segment segtext;
EXTERN Segment segdata;
-EXTERN Segment segsym;
-EXTERN Segment segdwarf;
+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);
@@ -185,7 +203,7 @@ void adddynrel(Sym*, Reloc*);
void adddynrela(Sym*, Sym*, Reloc*);
Sym* lookuprel(void);
void ldobj1(Biobuf *f, char*, int64 len, char *pn);
-void ldobj(Biobuf*, char*, int64, char*, int);
+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*);
@@ -207,6 +225,7 @@ 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*, int32);
vlong addpcrelplus(Sym*, Sym*, int32);
@@ -240,6 +259,10 @@ 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);
int pathchar(void);
void* mal(uint32);
@@ -359,5 +382,3 @@ char* decodetype_structfieldname(Sym*, int);
Sym* decodetype_structfieldtype(Sym*, int);
vlong decodetype_structfieldoffs(Sym*, int);
vlong decodetype_ifacemethodcount(Sym*);
-
-void sortdynexp(void);
diff --git a/src/cmd/ld/macho.c b/src/cmd/ld/macho.c
index 6781c25a4..d135a92da 100644
--- a/src/cmd/ld/macho.c
+++ b/src/cmd/ld/macho.c
@@ -14,9 +14,20 @@ static int macho64;
static MachoHdr hdr;
static MachoLoad *load;
static MachoSeg seg[16];
-static MachoDebug xdebug[16];
static int nload, mload, nseg, ndebug, nsect;
+enum
+{
+ SymKindLocal = 0,
+ SymKindExtdef,
+ SymKindUndef,
+ NumSymKind
+};
+
+static int nkind[NumSymKind];
+static Sym** sortsym;
+static int nsortsym;
+
// Amount of space left for adding load commands
// that refer to dynamic libraries. Because these have
// to go in the Mach-O header, we can't just pick a
@@ -25,6 +36,8 @@ static int nload, mload, nseg, ndebug, nsect;
// up about 1300 bytes; we overestimate that as 2k.
static int load_budget = INITIAL_MACHO_HEADR - 2*1024;
+static void machodysymtab(void);
+
void
machoinit(void)
{
@@ -56,11 +69,7 @@ newMachoLoad(uint32 type, uint32 ndata)
mload = 1;
else
mload *= 2;
- load = realloc(load, mload*sizeof load[0]);
- if(load == nil) {
- diag("out of memory");
- errorexit();
- }
+ load = erealloc(load, mload*sizeof load[0]);
}
if(macho64 && (ndata & 1))
@@ -90,7 +99,7 @@ newMachoSeg(char *name, int msect)
}
MachoSect*
-newMachoSect(MachoSeg *seg, char *name)
+newMachoSect(MachoSeg *seg, char *name, char *segname)
{
MachoSect *s;
@@ -100,21 +109,11 @@ newMachoSect(MachoSeg *seg, char *name)
}
s = &seg->sect[seg->nsect++];
s->name = name;
+ s->segname = segname;
nsect++;
return s;
}
-MachoDebug*
-newMachoDebug(void)
-{
- if(ndebug >= nelem(xdebug)) {
- diag("too many debugs");
- errorexit();
- }
- return &xdebug[ndebug++];
-}
-
-
// Generic linking code.
static char **dylib;
@@ -130,7 +129,6 @@ machowrite(void)
int i, j;
MachoSeg *s;
MachoSect *t;
- MachoDebug *d;
MachoLoad *l;
o1 = cpos();
@@ -152,7 +150,10 @@ machowrite(void)
LPUT(0xfeedface);
LPUT(hdr.cpu);
LPUT(hdr.subcpu);
- LPUT(2); /* file type - mach executable */
+ if(linkmode == LinkExternal)
+ LPUT(1); /* file type - mach object */
+ else
+ LPUT(2); /* file type - mach executable */
LPUT(nload+nseg+ndebug);
LPUT(loadsize);
LPUT(1); /* flags - no undefines */
@@ -190,7 +191,7 @@ machowrite(void)
t = &s->sect[j];
if(macho64) {
strnput(t->name, 16);
- strnput(s->name, 16);
+ strnput(t->segname, 16);
VPUT(t->addr);
VPUT(t->size);
LPUT(t->off);
@@ -203,7 +204,7 @@ machowrite(void)
LPUT(0); /* reserved */
} else {
strnput(t->name, 16);
- strnput(s->name, 16);
+ strnput(t->segname, 16);
LPUT(t->addr);
LPUT(t->size);
LPUT(t->off);
@@ -225,14 +226,6 @@ machowrite(void)
LPUT(l->data[j]);
}
- for(i=0; i<ndebug; i++) {
- d = &xdebug[i];
- LPUT(3); /* obsolete gdb debug info */
- LPUT(16); /* size of symseg command */
- LPUT(d->fileoffset);
- LPUT(d->filesize);
- }
-
return cpos() - o1;
}
@@ -245,31 +238,34 @@ domacho(void)
return;
// empirically, string table must begin with " \x00".
- s = lookup(".dynstr", 0);
- s->type = SMACHODYNSTR;
+ s = lookup(".machosymstr", 0);
+ s->type = SMACHOSYMSTR;
s->reachable = 1;
adduint8(s, ' ');
adduint8(s, '\0');
- s = lookup(".dynsym", 0);
- s->type = SMACHODYNSYM;
+ s = lookup(".machosymtab", 0);
+ s->type = SMACHOSYMTAB;
s->reachable = 1;
- s = lookup(".plt", 0); // will be __symbol_stub
- s->type = SMACHOPLT;
- s->reachable = 1;
+ if(linkmode != LinkExternal) {
+ s = lookup(".plt", 0); // will be __symbol_stub
+ s->type = SMACHOPLT;
+ s->reachable = 1;
- s = lookup(".got", 0); // will be __nl_symbol_ptr
- s->type = SMACHOGOT;
- s->reachable = 1;
+ s = lookup(".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->type = SMACHOINDIRECTPLT;
- s->reachable = 1;
+ s = lookup(".linkedit.plt", 0); // indirect table for .plt
+ s->type = SMACHOINDIRECTPLT;
+ s->reachable = 1;
- s = lookup(".linkedit.got", 0); // indirect table for .got
- s->type = SMACHOINDIRECTGOT;
- s->reachable = 1;
+ s = lookup(".linkedit.got", 0); // indirect table for .got
+ s->type = SMACHOINDIRECTGOT;
+ s->reachable = 1;
+ }
}
void
@@ -286,16 +282,62 @@ machoadddynlib(char *lib)
load_budget += 4096;
}
- if(ndylib%32 == 0) {
- dylib = realloc(dylib, (ndylib+32)*sizeof dylib[0]);
- if(dylib == nil) {
- diag("out of memory");
- errorexit();
- }
- }
+ if(ndylib%32 == 0)
+ dylib = erealloc(dylib, (ndylib+32)*sizeof dylib[0]);
dylib[ndylib++] = lib;
}
+static void
+machoshbits(MachoSeg *mseg, Section *sect, char *segname)
+{
+ MachoSect *msect;
+ char buf[40];
+ char *p;
+
+ snprint(buf, sizeof buf, "__%s", sect->name+1);
+ for(p=buf; *p; p++)
+ if(*p == '.')
+ *p = '_';
+
+ msect = newMachoSect(mseg, estrdup(buf), segname);
+ if(sect->rellen > 0) {
+ msect->reloc = sect->reloff;
+ msect->nreloc = sect->rellen / 8;
+ }
+
+ while(1<<msect->align < sect->align)
+ msect->align++;
+ msect->addr = sect->vaddr;
+ msect->size = sect->len;
+
+ if(sect->vaddr < sect->seg->vaddr + sect->seg->filelen) {
+ // data in file
+ if(sect->len > sect->seg->vaddr + sect->seg->filelen - sect->vaddr)
+ diag("macho cannot represent section %s crossing data and bss", sect->name);
+ msect->off = sect->seg->fileoff + sect->vaddr - sect->seg->vaddr;
+ } else {
+ // zero fill
+ msect->off = 0;
+ msect->flag |= 1;
+ }
+
+ if(sect->rwx & 1)
+ msect->flag |= 0x400; /* has instructions */
+
+ if(strcmp(sect->name, ".plt") == 0) {
+ msect->name = "__symbol_stub1";
+ msect->flag = 0x80000408; /* only instructions, code, symbol stubs */
+ msect->res1 = 0;//nkind[SymKindLocal];
+ msect->res2 = 6;
+ }
+
+ 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 */
+ }
+}
+
void
asmbmacho(void)
{
@@ -303,11 +345,9 @@ asmbmacho(void)
vlong va;
int a, i;
MachoHdr *mh;
- MachoSect *msect;
MachoSeg *ms;
- MachoDebug *md;
MachoLoad *ml;
- Sym *s;
+ Section *sect;
/* apple MACH */
va = INITTEXT - HEADR;
@@ -325,179 +365,305 @@ asmbmacho(void)
mh->subcpu = MACHO_SUBCPU_X86;
break;
}
+
+ ms = nil;
+ if(linkmode == LinkExternal) {
+ /* segment for entire file */
+ ms = newMachoSeg("", 40);
+ ms->fileoffset = segtext.fileoff;
+ ms->filesize = segdata.fileoff + segdata.filelen - segtext.fileoff;
+ }
/* segment for zero page */
- ms = newMachoSeg("__PAGEZERO", 0);
- ms->vsize = va;
+ if(linkmode != LinkExternal) {
+ ms = newMachoSeg("__PAGEZERO", 0);
+ ms->vsize = va;
+ }
/* text */
v = rnd(HEADR+segtext.len, INITRND);
- ms = newMachoSeg("__TEXT", 2);
- ms->vaddr = va;
- ms->vsize = v;
- ms->filesize = v;
- ms->prot1 = 7;
- ms->prot2 = 5;
-
- msect = newMachoSect(ms, "__text");
- msect->addr = INITTEXT;
- msect->size = segtext.sect->len;
- msect->off = INITTEXT - va;
- msect->flag = 0x400; /* flag - some instructions */
-
- s = lookup(".plt", 0);
- if(s->size > 0) {
- msect = newMachoSect(ms, "__symbol_stub1");
- msect->addr = symaddr(s);
- msect->size = s->size;
- msect->off = ms->fileoffset + msect->addr - ms->vaddr;
- msect->flag = 0x80000408; /* flag */
- msect->res1 = 0; /* index into indirect symbol table */
- msect->res2 = 6; /* size of stubs */
+ if(linkmode != LinkExternal) {
+ ms = newMachoSeg("__TEXT", 20);
+ ms->vaddr = va;
+ ms->vsize = v;
+ ms->fileoffset = 0;
+ ms->filesize = v;
+ ms->prot1 = 7;
+ ms->prot2 = 5;
}
+ for(sect=segtext.sect; sect!=nil; sect=sect->next)
+ machoshbits(ms, sect, "__TEXT");
+
/* data */
- w = segdata.len;
- ms = newMachoSeg("__DATA", 3);
- ms->vaddr = va+v;
- ms->vsize = w;
- ms->fileoffset = v;
- ms->filesize = segdata.filelen;
- ms->prot1 = 7;
- ms->prot2 = 3;
-
- msect = newMachoSect(ms, "__data");
- msect->addr = va+v;
- msect->off = v;
- msect->size = segdata.filelen;
-
- s = lookup(".got", 0);
- if(s->size > 0) {
- msect->size = symaddr(s) - msect->addr;
-
- msect = newMachoSect(ms, "__nl_symbol_ptr");
- msect->addr = symaddr(s);
- msect->size = s->size;
- msect->off = datoff(msect->addr);
- msect->align = 2;
- msect->flag = 6; /* section with nonlazy symbol pointers */
- msect->res1 = lookup(".linkedit.plt", 0)->size / 4; /* offset into indirect symbol table */
+ if(linkmode != LinkExternal) {
+ w = segdata.len;
+ ms = newMachoSeg("__DATA", 20);
+ ms->vaddr = va+v;
+ ms->vsize = w;
+ ms->fileoffset = v;
+ ms->filesize = segdata.filelen;
+ ms->prot1 = 3;
+ ms->prot2 = 3;
}
- msect = newMachoSect(ms, "__bss");
- msect->addr = va+v+segdata.filelen;
- msect->size = segdata.len - segdata.filelen;
- msect->flag = 1; /* flag - zero fill */
+ for(sect=segdata.sect; sect!=nil; sect=sect->next)
+ machoshbits(ms, sect, "__DATA");
- switch(thechar) {
- default:
- diag("unknown macho architecture");
- errorexit();
- case '6':
- ml = newMachoLoad(5, 42+2); /* unix thread */
- ml->data[0] = 4; /* thread type */
- ml->data[1] = 42; /* word count */
- ml->data[2+32] = entryvalue(); /* start pc */
- ml->data[2+32+1] = entryvalue()>>16>>16; // hide >>32 for 8l
- break;
- case '8':
- ml = newMachoLoad(5, 16+2); /* unix thread */
- ml->data[0] = 1; /* thread type */
- ml->data[1] = 16; /* word count */
- ml->data[2+10] = entryvalue(); /* start pc */
- break;
+ if(linkmode != LinkExternal) {
+ switch(thechar) {
+ default:
+ diag("unknown macho architecture");
+ errorexit();
+ case '6':
+ ml = newMachoLoad(5, 42+2); /* unix thread */
+ ml->data[0] = 4; /* thread type */
+ ml->data[1] = 42; /* word count */
+ ml->data[2+32] = entryvalue(); /* start pc */
+ ml->data[2+32+1] = entryvalue()>>16>>16; // hide >>32 for 8l
+ break;
+ case '8':
+ ml = newMachoLoad(5, 16+2); /* unix thread */
+ ml->data[0] = 1; /* thread type */
+ ml->data[1] = 16; /* word count */
+ ml->data[2+10] = entryvalue(); /* start pc */
+ break;
+ }
}
-
+
if(!debug['d']) {
Sym *s1, *s2, *s3, *s4;
// must match domacholink below
- s1 = lookup(".dynsym", 0);
+ s1 = lookup(".machosymtab", 0);
s2 = lookup(".linkedit.plt", 0);
s3 = lookup(".linkedit.got", 0);
- s4 = lookup(".dynstr", 0);
-
- ms = newMachoSeg("__LINKEDIT", 0);
- ms->vaddr = va+v+rnd(segdata.len, INITRND);
- ms->vsize = s1->size + s2->size + s3->size + s4->size;
- ms->fileoffset = linkoff;
- ms->filesize = ms->vsize;
- ms->prot1 = 7;
- ms->prot2 = 3;
+ s4 = lookup(".machosymstr", 0);
+
+ if(linkmode != LinkExternal) {
+ ms = newMachoSeg("__LINKEDIT", 0);
+ ms->vaddr = va+v+rnd(segdata.len, INITRND);
+ ms->vsize = s1->size + s2->size + s3->size + s4->size;
+ ms->fileoffset = linkoff;
+ ms->filesize = ms->vsize;
+ ms->prot1 = 7;
+ ms->prot2 = 3;
+ }
ml = newMachoLoad(2, 4); /* LC_SYMTAB */
ml->data[0] = linkoff; /* symoff */
- ml->data[1] = s1->size / (macho64 ? 16 : 12); /* nsyms */
+ ml->data[1] = nsortsym; /* nsyms */
ml->data[2] = linkoff + s1->size + s2->size + s3->size; /* stroff */
ml->data[3] = s4->size; /* strsize */
- ml = newMachoLoad(11, 18); /* LC_DYSYMTAB */
- ml->data[0] = 0; /* ilocalsym */
- ml->data[1] = 0; /* nlocalsym */
- ml->data[2] = 0; /* iextdefsym */
- ml->data[3] = ndynexp; /* nextdefsym */
- ml->data[4] = ndynexp; /* iundefsym */
- ml->data[5] = (s1->size / (macho64 ? 16 : 12)) - ndynexp; /* nundefsym */
- ml->data[6] = 0; /* tocoffset */
- ml->data[7] = 0; /* ntoc */
- ml->data[8] = 0; /* modtaboff */
- ml->data[9] = 0; /* nmodtab */
- ml->data[10] = 0; /* extrefsymoff */
- ml->data[11] = 0; /* nextrefsyms */
- ml->data[12] = linkoff + s1->size; /* indirectsymoff */
- ml->data[13] = (s2->size + s3->size) / 4; /* nindirectsyms */
- ml->data[14] = 0; /* extreloff */
- ml->data[15] = 0; /* nextrel */
- ml->data[16] = 0; /* locreloff */
- ml->data[17] = 0; /* nlocrel */
-
- ml = newMachoLoad(14, 6); /* LC_LOAD_DYLINKER */
- ml->data[0] = 12; /* offset to string */
- strcpy((char*)&ml->data[1], "/usr/lib/dyld");
-
- for(i=0; i<ndylib; i++) {
- ml = newMachoLoad(12, 4+(strlen(dylib[i])+1+7)/8*2); /* LC_LOAD_DYLIB */
- ml->data[0] = 24; /* offset of string from beginning of load */
- ml->data[1] = 0; /* time stamp */
- ml->data[2] = 0; /* version */
- ml->data[3] = 0; /* compatibility version */
- strcpy((char*)&ml->data[4], dylib[i]);
+ machodysymtab();
+
+ if(linkmode != LinkExternal) {
+ ml = newMachoLoad(14, 6); /* LC_LOAD_DYLINKER */
+ ml->data[0] = 12; /* offset to string */
+ strcpy((char*)&ml->data[1], "/usr/lib/dyld");
+
+ for(i=0; i<ndylib; i++) {
+ ml = newMachoLoad(12, 4+(strlen(dylib[i])+1+7)/8*2); /* LC_LOAD_DYLIB */
+ ml->data[0] = 24; /* offset of string from beginning of load */
+ ml->data[1] = 0; /* time stamp */
+ ml->data[2] = 0; /* version */
+ ml->data[3] = 0; /* compatibility version */
+ strcpy((char*)&ml->data[4], dylib[i]);
+ }
}
}
- if(!debug['s']) {
- Sym *s;
-
- md = newMachoDebug();
- s = lookup("symtab", 0);
- md->fileoffset = datoff(s->value);
- md->filesize = s->size;
-
- md = newMachoDebug();
- s = lookup("pclntab", 0);
- md->fileoffset = datoff(s->value);
- md->filesize = s->size;
-
+ // TODO: dwarf headers go in ms too
+ if(!debug['s'] && linkmode != LinkExternal)
dwarfaddmachoheaders();
- }
a = machowrite();
if(a > HEADR)
diag("HEADR too small: %d > %d", a, HEADR);
}
+static int
+symkind(Sym *s)
+{
+ if(s->type == SDYNIMPORT)
+ return SymKindUndef;
+ if(s->cgoexport)
+ return SymKindExtdef;
+ return SymKindLocal;
+}
+
+static void
+addsym(Sym *s, char *name, int type, vlong addr, vlong size, int ver, Sym *gotype)
+{
+ USED(name);
+ USED(addr);
+ USED(size);
+ USED(ver);
+ USED(gotype);
+
+ if(s == nil)
+ return;
+
+ switch(type) {
+ default:
+ return;
+ case 'D':
+ case 'B':
+ case 'T':
+ break;
+ }
+
+ if(sortsym) {
+ sortsym[nsortsym] = s;
+ nkind[symkind(s)]++;
+ }
+ nsortsym++;
+}
+
+static int
+scmp(const void *p1, const void *p2)
+{
+ Sym *s1, *s2;
+ int k1, k2;
+
+ s1 = *(Sym**)p1;
+ s2 = *(Sym**)p2;
+
+ k1 = symkind(s1);
+ k2 = symkind(s2);
+ if(k1 != k2)
+ return k1 - k2;
+
+ return strcmp(s1->extname, s2->extname);
+}
+
+static void
+machogenasmsym(void (*put)(Sym*, char*, int, vlong, vlong, int, Sym*))
+{
+ Sym *s;
+
+ genasmsym(put);
+ for(s=allsym; s; s=s->allsym)
+ if(s->type == SDYNIMPORT || s->type == SHOSTOBJ)
+ if(s->reachable)
+ put(s, nil, 'D', 0, 0, 0, nil);
+}
+
+void
+machosymorder(void)
+{
+ int i;
+
+ // On Mac OS X Mountain Lion, we must sort exported symbols
+ // So we sort them here and pre-allocate dynid for them
+ // See http://golang.org/issue/4029
+ for(i=0; i<ndynexp; i++)
+ dynexp[i]->reachable = 1;
+ machogenasmsym(addsym);
+ sortsym = mal(nsortsym * sizeof sortsym[0]);
+ nsortsym = 0;
+ machogenasmsym(addsym);
+ qsort(sortsym, nsortsym, sizeof sortsym[0], scmp);
+ for(i=0; i<nsortsym; i++)
+ sortsym[i]->dynid = i;
+}
+
+static void
+machosymtab(void)
+{
+ int i;
+ Sym *symtab, *symstr, *s, *o;
+
+ symtab = lookup(".machosymtab", 0);
+ symstr = lookup(".machosymstr", 0);
+
+ for(i=0; i<nsortsym; i++) {
+ s = sortsym[i];
+ adduint32(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);
+ 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
+ } else {
+ if(s->cgoexport)
+ adduint8(symtab, 0x0f);
+ else
+ adduint8(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);
+ } else
+ adduint8(symtab, o->sect->extnum);
+ adduint16(symtab, 0); // desc
+ adduintxx(symtab, symaddr(s), PtrSize);
+ }
+ }
+}
+
+static void
+machodysymtab(void)
+{
+ int n;
+ MachoLoad *ml;
+ Sym *s1, *s2, *s3;
+
+ ml = newMachoLoad(11, 18); /* LC_DYSYMTAB */
+
+ n = 0;
+ ml->data[0] = n; /* ilocalsym */
+ ml->data[1] = nkind[SymKindLocal]; /* nlocalsym */
+ n += nkind[SymKindLocal];
+
+ ml->data[2] = n; /* iextdefsym */
+ ml->data[3] = nkind[SymKindExtdef]; /* nextdefsym */
+ n += nkind[SymKindExtdef];
+
+ ml->data[4] = n; /* iundefsym */
+ ml->data[5] = nkind[SymKindUndef]; /* nundefsym */
+
+ ml->data[6] = 0; /* tocoffset */
+ ml->data[7] = 0; /* ntoc */
+ ml->data[8] = 0; /* modtaboff */
+ ml->data[9] = 0; /* nmodtab */
+ ml->data[10] = 0; /* extrefsymoff */
+ ml->data[11] = 0; /* nextrefsyms */
+
+ // must match domacholink below
+ s1 = lookup(".machosymtab", 0);
+ s2 = lookup(".linkedit.plt", 0);
+ s3 = lookup(".linkedit.got", 0);
+ ml->data[12] = linkoff + s1->size; /* indirectsymoff */
+ ml->data[13] = (s2->size + s3->size) / 4; /* nindirectsyms */
+
+ ml->data[14] = 0; /* extreloff */
+ ml->data[15] = 0; /* nextrel */
+ ml->data[16] = 0; /* locreloff */
+ ml->data[17] = 0; /* nlocrel */
+}
+
vlong
domacholink(void)
{
int size;
Sym *s1, *s2, *s3, *s4;
+ machosymtab();
+
// write data that will be linkedit section
- s1 = lookup(".dynsym", 0);
- relocsym(s1);
+ s1 = lookup(".machosymtab", 0);
s2 = lookup(".linkedit.plt", 0);
s3 = lookup(".linkedit.got", 0);
- s4 = lookup(".dynstr", 0);
+ s4 = lookup(".machosymstr", 0);
// Force the linkedit section to end on a 16-byte
// boundary. This allows pure (non-cgo) Go binaries
@@ -533,3 +699,57 @@ domacholink(void)
return rnd(size, INITRND);
}
+
+
+void
+machorelocsect(Section *sect, Sym *first)
+{
+ Sym *sym;
+ int32 eaddr;
+ Reloc *r;
+
+ // If main section has no bits, nothing to relocate.
+ if(sect->vaddr >= sect->seg->vaddr + sect->seg->filelen)
+ return;
+
+ sect->reloff = cpos();
+ for(sym = first; sym != nil; sym = sym->next) {
+ if(!sym->reachable)
+ continue;
+ if(sym->value >= sect->vaddr)
+ break;
+ }
+
+ eaddr = sect->vaddr + sect->len;
+ for(; sym != nil; sym = sym->next) {
+ if(!sym->reachable)
+ continue;
+ if(sym->value >= eaddr)
+ break;
+ cursym = sym;
+
+ for(r = sym->r; r < sym->r+sym->nr; r++) {
+ if(r->done)
+ continue;
+ if(machoreloc1(r, sym->value+r->off - sect->vaddr) < 0)
+ diag("unsupported obj reloc %d/%d to %s", r->type, r->siz, r->sym->name);
+ }
+ }
+
+ sect->rellen = cpos() - sect->reloff;
+}
+
+void
+machoemitreloc(void)
+{
+ Section *sect;
+
+ while(cpos()&7)
+ cput(0);
+
+ machorelocsect(segtext.sect, textp);
+ for(sect=segtext.sect->next; sect!=nil; sect=sect->next)
+ machorelocsect(sect, datap);
+ for(sect=segdata.sect; sect!=nil; sect=sect->next)
+ machorelocsect(sect, datap);
+}
diff --git a/src/cmd/ld/macho.h b/src/cmd/ld/macho.h
index baea6ff03..d759f4b0f 100644
--- a/src/cmd/ld/macho.h
+++ b/src/cmd/ld/macho.h
@@ -11,6 +11,7 @@ struct MachoHdr {
typedef struct MachoSect MachoSect;
struct MachoSect {
char* name;
+ char* segname;
uint64 addr;
uint64 size;
uint32 off;
@@ -44,19 +45,15 @@ struct MachoLoad {
uint32 *data;
};
-typedef struct MachoDebug MachoDebug;
-struct MachoDebug {
- uint32 fileoffset;
- uint32 filesize;
-};
-
MachoHdr* getMachoHdr(void);
MachoSeg* newMachoSeg(char*, int);
-MachoSect* newMachoSect(MachoSeg*, char*);
+MachoSect* newMachoSect(MachoSeg*, char*, char*);
MachoLoad* newMachoLoad(uint32, uint32);
-MachoDebug* newMachoDebug(void);
int machowrite(void);
void machoinit(void);
+void machosymorder(void);
+void machoemitreloc(void);
+int machoreloc1(Reloc*, vlong);
/*
* Total amount of space to reserve at the start of the file
diff --git a/src/cmd/ld/pe.c b/src/cmd/ld/pe.c
index f2903ba0f..090d083f5 100644
--- a/src/cmd/ld/pe.c
+++ b/src/cmd/ld/pe.c
@@ -195,7 +195,7 @@ initdynimport(void)
dr = nil;
m = nil;
for(s = allsym; s != S; s = s->allsym) {
- if(!s->reachable || !s->dynimpname || s->dynexport)
+ if(!s->reachable || s->type != SDYNIMPORT)
continue;
for(d = dr; d != nil; d = d->next) {
if(strcmp(d->name,s->dynimplib) == 0) {
@@ -262,7 +262,7 @@ addimports(IMAGE_SECTION_HEADER *datsect)
for(m = d->ms; m != nil; m = m->next) {
m->off = nextsectoff + cpos() - startoff;
wputl(0); // hint
- strput(m->s->dynimpname);
+ strput(m->s->extname);
}
}
@@ -325,7 +325,7 @@ scmp(const void *p1, const void *p2)
s1 = *(Sym**)p1;
s2 = *(Sym**)p2;
- return strcmp(s1->dynimpname, s2->dynimpname);
+ return strcmp(s1->extname, s2->extname);
}
static void
@@ -335,7 +335,7 @@ initdynexport(void)
nexport = 0;
for(s = allsym; s != S; s = s->allsym) {
- if(!s->reachable || !s->dynimpname || !s->dynexport)
+ if(!s->reachable || !(s->cgoexport & CgoExportDynamic))
continue;
if(nexport+1 > sizeof(dexport)/sizeof(dexport[0])) {
diag("pe dynexport table is full");
@@ -358,7 +358,7 @@ addexports(void)
size = sizeof e + 10*nexport + strlen(outfile) + 1;
for(i=0; i<nexport; i++)
- size += strlen(dexport[i]->dynimpname) + 1;
+ size += strlen(dexport[i]->extname) + 1;
if (nexport == 0)
return;
@@ -394,7 +394,7 @@ addexports(void)
v = e.Name + strlen(outfile)+1;
for(i=0; i<nexport; i++) {
lputl(v);
- v += strlen(dexport[i]->dynimpname)+1;
+ v += strlen(dexport[i]->extname)+1;
}
// put EXPORT Ordinal Table
for(i=0; i<nexport; i++)
@@ -402,7 +402,7 @@ addexports(void)
// put Names
strnput(outfile, strlen(outfile)+1);
for(i=0; i<nexport; i++)
- strnput(dexport[i]->dynimpname, strlen(dexport[i]->dynimpname)+1);
+ strnput(dexport[i]->extname, strlen(dexport[i]->extname)+1);
strnput("", sect->SizeOfRawData - size);
}
diff --git a/src/cmd/ld/symtab.c b/src/cmd/ld/symtab.c
index 89a594872..698194f84 100644
--- a/src/cmd/ld/symtab.c
+++ b/src/cmd/ld/symtab.c
@@ -121,12 +121,22 @@ putelfsym(Sym *x, char *s, int t, vlong addr, vlong size, int ver, Sym *go)
// One pass for each binding: STB_LOCAL, STB_GLOBAL,
// maybe one day STB_WEAK.
- bind = (ver || (x->type & SHIDDEN)) ? STB_LOCAL : STB_GLOBAL;
+ bind = STB_GLOBAL;
+ if(ver || (x->type & SHIDDEN))
+ bind = STB_LOCAL;
+
+ // In external linking mode, we have to invoke gcc with -rdynamic
+ // to get the exported symbols put into the dynamic symbol table.
+ // To avoid filling the dynamic table with lots of unnecessary symbols,
+ // mark all Go symbols local (not global) in the final executable.
+ if(linkmode == LinkExternal && !(x->cgoexport&CgoExportStatic))
+ bind = STB_LOCAL;
+
if(bind != elfbind)
return;
off = putelfstr(s);
- if(isobj)
+ if(linkmode == LinkExternal)
addr -= xo->sect->vaddr;
putelfsyment(off, addr, size, (bind<<4)|(type&0xf), xo->sect->elfsect->shnum, (x->type & SHIDDEN) ? 2 : 0);
x->elfsym = numelfsym++;
@@ -424,10 +434,8 @@ symtab(void)
xdefine("datarelro", SDATARELRO, 0);
xdefine("edatarelro", SDATARELRO, 0);
}
- xdefine("gcdata", SGCDATA, 0);
- xdefine("egcdata", SGCDATA, 0);
- xdefine("gcbss", SGCBSS, 0);
- xdefine("egcbss", SGCBSS, 0);
+ xdefine("egcdata", STYPE, 0);
+ xdefine("egcbss", STYPE, 0);
xdefine("noptrdata", SNOPTRDATA, 0);
xdefine("enoptrdata", SNOPTRDATA, 0);
xdefine("data", SDATA, 0);