diff options
Diffstat (limited to 'src/cmd/ld/symtab.c')
-rw-r--r-- | src/cmd/ld/symtab.c | 240 |
1 files changed, 185 insertions, 55 deletions
diff --git a/src/cmd/ld/symtab.c b/src/cmd/ld/symtab.c index 129b13ea0..89a594872 100644 --- a/src/cmd/ld/symtab.c +++ b/src/cmd/ld/symtab.c @@ -36,7 +36,7 @@ static int maxelfstr; -int +static int putelfstr(char *s) { int off, n; @@ -57,14 +57,14 @@ putelfstr(char *s) return off; } -void -putelfsyment(int off, vlong addr, vlong size, int info, int shndx) +static void +putelfsyment(int off, vlong addr, vlong size, int info, int shndx, int other) { switch(thechar) { case '6': LPUT(off); cput(info); - cput(0); + cput(other); WPUT(shndx); VPUT(addr); VPUT(size); @@ -75,17 +75,21 @@ putelfsyment(int off, vlong addr, vlong size, int info, int shndx) LPUT(addr); LPUT(size); cput(info); - cput(0); + cput(other); WPUT(shndx); symsize += ELF32SYMSIZE; break; } } -void +static int numelfsym = 1; // 0 is reserved +static int elfbind; + +static void putelfsym(Sym *x, char *s, int t, vlong addr, vlong size, int ver, Sym *go) { - int bind, type, shndx, off; + int bind, type, off; + Sym *xo; USED(go); switch(t) { @@ -93,37 +97,68 @@ putelfsym(Sym *x, char *s, int t, vlong addr, vlong size, int ver, Sym *go) return; case 'T': type = STT_FUNC; - shndx = elftextsh + 0; break; case 'D': type = STT_OBJECT; - if((x->type&~SSUB) == SRODATA) - shndx = elftextsh + 1; - else - shndx = elftextsh + 2; break; case 'B': type = STT_OBJECT; - shndx = elftextsh + 3; break; } - bind = ver ? STB_LOCAL : STB_GLOBAL; + xo = x; + while(xo->outer != nil) + xo = xo->outer; + if(xo->sect == nil) { + cursym = x; + diag("missing section in putelfsym"); + return; + } + if(xo->sect->elfsect == nil) { + cursym = x; + diag("missing ELF section in putelfsym"); + return; + } + + // One pass for each binding: STB_LOCAL, STB_GLOBAL, + // maybe one day STB_WEAK. + bind = (ver || (x->type & SHIDDEN)) ? STB_LOCAL : STB_GLOBAL; + if(bind != elfbind) + return; + off = putelfstr(s); - putelfsyment(off, addr, size, (bind<<4)|(type&0xf), shndx); + if(isobj) + addr -= xo->sect->vaddr; + putelfsyment(off, addr, size, (bind<<4)|(type&0xf), xo->sect->elfsect->shnum, (x->type & SHIDDEN) ? 2 : 0); + x->elfsym = numelfsym++; } void asmelfsym(void) { + Sym *s; + // the first symbol entry is reserved - putelfsyment(0, 0, 0, (STB_LOCAL<<4)|STT_NOTYPE, 0); + putelfsyment(0, 0, 0, (STB_LOCAL<<4)|STT_NOTYPE, 0, 0); + + elfbind = STB_LOCAL; genasmsym(putelfsym); + + elfbind = STB_GLOBAL; + elfglobalsymndx = numelfsym; + genasmsym(putelfsym); + + for(s=allsym; s!=S; s=s->allsym) { + if(s->type != SHOSTOBJ) + continue; + putelfsyment(putelfstr(s->name), 0, 0, (STB_GLOBAL<<4)|STT_NOTYPE, 0, 0); + s->elfsym = numelfsym++; + } } -void +static void putplan9sym(Sym *x, char *s, int t, vlong addr, vlong size, int ver, Sym *go) { - int i; + int i, l; USED(go); USED(ver); @@ -142,6 +177,11 @@ putplan9sym(Sym *x, char *s, int t, vlong addr, vlong size, int ver, Sym *go) case 'z': case 'Z': case 'm': + l = 4; + if(HEADTYPE == Hplan9x64 && !debug['8']) { + lputb(addr>>32); + l = 8; + } lputb(addr); cput(t+0x80); /* 0x80 is variable length */ @@ -162,7 +202,7 @@ putplan9sym(Sym *x, char *s, int t, vlong addr, vlong size, int ver, Sym *go) cput(s[i]); cput(0); } - symsize += 4 + 1 + i + 1; + symsize += l + 1 + i + 1; break; default: return; @@ -192,7 +232,7 @@ static void slputb(int32 v) { uchar *p; - + symgrow(symt, symt->size+4); p = symt->p + symt->size; *p++ = v>>24; @@ -202,6 +242,22 @@ slputb(int32 v) symt->size += 4; } +static void +slputl(int32 v) +{ + uchar *p; + + symgrow(symt, symt->size+4); + p = symt->p + symt->size; + *p++ = v; + *p++ = v>>8; + *p++ = v>>16; + *p = v>>24; + symt->size += 4; +} + +static void (*slput)(int32); + void wputl(ushort w) { @@ -248,32 +304,76 @@ vputl(uint64 v) lputl(v >> 32); } +// Emit symbol table entry. +// The table format is described at the top of ../../pkg/runtime/symtab.c. void putsymb(Sym *s, char *name, int t, vlong v, vlong size, int ver, Sym *typ) { - int i, f, l; + int i, f, c; + vlong v1; Reloc *rel; USED(size); - if(t == 'f') - name++; - l = 4; -// if(!debug['8']) -// l = 8; + + // type byte + if('A' <= t && t <= 'Z') + c = t - 'A'; + else if('a' <= t && t <= 'z') + c = t - 'a' + 26; + else { + diag("invalid symbol table type %c", t); + errorexit(); + return; + } + + if(s != nil) + c |= 0x40; // wide value + if(typ != nil) + c |= 0x80; // has go type + scput(c); + + // value if(s != nil) { + // full width rel = addrel(symt); - rel->siz = l + Rbig; + rel->siz = PtrSize; rel->sym = s; rel->type = D_ADDR; rel->off = symt->size; - v = 0; - } - if(l == 8) - slputb(v>>32); - slputb(v); - if(ver) - t += 'a' - 'A'; - scput(t+0x80); /* 0x80 is variable length */ + if(PtrSize == 8) + slput(0); + slput(0); + } else { + // varint + if(v < 0) { + diag("negative value in symbol table: %s %lld", name, v); + errorexit(); + } + v1 = v; + while(v1 >= 0x80) { + scput(v1 | 0x80); + v1 >>= 7; + } + scput(v1); + } + + // go type if present + if(typ != nil) { + if(!typ->reachable) + diag("unreachable type %s", typ->name); + rel = addrel(symt); + rel->siz = PtrSize; + rel->sym = typ; + rel->type = D_ADDR; + rel->off = symt->size; + if(PtrSize == 8) + slput(0); + slput(0); + } + + // name + if(t == 'f') + name++; if(t == 'Z' || t == 'z') { scput(name[0]); @@ -283,24 +383,11 @@ putsymb(Sym *s, char *name, int t, vlong v, vlong size, int ver, Sym *typ) } scput(0); scput(0); - } - else { + } else { for(i=0; name[i]; i++) scput(name[i]); scput(0); } - if(typ) { - if(!typ->reachable) - diag("unreachable type %s", typ->name); - rel = addrel(symt); - rel->siz = l; - rel->sym = typ; - rel->type = D_ADDR; - rel->off = symt->size; - } - if(l == 8) - slputb(0); - slputb(0); if(debug['n']) { if(t == 'z' || t == 'Z') { @@ -313,25 +400,34 @@ putsymb(Sym *s, char *name, int t, vlong v, vlong size, int ver, Sym *typ) return; } if(ver) - Bprint(&bso, "%c %.8llux %s<%d> %s\n", t, v, s->name, ver, typ ? typ->name : ""); + Bprint(&bso, "%c %.8llux %s<%d> %s\n", t, v, name, ver, typ ? typ->name : ""); else - Bprint(&bso, "%c %.8llux %s %s\n", t, v, s->name, typ ? typ->name : ""); + Bprint(&bso, "%c %.8llux %s %s\n", t, v, name, typ ? typ->name : ""); } } void symtab(void) { - Sym *s; - + Sym *s, *symtype, *symtypelink, *symgostring; dosymtype(); // 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); + if(flag_shared) { + xdefine("datarelro", SDATARELRO, 0); + xdefine("edatarelro", SDATARELRO, 0); + } + xdefine("gcdata", SGCDATA, 0); + xdefine("egcdata", SGCDATA, 0); + xdefine("gcbss", SGCBSS, 0); + xdefine("egcbss", SGCBSS, 0); xdefine("noptrdata", SNOPTRDATA, 0); xdefine("enoptrdata", SNOPTRDATA, 0); xdefine("data", SDATA, 0); @@ -343,23 +439,27 @@ 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; + symtype = s; s = lookup("go.string.*", 0); s->type = SGOSTRING; s->size = 0; s->reachable = 1; + symgostring = s; + + symtypelink = lookup("typelink", 0); symt = lookup("symtab", 0); symt->type = SSYMTAB; 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. @@ -370,14 +470,44 @@ symtab(void) if(strncmp(s->name, "type.", 5) == 0) { s->type = STYPE; s->hide = 1; + s->outer = symtype; + } + if(strncmp(s->name, "go.typelink.", 12) == 0) { + s->type = STYPELINK; + s->hide = 1; + s->outer = symtypelink; } if(strncmp(s->name, "go.string.", 10) == 0) { s->type = SGOSTRING; s->hide = 1; + s->outer = symgostring; } } if(debug['s']) return; + + switch(thechar) { + default: + diag("unknown architecture %c", thechar); + errorexit(); + case '5': + case '6': + case '8': + // little-endian symbol table + slput = slputl; + break; + case 'v': + // big-endian symbol table + slput = slputb; + break; + } + // new symbol table header. + slput(0xfffffffd); + scput(0); + scput(0); + scput(0); + scput(PtrSize); + genasmsym(putsymb); } |