summaryrefslogtreecommitdiff
path: root/src/cmd/ld/symtab.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/ld/symtab.c')
-rw-r--r--src/cmd/ld/symtab.c240
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);
}