aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRuss Cox <rsc@golang.org>2010-12-17 09:51:55 -0800
committerRuss Cox <rsc@golang.org>2010-12-17 09:51:55 -0800
commit0cd34753866bf6114df91d074f9e344cfd17aa1d (patch)
tree2e5575258a448326a6c29720acd9d57b8e89e9ff
parenta890d70cc1fff8513d89e88b7028132f6df40b42 (diff)
downloadgo-0cd34753866bf6114df91d074f9e344cfd17aa1d.tar.gz
go-0cd34753866bf6114df91d074f9e344cfd17aa1d.zip
misc/cgo/life: fix, add to build
#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
-rw-r--r--misc/cgo/life/Makefile18
-rw-r--r--misc/cgo/life/golden.out17
-rwxr-xr-xmisc/cgo/life/test.bash11
-rw-r--r--src/Make.pkg21
-rw-r--r--src/cmd/6l/asm.c65
-rw-r--r--src/cmd/8l/8.out.h2
-rw-r--r--src/cmd/8l/asm.c33
-rw-r--r--src/cmd/cgo/gcc.go13
-rw-r--r--src/cmd/cgo/main.go12
-rw-r--r--src/cmd/cgo/out.go17
-rw-r--r--src/pkg/runtime/cgo/Makefile9
-rwxr-xr-xsrc/run.bash8
12 files changed, 159 insertions, 67 deletions
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