diff options
Diffstat (limited to 'src/cmd/ld')
-rw-r--r-- | src/cmd/ld/data.c | 31 | ||||
-rw-r--r-- | src/cmd/ld/dwarf.c | 51 | ||||
-rw-r--r-- | src/cmd/ld/elf.c | 38 | ||||
-rw-r--r-- | src/cmd/ld/elf.h | 4 | ||||
-rw-r--r-- | src/cmd/ld/go.c | 13 | ||||
-rw-r--r-- | src/cmd/ld/ldmacho.c | 32 | ||||
-rw-r--r-- | src/cmd/ld/lib.c | 70 | ||||
-rw-r--r-- | src/cmd/ld/lib.h | 38 | ||||
-rw-r--r-- | src/cmd/ld/pe.c | 8 | ||||
-rw-r--r-- | src/cmd/ld/symtab.c | 30 |
10 files changed, 209 insertions, 106 deletions
diff --git a/src/cmd/ld/data.c b/src/cmd/ld/data.c index a20b057ce..d27416dac 100644 --- a/src/cmd/ld/data.c +++ b/src/cmd/ld/data.c @@ -722,7 +722,7 @@ addsize(Sym *s, Sym *t) void dodata(void) { - int32 h, t, datsize; + int32 t, datsize; Section *sect; Sym *s, *last, **l; @@ -732,23 +732,22 @@ dodata(void) last = nil; datap = nil; - for(h=0; h<NHASH; h++) { - for(s=hash[h]; s!=S; s=s->hash){ - if(!s->reachable || s->special) - continue; - if(STEXT < s->type && s->type < SXREF) { - if(last == nil) - datap = s; - else - last->next = s; - s->next = nil; - last = s; - } + + for(s=allsym; s!=S; s=s->allsym) { + if(!s->reachable || s->special) + continue; + if(STEXT < s->type && s->type < SXREF) { + if(last == nil) + datap = s; + else + last->next = s; + s->next = nil; + last = s; } } for(s = datap; s != nil; s = s->next) { - if(s->np > 0 && s->type == SBSS) // TODO: necessary? + if(s->np > 0 && s->type == SBSS) s->type = SDATA; if(s->np > s->size) diag("%s: initialize bounds (%lld < %d)", @@ -786,8 +785,7 @@ dodata(void) s = datap; for(; s != nil && s->type < SDATA; s = s->next) { s->type = SRODATA; - t = rnd(s->size, 4); - s->size = t; + t = rnd(s->size, PtrSize); s->value = datsize; datsize += t; } @@ -834,7 +832,6 @@ dodata(void) datsize = rnd(datsize, 4); else datsize = rnd(datsize, 8); - s->size = t; s->value = datsize; datsize += t; } diff --git a/src/cmd/ld/dwarf.c b/src/cmd/ld/dwarf.c index 5ba4b7c64..fa55fcbb4 100644 --- a/src/cmd/ld/dwarf.c +++ b/src/cmd/ld/dwarf.c @@ -6,7 +6,6 @@ // - eliminate DW_CLS_ if not used // - package info in compilation units // - assign global variables and types to their packages -// - (upstream) type info for C parts of runtime // - gdb uses c syntax, meaning clumsy quoting is needed for go identifiers. eg // ptype struct '[]uint8' and qualifiers need to be quoted away // - lexical scoping is lost, so gdb gets confused as to which 'main.i' you mean. @@ -943,14 +942,16 @@ enum { static char* decodetype_structfieldname(Sym *s, int i) { + Reloc *r; + // go.string."foo" 0x28 / 0x40 s = decode_reloc_sym(s, CommonSize + PtrSize + 2*4 + i*StructFieldSize); if (s == nil) // embedded structs have a nil name. return nil; - s = decode_reloc_sym(s, 0); // string."foo" - if (s == nil) // shouldn't happen. + r = decode_reloc(s, 0); // s has a pointer to the string data at offset 0 + if (r == nil) // shouldn't happen. return nil; - return (char*)s->p; // the c-string + return (char*) r->sym->p + r->add; // the c-string } static Sym* @@ -989,8 +990,8 @@ lookup_or_diag(char *n) { Sym *s; - s = lookup(n, 0); - if (s->size == 0) { + s = rlookup(n, 0); + if (s == nil || s->size == 0) { diag("dwarf: missing type: %s", n); errorexit(); } @@ -1021,22 +1022,8 @@ defgotype(Sym *gotype) if (die != nil) return die; - if (0 && debug['v'] > 2) { - print("new type: %s @0x%08x [%d]", gotype->name, gotype->value, gotype->size); - for (i = 0; i < gotype->size; i++) { - if (!(i%8)) print("\n\t%04x ", i); - print("%02x ", gotype->p[i]); - } - print("\n"); - for (i = 0; i < gotype->nr; i++) { - print("\t0x%02x[%x] %d %s[%llx]\n", - gotype->r[i].off, - gotype->r[i].siz, - gotype->r[i].type, - gotype->r[i].sym->name, - (vlong)gotype->r[i].add); - } - } + if (0 && debug['v'] > 2) + print("new type: %Y\n", gotype); kind = decodetype_kind(gotype); bytesize = decodetype_size(gotype); @@ -1117,7 +1104,6 @@ defgotype(Sym *gotype) fld = newdie(die, DW_ABRV_FUNCTYPEPARAM, s->name+5); newrefattr(fld, DW_AT_type, defptrto(defgotype(s))); } - die = defptrto(die); break; case KindInterface: @@ -1391,7 +1377,7 @@ static void synthesizechantypes(DWDie *die) { DWDie *sudog, *waitq, *link, *hchan, - *dws, *dww, *dwl, *dwh, *elemtype; + *dws, *dww, *dwh, *elemtype; DWAttr *a; int elemsize, linksize, sudogsize; @@ -1430,21 +1416,10 @@ synthesizechantypes(DWDie *die) newattr(dww, DW_AT_byte_size, DW_CLS_CONSTANT, getattr(waitq, DW_AT_byte_size)->value, NULL); - // link<T> - dwl = newdie(&dwtypes, DW_ABRV_STRUCTTYPE, - mkinternaltypename("link", getattr(elemtype, DW_AT_name)->data, NULL)); - copychildren(dwl, link); - substitutetype(dwl, "link", defptrto(dwl)); - substitutetype(dwl, "elem", elemtype); - newattr(dwl, DW_AT_byte_size, DW_CLS_CONSTANT, - linksize + (elemsize > 8 ? elemsize - 8 : 0), NULL); - // hchan<T> dwh = newdie(&dwtypes, DW_ABRV_STRUCTTYPE, mkinternaltypename("hchan", getattr(elemtype, DW_AT_name)->data, NULL)); copychildren(dwh, hchan); - substitutetype(dwh, "senddataq", defptrto(dwl)); - substitutetype(dwh, "recvdataq", defptrto(dwl)); substitutetype(dwh, "recvq", dww); substitutetype(dwh, "sendq", dww); substitutetype(dwh, "free", dws); @@ -1463,12 +1438,8 @@ defdwsymb(Sym* sym, char *s, int t, vlong v, vlong size, int ver, Sym *gotype) if (strncmp(s, "go.string.", 10) == 0) return; - if (strncmp(s, "string.", 7) == 0) - return; - if (strncmp(s, "type._.", 7) == 0) - return; - if (strncmp(s, "type.", 5) == 0) { + if (strncmp(s, "type.", 5) == 0 && strcmp(s, "type.*") != 0) { defgotype(sym); return; } diff --git a/src/cmd/ld/elf.c b/src/cmd/ld/elf.c index d5b0b0311..b0cce4985 100644 --- a/src/cmd/ld/elf.c +++ b/src/cmd/ld/elf.c @@ -336,7 +336,7 @@ void elfdynhash(void) { Sym *s, *sy; - int i, h, nbucket, b; + int i, nbucket, b; uchar *pc; uint32 hc, g; uint32 *chain, *buckets; @@ -367,26 +367,24 @@ elfdynhash(void) } memset(chain, 0, nsym * sizeof(uint32)); memset(buckets, 0, nbucket * sizeof(uint32)); - for(h = 0; h<NHASH; h++) { - for(sy=hash[h]; sy!=S; sy=sy->hash) { - if (sy->dynid <= 0) - continue; - - hc = 0; - name = sy->dynimpname; - if(name == nil) - name = sy->name; - for(pc = (uchar*)name; *pc; pc++) { - hc = (hc<<4) + *pc; - g = hc & 0xf0000000; - hc ^= g >> 24; - hc &= ~g; - } - - b = hc % nbucket; - chain[sy->dynid] = buckets[b]; - buckets[b] = sy->dynid; + for(sy=allsym; sy!=S; sy=sy->allsym) { + if (sy->dynid <= 0) + continue; + + hc = 0; + name = sy->dynimpname; + if(name == nil) + name = sy->name; + for(pc = (uchar*)name; *pc; pc++) { + hc = (hc<<4) + *pc; + g = hc & 0xf0000000; + hc ^= g >> 24; + hc &= ~g; } + + b = hc % nbucket; + chain[sy->dynid] = buckets[b]; + buckets[b] = sy->dynid; } adduint32(s, nbucket); diff --git a/src/cmd/ld/elf.h b/src/cmd/ld/elf.h index df15cb115..b27ae679b 100644 --- a/src/cmd/ld/elf.h +++ b/src/cmd/ld/elf.h @@ -946,10 +946,10 @@ typedef Elf64_Shdr ElfShdr; typedef Elf64_Phdr ElfPhdr; void elfinit(void); -ElfEhdr *getElfEhdr(); +ElfEhdr *getElfEhdr(void); ElfShdr *newElfShstrtab(vlong); ElfShdr *newElfShdr(vlong); -ElfPhdr *newElfPhdr(); +ElfPhdr *newElfPhdr(void); uint32 elfwritehdr(void); uint32 elfwritephdrs(void); uint32 elfwriteshdrs(void); diff --git a/src/cmd/ld/go.c b/src/cmd/ld/go.c index 3c1e230b4..055163d08 100644 --- a/src/cmd/ld/go.c +++ b/src/cmd/ld/go.c @@ -135,6 +135,7 @@ ldpkg(Biobuf *f, char *pkg, int64 len, char *filename, int whence) if(debug['u'] && whence != ArchiveObj && (p0+6 > p1 || memcmp(p0, " safe\n", 6) != 0)) { fprint(2, "%s: load of unsafe package %s\n", argv0, filename); + nerrors++; errorexit(); } if(p0 < p1) { @@ -657,27 +658,25 @@ deadcode(void) else last->next = nil; - for(i=0; i<NHASH; i++) - for(s = hash[i]; s != S; s = s->hash) + for(s = allsym; s != S; s = s->allsym) if(strncmp(s->name, "weak.", 5) == 0) { s->special = 1; // do not lay out in data segment s->reachable = 1; + s->hide = 1; } } void doweak(void) { - int i; Sym *s, *t; // resolve weak references only if // target symbol will be in binary anyway. - for(i=0; i<NHASH; i++) - for(s = hash[i]; s != S; s = s->hash) { + for(s = allsym; s != S; s = s->allsym) { if(strncmp(s->name, "weak.", 5) == 0) { - t = lookup(s->name+5, s->version); - if(t->type != 0 && t->reachable) { + t = rlookup(s->name+5, s->version); + if(t && t->type != 0 && t->reachable) { s->value = t->value; s->type = t->type; } else { diff --git a/src/cmd/ld/ldmacho.c b/src/cmd/ld/ldmacho.c index 7e38db0e4..bbb21d51a 100644 --- a/src/cmd/ld/ldmacho.c +++ b/src/cmd/ld/ldmacho.c @@ -422,6 +422,7 @@ void ldmacho(Biobuf *f, char *pkg, int64 len, char *pn) { int i, j, is64; + uint64 secaddr; uchar hdr[7*4], *cmdp; uchar tmp[4]; uchar *dat; @@ -581,7 +582,11 @@ ldmacho(Biobuf *f, char *pkg, int64 len, char *pn) else s->type = SRODATA; } else { - s->type = SDATA; + if (strcmp(sect->name, "__bss") == 0) { + s->type = SBSS; + s->np = 0; + } else + s->type = SDATA; } if(s->type == STEXT) { if(etextp) @@ -751,8 +756,29 @@ ldmacho(Biobuf *f, char *pkg, int64 len, char *pn) rp->siz = rel->length; rp->type = 512 + (rel->type<<1) + rel->pcrel; rp->off = rel->addr; - - rp->add = e->e32(s->p+rp->off); + + // Handle X86_64_RELOC_SIGNED referencing a section (rel->extrn == 0). + if (thechar == '6' && rel->extrn == 0 && rel->type == 1) { + // Calculate the addend as the offset into the section. + // + // The rip-relative offset stored in the object file is encoded + // as follows: + // + // movsd 0x00000360(%rip),%xmm0 + // + // To get the absolute address of the value this rip-relative address is pointing + // to, we must add the address of the next instruction to it. This is done by + // taking the address of the relocation and adding 4 to it (since the rip-relative + // offset can at most be 32 bits long). To calculate the offset into the section the + // relocation is referencing, we subtract the vaddr of the start of the referenced + // section found in the original object file. + // + // [For future reference, see Darwin's /usr/include/mach-o/x86_64/reloc.h] + secaddr = c->seg.sect[rel->symnum-1].addr; + rp->add = e->e32(s->p+rp->off) + rp->off + 4 - secaddr; + } else + rp->add = e->e32(s->p+rp->off); + // For i386 Mach-O PC-relative, the addend is written such that // it *is* the PC being subtracted. Use that to make // it match our version of PC-relative. diff --git a/src/cmd/ld/lib.c b/src/cmd/ld/lib.c index e645502b3..8cd570463 100644 --- a/src/cmd/ld/lib.c +++ b/src/cmd/ld/lib.c @@ -61,6 +61,7 @@ void libinit(void) { fmtinstall('i', iconv); + fmtinstall('Y', Yconv); mywhatsys(); // get goroot, goarch, goos if(strcmp(goarch, thestring) != 0) print("goarch is not known: %s\n", goarch); @@ -470,8 +471,8 @@ eof: diag("truncated object file: %s", pn); } -Sym* -lookup(char *symb, int v) +static Sym* +_lookup(char *symb, int v, int creat) { Sym *s; char *p; @@ -485,10 +486,12 @@ lookup(char *symb, int v) // not if(h < 0) h = ~h, because gcc 4.3 -O2 miscompiles it. h &= 0xffffff; h %= NHASH; + c = symb[0]; for(s = hash[h]; s != S; s = s->hash) - if(s->version == v) if(memcmp(s->name, symb, l) == 0) return s; + if(!creat) + return nil; s = mal(sizeof(*s)); if(debug['v'] > 1) @@ -508,9 +511,25 @@ lookup(char *symb, int v) s->size = 0; hash[h] = s; nsymbol++; + + s->allsym = allsym; + allsym = s; return s; } +Sym* +lookup(char *name, int v) +{ + return _lookup(name, v, 1); +} + +// read-only lookup +Sym* +rlookup(char *name, int v) +{ + return _lookup(name, v, 0); +} + void copyhistfrog(char *buf, int nbuf) { @@ -829,7 +848,7 @@ unmal(void *v, uint32 n) // Copied from ../gc/subr.c:/^pathtoprefix; must stay in sync. /* * Convert raw string to the prefix that will be used in the symbol table. - * Invalid bytes turn into %xx. Right now the only bytes that need + * Invalid bytes turn into %xx. Right now the only bytes that need * escaping are %, ., and ", but we escape all control characters too. */ static char* @@ -1104,7 +1123,7 @@ static Sym *newstack; enum { HasLinkRegister = (thechar == '5'), - CallSize = (!HasLinkRegister)*PtrSize, // bytes of stack required for a call + CallSize = (!HasLinkRegister)*PtrSize, // bytes of stack required for a call }; void @@ -1130,7 +1149,7 @@ dostkcheck(void) // Check calling contexts. // Some nosplits get called a little further down, - // like newproc and deferproc. We could hard-code + // like newproc and deferproc. We could hard-code // that knowledge but it's more robust to look at // the actual call sites. for(s = textp; s != nil; s = s->next) { @@ -1283,11 +1302,44 @@ headtype(char *name) void undef(void) { - int i; Sym *s; - for(i=0; i<NHASH; i++) - for(s = hash[i]; s != S; s = s->hash) + for(s = allsym; s != S; s = s->allsym) if(s->type == SXREF) diag("%s(%d): not defined", s->name, s->version); } + +int +Yconv(Fmt *fp) +{ + Sym *s; + Fmt fmt; + int i; + char *str; + + s = va_arg(fp->args, Sym*); + if (s == S) { + fmtprint(fp, "<nil>"); + } else { + fmtstrinit(&fmt); + fmtprint(&fmt, "%s @0x%08x [%d]", s->name, s->value, s->size); + for (i = 0; i < s->size; i++) { + if (!(i%8)) fmtprint(&fmt, "\n\t0x%04x ", i); + fmtprint(&fmt, "%02x ", s->p[i]); + } + fmtprint(&fmt, "\n"); + for (i = 0; i < s->nr; i++) { + fmtprint(&fmt, "\t0x%04x[%x] %d %s[%llx]\n", + s->r[i].off, + s->r[i].siz, + s->r[i].type, + s->r[i].sym->name, + (vlong)s->r[i].add); + } + str = fmtstrflush(&fmt); + fmtstrcpy(fp, str); + free(str); + } + + return 0; +} diff --git a/src/cmd/ld/lib.h b/src/cmd/ld/lib.h index adde2c9ff..646aeb535 100644 --- a/src/cmd/ld/lib.h +++ b/src/cmd/ld/lib.h @@ -28,8 +28,37 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. -// Where symbol table data gets mapped into memory. -#define SYMDATVA 0x99LL<<24 +enum +{ + Sxxx, + + /* order here is order in output file */ + STEXT, + SELFDATA, + SMACHOPLT, + STYPE, + SSTRING, + SGOSTRING, + SRODATA, + SDATA, + SMACHO, /* Mach-O __nl_symbol_ptr */ + SMACHOGOT, + SWINDOWS, + SBSS, + + SXREF, + SMACHODYNSTR, + SMACHODYNSYM, + SMACHOINDIRECTPLT, + SMACHOINDIRECTGOT, + SFILE, + SCONST, + SDYNIMPORT, + + SSUB = 1<<8, /* sub-symbol, linked from parent via ->sub list */ + + NHASH = 100003, +}; typedef struct Library Library; struct Library @@ -79,6 +108,7 @@ EXTERN Library* library; EXTERN int libraryp; EXTERN int nlibrary; EXTERN Sym* hash[NHASH]; +EXTERN Sym* allsym; EXTERN Sym* histfrog[MAXHIST]; EXTERN uchar fnuxi8[8]; EXTERN uchar fnuxi4[4]; @@ -106,6 +136,7 @@ void asmlc(void); void histtoauto(void); void collapsefrog(Sym *s); Sym* lookup(char *symb, int v); +Sym* rlookup(char *symb, int v); void nuxiinit(void); int find1(int32 l, int c); int find2(int32 l, int c); @@ -243,3 +274,6 @@ EXTERN char* headstring; extern Header headers[]; int headtype(char*); + +int Yconv(Fmt*); +#pragma varargck type "Y" Sym* diff --git a/src/cmd/ld/pe.c b/src/cmd/ld/pe.c index e72b0b2a0..0d4240e36 100644 --- a/src/cmd/ld/pe.c +++ b/src/cmd/ld/pe.c @@ -171,12 +171,10 @@ initdynimport(void) Imp *m; Dll *d; Sym *s, *dynamic; - int i; dr = nil; - for(i=0; i<NHASH; i++) - for(s = hash[i]; s != S; s = s->hash) { + for(s = allsym; s != S; s = s->allsym) { if(!s->reachable || !s->dynimpname || s->dynexport) continue; for(d = dr; d != nil; d = d->next) { @@ -312,12 +310,10 @@ scmp(const void *p1, const void *p2) static void initdynexport(void) { - int i; Sym *s; nexport = 0; - for(i=0; i<NHASH; i++) - for(s = hash[i]; s != S; s = s->hash) { + for(s = allsym; s != S; s = s->allsym) { if(!s->reachable || !s->dynimpname || !s->dynexport) continue; if(nexport+1 > sizeof(dexport)/sizeof(dexport[0])) { diff --git a/src/cmd/ld/symtab.c b/src/cmd/ld/symtab.c index 22777b6b5..aefe0b1af 100644 --- a/src/cmd/ld/symtab.c +++ b/src/cmd/ld/symtab.c @@ -340,6 +340,8 @@ putsymb(Sym *s, char *name, int t, vlong v, vlong size, int ver, Sym *typ) void symtab(void) { + Sym *s; + // Define these so that they'll get put into the symbol table. // data.c:/^address will provide the actual values. xdefine("text", STEXT, 0); @@ -351,11 +353,39 @@ symtab(void) xdefine("end", SBSS, 0); xdefine("epclntab", SRODATA, 0); xdefine("esymtab", SRODATA, 0); + + // pseudo-symbols to mark locations of type, string, and go string data. + s = lookup("type.*", 0); + s->type = STYPE; + s->size = 0; + s->reachable = 1; + + s = lookup("go.string.*", 0); + s->type = SGOSTRING; + s->size = 0; + s->reachable = 1; symt = lookup("symtab", 0); symt->type = SRODATA; symt->size = 0; symt->reachable = 1; + + // assign specific types so that they sort together. + // within a type they sort by size, so the .* symbols + // just defined above will be first. + // hide the specific symbols. + for(s = allsym; s != S; s = s->allsym) { + if(!s->reachable || s->special || s->type != SRODATA) + continue; + if(strncmp(s->name, "type.", 5) == 0) { + s->type = STYPE; + s->hide = 1; + } + if(strncmp(s->name, "go.string.", 10) == 0) { + s->type = SGOSTRING; + s->hide = 1; + } + } genasmsym(putsymb); } |