2016-03-01 22:57:46 +00:00
|
|
|
// Copyright 2009 The Go Authors. All rights reserved.
|
2009-09-24 11:43:19 -07:00
|
|
|
// Use of this source code is governed by a BSD-style
|
|
|
|
|
// license that can be found in the LICENSE file.
|
|
|
|
|
|
|
|
|
|
package main
|
|
|
|
|
|
|
|
|
|
import (
|
2010-07-14 17:17:53 -07:00
|
|
|
"bytes"
|
2020-10-02 16:03:37 -07:00
|
|
|
"cmd/internal/pkgpath"
|
2010-12-08 13:56:51 -05:00
|
|
|
"debug/elf"
|
|
|
|
|
"debug/macho"
|
2011-01-20 10:22:20 -05:00
|
|
|
"debug/pe"
|
2009-12-15 15:33:31 -08:00
|
|
|
"fmt"
|
|
|
|
|
"go/ast"
|
|
|
|
|
"go/printer"
|
2010-04-09 13:31:05 -07:00
|
|
|
"go/token"
|
2018-12-05 17:23:25 +01:00
|
|
|
"internal/xcoff"
|
2014-11-11 01:23:19 -05:00
|
|
|
"io"
|
2009-12-15 15:33:31 -08:00
|
|
|
"os"
|
2018-10-24 09:25:05 -04:00
|
|
|
"os/exec"
|
2017-11-10 15:46:56 -05:00
|
|
|
"path/filepath"
|
2018-04-19 12:56:29 -07:00
|
|
|
"regexp"
|
2012-07-05 15:24:33 -04:00
|
|
|
"sort"
|
2009-12-15 15:33:31 -08:00
|
|
|
"strings"
|
2020-03-10 00:22:01 +00:00
|
|
|
"unicode"
|
2009-09-24 11:43:19 -07:00
|
|
|
)
|
|
|
|
|
|
2016-09-24 17:03:30 +02:00
|
|
|
var (
|
|
|
|
|
conf = printer.Config{Mode: printer.SourcePos, Tabwidth: 8}
|
|
|
|
|
noSourceConf = printer.Config{Tabwidth: 8}
|
|
|
|
|
)
|
2012-02-10 13:27:32 -08:00
|
|
|
|
2015-06-24 09:50:12 +10:00
|
|
|
// writeDefs creates output files to be compiled by gc and gcc.
|
2010-07-14 17:17:53 -07:00
|
|
|
func (p *Package) writeDefs() {
|
2014-11-11 01:23:19 -05:00
|
|
|
var fgo2, fc io.Writer
|
|
|
|
|
f := creat(*objDir + "_cgo_gotypes.go")
|
|
|
|
|
defer f.Close()
|
|
|
|
|
fgo2 = f
|
|
|
|
|
if *gccgo {
|
|
|
|
|
f := creat(*objDir + "_cgo_defun.c")
|
|
|
|
|
defer f.Close()
|
|
|
|
|
fc = f
|
|
|
|
|
}
|
2011-12-14 22:42:42 -05:00
|
|
|
fm := creat(*objDir + "_cgo_main.c")
|
2010-12-17 11:37:11 -08:00
|
|
|
|
2012-11-01 11:21:30 -07:00
|
|
|
var gccgoInit bytes.Buffer
|
|
|
|
|
|
2011-12-14 22:42:42 -05:00
|
|
|
fflg := creat(*objDir + "_cgo_flags")
|
2011-02-01 08:44:18 -05:00
|
|
|
for k, v := range p.CgoFlags {
|
2013-03-06 16:57:14 -05:00
|
|
|
fmt.Fprintf(fflg, "_CGO_%s=%s\n", k, strings.Join(v, " "))
|
2013-07-17 18:02:21 -07:00
|
|
|
if k == "LDFLAGS" && !*gccgo {
|
2013-03-06 16:57:14 -05:00
|
|
|
for _, arg := range v {
|
2014-11-11 01:23:19 -05:00
|
|
|
fmt.Fprintf(fgo2, "//go:cgo_ldflag %q\n", arg)
|
2013-03-06 16:57:14 -05:00
|
|
|
}
|
|
|
|
|
}
|
2011-02-01 08:44:18 -05:00
|
|
|
}
|
|
|
|
|
fflg.Close()
|
|
|
|
|
|
2010-12-17 11:37:11 -08:00
|
|
|
// Write C main file for using gcc to resolve imports.
|
|
|
|
|
fmt.Fprintf(fm, "int main() { return 0; }\n")
|
2011-12-20 14:25:23 -05:00
|
|
|
if *importRuntimeCgo {
|
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 <austin@google.com>
Run-TryBot: Austin Clements <austin@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Cherry Zhang <cherryyz@google.com>
2020-10-01 17:22:38 -04:00
|
|
|
fmt.Fprintf(fm, "void crosscall2(void(*fn)(void*), void *a, int c, __SIZE_TYPE__ ctxt) { }\n")
|
2019-01-23 20:14:30 +00:00
|
|
|
fmt.Fprintf(fm, "__SIZE_TYPE__ _cgo_wait_runtime_init_done(void) { return 0; }\n")
|
2016-04-27 14:18:29 -07:00
|
|
|
fmt.Fprintf(fm, "void _cgo_release_context(__SIZE_TYPE__ ctxt) { }\n")
|
2014-09-25 08:37:04 -07:00
|
|
|
fmt.Fprintf(fm, "char* _cgo_topofstack(void) { return (char*)0; }\n")
|
2011-12-20 14:25:23 -05:00
|
|
|
} else {
|
|
|
|
|
// If we're not importing runtime/cgo, we *are* runtime/cgo,
|
2016-03-01 23:21:55 +00:00
|
|
|
// which provides these functions. We just need a prototype.
|
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 <austin@google.com>
Run-TryBot: Austin Clements <austin@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Cherry Zhang <cherryyz@google.com>
2020-10-01 17:22:38 -04:00
|
|
|
fmt.Fprintf(fm, "void crosscall2(void(*fn)(void*), void *a, int c, __SIZE_TYPE__ ctxt);\n")
|
2019-01-23 20:14:30 +00:00
|
|
|
fmt.Fprintf(fm, "__SIZE_TYPE__ _cgo_wait_runtime_init_done(void);\n")
|
2016-04-27 14:18:29 -07:00
|
|
|
fmt.Fprintf(fm, "void _cgo_release_context(__SIZE_TYPE__);\n")
|
2011-12-20 14:25:23 -05:00
|
|
|
}
|
2011-01-14 10:52:08 -08:00
|
|
|
fmt.Fprintf(fm, "void _cgo_allocate(void *a, int c) { }\n")
|
|
|
|
|
fmt.Fprintf(fm, "void _cgo_panic(void *a, int c) { }\n")
|
2014-12-16 18:34:55 -05:00
|
|
|
fmt.Fprintf(fm, "void _cgo_reginit(void) { }\n")
|
2009-09-30 11:51:08 -07:00
|
|
|
|
|
|
|
|
// Write second Go output: definitions of _C_xxx.
|
|
|
|
|
// In a separate file so that the import of "unsafe" does not
|
|
|
|
|
// pollute the original file.
|
2018-05-29 06:40:56 -07:00
|
|
|
fmt.Fprintf(fgo2, "// Code generated by cmd/cgo; DO NOT EDIT.\n\n")
|
2010-07-14 17:17:53 -07:00
|
|
|
fmt.Fprintf(fgo2, "package %s\n\n", p.PackageName)
|
2009-12-15 15:33:31 -08:00
|
|
|
fmt.Fprintf(fgo2, "import \"unsafe\"\n\n")
|
2011-12-20 14:25:23 -05:00
|
|
|
if !*gccgo && *importRuntimeCgo {
|
2011-12-14 15:40:35 -08:00
|
|
|
fmt.Fprintf(fgo2, "import _ \"runtime/cgo\"\n\n")
|
|
|
|
|
}
|
2012-09-18 23:42:18 +04:00
|
|
|
if *importSyscall {
|
2014-09-03 11:36:14 -04:00
|
|
|
fmt.Fprintf(fgo2, "import \"syscall\"\n\n")
|
|
|
|
|
fmt.Fprintf(fgo2, "var _ syscall.Errno\n")
|
2012-09-18 23:42:18 +04:00
|
|
|
}
|
2014-09-03 11:36:14 -04:00
|
|
|
fmt.Fprintf(fgo2, "func _Cgo_ptr(ptr unsafe.Pointer) unsafe.Pointer { return ptr }\n\n")
|
2009-09-24 11:43:19 -07:00
|
|
|
|
2015-06-07 22:14:04 -04:00
|
|
|
if !*gccgo {
|
|
|
|
|
fmt.Fprintf(fgo2, "//go:linkname _Cgo_always_false runtime.cgoAlwaysFalse\n")
|
|
|
|
|
fmt.Fprintf(fgo2, "var _Cgo_always_false bool\n")
|
|
|
|
|
fmt.Fprintf(fgo2, "//go:linkname _Cgo_use runtime.cgoUse\n")
|
|
|
|
|
fmt.Fprintf(fgo2, "func _Cgo_use(interface{})\n")
|
|
|
|
|
}
|
|
|
|
|
|
2012-07-05 15:24:33 -04:00
|
|
|
typedefNames := make([]string, 0, len(typedef))
|
|
|
|
|
for name := range typedef {
|
2020-06-26 11:26:33 -07:00
|
|
|
if name == "_Ctype_void" {
|
|
|
|
|
// We provide an appropriate declaration for
|
|
|
|
|
// _Ctype_void below (#39877).
|
|
|
|
|
continue
|
|
|
|
|
}
|
2012-07-05 15:24:33 -04:00
|
|
|
typedefNames = append(typedefNames, name)
|
|
|
|
|
}
|
|
|
|
|
sort.Strings(typedefNames)
|
|
|
|
|
for _, name := range typedefNames {
|
|
|
|
|
def := typedef[name]
|
2020-08-26 14:17:35 -07:00
|
|
|
if def.NotInHeap {
|
|
|
|
|
fmt.Fprintf(fgo2, "//go:notinheap\n")
|
|
|
|
|
}
|
2009-12-15 15:33:31 -08:00
|
|
|
fmt.Fprintf(fgo2, "type %s ", name)
|
2016-09-24 17:03:30 +02:00
|
|
|
// We don't have source info for these types, so write them out without source info.
|
|
|
|
|
// Otherwise types would look like:
|
|
|
|
|
//
|
|
|
|
|
// type _Ctype_struct_cb struct {
|
|
|
|
|
// //line :1
|
|
|
|
|
// on_test *[0]byte
|
|
|
|
|
// //line :1
|
|
|
|
|
// }
|
|
|
|
|
//
|
|
|
|
|
// Which is not useful. Moreover we never override source info,
|
|
|
|
|
// so subsequent source code uses the same source info.
|
|
|
|
|
// Moreover, empty file name makes compile emit no source debug info at all.
|
2017-09-09 21:38:51 -07:00
|
|
|
var buf bytes.Buffer
|
|
|
|
|
noSourceConf.Fprint(&buf, fset, def.Go)
|
cmd/cgo: fix mangling of enum and union types
Consider this test package:
package p
// enum E { E0 };
// union U { long x; };
// void f(enum E e, union U* up) {}
import "C"
func f() {
C.f(C.enum_E(C.E0), (*C.union_U)(nil))
}
In Go 1.14, cgo translated this to (omitting irrelevant details):
type _Ctype_union_U [8]byte
func f() {
_Cfunc_f(uint32(_Ciconst_E0), (*[8]byte)(nil))
}
func _Cfunc_f(p0 uint32, p1 *[8]byte) (r1 _Ctype_void) { ... }
Notably, _Ctype_union_U was declared as a defined type, but uses were
being rewritten into uses of the underlying type, which matched how
_Cfunc_f was declared.
After CL 230037, cgo started consistently rewriting "C.foo" type
expressions as "_Ctype_foo", which caused it to start emitting:
type _Ctype_enum_E uint32
type _Ctype_union_U [8]byte
func f() {
_Cfunc_f(_Ctype_enum_E(_Ciconst_E0), (*_Ctype_union_U)(nil))
}
// _Cfunc_f unchanged
Of course, this fails to type-check because _Ctype_enum_E and
_Ctype_union_U are defined types.
This CL changes cgo to emit:
type _Ctype_enum_E = uint32
type _Ctype_union_U = [8]byte
// f unchanged since CL 230037
// _Cfunc_f still unchanged
It would probably be better to fix this in (*typeConv).loadType so
that cgo generated code uses the _Ctype_foo aliases too. But as it
wouldn't have any effect on actual compilation, it's not worth the
risk of touching it at this point in the release cycle.
Updates #39537.
Fixes #40494.
Change-Id: I88269660b40aeda80a9a9433777601a781b48ac0
Reviewed-on: https://go-review.googlesource.com/c/go/+/246057
Reviewed-by: Ian Lance Taylor <iant@golang.org>
2020-07-30 18:35:00 -07:00
|
|
|
if bytes.HasPrefix(buf.Bytes(), []byte("_Ctype_")) ||
|
|
|
|
|
strings.HasPrefix(name, "_Ctype_enum_") ||
|
|
|
|
|
strings.HasPrefix(name, "_Ctype_union_") {
|
2017-09-09 21:38:51 -07:00
|
|
|
// This typedef is of the form `typedef a b` and should be an alias.
|
|
|
|
|
fmt.Fprintf(fgo2, "= ")
|
|
|
|
|
}
|
|
|
|
|
fmt.Fprintf(fgo2, "%s", buf.Bytes())
|
2011-11-10 19:08:04 -05:00
|
|
|
fmt.Fprintf(fgo2, "\n\n")
|
2009-09-24 11:43:19 -07:00
|
|
|
}
|
2013-01-09 15:25:46 -08:00
|
|
|
if *gccgo {
|
|
|
|
|
fmt.Fprintf(fgo2, "type _Ctype_void byte\n")
|
|
|
|
|
} else {
|
|
|
|
|
fmt.Fprintf(fgo2, "type _Ctype_void [0]byte\n")
|
|
|
|
|
}
|
2009-09-24 11:43:19 -07:00
|
|
|
|
2011-12-14 15:40:35 -08:00
|
|
|
if *gccgo {
|
2015-12-04 12:56:04 -08:00
|
|
|
fmt.Fprint(fgo2, gccgoGoProlog)
|
2014-09-03 11:36:14 -04:00
|
|
|
fmt.Fprint(fc, p.cPrologGccgo())
|
2011-12-14 15:40:35 -08:00
|
|
|
} else {
|
2014-09-03 11:36:14 -04:00
|
|
|
fmt.Fprint(fgo2, goProlog)
|
2011-12-14 15:40:35 -08:00
|
|
|
}
|
2009-09-24 11:43:19 -07:00
|
|
|
|
2016-11-02 19:41:01 -04:00
|
|
|
if fc != nil {
|
|
|
|
|
fmt.Fprintf(fc, "#line 1 \"cgo-generated-wrappers\"\n")
|
|
|
|
|
}
|
|
|
|
|
if fm != nil {
|
|
|
|
|
fmt.Fprintf(fm, "#line 1 \"cgo-generated-wrappers\"\n")
|
|
|
|
|
}
|
|
|
|
|
|
2012-11-01 11:21:30 -07:00
|
|
|
gccgoSymbolPrefix := p.gccgoSymbolPrefix()
|
|
|
|
|
|
2011-08-16 14:56:23 -04:00
|
|
|
cVars := make(map[string]bool)
|
2012-06-07 12:37:50 -04:00
|
|
|
for _, key := range nameKeys(p.Name) {
|
|
|
|
|
n := p.Name[key]
|
2013-08-13 12:42:21 -04:00
|
|
|
if !n.IsVar() {
|
2010-07-14 17:17:53 -07:00
|
|
|
continue
|
|
|
|
|
}
|
2010-12-08 13:56:51 -05:00
|
|
|
|
2011-08-16 14:56:23 -04:00
|
|
|
if !cVars[n.C] {
|
2014-11-11 01:23:19 -05:00
|
|
|
if *gccgo {
|
|
|
|
|
fmt.Fprintf(fc, "extern byte *%s;\n", n.C)
|
|
|
|
|
} else {
|
2015-06-28 23:04:05 -04:00
|
|
|
fmt.Fprintf(fm, "extern char %s[];\n", n.C)
|
|
|
|
|
fmt.Fprintf(fm, "void *_cgohack_%s = %s;\n\n", n.C, n.C)
|
2014-11-11 01:23:19 -05:00
|
|
|
fmt.Fprintf(fgo2, "//go:linkname __cgo_%s %s\n", n.C, n.C)
|
|
|
|
|
fmt.Fprintf(fgo2, "//go:cgo_import_static %s\n", n.C)
|
|
|
|
|
fmt.Fprintf(fgo2, "var __cgo_%s byte\n", n.C)
|
2013-07-17 18:02:21 -07:00
|
|
|
}
|
2011-08-16 14:56:23 -04:00
|
|
|
cVars[n.C] = true
|
|
|
|
|
}
|
2014-11-11 01:23:19 -05:00
|
|
|
|
2013-08-13 12:42:21 -04:00
|
|
|
var node ast.Node
|
|
|
|
|
if n.Kind == "var" {
|
|
|
|
|
node = &ast.StarExpr{X: n.Type.Go}
|
|
|
|
|
} else if n.Kind == "fpvar" {
|
|
|
|
|
node = n.Type.Go
|
|
|
|
|
} else {
|
|
|
|
|
panic(fmt.Errorf("invalid var kind %q", n.Kind))
|
|
|
|
|
}
|
2012-11-01 11:21:30 -07:00
|
|
|
if *gccgo {
|
2020-11-20 12:54:18 -08:00
|
|
|
fmt.Fprintf(fc, `extern void *%s __asm__("%s.%s");`, n.Mangle, gccgoSymbolPrefix, gccgoToSymbol(n.Mangle))
|
2014-11-11 01:23:19 -05:00
|
|
|
fmt.Fprintf(&gccgoInit, "\t%s = &%s;\n", n.Mangle, n.C)
|
|
|
|
|
fmt.Fprintf(fc, "\n")
|
2012-11-01 11:21:30 -07:00
|
|
|
}
|
2010-12-08 13:56:51 -05:00
|
|
|
|
2010-07-14 17:17:53 -07:00
|
|
|
fmt.Fprintf(fgo2, "var %s ", n.Mangle)
|
2013-08-13 12:42:21 -04:00
|
|
|
conf.Fprint(fgo2, fset, node)
|
2014-11-11 01:23:19 -05:00
|
|
|
if !*gccgo {
|
|
|
|
|
fmt.Fprintf(fgo2, " = (")
|
|
|
|
|
conf.Fprint(fgo2, fset, node)
|
|
|
|
|
fmt.Fprintf(fgo2, ")(unsafe.Pointer(&__cgo_%s))", n.C)
|
|
|
|
|
}
|
2009-12-15 15:33:31 -08:00
|
|
|
fmt.Fprintf(fgo2, "\n")
|
2009-09-24 11:43:19 -07:00
|
|
|
}
|
2014-11-11 01:23:19 -05:00
|
|
|
if *gccgo {
|
|
|
|
|
fmt.Fprintf(fc, "\n")
|
|
|
|
|
}
|
2009-09-24 11:43:19 -07:00
|
|
|
|
2012-06-07 12:37:50 -04:00
|
|
|
for _, key := range nameKeys(p.Name) {
|
|
|
|
|
n := p.Name[key]
|
2010-07-14 17:17:53 -07:00
|
|
|
if n.Const != "" {
|
2017-04-09 12:33:34 +09:00
|
|
|
fmt.Fprintf(fgo2, "const %s = %s\n", n.Mangle, n.Const)
|
2010-07-14 17:17:53 -07:00
|
|
|
}
|
2009-12-15 21:24:17 -08:00
|
|
|
}
|
|
|
|
|
fmt.Fprintf(fgo2, "\n")
|
|
|
|
|
|
2016-05-19 16:27:23 -07:00
|
|
|
callsMalloc := false
|
2012-06-07 12:37:50 -04:00
|
|
|
for _, key := range nameKeys(p.Name) {
|
|
|
|
|
n := p.Name[key]
|
2010-07-14 17:17:53 -07:00
|
|
|
if n.FuncType != nil {
|
2016-05-19 16:27:23 -07:00
|
|
|
p.writeDefsFunc(fgo2, n, &callsMalloc)
|
2009-12-15 15:33:31 -08:00
|
|
|
}
|
2010-07-14 17:17:53 -07:00
|
|
|
}
|
2009-09-24 11:43:19 -07:00
|
|
|
|
2015-05-06 17:53:17 -07:00
|
|
|
fgcc := creat(*objDir + "_cgo_export.c")
|
|
|
|
|
fgcch := creat(*objDir + "_cgo_export.h")
|
2012-03-15 23:50:25 +01:00
|
|
|
if *gccgo {
|
2015-05-06 17:53:17 -07:00
|
|
|
p.writeGccgoExports(fgo2, fm, fgcc, fgcch)
|
2012-03-15 23:50:25 +01:00
|
|
|
} else {
|
2015-05-06 17:53:17 -07:00
|
|
|
p.writeExports(fgo2, fm, fgcc, fgcch)
|
|
|
|
|
}
|
2016-05-19 16:27:23 -07:00
|
|
|
|
|
|
|
|
if callsMalloc && !*gccgo {
|
|
|
|
|
fmt.Fprint(fgo2, strings.Replace(cMallocDefGo, "PREFIX", cPrefix, -1))
|
|
|
|
|
fmt.Fprint(fgcc, strings.Replace(strings.Replace(cMallocDefC, "PREFIX", cPrefix, -1), "PACKED", p.packedAttribute(), -1))
|
|
|
|
|
}
|
|
|
|
|
|
2015-05-06 17:53:17 -07:00
|
|
|
if err := fgcc.Close(); err != nil {
|
|
|
|
|
fatalf("%s", err)
|
|
|
|
|
}
|
|
|
|
|
if err := fgcch.Close(); err != nil {
|
|
|
|
|
fatalf("%s", err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if *exportHeader != "" && len(p.ExpFunc) > 0 {
|
|
|
|
|
fexp := creat(*exportHeader)
|
|
|
|
|
fgcch, err := os.Open(*objDir + "_cgo_export.h")
|
|
|
|
|
if err != nil {
|
|
|
|
|
fatalf("%s", err)
|
|
|
|
|
}
|
2020-05-17 16:05:05 +00:00
|
|
|
defer fgcch.Close()
|
2015-05-06 17:53:17 -07:00
|
|
|
_, err = io.Copy(fexp, fgcch)
|
|
|
|
|
if err != nil {
|
|
|
|
|
fatalf("%s", err)
|
|
|
|
|
}
|
|
|
|
|
if err = fexp.Close(); err != nil {
|
|
|
|
|
fatalf("%s", err)
|
|
|
|
|
}
|
2012-03-15 23:50:25 +01:00
|
|
|
}
|
2009-09-24 11:43:19 -07:00
|
|
|
|
2012-11-01 11:21:30 -07:00
|
|
|
init := gccgoInit.String()
|
|
|
|
|
if init != "" {
|
2018-11-09 14:53:32 -08:00
|
|
|
// The init function does nothing but simple
|
|
|
|
|
// assignments, so it won't use much stack space, so
|
|
|
|
|
// it's OK to not split the stack. Splitting the stack
|
|
|
|
|
// can run into a bug in clang (as of 2018-11-09):
|
|
|
|
|
// this is a leaf function, and when clang sees a leaf
|
|
|
|
|
// function it won't emit the split stack prologue for
|
|
|
|
|
// the function. However, if this function refers to a
|
|
|
|
|
// non-split-stack function, which will happen if the
|
|
|
|
|
// cgo code refers to a C function not compiled with
|
|
|
|
|
// -fsplit-stack, then the linker will think that it
|
|
|
|
|
// needs to adjust the split stack prologue, but there
|
|
|
|
|
// won't be one. Marking the function explicitly
|
|
|
|
|
// no_split_stack works around this problem by telling
|
|
|
|
|
// the linker that it's OK if there is no split stack
|
|
|
|
|
// prologue.
|
|
|
|
|
fmt.Fprintln(fc, "static void init(void) __attribute__ ((constructor, no_split_stack));")
|
2012-11-01 11:21:30 -07:00
|
|
|
fmt.Fprintln(fc, "static void init(void) {")
|
|
|
|
|
fmt.Fprint(fc, init)
|
|
|
|
|
fmt.Fprintln(fc, "}")
|
|
|
|
|
}
|
2010-07-14 17:17:53 -07:00
|
|
|
}
|
|
|
|
|
|
2019-06-27 18:14:03 -04:00
|
|
|
// elfImportedSymbols is like elf.File.ImportedSymbols, but it
|
|
|
|
|
// includes weak symbols.
|
|
|
|
|
//
|
|
|
|
|
// A bug in some versions of LLD (at least LLD 8) cause it to emit
|
|
|
|
|
// several pthreads symbols as weak, but we need to import those. See
|
|
|
|
|
// issue #31912 or https://bugs.llvm.org/show_bug.cgi?id=42442.
|
|
|
|
|
//
|
|
|
|
|
// When doing external linking, we hand everything off to the external
|
|
|
|
|
// linker, which will create its own dynamic symbol tables. For
|
|
|
|
|
// internal linking, this may turn weak imports into strong imports,
|
|
|
|
|
// which could cause dynamic linking to fail if a symbol really isn't
|
|
|
|
|
// defined. However, the standard library depends on everything it
|
|
|
|
|
// imports, and this is the primary use of dynamic symbol tables with
|
|
|
|
|
// internal linking.
|
|
|
|
|
func elfImportedSymbols(f *elf.File) []elf.ImportedSymbol {
|
|
|
|
|
syms, _ := f.DynamicSymbols()
|
|
|
|
|
var imports []elf.ImportedSymbol
|
|
|
|
|
for _, s := range syms {
|
|
|
|
|
if (elf.ST_BIND(s.Info) == elf.STB_GLOBAL || elf.ST_BIND(s.Info) == elf.STB_WEAK) && s.Section == elf.SHN_UNDEF {
|
|
|
|
|
imports = append(imports, elf.ImportedSymbol{
|
|
|
|
|
Name: s.Name,
|
|
|
|
|
Library: s.Library,
|
|
|
|
|
Version: s.Version,
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return imports
|
|
|
|
|
}
|
|
|
|
|
|
2011-04-27 23:21:03 -04:00
|
|
|
func dynimport(obj string) {
|
2011-12-14 22:42:42 -05:00
|
|
|
stdout := os.Stdout
|
|
|
|
|
if *dynout != "" {
|
|
|
|
|
f, err := os.Create(*dynout)
|
|
|
|
|
if err != nil {
|
|
|
|
|
fatalf("%s", err)
|
|
|
|
|
}
|
|
|
|
|
stdout = f
|
|
|
|
|
}
|
|
|
|
|
|
2014-11-11 01:23:19 -05:00
|
|
|
fmt.Fprintf(stdout, "package %s\n", *dynpackage)
|
|
|
|
|
|
2011-04-27 23:21:03 -04:00
|
|
|
if f, err := elf.Open(obj); err == nil {
|
2013-03-04 11:23:17 -05:00
|
|
|
if *dynlinker {
|
|
|
|
|
// Emit the cgo_dynamic_linker line.
|
2013-03-01 00:27:57 -05:00
|
|
|
if sec := f.Section(".interp"); sec != nil {
|
|
|
|
|
if data, err := sec.Data(); err == nil && len(data) > 1 {
|
|
|
|
|
// skip trailing \0 in data
|
2014-11-11 01:23:19 -05:00
|
|
|
fmt.Fprintf(stdout, "//go:cgo_dynamic_linker %q\n", string(data[:len(data)-1]))
|
2013-03-01 00:27:57 -05:00
|
|
|
}
|
2012-05-05 01:54:16 +08:00
|
|
|
}
|
|
|
|
|
}
|
2019-06-27 18:14:03 -04:00
|
|
|
sym := elfImportedSymbols(f)
|
2011-04-27 23:21:03 -04:00
|
|
|
for _, s := range sym {
|
|
|
|
|
targ := s.Name
|
|
|
|
|
if s.Version != "" {
|
2013-01-30 08:29:33 -08:00
|
|
|
targ += "#" + s.Version
|
2011-01-20 10:22:20 -05:00
|
|
|
}
|
2020-11-06 09:38:38 -08:00
|
|
|
checkImportSymName(s.Name)
|
|
|
|
|
checkImportSymName(targ)
|
2014-11-11 01:23:19 -05:00
|
|
|
fmt.Fprintf(stdout, "//go:cgo_import_dynamic %s %s %q\n", s.Name, targ, s.Library)
|
2011-04-27 23:21:03 -04:00
|
|
|
}
|
2018-01-24 14:45:28 -08:00
|
|
|
lib, _ := f.ImportedLibraries()
|
2011-04-27 23:21:03 -04:00
|
|
|
for _, l := range lib {
|
2014-11-11 01:23:19 -05:00
|
|
|
fmt.Fprintf(stdout, "//go:cgo_import_dynamic _ _ %q\n", l)
|
2011-04-27 23:21:03 -04:00
|
|
|
}
|
|
|
|
|
return
|
2010-12-08 13:56:51 -05:00
|
|
|
}
|
|
|
|
|
|
2011-04-27 23:21:03 -04:00
|
|
|
if f, err := macho.Open(obj); err == nil {
|
2018-01-24 14:45:28 -08:00
|
|
|
sym, _ := f.ImportedSymbols()
|
2011-04-27 23:21:03 -04:00
|
|
|
for _, s := range sym {
|
|
|
|
|
if len(s) > 0 && s[0] == '_' {
|
|
|
|
|
s = s[1:]
|
2010-12-08 13:56:51 -05:00
|
|
|
}
|
2020-11-06 09:38:38 -08:00
|
|
|
checkImportSymName(s)
|
2014-11-11 01:23:19 -05:00
|
|
|
fmt.Fprintf(stdout, "//go:cgo_import_dynamic %s %s %q\n", s, s, "")
|
2011-04-27 23:21:03 -04:00
|
|
|
}
|
2018-01-24 14:45:28 -08:00
|
|
|
lib, _ := f.ImportedLibraries()
|
2011-04-27 23:21:03 -04:00
|
|
|
for _, l := range lib {
|
2014-11-11 01:23:19 -05:00
|
|
|
fmt.Fprintf(stdout, "//go:cgo_import_dynamic _ _ %q\n", l)
|
2010-12-08 13:56:51 -05:00
|
|
|
}
|
2011-04-27 23:21:03 -04:00
|
|
|
return
|
2010-12-08 13:56:51 -05:00
|
|
|
}
|
|
|
|
|
|
2011-04-27 23:21:03 -04:00
|
|
|
if f, err := pe.Open(obj); err == nil {
|
2018-01-24 14:45:28 -08:00
|
|
|
sym, _ := f.ImportedSymbols()
|
2011-04-27 23:21:03 -04:00
|
|
|
for _, s := range sym {
|
2011-06-28 09:43:14 +10:00
|
|
|
ss := strings.Split(s, ":")
|
2013-01-30 08:29:33 -08:00
|
|
|
name := strings.Split(ss[0], "@")[0]
|
2020-11-06 09:38:38 -08:00
|
|
|
checkImportSymName(name)
|
|
|
|
|
checkImportSymName(ss[0])
|
2014-11-11 01:23:19 -05:00
|
|
|
fmt.Fprintf(stdout, "//go:cgo_import_dynamic %s %s %q\n", name, ss[0], strings.ToLower(ss[1]))
|
2011-04-27 23:21:03 -04:00
|
|
|
}
|
|
|
|
|
return
|
2010-12-08 13:56:51 -05:00
|
|
|
}
|
|
|
|
|
|
2018-09-28 17:15:49 +02:00
|
|
|
if f, err := xcoff.Open(obj); err == nil {
|
|
|
|
|
sym, err := f.ImportedSymbols()
|
|
|
|
|
if err != nil {
|
|
|
|
|
fatalf("cannot load imported symbols from XCOFF file %s: %v", obj, err)
|
|
|
|
|
}
|
|
|
|
|
for _, s := range sym {
|
2019-03-25 10:31:30 +01:00
|
|
|
if s.Name == "runtime_rt0_go" || s.Name == "_rt0_ppc64_aix_lib" {
|
|
|
|
|
// These symbols are imported by runtime/cgo but
|
|
|
|
|
// must not be added to _cgo_import.go as there are
|
|
|
|
|
// Go symbols.
|
|
|
|
|
continue
|
|
|
|
|
}
|
2020-11-06 09:38:38 -08:00
|
|
|
checkImportSymName(s.Name)
|
2018-09-28 17:15:49 +02:00
|
|
|
fmt.Fprintf(stdout, "//go:cgo_import_dynamic %s %s %q\n", s.Name, s.Name, s.Library)
|
|
|
|
|
}
|
|
|
|
|
lib, err := f.ImportedLibraries()
|
|
|
|
|
if err != nil {
|
|
|
|
|
fatalf("cannot load imported libraries from XCOFF file %s: %v", obj, err)
|
|
|
|
|
}
|
|
|
|
|
for _, l := range lib {
|
|
|
|
|
fmt.Fprintf(stdout, "//go:cgo_import_dynamic _ _ %q\n", l)
|
|
|
|
|
}
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fatalf("cannot parse %s as ELF, Mach-O, PE or XCOFF", obj)
|
2010-12-08 13:56:51 -05:00
|
|
|
}
|
|
|
|
|
|
2020-11-06 09:38:38 -08:00
|
|
|
// checkImportSymName checks a symbol name we are going to emit as part
|
|
|
|
|
// of a //go:cgo_import_dynamic pragma. These names come from object
|
|
|
|
|
// files, so they may be corrupt. We are going to emit them unquoted,
|
|
|
|
|
// so while they don't need to be valid symbol names (and in some cases,
|
|
|
|
|
// involving symbol versions, they won't be) they must contain only
|
|
|
|
|
// graphic characters and must not contain Go comments.
|
|
|
|
|
func checkImportSymName(s string) {
|
|
|
|
|
for _, c := range s {
|
|
|
|
|
if !unicode.IsGraphic(c) || unicode.IsSpace(c) {
|
|
|
|
|
fatalf("dynamic symbol %q contains unsupported character", s)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if strings.Index(s, "//") >= 0 || strings.Index(s, "/*") >= 0 {
|
|
|
|
|
fatalf("dynamic symbol %q contains Go comment")
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-06-24 09:50:12 +10:00
|
|
|
// Construct a gcc struct matching the gc argument frame.
|
2010-07-14 17:17:53 -07:00
|
|
|
// Assumes that in gcc, char is 1 byte, short 2 bytes, int 4 bytes, long long 8 bytes.
|
|
|
|
|
// These assumptions are checked by the gccProlog.
|
2015-06-24 09:50:12 +10:00
|
|
|
// Also assumes that gc convention is to word-align the
|
2010-07-14 17:17:53 -07:00
|
|
|
// input and output parameters.
|
|
|
|
|
func (p *Package) structType(n *Name) (string, int64) {
|
|
|
|
|
var buf bytes.Buffer
|
|
|
|
|
fmt.Fprint(&buf, "struct {\n")
|
|
|
|
|
off := int64(0)
|
|
|
|
|
for i, t := range n.FuncType.Params {
|
|
|
|
|
if off%t.Align != 0 {
|
|
|
|
|
pad := t.Align - off%t.Align
|
|
|
|
|
fmt.Fprintf(&buf, "\t\tchar __pad%d[%d];\n", off, pad)
|
2009-12-15 15:33:31 -08:00
|
|
|
off += pad
|
2009-09-24 11:43:19 -07:00
|
|
|
}
|
2012-02-19 13:32:55 -05:00
|
|
|
c := t.Typedef
|
|
|
|
|
if c == "" {
|
|
|
|
|
c = t.C.String()
|
|
|
|
|
}
|
|
|
|
|
fmt.Fprintf(&buf, "\t\t%s p%d;\n", c, i)
|
2010-07-14 17:17:53 -07:00
|
|
|
off += t.Size
|
|
|
|
|
}
|
|
|
|
|
if off%p.PtrSize != 0 {
|
|
|
|
|
pad := p.PtrSize - off%p.PtrSize
|
|
|
|
|
fmt.Fprintf(&buf, "\t\tchar __pad%d[%d];\n", off, pad)
|
|
|
|
|
off += pad
|
|
|
|
|
}
|
|
|
|
|
if t := n.FuncType.Result; t != nil {
|
|
|
|
|
if off%t.Align != 0 {
|
|
|
|
|
pad := t.Align - off%t.Align
|
|
|
|
|
fmt.Fprintf(&buf, "\t\tchar __pad%d[%d];\n", off, pad)
|
2009-12-15 15:33:31 -08:00
|
|
|
off += pad
|
2009-09-24 11:43:19 -07:00
|
|
|
}
|
2016-11-10 14:34:32 -08:00
|
|
|
fmt.Fprintf(&buf, "\t\t%s r;\n", t.C)
|
2010-07-14 17:17:53 -07:00
|
|
|
off += t.Size
|
|
|
|
|
}
|
|
|
|
|
if off%p.PtrSize != 0 {
|
|
|
|
|
pad := p.PtrSize - off%p.PtrSize
|
|
|
|
|
fmt.Fprintf(&buf, "\t\tchar __pad%d[%d];\n", off, pad)
|
|
|
|
|
off += pad
|
|
|
|
|
}
|
|
|
|
|
if off == 0 {
|
|
|
|
|
fmt.Fprintf(&buf, "\t\tchar unused;\n") // avoid empty struct
|
|
|
|
|
}
|
2011-01-11 10:17:54 -05:00
|
|
|
fmt.Fprintf(&buf, "\t}")
|
2010-07-14 17:17:53 -07:00
|
|
|
return buf.String(), off
|
|
|
|
|
}
|
|
|
|
|
|
2016-05-19 16:27:23 -07:00
|
|
|
func (p *Package) writeDefsFunc(fgo2 io.Writer, n *Name, callsMalloc *bool) {
|
2010-07-14 17:17:53 -07:00
|
|
|
name := n.Go
|
|
|
|
|
gtype := n.FuncType.Go
|
2012-11-01 11:21:30 -07:00
|
|
|
void := gtype.Results == nil || len(gtype.Results.List) == 0
|
2010-07-14 17:17:53 -07:00
|
|
|
if n.AddError {
|
2011-11-01 21:49:22 -04:00
|
|
|
// Add "error" to return type list.
|
2010-07-14 17:17:53 -07:00
|
|
|
// Type list is known to be 0 or 1 element - it's a C function.
|
2011-11-01 21:49:22 -04:00
|
|
|
err := &ast.Field{Type: ast.NewIdent("error")}
|
2010-07-14 17:17:53 -07:00
|
|
|
l := gtype.Results.List
|
|
|
|
|
if len(l) == 0 {
|
|
|
|
|
l = []*ast.Field{err}
|
|
|
|
|
} else {
|
|
|
|
|
l = []*ast.Field{l[0], err}
|
2009-09-24 11:43:19 -07:00
|
|
|
}
|
2010-07-14 17:17:53 -07:00
|
|
|
t := new(ast.FuncType)
|
|
|
|
|
*t = *gtype
|
|
|
|
|
t.Results = &ast.FieldList{List: l}
|
|
|
|
|
gtype = t
|
2009-12-17 13:20:56 -08:00
|
|
|
}
|
|
|
|
|
|
2010-07-14 17:17:53 -07:00
|
|
|
// Go func declaration.
|
|
|
|
|
d := &ast.FuncDecl{
|
|
|
|
|
Name: ast.NewIdent(n.Mangle),
|
|
|
|
|
Type: gtype,
|
|
|
|
|
}
|
2012-02-14 20:23:45 +01:00
|
|
|
|
2013-07-25 09:53:57 -04:00
|
|
|
// Builtins defined in the C prolog.
|
2014-09-03 11:36:14 -04:00
|
|
|
inProlog := builtinDefs[name] != ""
|
|
|
|
|
cname := fmt.Sprintf("_cgo%s%s", cPrefix, n.Mangle)
|
|
|
|
|
paramnames := []string(nil)
|
2017-05-23 23:01:08 +09:00
|
|
|
if d.Type.Params != 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)
|
|
|
|
|
}
|
2014-09-03 11:36:14 -04:00
|
|
|
}
|
2013-07-25 09:53:57 -04:00
|
|
|
|
2011-12-14 15:40:35 -08:00
|
|
|
if *gccgo {
|
2012-02-14 20:23:45 +01:00
|
|
|
// Gccgo style hooks.
|
2012-11-01 11:21:30 -07:00
|
|
|
fmt.Fprint(fgo2, "\n")
|
|
|
|
|
conf.Fprint(fgo2, fset, d)
|
|
|
|
|
fmt.Fprint(fgo2, " {\n")
|
2013-07-25 09:53:57 -04:00
|
|
|
if !inProlog {
|
|
|
|
|
fmt.Fprint(fgo2, "\tdefer syscall.CgocallDone()\n")
|
|
|
|
|
fmt.Fprint(fgo2, "\tsyscall.Cgocall()\n")
|
|
|
|
|
}
|
2012-11-01 11:21:30 -07:00
|
|
|
if n.AddError {
|
|
|
|
|
fmt.Fprint(fgo2, "\tsyscall.SetErrno(0)\n")
|
|
|
|
|
}
|
|
|
|
|
fmt.Fprint(fgo2, "\t")
|
|
|
|
|
if !void {
|
|
|
|
|
fmt.Fprint(fgo2, "r := ")
|
|
|
|
|
}
|
|
|
|
|
fmt.Fprintf(fgo2, "%s(%s)\n", cname, strings.Join(paramnames, ", "))
|
|
|
|
|
|
|
|
|
|
if n.AddError {
|
|
|
|
|
fmt.Fprint(fgo2, "\te := syscall.GetErrno()\n")
|
|
|
|
|
fmt.Fprint(fgo2, "\tif e != 0 {\n")
|
|
|
|
|
fmt.Fprint(fgo2, "\t\treturn ")
|
|
|
|
|
if !void {
|
|
|
|
|
fmt.Fprint(fgo2, "r, ")
|
|
|
|
|
}
|
|
|
|
|
fmt.Fprint(fgo2, "e\n")
|
|
|
|
|
fmt.Fprint(fgo2, "\t}\n")
|
|
|
|
|
fmt.Fprint(fgo2, "\treturn ")
|
|
|
|
|
if !void {
|
|
|
|
|
fmt.Fprint(fgo2, "r, ")
|
2012-02-14 20:23:45 +01:00
|
|
|
}
|
2012-11-01 11:21:30 -07:00
|
|
|
fmt.Fprint(fgo2, "nil\n")
|
|
|
|
|
} else if !void {
|
|
|
|
|
fmt.Fprint(fgo2, "\treturn r\n")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fmt.Fprint(fgo2, "}\n")
|
|
|
|
|
|
|
|
|
|
// declare the C function.
|
2014-09-03 11:36:14 -04:00
|
|
|
fmt.Fprintf(fgo2, "//extern %s\n", cname)
|
2012-11-01 11:21:30 -07:00
|
|
|
d.Name = ast.NewIdent(cname)
|
|
|
|
|
if n.AddError {
|
2012-02-14 20:23:45 +01:00
|
|
|
l := d.Type.Results.List
|
|
|
|
|
d.Type.Results.List = l[:len(l)-1]
|
|
|
|
|
}
|
2012-11-01 11:21:30 -07:00
|
|
|
conf.Fprint(fgo2, fset, d)
|
|
|
|
|
fmt.Fprint(fgo2, "\n")
|
|
|
|
|
|
2012-02-14 20:23:45 +01:00
|
|
|
return
|
2011-12-14 15:40:35 -08:00
|
|
|
}
|
2010-04-09 13:31:05 -07:00
|
|
|
|
2013-07-25 09:53:57 -04:00
|
|
|
if inProlog {
|
2014-09-03 11:36:14 -04:00
|
|
|
fmt.Fprint(fgo2, builtinDefs[name])
|
2016-05-19 16:27:23 -07:00
|
|
|
if strings.Contains(builtinDefs[name], "_cgo_cmalloc") {
|
|
|
|
|
*callsMalloc = true
|
|
|
|
|
}
|
2010-07-14 17:17:53 -07:00
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
2015-06-07 22:14:04 -04:00
|
|
|
// Wrapper calls into gcc, passing a pointer to the argument frame.
|
2014-11-11 01:23:19 -05:00
|
|
|
fmt.Fprintf(fgo2, "//go:cgo_import_static %s\n", cname)
|
|
|
|
|
fmt.Fprintf(fgo2, "//go:linkname __cgofn_%s %s\n", cname, cname)
|
|
|
|
|
fmt.Fprintf(fgo2, "var __cgofn_%s byte\n", cname)
|
|
|
|
|
fmt.Fprintf(fgo2, "var %s = unsafe.Pointer(&__cgofn_%s)\n", cname, cname)
|
2014-09-03 11:36:14 -04:00
|
|
|
|
|
|
|
|
nret := 0
|
|
|
|
|
if !void {
|
|
|
|
|
d.Type.Results.List[0].Names = []*ast.Ident{ast.NewIdent("r1")}
|
|
|
|
|
nret = 1
|
2011-03-05 14:24:44 -05:00
|
|
|
}
|
2014-09-03 11:36:14 -04:00
|
|
|
if n.AddError {
|
|
|
|
|
d.Type.Results.List[nret].Names = []*ast.Ident{ast.NewIdent("r2")}
|
2013-09-24 15:52:48 -04:00
|
|
|
}
|
2014-09-03 11:36:14 -04:00
|
|
|
|
|
|
|
|
fmt.Fprint(fgo2, "\n")
|
2016-02-27 17:49:31 -08:00
|
|
|
fmt.Fprint(fgo2, "//go:cgo_unsafe_args\n")
|
2014-09-03 11:36:14 -04:00
|
|
|
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))"
|
2013-09-24 15:52:48 -04:00
|
|
|
}
|
2014-09-03 11:36:14 -04:00
|
|
|
|
|
|
|
|
prefix := ""
|
2010-07-14 17:17:53 -07:00
|
|
|
if n.AddError {
|
2014-09-03 11:36:14 -04:00
|
|
|
prefix = "errno := "
|
2010-07-14 17:17:53 -07:00
|
|
|
}
|
2015-04-27 17:32:23 +10:00
|
|
|
fmt.Fprintf(fgo2, "\t%s_cgo_runtime_cgocall(%s, %s)\n", prefix, cname, arg)
|
2014-09-03 11:36:14 -04:00
|
|
|
if n.AddError {
|
|
|
|
|
fmt.Fprintf(fgo2, "\tif errno != 0 { r2 = syscall.Errno(errno) }\n")
|
|
|
|
|
}
|
2015-06-07 22:14:04 -04:00
|
|
|
fmt.Fprintf(fgo2, "\tif _Cgo_always_false {\n")
|
2017-05-23 23:01:08 +09:00
|
|
|
if d.Type.Params != nil {
|
|
|
|
|
for i := range d.Type.Params.List {
|
|
|
|
|
fmt.Fprintf(fgo2, "\t\t_Cgo_use(p%d)\n", i)
|
|
|
|
|
}
|
2015-06-07 22:14:04 -04:00
|
|
|
}
|
|
|
|
|
fmt.Fprintf(fgo2, "\t}\n")
|
2014-09-03 11:36:14 -04:00
|
|
|
fmt.Fprintf(fgo2, "\treturn\n")
|
|
|
|
|
fmt.Fprintf(fgo2, "}\n")
|
2009-12-17 13:20:56 -08:00
|
|
|
}
|
|
|
|
|
|
2015-06-24 09:50:12 +10:00
|
|
|
// writeOutput creates stubs for a specific source file to be compiled by gc
|
2010-07-14 17:17:53 -07:00
|
|
|
func (p *Package) writeOutput(f *File, srcfile string) {
|
2009-12-17 13:20:56 -08:00
|
|
|
base := srcfile
|
|
|
|
|
if strings.HasSuffix(base, ".go") {
|
|
|
|
|
base = base[0 : len(base)-3]
|
|
|
|
|
}
|
2017-11-10 15:46:56 -05:00
|
|
|
base = filepath.Base(base)
|
2011-12-14 22:42:42 -05:00
|
|
|
fgo1 := creat(*objDir + base + ".cgo1.go")
|
|
|
|
|
fgcc := creat(*objDir + base + ".cgo2.c")
|
2009-12-17 13:20:56 -08:00
|
|
|
|
2010-12-08 13:56:51 -05:00
|
|
|
p.GoFiles = append(p.GoFiles, base+".cgo1.go")
|
|
|
|
|
p.GccFiles = append(p.GccFiles, base+".cgo2.c")
|
|
|
|
|
|
2009-12-17 13:20:56 -08:00
|
|
|
// Write Go output: Go input with rewrites of C.xxx to _C_xxx.
|
2018-05-29 06:40:56 -07:00
|
|
|
fmt.Fprintf(fgo1, "// Code generated by cmd/cgo; DO NOT EDIT.\n\n")
|
2018-07-30 17:05:49 +03:00
|
|
|
fmt.Fprintf(fgo1, "//line %s:1:1\n", srcfile)
|
2017-11-10 11:45:16 -05:00
|
|
|
fgo1.Write(f.Edit.Bytes())
|
2009-12-17 13:20:56 -08:00
|
|
|
|
2015-01-06 15:08:02 -08:00
|
|
|
// While we process the vars and funcs, also write gcc output.
|
2009-12-17 13:20:56 -08:00
|
|
|
// Gcc output starts with the preamble.
|
2017-10-13 18:26:10 -07:00
|
|
|
fmt.Fprintf(fgcc, "%s\n", builtinProlog)
|
2010-07-14 17:17:53 -07:00
|
|
|
fmt.Fprintf(fgcc, "%s\n", f.Preamble)
|
2009-12-17 13:20:56 -08:00
|
|
|
fmt.Fprintf(fgcc, "%s\n", gccProlog)
|
2015-12-03 19:17:21 -08:00
|
|
|
fmt.Fprintf(fgcc, "%s\n", tsanProlog)
|
2018-07-03 22:10:58 -07:00
|
|
|
fmt.Fprintf(fgcc, "%s\n", msanProlog)
|
2009-12-17 13:20:56 -08:00
|
|
|
|
2012-06-07 12:37:50 -04:00
|
|
|
for _, key := range nameKeys(f.Name) {
|
|
|
|
|
n := f.Name[key]
|
2010-07-14 17:17:53 -07:00
|
|
|
if n.FuncType != nil {
|
|
|
|
|
p.writeOutputFunc(fgcc, n)
|
2009-09-24 11:43:19 -07:00
|
|
|
}
|
|
|
|
|
}
|
2009-09-30 11:51:08 -07:00
|
|
|
|
2009-12-15 15:33:31 -08:00
|
|
|
fgo1.Close()
|
|
|
|
|
fgcc.Close()
|
2009-09-24 11:43:19 -07:00
|
|
|
}
|
|
|
|
|
|
2014-04-29 12:44:40 -04:00
|
|
|
// fixGo converts the internal Name.Go field into the name we should show
|
2013-09-11 11:30:08 -04:00
|
|
|
// 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,
|
2016-03-16 13:53:53 -04:00
|
|
|
"_Cfunc_CBytes": true,
|
2013-09-11 11:30:08 -04:00
|
|
|
"_Cfunc_GoString": true,
|
|
|
|
|
"_Cfunc_GoStringN": true,
|
|
|
|
|
"_Cfunc_GoBytes": true,
|
|
|
|
|
"_Cfunc__CMalloc": true,
|
|
|
|
|
}
|
|
|
|
|
|
2010-07-14 17:17:53 -07:00
|
|
|
func (p *Package) writeOutputFunc(fgcc *os.File, n *Name) {
|
|
|
|
|
name := n.Mangle
|
2013-09-11 11:30:08 -04:00
|
|
|
if isBuiltin[name] || p.Written[name] {
|
2010-07-14 17:17:53 -07:00
|
|
|
// The builtins are already defined in the C prolog, and we don't
|
|
|
|
|
// want to duplicate function definitions we've already done.
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
p.Written[name] = true
|
|
|
|
|
|
2012-02-14 20:23:45 +01:00
|
|
|
if *gccgo {
|
2013-07-25 09:53:57 -04:00
|
|
|
p.writeGccgoOutputFunc(fgcc, n)
|
2012-02-14 20:23:45 +01:00
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
2014-07-18 02:59:54 -04:00
|
|
|
ctype, _ := p.structType(n)
|
2010-07-14 17:17:53 -07:00
|
|
|
|
|
|
|
|
// Gcc wrapper unpacks the C argument struct
|
|
|
|
|
// and calls the actual C function.
|
2016-05-19 10:07:41 -07:00
|
|
|
fmt.Fprintf(fgcc, "CGO_NO_SANITIZE_THREAD\n")
|
2014-09-03 11:36:14 -04:00
|
|
|
if n.AddError {
|
|
|
|
|
fmt.Fprintf(fgcc, "int\n")
|
|
|
|
|
} else {
|
|
|
|
|
fmt.Fprintf(fgcc, "void\n")
|
|
|
|
|
}
|
2010-12-10 11:32:58 -08:00
|
|
|
fmt.Fprintf(fgcc, "_cgo%s%s(void *v)\n", cPrefix, n.Mangle)
|
2010-07-14 17:17:53 -07:00
|
|
|
fmt.Fprintf(fgcc, "{\n")
|
|
|
|
|
if n.AddError {
|
2016-05-01 17:03:46 -07:00
|
|
|
fmt.Fprintf(fgcc, "\tint _cgo_errno;\n")
|
2010-07-14 17:17:53 -07:00
|
|
|
}
|
2015-06-24 09:50:12 +10:00
|
|
|
// We're trying to write a gcc struct that matches gc's layout.
|
2011-05-18 14:08:12 -04:00
|
|
|
// Use packed attribute to force no padding in this struct in case
|
2013-12-10 11:30:12 +11:00
|
|
|
// gcc has different packing requirements.
|
2018-01-06 18:10:30 +09:00
|
|
|
fmt.Fprintf(fgcc, "\t%s %v *_cgo_a = v;\n", ctype, p.packedAttribute())
|
2014-09-25 07:59:01 -07:00
|
|
|
if n.FuncType.Result != nil {
|
|
|
|
|
// Save the stack top for use below.
|
2018-01-06 18:10:30 +09:00
|
|
|
fmt.Fprintf(fgcc, "\tchar *_cgo_stktop = _cgo_topofstack();\n")
|
2014-09-25 07:59:01 -07:00
|
|
|
}
|
2016-05-01 17:03:46 -07:00
|
|
|
tr := n.FuncType.Result
|
|
|
|
|
if tr != nil {
|
2018-01-06 18:10:30 +09:00
|
|
|
fmt.Fprintf(fgcc, "\t__typeof__(_cgo_a->r) _cgo_r;\n")
|
2016-05-01 17:03:46 -07:00
|
|
|
}
|
2015-12-03 19:17:21 -08:00
|
|
|
fmt.Fprintf(fgcc, "\t_cgo_tsan_acquire();\n")
|
2016-05-01 17:03:46 -07:00
|
|
|
if n.AddError {
|
|
|
|
|
fmt.Fprintf(fgcc, "\terrno = 0;\n")
|
|
|
|
|
}
|
2010-07-14 17:17:53 -07:00
|
|
|
fmt.Fprintf(fgcc, "\t")
|
2016-05-01 17:03:46 -07:00
|
|
|
if tr != nil {
|
2018-01-06 18:10:30 +09:00
|
|
|
fmt.Fprintf(fgcc, "_cgo_r = ")
|
2016-05-01 17:03:46 -07:00
|
|
|
if c := tr.C.String(); c[len(c)-1] == '*' {
|
2018-01-06 18:10:30 +09:00
|
|
|
fmt.Fprint(fgcc, "(__typeof__(_cgo_a->r)) ")
|
2011-04-21 17:02:52 -04:00
|
|
|
}
|
2010-07-14 17:17:53 -07:00
|
|
|
}
|
2017-05-23 23:01:08 +09:00
|
|
|
if n.Kind == "macro" {
|
|
|
|
|
fmt.Fprintf(fgcc, "%s;\n", n.C)
|
|
|
|
|
} else {
|
|
|
|
|
fmt.Fprintf(fgcc, "%s(", n.C)
|
|
|
|
|
for i := range n.FuncType.Params {
|
|
|
|
|
if i > 0 {
|
|
|
|
|
fmt.Fprintf(fgcc, ", ")
|
|
|
|
|
}
|
2018-01-06 18:10:30 +09:00
|
|
|
fmt.Fprintf(fgcc, "_cgo_a->p%d", i)
|
2010-07-14 17:17:53 -07:00
|
|
|
}
|
2017-05-23 23:01:08 +09:00
|
|
|
fmt.Fprintf(fgcc, ");\n")
|
2010-07-14 17:17:53 -07:00
|
|
|
}
|
2016-05-01 17:03:46 -07:00
|
|
|
if n.AddError {
|
|
|
|
|
fmt.Fprintf(fgcc, "\t_cgo_errno = errno;\n")
|
|
|
|
|
}
|
2015-12-03 19:17:21 -08:00
|
|
|
fmt.Fprintf(fgcc, "\t_cgo_tsan_release();\n")
|
2014-09-25 07:59:01 -07:00
|
|
|
if n.FuncType.Result != nil {
|
|
|
|
|
// The cgo call may have caused a stack copy (via a callback).
|
|
|
|
|
// Adjust the return value pointer appropriately.
|
2018-01-06 18:10:30 +09:00
|
|
|
fmt.Fprintf(fgcc, "\t_cgo_a = (void*)((char*)_cgo_a + (_cgo_topofstack() - _cgo_stktop));\n")
|
2014-09-25 07:59:01 -07:00
|
|
|
// Save the return value.
|
2018-01-06 18:10:30 +09:00
|
|
|
fmt.Fprintf(fgcc, "\t_cgo_a->r = _cgo_r;\n")
|
2018-07-03 22:10:58 -07:00
|
|
|
// The return value is on the Go stack. If we are using msan,
|
|
|
|
|
// and if the C value is partially or completely uninitialized,
|
|
|
|
|
// the assignment will mark the Go stack as uninitialized.
|
|
|
|
|
// The Go compiler does not update msan for changes to the
|
|
|
|
|
// stack. It is possible that the stack will remain
|
|
|
|
|
// uninitialized, and then later be used in a way that is
|
|
|
|
|
// visible to msan, possibly leading to a false positive.
|
|
|
|
|
// Mark the stack space as written, to avoid this problem.
|
|
|
|
|
// See issue 26209.
|
|
|
|
|
fmt.Fprintf(fgcc, "\t_cgo_msan_write(&_cgo_a->r, sizeof(_cgo_a->r));\n")
|
2014-09-25 07:59:01 -07:00
|
|
|
}
|
2010-07-14 17:17:53 -07:00
|
|
|
if n.AddError {
|
2016-05-01 17:03:46 -07:00
|
|
|
fmt.Fprintf(fgcc, "\treturn _cgo_errno;\n")
|
2010-07-14 17:17:53 -07:00
|
|
|
}
|
|
|
|
|
fmt.Fprintf(fgcc, "}\n")
|
|
|
|
|
fmt.Fprintf(fgcc, "\n")
|
|
|
|
|
}
|
|
|
|
|
|
2016-03-01 23:21:55 +00:00
|
|
|
// Write out a wrapper for a function when using gccgo. This is a
|
|
|
|
|
// simple wrapper that just calls the real function. We only need a
|
2013-07-25 09:53:57 -04:00
|
|
|
// wrapper to support static functions in the prologue--without a
|
|
|
|
|
// wrapper, we can't refer to the function, since the reference is in
|
|
|
|
|
// a different file.
|
|
|
|
|
func (p *Package) writeGccgoOutputFunc(fgcc *os.File, n *Name) {
|
2016-05-19 10:07:41 -07:00
|
|
|
fmt.Fprintf(fgcc, "CGO_NO_SANITIZE_THREAD\n")
|
2013-07-25 09:53:57 -04:00
|
|
|
if t := n.FuncType.Result; t != nil {
|
|
|
|
|
fmt.Fprintf(fgcc, "%s\n", t.C.String())
|
|
|
|
|
} else {
|
|
|
|
|
fmt.Fprintf(fgcc, "void\n")
|
|
|
|
|
}
|
|
|
|
|
fmt.Fprintf(fgcc, "_cgo%s%s(", cPrefix, n.Mangle)
|
|
|
|
|
for i, t := range n.FuncType.Params {
|
|
|
|
|
if i > 0 {
|
|
|
|
|
fmt.Fprintf(fgcc, ", ")
|
|
|
|
|
}
|
|
|
|
|
c := t.Typedef
|
|
|
|
|
if c == "" {
|
|
|
|
|
c = t.C.String()
|
|
|
|
|
}
|
|
|
|
|
fmt.Fprintf(fgcc, "%s p%d", c, i)
|
|
|
|
|
}
|
|
|
|
|
fmt.Fprintf(fgcc, ")\n")
|
|
|
|
|
fmt.Fprintf(fgcc, "{\n")
|
2015-12-03 19:17:21 -08:00
|
|
|
if t := n.FuncType.Result; t != nil {
|
2018-01-06 18:10:30 +09:00
|
|
|
fmt.Fprintf(fgcc, "\t%s _cgo_r;\n", t.C.String())
|
2015-12-03 19:17:21 -08:00
|
|
|
}
|
|
|
|
|
fmt.Fprintf(fgcc, "\t_cgo_tsan_acquire();\n")
|
2013-07-25 09:53:57 -04:00
|
|
|
fmt.Fprintf(fgcc, "\t")
|
|
|
|
|
if t := n.FuncType.Result; t != nil {
|
2018-01-06 18:10:30 +09:00
|
|
|
fmt.Fprintf(fgcc, "_cgo_r = ")
|
2013-07-25 09:53:57 -04:00
|
|
|
// Cast to void* to avoid warnings due to omitted qualifiers.
|
|
|
|
|
if c := t.C.String(); c[len(c)-1] == '*' {
|
|
|
|
|
fmt.Fprintf(fgcc, "(void*)")
|
|
|
|
|
}
|
|
|
|
|
}
|
2018-01-05 16:52:53 -08:00
|
|
|
if n.Kind == "macro" {
|
|
|
|
|
fmt.Fprintf(fgcc, "%s;\n", n.C)
|
|
|
|
|
} else {
|
|
|
|
|
fmt.Fprintf(fgcc, "%s(", n.C)
|
|
|
|
|
for i := range n.FuncType.Params {
|
|
|
|
|
if i > 0 {
|
|
|
|
|
fmt.Fprintf(fgcc, ", ")
|
|
|
|
|
}
|
|
|
|
|
fmt.Fprintf(fgcc, "p%d", i)
|
2013-07-25 09:53:57 -04:00
|
|
|
}
|
2018-01-05 16:52:53 -08:00
|
|
|
fmt.Fprintf(fgcc, ");\n")
|
2013-07-25 09:53:57 -04:00
|
|
|
}
|
2015-12-03 19:17:21 -08:00
|
|
|
fmt.Fprintf(fgcc, "\t_cgo_tsan_release();\n")
|
|
|
|
|
if t := n.FuncType.Result; t != nil {
|
|
|
|
|
fmt.Fprintf(fgcc, "\treturn ")
|
|
|
|
|
// Cast to void* to avoid warnings due to omitted qualifiers
|
|
|
|
|
// and explicit incompatible struct types.
|
|
|
|
|
if c := t.C.String(); c[len(c)-1] == '*' {
|
|
|
|
|
fmt.Fprintf(fgcc, "(void*)")
|
|
|
|
|
}
|
2018-01-06 18:10:30 +09:00
|
|
|
fmt.Fprintf(fgcc, "_cgo_r;\n")
|
2015-12-03 19:17:21 -08:00
|
|
|
}
|
2013-07-25 09:53:57 -04:00
|
|
|
fmt.Fprintf(fgcc, "}\n")
|
|
|
|
|
fmt.Fprintf(fgcc, "\n")
|
|
|
|
|
}
|
|
|
|
|
|
2013-12-10 11:30:12 +11:00
|
|
|
// packedAttribute returns host compiler struct attribute that will be
|
2015-06-24 09:50:12 +10:00
|
|
|
// used to match gc's struct layout. For example, on 386 Windows,
|
|
|
|
|
// gcc wants to 8-align int64s, but gc does not.
|
2018-06-01 17:29:59 -03:00
|
|
|
// Use __gcc_struct__ to work around https://gcc.gnu.org/PR52991 on x86,
|
2015-07-10 17:17:11 -06:00
|
|
|
// and https://golang.org/issue/5603.
|
2013-12-10 11:30:12 +11:00
|
|
|
func (p *Package) packedAttribute() string {
|
|
|
|
|
s := "__attribute__((__packed__"
|
2015-04-17 17:05:47 -07:00
|
|
|
if !p.GccIsClang && (goarch == "amd64" || goarch == "386") {
|
2013-12-10 11:30:12 +11:00
|
|
|
s += ", __gcc_struct__"
|
|
|
|
|
}
|
|
|
|
|
return s + "))"
|
|
|
|
|
}
|
|
|
|
|
|
2020-03-10 00:22:01 +00:00
|
|
|
// exportParamName returns the value of param as it should be
|
|
|
|
|
// displayed in a c header file. If param contains any non-ASCII
|
|
|
|
|
// characters, this function will return the character p followed by
|
|
|
|
|
// the value of position; otherwise, this function will return the
|
|
|
|
|
// value of param.
|
|
|
|
|
func exportParamName(param string, position int) string {
|
2020-03-09 21:33:35 -07:00
|
|
|
if param == "" {
|
|
|
|
|
return fmt.Sprintf("p%d", position)
|
|
|
|
|
}
|
|
|
|
|
|
2020-03-10 00:22:01 +00:00
|
|
|
pname := param
|
|
|
|
|
|
|
|
|
|
for i := 0; i < len(param); i++ {
|
|
|
|
|
if param[i] > unicode.MaxASCII {
|
|
|
|
|
pname = fmt.Sprintf("p%d", position)
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return pname
|
|
|
|
|
}
|
|
|
|
|
|
2010-04-09 13:31:05 -07:00
|
|
|
// Write out the various stubs we need to support functions exported
|
|
|
|
|
// from Go so that they are callable from C.
|
2015-05-06 17:53:17 -07:00
|
|
|
func (p *Package) writeExports(fgo2, fm, fgcc, fgcch io.Writer) {
|
2015-05-05 18:19:28 -07:00
|
|
|
p.writeExportHeader(fgcch)
|
2010-04-09 13:31:05 -07:00
|
|
|
|
2018-05-29 06:40:56 -07:00
|
|
|
fmt.Fprintf(fgcc, "/* Code generated by cmd/cgo; DO NOT EDIT. */\n\n")
|
2016-05-19 16:27:23 -07:00
|
|
|
fmt.Fprintf(fgcc, "#include <stdlib.h>\n")
|
2015-03-25 17:50:35 -07:00
|
|
|
fmt.Fprintf(fgcc, "#include \"_cgo_export.h\"\n\n")
|
2010-04-09 13:31:05 -07:00
|
|
|
|
2019-01-28 12:31:55 -08:00
|
|
|
// We use packed structs, but they are always aligned.
|
2019-03-07 08:33:01 +01:00
|
|
|
// The pragmas and address-of-packed-member are only recognized as
|
|
|
|
|
// warning groups in clang 4.0+, so ignore unknown pragmas first.
|
2019-02-01 13:51:31 +02:00
|
|
|
fmt.Fprintf(fgcc, "#pragma GCC diagnostic ignored \"-Wunknown-pragmas\"\n")
|
2019-01-28 12:31:55 -08:00
|
|
|
fmt.Fprintf(fgcc, "#pragma GCC diagnostic ignored \"-Wpragmas\"\n")
|
|
|
|
|
fmt.Fprintf(fgcc, "#pragma GCC diagnostic ignored \"-Waddress-of-packed-member\"\n")
|
|
|
|
|
|
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 <austin@google.com>
Run-TryBot: Austin Clements <austin@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Cherry Zhang <cherryyz@google.com>
2020-10-01 17:22:38 -04:00
|
|
|
fmt.Fprintf(fgcc, "extern void crosscall2(void (*fn)(void *), void *, int, __SIZE_TYPE__);\n")
|
2019-01-23 20:14:30 +00:00
|
|
|
fmt.Fprintf(fgcc, "extern __SIZE_TYPE__ _cgo_wait_runtime_init_done(void);\n")
|
2016-04-27 14:18:29 -07:00
|
|
|
fmt.Fprintf(fgcc, "extern void _cgo_release_context(__SIZE_TYPE__);\n\n")
|
2016-05-19 16:27:23 -07:00
|
|
|
fmt.Fprintf(fgcc, "extern char* _cgo_topofstack(void);")
|
2015-12-03 19:17:21 -08:00
|
|
|
fmt.Fprintf(fgcc, "%s\n", tsanProlog)
|
2018-07-03 22:10:58 -07:00
|
|
|
fmt.Fprintf(fgcc, "%s\n", msanProlog)
|
2012-07-25 14:14:37 -07:00
|
|
|
|
2010-07-14 17:17:53 -07:00
|
|
|
for _, exp := range p.ExpFunc {
|
2010-04-09 13:31:05 -07:00
|
|
|
fn := exp.Func
|
|
|
|
|
|
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 <austin@google.com>
Run-TryBot: Austin Clements <austin@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Cherry Zhang <cherryyz@google.com>
2020-10-01 17:22:38 -04:00
|
|
|
// 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.
|
2010-07-14 17:17:53 -07:00
|
|
|
ctype := "struct {\n"
|
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 <austin@google.com>
Run-TryBot: Austin Clements <austin@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Cherry Zhang <cherryyz@google.com>
2020-10-01 17:22:38 -04:00
|
|
|
gotype := new(bytes.Buffer)
|
|
|
|
|
fmt.Fprintf(gotype, "struct {\n")
|
2010-04-09 13:31:05 -07:00
|
|
|
off := int64(0)
|
|
|
|
|
npad := 0
|
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 <austin@google.com>
Run-TryBot: Austin Clements <austin@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Cherry Zhang <cherryyz@google.com>
2020-10-01 17:22:38 -04:00
|
|
|
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")
|
2010-04-09 13:31:05 -07:00
|
|
|
off += t.Size
|
|
|
|
|
}
|
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 <austin@google.com>
Run-TryBot: Austin Clements <austin@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Cherry Zhang <cherryyz@google.com>
2020-10-01 17:22:38 -04:00
|
|
|
if fn.Recv != nil {
|
|
|
|
|
argField(fn.Recv.List[0].Type, "recv")
|
|
|
|
|
}
|
2010-04-09 13:31:05 -07:00
|
|
|
fntype := fn.Type
|
|
|
|
|
forFieldList(fntype.Params,
|
2015-08-03 09:25:33 -04:00
|
|
|
func(i int, aname string, atype ast.Expr) {
|
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 <austin@google.com>
Run-TryBot: Austin Clements <austin@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Cherry Zhang <cherryyz@google.com>
2020-10-01 17:22:38 -04:00
|
|
|
argField(atype, "p%d", i)
|
2010-04-09 13:31:05 -07:00
|
|
|
})
|
|
|
|
|
forFieldList(fntype.Results,
|
2015-08-03 09:25:33 -04:00
|
|
|
func(i int, aname string, atype ast.Expr) {
|
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 <austin@google.com>
Run-TryBot: Austin Clements <austin@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Cherry Zhang <cherryyz@google.com>
2020-10-01 17:22:38 -04:00
|
|
|
argField(atype, "r%d", i)
|
2010-04-09 13:31:05 -07:00
|
|
|
})
|
2010-07-14 17:17:53 -07:00
|
|
|
if ctype == "struct {\n" {
|
|
|
|
|
ctype += "\t\tchar unused;\n" // avoid empty struct
|
2010-04-09 13:31:05 -07:00
|
|
|
}
|
2010-07-14 17:17:53 -07:00
|
|
|
ctype += "\t}"
|
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 <austin@google.com>
Run-TryBot: Austin Clements <austin@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Cherry Zhang <cherryyz@google.com>
2020-10-01 17:22:38 -04:00
|
|
|
fmt.Fprintf(gotype, "\t}")
|
2010-04-09 13:31:05 -07:00
|
|
|
|
|
|
|
|
// Get the return type of the wrapper function
|
|
|
|
|
// compiled by gcc.
|
|
|
|
|
gccResult := ""
|
|
|
|
|
if fntype.Results == nil || len(fntype.Results.List) == 0 {
|
|
|
|
|
gccResult = "void"
|
|
|
|
|
} else if len(fntype.Results.List) == 1 && len(fntype.Results.List[0].Names) <= 1 {
|
cgo: fix dwarf type parsing
The recursive algorithm used to parse types in cgo
has a bug related to building the C type representation.
As an example, when the recursion starts at a type *T,
the C type representation won't be known until type T
itself is parsed. But then, it is possible that type T
references the type **T internally. The latter
representation is built based on the one of *T, which
started the recursion, so it won't attempt to parse it
again, and will instead use the current representation
value for *T, which is still empty at this point.
This problem was fixed by introducing a simple TypeRepr
type which builds the string representation lazily,
analogous to how the Go type information is built within
the same algorithm. This way, even if a type
representation is still unknown at some level in the
recursion, representations dependant on it can still
be created correctly.
R=rsc
CC=golang-dev
https://golang.org/cl/4244052
2011-03-06 18:05:57 -05:00
|
|
|
gccResult = p.cgoType(fntype.Results.List[0].Type).C.String()
|
2010-04-09 13:31:05 -07:00
|
|
|
} else {
|
|
|
|
|
fmt.Fprintf(fgcch, "\n/* Return type for %s */\n", exp.ExpName)
|
|
|
|
|
fmt.Fprintf(fgcch, "struct %s_return {\n", exp.ExpName)
|
|
|
|
|
forFieldList(fntype.Results,
|
2015-08-03 09:25:33 -04:00
|
|
|
func(i int, aname string, atype ast.Expr) {
|
|
|
|
|
fmt.Fprintf(fgcch, "\t%s r%d;", p.cgoType(atype).C, i)
|
|
|
|
|
if len(aname) > 0 {
|
|
|
|
|
fmt.Fprintf(fgcch, " /* %s */", aname)
|
|
|
|
|
}
|
|
|
|
|
fmt.Fprint(fgcch, "\n")
|
2010-04-09 13:31:05 -07:00
|
|
|
})
|
|
|
|
|
fmt.Fprintf(fgcch, "};\n")
|
|
|
|
|
gccResult = "struct " + exp.ExpName + "_return"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Build the wrapper function compiled by gcc.
|
2020-10-15 23:12:49 +02:00
|
|
|
gccExport := ""
|
|
|
|
|
if goos == "windows" {
|
2021-01-14 21:29:49 +01:00
|
|
|
gccExport = "__declspec(dllexport) "
|
2020-10-15 23:12:49 +02:00
|
|
|
}
|
2021-01-14 21:29:49 +01:00
|
|
|
s := fmt.Sprintf("%s%s %s(", gccExport, gccResult, exp.ExpName)
|
2010-04-09 13:31:05 -07:00
|
|
|
if fn.Recv != nil {
|
cgo: fix dwarf type parsing
The recursive algorithm used to parse types in cgo
has a bug related to building the C type representation.
As an example, when the recursion starts at a type *T,
the C type representation won't be known until type T
itself is parsed. But then, it is possible that type T
references the type **T internally. The latter
representation is built based on the one of *T, which
started the recursion, so it won't attempt to parse it
again, and will instead use the current representation
value for *T, which is still empty at this point.
This problem was fixed by introducing a simple TypeRepr
type which builds the string representation lazily,
analogous to how the Go type information is built within
the same algorithm. This way, even if a type
representation is still unknown at some level in the
recursion, representations dependant on it can still
be created correctly.
R=rsc
CC=golang-dev
https://golang.org/cl/4244052
2011-03-06 18:05:57 -05:00
|
|
|
s += p.cgoType(fn.Recv.List[0].Type).C.String()
|
2010-04-09 13:31:05 -07:00
|
|
|
s += " recv"
|
|
|
|
|
}
|
|
|
|
|
forFieldList(fntype.Params,
|
2015-08-03 09:25:33 -04:00
|
|
|
func(i int, aname string, atype ast.Expr) {
|
2010-04-09 13:31:05 -07:00
|
|
|
if i > 0 || fn.Recv != nil {
|
|
|
|
|
s += ", "
|
|
|
|
|
}
|
2020-03-10 00:22:01 +00:00
|
|
|
s += fmt.Sprintf("%s %s", p.cgoType(atype).C, exportParamName(aname, i))
|
2010-04-09 13:31:05 -07:00
|
|
|
})
|
|
|
|
|
s += ")"
|
2015-05-05 18:19:28 -07:00
|
|
|
|
|
|
|
|
if len(exp.Doc) > 0 {
|
|
|
|
|
fmt.Fprintf(fgcch, "\n%s", exp.Doc)
|
2020-03-07 05:44:31 +00:00
|
|
|
if !strings.HasSuffix(exp.Doc, "\n") {
|
|
|
|
|
fmt.Fprint(fgcch, "\n")
|
|
|
|
|
}
|
2015-05-05 18:19:28 -07:00
|
|
|
}
|
2020-03-07 05:44:31 +00:00
|
|
|
fmt.Fprintf(fgcch, "extern %s;\n", s)
|
2010-04-09 13:31:05 -07:00
|
|
|
|
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 <austin@google.com>
Run-TryBot: Austin Clements <austin@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Cherry Zhang <cherryyz@google.com>
2020-10-01 17:22:38 -04:00
|
|
|
fmt.Fprintf(fgcc, "extern void _cgoexp%s_%s(void *);\n", cPrefix, exp.ExpName)
|
2016-05-19 10:07:41 -07:00
|
|
|
fmt.Fprintf(fgcc, "\nCGO_NO_SANITIZE_THREAD")
|
2010-04-09 13:31:05 -07:00
|
|
|
fmt.Fprintf(fgcc, "\n%s\n", s)
|
|
|
|
|
fmt.Fprintf(fgcc, "{\n")
|
2016-04-27 14:18:29 -07:00
|
|
|
fmt.Fprintf(fgcc, "\t__SIZE_TYPE__ _cgo_ctxt = _cgo_wait_runtime_init_done();\n")
|
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 <austin@google.com>
Run-TryBot: Austin Clements <austin@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Cherry Zhang <cherryyz@google.com>
2020-10-01 17:22:38 -04:00
|
|
|
// 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.
|
2020-11-11 15:33:39 -05:00
|
|
|
//
|
|
|
|
|
// We use a local static variable to get the zeroed
|
|
|
|
|
// value of the argument type. This avoids including
|
|
|
|
|
// string.h for memset, and is also robust to C++
|
|
|
|
|
// types with constructors. Both GCC and LLVM optimize
|
|
|
|
|
// this into just zeroing _cgo_a.
|
|
|
|
|
fmt.Fprintf(fgcc, "\ttypedef %s %v _cgo_argtype;\n", ctype, p.packedAttribute())
|
|
|
|
|
fmt.Fprintf(fgcc, "\tstatic _cgo_argtype _cgo_zero;\n")
|
|
|
|
|
fmt.Fprintf(fgcc, "\t_cgo_argtype _cgo_a = _cgo_zero;\n")
|
2010-04-09 13:31:05 -07:00
|
|
|
if gccResult != "void" && (len(fntype.Results.List) > 1 || len(fntype.Results.List[0].Names) > 1) {
|
|
|
|
|
fmt.Fprintf(fgcc, "\t%s r;\n", gccResult)
|
|
|
|
|
}
|
|
|
|
|
if fn.Recv != nil {
|
2020-03-10 00:22:01 +00:00
|
|
|
fmt.Fprintf(fgcc, "\t_cgo_a.recv = recv;\n")
|
2010-04-09 13:31:05 -07:00
|
|
|
}
|
|
|
|
|
forFieldList(fntype.Params,
|
2015-08-03 09:25:33 -04:00
|
|
|
func(i int, aname string, atype ast.Expr) {
|
2020-03-10 00:22:01 +00:00
|
|
|
fmt.Fprintf(fgcc, "\t_cgo_a.p%d = %s;\n", i, exportParamName(aname, i))
|
2010-04-09 13:31:05 -07:00
|
|
|
})
|
2015-12-03 19:17:21 -08:00
|
|
|
fmt.Fprintf(fgcc, "\t_cgo_tsan_release();\n")
|
2020-03-10 00:22:01 +00:00
|
|
|
fmt.Fprintf(fgcc, "\tcrosscall2(_cgoexp%s_%s, &_cgo_a, %d, _cgo_ctxt);\n", cPrefix, exp.ExpName, off)
|
2015-12-03 19:17:21 -08:00
|
|
|
fmt.Fprintf(fgcc, "\t_cgo_tsan_acquire();\n")
|
2016-04-27 14:18:29 -07:00
|
|
|
fmt.Fprintf(fgcc, "\t_cgo_release_context(_cgo_ctxt);\n")
|
2010-04-09 13:31:05 -07:00
|
|
|
if gccResult != "void" {
|
|
|
|
|
if len(fntype.Results.List) == 1 && len(fntype.Results.List[0].Names) <= 1 {
|
2020-03-10 00:22:01 +00:00
|
|
|
fmt.Fprintf(fgcc, "\treturn _cgo_a.r0;\n")
|
2010-04-09 13:31:05 -07:00
|
|
|
} else {
|
|
|
|
|
forFieldList(fntype.Results,
|
2015-08-03 09:25:33 -04:00
|
|
|
func(i int, aname string, atype ast.Expr) {
|
2020-03-10 00:22:01 +00:00
|
|
|
fmt.Fprintf(fgcc, "\tr.r%d = _cgo_a.r%d;\n", i, i)
|
2010-04-09 13:31:05 -07:00
|
|
|
})
|
|
|
|
|
fmt.Fprintf(fgcc, "\treturn r;\n")
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
fmt.Fprintf(fgcc, "}\n")
|
|
|
|
|
|
2015-11-18 21:25:44 -08:00
|
|
|
// Build the wrapper function compiled by cmd/compile.
|
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 <austin@google.com>
Run-TryBot: Austin Clements <austin@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Cherry Zhang <cherryyz@google.com>
2020-10-01 17:22:38 -04:00
|
|
|
// This unpacks the argument struct above and calls the Go function.
|
cmd/cgo: put the real C function in the dynamic symbol table
In the past, cgo generated Go code and C code. The C code was linked
into a shared library. The Go code was built into an executable that
dynamically linked against that shared library. C wrappers were
exported from the shared library, and the Go code called them.
It was all a long time ago, but in order to permit C code to call back
into Go, somebody implemented #pragma dynexport (https://golang.org/cl/661043)
to export a Go symbol into the dynamic symbol table. Then that same
person added code to cgo to recognize //export comments
(https://golang.org/cl/853042). The //export comments were implemented
by generating C code, to be compiled by GCC, that would refer to C code,
to be compiled by 6c, that would call the Go code. The GCC code would
go into a shared library. The code compiled by 6c would be in the Go
executable. The GCC code needed to refer to the 6c code, so the 6c
function was marked with #pragma dynexport. The important point here is
that #pragma dynexport was used to expose an internal detail of the
implementation of an exported function, because at the time it was
necessary.
Moving forward to today, cgo no longer generates a shared library and 6c
no longer exists. It's still true that we have a function compiled by
GCC that refers to a wrapper function now written in Go. In the normal
case today we are doing an external link, and we use a
//go:cgo_export_static function to make the Go wrapper function visible
to the C code under a known name.
The #pragma dynexport statement has become a //go:cgo_export_dynamic
comment on the Go code. That comment only takes effect when doing
internal linking. The comment tells the linker to put the symbol in the
dynamic symbol table. That still makes sense for the now unusual case
of using internal linking with a shared library.
However, all the changes to this code have carefully preserved the
property that the //go:cgo_export_dynamic comment refers to an internal
detail of the implementation of an exported function. That was
necessary a long time ago, but no longer makes sense.
This CL changes the code to put the actual C-callable function into the
dynamic symbol table. I considered dropping the comment entirely, but
it turns out that there is even a test for this, so I preserved it.
Change-Id: I66a7958e366e5974363099bfaa6ba862ca327849
Reviewed-on: https://go-review.googlesource.com/17061
Run-TryBot: Ian Lance Taylor <iant@golang.org>
Reviewed-by: Minux Ma <minux@golang.org>
2015-11-19 10:23:20 -08:00
|
|
|
fmt.Fprintf(fgo2, "//go:cgo_export_dynamic %s\n", exp.ExpName)
|
2014-11-11 01:23:19 -05:00
|
|
|
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)
|
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 <austin@google.com>
Run-TryBot: Austin Clements <austin@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Cherry Zhang <cherryyz@google.com>
2020-10-01 17:22:38 -04:00
|
|
|
fmt.Fprintf(fgo2, "func _cgoexp%s_%s(a *%s) {\n", cPrefix, exp.ExpName, gotype)
|
2010-04-09 13:31:05 -07:00
|
|
|
|
2010-12-17 11:37:11 -08:00
|
|
|
fmt.Fprintf(fm, "int _cgoexp%s_%s;\n", cPrefix, exp.ExpName)
|
|
|
|
|
|
2015-11-18 21:25:44 -08:00
|
|
|
if gccResult != "void" {
|
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 <austin@google.com>
Run-TryBot: Austin Clements <austin@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Cherry Zhang <cherryyz@google.com>
2020-10-01 17:22:38 -04:00
|
|
|
// Write results back to frame.
|
|
|
|
|
fmt.Fprintf(fgo2, "\t")
|
2015-11-18 21:25:44 -08:00
|
|
|
forFieldList(fntype.Results,
|
2015-08-03 09:25:33 -04:00
|
|
|
func(i int, aname string, atype ast.Expr) {
|
2015-11-18 21:25:44 -08:00
|
|
|
if i > 0 {
|
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 <austin@google.com>
Run-TryBot: Austin Clements <austin@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Cherry Zhang <cherryyz@google.com>
2020-10-01 17:22:38 -04:00
|
|
|
fmt.Fprintf(fgo2, ", ")
|
2015-11-18 21:25:44 -08:00
|
|
|
}
|
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 <austin@google.com>
Run-TryBot: Austin Clements <austin@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Cherry Zhang <cherryyz@google.com>
2020-10-01 17:22:38 -04:00
|
|
|
fmt.Fprintf(fgo2, "a.r%d", i)
|
2010-04-09 13:31:05 -07:00
|
|
|
})
|
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 <austin@google.com>
Run-TryBot: Austin Clements <austin@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Cherry Zhang <cherryyz@google.com>
2020-10-01 17:22:38 -04:00
|
|
|
fmt.Fprintf(fgo2, " = ")
|
2015-11-18 21:25:44 -08:00
|
|
|
}
|
|
|
|
|
if fn.Recv != nil {
|
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 <austin@google.com>
Run-TryBot: Austin Clements <austin@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Cherry Zhang <cherryyz@google.com>
2020-10-01 17:22:38 -04:00
|
|
|
fmt.Fprintf(fgo2, "a.recv.")
|
2010-04-09 13:31:05 -07:00
|
|
|
}
|
2015-11-18 21:25:44 -08:00
|
|
|
fmt.Fprintf(fgo2, "%s(", exp.Func.Name)
|
|
|
|
|
forFieldList(fntype.Params,
|
|
|
|
|
func(i int, aname string, atype ast.Expr) {
|
|
|
|
|
if i > 0 {
|
|
|
|
|
fmt.Fprint(fgo2, ", ")
|
|
|
|
|
}
|
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 <austin@google.com>
Run-TryBot: Austin Clements <austin@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Cherry Zhang <cherryyz@google.com>
2020-10-01 17:22:38 -04:00
|
|
|
fmt.Fprintf(fgo2, "a.p%d", i)
|
2015-11-18 21:25:44 -08:00
|
|
|
})
|
|
|
|
|
fmt.Fprint(fgo2, ")\n")
|
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 <austin@google.com>
Run-TryBot: Austin Clements <austin@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Cherry Zhang <cherryyz@google.com>
2020-10-01 17:22:38 -04:00
|
|
|
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)
|
|
|
|
|
})
|
|
|
|
|
}
|
2015-11-18 21:25:44 -08:00
|
|
|
fmt.Fprint(fgo2, "}\n")
|
2010-04-09 13:31:05 -07:00
|
|
|
}
|
2015-05-07 12:58:43 -07:00
|
|
|
|
|
|
|
|
fmt.Fprintf(fgcch, "%s", gccExportHeaderEpilog)
|
2010-04-09 13:31:05 -07:00
|
|
|
}
|
|
|
|
|
|
2012-03-15 23:50:25 +01:00
|
|
|
// Write out the C header allowing C code to call exported gccgo functions.
|
2015-05-06 17:53:17 -07:00
|
|
|
func (p *Package) writeGccgoExports(fgo2, fm, fgcc, fgcch io.Writer) {
|
2012-11-01 11:21:30 -07:00
|
|
|
gccgoSymbolPrefix := p.gccgoSymbolPrefix()
|
2012-03-15 23:50:25 +01:00
|
|
|
|
2015-05-05 18:19:28 -07:00
|
|
|
p.writeExportHeader(fgcch)
|
2012-03-15 23:50:25 +01:00
|
|
|
|
2018-05-29 06:40:56 -07:00
|
|
|
fmt.Fprintf(fgcc, "/* Code generated by cmd/cgo; DO NOT EDIT. */\n\n")
|
2012-11-01 11:21:30 -07:00
|
|
|
fmt.Fprintf(fgcc, "#include \"_cgo_export.h\"\n")
|
2012-07-20 16:58:08 -07:00
|
|
|
|
2015-04-29 14:32:48 -07:00
|
|
|
fmt.Fprintf(fgcc, "%s\n", gccgoExportFileProlog)
|
2015-12-03 19:17:21 -08:00
|
|
|
fmt.Fprintf(fgcc, "%s\n", tsanProlog)
|
2018-07-03 22:10:58 -07:00
|
|
|
fmt.Fprintf(fgcc, "%s\n", msanProlog)
|
2015-04-29 14:32:48 -07:00
|
|
|
|
2012-03-15 23:50:25 +01:00
|
|
|
for _, exp := range p.ExpFunc {
|
|
|
|
|
fn := exp.Func
|
|
|
|
|
fntype := fn.Type
|
|
|
|
|
|
|
|
|
|
cdeclBuf := new(bytes.Buffer)
|
|
|
|
|
resultCount := 0
|
|
|
|
|
forFieldList(fntype.Results,
|
2015-08-03 09:25:33 -04:00
|
|
|
func(i int, aname string, atype ast.Expr) { resultCount++ })
|
2012-03-15 23:50:25 +01:00
|
|
|
switch resultCount {
|
|
|
|
|
case 0:
|
|
|
|
|
fmt.Fprintf(cdeclBuf, "void")
|
|
|
|
|
case 1:
|
|
|
|
|
forFieldList(fntype.Results,
|
2015-08-03 09:25:33 -04:00
|
|
|
func(i int, aname string, atype ast.Expr) {
|
2012-03-15 23:50:25 +01:00
|
|
|
t := p.cgoType(atype)
|
|
|
|
|
fmt.Fprintf(cdeclBuf, "%s", t.C)
|
|
|
|
|
})
|
|
|
|
|
default:
|
|
|
|
|
// Declare a result struct.
|
2015-05-05 18:19:28 -07:00
|
|
|
fmt.Fprintf(fgcch, "\n/* Return type for %s */\n", exp.ExpName)
|
2017-07-17 11:14:23 -05:00
|
|
|
fmt.Fprintf(fgcch, "struct %s_return {\n", exp.ExpName)
|
2012-03-15 23:50:25 +01:00
|
|
|
forFieldList(fntype.Results,
|
2015-08-03 09:25:33 -04:00
|
|
|
func(i int, aname string, atype ast.Expr) {
|
2012-03-15 23:50:25 +01:00
|
|
|
t := p.cgoType(atype)
|
2015-08-03 09:25:33 -04:00
|
|
|
fmt.Fprintf(fgcch, "\t%s r%d;", t.C, i)
|
|
|
|
|
if len(aname) > 0 {
|
|
|
|
|
fmt.Fprintf(fgcch, " /* %s */", aname)
|
|
|
|
|
}
|
|
|
|
|
fmt.Fprint(fgcch, "\n")
|
2012-03-15 23:50:25 +01:00
|
|
|
})
|
|
|
|
|
fmt.Fprintf(fgcch, "};\n")
|
2017-07-17 11:14:23 -05:00
|
|
|
fmt.Fprintf(cdeclBuf, "struct %s_return", exp.ExpName)
|
2012-03-15 23:50:25 +01:00
|
|
|
}
|
|
|
|
|
|
2012-11-01 11:21:30 -07:00
|
|
|
cRet := cdeclBuf.String()
|
|
|
|
|
|
|
|
|
|
cdeclBuf = new(bytes.Buffer)
|
|
|
|
|
fmt.Fprintf(cdeclBuf, "(")
|
|
|
|
|
if fn.Recv != nil {
|
|
|
|
|
fmt.Fprintf(cdeclBuf, "%s recv", p.cgoType(fn.Recv.List[0].Type).C.String())
|
|
|
|
|
}
|
2012-03-15 23:50:25 +01:00
|
|
|
// Function parameters.
|
|
|
|
|
forFieldList(fntype.Params,
|
2015-08-03 09:25:33 -04:00
|
|
|
func(i int, aname string, atype ast.Expr) {
|
2012-11-01 11:21:30 -07:00
|
|
|
if i > 0 || fn.Recv != nil {
|
2012-03-15 23:50:25 +01:00
|
|
|
fmt.Fprintf(cdeclBuf, ", ")
|
|
|
|
|
}
|
|
|
|
|
t := p.cgoType(atype)
|
|
|
|
|
fmt.Fprintf(cdeclBuf, "%s p%d", t.C, i)
|
|
|
|
|
})
|
|
|
|
|
fmt.Fprintf(cdeclBuf, ")")
|
2012-11-01 11:21:30 -07:00
|
|
|
cParams := cdeclBuf.String()
|
|
|
|
|
|
2015-05-05 18:19:28 -07:00
|
|
|
if len(exp.Doc) > 0 {
|
|
|
|
|
fmt.Fprintf(fgcch, "\n%s", exp.Doc)
|
|
|
|
|
}
|
|
|
|
|
|
2017-07-17 11:14:23 -05:00
|
|
|
fmt.Fprintf(fgcch, "extern %s %s%s;\n", cRet, exp.ExpName, cParams)
|
2015-09-26 18:37:06 -07:00
|
|
|
|
2014-04-29 08:53:38 -04:00
|
|
|
// We need to use a name that will be exported by the
|
|
|
|
|
// Go code; otherwise gccgo will make it static and we
|
|
|
|
|
// will not be able to link against it from the C
|
|
|
|
|
// code.
|
2012-11-01 11:21:30 -07:00
|
|
|
goName := "Cgoexp_" + exp.ExpName
|
2020-11-20 12:54:18 -08:00
|
|
|
fmt.Fprintf(fgcc, `extern %s %s %s __asm__("%s.%s");`, cRet, goName, cParams, gccgoSymbolPrefix, gccgoToSymbol(goName))
|
2015-09-26 18:37:06 -07:00
|
|
|
fmt.Fprint(fgcc, "\n")
|
2014-04-29 08:53:38 -04:00
|
|
|
|
2016-05-19 10:07:41 -07:00
|
|
|
fmt.Fprint(fgcc, "\nCGO_NO_SANITIZE_THREAD\n")
|
2012-11-01 11:21:30 -07:00
|
|
|
fmt.Fprintf(fgcc, "%s %s %s {\n", cRet, exp.ExpName, cParams)
|
2015-12-03 19:17:21 -08:00
|
|
|
if resultCount > 0 {
|
|
|
|
|
fmt.Fprintf(fgcc, "\t%s r;\n", cRet)
|
|
|
|
|
}
|
2015-04-29 14:32:48 -07:00
|
|
|
fmt.Fprintf(fgcc, "\tif(_cgo_wait_runtime_init_done)\n")
|
|
|
|
|
fmt.Fprintf(fgcc, "\t\t_cgo_wait_runtime_init_done();\n")
|
2015-12-03 19:17:21 -08:00
|
|
|
fmt.Fprintf(fgcc, "\t_cgo_tsan_release();\n")
|
2012-11-01 11:21:30 -07:00
|
|
|
fmt.Fprint(fgcc, "\t")
|
|
|
|
|
if resultCount > 0 {
|
2015-12-03 19:17:21 -08:00
|
|
|
fmt.Fprint(fgcc, "r = ")
|
2012-11-01 11:21:30 -07:00
|
|
|
}
|
|
|
|
|
fmt.Fprintf(fgcc, "%s(", goName)
|
|
|
|
|
if fn.Recv != nil {
|
|
|
|
|
fmt.Fprint(fgcc, "recv")
|
|
|
|
|
}
|
|
|
|
|
forFieldList(fntype.Params,
|
2015-08-03 09:25:33 -04:00
|
|
|
func(i int, aname string, atype ast.Expr) {
|
2012-11-01 11:21:30 -07:00
|
|
|
if i > 0 || fn.Recv != nil {
|
|
|
|
|
fmt.Fprintf(fgcc, ", ")
|
|
|
|
|
}
|
|
|
|
|
fmt.Fprintf(fgcc, "p%d", i)
|
|
|
|
|
})
|
|
|
|
|
fmt.Fprint(fgcc, ");\n")
|
2015-12-03 19:17:21 -08:00
|
|
|
fmt.Fprintf(fgcc, "\t_cgo_tsan_acquire();\n")
|
|
|
|
|
if resultCount > 0 {
|
|
|
|
|
fmt.Fprint(fgcc, "\treturn r;\n")
|
|
|
|
|
}
|
2012-11-01 11:21:30 -07:00
|
|
|
fmt.Fprint(fgcc, "}\n")
|
2012-03-15 23:50:25 +01:00
|
|
|
|
|
|
|
|
// Dummy declaration for _cgo_main.c
|
2020-11-20 12:54:18 -08:00
|
|
|
fmt.Fprintf(fm, `char %s[1] __asm__("%s.%s");`, goName, gccgoSymbolPrefix, gccgoToSymbol(goName))
|
2014-12-19 17:21:14 -08:00
|
|
|
fmt.Fprint(fm, "\n")
|
2012-11-01 11:21:30 -07:00
|
|
|
|
|
|
|
|
// For gccgo we use a wrapper function in Go, in order
|
|
|
|
|
// to call CgocallBack and CgocallBackDone.
|
|
|
|
|
|
|
|
|
|
// This code uses printer.Fprint, not conf.Fprint,
|
|
|
|
|
// because we don't want //line comments in the middle
|
|
|
|
|
// of the function types.
|
|
|
|
|
fmt.Fprint(fgo2, "\n")
|
|
|
|
|
fmt.Fprintf(fgo2, "func %s(", goName)
|
|
|
|
|
if fn.Recv != nil {
|
|
|
|
|
fmt.Fprint(fgo2, "recv ")
|
|
|
|
|
printer.Fprint(fgo2, fset, fn.Recv.List[0].Type)
|
|
|
|
|
}
|
|
|
|
|
forFieldList(fntype.Params,
|
2015-08-03 09:25:33 -04:00
|
|
|
func(i int, aname string, atype ast.Expr) {
|
2012-11-01 11:21:30 -07:00
|
|
|
if i > 0 || fn.Recv != nil {
|
|
|
|
|
fmt.Fprintf(fgo2, ", ")
|
|
|
|
|
}
|
|
|
|
|
fmt.Fprintf(fgo2, "p%d ", i)
|
|
|
|
|
printer.Fprint(fgo2, fset, atype)
|
|
|
|
|
})
|
|
|
|
|
fmt.Fprintf(fgo2, ")")
|
|
|
|
|
if resultCount > 0 {
|
|
|
|
|
fmt.Fprintf(fgo2, " (")
|
|
|
|
|
forFieldList(fntype.Results,
|
2015-08-03 09:25:33 -04:00
|
|
|
func(i int, aname string, atype ast.Expr) {
|
2012-11-01 11:21:30 -07:00
|
|
|
if i > 0 {
|
|
|
|
|
fmt.Fprint(fgo2, ", ")
|
|
|
|
|
}
|
|
|
|
|
printer.Fprint(fgo2, fset, atype)
|
|
|
|
|
})
|
|
|
|
|
fmt.Fprint(fgo2, ")")
|
|
|
|
|
}
|
|
|
|
|
fmt.Fprint(fgo2, " {\n")
|
|
|
|
|
fmt.Fprint(fgo2, "\tsyscall.CgocallBack()\n")
|
|
|
|
|
fmt.Fprint(fgo2, "\tdefer syscall.CgocallBackDone()\n")
|
|
|
|
|
fmt.Fprint(fgo2, "\t")
|
|
|
|
|
if resultCount > 0 {
|
|
|
|
|
fmt.Fprint(fgo2, "return ")
|
|
|
|
|
}
|
|
|
|
|
if fn.Recv != nil {
|
|
|
|
|
fmt.Fprint(fgo2, "recv.")
|
|
|
|
|
}
|
|
|
|
|
fmt.Fprintf(fgo2, "%s(", exp.Func.Name)
|
|
|
|
|
forFieldList(fntype.Params,
|
2015-08-03 09:25:33 -04:00
|
|
|
func(i int, aname string, atype ast.Expr) {
|
2012-11-01 11:21:30 -07:00
|
|
|
if i > 0 {
|
|
|
|
|
fmt.Fprint(fgo2, ", ")
|
|
|
|
|
}
|
|
|
|
|
fmt.Fprintf(fgo2, "p%d", i)
|
|
|
|
|
})
|
|
|
|
|
fmt.Fprint(fgo2, ")\n")
|
|
|
|
|
fmt.Fprint(fgo2, "}\n")
|
2012-03-15 23:50:25 +01:00
|
|
|
}
|
2015-05-07 12:58:43 -07:00
|
|
|
|
|
|
|
|
fmt.Fprintf(fgcch, "%s", gccExportHeaderEpilog)
|
2012-03-15 23:50:25 +01:00
|
|
|
}
|
|
|
|
|
|
2015-05-05 18:19:28 -07:00
|
|
|
// writeExportHeader writes out the start of the _cgo_export.h file.
|
|
|
|
|
func (p *Package) writeExportHeader(fgcch io.Writer) {
|
2018-05-29 06:40:56 -07:00
|
|
|
fmt.Fprintf(fgcch, "/* Code generated by cmd/cgo; DO NOT EDIT. */\n\n")
|
2015-05-05 18:19:28 -07:00
|
|
|
pkg := *importPath
|
|
|
|
|
if pkg == "" {
|
|
|
|
|
pkg = p.PackagePath
|
|
|
|
|
}
|
|
|
|
|
fmt.Fprintf(fgcch, "/* package %s */\n\n", pkg)
|
2017-10-13 18:26:10 -07:00
|
|
|
fmt.Fprintf(fgcch, "%s\n", builtinExportProlog)
|
2015-05-05 18:19:28 -07:00
|
|
|
|
2018-04-19 12:56:29 -07:00
|
|
|
// Remove absolute paths from #line comments in the preamble.
|
|
|
|
|
// They aren't useful for people using the header file,
|
|
|
|
|
// and they mean that the header files change based on the
|
|
|
|
|
// exact location of GOPATH.
|
|
|
|
|
re := regexp.MustCompile(`(?m)^(#line\s+[0-9]+\s+")[^"]*[/\\]([^"]*")`)
|
|
|
|
|
preamble := re.ReplaceAllString(p.Preamble, "$1$2")
|
|
|
|
|
|
2015-05-05 18:19:28 -07:00
|
|
|
fmt.Fprintf(fgcch, "/* Start of preamble from import \"C\" comments. */\n\n")
|
2018-04-19 12:56:29 -07:00
|
|
|
fmt.Fprintf(fgcch, "%s\n", preamble)
|
2015-05-05 18:19:28 -07:00
|
|
|
fmt.Fprintf(fgcch, "\n/* End of preamble from import \"C\" comments. */\n\n")
|
|
|
|
|
|
|
|
|
|
fmt.Fprintf(fgcch, "%s\n", p.gccExportHeaderProlog())
|
|
|
|
|
}
|
|
|
|
|
|
2020-11-20 12:54:18 -08:00
|
|
|
// gccgoToSymbol converts a name to a mangled symbol for gccgo.
|
|
|
|
|
func gccgoToSymbol(ppath string) string {
|
2020-10-02 16:03:37 -07:00
|
|
|
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)
|
|
|
|
|
}
|
2018-10-24 09:25:05 -04:00
|
|
|
}
|
2020-10-02 16:03:37 -07:00
|
|
|
return gccgoMangler(ppath)
|
2018-10-24 09:25:05 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Return the package prefix when using gccgo.
|
|
|
|
|
func (p *Package) gccgoSymbolPrefix() string {
|
|
|
|
|
if !*gccgo {
|
|
|
|
|
return ""
|
|
|
|
|
}
|
2012-11-01 11:21:30 -07:00
|
|
|
|
|
|
|
|
if *gccgopkgpath != "" {
|
2020-11-20 12:54:18 -08:00
|
|
|
return gccgoToSymbol(*gccgopkgpath)
|
2012-11-01 11:21:30 -07:00
|
|
|
}
|
|
|
|
|
if *gccgoprefix == "" && p.PackageName == "main" {
|
|
|
|
|
return "main"
|
|
|
|
|
}
|
2020-11-20 12:54:18 -08:00
|
|
|
prefix := gccgoToSymbol(*gccgoprefix)
|
2012-11-01 11:21:30 -07:00
|
|
|
if prefix == "" {
|
|
|
|
|
prefix = "go"
|
|
|
|
|
}
|
|
|
|
|
return prefix + "." + p.PackageName
|
|
|
|
|
}
|
|
|
|
|
|
2010-04-09 13:31:05 -07:00
|
|
|
// Call a function for each entry in an ast.FieldList, passing the
|
2015-08-03 09:25:33 -04:00
|
|
|
// index into the list, the name if any, and the type.
|
|
|
|
|
func forFieldList(fl *ast.FieldList, fn func(int, string, ast.Expr)) {
|
2010-04-09 13:31:05 -07:00
|
|
|
if fl == nil {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
i := 0
|
|
|
|
|
for _, r := range fl.List {
|
|
|
|
|
if r.Names == nil {
|
2015-08-03 09:25:33 -04:00
|
|
|
fn(i, "", r.Type)
|
2010-04-09 13:31:05 -07:00
|
|
|
i++
|
|
|
|
|
} else {
|
2015-08-03 09:25:33 -04:00
|
|
|
for _, n := range r.Names {
|
|
|
|
|
fn(i, n.Name, r.Type)
|
2010-04-09 13:31:05 -07:00
|
|
|
i++
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
cgo: fix dwarf type parsing
The recursive algorithm used to parse types in cgo
has a bug related to building the C type representation.
As an example, when the recursion starts at a type *T,
the C type representation won't be known until type T
itself is parsed. But then, it is possible that type T
references the type **T internally. The latter
representation is built based on the one of *T, which
started the recursion, so it won't attempt to parse it
again, and will instead use the current representation
value for *T, which is still empty at this point.
This problem was fixed by introducing a simple TypeRepr
type which builds the string representation lazily,
analogous to how the Go type information is built within
the same algorithm. This way, even if a type
representation is still unknown at some level in the
recursion, representations dependant on it can still
be created correctly.
R=rsc
CC=golang-dev
https://golang.org/cl/4244052
2011-03-06 18:05:57 -05:00
|
|
|
func c(repr string, args ...interface{}) *TypeRepr {
|
|
|
|
|
return &TypeRepr{repr, args}
|
|
|
|
|
}
|
|
|
|
|
|
2010-04-09 13:31:05 -07:00
|
|
|
// Map predeclared Go types to Type.
|
|
|
|
|
var goTypes = map[string]*Type{
|
2019-06-03 18:04:58 -07:00
|
|
|
"bool": {Size: 1, Align: 1, C: c("GoUint8")},
|
|
|
|
|
"byte": {Size: 1, Align: 1, C: c("GoUint8")},
|
2012-09-24 14:58:57 -04:00
|
|
|
"int": {Size: 0, Align: 0, C: c("GoInt")},
|
|
|
|
|
"uint": {Size: 0, Align: 0, C: c("GoUint")},
|
2019-06-03 18:04:58 -07:00
|
|
|
"rune": {Size: 4, Align: 4, C: c("GoInt32")},
|
|
|
|
|
"int8": {Size: 1, Align: 1, C: c("GoInt8")},
|
|
|
|
|
"uint8": {Size: 1, Align: 1, C: c("GoUint8")},
|
|
|
|
|
"int16": {Size: 2, Align: 2, C: c("GoInt16")},
|
|
|
|
|
"uint16": {Size: 2, Align: 2, C: c("GoUint16")},
|
|
|
|
|
"int32": {Size: 4, Align: 4, C: c("GoInt32")},
|
|
|
|
|
"uint32": {Size: 4, Align: 4, C: c("GoUint32")},
|
|
|
|
|
"int64": {Size: 8, Align: 8, C: c("GoInt64")},
|
|
|
|
|
"uint64": {Size: 8, Align: 8, C: c("GoUint64")},
|
2012-05-01 09:04:13 -07:00
|
|
|
"float32": {Size: 4, Align: 4, C: c("GoFloat32")},
|
|
|
|
|
"float64": {Size: 8, Align: 8, C: c("GoFloat64")},
|
2016-02-21 02:28:37 -08:00
|
|
|
"complex64": {Size: 8, Align: 4, C: c("GoComplex64")},
|
|
|
|
|
"complex128": {Size: 16, Align: 8, C: c("GoComplex128")},
|
2010-04-09 13:31:05 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Map an ast type to a Type.
|
2010-07-14 17:17:53 -07:00
|
|
|
func (p *Package) cgoType(e ast.Expr) *Type {
|
2010-04-09 13:31:05 -07:00
|
|
|
switch t := e.(type) {
|
|
|
|
|
case *ast.StarExpr:
|
|
|
|
|
x := p.cgoType(t.X)
|
cgo: fix dwarf type parsing
The recursive algorithm used to parse types in cgo
has a bug related to building the C type representation.
As an example, when the recursion starts at a type *T,
the C type representation won't be known until type T
itself is parsed. But then, it is possible that type T
references the type **T internally. The latter
representation is built based on the one of *T, which
started the recursion, so it won't attempt to parse it
again, and will instead use the current representation
value for *T, which is still empty at this point.
This problem was fixed by introducing a simple TypeRepr
type which builds the string representation lazily,
analogous to how the Go type information is built within
the same algorithm. This way, even if a type
representation is still unknown at some level in the
recursion, representations dependant on it can still
be created correctly.
R=rsc
CC=golang-dev
https://golang.org/cl/4244052
2011-03-06 18:05:57 -05:00
|
|
|
return &Type{Size: p.PtrSize, Align: p.PtrSize, C: c("%s*", x.C)}
|
2010-04-09 13:31:05 -07:00
|
|
|
case *ast.ArrayType:
|
|
|
|
|
if t.Len == nil {
|
2013-05-23 22:51:07 -07:00
|
|
|
// Slice: pointer, len, cap.
|
|
|
|
|
return &Type{Size: p.PtrSize * 3, Align: p.PtrSize, C: c("GoSlice")}
|
2010-04-09 13:31:05 -07:00
|
|
|
}
|
2017-08-02 12:30:58 -07:00
|
|
|
// Non-slice array types are not supported.
|
2010-04-09 13:31:05 -07:00
|
|
|
case *ast.StructType:
|
2017-08-02 12:30:58 -07:00
|
|
|
// Not supported.
|
2010-04-09 13:31:05 -07:00
|
|
|
case *ast.FuncType:
|
cgo: fix dwarf type parsing
The recursive algorithm used to parse types in cgo
has a bug related to building the C type representation.
As an example, when the recursion starts at a type *T,
the C type representation won't be known until type T
itself is parsed. But then, it is possible that type T
references the type **T internally. The latter
representation is built based on the one of *T, which
started the recursion, so it won't attempt to parse it
again, and will instead use the current representation
value for *T, which is still empty at this point.
This problem was fixed by introducing a simple TypeRepr
type which builds the string representation lazily,
analogous to how the Go type information is built within
the same algorithm. This way, even if a type
representation is still unknown at some level in the
recursion, representations dependant on it can still
be created correctly.
R=rsc
CC=golang-dev
https://golang.org/cl/4244052
2011-03-06 18:05:57 -05:00
|
|
|
return &Type{Size: p.PtrSize, Align: p.PtrSize, C: c("void*")}
|
2010-04-09 13:31:05 -07:00
|
|
|
case *ast.InterfaceType:
|
2011-12-20 09:28:45 -08:00
|
|
|
return &Type{Size: 2 * p.PtrSize, Align: p.PtrSize, C: c("GoInterface")}
|
2010-04-09 13:31:05 -07:00
|
|
|
case *ast.MapType:
|
cgo: fix dwarf type parsing
The recursive algorithm used to parse types in cgo
has a bug related to building the C type representation.
As an example, when the recursion starts at a type *T,
the C type representation won't be known until type T
itself is parsed. But then, it is possible that type T
references the type **T internally. The latter
representation is built based on the one of *T, which
started the recursion, so it won't attempt to parse it
again, and will instead use the current representation
value for *T, which is still empty at this point.
This problem was fixed by introducing a simple TypeRepr
type which builds the string representation lazily,
analogous to how the Go type information is built within
the same algorithm. This way, even if a type
representation is still unknown at some level in the
recursion, representations dependant on it can still
be created correctly.
R=rsc
CC=golang-dev
https://golang.org/cl/4244052
2011-03-06 18:05:57 -05:00
|
|
|
return &Type{Size: p.PtrSize, Align: p.PtrSize, C: c("GoMap")}
|
2010-04-09 13:31:05 -07:00
|
|
|
case *ast.ChanType:
|
cgo: fix dwarf type parsing
The recursive algorithm used to parse types in cgo
has a bug related to building the C type representation.
As an example, when the recursion starts at a type *T,
the C type representation won't be known until type T
itself is parsed. But then, it is possible that type T
references the type **T internally. The latter
representation is built based on the one of *T, which
started the recursion, so it won't attempt to parse it
again, and will instead use the current representation
value for *T, which is still empty at this point.
This problem was fixed by introducing a simple TypeRepr
type which builds the string representation lazily,
analogous to how the Go type information is built within
the same algorithm. This way, even if a type
representation is still unknown at some level in the
recursion, representations dependant on it can still
be created correctly.
R=rsc
CC=golang-dev
https://golang.org/cl/4244052
2011-03-06 18:05:57 -05:00
|
|
|
return &Type{Size: p.PtrSize, Align: p.PtrSize, C: c("GoChan")}
|
2010-04-09 13:31:05 -07:00
|
|
|
case *ast.Ident:
|
|
|
|
|
// Look up the type in the top level declarations.
|
|
|
|
|
// TODO: Handle types defined within a function.
|
2010-07-14 17:17:53 -07:00
|
|
|
for _, d := range p.Decl {
|
2010-04-09 13:31:05 -07:00
|
|
|
gd, ok := d.(*ast.GenDecl)
|
|
|
|
|
if !ok || gd.Tok != token.TYPE {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
for _, spec := range gd.Specs {
|
|
|
|
|
ts, ok := spec.(*ast.TypeSpec)
|
|
|
|
|
if !ok {
|
|
|
|
|
continue
|
|
|
|
|
}
|
2010-08-13 10:42:18 -07:00
|
|
|
if ts.Name.Name == t.Name {
|
2010-04-09 13:31:05 -07:00
|
|
|
return p.cgoType(ts.Type)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2012-02-19 13:32:55 -05:00
|
|
|
if def := typedef[t.Name]; def != nil {
|
|
|
|
|
return def
|
2010-04-09 13:31:05 -07:00
|
|
|
}
|
2010-08-13 10:42:18 -07:00
|
|
|
if t.Name == "uintptr" {
|
2012-05-01 09:04:13 -07:00
|
|
|
return &Type{Size: p.PtrSize, Align: p.PtrSize, C: c("GoUintptr")}
|
2010-04-09 13:31:05 -07:00
|
|
|
}
|
2010-08-13 10:42:18 -07:00
|
|
|
if t.Name == "string" {
|
2013-05-23 22:51:07 -07:00
|
|
|
// The string data is 1 pointer + 1 (pointer-sized) int.
|
2012-09-24 14:58:57 -04:00
|
|
|
return &Type{Size: 2 * p.PtrSize, Align: p.PtrSize, C: c("GoString")}
|
2010-04-09 13:31:05 -07:00
|
|
|
}
|
2011-12-20 09:28:45 -08:00
|
|
|
if t.Name == "error" {
|
|
|
|
|
return &Type{Size: 2 * p.PtrSize, Align: p.PtrSize, C: c("GoInterface")}
|
|
|
|
|
}
|
2010-08-13 10:42:18 -07:00
|
|
|
if r, ok := goTypes[t.Name]; ok {
|
2012-09-24 14:58:57 -04:00
|
|
|
if r.Size == 0 { // int or uint
|
|
|
|
|
rr := new(Type)
|
|
|
|
|
*rr = *r
|
|
|
|
|
rr.Size = p.IntSize
|
|
|
|
|
rr.Align = p.IntSize
|
|
|
|
|
r = rr
|
|
|
|
|
}
|
2010-04-09 13:31:05 -07:00
|
|
|
if r.Align > p.PtrSize {
|
|
|
|
|
r.Align = p.PtrSize
|
|
|
|
|
}
|
|
|
|
|
return r
|
|
|
|
|
}
|
2011-11-01 22:06:05 -04:00
|
|
|
error_(e.Pos(), "unrecognized Go type %s", t.Name)
|
2011-07-28 12:39:50 -04:00
|
|
|
return &Type{Size: 4, Align: 4, C: c("int")}
|
2011-01-11 11:12:06 -05:00
|
|
|
case *ast.SelectorExpr:
|
|
|
|
|
id, ok := t.X.(*ast.Ident)
|
|
|
|
|
if ok && id.Name == "unsafe" && t.Sel.Name == "Pointer" {
|
cgo: fix dwarf type parsing
The recursive algorithm used to parse types in cgo
has a bug related to building the C type representation.
As an example, when the recursion starts at a type *T,
the C type representation won't be known until type T
itself is parsed. But then, it is possible that type T
references the type **T internally. The latter
representation is built based on the one of *T, which
started the recursion, so it won't attempt to parse it
again, and will instead use the current representation
value for *T, which is still empty at this point.
This problem was fixed by introducing a simple TypeRepr
type which builds the string representation lazily,
analogous to how the Go type information is built within
the same algorithm. This way, even if a type
representation is still unknown at some level in the
recursion, representations dependant on it can still
be created correctly.
R=rsc
CC=golang-dev
https://golang.org/cl/4244052
2011-03-06 18:05:57 -05:00
|
|
|
return &Type{Size: p.PtrSize, Align: p.PtrSize, C: c("void*")}
|
2011-01-11 11:12:06 -05:00
|
|
|
}
|
2010-04-09 13:31:05 -07:00
|
|
|
}
|
2012-02-19 13:32:55 -05:00
|
|
|
error_(e.Pos(), "Go type not supported in export: %s", gofmt(e))
|
cgo: fix dwarf type parsing
The recursive algorithm used to parse types in cgo
has a bug related to building the C type representation.
As an example, when the recursion starts at a type *T,
the C type representation won't be known until type T
itself is parsed. But then, it is possible that type T
references the type **T internally. The latter
representation is built based on the one of *T, which
started the recursion, so it won't attempt to parse it
again, and will instead use the current representation
value for *T, which is still empty at this point.
This problem was fixed by introducing a simple TypeRepr
type which builds the string representation lazily,
analogous to how the Go type information is built within
the same algorithm. This way, even if a type
representation is still unknown at some level in the
recursion, representations dependant on it can still
be created correctly.
R=rsc
CC=golang-dev
https://golang.org/cl/4244052
2011-03-06 18:05:57 -05:00
|
|
|
return &Type{Size: 4, Align: 4, C: c("int")}
|
2010-04-09 13:31:05 -07:00
|
|
|
}
|
|
|
|
|
|
2009-09-24 11:43:19 -07:00
|
|
|
const gccProlog = `
|
2016-11-02 19:41:01 -04:00
|
|
|
#line 1 "cgo-gcc-prolog"
|
2015-08-06 11:45:53 -04:00
|
|
|
/*
|
|
|
|
|
If x and y are not equal, the type will be invalid
|
|
|
|
|
(have a negative array count) and an inscrutable error will come
|
|
|
|
|
out of the compiler and hopefully mention "name".
|
|
|
|
|
*/
|
2009-09-24 11:43:19 -07:00
|
|
|
#define __cgo_compile_assert_eq(x, y, name) typedef char name[(x-y)*(x-y)*-2+1];
|
|
|
|
|
|
2017-04-21 20:18:28 +09:00
|
|
|
/* Check at compile time that the sizes we use match our expectations. */
|
2009-09-24 11:43:19 -07:00
|
|
|
#define __cgo_size_assert(t, n) __cgo_compile_assert_eq(sizeof(t), n, _cgo_sizeof_##t##_is_not_##n)
|
|
|
|
|
|
|
|
|
|
__cgo_size_assert(char, 1)
|
|
|
|
|
__cgo_size_assert(short, 2)
|
|
|
|
|
__cgo_size_assert(int, 4)
|
|
|
|
|
typedef long long __cgo_long_long;
|
|
|
|
|
__cgo_size_assert(__cgo_long_long, 8)
|
|
|
|
|
__cgo_size_assert(float, 4)
|
|
|
|
|
__cgo_size_assert(double, 8)
|
2010-07-14 17:17:53 -07:00
|
|
|
|
2014-09-25 08:37:04 -07:00
|
|
|
extern char* _cgo_topofstack(void);
|
2014-09-25 07:59:01 -07:00
|
|
|
|
2019-03-07 08:33:01 +01:00
|
|
|
/*
|
|
|
|
|
We use packed structs, but they are always aligned.
|
|
|
|
|
The pragmas and address-of-packed-member are only recognized as warning
|
|
|
|
|
groups in clang 4.0+, so ignore unknown pragmas first.
|
|
|
|
|
*/
|
2019-02-01 13:51:31 +02:00
|
|
|
#pragma GCC diagnostic ignored "-Wunknown-pragmas"
|
2019-01-28 12:31:55 -08:00
|
|
|
#pragma GCC diagnostic ignored "-Wpragmas"
|
|
|
|
|
#pragma GCC diagnostic ignored "-Waddress-of-packed-member"
|
|
|
|
|
|
2010-07-14 17:17:53 -07:00
|
|
|
#include <errno.h>
|
|
|
|
|
#include <string.h>
|
2009-09-24 11:43:19 -07:00
|
|
|
`
|
|
|
|
|
|
2015-12-03 19:17:21 -08:00
|
|
|
// Prologue defining TSAN functions in C.
|
2016-05-02 14:46:40 +12:00
|
|
|
const noTsanProlog = `
|
2016-05-19 10:07:41 -07:00
|
|
|
#define CGO_NO_SANITIZE_THREAD
|
2015-12-03 19:17:21 -08:00
|
|
|
#define _cgo_tsan_acquire()
|
|
|
|
|
#define _cgo_tsan_release()
|
2016-05-02 14:46:40 +12:00
|
|
|
`
|
2015-12-03 19:17:21 -08:00
|
|
|
|
2016-05-26 17:47:03 -07:00
|
|
|
// This must match the TSAN code in runtime/cgo/libcgo.h.
|
2017-05-25 12:20:58 -07:00
|
|
|
// This is used when the code is built with the C/C++ Thread SANitizer,
|
|
|
|
|
// which is not the same as the Go race detector.
|
|
|
|
|
// __tsan_acquire tells TSAN that we are acquiring a lock on a variable,
|
|
|
|
|
// in this case _cgo_sync. __tsan_release releases the lock.
|
|
|
|
|
// (There is no actual lock, we are just telling TSAN that there is.)
|
|
|
|
|
//
|
|
|
|
|
// When we call from Go to C we call _cgo_tsan_acquire.
|
|
|
|
|
// When the C function returns we call _cgo_tsan_release.
|
|
|
|
|
// Similarly, when C calls back into Go we call _cgo_tsan_release
|
|
|
|
|
// and then call _cgo_tsan_acquire when we return to C.
|
|
|
|
|
// These calls tell TSAN that there is a serialization point at the C call.
|
|
|
|
|
//
|
|
|
|
|
// This is necessary because TSAN, which is a C/C++ tool, can not see
|
|
|
|
|
// the synchronization in the Go code. Without these calls, when
|
|
|
|
|
// multiple goroutines call into C code, TSAN does not understand
|
|
|
|
|
// that the calls are properly synchronized on the Go side.
|
|
|
|
|
//
|
|
|
|
|
// To be clear, if the calls are not properly synchronized on the Go side,
|
|
|
|
|
// we will be hiding races. But when using TSAN on mixed Go C/C++ code
|
|
|
|
|
// it is more important to avoid false positives, which reduce confidence
|
|
|
|
|
// in the tool, than to avoid false negatives.
|
2016-05-02 14:46:40 +12:00
|
|
|
const yesTsanProlog = `
|
2016-11-02 19:41:01 -04:00
|
|
|
#line 1 "cgo-tsan-prolog"
|
2016-05-19 10:07:41 -07:00
|
|
|
#define CGO_NO_SANITIZE_THREAD __attribute__ ((no_sanitize_thread))
|
|
|
|
|
|
2015-12-03 19:17:21 -08:00
|
|
|
long long _cgo_sync __attribute__ ((common));
|
|
|
|
|
|
|
|
|
|
extern void __tsan_acquire(void*);
|
|
|
|
|
extern void __tsan_release(void*);
|
|
|
|
|
|
2016-05-26 17:47:03 -07:00
|
|
|
__attribute__ ((unused))
|
2015-12-03 19:17:21 -08:00
|
|
|
static void _cgo_tsan_acquire() {
|
|
|
|
|
__tsan_acquire(&_cgo_sync);
|
|
|
|
|
}
|
|
|
|
|
|
2016-05-26 17:47:03 -07:00
|
|
|
__attribute__ ((unused))
|
2015-12-03 19:17:21 -08:00
|
|
|
static void _cgo_tsan_release() {
|
|
|
|
|
__tsan_release(&_cgo_sync);
|
|
|
|
|
}
|
|
|
|
|
`
|
|
|
|
|
|
2016-05-02 14:46:40 +12:00
|
|
|
// Set to yesTsanProlog if we see -fsanitize=thread in the flags for gcc.
|
|
|
|
|
var tsanProlog = noTsanProlog
|
|
|
|
|
|
2018-07-03 22:10:58 -07:00
|
|
|
// noMsanProlog is a prologue defining an MSAN function in C.
|
|
|
|
|
// This is used when not compiling with -fsanitize=memory.
|
|
|
|
|
const noMsanProlog = `
|
|
|
|
|
#define _cgo_msan_write(addr, sz)
|
|
|
|
|
`
|
|
|
|
|
|
|
|
|
|
// yesMsanProlog is a prologue defining an MSAN function in C.
|
|
|
|
|
// This is used when compiling with -fsanitize=memory.
|
|
|
|
|
// See the comment above where _cgo_msan_write is called.
|
|
|
|
|
const yesMsanProlog = `
|
|
|
|
|
extern void __msan_unpoison(const volatile void *, size_t);
|
|
|
|
|
|
|
|
|
|
#define _cgo_msan_write(addr, sz) __msan_unpoison((addr), (sz))
|
|
|
|
|
`
|
|
|
|
|
|
|
|
|
|
// msanProlog is set to yesMsanProlog if we see -fsanitize=memory in the flags
|
|
|
|
|
// for the C compiler.
|
|
|
|
|
var msanProlog = noMsanProlog
|
|
|
|
|
|
2009-09-24 11:43:19 -07:00
|
|
|
const builtinProlog = `
|
2016-11-02 19:41:01 -04:00
|
|
|
#line 1 "cgo-builtin-prolog"
|
2014-08-05 18:12:32 -07:00
|
|
|
#include <stddef.h> /* for ptrdiff_t and size_t below */
|
2013-09-11 11:30:08 -04:00
|
|
|
|
2013-05-23 22:51:07 -07:00
|
|
|
/* Define intgo when compiling with GCC. */
|
2014-08-05 18:12:32 -07:00
|
|
|
typedef ptrdiff_t intgo;
|
2013-05-23 22:51:07 -07:00
|
|
|
|
2018-11-30 14:21:33 -08:00
|
|
|
#define GO_CGO_GOSTRING_TYPEDEF
|
2017-10-13 18:26:10 -07:00
|
|
|
typedef struct { const char *p; intgo n; } _GoString_;
|
2013-05-23 22:51:07 -07:00
|
|
|
typedef struct { char *p; intgo n; intgo c; } _GoBytes_;
|
2009-09-24 11:43:19 -07:00
|
|
|
_GoString_ GoString(char *p);
|
2013-05-23 23:19:47 -07:00
|
|
|
_GoString_ GoStringN(char *p, int l);
|
|
|
|
|
_GoBytes_ GoBytes(void *p, int n);
|
2009-09-24 11:43:19 -07:00
|
|
|
char *CString(_GoString_);
|
2016-03-16 13:53:53 -04:00
|
|
|
void *CBytes(_GoBytes_);
|
2013-09-11 11:30:08 -04:00
|
|
|
void *_CMalloc(size_t);
|
2017-10-13 18:26:10 -07:00
|
|
|
|
|
|
|
|
__attribute__ ((unused))
|
2018-08-21 05:09:24 +00:00
|
|
|
static size_t _GoStringLen(_GoString_ s) { return (size_t)s.n; }
|
2017-10-13 18:26:10 -07:00
|
|
|
|
|
|
|
|
__attribute__ ((unused))
|
|
|
|
|
static const char *_GoStringPtr(_GoString_ s) { return s.p; }
|
2009-09-24 11:43:19 -07:00
|
|
|
`
|
|
|
|
|
|
2014-09-03 11:36:14 -04:00
|
|
|
const goProlog = `
|
2015-04-27 17:32:23 +10:00
|
|
|
//go:linkname _cgo_runtime_cgocall runtime.cgocall
|
|
|
|
|
func _cgo_runtime_cgocall(unsafe.Pointer, uintptr) int32
|
2014-11-11 01:23:19 -05:00
|
|
|
|
2015-10-16 15:26:00 -07:00
|
|
|
//go:linkname _cgoCheckPointer runtime.cgoCheckPointer
|
2019-10-01 18:12:55 +03:00
|
|
|
func _cgoCheckPointer(interface{}, interface{})
|
2015-11-18 21:25:44 -08:00
|
|
|
|
|
|
|
|
//go:linkname _cgoCheckResult runtime.cgoCheckResult
|
|
|
|
|
func _cgoCheckResult(interface{})
|
2014-09-03 11:36:14 -04:00
|
|
|
`
|
|
|
|
|
|
2015-12-04 12:56:04 -08:00
|
|
|
const gccgoGoProlog = `
|
2019-10-01 18:12:55 +03:00
|
|
|
func _cgoCheckPointer(interface{}, interface{})
|
2015-12-04 12:56:04 -08:00
|
|
|
|
|
|
|
|
func _cgoCheckResult(interface{})
|
|
|
|
|
`
|
|
|
|
|
|
2014-09-03 11:36:14 -04:00
|
|
|
const goStringDef = `
|
2014-11-11 01:23:19 -05:00
|
|
|
//go:linkname _cgo_runtime_gostring runtime.gostring
|
|
|
|
|
func _cgo_runtime_gostring(*_Ctype_char) string
|
|
|
|
|
|
2014-09-03 11:36:14 -04:00
|
|
|
func _Cfunc_GoString(p *_Ctype_char) string {
|
|
|
|
|
return _cgo_runtime_gostring(p)
|
2009-09-24 11:43:19 -07:00
|
|
|
}
|
2014-09-03 11:36:14 -04:00
|
|
|
`
|
2009-09-24 11:43:19 -07:00
|
|
|
|
2014-09-03 11:36:14 -04:00
|
|
|
const goStringNDef = `
|
2014-11-11 01:23:19 -05:00
|
|
|
//go:linkname _cgo_runtime_gostringn runtime.gostringn
|
|
|
|
|
func _cgo_runtime_gostringn(*_Ctype_char, int) string
|
|
|
|
|
|
2014-09-03 11:36:14 -04:00
|
|
|
func _Cfunc_GoStringN(p *_Ctype_char, l _Ctype_int) string {
|
|
|
|
|
return _cgo_runtime_gostringn(p, int(l))
|
2010-08-18 22:29:05 -04:00
|
|
|
}
|
2014-09-03 11:36:14 -04:00
|
|
|
`
|
2010-08-18 22:29:05 -04:00
|
|
|
|
2014-09-03 11:36:14 -04:00
|
|
|
const goBytesDef = `
|
2014-11-11 01:23:19 -05:00
|
|
|
//go:linkname _cgo_runtime_gobytes runtime.gobytes
|
|
|
|
|
func _cgo_runtime_gobytes(unsafe.Pointer, int) []byte
|
|
|
|
|
|
2014-09-03 11:36:14 -04:00
|
|
|
func _Cfunc_GoBytes(p unsafe.Pointer, l _Ctype_int) []byte {
|
|
|
|
|
return _cgo_runtime_gobytes(p, int(l))
|
2011-07-28 12:39:50 -04:00
|
|
|
}
|
2014-09-03 11:36:14 -04:00
|
|
|
`
|
2011-07-28 12:39:50 -04:00
|
|
|
|
2014-09-03 11:36:14 -04:00
|
|
|
const cStringDef = `
|
|
|
|
|
func _Cfunc_CString(s string) *_Ctype_char {
|
2016-05-19 16:27:23 -07:00
|
|
|
p := _cgo_cmalloc(uint64(len(s)+1))
|
2014-09-03 11:36:14 -04:00
|
|
|
pp := (*[1<<30]byte)(p)
|
|
|
|
|
copy(pp[:], s)
|
|
|
|
|
pp[len(s)] = 0
|
|
|
|
|
return (*_Ctype_char)(p)
|
2009-09-24 11:43:19 -07:00
|
|
|
}
|
2014-09-03 11:36:14 -04:00
|
|
|
`
|
2013-09-11 11:30:08 -04:00
|
|
|
|
2016-03-16 13:53:53 -04:00
|
|
|
const cBytesDef = `
|
|
|
|
|
func _Cfunc_CBytes(b []byte) unsafe.Pointer {
|
2016-05-19 16:27:23 -07:00
|
|
|
p := _cgo_cmalloc(uint64(len(b)))
|
2016-03-16 13:53:53 -04:00
|
|
|
pp := (*[1<<30]byte)(p)
|
|
|
|
|
copy(pp[:], b)
|
|
|
|
|
return p
|
|
|
|
|
}
|
|
|
|
|
`
|
|
|
|
|
|
2014-09-03 11:36:14 -04:00
|
|
|
const cMallocDef = `
|
|
|
|
|
func _Cfunc__CMalloc(n _Ctype_size_t) unsafe.Pointer {
|
2016-05-19 16:27:23 -07:00
|
|
|
return _cgo_cmalloc(uint64(n))
|
2013-09-11 11:30:08 -04:00
|
|
|
}
|
2009-09-24 11:43:19 -07:00
|
|
|
`
|
2010-04-09 13:31:05 -07:00
|
|
|
|
2014-09-03 11:36:14 -04:00
|
|
|
var builtinDefs = map[string]string{
|
|
|
|
|
"GoString": goStringDef,
|
|
|
|
|
"GoStringN": goStringNDef,
|
|
|
|
|
"GoBytes": goBytesDef,
|
|
|
|
|
"CString": cStringDef,
|
2016-03-16 13:53:53 -04:00
|
|
|
"CBytes": cBytesDef,
|
2014-09-03 11:36:14 -04:00
|
|
|
"_CMalloc": cMallocDef,
|
|
|
|
|
}
|
|
|
|
|
|
2016-05-19 16:27:23 -07:00
|
|
|
// Definitions for C.malloc in Go and in C. We define it ourselves
|
|
|
|
|
// since we call it from functions we define, such as C.CString.
|
|
|
|
|
// Also, we have historically ensured that C.malloc does not return
|
|
|
|
|
// nil even for an allocation of 0.
|
|
|
|
|
|
|
|
|
|
const cMallocDefGo = `
|
|
|
|
|
//go:cgo_import_static _cgoPREFIX_Cfunc__Cmalloc
|
|
|
|
|
//go:linkname __cgofn__cgoPREFIX_Cfunc__Cmalloc _cgoPREFIX_Cfunc__Cmalloc
|
|
|
|
|
var __cgofn__cgoPREFIX_Cfunc__Cmalloc byte
|
|
|
|
|
var _cgoPREFIX_Cfunc__Cmalloc = unsafe.Pointer(&__cgofn__cgoPREFIX_Cfunc__Cmalloc)
|
|
|
|
|
|
2016-10-24 10:19:04 -07:00
|
|
|
//go:linkname runtime_throw runtime.throw
|
|
|
|
|
func runtime_throw(string)
|
|
|
|
|
|
2016-05-19 16:27:23 -07:00
|
|
|
//go:cgo_unsafe_args
|
|
|
|
|
func _cgo_cmalloc(p0 uint64) (r1 unsafe.Pointer) {
|
|
|
|
|
_cgo_runtime_cgocall(_cgoPREFIX_Cfunc__Cmalloc, uintptr(unsafe.Pointer(&p0)))
|
2016-10-24 10:19:04 -07:00
|
|
|
if r1 == nil {
|
|
|
|
|
runtime_throw("runtime: C malloc failed")
|
|
|
|
|
}
|
2016-05-19 16:27:23 -07:00
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
`
|
|
|
|
|
|
|
|
|
|
// cMallocDefC defines the C version of C.malloc for the gc compiler.
|
|
|
|
|
// It is defined here because C.CString and friends need a definition.
|
|
|
|
|
// We define it by hand, rather than simply inventing a reference to
|
|
|
|
|
// C.malloc, because <stdlib.h> may not have been included.
|
|
|
|
|
// This is approximately what writeOutputFunc would generate, but
|
|
|
|
|
// skips the cgo_topofstack code (which is only needed if the C code
|
|
|
|
|
// calls back into Go). This also avoids returning nil for an
|
|
|
|
|
// allocation of 0 bytes.
|
|
|
|
|
const cMallocDefC = `
|
|
|
|
|
CGO_NO_SANITIZE_THREAD
|
|
|
|
|
void _cgoPREFIX_Cfunc__Cmalloc(void *v) {
|
|
|
|
|
struct {
|
|
|
|
|
unsigned long long p0;
|
|
|
|
|
void *r1;
|
|
|
|
|
} PACKED *a = v;
|
|
|
|
|
void *ret;
|
|
|
|
|
_cgo_tsan_acquire();
|
|
|
|
|
ret = malloc(a->p0);
|
|
|
|
|
if (ret == 0 && a->p0 == 0) {
|
|
|
|
|
ret = malloc(1);
|
|
|
|
|
}
|
|
|
|
|
a->r1 = ret;
|
|
|
|
|
_cgo_tsan_release();
|
|
|
|
|
}
|
|
|
|
|
`
|
|
|
|
|
|
2013-09-24 18:11:13 -07:00
|
|
|
func (p *Package) cPrologGccgo() string {
|
2020-11-20 12:54:18 -08:00
|
|
|
r := strings.NewReplacer(
|
|
|
|
|
"PREFIX", cPrefix,
|
|
|
|
|
"GCCGOSYMBOLPREF", p.gccgoSymbolPrefix(),
|
|
|
|
|
"_cgoCheckPointer", gccgoToSymbol("_cgoCheckPointer"),
|
|
|
|
|
"_cgoCheckResult", gccgoToSymbol("_cgoCheckResult"))
|
|
|
|
|
return r.Replace(cPrologGccgo)
|
2013-09-24 18:11:13 -07:00
|
|
|
}
|
|
|
|
|
|
2011-12-14 15:40:35 -08:00
|
|
|
const cPrologGccgo = `
|
2016-11-02 19:41:01 -04:00
|
|
|
#line 1 "cgo-c-prolog-gccgo"
|
2011-12-14 15:40:35 -08:00
|
|
|
#include <stdint.h>
|
2013-09-24 18:11:13 -07:00
|
|
|
#include <stdlib.h>
|
2011-12-14 15:40:35 -08:00
|
|
|
#include <string.h>
|
|
|
|
|
|
2012-11-01 11:21:30 -07:00
|
|
|
typedef unsigned char byte;
|
2013-01-09 15:25:46 -08:00
|
|
|
typedef intptr_t intgo;
|
2012-11-01 11:21:30 -07:00
|
|
|
|
2011-12-14 15:40:35 -08:00
|
|
|
struct __go_string {
|
|
|
|
|
const unsigned char *__data;
|
2013-01-09 15:25:46 -08:00
|
|
|
intgo __length;
|
2011-12-14 15:40:35 -08:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
typedef struct __go_open_array {
|
|
|
|
|
void* __values;
|
2013-01-09 15:25:46 -08:00
|
|
|
intgo __count;
|
|
|
|
|
intgo __capacity;
|
2011-12-14 15:40:35 -08:00
|
|
|
} Slice;
|
|
|
|
|
|
2013-01-09 15:25:46 -08:00
|
|
|
struct __go_string __go_byte_array_to_string(const void* p, intgo len);
|
2011-12-14 15:40:35 -08:00
|
|
|
struct __go_open_array __go_string_to_byte_array (struct __go_string str);
|
|
|
|
|
|
2013-09-24 18:11:13 -07:00
|
|
|
const char *_cgoPREFIX_Cfunc_CString(struct __go_string s) {
|
2014-04-26 22:16:38 -07:00
|
|
|
char *p = malloc(s.__length+1);
|
|
|
|
|
memmove(p, s.__data, s.__length);
|
|
|
|
|
p[s.__length] = 0;
|
|
|
|
|
return p;
|
2011-12-14 15:40:35 -08:00
|
|
|
}
|
|
|
|
|
|
2016-03-16 13:53:53 -04:00
|
|
|
void *_cgoPREFIX_Cfunc_CBytes(struct __go_open_array b) {
|
|
|
|
|
char *p = malloc(b.__count);
|
2016-04-08 14:27:35 +12:00
|
|
|
memmove(p, b.__values, b.__count);
|
2016-03-16 13:53:53 -04:00
|
|
|
return p;
|
|
|
|
|
}
|
|
|
|
|
|
2013-09-24 18:11:13 -07:00
|
|
|
struct __go_string _cgoPREFIX_Cfunc_GoString(char *p) {
|
2013-01-09 15:25:46 -08:00
|
|
|
intgo len = (p != NULL) ? strlen(p) : 0;
|
2012-01-27 09:36:53 +01:00
|
|
|
return __go_byte_array_to_string(p, len);
|
2011-12-14 15:40:35 -08:00
|
|
|
}
|
|
|
|
|
|
2013-09-24 18:11:13 -07:00
|
|
|
struct __go_string _cgoPREFIX_Cfunc_GoStringN(char *p, int32_t n) {
|
2011-12-14 15:40:35 -08:00
|
|
|
return __go_byte_array_to_string(p, n);
|
|
|
|
|
}
|
|
|
|
|
|
2013-09-24 18:11:13 -07:00
|
|
|
Slice _cgoPREFIX_Cfunc_GoBytes(char *p, int32_t n) {
|
2012-02-14 20:23:45 +01:00
|
|
|
struct __go_string s = { (const unsigned char *)p, n };
|
2011-12-14 15:40:35 -08:00
|
|
|
return __go_string_to_byte_array(s);
|
|
|
|
|
}
|
2013-09-11 11:30:08 -04:00
|
|
|
|
2013-09-24 18:11:13 -07:00
|
|
|
extern void runtime_throw(const char *);
|
|
|
|
|
void *_cgoPREFIX_Cfunc__CMalloc(size_t n) {
|
2013-09-11 11:30:08 -04:00
|
|
|
void *p = malloc(n);
|
2013-09-16 14:04:55 -04:00
|
|
|
if(p == NULL && n == 0)
|
|
|
|
|
p = malloc(1);
|
2013-09-11 11:30:08 -04:00
|
|
|
if(p == NULL)
|
|
|
|
|
runtime_throw("runtime: C malloc failed");
|
|
|
|
|
return p;
|
|
|
|
|
}
|
2015-12-04 12:56:04 -08:00
|
|
|
|
|
|
|
|
struct __go_type_descriptor;
|
|
|
|
|
typedef struct __go_empty_interface {
|
|
|
|
|
const struct __go_type_descriptor *__type_descriptor;
|
|
|
|
|
void *__object;
|
|
|
|
|
} Eface;
|
|
|
|
|
|
2019-10-01 18:12:55 +03:00
|
|
|
extern void runtimeCgoCheckPointer(Eface, Eface)
|
2015-12-04 12:56:04 -08:00
|
|
|
__asm__("runtime.cgoCheckPointer")
|
|
|
|
|
__attribute__((weak));
|
|
|
|
|
|
2019-10-01 18:12:55 +03:00
|
|
|
extern void localCgoCheckPointer(Eface, Eface)
|
2015-12-04 12:56:04 -08:00
|
|
|
__asm__("GCCGOSYMBOLPREF._cgoCheckPointer");
|
|
|
|
|
|
2019-10-01 18:12:55 +03:00
|
|
|
void localCgoCheckPointer(Eface ptr, Eface arg) {
|
2015-12-04 12:56:04 -08:00
|
|
|
if(runtimeCgoCheckPointer) {
|
2019-10-01 18:12:55 +03:00
|
|
|
runtimeCgoCheckPointer(ptr, arg);
|
2015-12-04 12:56:04 -08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
extern void runtimeCgoCheckResult(Eface)
|
|
|
|
|
__asm__("runtime.cgoCheckResult")
|
|
|
|
|
__attribute__((weak));
|
|
|
|
|
|
|
|
|
|
extern void localCgoCheckResult(Eface)
|
|
|
|
|
__asm__("GCCGOSYMBOLPREF._cgoCheckResult");
|
|
|
|
|
|
|
|
|
|
void localCgoCheckResult(Eface val) {
|
|
|
|
|
if(runtimeCgoCheckResult) {
|
|
|
|
|
runtimeCgoCheckResult(val);
|
|
|
|
|
}
|
|
|
|
|
}
|
2011-12-14 15:40:35 -08:00
|
|
|
`
|
|
|
|
|
|
2017-10-13 18:26:10 -07:00
|
|
|
// builtinExportProlog is a shorter version of builtinProlog,
|
|
|
|
|
// to be put into the _cgo_export.h file.
|
|
|
|
|
// For historical reasons we can't use builtinProlog in _cgo_export.h,
|
|
|
|
|
// because _cgo_export.h defines GoString as a struct while builtinProlog
|
|
|
|
|
// defines it as a function. We don't change this to avoid unnecessarily
|
|
|
|
|
// breaking existing code.
|
2018-11-30 14:21:33 -08:00
|
|
|
// The test of GO_CGO_GOSTRING_TYPEDEF avoids a duplicate definition
|
|
|
|
|
// error if a Go file with a cgo comment #include's the export header
|
|
|
|
|
// generated by a different package.
|
2017-10-13 18:26:10 -07:00
|
|
|
const builtinExportProlog = `
|
2018-11-30 14:21:33 -08:00
|
|
|
#line 1 "cgo-builtin-export-prolog"
|
2017-10-13 18:26:10 -07:00
|
|
|
|
|
|
|
|
#include <stddef.h> /* for ptrdiff_t below */
|
|
|
|
|
|
|
|
|
|
#ifndef GO_CGO_EXPORT_PROLOGUE_H
|
|
|
|
|
#define GO_CGO_EXPORT_PROLOGUE_H
|
|
|
|
|
|
2018-11-30 14:21:33 -08:00
|
|
|
#ifndef GO_CGO_GOSTRING_TYPEDEF
|
2017-12-13 17:29:28 -08:00
|
|
|
typedef struct { const char *p; ptrdiff_t n; } _GoString_;
|
2018-11-30 14:21:33 -08:00
|
|
|
#endif
|
2017-10-13 18:26:10 -07:00
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
`
|
|
|
|
|
|
2012-09-24 14:58:57 -04:00
|
|
|
func (p *Package) gccExportHeaderProlog() string {
|
|
|
|
|
return strings.Replace(gccExportHeaderProlog, "GOINTBITS", fmt.Sprint(8*p.IntSize), -1)
|
|
|
|
|
}
|
|
|
|
|
|
2018-11-30 14:21:33 -08:00
|
|
|
// gccExportHeaderProlog is written to the exported header, after the
|
|
|
|
|
// import "C" comment preamble but before the generated declarations
|
|
|
|
|
// of exported functions. This permits the generated declarations to
|
|
|
|
|
// use the type names that appear in goTypes, above.
|
|
|
|
|
//
|
|
|
|
|
// The test of GO_CGO_GOSTRING_TYPEDEF avoids a duplicate definition
|
|
|
|
|
// error if a Go file with a cgo comment #include's the export header
|
|
|
|
|
// generated by a different package. Unfortunately GoString means two
|
|
|
|
|
// different things: in this prolog it means a C name for the Go type,
|
|
|
|
|
// while in the prolog written into the start of the C code generated
|
|
|
|
|
// from a cgo-using Go file it means the C.GoString function. There is
|
|
|
|
|
// no way to resolve this conflict, but it also doesn't make much
|
|
|
|
|
// difference, as Go code never wants to refer to the latter meaning.
|
2010-04-09 13:31:05 -07:00
|
|
|
const gccExportHeaderProlog = `
|
2015-05-05 18:19:28 -07:00
|
|
|
/* Start of boilerplate cgo prologue. */
|
2016-11-02 19:41:01 -04:00
|
|
|
#line 1 "cgo-gcc-export-header-prolog"
|
2015-05-05 18:19:28 -07:00
|
|
|
|
2015-05-06 16:25:15 -07:00
|
|
|
#ifndef GO_CGO_PROLOGUE_H
|
|
|
|
|
#define GO_CGO_PROLOGUE_H
|
|
|
|
|
|
2019-06-03 18:04:58 -07:00
|
|
|
typedef signed char GoInt8;
|
|
|
|
|
typedef unsigned char GoUint8;
|
|
|
|
|
typedef short GoInt16;
|
|
|
|
|
typedef unsigned short GoUint16;
|
|
|
|
|
typedef int GoInt32;
|
|
|
|
|
typedef unsigned int GoUint32;
|
|
|
|
|
typedef long long GoInt64;
|
|
|
|
|
typedef unsigned long long GoUint64;
|
|
|
|
|
typedef GoIntGOINTBITS GoInt;
|
|
|
|
|
typedef GoUintGOINTBITS GoUint;
|
2012-05-01 09:04:13 -07:00
|
|
|
typedef __SIZE_TYPE__ GoUintptr;
|
|
|
|
|
typedef float GoFloat32;
|
|
|
|
|
typedef double GoFloat64;
|
2015-12-10 19:38:14 -08:00
|
|
|
typedef float _Complex GoComplex64;
|
|
|
|
|
typedef double _Complex GoComplex128;
|
2010-04-09 13:31:05 -07:00
|
|
|
|
2015-08-06 11:45:53 -04:00
|
|
|
/*
|
|
|
|
|
static assertion to make sure the file is being used on architecture
|
|
|
|
|
at least with matching size of GoInt.
|
|
|
|
|
*/
|
2015-02-05 14:16:13 -05:00
|
|
|
typedef char _check_for_GOINTBITS_bit_pointer_matching_GoInt[sizeof(void*)==GOINTBITS/8 ? 1:-1];
|
|
|
|
|
|
2018-11-30 14:21:33 -08:00
|
|
|
#ifndef GO_CGO_GOSTRING_TYPEDEF
|
2017-10-13 18:26:10 -07:00
|
|
|
typedef _GoString_ GoString;
|
2018-11-30 14:21:33 -08:00
|
|
|
#endif
|
2010-04-09 13:31:05 -07:00
|
|
|
typedef void *GoMap;
|
|
|
|
|
typedef void *GoChan;
|
|
|
|
|
typedef struct { void *t; void *v; } GoInterface;
|
2013-05-23 22:51:07 -07:00
|
|
|
typedef struct { void *data; GoInt len; GoInt cap; } GoSlice;
|
2015-05-05 18:19:28 -07:00
|
|
|
|
2015-05-06 16:25:15 -07:00
|
|
|
#endif
|
|
|
|
|
|
2015-05-05 18:19:28 -07:00
|
|
|
/* End of boilerplate cgo prologue. */
|
2015-05-07 12:58:43 -07:00
|
|
|
|
|
|
|
|
#ifdef __cplusplus
|
|
|
|
|
extern "C" {
|
|
|
|
|
#endif
|
|
|
|
|
`
|
|
|
|
|
|
|
|
|
|
// gccExportHeaderEpilog goes at the end of the generated header file.
|
|
|
|
|
const gccExportHeaderEpilog = `
|
|
|
|
|
#ifdef __cplusplus
|
|
|
|
|
}
|
|
|
|
|
#endif
|
2010-04-09 13:31:05 -07:00
|
|
|
`
|
2015-04-29 14:32:48 -07:00
|
|
|
|
|
|
|
|
// gccgoExportFileProlog is written to the _cgo_export.c file when
|
|
|
|
|
// using gccgo.
|
|
|
|
|
// We use weak declarations, and test the addresses, so that this code
|
|
|
|
|
// works with older versions of gccgo.
|
|
|
|
|
const gccgoExportFileProlog = `
|
2016-11-02 19:41:01 -04:00
|
|
|
#line 1 "cgo-gccgo-export-file-prolog"
|
2015-04-29 14:32:48 -07:00
|
|
|
extern _Bool runtime_iscgo __attribute__ ((weak));
|
|
|
|
|
|
|
|
|
|
static void GoInit(void) __attribute__ ((constructor));
|
|
|
|
|
static void GoInit(void) {
|
|
|
|
|
if(&runtime_iscgo)
|
|
|
|
|
runtime_iscgo = 1;
|
|
|
|
|
}
|
|
|
|
|
|
2019-01-23 20:14:30 +00:00
|
|
|
extern __SIZE_TYPE__ _cgo_wait_runtime_init_done(void) __attribute__ ((weak));
|
2015-04-29 14:32:48 -07:00
|
|
|
`
|