From 825b1e15916833ff6b2affdb5b0bb7c5c908ac52 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Tue, 30 Apr 2013 14:01:05 -0700 Subject: [PATCH] cmd/ld: emit relocs for DWARF info when doing an external link I would like opinions on whether this is a good idea for 1.1. On the one hand it's a moderately important issue. On the other hand this introduces at least the possibility of external linker errors due to the additional relocations and it may be better to wait. I'm fairly confident that the behaviour is unchanged when not using an external linker. Update #5221 This CL is tested lightly on 386 and amd64 and fixes the cases I tested. I have not tested it on Darwin or Windows. R=golang-dev, dave, daniel.morsing, rsc CC=golang-dev https://golang.org/cl/8858047 --- src/cmd/ld/dwarf.c | 227 ++++++++++++++++++++++++++++++++++++++------ src/cmd/ld/elf.c | 4 +- src/cmd/ld/elf.h | 5 +- src/cmd/ld/lib.h | 2 + src/cmd/ld/symtab.c | 27 ++++++ 5 files changed, 230 insertions(+), 35 deletions(-) diff --git a/src/cmd/ld/dwarf.c b/src/cmd/ld/dwarf.c index 436e1e67ef..79f1ebb711 100644 --- a/src/cmd/ld/dwarf.c +++ b/src/cmd/ld/dwarf.c @@ -27,10 +27,16 @@ static vlong abbrevo; static vlong abbrevsize; +static Sym* abbrevsym; +static vlong abbrevsympos; static vlong lineo; static vlong linesize; +static Sym* linesym; +static vlong linesympos; static vlong infoo; // also the base for DWDie->offs and reference attributes. static vlong infosize; +static Sym* infosym; +static vlong infosympos; static vlong frameo; static vlong framesize; static vlong pubnameso; @@ -41,12 +47,20 @@ static vlong arangeso; static vlong arangessize; static vlong gdbscripto; static vlong gdbscriptsize; + +static Sym *infosec; static vlong inforeloco; static vlong inforelocsize; -static char gdbscript[1024]; +static Sym *arangessec; +static vlong arangesreloco; +static vlong arangesrelocsize; -static Sym *dsym; +static Sym *linesec; +static vlong linereloco; +static vlong linerelocsize; + +static char gdbscript[1024]; /* * Basic I/O @@ -573,6 +587,34 @@ find_or_diag(DWDie *die, char* name) return r; } +static void +adddwarfrel(Sym* sec, Sym* sym, vlong offsetbase, int siz, vlong addend) +{ + Reloc *r; + + r = addrel(sec); + r->sym = sym; + r->xsym = sym; + r->off = cpos() - offsetbase; + r->siz = siz; + r->type = D_ADDR; + r->add = addend; + r->xadd = addend; + if(iself && thechar == '6') + addend = 0; + switch(siz) { + case 4: + LPUT(addend); + break; + case 8: + VPUT(addend); + break; + default: + diag("bad size in adddwarfrel"); + break; + } +} + static DWAttr* newrefattr(DWDie *die, uint8 attr, DWDie* ref) { @@ -586,10 +628,15 @@ static int fwdcount; static void putattr(int abbrev, int form, int cls, vlong value, char *data) { - Reloc *r; + vlong off; switch(form) { case DW_FORM_addr: // address + if(linkmode == LinkExternal) { + value -= ((Sym*)data)->value; + adddwarfrel(infosec, (Sym*)data, infoo, PtrSize, value); + break; + } addrput(value); break; @@ -598,15 +645,9 @@ putattr(int abbrev, int form, int cls, vlong value, char *data) 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; + value -= ((Sym*)data)->value; + adddwarfrel(infosec, (Sym*)data, infoo, PtrSize, value); + break; } addrput(value); break; @@ -646,6 +687,10 @@ putattr(int abbrev, int form, int cls, vlong value, char *data) break; case DW_FORM_data4: // constant, {line,loclist,mac,rangelist}ptr + if(linkmode == LinkExternal && cls == DW_CLS_PTR) { + adddwarfrel(infosec, linesym, infoo, 4, value); + break; + } LPUT(value); break; @@ -681,12 +726,14 @@ putattr(int abbrev, int form, int cls, vlong value, char *data) else LPUT(0); // invalid dwarf, gdb will complain. } else { - if (((DWDie*)data)->offs == 0) + off = ((DWDie*)data)->offs; + if (off == 0) fwdcount++; - if(PtrSize == 8) - VPUT(((DWDie*)data)->offs); - else - LPUT(((DWDie*)data)->offs); + if(linkmode == LinkExternal) { + adddwarfrel(infosec, infosym, infoo, PtrSize, off); + break; + } + addrput(off); } break; @@ -1703,6 +1750,10 @@ writelines(void) DWDie *varhash[HASHSIZE]; char *n, *nn; + if(linesec == S) + linesec = lookup(".dwarfline", 0); + linesec->nr = 0; + unitstart = -1; headerend = -1; pc = 0; @@ -1777,7 +1828,11 @@ writelines(void) cput(0); // start extended opcode uleb128put(1 + PtrSize); cput(DW_LNE_set_address); - addrput(pc); + + if(linkmode == LinkExternal) + adddwarfrel(linesec, s, lineo, PtrSize, 0); + else + addrput(pc); } if(s->text == nil) continue; @@ -1996,9 +2051,13 @@ writeinfo(void) vlong unitstart, here; fwdcount = 0; - if (dsym == S) - dsym = lookup(".dwarfinfo", 0); - dsym->nr = 0; + if (infosec == S) + infosec = lookup(".dwarfinfo", 0); + infosec->nr = 0; + + if(arangessec == S) + arangessec = lookup(".dwarfaranges", 0); + arangessec->nr = 0; for (compunit = dwroot.child; compunit; compunit = compunit->link) { unitstart = cpos(); @@ -2008,7 +2067,13 @@ writeinfo(void) // This must match COMPUNITHEADERSIZE above. LPUT(0); // unit_length (*), will be filled in later. WPUT(2); // dwarf version (appendix F) - LPUT(0); // debug_abbrev_offset (*) + + // debug_abbrev_offset (*) + if(linkmode == LinkExternal) + adddwarfrel(infosec, abbrevsym, infoo, 4, 0); + else + LPUT(0); + cput(PtrSize); // address_size putdie(compunit); @@ -2096,6 +2161,7 @@ writearanges(void) DWAttr *b, *e; int headersize; vlong sectionstart; + vlong value; sectionstart = cpos(); headersize = rnd(4+2+4+1+1, PtrSize); // don't count unit_length field itself @@ -2111,12 +2177,22 @@ writearanges(void) // Write .debug_aranges Header + entry (sec 6.1.2) LPUT(headersize + 4*PtrSize - 4); // unit_length (*) WPUT(2); // dwarf version (appendix F) - LPUT(compunit->offs - COMPUNITHEADERSIZE); // debug_info_offset + + value = compunit->offs - COMPUNITHEADERSIZE; // debug_info_offset + if(linkmode == LinkExternal) + adddwarfrel(arangessec, infosym, sectionstart, 4, value); + else + LPUT(value); + cput(PtrSize); // address_size cput(0); // segment_size strnput("", headersize - (4+2+4+1+1)); // align to PtrSize - addrput(b->value); + if(linkmode == LinkExternal) + adddwarfrel(arangessec, (Sym*)b->data, sectionstart, PtrSize, b->value-((Sym*)b->data)->value); + else + addrput(b->value); + addrput(e->value - b->value); addrput(0); addrput(0); @@ -2148,14 +2224,14 @@ align(vlong size) } static vlong -writeinforeloc(void) +writedwarfreloc(Sym* s) { int i; vlong start; Reloc *r; start = cpos(); - for(r = dsym->r; r < dsym->r+dsym->nr; r++) { + for(r = s->r; r < s->r+s->nr; r++) { if(iself) i = elfreloc1(r, r->off); else if(HEADTYPE == Hdarwin) @@ -2267,10 +2343,20 @@ dwarfemitdebugsections(void) gdbscripto = writegdbscript(); gdbscriptsize = cpos() - gdbscripto; align(gdbscriptsize); - - inforeloco = writeinforeloc(); + + while(cpos()&7) + cput(0); + inforeloco = writedwarfreloc(infosec); inforelocsize = cpos() - inforeloco; align(inforelocsize); + + arangesreloco = writedwarfreloc(arangessec); + arangesrelocsize = cpos() - arangesreloco; + align(arangesrelocsize); + + linereloco = writedwarfreloc(linesec); + linerelocsize = cpos() - linereloco; + align(linerelocsize); } /* @@ -2290,6 +2376,9 @@ enum ElfStrDebugRanges, ElfStrDebugStr, ElfStrGDBScripts, + ElfStrRelDebugInfo, + ElfStrRelDebugAranges, + ElfStrRelDebugLine, NElfStrDbg }; @@ -2313,13 +2402,72 @@ dwarfaddshstrings(Sym *shstrtab) elfstrdbg[ElfStrDebugRanges] = addstring(shstrtab, ".debug_ranges"); elfstrdbg[ElfStrDebugStr] = addstring(shstrtab, ".debug_str"); elfstrdbg[ElfStrGDBScripts] = addstring(shstrtab, ".debug_gdb_scripts"); + if(linkmode == LinkExternal) { + if(thechar == '6') { + elfstrdbg[ElfStrRelDebugInfo] = addstring(shstrtab, ".rela.debug_info"); + elfstrdbg[ElfStrRelDebugAranges] = addstring(shstrtab, ".rela.debug_aranges"); + elfstrdbg[ElfStrRelDebugLine] = addstring(shstrtab, ".rela.debug_line"); + } else { + elfstrdbg[ElfStrRelDebugInfo] = addstring(shstrtab, ".rel.debug_info"); + elfstrdbg[ElfStrRelDebugAranges] = addstring(shstrtab, ".rel.debug_aranges"); + elfstrdbg[ElfStrRelDebugLine] = addstring(shstrtab, ".rel.debug_line"); + } + + infosym = lookup(".debug_info", 0); + infosym->hide = 1; + + abbrevsym = lookup(".debug_abbrev", 0); + abbrevsym->hide = 1; + + linesym = lookup(".debug_line", 0); + linesym->hide = 1; + } } +// Add section symbols for DWARF debug info. This is called before +// dwarfaddelfheaders. void -dwarfaddelfheaders(void) +dwarfaddelfsectionsyms() +{ + if(infosym != nil) { + infosympos = cpos(); + putelfsectionsym(infosym, 0); + } + if(abbrevsym != nil) { + abbrevsympos = cpos(); + putelfsectionsym(abbrevsym, 0); + } + if(linesym != nil) { + linesympos = cpos(); + putelfsectionsym(linesym, 0); + } +} + +static void +dwarfaddelfrelocheader(int elfstr, ElfShdr *shdata, vlong off, vlong size) { ElfShdr *sh; + sh = newElfShdr(elfstrdbg[elfstr]); + if(thechar == '6') { + sh->type = SHT_RELA; + } else { + sh->type = SHT_REL; + } + sh->entsize = PtrSize*(2+(sh->type==SHT_RELA)); + sh->link = elfshname(".symtab")->shnum; + sh->info = shdata->shnum; + sh->off = off; + sh->size = size; + sh->addralign = PtrSize; + +} + +void +dwarfaddelfheaders(void) +{ + ElfShdr *sh, *shinfo, *sharanges, *shline; + if(debug['w']) // disable dwarf return; @@ -2328,12 +2476,17 @@ dwarfaddelfheaders(void) sh->off = abbrevo; sh->size = abbrevsize; sh->addralign = 1; + if(abbrevsympos > 0) + putelfsymshndx(abbrevsympos, sh->shnum); sh = newElfShdr(elfstrdbg[ElfStrDebugLine]); sh->type = SHT_PROGBITS; sh->off = lineo; sh->size = linesize; sh->addralign = 1; + if(linesympos > 0) + putelfsymshndx(linesympos, sh->shnum); + shline = sh; sh = newElfShdr(elfstrdbg[ElfStrDebugFrame]); sh->type = SHT_PROGBITS; @@ -2346,6 +2499,9 @@ dwarfaddelfheaders(void) sh->off = infoo; sh->size = infosize; sh->addralign = 1; + if(infosympos > 0) + putelfsymshndx(infosympos, sh->shnum); + shinfo = sh; if (pubnamessize > 0) { sh = newElfShdr(elfstrdbg[ElfStrDebugPubNames]); @@ -2363,12 +2519,14 @@ dwarfaddelfheaders(void) sh->addralign = 1; } + sharanges = nil; if (arangessize) { sh = newElfShdr(elfstrdbg[ElfStrDebugAranges]); sh->type = SHT_PROGBITS; sh->off = arangeso; sh->size = arangessize; sh->addralign = 1; + sharanges = sh; } if (gdbscriptsize) { @@ -2378,6 +2536,15 @@ dwarfaddelfheaders(void) sh->size = gdbscriptsize; sh->addralign = 1; } + + if(inforelocsize) + dwarfaddelfrelocheader(ElfStrRelDebugInfo, shinfo, inforeloco, inforelocsize); + + if(arangesrelocsize) + dwarfaddelfrelocheader(ElfStrRelDebugAranges, sharanges, arangesreloco, arangesrelocsize); + + if(linerelocsize) + dwarfaddelfrelocheader(ElfStrRelDebugLine, shline, linereloco, linerelocsize); } /* @@ -2430,8 +2597,6 @@ dwarfaddmachoheaders(void) 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) { diff --git a/src/cmd/ld/elf.c b/src/cmd/ld/elf.c index 056f95b9cc..0d1b712ce8 100644 --- a/src/cmd/ld/elf.c +++ b/src/cmd/ld/elf.c @@ -1421,9 +1421,7 @@ elfobj: sh->size = elfstrsize; sh->addralign = 1; - // TODO(rsc): Enable for linkmode == LinkExternal too, once we know it works. - if(linkmode != LinkExternal) - dwarfaddelfheaders(); + dwarfaddelfheaders(); } /* Main header */ diff --git a/src/cmd/ld/elf.h b/src/cmd/ld/elf.h index 336fab4b4b..24c0ac43e0 100644 --- a/src/cmd/ld/elf.h +++ b/src/cmd/ld/elf.h @@ -855,7 +855,8 @@ struct Elf64_Shdr { Elf64_Xword addralign; /* Alignment in bytes. */ Elf64_Xword entsize; /* Size of each entry in section. */ - int shnum; /* section number, not stored on disk */ + int shnum; /* section number, not stored on disk */ + Sym* secsym; /* section symbol, if needed; not on disk */ }; /* @@ -998,6 +999,7 @@ void phsh(ElfPhdr*, ElfShdr*); void doelf(void); void elfsetupplt(void); void dwarfaddshstrings(Sym*); +void dwarfaddelfsectionsyms(void); void dwarfaddelfheaders(void); void asmbelf(vlong symo); void asmbelfsetup(void); @@ -1006,6 +1008,7 @@ extern char freebsddynld[]; extern char netbsddynld[]; extern char openbsddynld[]; int elfreloc1(Reloc*, vlong sectoff); +void putelfsectionsyms(void); EXTERN int elfstrsize; EXTERN char* elfstrdat; diff --git a/src/cmd/ld/lib.h b/src/cmd/ld/lib.h index 5b077e381f..e552deb02f 100644 --- a/src/cmd/ld/lib.h +++ b/src/cmd/ld/lib.h @@ -249,6 +249,8 @@ void setuint64(Sym*, vlong, uint64); void asmsym(void); void asmelfsym(void); void asmplan9sym(void); +void putelfsectionsym(Sym*, int); +void putelfsymshndx(vlong, int); void strnput(char*, int); void dodata(void); void dosymtype(void); diff --git a/src/cmd/ld/symtab.c b/src/cmd/ld/symtab.c index 01b92910e2..7c8ba642fb 100644 --- a/src/cmd/ld/symtab.c +++ b/src/cmd/ld/symtab.c @@ -142,6 +142,31 @@ putelfsym(Sym *x, char *s, int t, vlong addr, vlong size, int ver, Sym *go) x->elfsym = numelfsym++; } +void +putelfsectionsym(Sym* s, int shndx) +{ + putelfsyment(0, 0, 0, (STB_LOCAL<<4)|STT_SECTION, shndx, 0); + s->elfsym = numelfsym++; +} + +void +putelfsymshndx(vlong sympos, int shndx) +{ + vlong here; + + here = cpos(); + switch(thechar) { + case '6': + cseek(sympos+6); + break; + default: + cseek(sympos+14); + break; + } + WPUT(shndx); + cseek(here); +} + void asmelfsym(void) { @@ -150,6 +175,8 @@ asmelfsym(void) // the first symbol entry is reserved putelfsyment(0, 0, 0, (STB_LOCAL<<4)|STT_NOTYPE, 0, 0); + dwarfaddelfsectionsyms(); + elfbind = STB_LOCAL; genasmsym(putelfsym); -- 2.48.1