Commit 825b1e15 authored by Ian Lance Taylor's avatar Ian Lance Taylor

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
parent b461c94c
...@@ -27,10 +27,16 @@ ...@@ -27,10 +27,16 @@
static vlong abbrevo; static vlong abbrevo;
static vlong abbrevsize; static vlong abbrevsize;
static Sym* abbrevsym;
static vlong abbrevsympos;
static vlong lineo; static vlong lineo;
static vlong linesize; static vlong linesize;
static Sym* linesym;
static vlong linesympos;
static vlong infoo; // also the base for DWDie->offs and reference attributes. static vlong infoo; // also the base for DWDie->offs and reference attributes.
static vlong infosize; static vlong infosize;
static Sym* infosym;
static vlong infosympos;
static vlong frameo; static vlong frameo;
static vlong framesize; static vlong framesize;
static vlong pubnameso; static vlong pubnameso;
...@@ -41,12 +47,20 @@ static vlong arangeso; ...@@ -41,12 +47,20 @@ static vlong arangeso;
static vlong arangessize; static vlong arangessize;
static vlong gdbscripto; static vlong gdbscripto;
static vlong gdbscriptsize; static vlong gdbscriptsize;
static Sym *infosec;
static vlong inforeloco; static vlong inforeloco;
static vlong inforelocsize; 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 * Basic I/O
...@@ -573,6 +587,34 @@ find_or_diag(DWDie *die, char* name) ...@@ -573,6 +587,34 @@ find_or_diag(DWDie *die, char* name)
return r; 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* static DWAttr*
newrefattr(DWDie *die, uint8 attr, DWDie* ref) newrefattr(DWDie *die, uint8 attr, DWDie* ref)
{ {
...@@ -586,10 +628,15 @@ static int fwdcount; ...@@ -586,10 +628,15 @@ static int fwdcount;
static void static void
putattr(int abbrev, int form, int cls, vlong value, char *data) putattr(int abbrev, int form, int cls, vlong value, char *data)
{ {
Reloc *r; vlong off;
switch(form) { switch(form) {
case DW_FORM_addr: // address case DW_FORM_addr: // address
if(linkmode == LinkExternal) {
value -= ((Sym*)data)->value;
adddwarfrel(infosec, (Sym*)data, infoo, PtrSize, value);
break;
}
addrput(value); addrput(value);
break; break;
...@@ -598,15 +645,9 @@ putattr(int abbrev, int form, int cls, vlong value, char *data) ...@@ -598,15 +645,9 @@ putattr(int abbrev, int form, int cls, vlong value, char *data)
cput(1+PtrSize); cput(1+PtrSize);
cput(DW_OP_addr); cput(DW_OP_addr);
if(linkmode == LinkExternal) { if(linkmode == LinkExternal) {
r = addrel(dsym); value -= ((Sym*)data)->value;
r->sym = (Sym*)data; adddwarfrel(infosec, (Sym*)data, infoo, PtrSize, value);
r->xsym = r->sym; break;
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); addrput(value);
break; break;
...@@ -646,6 +687,10 @@ putattr(int abbrev, int form, int cls, vlong value, char *data) ...@@ -646,6 +687,10 @@ putattr(int abbrev, int form, int cls, vlong value, char *data)
break; break;
case DW_FORM_data4: // constant, {line,loclist,mac,rangelist}ptr 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); LPUT(value);
break; break;
...@@ -681,12 +726,14 @@ putattr(int abbrev, int form, int cls, vlong value, char *data) ...@@ -681,12 +726,14 @@ putattr(int abbrev, int form, int cls, vlong value, char *data)
else else
LPUT(0); // invalid dwarf, gdb will complain. LPUT(0); // invalid dwarf, gdb will complain.
} else { } else {
if (((DWDie*)data)->offs == 0) off = ((DWDie*)data)->offs;
if (off == 0)
fwdcount++; fwdcount++;
if(PtrSize == 8) if(linkmode == LinkExternal) {
VPUT(((DWDie*)data)->offs); adddwarfrel(infosec, infosym, infoo, PtrSize, off);
else break;
LPUT(((DWDie*)data)->offs); }
addrput(off);
} }
break; break;
...@@ -1703,6 +1750,10 @@ writelines(void) ...@@ -1703,6 +1750,10 @@ writelines(void)
DWDie *varhash[HASHSIZE]; DWDie *varhash[HASHSIZE];
char *n, *nn; char *n, *nn;
if(linesec == S)
linesec = lookup(".dwarfline", 0);
linesec->nr = 0;
unitstart = -1; unitstart = -1;
headerend = -1; headerend = -1;
pc = 0; pc = 0;
...@@ -1777,7 +1828,11 @@ writelines(void) ...@@ -1777,7 +1828,11 @@ writelines(void)
cput(0); // start extended opcode cput(0); // start extended opcode
uleb128put(1 + PtrSize); uleb128put(1 + PtrSize);
cput(DW_LNE_set_address); cput(DW_LNE_set_address);
addrput(pc);
if(linkmode == LinkExternal)
adddwarfrel(linesec, s, lineo, PtrSize, 0);
else
addrput(pc);
} }
if(s->text == nil) if(s->text == nil)
continue; continue;
...@@ -1996,9 +2051,13 @@ writeinfo(void) ...@@ -1996,9 +2051,13 @@ writeinfo(void)
vlong unitstart, here; vlong unitstart, here;
fwdcount = 0; fwdcount = 0;
if (dsym == S) if (infosec == S)
dsym = lookup(".dwarfinfo", 0); infosec = lookup(".dwarfinfo", 0);
dsym->nr = 0; infosec->nr = 0;
if(arangessec == S)
arangessec = lookup(".dwarfaranges", 0);
arangessec->nr = 0;
for (compunit = dwroot.child; compunit; compunit = compunit->link) { for (compunit = dwroot.child; compunit; compunit = compunit->link) {
unitstart = cpos(); unitstart = cpos();
...@@ -2008,7 +2067,13 @@ writeinfo(void) ...@@ -2008,7 +2067,13 @@ writeinfo(void)
// This must match COMPUNITHEADERSIZE above. // This must match COMPUNITHEADERSIZE above.
LPUT(0); // unit_length (*), will be filled in later. LPUT(0); // unit_length (*), will be filled in later.
WPUT(2); // dwarf version (appendix F) 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 cput(PtrSize); // address_size
putdie(compunit); putdie(compunit);
...@@ -2096,6 +2161,7 @@ writearanges(void) ...@@ -2096,6 +2161,7 @@ writearanges(void)
DWAttr *b, *e; DWAttr *b, *e;
int headersize; int headersize;
vlong sectionstart; vlong sectionstart;
vlong value;
sectionstart = cpos(); sectionstart = cpos();
headersize = rnd(4+2+4+1+1, PtrSize); // don't count unit_length field itself headersize = rnd(4+2+4+1+1, PtrSize); // don't count unit_length field itself
...@@ -2111,12 +2177,22 @@ writearanges(void) ...@@ -2111,12 +2177,22 @@ writearanges(void)
// Write .debug_aranges Header + entry (sec 6.1.2) // Write .debug_aranges Header + entry (sec 6.1.2)
LPUT(headersize + 4*PtrSize - 4); // unit_length (*) LPUT(headersize + 4*PtrSize - 4); // unit_length (*)
WPUT(2); // dwarf version (appendix F) 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(PtrSize); // address_size
cput(0); // segment_size cput(0); // segment_size
strnput("", headersize - (4+2+4+1+1)); // align to PtrSize 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(e->value - b->value);
addrput(0); addrput(0);
addrput(0); addrput(0);
...@@ -2148,14 +2224,14 @@ align(vlong size) ...@@ -2148,14 +2224,14 @@ align(vlong size)
} }
static vlong static vlong
writeinforeloc(void) writedwarfreloc(Sym* s)
{ {
int i; int i;
vlong start; vlong start;
Reloc *r; Reloc *r;
start = cpos(); start = cpos();
for(r = dsym->r; r < dsym->r+dsym->nr; r++) { for(r = s->r; r < s->r+s->nr; r++) {
if(iself) if(iself)
i = elfreloc1(r, r->off); i = elfreloc1(r, r->off);
else if(HEADTYPE == Hdarwin) else if(HEADTYPE == Hdarwin)
...@@ -2267,10 +2343,20 @@ dwarfemitdebugsections(void) ...@@ -2267,10 +2343,20 @@ dwarfemitdebugsections(void)
gdbscripto = writegdbscript(); gdbscripto = writegdbscript();
gdbscriptsize = cpos() - gdbscripto; gdbscriptsize = cpos() - gdbscripto;
align(gdbscriptsize); align(gdbscriptsize);
inforeloco = writeinforeloc(); while(cpos()&7)
cput(0);
inforeloco = writedwarfreloc(infosec);
inforelocsize = cpos() - inforeloco; inforelocsize = cpos() - inforeloco;
align(inforelocsize); align(inforelocsize);
arangesreloco = writedwarfreloc(arangessec);
arangesrelocsize = cpos() - arangesreloco;
align(arangesrelocsize);
linereloco = writedwarfreloc(linesec);
linerelocsize = cpos() - linereloco;
align(linerelocsize);
} }
/* /*
...@@ -2290,6 +2376,9 @@ enum ...@@ -2290,6 +2376,9 @@ enum
ElfStrDebugRanges, ElfStrDebugRanges,
ElfStrDebugStr, ElfStrDebugStr,
ElfStrGDBScripts, ElfStrGDBScripts,
ElfStrRelDebugInfo,
ElfStrRelDebugAranges,
ElfStrRelDebugLine,
NElfStrDbg NElfStrDbg
}; };
...@@ -2313,13 +2402,72 @@ dwarfaddshstrings(Sym *shstrtab) ...@@ -2313,13 +2402,72 @@ dwarfaddshstrings(Sym *shstrtab)
elfstrdbg[ElfStrDebugRanges] = addstring(shstrtab, ".debug_ranges"); elfstrdbg[ElfStrDebugRanges] = addstring(shstrtab, ".debug_ranges");
elfstrdbg[ElfStrDebugStr] = addstring(shstrtab, ".debug_str"); elfstrdbg[ElfStrDebugStr] = addstring(shstrtab, ".debug_str");
elfstrdbg[ElfStrGDBScripts] = addstring(shstrtab, ".debug_gdb_scripts"); 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 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; 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 if(debug['w']) // disable dwarf
return; return;
...@@ -2328,12 +2476,17 @@ dwarfaddelfheaders(void) ...@@ -2328,12 +2476,17 @@ dwarfaddelfheaders(void)
sh->off = abbrevo; sh->off = abbrevo;
sh->size = abbrevsize; sh->size = abbrevsize;
sh->addralign = 1; sh->addralign = 1;
if(abbrevsympos > 0)
putelfsymshndx(abbrevsympos, sh->shnum);
sh = newElfShdr(elfstrdbg[ElfStrDebugLine]); sh = newElfShdr(elfstrdbg[ElfStrDebugLine]);
sh->type = SHT_PROGBITS; sh->type = SHT_PROGBITS;
sh->off = lineo; sh->off = lineo;
sh->size = linesize; sh->size = linesize;
sh->addralign = 1; sh->addralign = 1;
if(linesympos > 0)
putelfsymshndx(linesympos, sh->shnum);
shline = sh;
sh = newElfShdr(elfstrdbg[ElfStrDebugFrame]); sh = newElfShdr(elfstrdbg[ElfStrDebugFrame]);
sh->type = SHT_PROGBITS; sh->type = SHT_PROGBITS;
...@@ -2346,6 +2499,9 @@ dwarfaddelfheaders(void) ...@@ -2346,6 +2499,9 @@ dwarfaddelfheaders(void)
sh->off = infoo; sh->off = infoo;
sh->size = infosize; sh->size = infosize;
sh->addralign = 1; sh->addralign = 1;
if(infosympos > 0)
putelfsymshndx(infosympos, sh->shnum);
shinfo = sh;
if (pubnamessize > 0) { if (pubnamessize > 0) {
sh = newElfShdr(elfstrdbg[ElfStrDebugPubNames]); sh = newElfShdr(elfstrdbg[ElfStrDebugPubNames]);
...@@ -2363,12 +2519,14 @@ dwarfaddelfheaders(void) ...@@ -2363,12 +2519,14 @@ dwarfaddelfheaders(void)
sh->addralign = 1; sh->addralign = 1;
} }
sharanges = nil;
if (arangessize) { if (arangessize) {
sh = newElfShdr(elfstrdbg[ElfStrDebugAranges]); sh = newElfShdr(elfstrdbg[ElfStrDebugAranges]);
sh->type = SHT_PROGBITS; sh->type = SHT_PROGBITS;
sh->off = arangeso; sh->off = arangeso;
sh->size = arangessize; sh->size = arangessize;
sh->addralign = 1; sh->addralign = 1;
sharanges = sh;
} }
if (gdbscriptsize) { if (gdbscriptsize) {
...@@ -2378,6 +2536,15 @@ dwarfaddelfheaders(void) ...@@ -2378,6 +2536,15 @@ dwarfaddelfheaders(void)
sh->size = gdbscriptsize; sh->size = gdbscriptsize;
sh->addralign = 1; 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) ...@@ -2430,8 +2597,6 @@ dwarfaddmachoheaders(void)
msect = newMachoSect(ms, "__debug_info", "__DWARF"); msect = newMachoSect(ms, "__debug_info", "__DWARF");
msect->off = infoo; msect->off = infoo;
msect->size = infosize; msect->size = infosize;
msect->reloc = inforeloco;
msect->nreloc = inforelocsize / 8;
ms->filesize += msect->size; ms->filesize += msect->size;
if (pubnamessize > 0) { if (pubnamessize > 0) {
......
...@@ -1421,9 +1421,7 @@ elfobj: ...@@ -1421,9 +1421,7 @@ elfobj:
sh->size = elfstrsize; sh->size = elfstrsize;
sh->addralign = 1; sh->addralign = 1;
// TODO(rsc): Enable for linkmode == LinkExternal too, once we know it works. dwarfaddelfheaders();
if(linkmode != LinkExternal)
dwarfaddelfheaders();
} }
/* Main header */ /* Main header */
......
...@@ -855,7 +855,8 @@ struct Elf64_Shdr { ...@@ -855,7 +855,8 @@ struct Elf64_Shdr {
Elf64_Xword addralign; /* Alignment in bytes. */ Elf64_Xword addralign; /* Alignment in bytes. */
Elf64_Xword entsize; /* Size of each entry in section. */ 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*); ...@@ -998,6 +999,7 @@ void phsh(ElfPhdr*, ElfShdr*);
void doelf(void); void doelf(void);
void elfsetupplt(void); void elfsetupplt(void);
void dwarfaddshstrings(Sym*); void dwarfaddshstrings(Sym*);
void dwarfaddelfsectionsyms(void);
void dwarfaddelfheaders(void); void dwarfaddelfheaders(void);
void asmbelf(vlong symo); void asmbelf(vlong symo);
void asmbelfsetup(void); void asmbelfsetup(void);
...@@ -1006,6 +1008,7 @@ extern char freebsddynld[]; ...@@ -1006,6 +1008,7 @@ extern char freebsddynld[];
extern char netbsddynld[]; extern char netbsddynld[];
extern char openbsddynld[]; extern char openbsddynld[];
int elfreloc1(Reloc*, vlong sectoff); int elfreloc1(Reloc*, vlong sectoff);
void putelfsectionsyms(void);
EXTERN int elfstrsize; EXTERN int elfstrsize;
EXTERN char* elfstrdat; EXTERN char* elfstrdat;
......
...@@ -249,6 +249,8 @@ void setuint64(Sym*, vlong, uint64); ...@@ -249,6 +249,8 @@ void setuint64(Sym*, vlong, uint64);
void asmsym(void); void asmsym(void);
void asmelfsym(void); void asmelfsym(void);
void asmplan9sym(void); void asmplan9sym(void);
void putelfsectionsym(Sym*, int);
void putelfsymshndx(vlong, int);
void strnput(char*, int); void strnput(char*, int);
void dodata(void); void dodata(void);
void dosymtype(void); void dosymtype(void);
......
...@@ -142,6 +142,31 @@ putelfsym(Sym *x, char *s, int t, vlong addr, vlong size, int ver, Sym *go) ...@@ -142,6 +142,31 @@ putelfsym(Sym *x, char *s, int t, vlong addr, vlong size, int ver, Sym *go)
x->elfsym = numelfsym++; 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 void
asmelfsym(void) asmelfsym(void)
{ {
...@@ -150,6 +175,8 @@ asmelfsym(void) ...@@ -150,6 +175,8 @@ asmelfsym(void)
// the first symbol entry is reserved // the first symbol entry is reserved
putelfsyment(0, 0, 0, (STB_LOCAL<<4)|STT_NOTYPE, 0, 0); putelfsyment(0, 0, 0, (STB_LOCAL<<4)|STT_NOTYPE, 0, 0);
dwarfaddelfsectionsyms();
elfbind = STB_LOCAL; elfbind = STB_LOCAL;
genasmsym(putelfsym); genasmsym(putelfsym);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment