diff options
Diffstat (limited to 'src/cmd')
| -rw-r--r-- | src/cmd/ld/data.c | 1 | ||||
| -rw-r--r-- | src/cmd/ld/lib.c | 34 | ||||
| -rw-r--r-- | src/cmd/ld/symtab.c | 108 |
3 files changed, 94 insertions, 49 deletions
diff --git a/src/cmd/ld/data.c b/src/cmd/ld/data.c index 99385fdcc2..e4d16fdc1f 100644 --- a/src/cmd/ld/data.c +++ b/src/cmd/ld/data.c @@ -1163,7 +1163,6 @@ dodata(void) sect->vaddr = 0; lookup("rodata", 0)->sect = sect; lookup("erodata", 0)->sect = sect; - lookup("reloffset", 0)->sect = sect; datsize = 0; s = datap; for(; s != nil && s->type < STYPELINK; s = s->next) { diff --git a/src/cmd/ld/lib.c b/src/cmd/ld/lib.c index 4f0b87466b..26fa4f2ac7 100644 --- a/src/cmd/ld/lib.c +++ b/src/cmd/ld/lib.c @@ -1564,6 +1564,7 @@ genasmsym(void (*put)(Sym*, char*, int, vlong, vlong, int, Sym*)) { Auto *a; Sym *s; + int32 off; // These symbols won't show up in the first loop below because we // skip STEXT symbols. Normal STEXT symbols are emitted by walking textp. @@ -1627,16 +1628,37 @@ genasmsym(void (*put)(Sym*, char*, int, vlong, vlong, int, Sym*)) put(s, s->name, 'T', s->value, s->size, s->version, s->gotype); /* frame, locals, args, auto and param after */ - put(nil, ".frame", 'm', s->text->to.offset+PtrSize, 0, 0, 0); + put(nil, ".frame", 'm', (uint32)s->text->to.offset+PtrSize, 0, 0, 0); put(nil, ".locals", 'm', s->locals, 0, 0, 0); put(nil, ".args", 'm', s->args, 0, 0, 0); - for(a=s->autom; a; a=a->link) - if(a->type == D_AUTO) - put(nil, a->asym->name, 'a', -a->aoffset, 0, 0, a->gotype); - else + for(a=s->autom; a; a=a->link) { + // Emit a or p according to actual offset, even if label is wrong. + // This avoids negative offsets, which cannot be encoded. + if(a->type != D_AUTO && a->type != D_PARAM) + continue; + + // compute offset relative to FP if(a->type == D_PARAM) - put(nil, a->asym->name, 'p', a->aoffset, 0, 0, a->gotype); + off = a->aoffset; + else + off = a->aoffset - PtrSize; + + // FP + if(off >= 0) { + put(nil, a->asym->name, 'p', off, 0, 0, a->gotype); + continue; + } + + // SP + if(off <= -PtrSize) { + put(nil, a->asym->name, 'a', -(off+PtrSize), 0, 0, a->gotype); + continue; + } + + // Otherwise, off is addressing the saved program counter. + // Something underhanded is going on. Say nothing. + } } if(debug['v'] || debug['n']) Bprint(&bso, "symsize = %ud\n", symsize); diff --git a/src/cmd/ld/symtab.c b/src/cmd/ld/symtab.c index 42e367291d..144f82a3ba 100644 --- a/src/cmd/ld/symtab.c +++ b/src/cmd/ld/symtab.c @@ -295,41 +295,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; + rel->siz = PtrSize; rel->sym = s; rel->type = D_ADDR; rel->off = symt->size; - v = 0; - } - - if(l == 8) { - if(slput == slputl) { - slputl(v); - slputl(v>>32); - } else { - slputb(v>>32); - slputb(v); + if(PtrSize == 8) + slput(0); + slput(0); + } else { + // varint + if(v < 0) { + diag("negative value in symbol table: %s %lld", name, v); + errorexit(); } - } else - slput(v); + v1 = v; + while(v1 >= 0x80) { + scput(v1 | 0x80); + v1 >>= 7; + } + scput(v1); + } - if(ver) - t += 'a' - 'A'; - scput(t+0x80); /* 0x80 is variable length */ + // 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]); @@ -339,24 +374,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) - slput(0); - slput(0); if(debug['n']) { if(t == 'z' || t == 'Z') { @@ -389,7 +411,6 @@ symtab(void) xdefine("etypelink", SRODATA, 0); xdefine("rodata", SRODATA, 0); xdefine("erodata", SRODATA, 0); - xdefine("reloffset", SRODATA, 0); if(flag_shared) { xdefine("datarelro", SDATARELRO, 0); xdefine("edatarelro", SDATARELRO, 0); @@ -464,17 +485,20 @@ symtab(void) case '5': case '6': case '8': - // magic entry to denote little-endian symbol table - slputl(0xfffffffe); - scput(0); - scput(0); + // little-endian symbol table slput = slputl; break; case 'v': - // big-endian (in case one comes along) + // big-endian symbol table slput = slputb; break; } + // new symbol table header. + slput(0xfffffffd); + scput(0); + scput(0); + scput(0); + scput(PtrSize); genasmsym(putsymb); } |
