diff options
| author | Russ Cox <rsc@golang.org> | 2013-01-04 17:03:57 -0500 |
|---|---|---|
| committer | Russ Cox <rsc@golang.org> | 2013-01-04 17:03:57 -0500 |
| commit | 4e2aa9bff0eb76f98bb3b238c7f56bea6330f70d (patch) | |
| tree | 41167a6068d324f4cc6df70088d8d4ce9e1c7c7f /src/pkg | |
| parent | f1e4ee3f49fd19d72fa3bbcbce4aab5c2fbef2ed (diff) | |
| download | go-4e2aa9bff0eb76f98bb3b238c7f56bea6330f70d.tar.xz | |
cmd/ld: use native-endian symbol values in symbol table
The Plan 9 symbol table format defines big-endian symbol values
for portability, but we want to be able to generate an ELF object file
and let the host linker link it, as part of the solution to issue 4069.
The symbol table itself, since it is loaded into memory at run time,
must be filled in by the final host linker, using relocation directives
to set the symbol values. On a little-endian machine, the linker will
only fill in little-endian values during relocation, so we are forced
to use little-endian symbol values.
To preserve most of the original portability of the symbol table
format, we make the table itself say whether it uses big- or
little-endian values. If the table begins with the magic sequence
fe ff ff ff 00 00
then the actual table begins after those six bytes and contains
little-endian symbol values. Otherwise, the table is in the original
format and contains big-endian symbol values. The magic sequence
looks like an "end of table" entry (the fifth byte is zero), so legacy
readers will see a little-endian table as an empty table.
All the gc architectures are little-endian today, so the practical
effect of this CL is to make all the generated tables little-endian,
but if a big-endian system comes along, ld will not generate
the magic sequence, and the various readers will fall back to the
original big-endian interpretation.
R=ken2
CC=golang-dev
https://golang.org/cl/7066043
Diffstat (limited to 'src/pkg')
| -rw-r--r-- | src/pkg/debug/gosym/pclntab_test.go | 2 | ||||
| -rw-r--r-- | src/pkg/debug/gosym/symtab.go | 12 | ||||
| -rw-r--r-- | src/pkg/runtime/symtab.c | 31 |
3 files changed, 33 insertions, 12 deletions
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<s.len; i++) { if(p[i] == 0) return 1; @@ -533,7 +546,7 @@ static bool contains(String s, int8 *p) { int32 i; - + if(p[0] == 0) return 1; for(i=0; i<s.len; i++) { @@ -549,7 +562,7 @@ bool runtime·showframe(Func *f) { static int32 traceback = -1; - + if(traceback < 0) traceback = runtime·gotraceback(); return traceback > 1 || contains(f->name, ".") && !hasprefix(f->name, "runtime."); |
