summaryrefslogtreecommitdiff
path: root/src/cmd/cgo
diff options
context:
space:
mode:
authorAustin Clements <austin@google.com>2014-10-22 11:21:16 -0400
committerAustin Clements <austin@google.com>2014-10-22 11:21:16 -0400
commit2c586384223e980fd3303625ea6b02ed5d9fb9c0 (patch)
tree54aa72cd9d5eb1566f682d3b0770141a11b54fc2 /src/cmd/cgo
parentebe8a09fb603d9510cb982a6c11a3e1638f7f8fb (diff)
parent45fcda1dc8d9b4d4a9b642faf8e78941873f508d (diff)
downloadgo-2c586384223e980fd3303625ea6b02ed5d9fb9c0.tar.gz
[dev.power64] build: merge default into dev.power64
LGTM=rsc R=rsc CC=golang-codereviews https://codereview.appspot.com/160200044
Diffstat (limited to 'src/cmd/cgo')
-rw-r--r--src/cmd/cgo/gcc.go94
-rw-r--r--src/cmd/cgo/out.go202
2 files changed, 163 insertions, 133 deletions
diff --git a/src/cmd/cgo/gcc.go b/src/cmd/cgo/gcc.go
index 841c84833..d77d56c22 100644
--- a/src/cmd/cgo/gcc.go
+++ b/src/cmd/cgo/gcc.go
@@ -229,7 +229,8 @@ func (p *Package) guessKinds(f *File) []*Name {
// Determine kinds for names we already know about,
// like #defines or 'struct foo', before bothering with gcc.
var names, needType []*Name
- for _, n := range f.Name {
+ for _, key := range nameKeys(f.Name) {
+ n := f.Name[key]
// If we've already found this name as a #define
// and we can translate it as a constant value, do so.
if n.Define != "" {
@@ -331,6 +332,7 @@ func (p *Package) guessKinds(f *File) []*Name {
const (
notType = 1 << iota
notConst
+ notDeclared
)
for _, line := range strings.Split(stderr, "\n") {
if !strings.Contains(line, ": error:") {
@@ -365,7 +367,7 @@ func (p *Package) guessKinds(f *File) []*Name {
completed = true
case "not-declared":
- error_(token.NoPos, "%s", strings.TrimSpace(line[c2+1:]))
+ sniff[i] |= notDeclared
case "not-type":
sniff[i] |= notType
case "not-const":
@@ -374,12 +376,12 @@ func (p *Package) guessKinds(f *File) []*Name {
}
if !completed {
- fatalf("%s did not produce error at completed:1\non input:\n%s", p.gccBaseCmd()[0], b.Bytes())
+ fatalf("%s did not produce error at completed:1\non input:\n%s\nfull error output:\n%s", p.gccBaseCmd()[0], b.Bytes(), stderr)
}
for i, n := range names {
switch sniff[i] {
- case 0:
+ default:
error_(token.NoPos, "could not determine kind of name for C.%s", fixGo(n.Go))
case notType:
n.Kind = "const"
@@ -390,6 +392,14 @@ func (p *Package) guessKinds(f *File) []*Name {
}
}
if nerrors > 0 {
+ // Check if compiling the preamble by itself causes any errors,
+ // because the messages we've printed out so far aren't helpful
+ // to users debugging preamble mistakes. See issue 8442.
+ preambleErrors := p.gccErrors([]byte(f.Preamble))
+ if len(preambleErrors) > 0 {
+ error_(token.NoPos, "\n%s errors for preamble:\n%s", p.gccBaseCmd()[0], preambleErrors)
+ }
+
fatalf("unresolved names")
}
@@ -649,7 +659,13 @@ func (p *Package) rewriteRef(f *File) {
f.Name[fpName] = name
}
r.Name = name
- expr = ast.NewIdent(name.Mangle)
+ // Rewrite into call to _Cgo_ptr to prevent assignments. The _Cgo_ptr
+ // function is defined in out.go and simply returns its argument. See
+ // issue 7757.
+ expr = &ast.CallExpr{
+ Fun: &ast.Ident{NamePos: (*r.Expr).Pos(), Name: "_Cgo_ptr"},
+ Args: []ast.Expr{ast.NewIdent(name.Mangle)},
+ }
} else if r.Name.Kind == "type" {
// Okay - might be new(T)
expr = r.Name.Type.Go
@@ -1068,12 +1084,6 @@ func (c *typeConv) Type(dtype dwarf.Type, pos token.Pos) *Type {
return t
}
- // clang won't generate DW_AT_byte_size for pointer types,
- // so we have to fix it here.
- if dt, ok := base(dtype).(*dwarf.PtrType); ok && dt.ByteSize == -1 {
- dt.ByteSize = c.ptrSize
- }
-
t := new(Type)
t.Size = dtype.Size() // note: wrong for array of pointers, corrected below
t.Align = -1
@@ -1097,12 +1107,20 @@ func (c *typeConv) Type(dtype dwarf.Type, pos token.Pos) *Type {
t.Go = c.Opaque(t.Size)
break
}
+ count := dt.Count
+ if count == -1 {
+ // Indicates flexible array member, which Go doesn't support.
+ // Translate to zero-length array instead.
+ count = 0
+ }
sub := c.Type(dt.Type, pos)
t.Align = sub.Align
t.Go = &ast.ArrayType{
- Len: c.intExpr(dt.Count),
+ Len: c.intExpr(count),
Elt: sub.Go,
}
+ // Recalculate t.Size now that we know sub.Size.
+ t.Size = count * sub.Size
t.C.Set("__typeof__(%s[%d])", sub.C, dt.Count)
case *dwarf.BoolType:
@@ -1203,6 +1221,11 @@ func (c *typeConv) Type(dtype dwarf.Type, pos token.Pos) *Type {
}
case *dwarf.PtrType:
+ // Clang doesn't emit DW_AT_byte_size for pointer types.
+ if t.Size != c.ptrSize && t.Size != -1 {
+ fatalf("%s: unexpected: %d-byte pointer type - %s", lineno(pos), t.Size, dtype)
+ }
+ t.Size = c.ptrSize
t.Align = c.ptrSize
if _, ok := base(dt.Type).(*dwarf.VoidType); ok {
@@ -1374,34 +1397,24 @@ func (c *typeConv) Type(dtype dwarf.Type, pos token.Pos) *Type {
}
}
- if t.Size <= 0 {
- // Clang does not record the size of a pointer in its DWARF entry,
- // so if dtype is an array, the call to dtype.Size at the top of the function
- // computed the size as the array length * 0 = 0.
- // The type switch called Type (this function) recursively on the pointer
- // entry, and the code near the top of the function updated the size to
- // be correct, so calling dtype.Size again will produce the correct value.
- t.Size = dtype.Size()
- if t.Size < 0 {
- // Unsized types are [0]byte, unless they're typedefs of other types
- // or structs with tags.
- // if so, use the name we've already defined.
- t.Size = 0
- switch dt := dtype.(type) {
- case *dwarf.TypedefType:
- // ok
- case *dwarf.StructType:
- if dt.StructName != "" {
- break
- }
- t.Go = c.Opaque(0)
- default:
- t.Go = c.Opaque(0)
- }
- if t.C.Empty() {
- t.C.Set("void")
+ if t.Size < 0 {
+ // Unsized types are [0]byte, unless they're typedefs of other types
+ // or structs with tags.
+ // if so, use the name we've already defined.
+ t.Size = 0
+ switch dt := dtype.(type) {
+ case *dwarf.TypedefType:
+ // ok
+ case *dwarf.StructType:
+ if dt.StructName != "" {
+ break
}
- return t
+ t.Go = c.Opaque(0)
+ default:
+ t.Go = c.Opaque(0)
+ }
+ if t.C.Empty() {
+ t.C.Set("void")
}
}
@@ -1533,6 +1546,9 @@ func (c *typeConv) pad(fld []*ast.Field, size int64) []*ast.Field {
// Struct conversion: return Go and (6g) C syntax for type.
func (c *typeConv) Struct(dt *dwarf.StructType, pos token.Pos) (expr *ast.StructType, csyntax string, align int64) {
+ // Minimum alignment for a struct is 1 byte.
+ align = 1
+
var buf bytes.Buffer
buf.WriteString("struct {")
fld := make([]*ast.Field, 0, 2*len(dt.Field)+1) // enough for padding around every field
diff --git a/src/cmd/cgo/out.go b/src/cmd/cgo/out.go
index 1ef78b757..6586531ad 100644
--- a/src/cmd/cgo/out.go
+++ b/src/cmd/cgo/out.go
@@ -58,16 +58,14 @@ func (p *Package) writeDefs() {
fmt.Fprintf(fgo2, "// Created by cgo - DO NOT EDIT\n\n")
fmt.Fprintf(fgo2, "package %s\n\n", p.PackageName)
fmt.Fprintf(fgo2, "import \"unsafe\"\n\n")
- if *importSyscall {
- fmt.Fprintf(fgo2, "import \"syscall\"\n\n")
- }
if !*gccgo && *importRuntimeCgo {
fmt.Fprintf(fgo2, "import _ \"runtime/cgo\"\n\n")
}
- fmt.Fprintf(fgo2, "type _ unsafe.Pointer\n\n")
if *importSyscall {
- fmt.Fprintf(fgo2, "func _Cerrno(dst *error, x int32) { *dst = syscall.Errno(x) }\n")
+ fmt.Fprintf(fgo2, "import \"syscall\"\n\n")
+ fmt.Fprintf(fgo2, "var _ syscall.Errno\n")
}
+ fmt.Fprintf(fgo2, "func _Cgo_ptr(ptr unsafe.Pointer) unsafe.Pointer { return ptr }\n\n")
typedefNames := make([]string, 0, len(typedef))
for name := range typedef {
@@ -87,9 +85,10 @@ func (p *Package) writeDefs() {
}
if *gccgo {
- fmt.Fprintf(fc, p.cPrologGccgo())
+ fmt.Fprint(fc, p.cPrologGccgo())
} else {
- fmt.Fprintf(fc, cProlog)
+ fmt.Fprint(fc, cProlog)
+ fmt.Fprint(fgo2, goProlog)
}
gccgoSymbolPrefix := p.gccgoSymbolPrefix()
@@ -296,10 +295,6 @@ func (p *Package) structType(n *Name) (string, int64) {
fmt.Fprintf(&buf, "\t\tchar __pad%d[%d];\n", off, pad)
off += pad
}
- if n.AddError {
- fmt.Fprint(&buf, "\t\tint e[2*sizeof(void *)/sizeof(int)]; /* error */\n")
- off += 2 * p.PtrSize
- }
if off == 0 {
fmt.Fprintf(&buf, "\t\tchar unused;\n") // avoid empty struct
}
@@ -334,19 +329,18 @@ 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" || name == "_CMalloc"
+ inProlog := builtinDefs[name] != ""
+ cname := fmt.Sprintf("_cgo%s%s", cPrefix, n.Mangle)
+ paramnames := []string(nil)
+ for i, param := range d.Type.Params.List {
+ paramName := fmt.Sprintf("p%d", i)
+ param.Names = []*ast.Ident{ast.NewIdent(paramName)}
+ paramnames = append(paramnames, paramName)
+ }
if *gccgo {
// Gccgo style hooks.
fmt.Fprint(fgo2, "\n")
- cname := fmt.Sprintf("_cgo%s%s", cPrefix, n.Mangle)
- paramnames := []string(nil)
- for i, param := range d.Type.Params.List {
- paramName := fmt.Sprintf("p%d", i)
- param.Names = []*ast.Ident{ast.NewIdent(paramName)}
- paramnames = append(paramnames, paramName)
- }
-
conf.Fprint(fgo2, fset, d)
fmt.Fprint(fgo2, " {\n")
if !inProlog {
@@ -383,7 +377,7 @@ func (p *Package) writeDefsFunc(fc, fgo2 *os.File, n *Name) {
fmt.Fprint(fgo2, "}\n")
// declare the C function.
- fmt.Fprintf(fgo2, "//extern _cgo%s%s\n", cPrefix, n.Mangle)
+ fmt.Fprintf(fgo2, "//extern %s\n", cname)
d.Name = ast.NewIdent(cname)
if n.AddError {
l := d.Type.Results.List
@@ -394,61 +388,49 @@ func (p *Package) writeDefsFunc(fc, fgo2 *os.File, n *Name) {
return
}
- conf.Fprint(fgo2, fset, d)
- fmt.Fprint(fgo2, "\n")
if inProlog {
+ fmt.Fprint(fgo2, builtinDefs[name])
return
}
- var argSize int64
- _, argSize = p.structType(n)
-
// C wrapper calls into gcc, passing a pointer to the argument frame.
- fmt.Fprintf(fc, "#pragma cgo_import_static _cgo%s%s\n", cPrefix, n.Mangle)
- fmt.Fprintf(fc, "void _cgo%s%s(void*);\n", cPrefix, n.Mangle)
- fmt.Fprintf(fc, "\n")
- fmt.Fprintf(fc, "void\n")
- if argSize == 0 {
- argSize++
+ fmt.Fprintf(fc, "#pragma cgo_import_static %s\n", cname)
+ fmt.Fprintf(fc, "void %s(void*);\n", cname)
+ fmt.Fprintf(fc, "void *·%s = %s;\n", cname, cname)
+
+ nret := 0
+ if !void {
+ d.Type.Results.List[0].Names = []*ast.Ident{ast.NewIdent("r1")}
+ nret = 1
}
- // 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.AddError {
+ d.Type.Results.List[nret].Names = []*ast.Ident{ast.NewIdent("r2")}
}
- if n := argSize % p.PtrSize; n > 0 {
- fmt.Fprintf(fc, "uint8 x[%d];", n)
+
+ fmt.Fprint(fgo2, "\n")
+ fmt.Fprintf(fgo2, "var %s unsafe.Pointer\n", cname)
+ conf.Fprint(fgo2, fset, d)
+ fmt.Fprint(fgo2, " {\n")
+
+ // NOTE: Using uintptr to hide from escape analysis.
+ arg := "0"
+ if len(paramnames) > 0 {
+ arg = "uintptr(unsafe.Pointer(&p0))"
+ } else if !void {
+ arg = "uintptr(unsafe.Pointer(&r1))"
}
- fmt.Fprintf(fc, "}p)\n")
- fmt.Fprintf(fc, "{\n")
- fmt.Fprintf(fc, "\truntime·cgocall(_cgo%s%s, &p);\n", cPrefix, n.Mangle)
+
+ prefix := ""
if n.AddError {
- // gcc leaves errno in first word of interface at end of p.
- // check whether it is zero; if so, turn interface into nil.
- // if not, turn interface into errno.
- // Go init function initializes ·_Cerrno with an os.Errno
- // for us to copy.
- fmt.Fprintln(fc, ` {
- int32 e;
- void **v;
- v = (void**)(&p+1) - 2; /* v = final two void* of p */
- e = *(int32*)v;
- v[0] = (void*)0xdeadbeef;
- v[1] = (void*)0xdeadbeef;
- if(e == 0) {
- /* nil interface */
- v[0] = 0;
- v[1] = 0;
- } else {
- ·_Cerrno(v, e); /* fill in v as error for errno e */
- }
- }`)
+ prefix = "errno := "
}
- fmt.Fprintf(fc, "}\n")
- fmt.Fprintf(fc, "\n")
+ fmt.Fprintf(fgo2, "\t%s_cgo_runtime_cgocall_errno(%s, %s)\n", prefix, cname, arg)
+ if n.AddError {
+ fmt.Fprintf(fgo2, "\tif errno != 0 { r2 = syscall.Errno(errno) }\n")
+ }
+ fmt.Fprintf(fgo2, "\treturn\n")
+ fmt.Fprintf(fgo2, "}\n")
}
// writeOutput creates stubs for a specific source file to be compiled by 6g
@@ -521,7 +503,11 @@ func (p *Package) writeOutputFunc(fgcc *os.File, n *Name) {
// Gcc wrapper unpacks the C argument struct
// and calls the actual C function.
- fmt.Fprintf(fgcc, "void\n")
+ if n.AddError {
+ fmt.Fprintf(fgcc, "int\n")
+ } else {
+ fmt.Fprintf(fgcc, "void\n")
+ }
fmt.Fprintf(fgcc, "_cgo%s%s(void *v)\n", cPrefix, n.Mangle)
fmt.Fprintf(fgcc, "{\n")
if n.AddError {
@@ -557,7 +543,7 @@ func (p *Package) writeOutputFunc(fgcc *os.File, n *Name) {
}
fmt.Fprintf(fgcc, ");\n")
if n.AddError {
- fmt.Fprintf(fgcc, "\t*(int*)(a->e) = errno;\n")
+ fmt.Fprintf(fgcc, "\treturn errno;\n")
}
fmt.Fprintf(fgcc, "}\n")
fmt.Fprintf(fgcc, "\n")
@@ -1166,46 +1152,74 @@ const cProlog = `
#include "runtime.h"
#include "cgocall.h"
+static void *cgocall_errno = runtime·cgocall_errno;
+void *·_cgo_runtime_cgocall_errno = &cgocall_errno;
+
+static void *runtime_gostring = runtime·gostring;
+void *·_cgo_runtime_gostring = &runtime_gostring;
+
+static void *runtime_gostringn = runtime·gostringn;
+void *·_cgo_runtime_gostringn = &runtime_gostringn;
+
+static void *runtime_gobytes = runtime·gobytes;
+void *·_cgo_runtime_gobytes = &runtime_gobytes;
+
+static void *runtime_cmalloc = runtime·cmalloc;
+void *·_cgo_runtime_cmalloc = &runtime_cmalloc;
+
void ·_Cerrno(void*, int32);
+`
-void
-·_Cfunc_GoString(int8 *p, String s)
-{
- s = runtime·gostring((byte*)p);
- FLUSH(&s);
+const goProlog = `
+var _cgo_runtime_cgocall_errno func(unsafe.Pointer, uintptr) int32
+var _cgo_runtime_cmalloc func(uintptr) unsafe.Pointer
+`
+
+const goStringDef = `
+var _cgo_runtime_gostring func(*_Ctype_char) string
+func _Cfunc_GoString(p *_Ctype_char) string {
+ return _cgo_runtime_gostring(p)
}
+`
-void
-·_Cfunc_GoStringN(int8 *p, int32 l, String s)
-{
- s = runtime·gostringn((byte*)p, l);
- FLUSH(&s);
+const goStringNDef = `
+var _cgo_runtime_gostringn func(*_Ctype_char, int) string
+func _Cfunc_GoStringN(p *_Ctype_char, l _Ctype_int) string {
+ return _cgo_runtime_gostringn(p, int(l))
}
+`
-void
-·_Cfunc_GoBytes(int8 *p, int32 l, Slice s)
-{
- s = runtime·gobytes((byte*)p, l);
- FLUSH(&s);
+const goBytesDef = `
+var _cgo_runtime_gobytes func(unsafe.Pointer, int) []byte
+func _Cfunc_GoBytes(p unsafe.Pointer, l _Ctype_int) []byte {
+ return _cgo_runtime_gobytes(p, int(l))
}
+`
-void
-·_Cfunc_CString(String s, int8 *p)
-{
- p = runtime·cmalloc(s.len+1);
- runtime·memmove((byte*)p, s.str, s.len);
- p[s.len] = 0;
- FLUSH(&p);
+const cStringDef = `
+func _Cfunc_CString(s string) *_Ctype_char {
+ p := _cgo_runtime_cmalloc(uintptr(len(s)+1))
+ pp := (*[1<<30]byte)(p)
+ copy(pp[:], s)
+ pp[len(s)] = 0
+ return (*_Ctype_char)(p)
}
+`
-void
-·_Cfunc__CMalloc(uintptr n, int8 *p)
-{
- p = runtime·cmalloc(n);
- FLUSH(&p);
+const cMallocDef = `
+func _Cfunc__CMalloc(n _Ctype_size_t) unsafe.Pointer {
+ return _cgo_runtime_cmalloc(uintptr(n))
}
`
+var builtinDefs = map[string]string{
+ "GoString": goStringDef,
+ "GoStringN": goStringNDef,
+ "GoBytes": goBytesDef,
+ "CString": cStringDef,
+ "_CMalloc": cMallocDef,
+}
+
func (p *Package) cPrologGccgo() string {
return strings.Replace(cPrologGccgo, "PREFIX", cPrefix, -1)
}