diff --git a/misc/cgo/life/Makefile b/misc/cgo/life/Makefile index b50a5ee7d2..5a10380edb 100644 --- a/misc/cgo/life/Makefile +++ b/misc/cgo/life/Makefile @@ -7,25 +7,15 @@ include ../../../src/Make.inc TARG=life CGOFILES=\ - life.go + life.go\ -LDPATH_freebsd=-Wl,-R,`pwd` -LDPATH_linux=-Wl,-R,`pwd` -LDPATH_darwin= +CGO_OFILES=\ + c-life.o\ -CGO_LDFLAGS=_cgo_export.o c-life.so $(LDPATH_$(GOOS)) -CGO_DEPS=_cgo_export.o c-life.so - -CLEANFILES += life +CLEANFILES+=life include ../../../src/Make.pkg -c-life.o: c-life.c _cgo_export.h - gcc $(_CGO_CFLAGS_$(GOARCH)) -g -c -fPIC $(CFLAGS) c-life.c - -c-life.so: c-life.o - gcc $(_CGO_CFLAGS_$(GOARCH)) -o $@ c-life.o $(_CGO_LDFLAGS_$(GOOS)) - life: install main.go $(GC) main.go $(LD) -o $@ main.$O diff --git a/misc/cgo/life/golden.out b/misc/cgo/life/golden.out new file mode 100644 index 0000000000..539d2106d6 --- /dev/null +++ b/misc/cgo/life/golden.out @@ -0,0 +1,17 @@ +* life + + + XXX XXX + + + + + + + + XXX XXX + + + + + diff --git a/misc/cgo/life/test.bash b/misc/cgo/life/test.bash new file mode 100755 index 0000000000..5c5fba1a97 --- /dev/null +++ b/misc/cgo/life/test.bash @@ -0,0 +1,11 @@ +#!/bin/sh +# 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. + +set -e +gomake life +echo '*' life >run.out +./life >>run.out +diff run.out golden.out +gomake clean diff --git a/src/Make.pkg b/src/Make.pkg index 6aa5e29c0c..420f610030 100644 --- a/src/Make.pkg +++ b/src/Make.pkg @@ -37,8 +37,8 @@ INSTALLFILES+=$(pkgdir)/$(TARG).a # must be done here so they apply to the main rules. ifdef CGOFILES GOFILES+=$(patsubst %.go,%.cgo1.go,$(CGOFILES)) _cgo_gotypes.go -GCC_OFILES=$(patsubst %.go,%.cgo2.o,$(CGOFILES)) -OFILES+=_cgo_defun.$O _cgo_import.$O $(GCC_OFILES) +CGO_OFILES+=$(patsubst %.go,%.cgo2.o,$(CGOFILES)) _cgo_export.o +OFILES+=_cgo_defun.$O _cgo_import.$O $(CGO_OFILES) endif PREREQ+=$(patsubst %,%.make,$(DEPS)) @@ -111,8 +111,10 @@ dir: # x.cgo2.c - C implementations compiled with gcc to create a dynamic library # +ifdef CGOFILES _cgo_defun.c: $(CGOFILES) CGOPKGPATH=$(dir) cgo -- $(CGO_CFLAGS) $(CGOFILES) +endif # Ugly but necessary _cgo_gotypes.go _cgo_export.c _cgo_export.h: _cgo_defun.c @@ -122,24 +124,25 @@ _cgo_gotypes.go _cgo_export.c _cgo_export.h: _cgo_defun.c @true # Compile rules for gcc source files. -%.cgo2.o: %.cgo2.c - $(HOST_CC) $(_CGO_CFLAGS_$(GOARCH)) -g -fPIC -O2 -o $@ -c $(CGO_CFLAGS) $*.cgo2.c - -_cgo_export.o: _cgo_export.c _cgo_export.h - $(HOST_CC) $(_CGO_CFLAGS_$(GOARCH)) -g -fPIC -O2 -o $@ -c $(CGO_CFLAGS) _cgo_export.c +%.o: %.c + $(HOST_CC) $(_CGO_CFLAGS_$(GOARCH)) -g -fPIC -O2 -o $@ -c $(CGO_CFLAGS) $*.c # To find out which symbols are needed from external libraries # and which libraries are needed, we build a simple a.out that # links all the objects we just created and then use cgo -dynimport # to inspect it. That is, we make gcc tell us which dynamic symbols # and libraries are involved, instead of duplicating gcc's logic ourselves. -_cgo_main.c: +# After main we have to define all the symbols that will be provided +# by Go code. That's crosscall2 and any exported symbols. +_cgo_main.c: _cgo_defun.c echo 'int main() { return 0; }' >$@ + echo 'int crosscall2;' >>$@ + awk -F'(' '/^_cgoexp_/ {print "int " $$1 ";"}' _cgo_defun.c >>$@ _cgo_main.o: _cgo_main.c $(HOST_CC) $(_CGO_CFLAGS_$(GOARCH)) -g -fPIC -O2 -o $@ -c $(CGO_CFLAGS) _cgo_main.c -_cgo1_.o: _cgo_main.o $(GCC_OFILES) +_cgo1_.o: _cgo_main.o $(CGO_OFILES) $(HOST_CC) $(_CGO_CFLAGS_$(GOARCH)) -g -fPIC -O2 -o $@ $^ $(CGO_LDFLAGS) _cgo_import.c: _cgo1_.o diff --git a/src/cmd/6l/asm.c b/src/cmd/6l/asm.c index bd25d7942b..26293454bf 100644 --- a/src/cmd/6l/asm.c +++ b/src/cmd/6l/asm.c @@ -193,14 +193,28 @@ adddynrel(Sym *s, Reloc *r) return; case 256 + R_X86_64_PLT32: - addpltsym(targ); r->type = D_PCREL; - r->sym = lookup(".plt", 0); r->add += 4; - r->add += targ->plt; + if(targ->dynimpname != nil) { + addpltsym(targ); + r->sym = lookup(".plt", 0); + r->add += targ->plt; + } return; case 256 + R_X86_64_GOTPCREL: + if(targ->dynimpname == nil) { + // have symbol + // turn MOVQ of GOT entry into LEAQ of symbol itself + if(r->off < 2 || s->p[r->off-2] != 0x8b) { + diag("unexpected GOT_LOAD reloc for non-dynamic symbol %s", targ->name); + return; + } + s->p[r->off-2] = 0x8d; + r->type = D_PCREL; + r->add += 4; + return; + } addgotsym(targ); r->type = D_PCREL; r->sym = lookup(".got", 0); @@ -244,8 +258,21 @@ adddynrel(Sym *s, Reloc *r) return; case 512 + MACHO_X86_64_RELOC_GOT_LOAD*2 + 1: + if(targ->dynimpname == nil) { + // have symbol + // turn MOVQ of GOT entry into LEAQ of symbol itself + if(r->off < 2 || s->p[r->off-2] != 0x8b) { + diag("unexpected GOT_LOAD reloc for non-dynamic symbol %s", targ->name); + return; + } + s->p[r->off-2] = 0x8d; + r->type = D_PCREL; + return; + } + // fall through case 512 + MACHO_X86_64_RELOC_GOT*2 + 1: - // TODO: What is the difference between these two? + if(targ->dynimpname == nil) + diag("unexpected GOT reloc for non-dynamic symbol %s", targ->name); addgotsym(targ); r->type = D_PCREL; r->sym = lookup(".got", 0); @@ -446,9 +473,12 @@ adddynsym(Sym *s) if(s->dynid >= 0) return; + if(s->dynimpname == nil) + diag("adddynsym: no dynamic name for %s", s->name); + if(iself) { s->dynid = nelfsym++; - + d = lookup(".dynsym", 0); name = s->dynimpname; if(name == nil) @@ -512,10 +542,29 @@ adddynsym(Sym *s) adduint32(d, str->size); adduint8(str, '_'); addstring(str, name); - adduint8(d, 0x01); // type - N_EXT - external symbol - adduint8(d, 0); // section + if(s->type == SDYNIMPORT) { + adduint8(d, 0x01); // type - N_EXT - external symbol + adduint8(d, 0); // section + } else { + adduint8(d, 0x0f); + switch(s->type) { + default: + case STEXT: + adduint8(d, 1); + break; + case SDATA: + adduint8(d, 2); + break; + case SBSS: + adduint8(d, 4); + break; + } + } adduint16(d, 0); // desc - adduint64(d, 0); // value + if(s->type == SDYNIMPORT) + adduint64(d, 0); // value + else + addaddr(d, s); } else { diag("adddynsym: unsupported binary format"); } diff --git a/src/cmd/8l/8.out.h b/src/cmd/8l/8.out.h index c41a676d43..0866f05f00 100644 --- a/src/cmd/8l/8.out.h +++ b/src/cmd/8l/8.out.h @@ -501,7 +501,7 @@ enum D_SIZE, /* 8l internal */ D_PCREL, D_GOTOFF, - D_GOTPCREL, + D_GOTREL, T_TYPE = 1<<0, T_INDEX = 1<<1, diff --git a/src/cmd/8l/asm.c b/src/cmd/8l/asm.c index 8ffa43e02e..e1496e3d80 100644 --- a/src/cmd/8l/asm.c +++ b/src/cmd/8l/asm.c @@ -183,14 +183,27 @@ adddynrel(Sym *s, Reloc *r) return; case 256 + R_386_PLT32: - addpltsym(targ); r->type = D_PCREL; - r->sym = lookup(".plt", 0); r->add += 4; - r->add += targ->plt; + if(targ->dynimpname != nil) { + addpltsym(targ); + r->sym = lookup(".plt", 0); + r->add += targ->plt; + } return; case 256 + R_386_GOT32: + if(targ->dynimpname == nil) { + // have symbol + // turn MOVL of GOT entry into LEAL of symbol itself + if(r->off < 2 || s->p[r->off-2] != 0x8b) { + diag("unexpected GOT reloc for non-dynamic symbol %s", targ->name); + return; + } + s->p[r->off-2] = 0x8d; + r->type = D_GOTOFF; + return; + } addgotsym(targ); r->type = D_CONST; // write r->add during relocsym r->sym = S; @@ -233,6 +246,17 @@ adddynrel(Sym *s, Reloc *r) return; case 512 + MACHO_FAKE_GOTPCREL: + if(targ->dynimpname == nil) { + // have symbol + // turn MOVL of GOT entry into LEAL of symbol itself + if(r->off < 2 || s->p[r->off-2] != 0x8b) { + diag("unexpected GOT reloc for non-dynamic symbol %s", targ->name); + return; + } + s->p[r->off-2] = 0x8d; + r->type = D_PCREL; + return; + } addgotsym(targ); r->sym = lookup(".got", 0); r->add += targ->got; @@ -429,6 +453,9 @@ adddynsym(Sym *s) if(s->dynid >= 0) return; + if(s->dynimpname == nil) + diag("adddynsym: no dynamic name for %s", s->name, *(int32*)0); + if(iself) { s->dynid = nelfsym++; diff --git a/src/cmd/cgo/gcc.go b/src/cmd/cgo/gcc.go index 6fad336354..7626038c4b 100644 --- a/src/cmd/cgo/gcc.go +++ b/src/cmd/cgo/gcc.go @@ -377,7 +377,6 @@ func (p *Package) loadDWARF(f *File, names []*Name) { } } } - f.Typedef = conv.typedef } // rewriteRef rewrites all the C.xxx references in f.AST to refer to the @@ -596,11 +595,11 @@ type typeConv struct { } var tagGen int +var typedef = make(map[string]ast.Expr) func (c *typeConv) Init(ptrSize int64) { c.ptrSize = ptrSize c.m = make(map[dwarf.Type]*Type) - c.typedef = make(map[string]ast.Expr) c.bool = c.Ident("bool") c.byte = c.Ident("byte") c.int8 = c.Ident("int8") @@ -808,7 +807,7 @@ func (c *typeConv) Type(dtype dwarf.Type) *Type { t.Go = name // publish before recursive calls switch dt.Kind { case "union", "class": - c.typedef[name.Name] = c.Opaque(t.Size) + typedef[name.Name] = c.Opaque(t.Size) if t.C == "" { t.C = fmt.Sprintf("typeof(unsigned char[%d])", t.Size) } @@ -818,7 +817,7 @@ func (c *typeConv) Type(dtype dwarf.Type) *Type { t.C = csyntax } t.Align = align - c.typedef[name.Name] = g + typedef[name.Name] = g } case *dwarf.TypedefType: @@ -837,8 +836,8 @@ func (c *typeConv) Type(dtype dwarf.Type) *Type { sub := c.Type(dt.Type) t.Size = sub.Size t.Align = sub.Align - if _, ok := c.typedef[name.Name]; !ok { - c.typedef[name.Name] = sub.Go + if _, ok := typedef[name.Name]; !ok { + typedef[name.Name] = sub.Go } case *dwarf.UcharType: @@ -882,7 +881,7 @@ func (c *typeConv) Type(dtype dwarf.Type) *Type { } s = strings.Join(strings.Split(s, " ", -1), "") // strip spaces name := c.Ident("_Ctype_" + s) - c.typedef[name.Name] = t.Go + typedef[name.Name] = t.Go t.Go = name } } diff --git a/src/cmd/cgo/main.go b/src/cmd/cgo/main.go index c50ecfb059..942bda5f4d 100644 --- a/src/cmd/cgo/main.go +++ b/src/cmd/cgo/main.go @@ -232,18 +232,6 @@ func (p *Package) Record(f *File) { error(token.NoPos, "inconsistent package names: %s, %s", p.PackageName, f.Package) } - if p.Typedef == nil { - p.Typedef = f.Typedef - } else { - for k, v := range f.Typedef { - if p.Typedef[k] == nil { - p.Typedef[k] = v - } else if !reflect.DeepEqual(p.Typedef[k], v) { - error(token.NoPos, "inconsistent definitions for C type %s", k) - } - } - } - if p.Name == nil { p.Name = f.Name } else { diff --git a/src/cmd/cgo/out.go b/src/cmd/cgo/out.go index 8926cb22cc..d960079e1a 100644 --- a/src/cmd/cgo/out.go +++ b/src/cmd/cgo/out.go @@ -42,7 +42,7 @@ func (p *Package) writeDefs() { fmt.Fprintf(fgo2, "type _ unsafe.Pointer\n\n") fmt.Fprintf(fgo2, "func _Cerrno(dst *os.Error, x int) { *dst = os.Errno(x) }\n") - for name, def := range p.Typedef { + for name, def := range typedef { fmt.Fprintf(fgo2, "type %s ", name) printer.Fprint(fgo2, fset, def) fmt.Fprintf(fgo2, "\n") @@ -321,10 +321,6 @@ func (p *Package) writeOutputFunc(fgcc *os.File, n *Name) { // Write out the various stubs we need to support functions exported // from Go so that they are callable from C. func (p *Package) writeExports(fgo2, fc *os.File) { - if len(p.ExpFunc) == 0 { - return - } - fgcc := creat("_cgo_export.c") fgcch := creat("_cgo_export.h") @@ -424,7 +420,7 @@ func (p *Package) writeExports(fgo2, fc *os.File) { s += ")" fmt.Fprintf(fgcch, "\nextern %s;\n", s) - fmt.Fprintf(fgcc, "extern _cgoexp_%s(void *, int);\n", exp.ExpName) + fmt.Fprintf(fgcc, "extern _cgoexp%s_%s(void *, int);\n", cPrefix, exp.ExpName) fmt.Fprintf(fgcc, "\n%s\n", s) fmt.Fprintf(fgcc, "{\n") fmt.Fprintf(fgcc, "\t%s a;\n", ctype) @@ -438,7 +434,7 @@ func (p *Package) writeExports(fgo2, fc *os.File) { func(i int, atype ast.Expr) { fmt.Fprintf(fgcc, "\ta.p%d = p%d;\n", i, i) }) - fmt.Fprintf(fgcc, "\tcrosscall2(_cgoexp_%s, &a, (int) sizeof a);\n", exp.ExpName) + fmt.Fprintf(fgcc, "\tcrosscall2(_cgoexp%s_%s, &a, (int) sizeof a);\n", cPrefix, exp.ExpName) if gccResult != "void" { if len(fntype.Results.List) == 1 && len(fntype.Results.List[0].Names) <= 1 { fmt.Fprintf(fgcc, "\treturn a.r0;\n") @@ -455,12 +451,11 @@ func (p *Package) writeExports(fgo2, fc *os.File) { // Build the wrapper function compiled by 6c/8c goname := exp.Func.Name.Name if fn.Recv != nil { - goname = "_cgoexpwrap_" + fn.Recv.List[0].Names[0].Name + "_" + goname + goname = "_cgoexpwrap" + cPrefix + "_" + fn.Recv.List[0].Names[0].Name + "_" + goname } - fmt.Fprintf(fc, "#pragma dynexport _cgoexp_%s _cgoexp_%s\n", exp.ExpName, exp.ExpName) fmt.Fprintf(fc, "extern void ·%s();\n", goname) fmt.Fprintf(fc, "\nvoid\n") - fmt.Fprintf(fc, "_cgoexp_%s(void *a, int32 n)\n", exp.ExpName) + fmt.Fprintf(fc, "_cgoexp%s_%s(void *a, int32 n)\n", cPrefix, exp.ExpName) fmt.Fprintf(fc, "{\n") fmt.Fprintf(fc, "\truntime·cgocallback(·%s, a, n);\n", goname) fmt.Fprintf(fc, "}\n") @@ -584,7 +579,7 @@ func (p *Package) cgoType(e ast.Expr) *Type { } } } - for name, def := range p.Typedef { + for name, def := range typedef { if name == t.Name { return p.cgoType(def) } diff --git a/src/pkg/runtime/cgo/Makefile b/src/pkg/runtime/cgo/Makefile index 917166e069..b825c17805 100644 --- a/src/pkg/runtime/cgo/Makefile +++ b/src/pkg/runtime/cgo/Makefile @@ -19,7 +19,7 @@ ifeq ($(ENABLED),1) # Unwarranted chumminess with Make.pkg's cgo rules. # Do not try this at home. -GCC_OFILES=\ +CGO_OFILES=\ $(GOARCH).o\ $(GOOS)_$(GOARCH).o\ util.o\ @@ -27,7 +27,7 @@ GCC_OFILES=\ OFILES=\ iscgo.$O\ _cgo_import.$O\ - $(GCC_OFILES)\ + $(CGO_OFILES)\ CGO_LDFLAGS=-lpthread @@ -41,6 +41,11 @@ endif include ../../../Make.pkg +ifeq ($(ENABLED),1) +_cgo_defun.c: + echo >$@ +endif + $(GOARCH).o: $(GOARCH).S $(HOST_CC) $(_CGO_CFLAGS_$(GOARCH)) -g -O2 -fPIC -o $@ -c $^ diff --git a/src/run.bash b/src/run.bash index 4455d2736e..0cd129253c 100755 --- a/src/run.bash +++ b/src/run.bash @@ -84,6 +84,14 @@ if [[ $(uname | tr A-Z a-z | sed 's/mingw/windows/') != *windows* ]]; then fi ) || exit $? +[ "$GOARCH" == arm ] || +(xcd ../misc/cgo/life +if [[ $(uname | tr A-Z a-z | sed 's/mingw/windows/') != *windows* ]]; then + gomake clean + ./test.bash +fi +) || exit $? + (xcd pkg/exp/ogle gomake clean time gomake ogle