diff options
| author | Russ Cox <rsc@golang.org> | 2013-02-26 22:38:14 -0500 |
|---|---|---|
| committer | Russ Cox <rsc@golang.org> | 2013-02-26 22:38:14 -0500 |
| commit | c8dcaeb25deddac52cfca6ae6882ce94780582d3 (patch) | |
| tree | d12f5b99253e3e8a8f1606afebc8d5908470da88 /src/cmd | |
| parent | 15cce227c78ac2b499e9ad3c49ccb67d2f870169 (diff) | |
| download | go-c8dcaeb25deddac52cfca6ae6882ce94780582d3.tar.xz | |
cmd/ld, runtime: adjust symbol table representation
This CL changes the encoding used for the Go symbol table,
stored in the binary and used at run time. It does not change
any of the semantics or structure: the bits are just packed
a little differently.
The comment at the top of runtime/symtab.c describes the new format.
Compared to the Go 1.0 format, the main changes are:
* Store symbol addresses as full-pointer-sized host-endian values.
(For 6g, this means addresses are 64-bit little-endian.)
* Store other values (frame sizes and so on) varint-encoded.
The second change more than compensates for the first:
for the godoc binary on OS X/amd64, the new symbol table
is 8% smaller than the old symbol table (1,425,668 down from 1,546,276).
This is a required step for allowing the host linker (gcc) to write
the final Go binary, since it will have to fill in the symbol address slots
(so the slots must be host-endian) and on 64-bit systems it may
choose addresses above 4 GB.
R=golang-dev, iant
CC=golang-dev
https://golang.org/cl/7403054
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); } |
