diff options
Diffstat (limited to 'src/cmd/cgo/out.go')
-rw-r--r-- | src/cmd/cgo/out.go | 142 |
1 files changed, 110 insertions, 32 deletions
diff --git a/src/cmd/cgo/out.go b/src/cmd/cgo/out.go index 7fb818168..83ab95251 100644 --- a/src/cmd/cgo/out.go +++ b/src/cmd/cgo/out.go @@ -32,7 +32,7 @@ func (p *Package) writeDefs() { fflg := creat(*objDir + "_cgo_flags") for k, v := range p.CgoFlags { fmt.Fprintf(fflg, "_CGO_%s=%s\n", k, strings.Join(v, " ")) - if k == "LDFLAGS" { + if k == "LDFLAGS" && !*gccgo { for _, arg := range v { fmt.Fprintf(fc, "#pragma cgo_ldflag %q\n", arg) } @@ -47,7 +47,7 @@ func (p *Package) writeDefs() { } else { // If we're not importing runtime/cgo, we *are* runtime/cgo, // which provides crosscall2. We just need a prototype. - fmt.Fprintf(fm, "void crosscall2(void(*fn)(void*, int), void *a, int c);") + fmt.Fprintf(fm, "void crosscall2(void(*fn)(void*, int), void *a, int c);\n") } fmt.Fprintf(fm, "void _cgo_allocate(void *a, int c) { }\n") fmt.Fprintf(fm, "void _cgo_panic(void *a, int c) { }\n") @@ -87,7 +87,7 @@ func (p *Package) writeDefs() { } if *gccgo { - fmt.Fprintf(fc, cPrologGccgo) + fmt.Fprintf(fc, p.cPrologGccgo()) } else { fmt.Fprintf(fc, cProlog) } @@ -97,7 +97,7 @@ func (p *Package) writeDefs() { cVars := make(map[string]bool) for _, key := range nameKeys(p.Name) { n := p.Name[key] - if n.Kind != "var" { + if !n.IsVar() { continue } @@ -105,22 +105,37 @@ func (p *Package) writeDefs() { fmt.Fprintf(fm, "extern char %s[];\n", n.C) fmt.Fprintf(fm, "void *_cgohack_%s = %s;\n\n", n.C, n.C) - fmt.Fprintf(fc, "#pragma cgo_import_static %s\n", n.C) + if !*gccgo { + fmt.Fprintf(fc, "#pragma cgo_import_static %s\n", n.C) + } + fmt.Fprintf(fc, "extern byte *%s;\n", n.C) cVars[n.C] = true } - + var amp string + var node ast.Node + if n.Kind == "var" { + amp = "&" + node = &ast.StarExpr{X: n.Type.Go} + } else if n.Kind == "fpvar" { + node = n.Type.Go + if *gccgo { + amp = "&" + } + } else { + panic(fmt.Errorf("invalid var kind %q", n.Kind)) + } if *gccgo { fmt.Fprintf(fc, `extern void *%s __asm__("%s.%s");`, n.Mangle, gccgoSymbolPrefix, n.Mangle) - fmt.Fprintf(&gccgoInit, "\t%s = &%s;\n", n.Mangle, n.C) + fmt.Fprintf(&gccgoInit, "\t%s = %s%s;\n", n.Mangle, amp, n.C) } else { - fmt.Fprintf(fc, "void *·%s = &%s;\n", n.Mangle, n.C) + fmt.Fprintf(fc, "void *·%s = %s%s;\n", n.Mangle, amp, n.C) } fmt.Fprintf(fc, "\n") fmt.Fprintf(fgo2, "var %s ", n.Mangle) - conf.Fprint(fgo2, fset, &ast.StarExpr{X: n.Type.Go}) + conf.Fprint(fgo2, fset, node) fmt.Fprintf(fgo2, "\n") } fmt.Fprintf(fc, "\n") @@ -282,7 +297,7 @@ func (p *Package) structType(n *Name) (string, int64) { off += pad } if n.AddError { - fmt.Fprint(&buf, "\t\tvoid *e[2]; /* error */\n") + fmt.Fprint(&buf, "\t\tint e[2*sizeof(void *)/sizeof(int)]; /* error */\n") off += 2 * p.PtrSize } if off == 0 { @@ -319,7 +334,7 @@ func (p *Package) writeDefsFunc(fc, fgo2 *os.File, n *Name) { } // Builtins defined in the C prolog. - inProlog := name == "CString" || name == "GoString" || name == "GoStringN" || name == "GoBytes" + inProlog := name == "CString" || name == "GoString" || name == "GoStringN" || name == "GoBytes" || name == "_CMalloc" if *gccgo { // Gccgo style hooks. @@ -368,11 +383,7 @@ func (p *Package) writeDefsFunc(fc, fgo2 *os.File, n *Name) { fmt.Fprint(fgo2, "}\n") // declare the C function. - if inProlog { - fmt.Fprintf(fgo2, "//extern %s\n", n.C) - } else { - fmt.Fprintf(fgo2, "//extern _cgo%s%s\n", cPrefix, n.Mangle) - } + fmt.Fprintf(fgo2, "//extern _cgo%s%s\n", cPrefix, n.Mangle) d.Name = ast.NewIdent(cname) if n.AddError { l := d.Type.Results.List @@ -401,7 +412,17 @@ func (p *Package) writeDefsFunc(fc, fgo2 *os.File, n *Name) { if argSize == 0 { argSize++ } - fmt.Fprintf(fc, "·%s(struct{uint8 x[%d];}p)\n", n.Mangle, argSize) + // TODO(rsc): The struct here should declare pointers only where + // there are pointers in the actual argument frame. + // This is a workaround for golang.org/issue/6397. + fmt.Fprintf(fc, "·%s(struct{", n.Mangle) + if n := argSize / p.PtrSize; n > 0 { + fmt.Fprintf(fc, "void *y[%d];", n) + } + if n := argSize % p.PtrSize; n > 0 { + fmt.Fprintf(fc, "uint8 x[%d];", n) + } + fmt.Fprintf(fc, "}p)\n") fmt.Fprintf(fc, "{\n") fmt.Fprintf(fc, "\truntime·cgocall(_cgo%s%s, &p);\n", cPrefix, n.Mangle) if n.AddError { @@ -464,9 +485,27 @@ func (p *Package) writeOutput(f *File, srcfile string) { fgcc.Close() } +// fixGo convers the internal Name.Go field into the name we should show +// to users in error messages. There's only one for now: on input we rewrite +// C.malloc into C._CMalloc, so change it back here. +func fixGo(name string) string { + if name == "_CMalloc" { + return "malloc" + } + return name +} + +var isBuiltin = map[string]bool{ + "_Cfunc_CString": true, + "_Cfunc_GoString": true, + "_Cfunc_GoStringN": true, + "_Cfunc_GoBytes": true, + "_Cfunc__CMalloc": true, +} + func (p *Package) writeOutputFunc(fgcc *os.File, n *Name) { name := n.Mangle - if name == "_Cfunc_CString" || name == "_Cfunc_GoString" || name == "_Cfunc_GoStringN" || name == "_Cfunc_GoBytes" || p.Written[name] { + if isBuiltin[name] || p.Written[name] { // The builtins are already defined in the C prolog, and we don't // want to duplicate function definitions we've already done. return @@ -486,19 +525,24 @@ func (p *Package) writeOutputFunc(fgcc *os.File, n *Name) { fmt.Fprintf(fgcc, "_cgo%s%s(void *v)\n", cPrefix, n.Mangle) fmt.Fprintf(fgcc, "{\n") if n.AddError { - fmt.Fprintf(fgcc, "\tint e;\n") // assuming 32 bit (see comment above structType) fmt.Fprintf(fgcc, "\terrno = 0;\n") } // We're trying to write a gcc struct that matches 6c/8c/5c's layout. // Use packed attribute to force no padding in this struct in case // gcc has different packing requirements. For example, // on 386 Windows, gcc wants to 8-align int64s, but 8c does not. - fmt.Fprintf(fgcc, "\t%s __attribute__((__packed__)) *a = v;\n", ctype) + // Use __gcc_struct__ to work around http://gcc.gnu.org/PR52991 on x86, + // and http://golang.org/issue/5603. + extraAttr := "" + if !strings.Contains(p.gccBaseCmd()[0], "clang") && (goarch == "amd64" || goarch == "386") { + extraAttr = ", __gcc_struct__" + } + fmt.Fprintf(fgcc, "\t%s __attribute__((__packed__%v)) *a = v;\n", ctype, extraAttr) fmt.Fprintf(fgcc, "\t") if t := n.FuncType.Result; t != nil { fmt.Fprintf(fgcc, "a->r = ") if c := t.C.String(); c[len(c)-1] == '*' { - fmt.Fprintf(fgcc, "(const %s) ", t.C) + fmt.Fprint(fgcc, "(__typeof__(a->r)) ") } } fmt.Fprintf(fgcc, "%s(", n.C) @@ -993,7 +1037,8 @@ func (p *Package) cgoType(e ast.Expr) *Type { return &Type{Size: p.PtrSize, Align: p.PtrSize, C: c("%s*", x.C)} case *ast.ArrayType: if t.Len == nil { - return &Type{Size: p.PtrSize + 8, Align: p.PtrSize, C: c("GoSlice")} + // Slice: pointer, len, cap. + return &Type{Size: p.PtrSize * 3, Align: p.PtrSize, C: c("GoSlice")} } case *ast.StructType: // TODO @@ -1030,8 +1075,7 @@ func (p *Package) cgoType(e ast.Expr) *Type { return &Type{Size: p.PtrSize, Align: p.PtrSize, C: c("GoUintptr")} } if t.Name == "string" { - // The string data is 1 pointer + 1 int, but this always - // rounds to 2 pointers due to alignment. + // The string data is 1 pointer + 1 (pointer-sized) int. return &Type{Size: 2 * p.PtrSize, Align: p.PtrSize, C: c("GoString")} } if t.Name == "error" { @@ -1084,12 +1128,24 @@ __cgo_size_assert(double, 8) ` const builtinProlog = ` -typedef struct { char *p; int n; } _GoString_; -typedef struct { char *p; int n; int c; } _GoBytes_; +#include <sys/types.h> /* for size_t below */ + +/* Define intgo when compiling with GCC. */ +#ifdef __PTRDIFF_TYPE__ +typedef __PTRDIFF_TYPE__ intgo; +#elif defined(_LP64) +typedef long long intgo; +#else +typedef int intgo; +#endif + +typedef struct { char *p; intgo n; } _GoString_; +typedef struct { char *p; intgo n; intgo c; } _GoBytes_; _GoString_ GoString(char *p); _GoString_ GoStringN(char *p, int l); _GoBytes_ GoBytes(void *p, int n); char *CString(_GoString_); +void *_CMalloc(size_t); ` const cProlog = ` @@ -1127,10 +1183,22 @@ void p[s.len] = 0; FLUSH(&p); } + +void +·_Cfunc__CMalloc(uintptr n, int8 *p) +{ + p = runtime·cmalloc(n); + FLUSH(&p); +} ` +func (p *Package) cPrologGccgo() string { + return strings.Replace(cPrologGccgo, "PREFIX", cPrefix, -1) +} + const cPrologGccgo = ` #include <stdint.h> +#include <stdlib.h> #include <string.h> typedef unsigned char byte; @@ -1150,23 +1218,33 @@ typedef struct __go_open_array { struct __go_string __go_byte_array_to_string(const void* p, intgo len); struct __go_open_array __go_string_to_byte_array (struct __go_string str); -const char *CString(struct __go_string s) { +const char *_cgoPREFIX_Cfunc_CString(struct __go_string s) { return strndup((const char*)s.__data, s.__length); } -struct __go_string GoString(char *p) { +struct __go_string _cgoPREFIX_Cfunc_GoString(char *p) { intgo len = (p != NULL) ? strlen(p) : 0; return __go_byte_array_to_string(p, len); } -struct __go_string GoStringN(char *p, intgo n) { +struct __go_string _cgoPREFIX_Cfunc_GoStringN(char *p, int32_t n) { return __go_byte_array_to_string(p, n); } -Slice GoBytes(char *p, intgo n) { +Slice _cgoPREFIX_Cfunc_GoBytes(char *p, int32_t n) { struct __go_string s = { (const unsigned char *)p, n }; return __go_string_to_byte_array(s); } + +extern void runtime_throw(const char *); +void *_cgoPREFIX_Cfunc__CMalloc(size_t n) { + void *p = malloc(n); + if(p == NULL && n == 0) + p = malloc(1); + if(p == NULL) + runtime_throw("runtime: C malloc failed"); + return p; +} ` func (p *Package) gccExportHeaderProlog() string { @@ -1190,9 +1268,9 @@ typedef double GoFloat64; typedef __complex float GoComplex64; typedef __complex double GoComplex128; -typedef struct { char *p; int n; } GoString; +typedef struct { char *p; GoInt n; } GoString; typedef void *GoMap; typedef void *GoChan; typedef struct { void *t; void *v; } GoInterface; -typedef struct { void *data; int len; int cap; } GoSlice; +typedef struct { void *data; GoInt len; GoInt cap; } GoSlice; ` |