aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIan Lance Taylor <iant@golang.org>2013-04-30 14:01:05 -0700
committerIan Lance Taylor <iant@golang.org>2013-04-30 14:01:05 -0700
commit825b1e15916833ff6b2affdb5b0bb7c5c908ac52 (patch)
tree2332fab4d5d7770999b5dca31b72f93dbb787ca8
parentb461c94cfaf79f2f84abd7513eb35218dc6235ed (diff)
downloadgo-825b1e15916833ff6b2affdb5b0bb7c5c908ac52.tar.gz
go-825b1e15916833ff6b2affdb5b0bb7c5c908ac52.zip
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
-rw-r--r--src/cmd/ld/dwarf.c227
-rw-r--r--src/cmd/ld/elf.c4
-rw-r--r--src/cmd/ld/elf.h5
-rw-r--r--src/cmd/ld/lib.h2
-rw-r--r--src/cmd/ld/symtab.c27
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
@@ -143,6 +143,31 @@ putelfsym(Sym *x, char *s, int t, vlong addr, vlong size, int ver, Sym *go)
}
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)
{
Sym *s;
@@ -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);