From 72ee5bad9f9bd8979e14fab02fb07e39c5e9fd8c Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Fri, 2 Oct 2020 16:03:37 -0700 Subject: cmd/cgo: split gofrontend mangling checks into cmd/internal/pkgpath This is a step toward porting https://golang.org/cl/219817 from the gofrontend repo to the main repo. Note that this also corrects the implementation of the v2 mangling scheme to use ..u and ..U where appropriate. For #37272 Change-Id: I64a1e7ca1c84348efcbf1cf62049eeb05c830ed8 Reviewed-on: https://go-review.googlesource.com/c/go/+/259298 Trust: Ian Lance Taylor Run-TryBot: Ian Lance Taylor TryBot-Result: Go Bot Reviewed-by: Than McIntosh --- src/cmd/cgo/main.go | 3 +- src/cmd/cgo/out.go | 118 +++++++--------------------------------------------- 2 files changed, 16 insertions(+), 105 deletions(-) (limited to 'src/cmd/cgo') diff --git a/src/cmd/cgo/main.go b/src/cmd/cgo/main.go index ef3ed968e4..5c44fb72f4 100644 --- a/src/cmd/cgo/main.go +++ b/src/cmd/cgo/main.go @@ -224,8 +224,7 @@ var exportHeader = flag.String("exportheader", "", "where to write export header var gccgo = flag.Bool("gccgo", false, "generate files for use with gccgo") var gccgoprefix = flag.String("gccgoprefix", "", "-fgo-prefix option used with gccgo") var gccgopkgpath = flag.String("gccgopkgpath", "", "-fgo-pkgpath option used with gccgo") -var gccgoMangleCheckDone bool -var gccgoNewmanglingInEffect bool +var gccgoMangler func(string) string var importRuntimeCgo = flag.Bool("import_runtime_cgo", true, "import runtime/cgo in generated code") var importSyscall = flag.Bool("import_syscall", true, "import syscall in generated code") var goarch, goos string diff --git a/src/cmd/cgo/out.go b/src/cmd/cgo/out.go index 03b8333b10..b447b07645 100644 --- a/src/cmd/cgo/out.go +++ b/src/cmd/cgo/out.go @@ -6,6 +6,7 @@ package main import ( "bytes" + "cmd/internal/pkgpath" "debug/elf" "debug/macho" "debug/pe" @@ -15,7 +16,6 @@ import ( "go/token" "internal/xcoff" "io" - "io/ioutil" "os" "os/exec" "path/filepath" @@ -1282,112 +1282,24 @@ func (p *Package) writeExportHeader(fgcch io.Writer) { fmt.Fprintf(fgcch, "%s\n", p.gccExportHeaderProlog()) } -// gccgoUsesNewMangling reports whether gccgo uses the new collision-free -// packagepath mangling scheme (see determineGccgoManglingScheme for more -// info). -func gccgoUsesNewMangling() bool { - if !gccgoMangleCheckDone { - gccgoNewmanglingInEffect = determineGccgoManglingScheme() - gccgoMangleCheckDone = true - } - return gccgoNewmanglingInEffect -} - -const mangleCheckCode = ` -package läufer -func Run(x int) int { - return 1 -} -` - -// determineGccgoManglingScheme performs a runtime test to see which -// flavor of packagepath mangling gccgo is using. Older versions of -// gccgo use a simple mangling scheme where there can be collisions -// between packages whose paths are different but mangle to the same -// string. More recent versions of gccgo use a new mangler that avoids -// these collisions. Return value is whether gccgo uses the new mangling. -func determineGccgoManglingScheme() bool { - - // Emit a small Go file for gccgo to compile. - filepat := "*_gccgo_manglecheck.go" - var f *os.File - var err error - if f, err = ioutil.TempFile(*objDir, filepat); err != nil { - fatalf("%v", err) - } - gofilename := f.Name() - defer os.Remove(gofilename) - - if err = ioutil.WriteFile(gofilename, []byte(mangleCheckCode), 0666); err != nil { - fatalf("%v", err) - } - - // Compile with gccgo, capturing generated assembly. - gccgocmd := os.Getenv("GCCGO") - if gccgocmd == "" { - gpath, gerr := exec.LookPath("gccgo") - if gerr != nil { - fatalf("unable to locate gccgo: %v", gerr) - } - gccgocmd = gpath - } - cmd := exec.Command(gccgocmd, "-S", "-o", "-", gofilename) - buf, cerr := cmd.CombinedOutput() - if cerr != nil { - fatalf("%s", cerr) - } - - // New mangling: expect go.l..u00e4ufer.Run - // Old mangling: expect go.l__ufer.Run - return regexp.MustCompile(`go\.l\.\.u00e4ufer\.Run`).Match(buf) -} - -// gccgoPkgpathToSymbolNew converts a package path to a gccgo-style -// package symbol. -func gccgoPkgpathToSymbolNew(ppath string) string { - bsl := []byte{} - changed := false - for _, c := range []byte(ppath) { - switch { - case 'A' <= c && c <= 'Z', 'a' <= c && c <= 'z', - '0' <= c && c <= '9', c == '_': - bsl = append(bsl, c) - case c == '.': - bsl = append(bsl, ".x2e"...) - default: - changed = true - encbytes := []byte(fmt.Sprintf("..z%02x", c)) - bsl = append(bsl, encbytes...) - } - } - if !changed { - return ppath - } - return string(bsl) -} - -// gccgoPkgpathToSymbolOld converts a package path to a gccgo-style -// package symbol using the older mangling scheme. -func gccgoPkgpathToSymbolOld(ppath string) string { - clean := func(r rune) rune { - switch { - case 'A' <= r && r <= 'Z', 'a' <= r && r <= 'z', - '0' <= r && r <= '9': - return r - } - return '_' - } - return strings.Map(clean, ppath) -} - // gccgoPkgpathToSymbol converts a package path to a mangled packagepath // symbol. func gccgoPkgpathToSymbol(ppath string) string { - if gccgoUsesNewMangling() { - return gccgoPkgpathToSymbolNew(ppath) - } else { - return gccgoPkgpathToSymbolOld(ppath) + if gccgoMangler == nil { + var err error + cmd := os.Getenv("GCCGO") + if cmd == "" { + cmd, err = exec.LookPath("gccgo") + if err != nil { + fatalf("unable to locate gccgo: %v", err) + } + } + gccgoMangler, err = pkgpath.ToSymbolFunc(cmd, *objDir) + if err != nil { + fatalf("%v", err) + } } + return gccgoMangler(ppath) } // Return the package prefix when using gccgo. -- cgit v1.2.1 From 5d1378143bc07791296abb420df35537ad80492f Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Wed, 7 Oct 2020 16:37:05 -0700 Subject: cmd/cgo: add more architectures to size maps This brings over the architectures that the gofrontend knows about. This permits using the main cgo tool for those architectures, as cgo can be used with -godefs without gc support. This will help add golang.org/x/sys/unix support for other architectures. For #37443 Change-Id: I63632b9c5139e71b9ccab8edcc7acdb464229b74 Reviewed-on: https://go-review.googlesource.com/c/go/+/260657 Trust: Ian Lance Taylor Run-TryBot: Ian Lance Taylor TryBot-Result: Go Bot Reviewed-by: Than McIntosh --- src/cmd/cgo/main.go | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'src/cmd/cgo') diff --git a/src/cmd/cgo/main.go b/src/cmd/cgo/main.go index 5c44fb72f4..7d02ac3c54 100644 --- a/src/cmd/cgo/main.go +++ b/src/cmd/cgo/main.go @@ -170,35 +170,51 @@ func usage() { var ptrSizeMap = map[string]int64{ "386": 4, + "alpha": 8, "amd64": 8, "arm": 4, "arm64": 8, + "m68k": 4, "mips": 4, "mipsle": 4, "mips64": 8, "mips64le": 8, + "nios2": 4, + "ppc": 4, "ppc64": 8, "ppc64le": 8, + "riscv": 4, "riscv64": 8, "s390": 4, "s390x": 8, + "sh": 4, + "shbe": 4, + "sparc": 4, "sparc64": 8, } var intSizeMap = map[string]int64{ "386": 4, + "alpha": 8, "amd64": 8, "arm": 4, "arm64": 8, + "m68k": 4, "mips": 4, "mipsle": 4, "mips64": 8, "mips64le": 8, + "nios2": 4, + "ppc": 4, "ppc64": 8, "ppc64le": 8, + "riscv": 4, "riscv64": 8, "s390": 4, "s390x": 8, + "sh": 4, + "shbe": 4, + "sparc": 4, "sparc64": 8, } -- cgit v1.2.1 From 6f7b553c82b69b47becbe36d9115971d30fdab48 Mon Sep 17 00:00:00 2001 From: Quim Muntal Date: Thu, 15 Oct 2020 23:12:49 +0200 Subject: cmd/cgo: avoid exporting all symbols on windows buildmode=c-shared Disable default symbol auto-export behaviour by marking exported function with the __declspec(dllexport) attribute. Old behaviour can still be used by setting -extldflags=-Wl,--export-all-symbols. See https://sourceware.org/binutils/docs/ld/WIN32.html for more info. This change cuts 50kb of a "hello world" dll. Updates #6853 Fixes #30674 Change-Id: I9c7fb09c677cc760f24d0f7d199740ae73981413 Reviewed-on: https://go-review.googlesource.com/c/go/+/262797 Run-TryBot: Ian Lance Taylor TryBot-Result: Go Bot Reviewed-by: Ian Lance Taylor Reviewed-by: Alex Brainman Trust: Alex Brainman --- src/cmd/cgo/out.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'src/cmd/cgo') diff --git a/src/cmd/cgo/out.go b/src/cmd/cgo/out.go index b447b07645..82316a300b 100644 --- a/src/cmd/cgo/out.go +++ b/src/cmd/cgo/out.go @@ -939,7 +939,11 @@ func (p *Package) writeExports(fgo2, fm, fgcc, fgcch io.Writer) { } // Build the wrapper function compiled by gcc. - s := fmt.Sprintf("%s %s(", gccResult, exp.ExpName) + gccExport := "" + if goos == "windows" { + gccExport = "__declspec(dllexport)" + } + s := fmt.Sprintf("%s %s %s(", gccExport, gccResult, exp.ExpName) if fn.Recv != nil { s += p.cgoType(fn.Recv.List[0].Type).C.String() s += " recv" -- cgit v1.2.1 From 30c18878730434027dbefd343aad74963a1fdc48 Mon Sep 17 00:00:00 2001 From: Austin Clements Date: Thu, 1 Oct 2020 17:22:38 -0400 Subject: runtime,cmd/cgo: simplify C -> Go call path This redesigns the way calls work from C to exported Go functions. It removes several steps from the call path, makes cmd/cgo no longer sensitive to the Go calling convention, and eliminates the use of reflectcall from cgo. In order to avoid generating a large amount of FFI glue between the C and Go ABIs, the cgo tool has long depended on generating a C function that marshals the arguments into a struct, and then the actual ABI switch happens in functions with fixed signatures that simply take a pointer to this struct. In a way, this CL simply pushes this idea further. Currently, the cgo tool generates this argument struct in the exact layout of the Go stack frame and depends on reflectcall to unpack it into the appropriate Go call (even though it's actually reflectcall'ing a function generated by cgo). In this CL, we decouple this struct from the Go stack layout. Instead, cgo generates a Go function that takes the struct, unpacks it, and calls the exported function. Since this generated function has a generic signature (like the rest of the call path), we don't need reflectcall and can instead depend on the Go compiler itself to implement the call to the exported Go function. One complication is that syscall.NewCallback on Windows, which converts a Go function into a C function pointer, depends on cgocallback's current dynamic calling approach since the signatures of the callbacks aren't known statically. For this specific case, we continue to depend on reflectcall. Really, the current approach makes some overly simplistic assumptions about translating the C ABI to the Go ABI. Now we're at least in a much better position to do a proper ABI translation. For comparison, the current cgo call path looks like: GoF (generated C function) -> crosscall2 (in cgo/asm_*.s) -> _cgoexp_GoF (generated Go function) -> cgocallback (in asm_*.s) -> cgocallback_gofunc (in asm_*.s) -> cgocallbackg (in cgocall.go) -> cgocallbackg1 (in cgocall.go) -> reflectcall (in asm_*.s) -> _cgoexpwrap_GoF (generated Go function) -> p.GoF Now the call path looks like: GoF (generated C function) -> crosscall2 (in cgo/asm_*.s) -> cgocallback (in asm_*.s) -> cgocallbackg (in cgocall.go) -> cgocallbackg1 (in cgocall.go) -> _cgoexp_GoF (generated Go function) -> p.GoF Notably: 1. We combine _cgoexp_GoF and _cgoexpwrap_GoF and move the combined operation to the end of the sequence. This combined function also handles reflectcall's previous role. 2. We combined cgocallback and cgocallback_gofunc since the only purpose of having both was to convert a raw PC into a Go function value. We instead construct the Go function value in cgocallbackg1. 3. cgocallbackg1 no longer reaches backwards through the stack to get the arguments to cgocallback_gofunc. Instead, we just pass the arguments down. 4. Currently, we need an explicit msanwrite to mark the results struct as written because reflectcall doesn't do this. Now, the results are written by regular Go assignments, so the Go compiler generates the necessary MSAN annotations. This also means we no longer need to track the size of the arguments frame. Updates #40724, since now we don't need to teach cgo about the register ABI or change how it uses reflectcall. Change-Id: I7840489a2597962aeb670e0c1798a16a7359c94f Reviewed-on: https://go-review.googlesource.com/c/go/+/258938 Trust: Austin Clements Run-TryBot: Austin Clements TryBot-Result: Go Bot Reviewed-by: Cherry Zhang --- src/cmd/cgo/doc.go | 2 +- src/cmd/cgo/out.go | 162 ++++++++++++++++++----------------------------------- 2 files changed, 55 insertions(+), 109 deletions(-) (limited to 'src/cmd/cgo') diff --git a/src/cmd/cgo/doc.go b/src/cmd/cgo/doc.go index b3f371b08c..e782c866ac 100644 --- a/src/cmd/cgo/doc.go +++ b/src/cmd/cgo/doc.go @@ -721,7 +721,7 @@ linkage to the desired libraries. The main function is provided by _cgo_main.c: int main() { return 0; } - void crosscall2(void(*fn)(void*, int, uintptr_t), void *a, int c, uintptr_t ctxt) { } + void crosscall2(void(*fn)(void*), void *a, int c, uintptr_t ctxt) { } uintptr_t _cgo_wait_runtime_init_done(void) { return 0; } void _cgo_release_context(uintptr_t ctxt) { } char* _cgo_topofstack(void) { return (char*)0; } diff --git a/src/cmd/cgo/out.go b/src/cmd/cgo/out.go index 82316a300b..eef54f2d0f 100644 --- a/src/cmd/cgo/out.go +++ b/src/cmd/cgo/out.go @@ -59,14 +59,14 @@ func (p *Package) writeDefs() { // Write C main file for using gcc to resolve imports. fmt.Fprintf(fm, "int main() { return 0; }\n") if *importRuntimeCgo { - fmt.Fprintf(fm, "void crosscall2(void(*fn)(void*, int, __SIZE_TYPE__), void *a, int c, __SIZE_TYPE__ ctxt) { }\n") + fmt.Fprintf(fm, "void crosscall2(void(*fn)(void*), void *a, int c, __SIZE_TYPE__ ctxt) { }\n") fmt.Fprintf(fm, "__SIZE_TYPE__ _cgo_wait_runtime_init_done(void) { return 0; }\n") fmt.Fprintf(fm, "void _cgo_release_context(__SIZE_TYPE__ ctxt) { }\n") fmt.Fprintf(fm, "char* _cgo_topofstack(void) { return (char*)0; }\n") } else { // If we're not importing runtime/cgo, we *are* runtime/cgo, // which provides these functions. We just need a prototype. - fmt.Fprintf(fm, "void crosscall2(void(*fn)(void*, int, __SIZE_TYPE__), void *a, int c, __SIZE_TYPE__ ctxt);\n") + fmt.Fprintf(fm, "void crosscall2(void(*fn)(void*), void *a, int c, __SIZE_TYPE__ ctxt);\n") fmt.Fprintf(fm, "__SIZE_TYPE__ _cgo_wait_runtime_init_done(void);\n") fmt.Fprintf(fm, "void _cgo_release_context(__SIZE_TYPE__);\n") } @@ -852,7 +852,7 @@ func (p *Package) writeExports(fgo2, fm, fgcc, fgcch io.Writer) { fmt.Fprintf(fgcc, "#pragma GCC diagnostic ignored \"-Wpragmas\"\n") fmt.Fprintf(fgcc, "#pragma GCC diagnostic ignored \"-Waddress-of-packed-member\"\n") - fmt.Fprintf(fgcc, "extern void crosscall2(void (*fn)(void *, int, __SIZE_TYPE__), void *, int, __SIZE_TYPE__);\n") + fmt.Fprintf(fgcc, "extern void crosscall2(void (*fn)(void *), void *, int, __SIZE_TYPE__);\n") fmt.Fprintf(fgcc, "extern __SIZE_TYPE__ _cgo_wait_runtime_init_done(void);\n") fmt.Fprintf(fgcc, "extern void _cgo_release_context(__SIZE_TYPE__);\n\n") fmt.Fprintf(fgcc, "extern char* _cgo_topofstack(void);") @@ -862,59 +862,48 @@ func (p *Package) writeExports(fgo2, fm, fgcc, fgcch io.Writer) { for _, exp := range p.ExpFunc { fn := exp.Func - // Construct a gcc struct matching the gc argument and - // result frame. The gcc struct will be compiled with - // __attribute__((packed)) so all padding must be accounted - // for explicitly. + // Construct a struct that will be used to communicate + // arguments from C to Go. The C and Go definitions + // just have to agree. The gcc struct will be compiled + // with __attribute__((packed)) so all padding must be + // accounted for explicitly. ctype := "struct {\n" + gotype := new(bytes.Buffer) + fmt.Fprintf(gotype, "struct {\n") off := int64(0) npad := 0 - if fn.Recv != nil { - t := p.cgoType(fn.Recv.List[0].Type) - ctype += fmt.Sprintf("\t\t%s recv;\n", t.C) + argField := func(typ ast.Expr, namePat string, args ...interface{}) { + name := fmt.Sprintf(namePat, args...) + t := p.cgoType(typ) + if off%t.Align != 0 { + pad := t.Align - off%t.Align + ctype += fmt.Sprintf("\t\tchar __pad%d[%d];\n", npad, pad) + off += pad + npad++ + } + ctype += fmt.Sprintf("\t\t%s %s;\n", t.C, name) + fmt.Fprintf(gotype, "\t\t%s ", name) + noSourceConf.Fprint(gotype, fset, typ) + fmt.Fprintf(gotype, "\n") off += t.Size } + if fn.Recv != nil { + argField(fn.Recv.List[0].Type, "recv") + } fntype := fn.Type forFieldList(fntype.Params, func(i int, aname string, atype ast.Expr) { - t := p.cgoType(atype) - if off%t.Align != 0 { - pad := t.Align - off%t.Align - ctype += fmt.Sprintf("\t\tchar __pad%d[%d];\n", npad, pad) - off += pad - npad++ - } - ctype += fmt.Sprintf("\t\t%s p%d;\n", t.C, i) - off += t.Size + argField(atype, "p%d", i) }) - if off%p.PtrSize != 0 { - pad := p.PtrSize - off%p.PtrSize - ctype += fmt.Sprintf("\t\tchar __pad%d[%d];\n", npad, pad) - off += pad - npad++ - } forFieldList(fntype.Results, func(i int, aname string, atype ast.Expr) { - t := p.cgoType(atype) - if off%t.Align != 0 { - pad := t.Align - off%t.Align - ctype += fmt.Sprintf("\t\tchar __pad%d[%d];\n", npad, pad) - off += pad - npad++ - } - ctype += fmt.Sprintf("\t\t%s r%d;\n", t.C, i) - off += t.Size + argField(atype, "r%d", i) }) - if off%p.PtrSize != 0 { - pad := p.PtrSize - off%p.PtrSize - ctype += fmt.Sprintf("\t\tchar __pad%d[%d];\n", npad, pad) - off += pad - npad++ - } if ctype == "struct {\n" { ctype += "\t\tchar unused;\n" // avoid empty struct } ctype += "\t}" + fmt.Fprintf(gotype, "\t}") // Get the return type of the wrapper function // compiled by gcc. @@ -965,12 +954,15 @@ func (p *Package) writeExports(fgo2, fm, fgcc, fgcch io.Writer) { } fmt.Fprintf(fgcch, "extern %s;\n", s) - fmt.Fprintf(fgcc, "extern void _cgoexp%s_%s(void *, int, __SIZE_TYPE__);\n", cPrefix, exp.ExpName) + fmt.Fprintf(fgcc, "extern void _cgoexp%s_%s(void *);\n", cPrefix, exp.ExpName) fmt.Fprintf(fgcc, "\nCGO_NO_SANITIZE_THREAD") fmt.Fprintf(fgcc, "\n%s\n", s) fmt.Fprintf(fgcc, "{\n") fmt.Fprintf(fgcc, "\t__SIZE_TYPE__ _cgo_ctxt = _cgo_wait_runtime_init_done();\n") - fmt.Fprintf(fgcc, "\t%s %v _cgo_a;\n", ctype, p.packedAttribute()) + // The results part of the argument structure must be + // initialized to 0 so the write barriers generated by + // the assignments to these fields in Go are safe. + fmt.Fprintf(fgcc, "\t%s %v _cgo_a = {0};\n", ctype, p.packedAttribute()) if gccResult != "void" && (len(fntype.Results.List) > 1 || len(fntype.Results.List[0].Names) > 1) { fmt.Fprintf(fgcc, "\t%s r;\n", gccResult) } @@ -999,82 +991,28 @@ func (p *Package) writeExports(fgo2, fm, fgcc, fgcch io.Writer) { fmt.Fprintf(fgcc, "}\n") // Build the wrapper function compiled by cmd/compile. - goname := "_cgoexpwrap" + cPrefix + "_" - if fn.Recv != nil { - goname += fn.Recv.List[0].Names[0].Name + "_" - } - goname += exp.Func.Name.Name + // This unpacks the argument struct above and calls the Go function. fmt.Fprintf(fgo2, "//go:cgo_export_dynamic %s\n", exp.ExpName) fmt.Fprintf(fgo2, "//go:linkname _cgoexp%s_%s _cgoexp%s_%s\n", cPrefix, exp.ExpName, cPrefix, exp.ExpName) fmt.Fprintf(fgo2, "//go:cgo_export_static _cgoexp%s_%s\n", cPrefix, exp.ExpName) - fmt.Fprintf(fgo2, "//go:nosplit\n") // no split stack, so no use of m or g - fmt.Fprintf(fgo2, "//go:norace\n") // must not have race detector calls inserted - fmt.Fprintf(fgo2, "func _cgoexp%s_%s(a unsafe.Pointer, n int32, ctxt uintptr) {\n", cPrefix, exp.ExpName) - fmt.Fprintf(fgo2, "\tfn := %s\n", goname) - // The indirect here is converting from a Go function pointer to a C function pointer. - fmt.Fprintf(fgo2, "\t_cgo_runtime_cgocallback(**(**unsafe.Pointer)(unsafe.Pointer(&fn)), a, uintptr(n), ctxt);\n") - fmt.Fprintf(fgo2, "}\n") + fmt.Fprintf(fgo2, "func _cgoexp%s_%s(a *%s) {\n", cPrefix, exp.ExpName, gotype) fmt.Fprintf(fm, "int _cgoexp%s_%s;\n", cPrefix, exp.ExpName) - // This code uses printer.Fprint, not conf.Fprint, - // because we don't want //line comments in the middle - // of the function types. - fmt.Fprintf(fgo2, "\n") - fmt.Fprintf(fgo2, "func %s(", goname) - comma := false - if fn.Recv != nil { - fmt.Fprintf(fgo2, "recv ") - printer.Fprint(fgo2, fset, fn.Recv.List[0].Type) - comma = true - } - forFieldList(fntype.Params, - func(i int, aname string, atype ast.Expr) { - if comma { - fmt.Fprintf(fgo2, ", ") - } - fmt.Fprintf(fgo2, "p%d ", i) - printer.Fprint(fgo2, fset, atype) - comma = true - }) - fmt.Fprintf(fgo2, ")") if gccResult != "void" { - fmt.Fprint(fgo2, " (") + // Write results back to frame. + fmt.Fprintf(fgo2, "\t") forFieldList(fntype.Results, func(i int, aname string, atype ast.Expr) { if i > 0 { - fmt.Fprint(fgo2, ", ") + fmt.Fprintf(fgo2, ", ") } - fmt.Fprintf(fgo2, "r%d ", i) - printer.Fprint(fgo2, fset, atype) + fmt.Fprintf(fgo2, "a.r%d", i) }) - fmt.Fprint(fgo2, ")") - } - fmt.Fprint(fgo2, " {\n") - if gccResult == "void" { - fmt.Fprint(fgo2, "\t") - } else { - // Verify that any results don't contain any - // Go pointers. - addedDefer := false - forFieldList(fntype.Results, - func(i int, aname string, atype ast.Expr) { - if !p.hasPointer(nil, atype, false) { - return - } - if !addedDefer { - fmt.Fprint(fgo2, "\tdefer func() {\n") - addedDefer = true - } - fmt.Fprintf(fgo2, "\t\t_cgoCheckResult(r%d)\n", i) - }) - if addedDefer { - fmt.Fprint(fgo2, "\t}()\n") - } - fmt.Fprint(fgo2, "\treturn ") + fmt.Fprintf(fgo2, " = ") } if fn.Recv != nil { - fmt.Fprintf(fgo2, "recv.") + fmt.Fprintf(fgo2, "a.recv.") } fmt.Fprintf(fgo2, "%s(", exp.Func.Name) forFieldList(fntype.Params, @@ -1082,9 +1020,20 @@ func (p *Package) writeExports(fgo2, fm, fgcc, fgcch io.Writer) { if i > 0 { fmt.Fprint(fgo2, ", ") } - fmt.Fprintf(fgo2, "p%d", i) + fmt.Fprintf(fgo2, "a.p%d", i) }) fmt.Fprint(fgo2, ")\n") + if gccResult != "void" { + // Verify that any results don't contain any + // Go pointers. + forFieldList(fntype.Results, + func(i int, aname string, atype ast.Expr) { + if !p.hasPointer(nil, atype, false) { + return + } + fmt.Fprintf(fgo2, "\t_cgoCheckResult(a.r%d)\n", i) + }) + } fmt.Fprint(fgo2, "}\n") } @@ -1582,9 +1531,6 @@ const goProlog = ` //go:linkname _cgo_runtime_cgocall runtime.cgocall func _cgo_runtime_cgocall(unsafe.Pointer, uintptr) int32 -//go:linkname _cgo_runtime_cgocallback runtime.cgocallback -func _cgo_runtime_cgocallback(unsafe.Pointer, unsafe.Pointer, uintptr, uintptr) - //go:linkname _cgoCheckPointer runtime.cgoCheckPointer func _cgoCheckPointer(interface{}, interface{}) -- cgit v1.2.1