diff options
Diffstat (limited to 'src/cmd/ld')
-rw-r--r-- | src/cmd/ld/data.c | 357 | ||||
-rw-r--r-- | src/cmd/ld/decodesym.c | 38 | ||||
-rw-r--r-- | src/cmd/ld/doc.go | 6 | ||||
-rw-r--r-- | src/cmd/ld/dwarf.c | 156 | ||||
-rw-r--r-- | src/cmd/ld/elf.c | 3 | ||||
-rw-r--r-- | src/cmd/ld/ldelf.c | 8 | ||||
-rw-r--r-- | src/cmd/ld/ldmacho.c | 4 | ||||
-rw-r--r-- | src/cmd/ld/ldpe.c | 32 | ||||
-rw-r--r-- | src/cmd/ld/lib.c | 91 | ||||
-rw-r--r-- | src/cmd/ld/lib.h | 14 | ||||
-rw-r--r-- | src/cmd/ld/macho.c | 3 | ||||
-rw-r--r-- | src/cmd/ld/pass.c | 104 | ||||
-rw-r--r-- | src/cmd/ld/pcln.c | 6 | ||||
-rw-r--r-- | src/cmd/ld/pobj.c | 22 | ||||
-rw-r--r-- | src/cmd/ld/symtab.c | 55 | ||||
-rw-r--r-- | src/cmd/ld/textflag.h | 13 |
16 files changed, 564 insertions, 348 deletions
diff --git a/src/cmd/ld/data.c b/src/cmd/ld/data.c index 55d020710..61847546a 100644 --- a/src/cmd/ld/data.c +++ b/src/cmd/ld/data.c @@ -35,7 +35,7 @@ #include "../ld/elf.h" #include "../ld/macho.h" #include "../ld/pe.h" -#include "../../pkg/runtime/mgc0.h" +#include "../../runtime/mgc0.h" void dynreloc(void); @@ -145,7 +145,7 @@ relocsym(LSym *s) diag("%s: invalid relocation %d+%d not in [%d,%d)", s->name, off, siz, 0, s->np); continue; } - if(r->sym != S && (r->sym->type & SMASK == 0 || r->sym->type & SMASK == SXREF)) { + if(r->sym != S && ((r->sym->type & (SMASK | SHIDDEN)) == 0 || (r->sym->type & SMASK) == SXREF)) { diag("%s: not defined", r->sym->name); continue; } @@ -160,6 +160,10 @@ relocsym(LSym *s) if(r->sym != S && r->sym->type != STLSBSS && !r->sym->reachable) diag("unreachable sym in relocation: %s %s", s->name, r->sym->name); + // Android emulates runtime.tlsg as a regular variable. + if (r->type == R_TLS && strcmp(goos, "android") == 0) + r->type = R_ADDR; + switch(r->type) { default: o = 0; @@ -186,8 +190,8 @@ relocsym(LSym *s) case R_TLS_LE: if(linkmode == LinkExternal && iself && HEADTYPE != Hopenbsd) { r->done = 0; - r->sym = ctxt->gmsym; - r->xsym = ctxt->gmsym; + r->sym = ctxt->tlsg; + r->xsym = ctxt->tlsg; r->xadd = r->add; o = 0; if(thechar != '6') @@ -200,8 +204,8 @@ relocsym(LSym *s) case R_TLS_IE: if(linkmode == LinkExternal && iself && HEADTYPE != Hopenbsd) { r->done = 0; - r->sym = ctxt->gmsym; - r->xsym = ctxt->gmsym; + r->sym = ctxt->tlsg; + r->xsym = ctxt->tlsg; r->xadd = r->add; o = 0; if(thechar != '6') @@ -277,9 +281,13 @@ relocsym(LSym *s) if(thechar == '6') o = 0; } else if(HEADTYPE == Hdarwin) { - if(rs->type != SHOSTOBJ) - o += symaddr(rs) - rs->sect->vaddr; - o -= r->off; // WTF? + if(r->type == R_CALL) { + if(rs->type != SHOSTOBJ) + o += symaddr(rs) - rs->sect->vaddr; + o -= r->off; // relative to section offset, not symbol + } else { + o += r->siz; + } } else { diag("unhandled pcrel relocation for %s", headstring); } @@ -421,10 +429,10 @@ dynreloc(void) } static void -blk(LSym *start, int32 addr, int32 size) +blk(LSym *start, int64 addr, int64 size) { LSym *sym; - int32 eaddr; + int64 eaddr; uchar *p, *ep; for(sym = start; sym != nil; sym = sym->next) @@ -463,10 +471,10 @@ blk(LSym *start, int32 addr, int32 size) } void -codeblk(int32 addr, int32 size) +codeblk(int64 addr, int64 size) { LSym *sym; - int32 eaddr, n; + int64 eaddr, n; uchar *q; if(debug['a']) @@ -523,10 +531,10 @@ codeblk(int32 addr, int32 size) } void -datblk(int32 addr, int32 size) +datblk(int64 addr, int64 size) { LSym *sym; - int32 i, eaddr; + int64 i, eaddr; uchar *p, *ep; char *typ, *rsname; Reloc *r; @@ -612,22 +620,26 @@ addstrdata(char *name, char *value) { LSym *s, *sp; char *p; + uchar reachable; p = smprint("%s.str", name); sp = linklookup(ctxt, p, 0); free(p); addstring(sp, value); + sp->type = SRODATA; s = linklookup(ctxt, name, 0); s->size = 0; s->dupok = 1; + reachable = s->reachable; addaddr(ctxt, s, sp); - adduint32(ctxt, s, strlen(value)); - if(PtrSize == 8) - adduint32(ctxt, s, 0); // round struct to pointer width + adduintxx(ctxt, s, strlen(value), PtrSize); - // in case reachability has already been computed - sp->reachable = s->reachable; + // addstring, addaddr, etc., mark the symbols as reachable. + // In this case that is not necessarily true, so stick to what + // we know before entering this function. + s->reachable = reachable; + sp->reachable = reachable; } vlong @@ -702,31 +714,176 @@ maxalign(LSym *s, int type) return max; } +// Helper object for building GC type programs. +typedef struct ProgGen ProgGen; +struct ProgGen +{ + LSym* s; + int32 datasize; + uint8 data[256/PointersPerByte]; + vlong pos; +}; + static void -gcaddsym(LSym *gc, LSym *s, vlong off) +proggeninit(ProgGen *g, LSym *s) { - vlong a; - LSym *gotype; + g->s = s; + g->datasize = 0; + g->pos = 0; + memset(g->data, 0, sizeof(g->data)); +} - if(s->size < PtrSize) +static void +proggenemit(ProgGen *g, uint8 v) +{ + adduint8(ctxt, g->s, v); +} + +// Writes insData block from g->data. +static void +proggendataflush(ProgGen *g) +{ + int32 i, s; + + if(g->datasize == 0) return; - if(strcmp(s->name, ".string") == 0) + proggenemit(g, insData); + proggenemit(g, g->datasize); + s = (g->datasize + PointersPerByte - 1)/PointersPerByte; + for(i = 0; i < s; i++) + proggenemit(g, g->data[i]); + g->datasize = 0; + memset(g->data, 0, sizeof(g->data)); +} + +static void +proggendata(ProgGen *g, uint8 d) +{ + g->data[g->datasize/PointersPerByte] |= d << ((g->datasize%PointersPerByte)*BitsPerPointer); + g->datasize++; + if(g->datasize == 255) + proggendataflush(g); +} + +// Skip v bytes due to alignment, etc. +static void +proggenskip(ProgGen *g, vlong off, vlong v) +{ + vlong i; + + for(i = off; i < off+v; i++) { + if((i%PtrSize) == 0) + proggendata(g, BitsScalar); + } +} + +// Emit insArray instruction. +static void +proggenarray(ProgGen *g, vlong len) +{ + int32 i; + + proggendataflush(g); + proggenemit(g, insArray); + for(i = 0; i < PtrSize; i++, len >>= 8) + proggenemit(g, len); +} + +static void +proggenarrayend(ProgGen *g) +{ + proggendataflush(g); + proggenemit(g, insArrayEnd); +} + +static void +proggenfini(ProgGen *g, vlong size) +{ + proggenskip(g, g->pos, size - g->pos); + proggendataflush(g); + proggenemit(g, insEnd); +} + + +// This function generates GC pointer info for global variables. +static void +proggenaddsym(ProgGen *g, LSym *s) +{ + LSym *gcprog; + uint8 *mask; + vlong i, size; + + if(s->size == 0) return; - gotype = s->gotype; - if(gotype != nil) { - //print("gcaddsym: %s %d %s\n", s->name, s->size, gotype->name); - adduintxx(ctxt, gc, GC_CALL, PtrSize); - adduintxx(ctxt, gc, off, PtrSize); - addpcrelplus(ctxt, gc, decodetype_gc(gotype), 3*PtrSize+4); - if(PtrSize == 8) - adduintxx(ctxt, gc, 0, 4); - } else { - //print("gcaddsym: %s %d <unknown type>\n", s->name, s->size); - for(a = -off&(PtrSize-1); a+PtrSize<=s->size; a+=PtrSize) { - adduintxx(ctxt, gc, GC_APTR, PtrSize); - adduintxx(ctxt, gc, off+a, PtrSize); + // Skip alignment hole from the previous symbol. + proggenskip(g, g->pos, s->value - g->pos); + g->pos += s->value - g->pos; + + // The test for names beginning with . here is meant + // to keep .dynamic and .dynsym from turning up as + // conservative symbols. They should be marked SELFSECT + // and not SDATA, but sometimes that doesn't happen. + // Leave debugging the SDATA issue for the Go rewrite. + + if(s->gotype == nil && s->size >= PtrSize && s->name[0] != '.') { + // conservative scan + diag("missing Go type information for global symbol: %s size %d", s->name, (int)s->size); + if((s->size%PtrSize) || (g->pos%PtrSize)) + diag("proggenaddsym: unaligned conservative symbol %s: size=%lld pos=%lld", + s->name, s->size, g->pos); + size = (s->size+PtrSize-1)/PtrSize*PtrSize; + if(size < 32*PtrSize) { + // Emit small symbols as data. + for(i = 0; i < size/PtrSize; i++) + proggendata(g, BitsPointer); + } else { + // Emit large symbols as array. + proggenarray(g, size/PtrSize); + proggendata(g, BitsPointer); + proggenarrayend(g); + } + g->pos = s->value + size; + } else if(s->gotype == nil || decodetype_noptr(s->gotype) || s->size < PtrSize || s->name[0] == '.') { + // no scan + if(s->size < 32*PtrSize) { + // Emit small symbols as data. + // This case also handles unaligned and tiny symbols, so tread carefully. + for(i = s->value; i < s->value+s->size; i++) { + if((i%PtrSize) == 0) + proggendata(g, BitsScalar); + } + } else { + // Emit large symbols as array. + if((s->size%PtrSize) || (g->pos%PtrSize)) + diag("proggenaddsym: unaligned noscan symbol %s: size=%lld pos=%lld", + s->name, s->size, g->pos); + proggenarray(g, s->size/PtrSize); + proggendata(g, BitsScalar); + proggenarrayend(g); } + g->pos = s->value + s->size; + } else if(decodetype_usegcprog(s->gotype)) { + // gc program, copy directly + proggendataflush(g); + gcprog = decodetype_gcprog(s->gotype); + size = decodetype_size(s->gotype); + if((size%PtrSize) || (g->pos%PtrSize)) + diag("proggenaddsym: unaligned gcprog symbol %s: size=%lld pos=%lld", + s->name, s->size, g->pos); + for(i = 0; i < gcprog->np-1; i++) + proggenemit(g, gcprog->p[i]); + g->pos = s->value + size; + } else { + // gc mask, it's small so emit as data + mask = decodetype_gcmask(s->gotype); + size = decodetype_size(s->gotype); + if((size%PtrSize) || (g->pos%PtrSize)) + diag("proggenaddsym: unaligned gcmask symbol %s: size=%lld pos=%lld", + s->name, s->size, g->pos); + for(i = 0; i < size; i += PtrSize) + proggendata(g, (mask[i/PtrSize/2]>>((i/PtrSize%2)*4+2))&BitsMask); + g->pos = s->value + size; } } @@ -751,19 +908,13 @@ dodata(void) Section *sect; Segment *segro; LSym *s, *last, **l; - LSym *gcdata1, *gcbss1; + LSym *gcdata, *gcbss; + ProgGen gen; if(debug['v']) Bprint(&bso, "%5.2f dodata\n", cputime()); Bflush(&bso); - gcdata1 = linklookup(ctxt, "gcdata", 0); - gcbss1 = linklookup(ctxt, "gcbss", 0); - - // size of .data and .bss section. the zero value is later replaced by the actual size of the section. - adduintxx(ctxt, gcdata1, 0, PtrSize); - adduintxx(ctxt, gcbss1, 0, PtrSize); - last = nil; datap = nil; @@ -847,8 +998,8 @@ dodata(void) sect->align = maxalign(s, SINITARR-1); datsize = rnd(datsize, sect->align); sect->vaddr = datsize; - linklookup(ctxt, "noptrdata", 0)->sect = sect; - linklookup(ctxt, "enoptrdata", 0)->sect = sect; + linklookup(ctxt, "runtime.noptrdata", 0)->sect = sect; + linklookup(ctxt, "runtime.enoptrdata", 0)->sect = sect; for(; s != nil && s->type < SINITARR; s = s->next) { datsize = aligndatsize(datsize, s); s->sect = sect; @@ -878,8 +1029,10 @@ dodata(void) sect->align = maxalign(s, SBSS-1); datsize = rnd(datsize, sect->align); sect->vaddr = datsize; - linklookup(ctxt, "data", 0)->sect = sect; - linklookup(ctxt, "edata", 0)->sect = sect; + linklookup(ctxt, "runtime.data", 0)->sect = sect; + linklookup(ctxt, "runtime.edata", 0)->sect = sect; + gcdata = linklookup(ctxt, "runtime.gcdata", 0); + proggeninit(&gen, gcdata); for(; s != nil && s->type < SBSS; s = s->next) { if(s->type == SINITARR) { ctxt->cursym = s; @@ -889,40 +1042,38 @@ dodata(void) s->type = SDATA; datsize = aligndatsize(datsize, s); s->value = datsize - sect->vaddr; - gcaddsym(gcdata1, s, datsize - sect->vaddr); // gc + proggenaddsym(&gen, s); // gc growdatsize(&datsize, s); } sect->len = datsize - sect->vaddr; - - adduintxx(ctxt, gcdata1, GC_END, PtrSize); - setuintxx(ctxt, gcdata1, 0, sect->len, PtrSize); + proggenfini(&gen, sect->len); // gc /* bss */ sect = addsection(&segdata, ".bss", 06); sect->align = maxalign(s, SNOPTRBSS-1); datsize = rnd(datsize, sect->align); sect->vaddr = datsize; - linklookup(ctxt, "bss", 0)->sect = sect; - linklookup(ctxt, "ebss", 0)->sect = sect; + linklookup(ctxt, "runtime.bss", 0)->sect = sect; + linklookup(ctxt, "runtime.ebss", 0)->sect = sect; + gcbss = linklookup(ctxt, "runtime.gcbss", 0); + proggeninit(&gen, gcbss); for(; s != nil && s->type < SNOPTRBSS; s = s->next) { s->sect = sect; datsize = aligndatsize(datsize, s); s->value = datsize - sect->vaddr; - gcaddsym(gcbss1, s, datsize - sect->vaddr); // gc + proggenaddsym(&gen, s); // gc growdatsize(&datsize, s); } sect->len = datsize - sect->vaddr; - - adduintxx(ctxt, gcbss1, GC_END, PtrSize); - setuintxx(ctxt, gcbss1, 0, sect->len, PtrSize); + proggenfini(&gen, sect->len); // gc /* pointer-free bss */ sect = addsection(&segdata, ".noptrbss", 06); sect->align = maxalign(s, SNOPTRBSS); datsize = rnd(datsize, sect->align); sect->vaddr = datsize; - linklookup(ctxt, "noptrbss", 0)->sect = sect; - linklookup(ctxt, "enoptrbss", 0)->sect = sect; + linklookup(ctxt, "runtime.noptrbss", 0)->sect = sect; + linklookup(ctxt, "runtime.enoptrbss", 0)->sect = sect; for(; s != nil && s->type == SNOPTRBSS; s = s->next) { datsize = aligndatsize(datsize, s); s->sect = sect; @@ -930,7 +1081,7 @@ dodata(void) growdatsize(&datsize, s); } sect->len = datsize - sect->vaddr; - linklookup(ctxt, "end", 0)->sect = sect; + linklookup(ctxt, "runtime.end", 0)->sect = sect; // 6g uses 4-byte relocation offsets, so the entire segment must fit in 32 bits. if(datsize != (uint32)datsize) { @@ -951,9 +1102,9 @@ dodata(void) sect->len = datsize; } else { // Might be internal linking but still using cgo. - // In that case, the only possible STLSBSS symbol is tlsgm. + // In that case, the only possible STLSBSS symbol is runtime.tlsg. // Give it offset 0, because it's the only thing here. - if(s != nil && s->type == STLSBSS && strcmp(s->name, "runtime.tlsgm") == 0) { + if(s != nil && s->type == STLSBSS && strcmp(s->name, "runtime.tlsg") == 0) { s->value = 0; s = s->next; } @@ -1001,8 +1152,8 @@ dodata(void) sect->align = maxalign(s, STYPELINK-1); datsize = rnd(datsize, sect->align); sect->vaddr = 0; - linklookup(ctxt, "rodata", 0)->sect = sect; - linklookup(ctxt, "erodata", 0)->sect = sect; + linklookup(ctxt, "runtime.rodata", 0)->sect = sect; + linklookup(ctxt, "runtime.erodata", 0)->sect = sect; for(; s != nil && s->type < STYPELINK; s = s->next) { datsize = aligndatsize(datsize, s); s->sect = sect; @@ -1017,8 +1168,8 @@ dodata(void) sect->align = maxalign(s, STYPELINK); datsize = rnd(datsize, sect->align); sect->vaddr = datsize; - linklookup(ctxt, "typelink", 0)->sect = sect; - linklookup(ctxt, "etypelink", 0)->sect = sect; + linklookup(ctxt, "runtime.typelink", 0)->sect = sect; + linklookup(ctxt, "runtime.etypelink", 0)->sect = sect; for(; s != nil && s->type == STYPELINK; s = s->next) { datsize = aligndatsize(datsize, s); s->sect = sect; @@ -1033,8 +1184,8 @@ dodata(void) sect->align = maxalign(s, SPCLNTAB-1); datsize = rnd(datsize, sect->align); sect->vaddr = datsize; - linklookup(ctxt, "symtab", 0)->sect = sect; - linklookup(ctxt, "esymtab", 0)->sect = sect; + linklookup(ctxt, "runtime.symtab", 0)->sect = sect; + linklookup(ctxt, "runtime.esymtab", 0)->sect = sect; for(; s != nil && s->type < SPCLNTAB; s = s->next) { datsize = aligndatsize(datsize, s); s->sect = sect; @@ -1049,8 +1200,8 @@ dodata(void) sect->align = maxalign(s, SELFROSECT-1); datsize = rnd(datsize, sect->align); sect->vaddr = datsize; - linklookup(ctxt, "pclntab", 0)->sect = sect; - linklookup(ctxt, "epclntab", 0)->sect = sect; + linklookup(ctxt, "runtime.pclntab", 0)->sect = sect; + linklookup(ctxt, "runtime.epclntab", 0)->sect = sect; for(; s != nil && s->type < SELFROSECT; s = s->next) { datsize = aligndatsize(datsize, s); s->sect = sect; @@ -1103,8 +1254,8 @@ textaddress(void) // and then letting threads copy down, but probably not worth it. sect = segtext.sect; sect->align = funcalign; - linklookup(ctxt, "text", 0)->sect = sect; - linklookup(ctxt, "etext", 0)->sect = sect; + linklookup(ctxt, "runtime.text", 0)->sect = sect; + linklookup(ctxt, "runtime.etext", 0)->sect = sect; va = INITTEXT; sect->vaddr = va; for(sym = ctxt->textp; sym != nil; sym = sym->next) { @@ -1215,32 +1366,32 @@ address(void) sub->value += sym->value; } - xdefine("text", STEXT, text->vaddr); - xdefine("etext", STEXT, text->vaddr + text->len); - xdefine("rodata", SRODATA, rodata->vaddr); - xdefine("erodata", SRODATA, rodata->vaddr + rodata->len); - xdefine("typelink", SRODATA, typelink->vaddr); - xdefine("etypelink", SRODATA, typelink->vaddr + typelink->len); - - sym = linklookup(ctxt, "gcdata", 0); - xdefine("egcdata", SRODATA, symaddr(sym) + sym->size); - linklookup(ctxt, "egcdata", 0)->sect = sym->sect; - - sym = linklookup(ctxt, "gcbss", 0); - xdefine("egcbss", SRODATA, symaddr(sym) + sym->size); - linklookup(ctxt, "egcbss", 0)->sect = sym->sect; - - xdefine("symtab", SRODATA, symtab->vaddr); - xdefine("esymtab", SRODATA, symtab->vaddr + symtab->len); - xdefine("pclntab", SRODATA, pclntab->vaddr); - xdefine("epclntab", SRODATA, pclntab->vaddr + pclntab->len); - xdefine("noptrdata", SNOPTRDATA, noptr->vaddr); - xdefine("enoptrdata", SNOPTRDATA, noptr->vaddr + noptr->len); - xdefine("bss", SBSS, bss->vaddr); - xdefine("ebss", SBSS, bss->vaddr + bss->len); - xdefine("data", SDATA, data->vaddr); - xdefine("edata", SDATA, data->vaddr + data->len); - xdefine("noptrbss", SNOPTRBSS, noptrbss->vaddr); - xdefine("enoptrbss", SNOPTRBSS, noptrbss->vaddr + noptrbss->len); - xdefine("end", SBSS, segdata.vaddr + segdata.len); + xdefine("runtime.text", STEXT, text->vaddr); + xdefine("runtime.etext", STEXT, text->vaddr + text->len); + xdefine("runtime.rodata", SRODATA, rodata->vaddr); + xdefine("runtime.erodata", SRODATA, rodata->vaddr + rodata->len); + xdefine("runtime.typelink", SRODATA, typelink->vaddr); + xdefine("runtime.etypelink", SRODATA, typelink->vaddr + typelink->len); + + sym = linklookup(ctxt, "runtime.gcdata", 0); + xdefine("runtime.egcdata", SRODATA, symaddr(sym) + sym->size); + linklookup(ctxt, "runtime.egcdata", 0)->sect = sym->sect; + + sym = linklookup(ctxt, "runtime.gcbss", 0); + xdefine("runtime.egcbss", SRODATA, symaddr(sym) + sym->size); + linklookup(ctxt, "runtime.egcbss", 0)->sect = sym->sect; + + xdefine("runtime.symtab", SRODATA, symtab->vaddr); + xdefine("runtime.esymtab", SRODATA, symtab->vaddr + symtab->len); + xdefine("runtime.pclntab", SRODATA, pclntab->vaddr); + xdefine("runtime.epclntab", SRODATA, pclntab->vaddr + pclntab->len); + xdefine("runtime.noptrdata", SNOPTRDATA, noptr->vaddr); + xdefine("runtime.enoptrdata", SNOPTRDATA, noptr->vaddr + noptr->len); + xdefine("runtime.bss", SBSS, bss->vaddr); + xdefine("runtime.ebss", SBSS, bss->vaddr + bss->len); + xdefine("runtime.data", SDATA, data->vaddr); + xdefine("runtime.edata", SDATA, data->vaddr + data->len); + xdefine("runtime.noptrbss", SNOPTRBSS, noptrbss->vaddr); + xdefine("runtime.enoptrbss", SNOPTRBSS, noptrbss->vaddr + noptrbss->len); + xdefine("runtime.end", SBSS, segdata.vaddr + segdata.len); } diff --git a/src/cmd/ld/decodesym.c b/src/cmd/ld/decodesym.c index da48d3786..037263dce 100644 --- a/src/cmd/ld/decodesym.c +++ b/src/cmd/ld/decodesym.c @@ -4,10 +4,10 @@ #include "l.h" #include "lib.h" -#include "../../pkg/runtime/typekind.h" +#include "../../runtime/typekind.h" // Decoding the type.* symbols. This has to be in sync with -// ../../pkg/runtime/type.go, or more specificaly, with what +// ../../runtime/type.go, or more specificaly, with what // ../gc/reflect.c stuffs in these. static Reloc* @@ -70,14 +70,28 @@ decode_inuxi(uchar* p, int sz) static int commonsize(void) { - return 7*PtrSize + 8; + return 8*PtrSize + 8; } // Type.commonType.kind uint8 decodetype_kind(LSym *s) { - return s->p[1*PtrSize + 7] & ~KindNoPointers; // 0x13 / 0x1f + return s->p[1*PtrSize + 7] & KindMask; // 0x13 / 0x1f +} + +// Type.commonType.kind +uint8 +decodetype_noptr(LSym *s) +{ + return s->p[1*PtrSize + 7] & KindNoPointers; // 0x13 / 0x1f +} + +// Type.commonType.kind +uint8 +decodetype_usegcprog(LSym *s) +{ + return s->p[1*PtrSize + 7] & KindGCProg; // 0x13 / 0x1f } // Type.commonType.size @@ -89,9 +103,18 @@ decodetype_size(LSym *s) // Type.commonType.gc LSym* -decodetype_gc(LSym *s) +decodetype_gcprog(LSym *s) { - return decode_reloc_sym(s, 1*PtrSize + 8 + 1*PtrSize); + return decode_reloc_sym(s, 1*PtrSize + 8 + 2*PtrSize); +} + +uint8* +decodetype_gcmask(LSym *s) +{ + LSym *mask; + + mask = decode_reloc_sym(s, 1*PtrSize + 8 + 1*PtrSize); + return mask->p; } // Type.ArrayType.elem and Type.SliceType.Elem @@ -104,7 +127,7 @@ decodetype_arrayelem(LSym *s) vlong decodetype_arraylen(LSym *s) { - return decode_inuxi(s->p + commonsize()+PtrSize, PtrSize); + return decode_inuxi(s->p + commonsize()+2*PtrSize, PtrSize); } // Type.PtrType.elem @@ -120,6 +143,7 @@ decodetype_mapkey(LSym *s) { return decode_reloc_sym(s, commonsize()); // 0x1c / 0x30 } + LSym* decodetype_mapvalue(LSym *s) { diff --git a/src/cmd/ld/doc.go b/src/cmd/ld/doc.go index 8135bd549..5b5833db5 100644 --- a/src/cmd/ld/doc.go +++ b/src/cmd/ld/doc.go @@ -63,9 +63,9 @@ Options new in this version: -w Omit the DWARF symbol table. -X symbol value - Set the value of an otherwise uninitialized string variable. - The symbol name should be of the form importpath.name, - as displayed in the symbol table printed by "go tool nm". + Set the value of a string variable. The symbol name + should be of the form importpath.name, as displayed + in the symbol table printed by "go tool nm". -race Link with race detection libraries. -B value diff --git a/src/cmd/ld/dwarf.c b/src/cmd/ld/dwarf.c index cc77b45cd..a3ba52325 100644 --- a/src/cmd/ld/dwarf.c +++ b/src/cmd/ld/dwarf.c @@ -19,7 +19,7 @@ #include "../ld/elf.h" #include "../ld/macho.h" #include "../ld/pe.h" -#include "../../pkg/runtime/typekind.h" +#include "../../runtime/typekind.h" /* * Offsets and sizes of the debug_* sections in the cout file. @@ -141,16 +141,22 @@ sleb128put(vlong v) * only a handful of them. The DWARF spec places no restriction on * the ordering of attributes in the Abbrevs and DIEs, and we will * always write them out in the order of declaration in the abbrev. - * This implementation relies on tag, attr < 127, so they serialize as - * a char. Higher numbered user-defined tags or attributes can be used - * for storing internal data but won't be serialized. */ typedef struct DWAttrForm DWAttrForm; struct DWAttrForm { - uint8 attr; + uint16 attr; uint8 form; }; +// Go-specific type attributes. +enum { + DW_AT_go_kind = 0x2900, + DW_AT_go_key = 0x2901, + DW_AT_go_elem = 0x2902, + + DW_AT_internal_location = 253, // params and locals; not emitted +}; + // Index into the abbrevs table below. // Keep in sync with ispubname() and ispubtype() below. // ispubtype considers >= NULLTYPE public @@ -260,7 +266,7 @@ static struct DWAbbrev { DW_TAG_subrange_type, DW_CHILDREN_no, // No name! DW_AT_type, DW_FORM_ref_addr, - DW_AT_upper_bound, DW_FORM_data1, + DW_AT_count, DW_FORM_udata, 0, 0 }, @@ -277,6 +283,7 @@ static struct DWAbbrev { DW_AT_name, DW_FORM_string, DW_AT_encoding, DW_FORM_data1, DW_AT_byte_size, DW_FORM_data1, + DW_AT_go_kind, DW_FORM_data1, 0, 0 }, /* ARRAYTYPE */ @@ -286,6 +293,7 @@ static struct DWAbbrev { DW_AT_name, DW_FORM_string, DW_AT_type, DW_FORM_ref_addr, DW_AT_byte_size, DW_FORM_udata, + DW_AT_go_kind, DW_FORM_data1, 0, 0 }, @@ -294,6 +302,8 @@ static struct DWAbbrev { DW_TAG_typedef, DW_CHILDREN_no, DW_AT_name, DW_FORM_string, DW_AT_type, DW_FORM_ref_addr, + DW_AT_go_kind, DW_FORM_data1, + DW_AT_go_elem, DW_FORM_ref_addr, 0, 0 }, @@ -302,6 +312,7 @@ static struct DWAbbrev { DW_TAG_subroutine_type, DW_CHILDREN_yes, DW_AT_name, DW_FORM_string, // DW_AT_type, DW_FORM_ref_addr, + DW_AT_go_kind, DW_FORM_data1, 0, 0 }, @@ -310,6 +321,7 @@ static struct DWAbbrev { DW_TAG_typedef, DW_CHILDREN_yes, DW_AT_name, DW_FORM_string, DW_AT_type, DW_FORM_ref_addr, + DW_AT_go_kind, DW_FORM_data1, 0, 0 }, @@ -318,6 +330,9 @@ static struct DWAbbrev { DW_TAG_typedef, DW_CHILDREN_no, DW_AT_name, DW_FORM_string, DW_AT_type, DW_FORM_ref_addr, + DW_AT_go_kind, DW_FORM_data1, + DW_AT_go_key, DW_FORM_ref_addr, + DW_AT_go_elem, DW_FORM_ref_addr, 0, 0 }, @@ -326,6 +341,7 @@ static struct DWAbbrev { DW_TAG_pointer_type, DW_CHILDREN_no, DW_AT_name, DW_FORM_string, DW_AT_type, DW_FORM_ref_addr, + DW_AT_go_kind, DW_FORM_data1, 0, 0 }, /* BARE_PTRTYPE */ @@ -340,6 +356,8 @@ static struct DWAbbrev { DW_TAG_structure_type, DW_CHILDREN_yes, DW_AT_name, DW_FORM_string, DW_AT_byte_size, DW_FORM_udata, + DW_AT_go_kind, DW_FORM_data1, + DW_AT_go_elem, DW_FORM_ref_addr, 0, 0 }, @@ -348,6 +366,7 @@ static struct DWAbbrev { DW_TAG_structure_type, DW_CHILDREN_yes, DW_AT_name, DW_FORM_string, DW_AT_byte_size, DW_FORM_udata, + DW_AT_go_kind, DW_FORM_data1, 0, 0 }, @@ -356,6 +375,7 @@ static struct DWAbbrev { DW_TAG_structure_type, DW_CHILDREN_yes, DW_AT_name, DW_FORM_string, DW_AT_byte_size, DW_FORM_udata, + DW_AT_go_kind, DW_FORM_data1, 0, 0 }, @@ -371,7 +391,8 @@ static struct DWAbbrev { static void writeabbrev(void) { - int i, n; + int i, j; + DWAttrForm *f; abbrevo = cpos(); for (i = 1; i < DW_NABRV; i++) { @@ -379,11 +400,13 @@ writeabbrev(void) uleb128put(i); uleb128put(abbrevs[i].tag); cput(abbrevs[i].children); - // 0 is not a valid attr or form, and DWAbbrev.attr is - // 0-terminated, so we can treat it as a string - n = strlen((char*)abbrevs[i].attr) / 2; - strnput((char*)abbrevs[i].attr, - (n+1) * sizeof(DWAttrForm)); + for(j=0; j<nelem(abbrevs[i].attr); j++) { + f = &abbrevs[i].attr[j]; + uleb128put(f->attr); + uleb128put(f->form); + if(f->attr == 0) + break; + } } cput(0); abbrevsize = cpos() - abbrevo; @@ -417,7 +440,7 @@ hashstr(char* s) typedef struct DWAttr DWAttr; struct DWAttr { DWAttr *link; - uint8 atr; // DW_AT_ + uint16 atr; // DW_AT_ uint8 cls; // DW_CLS_ vlong value; char *data; @@ -445,7 +468,7 @@ static DWDie dwtypes; static DWDie dwglobals; static DWAttr* -newattr(DWDie *die, uint8 attr, int cls, vlong value, char *data) +newattr(DWDie *die, uint16 attr, int cls, vlong value, char *data) { DWAttr *a; @@ -463,7 +486,7 @@ newattr(DWDie *die, uint8 attr, int cls, vlong value, char *data) // name. getattr moves the desired one to the front so // frequently searched ones are found faster. static DWAttr* -getattr(DWDie *die, uint8 attr) +getattr(DWDie *die, uint16 attr) { DWAttr *a, *b; @@ -622,7 +645,7 @@ adddwarfrel(LSym* sec, LSym* sym, vlong offsetbase, int siz, vlong addend) } static DWAttr* -newrefattr(DWDie *die, uint8 attr, DWDie* ref) +newrefattr(DWDie *die, uint16 attr, DWDie* ref) { if (ref == nil) return nil; @@ -762,22 +785,22 @@ putattr(int abbrev, int form, int cls, vlong value, char *data) static void putattrs(int abbrev, DWAttr* attr) { - DWAttr *attrs[DW_AT_recursive + 1]; DWAttrForm* af; - - memset(attrs, 0, sizeof attrs); - for( ; attr; attr = attr->link) - if (attr->atr < nelem(attrs)) - attrs[attr->atr] = attr; - - for(af = abbrevs[abbrev].attr; af->attr; af++) - if (attrs[af->attr]) - putattr(abbrev, af->form, - attrs[af->attr]->cls, - attrs[af->attr]->value, - attrs[af->attr]->data); - else - putattr(abbrev, af->form, 0, 0, nil); + DWAttr *ap; + + for(af = abbrevs[abbrev].attr; af->attr; af++) { + for(ap=attr; ap; ap=ap->link) { + if(ap->atr == af->attr) { + putattr(abbrev, af->form, + ap->cls, + ap->value, + ap->data); + goto done; + } + } + putattr(abbrev, af->form, 0, 0, nil); + done:; + } } static void putdie(DWDie* die); @@ -835,11 +858,8 @@ newmemberoffsetattr(DWDie *die, int32 offs) int i; i = 0; - if (offs != 0) { - block[i++] = DW_OP_consts; - i += sleb128enc(offs, block+i); - block[i++] = DW_OP_plus; - } + block[i++] = DW_OP_plus_uconst; + i += uleb128enc(offs, block+i); newattr(die, DW_AT_data_member_location, DW_CLS_BLOCK, i, mal(i)); memmove(die->attr->data, block, i); } @@ -852,15 +872,6 @@ newabslocexprattr(DWDie *die, vlong addr, LSym *sym) newattr(die, DW_AT_location, DW_CLS_ADDRESS, addr, (char*)sym); } - -// Fake attributes for slices, maps and channel -enum { - DW_AT_internal_elem_type = 250, // channels and slices - DW_AT_internal_key_type = 251, // maps - DW_AT_internal_val_type = 252, // maps - DW_AT_internal_location = 253, // params and locals -}; - static DWDie* defptrto(DWDie *dwtype); // below // Lookup predefined types @@ -981,7 +992,8 @@ defgotype(LSym *gotype) s = decodetype_arrayelem(gotype); newrefattr(die, DW_AT_type, defgotype(s)); fld = newdie(die, DW_ABRV_ARRAYRANGE, "range"); - newattr(fld, DW_AT_upper_bound, DW_CLS_CONSTANT, decodetype_arraylen(gotype), 0); + // use actual length not upper bound; correct for 0-length arrays. + newattr(fld, DW_AT_count, DW_CLS_CONSTANT, decodetype_arraylen(gotype), 0); newrefattr(fld, DW_AT_type, find_or_diag(&dwtypes, "uintptr")); break; @@ -989,7 +1001,7 @@ defgotype(LSym *gotype) die = newdie(&dwtypes, DW_ABRV_CHANTYPE, name); newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0); s = decodetype_chanelem(gotype); - newrefattr(die, DW_AT_internal_elem_type, defgotype(s)); + newrefattr(die, DW_AT_go_elem, defgotype(s)); break; case KindFunc: @@ -1027,9 +1039,9 @@ defgotype(LSym *gotype) case KindMap: die = newdie(&dwtypes, DW_ABRV_MAPTYPE, name); s = decodetype_mapkey(gotype); - newrefattr(die, DW_AT_internal_key_type, defgotype(s)); + newrefattr(die, DW_AT_go_key, defgotype(s)); s = decodetype_mapvalue(gotype); - newrefattr(die, DW_AT_internal_val_type, defgotype(s)); + newrefattr(die, DW_AT_go_elem, defgotype(s)); break; case KindPtr: @@ -1044,7 +1056,7 @@ defgotype(LSym *gotype) dotypedef(&dwtypes, name, die); newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0); s = decodetype_arrayelem(gotype); - newrefattr(die, DW_AT_internal_elem_type, defgotype(s)); + newrefattr(die, DW_AT_go_elem, defgotype(s)); break; case KindString: @@ -1076,7 +1088,9 @@ defgotype(LSym *gotype) 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>")); - } + } + + newattr(die, DW_AT_go_kind, DW_CLS_CONSTANT, kind, 0); return die; } @@ -1171,7 +1185,7 @@ synthesizeslicetypes(DWDie *die) if (die->abbrev != DW_ABRV_SLICETYPE) continue; copychildren(die, prototype); - elem = (DWDie*) getattr(die, DW_AT_internal_elem_type)->data; + elem = (DWDie*) getattr(die, DW_AT_go_elem)->data; substitutetype(die, "array", defptrto(elem)); } } @@ -1208,7 +1222,7 @@ synthesizemaptypes(DWDie *die) DWAttr *a; hash = walktypedef(defgotype(lookup_or_diag("type.runtime.hmap"))); - bucket = walktypedef(defgotype(lookup_or_diag("type.runtime.bucket"))); + bucket = walktypedef(defgotype(lookup_or_diag("type.runtime.bmap"))); if (hash == nil) return; @@ -1217,8 +1231,8 @@ synthesizemaptypes(DWDie *die) if (die->abbrev != DW_ABRV_MAPTYPE) continue; - keytype = walktypedef((DWDie*) getattr(die, DW_AT_internal_key_type)->data); - valtype = walktypedef((DWDie*) getattr(die, DW_AT_internal_val_type)->data); + keytype = walktypedef((DWDie*) getattr(die, DW_AT_go_key)->data); + valtype = walktypedef((DWDie*) getattr(die, DW_AT_go_elem)->data); // compute size info like hashmap.c does. a = getattr(keytype, DW_AT_byte_size); @@ -1243,7 +1257,7 @@ synthesizemaptypes(DWDie *die) newattr(dwhk, DW_AT_byte_size, DW_CLS_CONSTANT, BucketSize * keysize, 0); newrefattr(dwhk, DW_AT_type, indirect_key ? defptrto(keytype) : keytype); fld = newdie(dwhk, DW_ABRV_ARRAYRANGE, "size"); - newattr(fld, DW_AT_upper_bound, DW_CLS_CONSTANT, BucketSize, 0); + newattr(fld, DW_AT_count, DW_CLS_CONSTANT, BucketSize, 0); newrefattr(fld, DW_AT_type, find_or_diag(&dwtypes, "uintptr")); // Construct type to represent an array of BucketSize values @@ -1253,7 +1267,7 @@ synthesizemaptypes(DWDie *die) newattr(dwhv, DW_AT_byte_size, DW_CLS_CONSTANT, BucketSize * valsize, 0); newrefattr(dwhv, DW_AT_type, indirect_val ? defptrto(valtype) : valtype); fld = newdie(dwhv, DW_ABRV_ARRAYRANGE, "size"); - newattr(fld, DW_AT_upper_bound, DW_CLS_CONSTANT, BucketSize, 0); + newattr(fld, DW_AT_count, DW_CLS_CONSTANT, BucketSize, 0); newrefattr(fld, DW_AT_type, find_or_diag(&dwtypes, "uintptr")); // Construct bucket<K,V> @@ -1309,7 +1323,7 @@ synthesizechantypes(DWDie *die) for (; die != nil; die = die->link) { if (die->abbrev != DW_ABRV_CHANTYPE) continue; - elemtype = (DWDie*) getattr(die, DW_AT_internal_elem_type)->data; + elemtype = (DWDie*) getattr(die, DW_AT_go_elem)->data; a = getattr(elemtype, DW_AT_byte_size); elemsize = a ? a->value : PtrSize; @@ -1696,6 +1710,9 @@ enum static void putpccfadelta(vlong deltapc, vlong cfa) { + cput(DW_CFA_def_cfa_offset_sf); + sleb128put(cfa / DATAALIGNMENTFACTOR); + if (deltapc < 0x40) { cput(DW_CFA_advance_loc + deltapc); } else if (deltapc < 0x100) { @@ -1708,9 +1725,6 @@ putpccfadelta(vlong deltapc, vlong cfa) cput(DW_CFA_advance_loc4); LPUT(deltapc); } - - cput(DW_CFA_def_cfa_offset_sf); - sleb128put(cfa / DATAALIGNMENTFACTOR); } static void @@ -1719,6 +1733,7 @@ writeframes(void) LSym *s; vlong fdeo, fdesize, pad; Pciter pcsp; + uint32 nextpc; if(framesec == S) framesec = linklookup(ctxt, ".dwarfframe", 0); @@ -1761,8 +1776,17 @@ writeframes(void) addrput(0); // initial location addrput(0); // address range - for(pciterinit(ctxt, &pcsp, &s->pcln->pcsp); !pcsp.done; pciternext(&pcsp)) - putpccfadelta(pcsp.nextpc - pcsp.pc, PtrSize + pcsp.value); + for(pciterinit(ctxt, &pcsp, &s->pcln->pcsp); !pcsp.done; pciternext(&pcsp)) { + nextpc = pcsp.nextpc; + // pciterinit goes up to the end of the function, + // but DWARF expects us to stop just before the end. + if(nextpc == s->size) { + nextpc--; + if(nextpc < pcsp.pc) + continue; + } + putpccfadelta(nextpc - pcsp.pc, PtrSize + pcsp.value); + } fdesize = cpos() - fdeo - 4; // exclude the length field. pad = rnd(fdesize, PtrSize) - fdesize; @@ -2028,13 +2052,15 @@ dwarfemitdebugsections(void) newdie(&dwtypes, DW_ABRV_NULLTYPE, "<unspecified>"); newdie(&dwtypes, DW_ABRV_NULLTYPE, "void"); newdie(&dwtypes, DW_ABRV_BARE_PTRTYPE, "unsafe.Pointer"); + die = newdie(&dwtypes, DW_ABRV_BASETYPE, "uintptr"); // needed for array size newattr(die, DW_AT_encoding, DW_CLS_CONSTANT, DW_ATE_unsigned, 0); newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, PtrSize, 0); + newattr(die, DW_AT_go_kind, DW_CLS_CONSTANT, KindUintptr, 0); // Needed by the prettyprinter code for interface inspection. - defgotype(lookup_or_diag("type.runtime.rtype")); - defgotype(lookup_or_diag("type.runtime.interfaceType")); + defgotype(lookup_or_diag("type.runtime._type")); + defgotype(lookup_or_diag("type.runtime.interfacetype")); defgotype(lookup_or_diag("type.runtime.itab")); genasmsym(defdwsymb); diff --git a/src/cmd/ld/elf.c b/src/cmd/ld/elf.c index 0555cf46a..3196961f3 100644 --- a/src/cmd/ld/elf.c +++ b/src/cmd/ld/elf.c @@ -776,7 +776,8 @@ elfshbits(Section *sect) if(sect->rwx & 2) sh->flags |= SHF_WRITE; if(strcmp(sect->name, ".tbss") == 0) { - sh->flags |= SHF_TLS; + if(strcmp(goos, "android") != 0) + sh->flags |= SHF_TLS; // no TLS on android sh->type = SHT_NOBITS; } if(linkmode != LinkExternal) diff --git a/src/cmd/ld/ldelf.c b/src/cmd/ld/ldelf.c index 1d7c4c13e..b5d081949 100644 --- a/src/cmd/ld/ldelf.c +++ b/src/cmd/ld/ldelf.c @@ -539,7 +539,7 @@ ldelf(Biobuf *f, char *pkg, int64 len, char *pn) s->type = SRODATA; break; case ElfSectFlagAlloc + ElfSectFlagWrite: - s->type = SDATA; + s->type = SNOPTRDATA; break; case ElfSectFlagAlloc + ElfSectFlagExec: s->type = STEXT; @@ -572,7 +572,7 @@ ldelf(Biobuf *f, char *pkg, int64 len, char *pn) if(s->size < sym.size) s->size = sym.size; if(s->type == 0 || s->type == SXREF) - s->type = SBSS; + s->type = SNOPTRBSS; continue; } if(sym.shndx >= obj->nsect || sym.shndx == 0) @@ -582,6 +582,8 @@ ldelf(Biobuf *f, char *pkg, int64 len, char *pn) continue; sect = obj->sect+sym.shndx; if(sect->sym == nil) { + if(strncmp(sym.name, ".Linfo_string", 13) == 0) // clang does this + continue; diag("%s: sym#%d: ignoring %s in section %d (type %d)", pn, i, sym.name, sym.shndx, sym.type); continue; } @@ -817,7 +819,7 @@ readsym(ElfObj *obj, int i, ElfSym *sym, int needSym) } break; case ElfSymBindLocal: - if(!(thechar == '5' && (strcmp(sym->name, "$a") == 0 || strcmp(sym->name, "$d") == 0))) // binutils for arm generate these mapping symbols, ignore these + if(!(thechar == '5' && (strncmp(sym->name, "$a", 2) == 0 || strncmp(sym->name, "$d", 2) == 0))) // binutils for arm generate these mapping symbols, ignore these if(needSym) { // local names and hidden visiblity global names are unique // and should only reference by its index, not name, so we diff --git a/src/cmd/ld/ldmacho.c b/src/cmd/ld/ldmacho.c index 413dedabd..71cfa63de 100644 --- a/src/cmd/ld/ldmacho.c +++ b/src/cmd/ld/ldmacho.c @@ -589,10 +589,10 @@ ldmacho(Biobuf *f, char *pkg, int64 len, char *pn) s->type = SRODATA; } else { if (strcmp(sect->name, "__bss") == 0) { - s->type = SBSS; + s->type = SNOPTRBSS; s->np = 0; } else - s->type = SDATA; + s->type = SNOPTRDATA; } sect->sym = s; } diff --git a/src/cmd/ld/ldpe.c b/src/cmd/ld/ldpe.c index f6eda900d..4f5e51f2f 100644 --- a/src/cmd/ld/ldpe.c +++ b/src/cmd/ld/ldpe.c @@ -128,6 +128,7 @@ struct PeObj { }; static int map(PeObj *obj, PeSect *sect); +static int issect(PeSym *s); static int readsym(PeObj *obj, int i, PeSym **sym); void @@ -179,6 +180,15 @@ ldpe(Biobuf *f, char *pkg, int64 len, char *pn) Bseek(f, base+obj->fh.PointerToSymbolTable+sizeof(symbuf)*obj->fh.NumberOfSymbols, 0); if(Bread(f, obj->snames, l) != l) goto bad; + // rewrite section names if they start with / + for(i=0; i < obj->fh.NumberOfSections; i++) { + if(obj->sect[i].name == nil) + continue; + if(obj->sect[i].name[0] != '/') + continue; + l = atoi(obj->sect[i].name + 1); + obj->sect[i].name = (char*)&obj->snames[l]; + } // read symbols obj->pesym = mal(obj->fh.NumberOfSymbols*sizeof obj->pesym[0]); obj->npesym = obj->fh.NumberOfSymbols; @@ -230,10 +240,10 @@ ldpe(Biobuf *f, char *pkg, int64 len, char *pn) s->type = SRODATA; break; case IMAGE_SCN_CNT_UNINITIALIZED_DATA|IMAGE_SCN_MEM_READ|IMAGE_SCN_MEM_WRITE: //.bss - s->type = SBSS; + s->type = SNOPTRBSS; break; case IMAGE_SCN_CNT_INITIALIZED_DATA|IMAGE_SCN_MEM_READ|IMAGE_SCN_MEM_WRITE: //.data - s->type = SDATA; + s->type = SNOPTRDATA; break; case IMAGE_SCN_CNT_CODE|IMAGE_SCN_MEM_EXECUTE|IMAGE_SCN_MEM_READ: //.text s->type = STEXT; @@ -309,8 +319,8 @@ ldpe(Biobuf *f, char *pkg, int64 len, char *pn) // ld -r could generate multiple section symbols for the // same section but with different values, we have to take // that into account - if (obj->pesym[symindex].name[0] == '.') - rp->add += obj->pesym[symindex].value; + if(issect(&obj->pesym[symindex])) + rp->add += obj->pesym[symindex].value; } qsort(r, rsect->sh.NumberOfRelocations, sizeof r[0], rbyoff); @@ -318,12 +328,12 @@ ldpe(Biobuf *f, char *pkg, int64 len, char *pn) s->r = r; s->nr = rsect->sh.NumberOfRelocations; } - + // enter sub-symbols into symbol table. for(i=0; i<obj->npesym; i++) { if(obj->pesym[i].name == 0) continue; - if(obj->pesym[i].name[0] == '.') //skip section + if(issect(&obj->pesym[i])) continue; if(obj->pesym[i].sectnum > 0) { sect = &obj->sect[obj->pesym[i].sectnum-1]; @@ -338,7 +348,7 @@ ldpe(Biobuf *f, char *pkg, int64 len, char *pn) if(s->type == SDYNIMPORT) s->plt = -2; // flag for dynimport in PE object files. if (s->type == SXREF && sym->value > 0) {// global data - s->type = SDATA; + s->type = SNOPTRDATA; s->size = sym->value; } continue; @@ -422,6 +432,12 @@ map(PeObj *obj, PeSect *sect) } static int +issect(PeSym *s) +{ + return s->sclass == IMAGE_SYM_CLASS_STATIC && s->type == 0 && s->name[0] == '.'; +} + +static int readsym(PeObj *obj, int i, PeSym **y) { LSym *s; @@ -436,7 +452,7 @@ readsym(PeObj *obj, int i, PeSym **y) sym = &obj->pesym[i]; *y = sym; - if(sym->name[0] == '.') // .section + if(issect(sym)) name = obj->sect[sym->sectnum-1].sym->name; else { name = sym->name; diff --git a/src/cmd/ld/lib.c b/src/cmd/ld/lib.c index da6194e4f..f889aba8a 100644 --- a/src/cmd/ld/lib.c +++ b/src/cmd/ld/lib.c @@ -33,8 +33,8 @@ #include "lib.h" #include "../ld/elf.h" #include "../ld/dwarf.h" -#include "../../pkg/runtime/stack.h" -#include "../../pkg/runtime/funcdata.h" +#include "../../runtime/stack.h" +#include "../../runtime/funcdata.h" #include <ar.h> #if !(defined(_WIN32) || defined(PLAN9)) @@ -144,6 +144,10 @@ libinit(void) void errorexit(void) { + if(cout >= 0) { + // For rmtemp run at atexit time on Windows. + close(cout); + } if(nerrors) { if(cout >= 0) mayberemoveoutfile(); @@ -177,7 +181,7 @@ void loadlib(void) { int i, w, x; - LSym *s, *gmsym; + LSym *s, *tlsg; char* cgostrsym; if(flag_shared) { @@ -217,8 +221,12 @@ loadlib(void) // Provided by the code that imports the package. // Since we are simulating the import, we have to provide this string. cgostrsym = "go.string.\"runtime/cgo\""; - if(linkrlookup(ctxt, cgostrsym, 0) == nil) + if(linkrlookup(ctxt, cgostrsym, 0) == nil) { + s = linklookup(ctxt, cgostrsym, 0); + s->type = SRODATA; + s->reachable = 1; addstrdata(cgostrsym, "runtime/cgo"); + } } if(linkmode == LinkAuto) { @@ -226,6 +234,10 @@ loadlib(void) linkmode = LinkExternal; else linkmode = LinkInternal; + + // Force external linking for android. + if(strcmp(goos, "android") == 0) + linkmode = LinkExternal; } if(linkmode == LinkInternal) { @@ -244,12 +256,12 @@ loadlib(void) } } - gmsym = linklookup(ctxt, "runtime.tlsgm", 0); - gmsym->type = STLSBSS; - gmsym->size = 2*PtrSize; - gmsym->hide = 1; - gmsym->reachable = 1; - ctxt->gmsym = gmsym; + tlsg = linklookup(ctxt, "runtime.tlsg", 0); + tlsg->type = STLSBSS; + tlsg->size = PtrSize; + tlsg->hide = 1; + tlsg->reachable = 1; + ctxt->tlsg = tlsg; // Now that we know the link mode, trim the dynexp list. x = CgoExportDynamic; @@ -895,7 +907,7 @@ unmal(void *v, uint32 n) * escaping are %, ., and ", but we escape all control characters too. * * If you edit this, edit ../gc/subr.c:/^pathtoprefix too. - * If you edit this, edit ../../pkg/debug/goobj/read.go:/importPathToPrefix too. + * If you edit this, edit ../../debug/goobj/read.go:/importPathToPrefix too. */ static char* pathtoprefix(char *s) @@ -1345,10 +1357,10 @@ genasmsym(void (*put)(LSym*, char*, int, vlong, vlong, int, LSym*)) // These symbols won't show up in the first loop below because we // skip STEXT symbols. Normal STEXT symbols are emitted by walking textp. - s = linklookup(ctxt, "text", 0); + s = linklookup(ctxt, "runtime.text", 0); if(s->type == STEXT) put(s, s->name, 'T', s->value, s->size, s->version, 0); - s = linklookup(ctxt, "etext", 0); + s = linklookup(ctxt, "runtime.etext", 0); if(s->type == STEXT) put(s, s->name, 'T', s->value, s->size, s->version, 0); @@ -1550,3 +1562,56 @@ diag(char *fmt, ...) errorexit(); } } + +void +checkgo(void) +{ + LSym *s; + Reloc *r; + int i; + int changed; + + if(!debug['C']) + return; + + // TODO(rsc,khr): Eventually we want to get to no Go-called C functions at all, + // which would simplify this logic quite a bit. + + // Mark every Go-called C function with cfunc=2, recursively. + do { + changed = 0; + for(s = ctxt->textp; s != nil; s = s->next) { + if(s->cfunc == 0 || (s->cfunc == 2 && s->nosplit)) { + for(i=0; i<s->nr; i++) { + r = &s->r[i]; + if(r->sym == nil) + continue; + if((r->type == R_CALL || r->type == R_CALLARM) && r->sym->type == STEXT) { + if(r->sym->cfunc == 1) { + changed = 1; + r->sym->cfunc = 2; + } + } + } + } + } + }while(changed); + + // Complain about Go-called C functions that can split the stack + // (that can be preempted for garbage collection or trigger a stack copy). + for(s = ctxt->textp; s != nil; s = s->next) { + if(s->cfunc == 0 || (s->cfunc == 2 && s->nosplit)) { + for(i=0; i<s->nr; i++) { + r = &s->r[i]; + if(r->sym == nil) + continue; + if((r->type == R_CALL || r->type == R_CALLARM) && r->sym->type == STEXT) { + if(s->cfunc == 0 && r->sym->cfunc == 2 && !r->sym->nosplit) + print("Go %s calls C %s\n", s->name, r->sym->name); + else if(s->cfunc == 2 && s->nosplit && !r->sym->nosplit) + print("Go calls C %s calls %s\n", s->name, r->sym->name); + } + } + } + } +} diff --git a/src/cmd/ld/lib.h b/src/cmd/ld/lib.h index 7267c6371..067ffa0bc 100644 --- a/src/cmd/ld/lib.h +++ b/src/cmd/ld/lib.h @@ -33,6 +33,10 @@ // A section further describes the pieces of that block for // use in debuggers and such. +enum { + MAXIO = 8192, +}; + typedef struct Segment Segment; typedef struct Section Section; @@ -179,12 +183,13 @@ uint16 be16(uchar *b); uint32 be32(uchar *b); uint64 be64(uchar *b); void callgraph(void); +void checkgo(void); void cflush(void); -void codeblk(int32 addr, int32 size); +void codeblk(int64 addr, int64 size); vlong cpos(void); void cseek(vlong p); void cwrite(void *buf, int n); -void datblk(int32 addr, int32 size); +void datblk(int64 addr, int64 size); int datcmp(LSym *s1, LSym *s2); vlong datoff(vlong addr); void deadcode(void); @@ -196,9 +201,12 @@ int decodetype_funcincount(LSym *s); LSym* decodetype_funcintype(LSym *s, int i); int decodetype_funcoutcount(LSym *s); LSym* decodetype_funcouttype(LSym *s, int i); -LSym* decodetype_gc(LSym *s); +LSym* decodetype_gcprog(LSym *s); +uint8* decodetype_gcmask(LSym *s); vlong decodetype_ifacemethodcount(LSym *s); uint8 decodetype_kind(LSym *s); +uint8 decodetype_noptr(LSym *s); +uint8 decodetype_usegcprog(LSym *s); LSym* decodetype_mapkey(LSym *s); LSym* decodetype_mapvalue(LSym *s); LSym* decodetype_ptrelem(LSym *s); diff --git a/src/cmd/ld/macho.c b/src/cmd/ld/macho.c index 61306bb7c..fe7e10e46 100644 --- a/src/cmd/ld/macho.c +++ b/src/cmd/ld/macho.c @@ -590,8 +590,7 @@ machosymtab(void) if(strstr(s->extname, "·") == nil) { addstring(symstr, s->extname); } else { - p = s->extname; - while (*p++ != '\0') { + for(p = s->extname; *p; p++) { if((uchar)*p == 0xc2 && (uchar)*(p+1) == 0xb7) { adduint8(ctxt, symstr, '.'); p++; diff --git a/src/cmd/ld/pass.c b/src/cmd/ld/pass.c deleted file mode 100644 index 788b7c75a..000000000 --- a/src/cmd/ld/pass.c +++ /dev/null @@ -1,104 +0,0 @@ -// Inferno utils/6l/pass.c -// http://code.google.com/p/inferno-os/source/browse/utils/6l/pass.c -// -// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. -// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) -// Portions Copyright © 1997-1999 Vita Nuova Limited -// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) -// Portions Copyright © 2004,2006 Bruce Ellis -// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) -// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others -// Portions Copyright © 2009 The Go Authors. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -// Code and data passes. - -#include "l.h" -#include "../ld/lib.h" -#include "../../pkg/runtime/stack.h" - -void -follow(void) -{ - LSym *s; - - if(debug['v']) - Bprint(&bso, "%5.2f follow\n", cputime()); - Bflush(&bso); - - for(s = ctxt->textp; s != nil; s = s->next) - ctxt->arch->follow(ctxt, s); -} - -void -patch(void) -{ - LSym *s; - - if(debug['v']) - Bprint(&bso, "%5.2f mkfwd\n", cputime()); - Bflush(&bso); - for(s = ctxt->textp; s != nil; s = s->next) - mkfwd(s); - if(debug['v']) - Bprint(&bso, "%5.2f patch\n", cputime()); - Bflush(&bso); - - if(flag_shared) { - s = linklookup(ctxt, "init_array", 0); - s->type = SINITARR; - s->reachable = 1; - s->hide = 1; - addaddr(ctxt, s, linklookup(ctxt, INITENTRY, 0)); - } - - for(s = ctxt->textp; s != nil; s = s->next) - linkpatch(ctxt, s); -} - -void -dostkoff(void) -{ - LSym *s; - - for(s = ctxt->textp; s != nil; s = s->next) - ctxt->arch->addstacksplit(ctxt, s); -} - -void -span(void) -{ - LSym *s; - - if(debug['v']) - Bprint(&bso, "%5.2f span\n", cputime()); - - for(s = ctxt->textp; s != nil; s = s->next) - ctxt->arch->assemble(ctxt, s); -} - -void -pcln(void) -{ - LSym *s; - - for(s = ctxt->textp; s != nil; s = s->next) - linkpcln(ctxt, s); -} diff --git a/src/cmd/ld/pcln.c b/src/cmd/ld/pcln.c index 4c2ffa78e..69671c0fc 100644 --- a/src/cmd/ld/pcln.c +++ b/src/cmd/ld/pcln.c @@ -4,7 +4,7 @@ #include "l.h" #include "lib.h" -#include "../../pkg/runtime/funcdata.h" +#include "../../runtime/funcdata.h" static void addvarint(Pcdata *d, uint32 val) @@ -90,7 +90,7 @@ renumberfiles(Link *ctxt, LSym **files, int nfiles, Pcdata *d) } dv = val - newval; newval = val; - v = (uint32)(dv<<1) ^ (uint32)(int32)(dv>>31); + v = ((uint32)dv<<1) ^ (uint32)(int32)(dv>>31); addvarint(&out, v); // pc delta @@ -119,7 +119,7 @@ pclntab(void) static Pcln zpcln; funcdata_bytes = 0; - ftab = linklookup(ctxt, "pclntab", 0); + ftab = linklookup(ctxt, "runtime.pclntab", 0); ftab->type = SPCLNTAB; ftab->reachable = 1; diff --git a/src/cmd/ld/pobj.c b/src/cmd/ld/pobj.c index 819c37954..63460df30 100644 --- a/src/cmd/ld/pobj.c +++ b/src/cmd/ld/pobj.c @@ -45,6 +45,8 @@ char* paramspace = "FP"; void main(int argc, char *argv[]) { + int i; + linkarchinit(); ctxt = linknew(thelinkarch); ctxt->thechar = thechar; @@ -63,7 +65,13 @@ main(int argc, char *argv[]) INITRND = -1; INITENTRY = 0; linkmode = LinkAuto; - nuxiinit(); + + // For testing behavior of go command when tools crash. + // Undocumented, not in standard flag parser to avoid + // exposing in usage message. + for(i=1; i<argc; i++) + if(strcmp(argv[i], "-crash_for_testing") == 0) + *(volatile int*)0 = 0; if(thechar == '5' && ctxt->goarm == 5) debug['F'] = 1; @@ -72,6 +80,7 @@ main(int argc, char *argv[]) if(thechar == '6') flagcount("8", "assume 64-bit addresses", &debug['8']); flagfn1("B", "info: define ELF NT_GNU_BUILD_ID note", addbuildinfo); + flagcount("C", "check Go calls to C code", &debug['C']); flagint64("D", "addr: data address", &INITDAT); flagstr("E", "sym: entry symbol", &INITENTRY); if(thechar == '5') @@ -96,11 +105,11 @@ main(int argc, char *argv[]) flagcount("a", "disassemble output", &debug['a']); flagcount("c", "dump call graph", &debug['c']); flagcount("d", "disable dynamic executable", &debug['d']); - flagstr("extld", "linker to run in external mode", &extld); - flagstr("extldflags", "flags for external linker", &extldflags); + flagstr("extld", "ld: linker to run in external mode", &extld); + flagstr("extldflags", "ldflags: flags for external linker", &extldflags); flagcount("f", "ignore version mismatch", &debug['f']); flagcount("g", "disable go package data checks", &debug['g']); - flagstr("installsuffix", "pkg directory suffix", &flag_installsuffix); + flagstr("installsuffix", "suffix: pkg directory suffix", &flag_installsuffix); flagstr("k", "sym: set field tracking symbol", &tracksym); flagfn1("linkmode", "mode: set link mode (internal, external, auto)", setlinkmode); flagcount("n", "dump symbol table", &debug['n']); @@ -110,7 +119,7 @@ main(int argc, char *argv[]) flagcount("s", "disable symbol table", &debug['s']); if(thechar == '5' || thechar == '6') flagcount("shared", "generate shared object (implies -linkmode external)", &flag_shared); - flagstr("tmpdir", "leave temporary files in this directory", &tmpdir); + flagstr("tmpdir", "dir: leave temporary files in this directory", &tmpdir); flagcount("u", "reject unsafe packages", &debug['u']); flagcount("v", "print link trace", &debug['v']); flagcount("w", "disable DWARF generation", &debug['w']); @@ -139,7 +148,7 @@ main(int argc, char *argv[]) if(HEADTYPE == -1) HEADTYPE = headtype(goos); ctxt->headtype = HEADTYPE; - if (headstring == nil) + if(headstring == nil) headstring = headstr(HEADTYPE); archinit(); @@ -163,6 +172,7 @@ main(int argc, char *argv[]) mark(linklookup(ctxt, "runtime.read_tls_fallback", 0)); } + checkgo(); deadcode(); callgraph(); paramspace = "SP"; /* (FP) now (SP) on output */ diff --git a/src/cmd/ld/symtab.c b/src/cmd/ld/symtab.c index 6d321c0bb..156270c8f 100644 --- a/src/cmd/ld/symtab.c +++ b/src/cmd/ld/symtab.c @@ -198,13 +198,18 @@ asmelfsym(void) genasmsym(putelfsym); if(linkmode == LinkExternal && HEADTYPE != Hopenbsd) { - s = linklookup(ctxt, "runtime.tlsgm", 0); + s = linklookup(ctxt, "runtime.tlsg", 0); if(s->sect == nil) { ctxt->cursym = nil; diag("missing section for %s", s->name); errorexit(); } - putelfsyment(putelfstr(s->name), 0, 2*PtrSize, (STB_LOCAL<<4)|STT_TLS, s->sect->elfsect->shnum, 0); + if (strcmp(goos, "android") == 0) { + // Android emulates runtime.tlsg as a regular variable. + putelfsyment(putelfstr(s->name), 0, s->size, (STB_LOCAL<<4)|STT_OBJECT, s->sect->elfsect->shnum, 0); + } else { + putelfsyment(putelfstr(s->name), 0, s->size, (STB_LOCAL<<4)|STT_TLS, s->sect->elfsect->shnum, 0); + } s->elfsym = numelfsym++; } @@ -341,36 +346,36 @@ symtab(void) // Define these so that they'll get put into the symbol table. // data.c:/^address will provide the actual values. - xdefine("text", STEXT, 0); - xdefine("etext", STEXT, 0); - xdefine("typelink", SRODATA, 0); - xdefine("etypelink", SRODATA, 0); - xdefine("rodata", SRODATA, 0); - xdefine("erodata", SRODATA, 0); - xdefine("noptrdata", SNOPTRDATA, 0); - xdefine("enoptrdata", SNOPTRDATA, 0); - xdefine("data", SDATA, 0); - xdefine("edata", SDATA, 0); - xdefine("bss", SBSS, 0); - xdefine("ebss", SBSS, 0); - xdefine("noptrbss", SNOPTRBSS, 0); - xdefine("enoptrbss", SNOPTRBSS, 0); - xdefine("end", SBSS, 0); - xdefine("epclntab", SRODATA, 0); - xdefine("esymtab", SRODATA, 0); + xdefine("runtime.text", STEXT, 0); + xdefine("runtime.etext", STEXT, 0); + xdefine("runtime.typelink", SRODATA, 0); + xdefine("runtime.etypelink", SRODATA, 0); + xdefine("runtime.rodata", SRODATA, 0); + xdefine("runtime.erodata", SRODATA, 0); + xdefine("runtime.noptrdata", SNOPTRDATA, 0); + xdefine("runtime.enoptrdata", SNOPTRDATA, 0); + xdefine("runtime.data", SDATA, 0); + xdefine("runtime.edata", SDATA, 0); + xdefine("runtime.bss", SBSS, 0); + xdefine("runtime.ebss", SBSS, 0); + xdefine("runtime.noptrbss", SNOPTRBSS, 0); + xdefine("runtime.enoptrbss", SNOPTRBSS, 0); + xdefine("runtime.end", SBSS, 0); + xdefine("runtime.epclntab", SRODATA, 0); + xdefine("runtime.esymtab", SRODATA, 0); // garbage collection symbols - s = linklookup(ctxt, "gcdata", 0); + s = linklookup(ctxt, "runtime.gcdata", 0); s->type = SRODATA; s->size = 0; s->reachable = 1; - xdefine("egcdata", SRODATA, 0); + xdefine("runtime.egcdata", SRODATA, 0); - s = linklookup(ctxt, "gcbss", 0); + s = linklookup(ctxt, "runtime.gcbss", 0); s->type = SRODATA; s->size = 0; s->reachable = 1; - xdefine("egcbss", SRODATA, 0); + xdefine("runtime.egcbss", SRODATA, 0); // pseudo-symbols to mark locations of type, string, and go string data. s = linklookup(ctxt, "type.*", 0); @@ -391,9 +396,9 @@ symtab(void) s->reachable = 1; symgofunc = s; - symtypelink = linklookup(ctxt, "typelink", 0); + symtypelink = linklookup(ctxt, "runtime.typelink", 0); - symt = linklookup(ctxt, "symtab", 0); + symt = linklookup(ctxt, "runtime.symtab", 0); symt->type = SSYMTAB; symt->size = 0; symt->reachable = 1; diff --git a/src/cmd/ld/textflag.h b/src/cmd/ld/textflag.h index 2a76e76c2..0ee8b5f1c 100644 --- a/src/cmd/ld/textflag.h +++ b/src/cmd/ld/textflag.h @@ -21,3 +21,16 @@ #define WRAPPER 32 // This function uses its incoming context register. #define NEEDCTXT 64 + +/*c2go +enum +{ + NOPROF = 1, + DUPOK = 2, + NOSPLIT = 4, + RODATA = 8, + NOPTR = 16, + WRAPPER = 32, + NEEDCTXT = 64, +}; +*/ |