diff --git a/doc/go1.1.html b/doc/go1.1.html
index eaaa90c580..55c76562e0 100644
--- a/doc/go1.1.html
+++ b/doc/go1.1.html
@@ -66,6 +66,15 @@ to adjust frame pointer offsets.
The implementation now includes a built-in data race detector.
+Symbol table
+
+
+In the gc toolchain, the symbol table format has been extended to allow
+little-endian encoding of symbol values, and the extension is used in
+binaries generated by the Go 1.1 version of the gc linker.
+To the Go 1.0 toolchain and libraries, these new symbol tables appear empty.
+
+
Changes to the standard library
debug/elf
diff --git a/src/cmd/ld/data.c b/src/cmd/ld/data.c
index 89f73ec99f..88808d75f7 100644
--- a/src/cmd/ld/data.c
+++ b/src/cmd/ld/data.c
@@ -150,14 +150,14 @@ relocsym(Sym *s)
int32 i, off, siz, fl;
vlong o;
uchar *cast;
-
+
cursym = s;
memset(&p, 0, sizeof p);
for(r=s->r; rr+s->nr; r++) {
off = r->off;
siz = r->siz;
- if(off < 0 || off+(siz&~Rbig) > s->np) {
- diag("%s: invalid relocation %d+%d not in [%d,%d)", s->name, off, siz&~Rbig, 0, s->np);
+ if(off < 0 || off+siz > s->np) {
+ 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)) {
@@ -198,20 +198,6 @@ relocsym(Sym *s)
default:
cursym = s;
diag("bad reloc size %#ux for %s", siz, r->sym->name);
- case 4 + Rbig:
- fl = o;
- s->p[off] = fl>>24;
- s->p[off+1] = fl>>16;
- s->p[off+2] = fl>>8;
- s->p[off+3] = fl;
- break;
- case 4 + Rlittle:
- fl = o;
- s->p[off] = fl;
- s->p[off+1] = fl>>8;
- s->p[off+2] = fl>>16;
- s->p[off+3] = fl>>24;
- break;
case 4:
fl = o;
cast = (uchar*)&fl;
@@ -223,7 +209,7 @@ relocsym(Sym *s)
for(i=0; i<8; i++)
s->p[off+i] = cast[inuxi8[i]];
break;
- }
+ }
}
}
@@ -231,7 +217,7 @@ void
reloc(void)
{
Sym *s;
-
+
if(debug['v'])
Bprint(&bso, "%5.2f reloc\n", cputime());
Bflush(&bso);
@@ -246,10 +232,10 @@ void
dynrelocsym(Sym *s)
{
Reloc *r;
-
+
if(HEADTYPE == Hwindows) {
Sym *rel, *targ;
-
+
rel = lookup(".rel", 0);
if(s == rel)
return;
@@ -259,7 +245,7 @@ dynrelocsym(Sym *s)
targ->plt = rel->size;
r->sym = rel;
r->add = targ->plt;
-
+
// jmp *addr
if(thechar == '8') {
adduint8(rel, 0xff);
@@ -291,7 +277,7 @@ void
dynreloc(void)
{
Sym *s;
-
+
// -d supresses dynamic loader format, so we may as well not
// compute these sections or mark their symbols as reachable.
if(debug['d'] && HEADTYPE != Hwindows)
@@ -364,12 +350,12 @@ savedata(Sym *s, Prog *p, char *pn)
break;
}
break;
-
+
case D_SCONST:
for(i=0; ip[off+i] = p->to.scon[i];
break;
-
+
case D_CONST:
if(p->to.sym)
goto Addr;
@@ -450,12 +436,12 @@ blk(Sym *start, int32 addr, int32 size)
errorexit();
}
}
-
+
for(; addr < eaddr; addr++)
cput(0);
cflush();
}
-
+
void
codeblk(int32 addr, int32 size)
{
@@ -498,7 +484,7 @@ codeblk(int32 addr, int32 size)
Bprint(&bso, "%.6llux\t%-20s | foreign text\n", (vlong)addr, sym->name);
n = sym->size;
q = sym->p;
-
+
while(n >= 16) {
Bprint(&bso, "%.6ux\t%-20.16I\n", addr, q);
addr += 16;
@@ -510,7 +496,7 @@ codeblk(int32 addr, int32 size)
addr += n;
continue;
}
-
+
Bprint(&bso, "%.6llux\t%-20s | %P\n", (vlong)sym->value, sym->name, p);
for(p = p->link; p != P; p = p->link) {
if(p->link != P)
@@ -532,7 +518,7 @@ codeblk(int32 addr, int32 size)
}
Bflush(&bso);
}
-
+
void
datblk(int32 addr, int32 size)
{
@@ -595,7 +581,7 @@ addstrdata(char *name, char *value)
{
Sym *s, *sp;
char *p;
-
+
p = smprint("%s.str", name);
sp = lookup(p, 0);
free(p);
@@ -775,7 +761,7 @@ addpcrelplus(Sym *s, Sym *t, int32 add)
{
vlong i;
Reloc *r;
-
+
if(s->type == 0)
s->type = SDATA;
s->reachable = 1;
@@ -972,7 +958,7 @@ dodata(void)
* symbol, which is itself data.
*/
dynreloc();
-
+
/* some symbols may no longer belong in datap (Mach-O) */
for(l=&datap; (s=*l) != nil; ) {
if(s->type <= STEXT || SXREF <= s->type)
@@ -1099,7 +1085,7 @@ dodata(void)
}
sect->len = datsize - sect->vaddr;
datsize = rnd(datsize, PtrSize);
-
+
/* gcdata */
sect = addsection(&segtext, ".gcdata", 04);
sect->vaddr = datsize;
@@ -1169,7 +1155,7 @@ textaddress(void)
addsection(&segtext, ".text", 05);
// Assign PCs in text segment.
- // Could parallelize, by assigning to text
+ // Could parallelize, by assigning to text
// and then letting threads copy down, but probably not worth it.
sect = segtext.sect;
va = INITTEXT;
@@ -1192,7 +1178,7 @@ textaddress(void)
}
va += sym->size;
}
-
+
// Align end of code so that rodata starts aligned.
// 128 bytes is likely overkill but definitely cheap.
va = rnd(va, 128);
@@ -1267,7 +1253,7 @@ address(void)
for(sub = sym->sub; sub != nil; sub = sub->sub)
sub->value += sym->value;
}
-
+
xdefine("text", STEXT, text->vaddr);
xdefine("etext", STEXT, text->vaddr + text->len);
xdefine("rodata", SRODATA, rodata->vaddr);
diff --git a/src/cmd/ld/lib.h b/src/cmd/ld/lib.h
index cf334a4bf7..0a582b9b10 100644
--- a/src/cmd/ld/lib.h
+++ b/src/cmd/ld/lib.h
@@ -31,7 +31,7 @@
enum
{
Sxxx,
-
+
/* order here is order in output file */
STEXT,
SMACHOPLT,
@@ -246,12 +246,6 @@ struct Endian
extern Endian be, le;
-// relocation size bits
-enum {
- Rbig = 128,
- Rlittle = 64,
-};
-
/* set by call to mywhatsys() */
extern char* goroot;
extern char* goarch;
diff --git a/src/cmd/ld/symtab.c b/src/cmd/ld/symtab.c
index a27b181edc..92627f5986 100644
--- a/src/cmd/ld/symtab.c
+++ b/src/cmd/ld/symtab.c
@@ -199,7 +199,7 @@ static void
slputb(int32 v)
{
uchar *p;
-
+
symgrow(symt, symt->size+4);
p = symt->p + symt->size;
*p++ = v>>24;
@@ -209,6 +209,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)
{
@@ -269,15 +285,24 @@ putsymb(Sym *s, char *name, int t, vlong v, vlong size, int ver, Sym *typ)
// l = 8;
if(s != nil) {
rel = addrel(symt);
- rel->siz = l + Rbig;
+ rel->siz = l;
rel->sym = s;
rel->type = D_ADDR;
rel->off = symt->size;
v = 0;
- }
- if(l == 8)
- slputb(v>>32);
- slputb(v);
+ }
+
+ if(l == 8) {
+ if(slput == slputl) {
+ slputl(v);
+ slputl(v>>32);
+ } else {
+ slputb(v>>32);
+ slputb(v);
+ }
+ } else
+ slput(v);
+
if(ver)
t += 'a' - 'A';
scput(t+0x80); /* 0x80 is variable length */
@@ -306,8 +331,8 @@ putsymb(Sym *s, char *name, int t, vlong v, vlong size, int ver, Sym *typ)
rel->off = symt->size;
}
if(l == 8)
- slputb(0);
- slputb(0);
+ slput(0);
+ slput(0);
if(debug['n']) {
if(t == 'z' || t == 'Z') {
@@ -356,7 +381,7 @@ 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;
@@ -372,7 +397,7 @@ symtab(void)
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.
@@ -396,5 +421,25 @@ symtab(void)
if(debug['s'])
return;
+
+ switch(thechar) {
+ default:
+ diag("unknown architecture %c", thechar);
+ errorexit();
+ case '5':
+ case '6':
+ case '8':
+ // magic entry to denote little-endian symbol table
+ slputl(0xfffffffe);
+ scput(0);
+ scput(0);
+ slput = slputl;
+ break;
+ case 'v':
+ // big-endian (in case one comes along)
+ slput = slputb;
+ break;
+ }
+
genasmsym(putsymb);
}
diff --git a/src/libmach/sym.c b/src/libmach/sym.c
index 1512d7a4fe..bb758addb5 100644
--- a/src/libmach/sym.c
+++ b/src/libmach/sym.c
@@ -1,11 +1,11 @@
// Inferno libmach/sym.c
// http://code.google.com/p/inferno-os/source/browse/utils/libmach/sym.c
//
-// Copyright © 1994-1999 Lucent Technologies Inc.
-// Power PC support Copyright © 1995-2004 C H Forsyth (forsyth@terzarima.net).
-// Portions Copyright © 1997-1999 Vita Nuova Limited.
-// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com).
-// Revisions Copyright © 2000-2004 Lucent Technologies Inc. and others.
+// Copyright © 1994-1999 Lucent Technologies Inc.
+// Power PC support Copyright © 1995-2004 C H Forsyth (forsyth@terzarima.net).
+// Portions Copyright © 1997-1999 Vita Nuova Limited.
+// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com).
+// Revisions Copyright © 2000-2004 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
@@ -113,12 +113,18 @@ syminit(int fd, Fhdr *fp)
vlong vl;
Biobuf b;
int svalsz;
+ uvlong (*swav)(uvlong);
+ uint32 (*swal)(uint32);
+ uchar buf[6];
if(fp->symsz == 0)
return 0;
if(fp->type == FNONE)
return 0;
+ swav = beswav;
+ swal = beswal;
+
cleansyms();
textseg(fp->txtaddr, fp);
/* minimum symbol record size = 4+1+2 bytes */
@@ -129,6 +135,15 @@ syminit(int fd, Fhdr *fp)
}
Binit(&b, fd, OREAD);
Bseek(&b, fp->symoff, 0);
+ memset(buf, 0, sizeof buf);
+ Bread(&b, buf, sizeof buf);
+ if(memcmp(buf, "\xfe\xff\xff\xff\x00\x00", 6) == 0) {
+ swav = leswav;
+ swal = leswal;
+ } else {
+ Bseek(&b, fp->symoff, 0);
+ }
+
nsym = 0;
size = 0;
for(p = symbols; size < fp->symsz; p++, nsym++) {
@@ -136,13 +151,13 @@ syminit(int fd, Fhdr *fp)
svalsz = 8;
if(Bread(&b, &vl, 8) != 8)
return symerrmsg(8, "symbol");
- p->value = beswav(vl);
+ p->value = swav(vl);
}
else{
svalsz = 4;
if(Bread(&b, &l, 4) != 4)
return symerrmsg(4, "symbol");
- p->value = (u32int)beswal(l);
+ p->value = (u32int)swal(l);
}
if(Bread(&b, &p->type, sizeof(p->type)) != sizeof(p->type))
return symerrmsg(sizeof(p->value), "symbol");
@@ -155,12 +170,12 @@ syminit(int fd, Fhdr *fp)
if(svalsz == 8){
if(Bread(&b, &vl, 8) != 8)
return symerrmsg(8, "symbol");
- p->gotype = beswav(vl);
+ p->gotype = swav(vl);
}
else{
if(Bread(&b, &l, 4) != 4)
return symerrmsg(4, "symbol");
- p->gotype = (u32int)beswal(l);
+ p->gotype = (u32int)swal(l);
}
size += svalsz;
diff --git a/src/pkg/debug/gosym/pclntab_test.go b/src/pkg/debug/gosym/pclntab_test.go
index ade704335d..5f2242eba0 100644
--- a/src/pkg/debug/gosym/pclntab_test.go
+++ b/src/pkg/debug/gosym/pclntab_test.go
@@ -129,7 +129,7 @@ func TestLineFromAline(t *testing.T) {
if !ok {
t.Errorf("file %s starts on line %d", path, line)
} else if line != ll+1 {
- t.Errorf("expected next line of file %s to be %d, got %d", path, ll+1, line)
+ t.Fatalf("expected next line of file %s to be %d, got %d", path, ll+1, line)
}
lastline[path] = line
}
diff --git a/src/pkg/debug/gosym/symtab.go b/src/pkg/debug/gosym/symtab.go
index 52d7d55a33..cc01e0b9d6 100644
--- a/src/pkg/debug/gosym/symtab.go
+++ b/src/pkg/debug/gosym/symtab.go
@@ -13,6 +13,7 @@ package gosym
// and the Go format is the runtime source, specifically ../../runtime/symtab.c.
import (
+ "bytes"
"encoding/binary"
"fmt"
"strconv"
@@ -104,11 +105,18 @@ type sym struct {
name []byte
}
+var littleEndianSymtab = []byte{0xFE, 0xFF, 0xFF, 0xFF, 0x00, 0x00}
+
func walksymtab(data []byte, fn func(sym) error) error {
+ var order binary.ByteOrder = binary.BigEndian
+ if bytes.HasPrefix(data, littleEndianSymtab) {
+ data = data[6:]
+ order = binary.LittleEndian
+ }
var s sym
p := data
for len(p) >= 6 {
- s.value = binary.BigEndian.Uint32(p[0:4])
+ s.value = order.Uint32(p[0:4])
typ := p[4]
if typ&0x80 == 0 {
return &DecodingError{len(data) - len(p) + 4, "bad symbol type", typ}
@@ -139,7 +147,7 @@ func walksymtab(data []byte, fn func(sym) error) error {
}
s.name = p[0:i]
i += nnul
- s.gotype = binary.BigEndian.Uint32(p[i : i+4])
+ s.gotype = order.Uint32(p[i : i+4])
p = p[i+4:]
fn(s)
}
diff --git a/src/pkg/runtime/symtab.c b/src/pkg/runtime/symtab.c
index 74b0071476..5df9fd2d3d 100644
--- a/src/pkg/runtime/symtab.c
+++ b/src/pkg/runtime/symtab.c
@@ -40,13 +40,26 @@ walksymtab(void (*fn)(Sym*))
{
byte *p, *ep, *q;
Sym s;
+ int32 bigend;
p = symtab;
ep = esymtab;
+
+ // Default is big-endian value encoding.
+ // If table begins fe ff ff ff 00 00, little-endian.
+ bigend = 1;
+ if(symtab[0] == 0xfe && symtab[1] == 0xff && symtab[2] == 0xff && symtab[3] == 0xff && symtab[4] == 0x00 && symtab[5] == 0x00) {
+ p += 6;
+ bigend = 0;
+ }
while(p < ep) {
if(p + 7 > ep)
break;
- s.value = ((uint32)p[0]<<24) | ((uint32)p[1]<<16) | ((uint32)p[2]<<8) | ((uint32)p[3]);
+
+ if(bigend)
+ s.value = ((uint32)p[0]<<24) | ((uint32)p[1]<<16) | ((uint32)p[2]<<8) | ((uint32)p[3]);
+ else
+ s.value = ((uint32)p[3]<<24) | ((uint32)p[2]<<16) | ((uint32)p[1]<<8) | ((uint32)p[0]);
if(!(p[4]&0x80))
break;
@@ -304,7 +317,7 @@ splitpcln(void)
line += *p++;
else
line -= *p++ - 64;
-
+
// pc, line now match.
// Because the state machine begins at pc==entry and line==0,
// it can happen - just at the beginning! - that the update may
@@ -326,7 +339,7 @@ splitpcln(void)
while(f < ef && pc >= (f+1)->entry);
f->pcln.array = p;
// pc0 and ln0 are the starting values for
- // the loop over f->pcln, so pc must be
+ // the loop over f->pcln, so pc must be
// adjusted by the same pcquant update
// that we're going to do as we continue our loop.
f->pc0 = pc + pcquant;
@@ -352,11 +365,11 @@ runtime·funcline(Func *f, uintptr targetpc)
uintptr pc;
int32 line;
int32 pcquant;
-
+
enum {
debug = 0
};
-
+
switch(thechar) {
case '5':
pcquant = 4;
@@ -383,7 +396,7 @@ runtime·funcline(Func *f, uintptr targetpc)
if(debug && !runtime·panicking)
runtime·printf("pc<%p targetpc=%p line=%d\n", pc, targetpc, line);
-
+
// If the pc has advanced too far or we're out of data,
// stop and the last known line number.
if(pc > targetpc || p >= ep)
@@ -519,7 +532,7 @@ static bool
hasprefix(String s, int8 *p)
{
int32 i;
-
+
for(i=0; i 1 || contains(f->name, ".") && !hasprefix(f->name, "runtime.");