]> Cypherpunks repositories - gostls13.git/commitdiff
misc/cgo/life: fix, add to build
authorRuss Cox <rsc@golang.org>
Fri, 17 Dec 2010 17:51:55 +0000 (09:51 -0800)
committerRuss Cox <rsc@golang.org>
Fri, 17 Dec 2010 17:51:55 +0000 (09:51 -0800)
#pragma dynexport is no longer needed for
this use of cgo, since the gcc and gc code are
now linked together into the same binary.
It may still be necessary later.

On the Mac, you cannot use the GOT to resolve
symbols that exist in the current binary, so 6l and 8l
translate the GOT-loading mov instructions into lea
instructions.

On ELF systems, we could use the GOT for those
symbols, but for consistency 6l and 8l apply the
same translation.

The translation is sketchy in the extreme
(depending on the relocation being in a mov
instruction) but it verifies that the instruction
is a mov before rewriting it to lea.

Also makes typedefs global across files.

Fixes #1335.
Fixes #1345.

R=iant, r
CC=golang-dev
https://golang.org/cl/3650042

12 files changed:
misc/cgo/life/Makefile
misc/cgo/life/golden.out [new file with mode: 0644]
misc/cgo/life/test.bash [new file with mode: 0755]
src/Make.pkg
src/cmd/6l/asm.c
src/cmd/8l/8.out.h
src/cmd/8l/asm.c
src/cmd/cgo/gcc.go
src/cmd/cgo/main.go
src/cmd/cgo/out.go
src/pkg/runtime/cgo/Makefile
src/run.bash

index b50a5ee7d29c92de6eea32b641a67a6f06f57fbc..5a10380edb5dd4fae69267c91212a57ec904573a 100644 (file)
@@ -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 (file)
index 0000000..539d210
--- /dev/null
@@ -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 (executable)
index 0000000..5c5fba1
--- /dev/null
@@ -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
index 6aa5e29c0c39b9447cf4fc403b9e791211343275..420f61003036aeec86f61a4ee2951ab0e6dc9457 100644 (file)
@@ -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
index bd25d7942b33498377347e05ccece929d135b108..26293454bf6013bcccb3acbc69ad973cbed0eee6 100644 (file)
@@ -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");
        }
index c41a676d438dcf5986bc324ca0682d14c6d93240..0866f05f00ee0351471978d8cb99ae5abbb4f955 100644 (file)
@@ -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,
index 8ffa43e02e5ceeb24f6f92e6bbe56216bf9dbe80..e1496e3d802cfd1ab37f498f9f254f6ee8e15fae 100644 (file)
@@ -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++;
                
index 6fad3363540eaa2272a62e9533bc121c4f76f47a..7626038c4babca228e515e92060c45c2e3d106b0 100644 (file)
@@ -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
                }
        }
index c50ecfb059c9e4e8d2e311929149a861ed51f2a4..942bda5f4da44eb23cbd48dfd5e3c0c4d67de1a8 100644 (file)
@@ -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 {
index 8926cb22cc3acaf10ef6ba4942f900004ae6c780..d960079e1a47156a3af83de9299f6c46af03743c 100644 (file)
@@ -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)
                        }
index 917166e06979413d56486adf72341aaf2f050f6a..b825c17805b7ab0eb266376af3a151486e2dbc20 100644 (file)
@@ -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 $^
 
index 4455d2736e46058330756e979ad2a6f43325b9c2..0cd129253c2c23321704d655ca10e9f2035a84bc 100755 (executable)
@@ -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