diff options
-rw-r--r-- | doc/devel/release.html | 8 | ||||
-rw-r--r-- | src/cmd/cgo/gcc.go | 89 | ||||
-rw-r--r-- | src/pkg/debug/dwarf/type.go | 4 | ||||
-rw-r--r-- | src/pkg/debug/elf/file.go | 6 | ||||
-rwxr-xr-x | src/pkg/deps.bash | 10 | ||||
-rw-r--r-- | src/pkg/runtime/cgo/darwin_386.c | 72 | ||||
-rw-r--r-- | src/pkg/runtime/cgo/darwin_amd64.c | 65 | ||||
-rw-r--r-- | src/pkg/runtime/cgo/nacl_386.c | 19 | ||||
-rw-r--r-- | src/pkg/runtime/cgo/util.c | 2 |
9 files changed, 160 insertions, 115 deletions
diff --git a/doc/devel/release.html b/doc/devel/release.html index d632200d3..e1a1cabe5 100644 --- a/doc/devel/release.html +++ b/doc/devel/release.html @@ -86,6 +86,14 @@ the Go tree (and avoid writing Makefiles). </p> +<h3 id="r58.minor">Minor revisions</h3> + +<p>r58.1 adds +<a href="http://code.google.com/p/go/source/detail?r=293c25943586">build</a> and +<a href="http://code.google.com/p/go/source/detail?r=bf17e96b6582">runtime</a> +changes to make Go run on OS X 10.7 Lion. +</p> + <h2 id="r57">r57 (released 2011/05/03)</h2> <p> diff --git a/src/cmd/cgo/gcc.go b/src/cmd/cgo/gcc.go index 10411e94f..e4e56d8dd 100644 --- a/src/cmd/cgo/gcc.go +++ b/src/cmd/cgo/gcc.go @@ -13,6 +13,7 @@ import ( "debug/elf" "debug/macho" "debug/pe" + "encoding/binary" "flag" "fmt" "go/ast" @@ -477,7 +478,27 @@ func (p *Package) loadDWARF(f *File, names []*Name) { fmt.Fprintf(&b, "enum { __cgo_enum__%d = %s };\n", i, n.C) } } - d := p.gccDebug(b.Bytes()) + + // Apple's LLVM-based gcc does not include the enumeration + // names and values in its DWARF debug output. In case we're + // using such a gcc, create a data block initialized with the values. + // We can read them out of the object file. + fmt.Fprintf(&b, "long long __cgodebug_data[] = {\n") + for _, n := range names { + if n.Kind == "const" { + fmt.Fprintf(&b, "\t%s,\n", n.C) + } else { + fmt.Fprintf(&b, "\t0,\n") + } + } + fmt.Fprintf(&b, "\t0\n") + fmt.Fprintf(&b, "};\n") + + d, bo, debugData := p.gccDebug(b.Bytes()) + enumVal := make([]int64, len(debugData)/8) + for i := range enumVal { + enumVal[i] = int64(bo.Uint64(debugData[i*8:])) + } // Scan DWARF info for top-level TagVariable entries with AttrName __cgo__i. types := make([]dwarf.Type, len(names)) @@ -569,9 +590,12 @@ func (p *Package) loadDWARF(f *File, names []*Name) { // Remove injected enum to ensure the value will deep-compare // equally in future loads of the same constant. n.Type.EnumValues[k] = 0, false + } else if n.Kind == "const" && i < len(enumVal) { + n.Const = strconv.Itoa64(enumVal[i]) } } } + } // rewriteRef rewrites all the C.xxx references in f.AST to refer to the @@ -593,6 +617,9 @@ func (p *Package) rewriteRef(f *File) { // are trying to do a ,err call. Also check that // functions are only used in calls. for _, r := range f.Ref { + if r.Name.Kind == "const" && r.Name.Const == "" { + error(r.Pos(), "unable to find value of constant C.%s", r.Name.Go) + } var expr ast.Expr = ast.NewIdent(r.Name.Mangle) // default switch r.Context { case "call", "call2": @@ -692,29 +719,57 @@ func (p *Package) gccCmd() []string { } // gccDebug runs gcc -gdwarf-2 over the C program stdin and -// returns the corresponding DWARF data and any messages -// printed to standard error. -func (p *Package) gccDebug(stdin []byte) *dwarf.Data { +// returns the corresponding DWARF data and, if present, debug data block. +func (p *Package) gccDebug(stdin []byte) (*dwarf.Data, binary.ByteOrder, []byte) { runGcc(stdin, p.gccCmd()) - // Try to parse f as ELF and Mach-O and hope one works. - var f interface { - DWARF() (*dwarf.Data, os.Error) - } - var err os.Error - if f, err = elf.Open(gccTmp); err != nil { - if f, err = macho.Open(gccTmp); err != nil { - if f, err = pe.Open(gccTmp); err != nil { - fatalf("cannot parse gcc output %s as ELF or Mach-O or PE object", gccTmp) + if f, err := macho.Open(gccTmp); err == nil { + d, err := f.DWARF() + if err != nil { + fatalf("cannot load DWARF output from %s: %v", gccTmp, err) + } + var data []byte + if f.Symtab != nil { + for i := range f.Symtab.Syms { + s := &f.Symtab.Syms[i] + // Mach-O still uses a leading _ to denote non-assembly symbols. + if s.Name == "_"+"__cgodebug_data" { + // Found it. Now find data section. + if i := int(s.Sect) - 1; 0 <= i && i < len(f.Sections) { + sect := f.Sections[i] + if sect.Addr <= s.Value && s.Value < sect.Addr+sect.Size { + if sdat, err := sect.Data(); err == nil { + data = sdat[s.Value-sect.Addr:] + } + } + } + } } } + return d, f.ByteOrder, data } - d, err := f.DWARF() - if err != nil { - fatalf("cannot load DWARF debug information from %s: %s", gccTmp, err) + // Can skip debug data block in ELF and PE for now. + // The DWARF information is complete. + + if f, err := elf.Open(gccTmp); err == nil { + d, err := f.DWARF() + if err != nil { + fatalf("cannot load DWARF output from %s: %v", gccTmp, err) + } + return d, f.ByteOrder, nil } - return d + + if f, err := pe.Open(gccTmp); err == nil { + d, err := f.DWARF() + if err != nil { + fatalf("cannot load DWARF output from %s: %v", gccTmp, err) + } + return d, binary.LittleEndian, nil + } + + fatalf("cannot parse gcc output %s as ELF, Mach-O, PE object", gccTmp) + panic("not reached") } // gccDefines runs gcc -E -dM -xc - over the C program stdin diff --git a/src/pkg/debug/dwarf/type.go b/src/pkg/debug/dwarf/type.go index f9acf119f..a33785b04 100644 --- a/src/pkg/debug/dwarf/type.go +++ b/src/pkg/debug/dwarf/type.go @@ -352,8 +352,8 @@ func (d *Data) Type(off Offset) (Type, os.Error) { } } if ndim == 0 { - err = DecodeError{"info", e.Offset, "missing dimension for array"} - goto Error + // LLVM generates this for x[]. + t.Count = -1 } case TagBaseType: diff --git a/src/pkg/debug/elf/file.go b/src/pkg/debug/elf/file.go index 9ae8b413d..220ab9408 100644 --- a/src/pkg/debug/elf/file.go +++ b/src/pkg/debug/elf/file.go @@ -546,6 +546,12 @@ func (f *File) DWARF() (*dwarf.Data, os.Error) { return dwarf.New(abbrev, nil, nil, info, nil, nil, nil, str) } +// Symbols returns the symbol table for f. +func (f *File) Symbols() ([]Symbol, os.Error) { + sym, _, err := f.getSymbols(SHT_SYMTAB) + return sym, err +} + type ImportedSymbol struct { Name string Version string diff --git a/src/pkg/deps.bash b/src/pkg/deps.bash index a8e3dfc3a..2095ec1d8 100755 --- a/src/pkg/deps.bash +++ b/src/pkg/deps.bash @@ -15,7 +15,13 @@ fi # Get list of directories from Makefile dirs=$(gomake --no-print-directory echo-dirs) -dirpat=$(echo $dirs C | sed 's/ /|/g; s/.*/^(&)$/') +dirpat=$(echo $dirs C | awk '{ + for(i=1;i<=NF;i++){ + x=$i + gsub("/", "\\/", x) + printf("/^(%s)$/\n", x) + } +}') for dir in $dirs; do ( cd $dir || exit 1 @@ -30,7 +36,7 @@ for dir in $dirs; do ( deps=$( sed -n '/^import.*"/p; /^import[ \t]*(/,/^)/p' $sources /dev/null | cut -d '"' -f2 | - egrep "$dirpat" | + awk "$dirpat" | grep -v "^$dir\$" | sed 's/$/.install/' | sed 's;^C\.install;runtime/cgo.install;' | diff --git a/src/pkg/runtime/cgo/darwin_386.c b/src/pkg/runtime/cgo/darwin_386.c index 4fc7eb4e0..13184f321 100644 --- a/src/pkg/runtime/cgo/darwin_386.c +++ b/src/pkg/runtime/cgo/darwin_386.c @@ -8,11 +8,13 @@ static void* threadentry(void*); static pthread_key_t k1, k2; +#define magic1 (0x23581321U) + static void inittls(void) { uint32 x, y; - pthread_key_t tofree[16], k; + pthread_key_t tofree[128], k; int i, ntofree; int havek1, havek2; @@ -35,9 +37,8 @@ inittls(void) * 0x48+4*0x108 = 0x468 and 0x48+4*0x109 = 0x46c. * * The linker and runtime hard-code these constant offsets - * from %gs where we expect to find m and g. The code - * below verifies that the constants are correct once it has - * obtained the keys. Known to ../cmd/8l/obj.c:/468 + * from %gs where we expect to find m and g. + * Known to ../cmd/8l/obj.c:/468 * and to ../pkg/runtime/darwin/386/sys.s:/468 * * This is truly disgusting and a bit fragile, but taking care @@ -48,55 +49,54 @@ inittls(void) * require an extra instruction and memory reference in * every stack growth prolog and would also require * rewriting the code that 8c generates for extern registers. + * + * Things get more disgusting on OS X 10.7 Lion. + * The 0x48 base mentioned above is the offset of the tsd + * array within the per-thread structure on Leopard and Snow Leopard. + * On Lion, the base moved a little, so while the math above + * still applies, the base is different. Thus, we cannot + * look for specific key values if we want to build binaries + * that run on both systems. Instead, forget about the + * specific key values and just allocate and initialize per-thread + * storage until we find a key that writes to the memory location + * we want. Then keep that key. */ havek1 = 0; havek2 = 0; ntofree = 0; while(!havek1 || !havek2) { if(pthread_key_create(&k, nil) < 0) { - fprintf(stderr, "libcgo: pthread_key_create failed\n"); + fprintf(stderr, "runtime/cgo: pthread_key_create failed\n"); abort(); } - if(k == 0x108) { + pthread_setspecific(k, (void*)magic1); + asm volatile("movl %%gs:0x468, %0" : "=r"(x)); + asm volatile("movl %%gs:0x46c, %0" : "=r"(y)); + if(x == magic1) { havek1 = 1; k1 = k; - continue; - } - if(k == 0x109) { + } else if(y == magic1) { havek2 = 1; k2 = k; - continue; + } else { + if(ntofree >= nelem(tofree)) { + fprintf(stderr, "runtime/cgo: could not obtain pthread_keys\n"); + fprintf(stderr, "\ttried"); + for(i=0; i<ntofree; i++) + fprintf(stderr, " %#x", (unsigned)tofree[i]); + fprintf(stderr, "\n"); + abort(); + } + tofree[ntofree++] = k; } - if(ntofree >= nelem(tofree)) { - fprintf(stderr, "libcgo: could not obtain pthread_keys\n"); - fprintf(stderr, "\twanted 0x108 and 0x109\n"); - fprintf(stderr, "\tgot"); - for(i=0; i<ntofree; i++) - fprintf(stderr, " %#lx", tofree[i]); - fprintf(stderr, "\n"); - abort(); - } - tofree[ntofree++] = k; + pthread_setspecific(k, 0); } - for(i=0; i<ntofree; i++) - pthread_key_delete(tofree[i]); - /* - * We got the keys we wanted. Make sure that we observe - * updates to k1 at 0x468, to verify that the TLS array - * offset from %gs hasn't changed. + * We got the keys we wanted. Free the others. */ - pthread_setspecific(k1, (void*)0x12345678); - asm volatile("movl %%gs:0x468, %0" : "=r"(x)); - - pthread_setspecific(k1, (void*)0x87654321); - asm volatile("movl %%gs:0x468, %0" : "=r"(y)); - - if(x != 0x12345678 || y != 0x87654321) { - printf("libcgo: thread-local storage %#lx not at %%gs:0x468 - x=%#x y=%#x\n", k1, x, y); - abort(); - } + for(i=0; i<ntofree; i++) + pthread_key_delete(tofree[i]); } static void diff --git a/src/pkg/runtime/cgo/darwin_amd64.c b/src/pkg/runtime/cgo/darwin_amd64.c index 253a1b252..38cd80a6f 100644 --- a/src/pkg/runtime/cgo/darwin_amd64.c +++ b/src/pkg/runtime/cgo/darwin_amd64.c @@ -8,24 +8,25 @@ static void* threadentry(void*); static pthread_key_t k1, k2; +#define magic1 (0x23581321345589ULL) + static void inittls(void) { uint64 x, y; - pthread_key_t tofree[16], k; + pthread_key_t tofree[128], k; int i, ntofree; int havek1, havek2; /* * Same logic, code as darwin_386.c:/inittls, except that words - * are 8 bytes long now, and the thread-local storage starts at 0x60. - * So the offsets are + * are 8 bytes long now, and the thread-local storage starts + * at 0x60 on Leopard / Snow Leopard. So the offsets are * 0x60+8*0x108 = 0x8a0 and 0x60+8*0x109 = 0x8a8. * * The linker and runtime hard-code these constant offsets - * from %gs where we expect to find m and g. The code - * below verifies that the constants are correct once it has - * obtained the keys. Known to ../cmd/6l/obj.c:/8a0 + * from %gs where we expect to find m and g. + * Known to ../cmd/6l/obj.c:/8a0 * and to ../pkg/runtime/darwin/amd64/sys.s:/8a0 * * As disgusting as on the 386; same justification. @@ -35,49 +36,37 @@ inittls(void) ntofree = 0; while(!havek1 || !havek2) { if(pthread_key_create(&k, nil) < 0) { - fprintf(stderr, "libcgo: pthread_key_create failed\n"); + fprintf(stderr, "runtime/cgo: pthread_key_create failed\n"); abort(); } - if(k == 0x108) { + pthread_setspecific(k, (void*)magic1); + asm volatile("movq %%gs:0x8a0, %0" : "=r"(x)); + asm volatile("movq %%gs:0x8a8, %0" : "=r"(y)); + if(x == magic1) { havek1 = 1; k1 = k; - continue; - } - if(k == 0x109) { + } else if(y == magic1) { havek2 = 1; k2 = k; - continue; - } - if(ntofree >= nelem(tofree)) { - fprintf(stderr, "libcgo: could not obtain pthread_keys\n"); - fprintf(stderr, "\twanted 0x108 and 0x109\n"); - fprintf(stderr, "\tgot"); - for(i=0; i<ntofree; i++) - fprintf(stderr, " %#x", (unsigned)tofree[i]); - fprintf(stderr, "\n"); - abort(); + } else { + if(ntofree >= nelem(tofree)) { + fprintf(stderr, "runtime/cgo: could not obtain pthread_keys\n"); + fprintf(stderr, "\ttried"); + for(i=0; i<ntofree; i++) + fprintf(stderr, " %#x", (unsigned)tofree[i]); + fprintf(stderr, "\n"); + abort(); + } + tofree[ntofree++] = k; } - tofree[ntofree++] = k; + pthread_setspecific(k, 0); } - for(i=0; i<ntofree; i++) - pthread_key_delete(tofree[i]); - /* - * We got the keys we wanted. Make sure that we observe - * updates to k1 at 0x8a0, to verify that the TLS array - * offset from %gs hasn't changed. + * We got the keys we wanted. Free the others. */ - pthread_setspecific(k1, (void*)0x123456789abcdef0ULL); - asm volatile("movq %%gs:0x8a0, %0" : "=r"(x)); - - pthread_setspecific(k2, (void*)0x0fedcba987654321); - asm volatile("movq %%gs:0x8a8, %0" : "=r"(y)); - - if(x != 0x123456789abcdef0ULL || y != 0x0fedcba987654321) { - printf("libcgo: thread-local storage %#x not at %%gs:0x8a0 - x=%#llx y=%#llx\n", (unsigned)k1, x, y); - abort(); - } + for(i=0; i<ntofree; i++) + pthread_key_delete(tofree[i]); } void diff --git a/src/pkg/runtime/cgo/nacl_386.c b/src/pkg/runtime/cgo/nacl_386.c deleted file mode 100644 index e556c433c..000000000 --- a/src/pkg/runtime/cgo/nacl_386.c +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright 2010 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -#include "libcgo.h" - -static void -xinitcgo(void) -{ -} - -void (*initcgo)(void) = xinitcgo; - -void -libcgo_sys_thread_start(ThreadStart *ts) -{ - // unimplemented - *(int*)0 = 0; -} diff --git a/src/pkg/runtime/cgo/util.c b/src/pkg/runtime/cgo/util.c index 0eff19aa6..9d96521f5 100644 --- a/src/pkg/runtime/cgo/util.c +++ b/src/pkg/runtime/cgo/util.c @@ -40,7 +40,7 @@ xlibcgo_thread_start(ThreadStart *arg) /* Make our own copy that can persist after we return. */ ts = malloc(sizeof *ts); if(ts == nil) { - fprintf(stderr, "libcgo: out of memory in thread_start\n"); + fprintf(stderr, "runtime/cgo: out of memory in thread_start\n"); abort(); } *ts = *arg; |