diff options
Diffstat (limited to 'src/cmd/ld/data.c')
-rw-r--r-- | src/cmd/ld/data.c | 334 |
1 files changed, 194 insertions, 140 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); |