diff options
author | Ondřej Surý <ondrej@sury.org> | 2011-06-30 15:34:22 +0200 |
---|---|---|
committer | Ondřej Surý <ondrej@sury.org> | 2011-06-30 15:34:22 +0200 |
commit | d39f5aa373a4422f7a5f3ee764fb0f6b0b719d61 (patch) | |
tree | 1833f8b72a4b3a8f00d0d143b079a8fcad01c6ae /src/cmd/ld | |
parent | 8652e6c371b8905498d3d314491d36c58d5f68d5 (diff) | |
download | golang-upstream/58.tar.gz |
Imported Upstream version 58upstream/58
Diffstat (limited to 'src/cmd/ld')
-rw-r--r-- | src/cmd/ld/data.c | 12 | ||||
-rw-r--r-- | src/cmd/ld/dwarf.c | 112 | ||||
-rw-r--r-- | src/cmd/ld/elf.h | 4 | ||||
-rw-r--r-- | src/cmd/ld/go.c | 6 | ||||
-rw-r--r-- | src/cmd/ld/ldpe.c | 5 | ||||
-rw-r--r-- | src/cmd/ld/lib.c | 43 | ||||
-rw-r--r-- | src/cmd/ld/lib.h | 4 | ||||
-rw-r--r-- | src/cmd/ld/macho.c | 23 | ||||
-rw-r--r-- | src/cmd/ld/macho.h | 2 | ||||
-rw-r--r-- | src/cmd/ld/pe.c | 54 | ||||
-rw-r--r-- | src/cmd/ld/pe.h | 2 | ||||
-rw-r--r-- | src/cmd/ld/symtab.c | 78 |
12 files changed, 228 insertions, 117 deletions
diff --git a/src/cmd/ld/data.c b/src/cmd/ld/data.c index 0cb2b2138..3f3faade0 100644 --- a/src/cmd/ld/data.c +++ b/src/cmd/ld/data.c @@ -804,6 +804,10 @@ dodata(void) diag("%s: no size", s->name); t = 1; } + if(t >= PtrSize) + t = rnd(t, PtrSize); + else if(t > 2) + t = rnd(t, 4); if(t & 1) ; else if(t & 2) @@ -826,6 +830,10 @@ dodata(void) diag("unexpected symbol type %d", s->type); } t = s->size; + if(t >= PtrSize) + t = rnd(t, PtrSize); + else if(t > 2) + t = rnd(t, 4); if(t & 1) ; else if(t & 2) @@ -899,10 +907,8 @@ address(void) segdata.fileoff = va - segtext.vaddr + segtext.fileoff; if(HEADTYPE == Hwindows) segdata.fileoff = segtext.fileoff + rnd(segtext.len, PEFILEALIGN); - if(HEADTYPE == Hplan9x32) { - segdata.vaddr = va = rnd(va, 4096); + if(HEADTYPE == Hplan9x32) segdata.fileoff = segtext.fileoff + segtext.filelen; - } for(s=segdata.sect; s != nil; s=s->next) { s->vaddr = va; va += s->len; diff --git a/src/cmd/ld/dwarf.c b/src/cmd/ld/dwarf.c index 98b068008..50b42183e 100644 --- a/src/cmd/ld/dwarf.c +++ b/src/cmd/ld/dwarf.c @@ -529,8 +529,10 @@ find_or_diag(DWDie *die, char* name) { DWDie *r; r = find(die, name); - if (r == nil) + if (r == nil) { diag("dwarf find: %s has no %s", getattr(die, DW_AT_name)->data, name); + errorexit(); + } return r; } @@ -613,7 +615,7 @@ putattr(int form, int cls, vlong value, char *data) case DW_FORM_ref_addr: // reference to a DIE in the .info section if (data == nil) { - diag("null dwarf reference"); + diag("dwarf: null reference"); LPUT(0); // invalid dwarf, gdb will complain. } else { if (((DWDie*)data)->offs == 0) @@ -631,7 +633,7 @@ putattr(int form, int cls, vlong value, char *data) case DW_FORM_strp: // string case DW_FORM_indirect: // (see Section 7.5.3) default: - diag("Unsupported atribute form %d / class %d", form, cls); + diag("dwarf: unsupported attribute form %d / class %d", form, cls); errorexit(); } } @@ -823,7 +825,7 @@ decode_inuxi(uchar* p, int sz) inuxi = inuxi8; break; default: - diag("decode inuxi %d", sz); + diag("dwarf: decode inuxi %d", sz); errorexit(); } for (i = 0; i < sz; i++) @@ -1013,7 +1015,7 @@ defgotype(Sym *gotype) return find_or_diag(&dwtypes, "<unspecified>"); if (strncmp("type.", gotype->name, 5) != 0) { - diag("Type name doesn't start with \".type\": %s", gotype->name); + diag("dwarf: type name doesn't start with \".type\": %s", gotype->name); return find_or_diag(&dwtypes, "<unspecified>"); } name = gotype->name + 5; // could also decode from Type.string @@ -1164,7 +1166,7 @@ defgotype(Sym *gotype) break; default: - diag("definition of unknown kind %d: %s", kind, gotype->name); + diag("dwarf: definition of unknown kind %d: %s", kind, gotype->name); die = newdie(&dwtypes, DW_ABRV_TYPEDECL, name); newrefattr(die, DW_AT_type, find_or_diag(&dwtypes, "<unspecified>")); } @@ -1346,7 +1348,7 @@ synthesizemaptypes(DWDie *die) valtype = defptrto(valtype); newrefattr(fld, DW_AT_type, valtype); newmemberoffsetattr(fld, hashsize + datavo); - newattr(dwhe, DW_AT_byte_size, DW_CLS_CONSTANT, hashsize + datsize, NULL); + newattr(dwhe, DW_AT_byte_size, DW_CLS_CONSTANT, hashsize + datsize, nil); // Construct hash_subtable<hash_entry<K,V>> dwhs = newdie(&dwtypes, DW_ABRV_STRUCTTYPE, @@ -1357,7 +1359,7 @@ synthesizemaptypes(DWDie *die) substitutetype(dwhs, "end", defptrto(dwhe)); substitutetype(dwhs, "entry", dwhe); // todo: []hash_entry with dynamic size newattr(dwhs, DW_AT_byte_size, DW_CLS_CONSTANT, - getattr(hash_subtable, DW_AT_byte_size)->value, NULL); + getattr(hash_subtable, DW_AT_byte_size)->value, nil); // Construct hash<K,V> dwh = newdie(&dwtypes, DW_ABRV_STRUCTTYPE, @@ -1367,7 +1369,7 @@ synthesizemaptypes(DWDie *die) copychildren(dwh, hash); substitutetype(dwh, "st", defptrto(dwhs)); newattr(dwh, DW_AT_byte_size, DW_CLS_CONSTANT, - getattr(hash, DW_AT_byte_size)->value, NULL); + getattr(hash, DW_AT_byte_size)->value, nil); newrefattr(die, DW_AT_type, defptrto(dwh)); } @@ -1399,30 +1401,30 @@ synthesizechantypes(DWDie *die) // sudog<T> dws = newdie(&dwtypes, DW_ABRV_STRUCTTYPE, mkinternaltypename("sudog", - getattr(elemtype, DW_AT_name)->data, NULL)); + getattr(elemtype, DW_AT_name)->data, nil)); copychildren(dws, sudog); substitutetype(dws, "elem", elemtype); newattr(dws, DW_AT_byte_size, DW_CLS_CONSTANT, - sudogsize + (elemsize > 8 ? elemsize - 8 : 0), NULL); + sudogsize + (elemsize > 8 ? elemsize - 8 : 0), nil); // waitq<T> dww = newdie(&dwtypes, DW_ABRV_STRUCTTYPE, - mkinternaltypename("waitq", getattr(elemtype, DW_AT_name)->data, NULL)); + mkinternaltypename("waitq", getattr(elemtype, DW_AT_name)->data, nil)); copychildren(dww, waitq); substitutetype(dww, "first", defptrto(dws)); substitutetype(dww, "last", defptrto(dws)); newattr(dww, DW_AT_byte_size, DW_CLS_CONSTANT, - getattr(waitq, DW_AT_byte_size)->value, NULL); + getattr(waitq, DW_AT_byte_size)->value, nil); // hchan<T> dwh = newdie(&dwtypes, DW_ABRV_STRUCTTYPE, - mkinternaltypename("hchan", getattr(elemtype, DW_AT_name)->data, NULL)); + mkinternaltypename("hchan", getattr(elemtype, DW_AT_name)->data, nil)); copychildren(dwh, hchan); substitutetype(dwh, "recvq", dww); substitutetype(dwh, "sendq", dww); substitutetype(dwh, "free", defptrto(dws)); newattr(dwh, DW_AT_byte_size, DW_CLS_CONSTANT, - getattr(hchan, DW_AT_byte_size)->value, NULL); + getattr(hchan, DW_AT_byte_size)->value, nil); newrefattr(die, DW_AT_type, defptrto(dwh)); } @@ -1434,6 +1436,7 @@ defdwsymb(Sym* sym, char *s, int t, vlong v, vlong size, int ver, Sym *gotype) { DWDie *dv, *dt; + USED(size); if (strncmp(s, "go.string.", 10) == 0) return; @@ -1513,12 +1516,12 @@ decodez(char *s) ss = s + 1; // first is 0 while((o = ((uint8)ss[0] << 8) | (uint8)ss[1]) != 0) { if (o < 0 || o >= ftabsize) { - diag("corrupt z entry"); + diag("dwarf: corrupt z entry"); return 0; } f = ftab[o]; if (f == nil) { - diag("corrupt z entry"); + diag("dwarf: corrupt z entry"); return 0; } len += strlen(f) + 1; // for the '/' @@ -1590,7 +1593,7 @@ addhistfile(char *zentry) // if the histfile stack contains ..../runtime/runtime_defs.go // use that to set gdbscript static void -finddebugruntimepath() +finddebugruntimepath(void) { int i, l; char *c; @@ -1630,11 +1633,11 @@ checknesting(void) int i; if (includetop < 0) { - diag("corrupt z stack"); + diag("dwarf: corrupt z stack"); errorexit(); } if (includetop >= nelem(includestack)) { - diag("nesting too deep"); + diag("dwarf: nesting too deep"); for (i = 0; i < nelem(includestack); i++) diag("\t%s", histfile[includestack[i].file]); errorexit(); @@ -1660,7 +1663,7 @@ inithist(Auto *a) // We have a new history. They are guaranteed to come completely // at the beginning of the compilation unit. if (a->aoffset != 1) { - diag("stray 'z' with offset %d", a->aoffset); + diag("dwarf: stray 'z' with offset %d", a->aoffset); return 0; } @@ -1801,7 +1804,7 @@ mkvarname(char* name, int da) // flush previous compilation unit. static void -flushunit(DWDie *dwinfo, vlong pc, vlong unitstart) +flushunit(DWDie *dwinfo, vlong pc, vlong unitstart, int32 header_length) { vlong here; @@ -1817,7 +1820,9 @@ flushunit(DWDie *dwinfo, vlong pc, vlong unitstart) here = cpos(); seek(cout, unitstart, 0); - LPUT(here - unitstart - sizeof(int32)); + LPUT(here - unitstart - sizeof(int32)); // unit_length + WPUT(3); // dwarf version + LPUT(header_length); // header lenght starting here cflush(); seek(cout, here, 0); } @@ -1829,7 +1834,7 @@ writelines(void) Prog *q; Sym *s; Auto *a; - vlong unitstart, offs; + vlong unitstart, headerend, offs; vlong pc, epc, lc, llc, lline; int currfile; int i, lang, da, dt; @@ -1839,7 +1844,9 @@ writelines(void) char *n, *nn; unitstart = -1; - epc = pc = 0; + headerend = -1; + pc = 0; + epc = 0; lc = 1; llc = 1; currfile = -1; @@ -1855,7 +1862,7 @@ writelines(void) // we're entering a new compilation unit if (inithist(s->autom)) { - flushunit(dwinfo, epc, unitstart); + flushunit(dwinfo, epc, unitstart, headerend - unitstart - 10); unitstart = cpos(); if(debug['v'] > 1) { @@ -1876,10 +1883,10 @@ writelines(void) // Write .debug_line Line Number Program Header (sec 6.2.4) // Fields marked with (*) must be changed for 64-bit dwarf - LPUT(0); // unit_length (*), will be filled in later. + LPUT(0); // unit_length (*), will be filled in by flushunit. WPUT(3); // dwarf version (appendix F) - LPUT(11); // header_length (*), starting here. - + LPUT(0); // header_length (*), filled in by flushunit. + // cpos == unitstart + 4 + 2 + 4 cput(1); // minimum_instruction_length cput(1); // default_is_stmt cput(LINE_BASE); // line_base @@ -1890,18 +1897,17 @@ writelines(void) cput(1); // standard_opcode_lengths[3] cput(1); // standard_opcode_lengths[4] cput(0); // include_directories (empty) - cput(0); // file_names (empty) (emitted by DW_LNE's below) - // header_length ends here. for (i=1; i < histfilesize; i++) { - cput(0); // start extended opcode - uleb128put(1 + strlen(histfile[i]) + 4); - cput(DW_LNE_define_file); strnput(histfile[i], strlen(histfile[i]) + 4); // 4 zeros: the string termination + 3 fields. } - epc = pc = s->text->pc; + cput(0); // terminate file_names. + headerend = cpos(); + + pc = s->text->pc; + epc = pc; currfile = 1; lc = 1; llc = 1; @@ -1915,7 +1921,7 @@ writelines(void) continue; if (unitstart < 0) { - diag("reachable code before seeing any history: %P", s->text); + diag("dwarf: reachable code before seeing any history: %P", s->text); continue; } @@ -1932,7 +1938,7 @@ writelines(void) for(q = s->text; q != P; q = q->link) { lh = searchhist(q->line); if (lh == nil) { - diag("corrupt history or bad absolute line: %P", q); + diag("dwarf: corrupt history or bad absolute line: %P", q); continue; } @@ -1990,7 +1996,7 @@ writelines(void) newrefattr(dwvar, DW_AT_type, defgotype(a->gotype)); // push dwvar down dwfunc->child to preserve order - newattr(dwvar, DW_AT_internal_location, DW_CLS_CONSTANT, offs, NULL); + newattr(dwvar, DW_AT_internal_location, DW_CLS_CONSTANT, offs, nil); dwfunc->child = dwvar->link; // take dwvar out from the top of the list for (dws = &dwfunc->child; *dws != nil; dws = &(*dws)->link) if (offs > getattr(*dws, DW_AT_internal_location)->value) @@ -2004,7 +2010,7 @@ writelines(void) dwfunc->hash = nil; } - flushunit(dwinfo, epc, unitstart); + flushunit(dwinfo, epc, unitstart, headerend - unitstart - 10); linesize = cpos() - lineo; } @@ -2066,7 +2072,7 @@ writeframes(void) // 4 is to exclude the length field. pad = CIERESERVE + frameo + 4 - cpos(); if (pad < 0) { - diag("CIERESERVE too small by %lld bytes.", -pad); + diag("dwarf: CIERESERVE too small by %lld bytes.", -pad); errorexit(); } strnput("", pad); @@ -2296,6 +2302,9 @@ dwarfemitdebugsections(void) vlong infoe; DWDie* die; + if(debug['w']) // disable dwarf + return; + // For diagnostic messages. newattr(&dwtypes, DW_AT_name, DW_CLS_STRING, strlen("dwtypes"), "dwtypes"); @@ -2340,7 +2349,11 @@ dwarfemitdebugsections(void) infoo = cpos(); writeinfo(); - gdbscripto = arangeso = pubtypeso = pubnameso = infoe = cpos(); + infoe = cpos(); + pubnameso = infoe; + pubtypeso = infoe; + arangeso = infoe; + gdbscripto = infoe; if (fwdcount > 0) { if (debug['v']) @@ -2348,11 +2361,11 @@ dwarfemitdebugsections(void) seek(cout, infoo, 0); writeinfo(); if (fwdcount > 0) { - diag("unresolved references after first dwarf info pass"); + diag("dwarf: unresolved references after first dwarf info pass"); errorexit(); } if (infoe != cpos()) { - diag("inconsistent second dwarf info pass"); + diag("dwarf: inconsistent second dwarf info pass"); errorexit(); } } @@ -2401,6 +2414,9 @@ vlong elfstrdbg[NElfStrDbg]; void dwarfaddshstrings(Sym *shstrtab) { + if(debug['w']) // disable dwarf + return; + elfstrdbg[ElfStrDebugAbbrev] = addstring(shstrtab, ".debug_abbrev"); elfstrdbg[ElfStrDebugAranges] = addstring(shstrtab, ".debug_aranges"); elfstrdbg[ElfStrDebugFrame] = addstring(shstrtab, ".debug_frame"); @@ -2420,6 +2436,9 @@ dwarfaddelfheaders(void) { ElfShdr *sh; + if(debug['w']) // disable dwarf + return; + sh = newElfShdr(elfstrdbg[ElfStrDebugAbbrev]); sh->type = SHT_PROGBITS; sh->off = abbrevo; @@ -2488,6 +2507,9 @@ dwarfaddmachoheaders(void) vlong fakestart; int nsect; + if(debug['w']) // disable dwarf + return; + // Zero vsize segments won't be loaded in memory, even so they // have to be page aligned in the file. fakestart = abbrevo & ~0xfff; @@ -2562,7 +2584,9 @@ dwarfaddmachoheaders(void) void dwarfaddpeheaders(void) { - dwarfemitdebugsections(); + if(debug['w']) // disable dwarf + return; + newPEDWARFSection(".debug_abbrev", abbrevsize); newPEDWARFSection(".debug_line", linesize); newPEDWARFSection(".debug_frame", framesize); diff --git a/src/cmd/ld/elf.h b/src/cmd/ld/elf.h index 08583cc8f..d1370d28b 100644 --- a/src/cmd/ld/elf.h +++ b/src/cmd/ld/elf.h @@ -978,6 +978,10 @@ ElfShdr* elfshbits(Section*); void elfsetstring(char*, int); void elfaddverneed(Sym*); +EXTERN int elfstrsize; +EXTERN char* elfstrdat; +EXTERN int elftextsh; + /* * Total amount of space to reserve at the start of the file * for Header, PHeaders, SHeaders, and interp. diff --git a/src/cmd/ld/go.c b/src/cmd/ld/go.c index e52c5cb34..05d1cc136 100644 --- a/src/cmd/ld/go.c +++ b/src/cmd/ld/go.c @@ -415,8 +415,8 @@ loaddynimport(char *file, char *pkg, char *p, int n) char *pend, *next, *name, *def, *p0, *lib, *q; Sym *s; + USED(file); pend = p + n; - p0 = p; for(; p<pend; p=next) { next = strchr(p, '\n'); if(next == nil) @@ -454,6 +454,7 @@ loaddynimport(char *file, char *pkg, char *p, int n) if(strcmp(name, "_") == 0 && strcmp(def, "_") == 0) { // allow #pragma dynimport _ _ "foo.so" // to force a link of foo.so. + havedynamic = 1; adddynlib(lib); continue; } @@ -468,6 +469,7 @@ loaddynimport(char *file, char *pkg, char *p, int n) s->dynimpname = def; s->dynimpvers = q; s->type = SDYNIMPORT; + havedynamic = 1; } } return; @@ -483,8 +485,8 @@ loaddynexport(char *file, char *pkg, char *p, int n) char *pend, *next, *local, *elocal, *remote, *p0; Sym *s; + USED(file); pend = p + n; - p0 = p; for(; p<pend; p=next) { next = strchr(p, '\n'); if(next == nil) diff --git a/src/cmd/ld/ldpe.c b/src/cmd/ld/ldpe.c index d8b0a6fc2..d6aa267c4 100644 --- a/src/cmd/ld/ldpe.c +++ b/src/cmd/ld/ldpe.c @@ -147,7 +147,7 @@ ldpe(Biobuf *f, char *pkg, int64 len, char *pn) goto bad; obj->sect[i].size = obj->sect[i].sh.SizeOfRawData; obj->sect[i].name = (char*)obj->sect[i].sh.Name; - // TODO return error if found .cormeta .rsrc + // TODO return error if found .cormeta } // load string table Bseek(f, base+obj->fh.PointerToSymbolTable+18*obj->fh.NumberOfSymbols, 0); @@ -222,6 +222,8 @@ ldpe(Biobuf *f, char *pkg, int64 len, char *pn) etextp = s; } sect->sym = s; + if(strcmp(sect->name, ".rsrc") == 0) + setpersrc(sect->sym); } // load relocations @@ -259,6 +261,7 @@ ldpe(Biobuf *f, char *pkg, int64 len, char *pn) rp->type = D_PCREL; rp->add = 0; break; + case IMAGE_REL_I386_DIR32NB: case IMAGE_REL_I386_DIR32: rp->type = D_ADDR; // load addend from image diff --git a/src/cmd/ld/lib.c b/src/cmd/ld/lib.c index 15219ba11..04ee790a4 100644 --- a/src/cmd/ld/lib.c +++ b/src/cmd/ld/lib.c @@ -69,7 +69,7 @@ libinit(void) // add goroot to the end of the libdir list. libdir[nlibdir++] = smprint("%s/pkg/%s_%s", goroot, goos, goarch); - unlink(outfile); + remove(outfile); cout = create(outfile, 1, 0775); if(cout < 0) { diag("cannot create %s", outfile); @@ -235,30 +235,52 @@ addlibpath(char *srcref, char *objref, char *file, char *pkg) } void -loadlib(void) +loadinternal(char *name) { char pname[1024]; int i, found; found = 0; for(i=0; i<nlibdir; i++) { - snprint(pname, sizeof pname, "%s/runtime.a", libdir[i]); + snprint(pname, sizeof pname, "%s/%s.a", libdir[i], name); if(debug['v']) - Bprint(&bso, "searching for runtime.a in %s\n", pname); + Bprint(&bso, "searching for %s.a in %s\n", name, pname); if(access(pname, AEXIST) >= 0) { - addlibpath("internal", "internal", pname, "runtime"); + addlibpath("internal", "internal", pname, name); found = 1; break; } } if(!found) - Bprint(&bso, "warning: unable to find runtime.a\n"); + Bprint(&bso, "warning: unable to find %s.a\n", name); +} + +void +loadlib(void) +{ + int i; + + loadinternal("runtime"); + if(thechar == '5') + loadinternal("math"); for(i=0; i<libraryp; i++) { if(debug['v']) Bprint(&bso, "%5.2f autolib: %s (from %s)\n", cputime(), library[i].file, library[i].objref); objfile(library[i].file, library[i].pkg); } + + // We've loaded all the code now. + // If there are no dynamic libraries needed, gcc disables dynamic linking. + // Because of this, glibc's dynamic ELF loader occasionally (like in version 2.13) + // assumes that a dynamic binary always refers to at least one dynamic library. + // Rather than be a source of test cases for glibc, disable dynamic linking + // the same way that gcc would. + // + // Exception: on OS X, programs such as Shark only work with dynamic + // binaries, so leave it enabled on OS X (Mach-O) binaries. + if(!havedynamic && HEADTYPE != Hdarwin) + debug['d'] = 1; } /* @@ -386,9 +408,6 @@ ldobj(Biobuf *f, char *pkg, int64 len, char *pn, int whence) eof = Boffset(f) + len; pn = strdup(pn); - - USED(c4); - USED(magic); c1 = Bgetc(f); c2 = Bgetc(f); @@ -398,7 +417,7 @@ ldobj(Biobuf *f, char *pkg, int64 len, char *pn, int whence) Bungetc(f); Bungetc(f); Bungetc(f); - + magic = c1<<24 | c2<<16 | c3<<8 | c4; if(magic == 0x7f454c46) { // \x7F E L F ldelf(f, pkg, len, pn); @@ -486,7 +505,6 @@ _lookup(char *symb, int v, int creat) // 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(memcmp(s->name, symb, l) == 0) return s; @@ -511,7 +529,7 @@ _lookup(char *symb, int v, int creat) s->size = 0; hash[h] = s; nsymbol++; - + s->allsym = allsym; allsym = s; return s; @@ -538,7 +556,6 @@ copyhistfrog(char *buf, int nbuf) p = buf; ep = buf + nbuf; - i = 0; for(i=0; i<histfrogp; i++) { p = seprint(p, ep, "%s", histfrog[i]->name+1); if(i+1<histfrogp && (p == buf || p[-1] != '/')) diff --git a/src/cmd/ld/lib.h b/src/cmd/ld/lib.h index 8b603a04a..dfd18fbff 100644 --- a/src/cmd/ld/lib.h +++ b/src/cmd/ld/lib.h @@ -122,6 +122,7 @@ EXTERN char* outfile; EXTERN int32 nsymbol; EXTERN char* thestring; EXTERN int ndynexp; +EXTERN int havedynamic; EXTERN Segment segtext; EXTERN Segment segdata; @@ -185,7 +186,7 @@ vlong addsize(Sym*, Sym*); vlong adduint8(Sym*, uint8); vlong adduint16(Sym*, uint16); void asmsym(void); -void asmelfsym64(void); +void asmelfsym(void); void asmplan9sym(void); void strnput(char*, int); void dodata(void); @@ -200,6 +201,7 @@ void addexport(void); void dostkcheck(void); void undef(void); void doweak(void); +void setpersrc(Sym*); int pathchar(void); void* mal(uint32); diff --git a/src/cmd/ld/macho.c b/src/cmd/ld/macho.c index 01349bb10..0b12ac17b 100644 --- a/src/cmd/ld/macho.c +++ b/src/cmd/ld/macho.c @@ -17,6 +17,14 @@ static MachoSeg seg[16]; static MachoDebug xdebug[16]; static int nload, mload, nseg, ndebug, nsect; +// Amount of space left for adding load commands +// that refer to dynamic libraries. Because these have +// to go in the Mach-O header, we can't just pick a +// "big enough" header size. The initial header is +// one page, the non-dynamic library stuff takes +// up about 1300 bytes; we overestimate that as 2k. +static int load_budget = INITIAL_MACHO_HEADR - 2*1024; + void machoinit(void) { @@ -267,6 +275,17 @@ domacho(void) void machoadddynlib(char *lib) { + // Will need to store the library name rounded up + // and 24 bytes of header metadata. If not enough + // space, grab another page of initial space at the + // beginning of the output file. + load_budget -= (strlen(lib)+7)/8*8 + 24; + if(load_budget < 0) { + HEADR += 4096; + INITTEXT += 4096; + load_budget += 4096; + } + if(ndylib%32 == 0) { dylib = realloc(dylib, (ndylib+32)*sizeof dylib[0]); if(dylib == nil) { @@ -463,8 +482,8 @@ asmbmacho(void) } a = machowrite(); - if(a > MACHORESERVE) - diag("MACHORESERVE too small: %d > %d", a, MACHORESERVE); + if(a > HEADR) + diag("HEADR too small: %d > %d", a, HEADR); } vlong diff --git a/src/cmd/ld/macho.h b/src/cmd/ld/macho.h index 4cc7edc80..f55104150 100644 --- a/src/cmd/ld/macho.h +++ b/src/cmd/ld/macho.h @@ -63,7 +63,7 @@ void machoinit(void); * for Header, PHeaders, and SHeaders. * May waste some. */ -#define MACHORESERVE 3*1024 +#define INITIAL_MACHO_HEADR 4*1024 enum { MACHO_CPU_AMD64 = (1<<24)|7, diff --git a/src/cmd/ld/pe.c b/src/cmd/ld/pe.c index d523ca9c5..91e15d343 100644 --- a/src/cmd/ld/pe.c +++ b/src/cmd/ld/pe.c @@ -34,6 +34,8 @@ static char dosstub[] = 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; +static Sym *rsrcsym; + static char symnames[256]; static int nextsymoff; @@ -459,6 +461,48 @@ addsymtable(void) } void +setpersrc(Sym *sym) +{ + if(rsrcsym != nil) + diag("too many .rsrc sections"); + + rsrcsym = sym; +} + +void +addpersrc(void) +{ + IMAGE_SECTION_HEADER *h; + uchar *p; + uint32 val; + Reloc *r; + + if(rsrcsym == nil) + return; + + h = addpesection(".rsrc", rsrcsym->size, rsrcsym->size, 0); + h->Characteristics = IMAGE_SCN_MEM_READ| + IMAGE_SCN_MEM_WRITE | IMAGE_SCN_CNT_INITIALIZED_DATA; + // relocation + for(r=rsrcsym->r; r<rsrcsym->r+rsrcsym->nr; r++) { + p = rsrcsym->p + r->off; + val = h->VirtualAddress + r->add; + // 32-bit little-endian + p[0] = val; + p[1] = val>>8; + p[2] = val>>16; + p[3] = val>>24; + } + ewrite(cout, rsrcsym->p, rsrcsym->size); + strnput("", h->SizeOfRawData - rsrcsym->size); + cflush(); + + // update data directory + dd[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress = h->VirtualAddress; + dd[IMAGE_DIRECTORY_ENTRY_RESOURCE].Size = h->VirtualSize; +} + +void asmbpe(void) { IMAGE_SECTION_HEADER *t, *d; @@ -484,15 +528,17 @@ asmbpe(void) d->Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA| IMAGE_SCN_MEM_READ|IMAGE_SCN_MEM_WRITE; + if(!debug['s']) + dwarfaddpeheaders(); + addimports(nextfileoff, d); addexports(nextfileoff); - if(!debug['s']) - dwarfaddpeheaders(); - addsymtable(); - + + addpersrc(); + fh.NumberOfSections = nsect; fh.TimeDateStamp = time(0); fh.Characteristics = IMAGE_FILE_RELOCS_STRIPPED| diff --git a/src/cmd/ld/pe.h b/src/cmd/ld/pe.h index 2180fb88c..7aa938829 100644 --- a/src/cmd/ld/pe.h +++ b/src/cmd/ld/pe.h @@ -175,3 +175,5 @@ typedef struct { uint32 NumberOfRvaAndSizes; IMAGE_DATA_DIRECTORY DataDirectory[16]; } PE64_IMAGE_OPTIONAL_HEADER; + +void setpersrc(Sym *sym); diff --git a/src/cmd/ld/symtab.c b/src/cmd/ld/symtab.c index da698fcc0..e3093b2aa 100644 --- a/src/cmd/ld/symtab.c +++ b/src/cmd/ld/symtab.c @@ -61,49 +61,35 @@ putelfstr(char *s) } void -putelfsym64(Sym *x, char *s, int t, vlong addr, vlong size, int ver, Sym *go) +putelfsyment(int off, vlong addr, vlong size, int info, int shndx) { - int bind, type, shndx, stroff; - - bind = STB_GLOBAL; - switch(t) { - default: - return; - case 'T': - type = STT_FUNC; - shndx = elftextsh + 0; - break; - case 'D': - type = STT_OBJECT; - shndx = elftextsh + 1; + switch(thechar) { + case '6': + LPUT(off); + cput(info); + cput(0); + WPUT(shndx); + VPUT(addr); + VPUT(size); + symsize += ELF64SYMSIZE; break; - case 'B': - type = STT_OBJECT; - shndx = elftextsh + 2; + default: + LPUT(off); + LPUT(addr); + LPUT(size); + cput(info); + cput(0); + WPUT(shndx); + symsize += ELF32SYMSIZE; break; } - - stroff = putelfstr(s); - LPUT(stroff); // string - cput((bind<<4)|(type&0xF)); - cput(0); - WPUT(shndx); - VPUT(addr); - VPUT(size); } void -asmelfsym64(void) +putelfsym(Sym *x, char *s, int t, vlong addr, vlong size, int ver, Sym *go) { - genasmsym(putelfsym64); -} + int bind, type, shndx, off; -void -putelfsym32(Sym *x, char *s, int t, vlong addr, vlong size, int ver, Sym *go) -{ - int bind, type, shndx, stroff; - - bind = STB_GLOBAL; switch(t) { default: return; @@ -113,27 +99,27 @@ putelfsym32(Sym *x, char *s, int t, vlong addr, vlong size, int ver, Sym *go) break; case 'D': type = STT_OBJECT; - shndx = elftextsh + 1; + if((x->type&~SSUB) == SRODATA) + shndx = elftextsh + 1; + else + shndx = elftextsh + 2; break; case 'B': type = STT_OBJECT; - shndx = elftextsh + 2; + shndx = elftextsh + 3; break; } - - stroff = putelfstr(s); - LPUT(stroff); // string - LPUT(addr); - LPUT(size); - cput((bind<<4)|(type&0xF)); - cput(0); - WPUT(shndx); + bind = ver ? STB_LOCAL : STB_GLOBAL; + off = putelfstr(s); + putelfsyment(off, addr, size, (bind<<4)|(type&0xf), shndx); } void -asmelfsym32(void) +asmelfsym(void) { - genasmsym(putelfsym32); + // the first symbol entry is reserved + putelfsyment(0, 0, 0, (STB_LOCAL<<4)|STT_NOTYPE, 0); + genasmsym(putelfsym); } void |