Commit 0cd34753 authored by Russ Cox's avatar Russ Cox

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
parent a890d70c
......@@ -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
* life
XXX XXX
XXX XXX
#!/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
......@@ -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
......
......@@ -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");
}
......
......@@ -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,
......
......@@ -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++;
......
......@@ -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
}
}
......
......@@ -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 {
......
......@@ -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)
}
......
......@@ -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 $^
......
......@@ -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
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment