summaryrefslogtreecommitdiff
path: root/src/cmd/cgo/out.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/cgo/out.go')
-rw-r--r--src/cmd/cgo/out.go142
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;
`