1 // Copyright 2009 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
25 conf
= printer
.Config
{Mode
: printer
.SourcePos
, Tabwidth
: 8}
26 noSourceConf
= printer
.Config
{Tabwidth
: 8}
29 // writeDefs creates output files to be compiled by gc and gcc.
30 func (p
*Package
) writeDefs() {
31 var fgo2
, fc io
.Writer
32 f
:= creat(*objDir
+ "_cgo_gotypes.go")
36 f
:= creat(*objDir
+ "_cgo_defun.c")
40 fm
:= creat(*objDir
+ "_cgo_main.c")
42 var gccgoInit bytes
.Buffer
44 fflg
:= creat(*objDir
+ "_cgo_flags")
46 for k
, v
:= range p
.CgoFlags
{
47 flags
= append(flags
, fmt
.Sprintf("_CGO_%s=%s", k
, strings
.Join(v
, " ")))
48 if k
== "LDFLAGS" && !*gccgo
{
49 for _
, arg
:= range v
{
50 fmt
.Fprintf(fgo2
, "//go:cgo_ldflag %q\n", arg
)
55 for _
, flag
:= range flags
{
56 fmt
.Fprintln(fflg
, flag
)
60 // Write C main file for using gcc to resolve imports.
61 fmt
.Fprintf(fm
, "int main() { return 0; }\n")
62 if *importRuntimeCgo
{
63 fmt
.Fprintf(fm
, "void crosscall2(void(*fn)(void*, int, __SIZE_TYPE__), void *a, int c, __SIZE_TYPE__ ctxt) { }\n")
64 fmt
.Fprintf(fm
, "__SIZE_TYPE__ _cgo_wait_runtime_init_done() { return 0; }\n")
65 fmt
.Fprintf(fm
, "void _cgo_release_context(__SIZE_TYPE__ ctxt) { }\n")
66 fmt
.Fprintf(fm
, "char* _cgo_topofstack(void) { return (char*)0; }\n")
68 // If we're not importing runtime/cgo, we *are* runtime/cgo,
69 // which provides these functions. We just need a prototype.
70 fmt
.Fprintf(fm
, "void crosscall2(void(*fn)(void*, int, __SIZE_TYPE__), void *a, int c, __SIZE_TYPE__ ctxt);\n")
71 fmt
.Fprintf(fm
, "__SIZE_TYPE__ _cgo_wait_runtime_init_done();\n")
72 fmt
.Fprintf(fm
, "void _cgo_release_context(__SIZE_TYPE__);\n")
74 fmt
.Fprintf(fm
, "void _cgo_allocate(void *a, int c) { }\n")
75 fmt
.Fprintf(fm
, "void _cgo_panic(void *a, int c) { }\n")
76 fmt
.Fprintf(fm
, "void _cgo_reginit(void) { }\n")
78 // Write second Go output: definitions of _C_xxx.
79 // In a separate file so that the import of "unsafe" does not
80 // pollute the original file.
81 fmt
.Fprintf(fgo2
, "// Created by cgo - DO NOT EDIT\n\n")
82 fmt
.Fprintf(fgo2
, "package %s\n\n", p
.PackageName
)
83 fmt
.Fprintf(fgo2
, "import \"unsafe\"\n\n")
84 if !*gccgo
&& *importRuntimeCgo
{
85 fmt
.Fprintf(fgo2
, "import _ \"runtime/cgo\"\n\n")
88 fmt
.Fprintf(fgo2
, "import \"syscall\"\n\n")
89 fmt
.Fprintf(fgo2
, "var _ syscall.Errno\n")
91 fmt
.Fprintf(fgo2
, "func _Cgo_ptr(ptr unsafe.Pointer) unsafe.Pointer { return ptr }\n\n")
94 fmt
.Fprintf(fgo2
, "//go:linkname _Cgo_always_false runtime.cgoAlwaysFalse\n")
95 fmt
.Fprintf(fgo2
, "var _Cgo_always_false bool\n")
96 fmt
.Fprintf(fgo2
, "//go:linkname _Cgo_use runtime.cgoUse\n")
97 fmt
.Fprintf(fgo2
, "func _Cgo_use(interface{})\n")
100 typedefNames
:= make([]string, 0, len(typedef
))
101 for name
:= range typedef
{
102 typedefNames
= append(typedefNames
, name
)
104 sort
.Strings(typedefNames
)
105 for _
, name
:= range typedefNames
{
107 fmt
.Fprintf(fgo2
, "type %s ", name
)
108 // We don't have source info for these types, so write them out without source info.
109 // Otherwise types would look like:
111 // type _Ctype_struct_cb struct {
117 // Which is not useful. Moreover we never override source info,
118 // so subsequent source code uses the same source info.
119 // Moreover, empty file name makes compile emit no source debug info at all.
121 noSourceConf
.Fprint(&buf
, fset
, def
.Go
)
122 if bytes
.HasPrefix(buf
.Bytes(), []byte("_Ctype_")) {
123 // This typedef is of the form `typedef a b` and should be an alias.
124 fmt
.Fprintf(fgo2
, "= ")
126 fmt
.Fprintf(fgo2
, "%s", buf
.Bytes())
127 fmt
.Fprintf(fgo2
, "\n\n")
130 fmt
.Fprintf(fgo2
, "type _Ctype_void byte\n")
132 fmt
.Fprintf(fgo2
, "type _Ctype_void [0]byte\n")
136 fmt
.Fprint(fgo2
, gccgoGoProlog
)
137 fmt
.Fprint(fc
, p
.cPrologGccgo())
139 fmt
.Fprint(fgo2
, goProlog
)
143 fmt
.Fprintf(fc
, "#line 1 \"cgo-generated-wrappers\"\n")
146 fmt
.Fprintf(fm
, "#line 1 \"cgo-generated-wrappers\"\n")
149 gccgoSymbolPrefix
:= p
.gccgoSymbolPrefix()
151 cVars
:= make(map[string]bool)
152 for _
, key
:= range nameKeys(p
.Name
) {
160 fmt
.Fprintf(fc
, "extern byte *%s;\n", n
.C
)
162 fmt
.Fprintf(fm
, "extern char %s[];\n", n
.C
)
163 fmt
.Fprintf(fm
, "void *_cgohack_%s = %s;\n\n", n
.C
, n
.C
)
164 fmt
.Fprintf(fgo2
, "//go:linkname __cgo_%s %s\n", n
.C
, n
.C
)
165 fmt
.Fprintf(fgo2
, "//go:cgo_import_static %s\n", n
.C
)
166 fmt
.Fprintf(fgo2
, "var __cgo_%s byte\n", n
.C
)
173 node
= &ast
.StarExpr
{X
: n
.Type
.Go
}
174 } else if n
.Kind
== "fpvar" {
177 panic(fmt
.Errorf("invalid var kind %q", n
.Kind
))
180 fmt
.Fprintf(fc
, `extern void *%s __asm__("%s.%s");`, n
.Mangle
, gccgoSymbolPrefix
, n
.Mangle
)
181 fmt
.Fprintf(&gccgoInit
, "\t%s = &%s;\n", n
.Mangle
, n
.C
)
182 fmt
.Fprintf(fc
, "\n")
185 fmt
.Fprintf(fgo2
, "var %s ", n
.Mangle
)
186 conf
.Fprint(fgo2
, fset
, node
)
188 fmt
.Fprintf(fgo2
, " = (")
189 conf
.Fprint(fgo2
, fset
, node
)
190 fmt
.Fprintf(fgo2
, ")(unsafe.Pointer(&__cgo_%s))", n
.C
)
192 fmt
.Fprintf(fgo2
, "\n")
195 fmt
.Fprintf(fc
, "\n")
198 for _
, key
:= range nameKeys(p
.Name
) {
201 fmt
.Fprintf(fgo2
, "const %s = %s\n", n
.Mangle
, n
.Const
)
204 fmt
.Fprintf(fgo2
, "\n")
207 for _
, key
:= range nameKeys(p
.Name
) {
209 if n
.FuncType
!= nil {
210 p
.writeDefsFunc(fgo2
, n
, &callsMalloc
)
214 fgcc
:= creat(*objDir
+ "_cgo_export.c")
215 fgcch
:= creat(*objDir
+ "_cgo_export.h")
217 p
.writeGccgoExports(fgo2
, fm
, fgcc
, fgcch
)
219 p
.writeExports(fgo2
, fm
, fgcc
, fgcch
)
222 if callsMalloc
&& !*gccgo
{
223 fmt
.Fprint(fgo2
, strings
.Replace(cMallocDefGo
, "PREFIX", cPrefix
, -1))
224 fmt
.Fprint(fgcc
, strings
.Replace(strings
.Replace(cMallocDefC
, "PREFIX", cPrefix
, -1), "PACKED", p
.packedAttribute(), -1))
227 if err
:= fgcc
.Close(); err
!= nil {
230 if err
:= fgcch
.Close(); err
!= nil {
234 if *exportHeader
!= "" && len(p
.ExpFunc
) > 0 {
235 fexp
:= creat(*exportHeader
)
236 fgcch
, err
:= os
.Open(*objDir
+ "_cgo_export.h")
240 _
, err
= io
.Copy(fexp
, fgcch
)
244 if err
= fexp
.Close(); err
!= nil {
249 init
:= gccgoInit
.String()
251 fmt
.Fprintln(fc
, "static void init(void) __attribute__ ((constructor));")
252 fmt
.Fprintln(fc
, "static void init(void) {")
254 fmt
.Fprintln(fc
, "}")
258 func dynimport(obj
string) {
261 f
, err
:= os
.Create(*dynout
)
268 fmt
.Fprintf(stdout
, "package %s\n", *dynpackage
)
270 if f
, err
:= elf
.Open(obj
); err
== nil {
272 // Emit the cgo_dynamic_linker line.
273 if sec
:= f
.Section(".interp"); sec
!= nil {
274 if data
, err
:= sec
.Data(); err
== nil && len(data
) > 1 {
275 // skip trailing \0 in data
276 fmt
.Fprintf(stdout
, "//go:cgo_dynamic_linker %q\n", string(data
[:len(data
)-1]))
280 sym
, err
:= f
.ImportedSymbols()
282 fatalf("cannot load imported symbols from ELF file %s: %v", obj
, err
)
284 for _
, s
:= range sym
{
287 targ
+= "#" + s
.Version
289 fmt
.Fprintf(stdout
, "//go:cgo_import_dynamic %s %s %q\n", s
.Name
, targ
, s
.Library
)
291 lib
, err
:= f
.ImportedLibraries()
293 fatalf("cannot load imported libraries from ELF file %s: %v", obj
, err
)
295 for _
, l
:= range lib
{
296 fmt
.Fprintf(stdout
, "//go:cgo_import_dynamic _ _ %q\n", l
)
301 if f
, err
:= macho
.Open(obj
); err
== nil {
302 sym
, err
:= f
.ImportedSymbols()
304 fatalf("cannot load imported symbols from Mach-O file %s: %v", obj
, err
)
306 for _
, s
:= range sym
{
307 if len(s
) > 0 && s
[0] == '_' {
310 fmt
.Fprintf(stdout
, "//go:cgo_import_dynamic %s %s %q\n", s
, s
, "")
312 lib
, err
:= f
.ImportedLibraries()
314 fatalf("cannot load imported libraries from Mach-O file %s: %v", obj
, err
)
316 for _
, l
:= range lib
{
317 fmt
.Fprintf(stdout
, "//go:cgo_import_dynamic _ _ %q\n", l
)
322 if f
, err
:= pe
.Open(obj
); err
== nil {
323 sym
, err
:= f
.ImportedSymbols()
325 fatalf("cannot load imported symbols from PE file %s: %v", obj
, err
)
327 for _
, s
:= range sym
{
328 ss
:= strings
.Split(s
, ":")
329 name
:= strings
.Split(ss
[0], "@")[0]
330 fmt
.Fprintf(stdout
, "//go:cgo_import_dynamic %s %s %q\n", name
, ss
[0], strings
.ToLower(ss
[1]))
335 if f
, err
:= xcoff
.Open(obj
); err
== nil {
336 sym
, err
:= f
.ImportedSymbols()
338 fatalf("cannot load imported symbols from XCOFF file %s: %v", obj
, err
)
340 for _
, s
:= range sym
{
341 fmt
.Fprintf(stdout
, "//go:cgo_import_dynamic %s %s %q\n", s
.Name
, s
.Name
, s
.Library
)
343 lib
, err
:= f
.ImportedLibraries()
345 fatalf("cannot load imported libraries from XCOFF file %s: %v", obj
, err
)
347 for _
, l
:= range lib
{
348 fmt
.Fprintf(stdout
, "//go:cgo_import_dynamic _ _ %q\n", l
)
353 fatalf("cannot parse %s as ELF, Mach-O, PE or XCOFF", obj
)
356 // Construct a gcc struct matching the gc argument frame.
357 // Assumes that in gcc, char is 1 byte, short 2 bytes, int 4 bytes, long long 8 bytes.
358 // These assumptions are checked by the gccProlog.
359 // Also assumes that gc convention is to word-align the
360 // input and output parameters.
361 func (p
*Package
) structType(n
*Name
) (string, int64) {
363 fmt
.Fprint(&buf
, "struct {\n")
365 for i
, t
:= range n
.FuncType
.Params
{
366 if off%t
.Align
!= 0 {
367 pad
:= t
.Align
- off%t
.Align
368 fmt
.Fprintf(&buf
, "\t\tchar __pad%d[%d];\n", off
, pad
)
375 fmt
.Fprintf(&buf
, "\t\t%s p%d;\n", c
, i
)
378 if off%p
.PtrSize
!= 0 {
379 pad
:= p
.PtrSize
- off%p
.PtrSize
380 fmt
.Fprintf(&buf
, "\t\tchar __pad%d[%d];\n", off
, pad
)
383 if t
:= n
.FuncType
.Result
; t
!= nil {
384 if off%t
.Align
!= 0 {
385 pad
:= t
.Align
- off%t
.Align
386 fmt
.Fprintf(&buf
, "\t\tchar __pad%d[%d];\n", off
, pad
)
389 fmt
.Fprintf(&buf
, "\t\t%s r;\n", t
.C
)
392 if off%p
.PtrSize
!= 0 {
393 pad
:= p
.PtrSize
- off%p
.PtrSize
394 fmt
.Fprintf(&buf
, "\t\tchar __pad%d[%d];\n", off
, pad
)
398 fmt
.Fprintf(&buf
, "\t\tchar unused;\n") // avoid empty struct
400 fmt
.Fprintf(&buf
, "\t}")
401 return buf
.String(), off
404 func (p
*Package
) writeDefsFunc(fgo2 io
.Writer
, n
*Name
, callsMalloc
*bool) {
406 gtype
:= n
.FuncType
.Go
407 void
:= gtype
.Results
== nil ||
len(gtype
.Results
.List
) == 0
409 // Add "error" to return type list.
410 // Type list is known to be 0 or 1 element - it's a C function.
411 err
:= &ast
.Field
{Type
: ast
.NewIdent("error")}
412 l
:= gtype
.Results
.List
414 l
= []*ast
.Field
{err
}
416 l
= []*ast
.Field
{l
[0], err
}
418 t
:= new(ast
.FuncType
)
420 t
.Results
= &ast
.FieldList
{List
: l
}
424 // Go func declaration.
426 Name
: ast
.NewIdent(n
.Mangle
),
430 // Builtins defined in the C prolog.
431 inProlog
:= builtinDefs
[name
] != ""
432 cname
:= fmt
.Sprintf("_cgo%s%s", cPrefix
, n
.Mangle
)
433 paramnames
:= []string(nil)
434 if d
.Type
.Params
!= nil {
435 for i
, param
:= range d
.Type
.Params
.List
{
436 paramName
:= fmt
.Sprintf("p%d", i
)
437 param
.Names
= []*ast
.Ident
{ast
.NewIdent(paramName
)}
438 paramnames
= append(paramnames
, paramName
)
443 // Gccgo style hooks.
444 fmt
.Fprint(fgo2
, "\n")
445 conf
.Fprint(fgo2
, fset
, d
)
446 fmt
.Fprint(fgo2
, " {\n")
448 fmt
.Fprint(fgo2
, "\tdefer syscall.CgocallDone()\n")
449 fmt
.Fprint(fgo2
, "\tsyscall.Cgocall()\n")
452 fmt
.Fprint(fgo2
, "\tsyscall.SetErrno(0)\n")
454 fmt
.Fprint(fgo2
, "\t")
456 fmt
.Fprint(fgo2
, "r := ")
458 fmt
.Fprintf(fgo2
, "%s(%s)\n", cname
, strings
.Join(paramnames
, ", "))
461 fmt
.Fprint(fgo2
, "\te := syscall.GetErrno()\n")
462 fmt
.Fprint(fgo2
, "\tif e != 0 {\n")
463 fmt
.Fprint(fgo2
, "\t\treturn ")
465 fmt
.Fprint(fgo2
, "r, ")
467 fmt
.Fprint(fgo2
, "e\n")
468 fmt
.Fprint(fgo2
, "\t}\n")
469 fmt
.Fprint(fgo2
, "\treturn ")
471 fmt
.Fprint(fgo2
, "r, ")
473 fmt
.Fprint(fgo2
, "nil\n")
475 fmt
.Fprint(fgo2
, "\treturn r\n")
478 fmt
.Fprint(fgo2
, "}\n")
480 // declare the C function.
481 fmt
.Fprintf(fgo2
, "//extern %s\n", cname
)
482 d
.Name
= ast
.NewIdent(cname
)
484 l
:= d
.Type
.Results
.List
485 d
.Type
.Results
.List
= l
[:len(l
)-1]
487 conf
.Fprint(fgo2
, fset
, d
)
488 fmt
.Fprint(fgo2
, "\n")
494 fmt
.Fprint(fgo2
, builtinDefs
[name
])
495 if strings
.Contains(builtinDefs
[name
], "_cgo_cmalloc") {
501 // Wrapper calls into gcc, passing a pointer to the argument frame.
502 fmt
.Fprintf(fgo2
, "//go:cgo_import_static %s\n", cname
)
503 fmt
.Fprintf(fgo2
, "//go:linkname __cgofn_%s %s\n", cname
, cname
)
504 fmt
.Fprintf(fgo2
, "var __cgofn_%s byte\n", cname
)
505 fmt
.Fprintf(fgo2
, "var %s = unsafe.Pointer(&__cgofn_%s)\n", cname
, cname
)
509 d
.Type
.Results
.List
[0].Names
= []*ast
.Ident
{ast
.NewIdent("r1")}
513 d
.Type
.Results
.List
[nret
].Names
= []*ast
.Ident
{ast
.NewIdent("r2")}
516 fmt
.Fprint(fgo2
, "\n")
517 fmt
.Fprint(fgo2
, "//go:cgo_unsafe_args\n")
518 conf
.Fprint(fgo2
, fset
, d
)
519 fmt
.Fprint(fgo2
, " {\n")
521 // NOTE: Using uintptr to hide from escape analysis.
523 if len(paramnames
) > 0 {
524 arg
= "uintptr(unsafe.Pointer(&p0))"
526 arg
= "uintptr(unsafe.Pointer(&r1))"
533 fmt
.Fprintf(fgo2
, "\t%s_cgo_runtime_cgocall(%s, %s)\n", prefix
, cname
, arg
)
535 fmt
.Fprintf(fgo2
, "\tif errno != 0 { r2 = syscall.Errno(errno) }\n")
537 fmt
.Fprintf(fgo2
, "\tif _Cgo_always_false {\n")
538 if d
.Type
.Params
!= nil {
539 for i
:= range d
.Type
.Params
.List
{
540 fmt
.Fprintf(fgo2
, "\t\t_Cgo_use(p%d)\n", i
)
543 fmt
.Fprintf(fgo2
, "\t}\n")
544 fmt
.Fprintf(fgo2
, "\treturn\n")
545 fmt
.Fprintf(fgo2
, "}\n")
548 // writeOutput creates stubs for a specific source file to be compiled by gc
549 func (p
*Package
) writeOutput(f
*File
, srcfile
string) {
551 if strings
.HasSuffix(base
, ".go") {
552 base
= base
[0 : len(base
)-3]
554 base
= filepath
.Base(base
)
555 fgo1
:= creat(*objDir
+ base
+ ".cgo1.go")
556 fgcc
:= creat(*objDir
+ base
+ ".cgo2.c")
558 p
.GoFiles
= append(p
.GoFiles
, base
+".cgo1.go")
559 p
.GccFiles
= append(p
.GccFiles
, base
+".cgo2.c")
561 // Write Go output: Go input with rewrites of C.xxx to _C_xxx.
562 fmt
.Fprintf(fgo1
, "// Created by cgo - DO NOT EDIT\n\n")
563 fmt
.Fprintf(fgo1
, "//line %s:1\n", srcfile
)
564 fgo1
.Write(f
.Edit
.Bytes())
566 // While we process the vars and funcs, also write gcc output.
567 // Gcc output starts with the preamble.
568 fmt
.Fprintf(fgcc
, "%s\n", builtinProlog
)
569 fmt
.Fprintf(fgcc
, "%s\n", f
.Preamble
)
570 fmt
.Fprintf(fgcc
, "%s\n", gccProlog
)
571 fmt
.Fprintf(fgcc
, "%s\n", tsanProlog
)
573 for _
, key
:= range nameKeys(f
.Name
) {
575 if n
.FuncType
!= nil {
576 p
.writeOutputFunc(fgcc
, n
)
584 // fixGo converts the internal Name.Go field into the name we should show
585 // to users in error messages. There's only one for now: on input we rewrite
586 // C.malloc into C._CMalloc, so change it back here.
587 func fixGo(name
string) string {
588 if name
== "_CMalloc" {
594 var isBuiltin
= map[string]bool{
595 "_Cfunc_CString": true,
596 "_Cfunc_CBytes": true,
597 "_Cfunc_GoString": true,
598 "_Cfunc_GoStringN": true,
599 "_Cfunc_GoBytes": true,
600 "_Cfunc__CMalloc": true,
603 func (p
*Package
) writeOutputFunc(fgcc
*os
.File
, n
*Name
) {
605 if isBuiltin
[name
] || p
.Written
[name
] {
606 // The builtins are already defined in the C prolog, and we don't
607 // want to duplicate function definitions we've already done.
610 p
.Written
[name
] = true
613 p
.writeGccgoOutputFunc(fgcc
, n
)
617 ctype
, _
:= p
.structType(n
)
619 // Gcc wrapper unpacks the C argument struct
620 // and calls the actual C function.
621 fmt
.Fprintf(fgcc
, "CGO_NO_SANITIZE_THREAD\n")
623 fmt
.Fprintf(fgcc
, "int\n")
625 fmt
.Fprintf(fgcc
, "void\n")
627 fmt
.Fprintf(fgcc
, "_cgo%s%s(void *v)\n", cPrefix
, n
.Mangle
)
628 fmt
.Fprintf(fgcc
, "{\n")
630 fmt
.Fprintf(fgcc
, "\tint _cgo_errno;\n")
632 // We're trying to write a gcc struct that matches gc's layout.
633 // Use packed attribute to force no padding in this struct in case
634 // gcc has different packing requirements.
635 fmt
.Fprintf(fgcc
, "\t%s %v *a = v;\n", ctype
, p
.packedAttribute())
636 if n
.FuncType
.Result
!= nil {
637 // Save the stack top for use below.
638 fmt
.Fprintf(fgcc
, "\tchar *stktop = _cgo_topofstack();\n")
640 tr
:= n
.FuncType
.Result
642 fmt
.Fprintf(fgcc
, "\t__typeof__(a->r) r;\n")
644 fmt
.Fprintf(fgcc
, "\t_cgo_tsan_acquire();\n")
646 fmt
.Fprintf(fgcc
, "\terrno = 0;\n")
648 fmt
.Fprintf(fgcc
, "\t")
650 fmt
.Fprintf(fgcc
, "r = ")
651 if c
:= tr
.C
.String(); c
[len(c
)-1] == '*' {
652 fmt
.Fprint(fgcc
, "(__typeof__(a->r)) ")
655 if n
.Kind
== "macro" {
656 fmt
.Fprintf(fgcc
, "%s;\n", n
.C
)
658 fmt
.Fprintf(fgcc
, "%s(", n
.C
)
659 for i
:= range n
.FuncType
.Params
{
661 fmt
.Fprintf(fgcc
, ", ")
663 fmt
.Fprintf(fgcc
, "a->p%d", i
)
665 fmt
.Fprintf(fgcc
, ");\n")
668 fmt
.Fprintf(fgcc
, "\t_cgo_errno = errno;\n")
670 fmt
.Fprintf(fgcc
, "\t_cgo_tsan_release();\n")
671 if n
.FuncType
.Result
!= nil {
672 // The cgo call may have caused a stack copy (via a callback).
673 // Adjust the return value pointer appropriately.
674 fmt
.Fprintf(fgcc
, "\ta = (void*)((char*)a + (_cgo_topofstack() - stktop));\n")
675 // Save the return value.
676 fmt
.Fprintf(fgcc
, "\ta->r = r;\n")
679 fmt
.Fprintf(fgcc
, "\treturn _cgo_errno;\n")
681 fmt
.Fprintf(fgcc
, "}\n")
682 fmt
.Fprintf(fgcc
, "\n")
685 // Write out a wrapper for a function when using gccgo. This is a
686 // simple wrapper that just calls the real function. We only need a
687 // wrapper to support static functions in the prologue--without a
688 // wrapper, we can't refer to the function, since the reference is in
690 func (p
*Package
) writeGccgoOutputFunc(fgcc
*os
.File
, n
*Name
) {
691 fmt
.Fprintf(fgcc
, "CGO_NO_SANITIZE_THREAD\n")
692 if t
:= n
.FuncType
.Result
; t
!= nil {
693 fmt
.Fprintf(fgcc
, "%s\n", t
.C
.String())
695 fmt
.Fprintf(fgcc
, "void\n")
697 fmt
.Fprintf(fgcc
, "_cgo%s%s(", cPrefix
, n
.Mangle
)
698 for i
, t
:= range n
.FuncType
.Params
{
700 fmt
.Fprintf(fgcc
, ", ")
706 fmt
.Fprintf(fgcc
, "%s p%d", c
, i
)
708 fmt
.Fprintf(fgcc
, ")\n")
709 fmt
.Fprintf(fgcc
, "{\n")
710 if t
:= n
.FuncType
.Result
; t
!= nil {
711 fmt
.Fprintf(fgcc
, "\t%s r;\n", t
.C
.String())
713 fmt
.Fprintf(fgcc
, "\t_cgo_tsan_acquire();\n")
714 fmt
.Fprintf(fgcc
, "\t")
715 if t
:= n
.FuncType
.Result
; t
!= nil {
716 fmt
.Fprintf(fgcc
, "r = ")
717 // Cast to void* to avoid warnings due to omitted qualifiers.
718 if c
:= t
.C
.String(); c
[len(c
)-1] == '*' {
719 fmt
.Fprintf(fgcc
, "(void*)")
722 if n
.Kind
== "macro" {
723 fmt
.Fprintf(fgcc
, "%s;\n", n
.C
)
725 fmt
.Fprintf(fgcc
, "%s(", n
.C
)
726 for i
:= range n
.FuncType
.Params
{
728 fmt
.Fprintf(fgcc
, ", ")
730 fmt
.Fprintf(fgcc
, "p%d", i
)
732 fmt
.Fprintf(fgcc
, ");\n")
734 fmt
.Fprintf(fgcc
, "\t_cgo_tsan_release();\n")
735 if t
:= n
.FuncType
.Result
; t
!= nil {
736 fmt
.Fprintf(fgcc
, "\treturn ")
737 // Cast to void* to avoid warnings due to omitted qualifiers
738 // and explicit incompatible struct types.
739 if c
:= t
.C
.String(); c
[len(c
)-1] == '*' {
740 fmt
.Fprintf(fgcc
, "(void*)")
742 fmt
.Fprintf(fgcc
, "r;\n")
744 fmt
.Fprintf(fgcc
, "}\n")
745 fmt
.Fprintf(fgcc
, "\n")
748 // packedAttribute returns host compiler struct attribute that will be
749 // used to match gc's struct layout. For example, on 386 Windows,
750 // gcc wants to 8-align int64s, but gc does not.
751 // Use __gcc_struct__ to work around http://gcc.gnu.org/PR52991 on x86,
752 // and https://golang.org/issue/5603.
753 func (p
*Package
) packedAttribute() string {
754 s
:= "__attribute__((__packed__"
755 if !p
.GccIsClang
&& (goarch
== "amd64" || goarch
== "386") {
756 s
+= ", __gcc_struct__"
761 // Write out the various stubs we need to support functions exported
762 // from Go so that they are callable from C.
763 func (p
*Package
) writeExports(fgo2
, fm
, fgcc
, fgcch io
.Writer
) {
764 p
.writeExportHeader(fgcch
)
766 fmt
.Fprintf(fgcc
, "/* Created by cgo - DO NOT EDIT. */\n")
767 fmt
.Fprintf(fgcc
, "#include <stdlib.h>\n")
768 fmt
.Fprintf(fgcc
, "#include \"_cgo_export.h\"\n\n")
770 fmt
.Fprintf(fgcc
, "extern void crosscall2(void (*fn)(void *, int, __SIZE_TYPE__), void *, int, __SIZE_TYPE__);\n")
771 fmt
.Fprintf(fgcc
, "extern __SIZE_TYPE__ _cgo_wait_runtime_init_done();\n")
772 fmt
.Fprintf(fgcc
, "extern void _cgo_release_context(__SIZE_TYPE__);\n\n")
773 fmt
.Fprintf(fgcc
, "extern char* _cgo_topofstack(void);")
774 fmt
.Fprintf(fgcc
, "%s\n", tsanProlog
)
776 for _
, exp
:= range p
.ExpFunc
{
779 // Construct a gcc struct matching the gc argument and
780 // result frame. The gcc struct will be compiled with
781 // __attribute__((packed)) so all padding must be accounted
783 ctype
:= "struct {\n"
787 t
:= p
.cgoType(fn
.Recv
.List
[0].Type
)
788 ctype
+= fmt
.Sprintf("\t\t%s recv;\n", t
.C
)
792 forFieldList(fntype
.Params
,
793 func(i
int, aname
string, atype ast
.Expr
) {
794 t
:= p
.cgoType(atype
)
795 if off%t
.Align
!= 0 {
796 pad
:= t
.Align
- off%t
.Align
797 ctype
+= fmt
.Sprintf("\t\tchar __pad%d[%d];\n", npad
, pad
)
801 ctype
+= fmt
.Sprintf("\t\t%s p%d;\n", t
.C
, i
)
804 if off%p
.PtrSize
!= 0 {
805 pad
:= p
.PtrSize
- off%p
.PtrSize
806 ctype
+= fmt
.Sprintf("\t\tchar __pad%d[%d];\n", npad
, pad
)
810 forFieldList(fntype
.Results
,
811 func(i
int, aname
string, atype ast
.Expr
) {
812 t
:= p
.cgoType(atype
)
813 if off%t
.Align
!= 0 {
814 pad
:= t
.Align
- off%t
.Align
815 ctype
+= fmt
.Sprintf("\t\tchar __pad%d[%d];\n", npad
, pad
)
819 ctype
+= fmt
.Sprintf("\t\t%s r%d;\n", t
.C
, i
)
822 if off%p
.PtrSize
!= 0 {
823 pad
:= p
.PtrSize
- off%p
.PtrSize
824 ctype
+= fmt
.Sprintf("\t\tchar __pad%d[%d];\n", npad
, pad
)
828 if ctype
== "struct {\n" {
829 ctype
+= "\t\tchar unused;\n" // avoid empty struct
833 // Get the return type of the wrapper function
836 if fntype
.Results
== nil ||
len(fntype
.Results
.List
) == 0 {
838 } else if len(fntype
.Results
.List
) == 1 && len(fntype
.Results
.List
[0].Names
) <= 1 {
839 gccResult
= p
.cgoType(fntype
.Results
.List
[0].Type
).C
.String()
841 fmt
.Fprintf(fgcch
, "\n/* Return type for %s */\n", exp
.ExpName
)
842 fmt
.Fprintf(fgcch
, "struct %s_return {\n", exp
.ExpName
)
843 forFieldList(fntype
.Results
,
844 func(i
int, aname
string, atype ast
.Expr
) {
845 fmt
.Fprintf(fgcch
, "\t%s r%d;", p
.cgoType(atype
).C
, i
)
847 fmt
.Fprintf(fgcch
, " /* %s */", aname
)
849 fmt
.Fprint(fgcch
, "\n")
851 fmt
.Fprintf(fgcch
, "};\n")
852 gccResult
= "struct " + exp
.ExpName
+ "_return"
855 // Build the wrapper function compiled by gcc.
856 s
:= fmt
.Sprintf("%s %s(", gccResult
, exp
.ExpName
)
858 s
+= p
.cgoType(fn
.Recv
.List
[0].Type
).C
.String()
861 forFieldList(fntype
.Params
,
862 func(i
int, aname
string, atype ast
.Expr
) {
863 if i
> 0 || fn
.Recv
!= nil {
866 s
+= fmt
.Sprintf("%s p%d", p
.cgoType(atype
).C
, i
)
870 if len(exp
.Doc
) > 0 {
871 fmt
.Fprintf(fgcch
, "\n%s", exp
.Doc
)
873 fmt
.Fprintf(fgcch
, "\nextern %s;\n", s
)
875 fmt
.Fprintf(fgcc
, "extern void _cgoexp%s_%s(void *, int, __SIZE_TYPE__);\n", cPrefix
, exp
.ExpName
)
876 fmt
.Fprintf(fgcc
, "\nCGO_NO_SANITIZE_THREAD")
877 fmt
.Fprintf(fgcc
, "\n%s\n", s
)
878 fmt
.Fprintf(fgcc
, "{\n")
879 fmt
.Fprintf(fgcc
, "\t__SIZE_TYPE__ _cgo_ctxt = _cgo_wait_runtime_init_done();\n")
880 fmt
.Fprintf(fgcc
, "\t%s %v a;\n", ctype
, p
.packedAttribute())
881 if gccResult
!= "void" && (len(fntype
.Results
.List
) > 1 ||
len(fntype
.Results
.List
[0].Names
) > 1) {
882 fmt
.Fprintf(fgcc
, "\t%s r;\n", gccResult
)
885 fmt
.Fprintf(fgcc
, "\ta.recv = recv;\n")
887 forFieldList(fntype
.Params
,
888 func(i
int, aname
string, atype ast
.Expr
) {
889 fmt
.Fprintf(fgcc
, "\ta.p%d = p%d;\n", i
, i
)
891 fmt
.Fprintf(fgcc
, "\t_cgo_tsan_release();\n")
892 fmt
.Fprintf(fgcc
, "\tcrosscall2(_cgoexp%s_%s, &a, %d, _cgo_ctxt);\n", cPrefix
, exp
.ExpName
, off
)
893 fmt
.Fprintf(fgcc
, "\t_cgo_tsan_acquire();\n")
894 fmt
.Fprintf(fgcc
, "\t_cgo_release_context(_cgo_ctxt);\n")
895 if gccResult
!= "void" {
896 if len(fntype
.Results
.List
) == 1 && len(fntype
.Results
.List
[0].Names
) <= 1 {
897 fmt
.Fprintf(fgcc
, "\treturn a.r0;\n")
899 forFieldList(fntype
.Results
,
900 func(i
int, aname
string, atype ast
.Expr
) {
901 fmt
.Fprintf(fgcc
, "\tr.r%d = a.r%d;\n", i
, i
)
903 fmt
.Fprintf(fgcc
, "\treturn r;\n")
906 fmt
.Fprintf(fgcc
, "}\n")
908 // Build the wrapper function compiled by cmd/compile.
909 goname
:= "_cgoexpwrap" + cPrefix
+ "_"
911 goname
+= fn
.Recv
.List
[0].Names
[0].Name
+ "_"
913 goname
+= exp
.Func
.Name
.Name
914 fmt
.Fprintf(fgo2
, "//go:cgo_export_dynamic %s\n", exp
.ExpName
)
915 fmt
.Fprintf(fgo2
, "//go:linkname _cgoexp%s_%s _cgoexp%s_%s\n", cPrefix
, exp
.ExpName
, cPrefix
, exp
.ExpName
)
916 fmt
.Fprintf(fgo2
, "//go:cgo_export_static _cgoexp%s_%s\n", cPrefix
, exp
.ExpName
)
917 fmt
.Fprintf(fgo2
, "//go:nosplit\n") // no split stack, so no use of m or g
918 fmt
.Fprintf(fgo2
, "//go:norace\n") // must not have race detector calls inserted
919 fmt
.Fprintf(fgo2
, "func _cgoexp%s_%s(a unsafe.Pointer, n int32, ctxt uintptr) {\n", cPrefix
, exp
.ExpName
)
920 fmt
.Fprintf(fgo2
, "\tfn := %s\n", goname
)
921 // The indirect here is converting from a Go function pointer to a C function pointer.
922 fmt
.Fprintf(fgo2
, "\t_cgo_runtime_cgocallback(**(**unsafe.Pointer)(unsafe.Pointer(&fn)), a, uintptr(n), ctxt);\n")
923 fmt
.Fprintf(fgo2
, "}\n")
925 fmt
.Fprintf(fm
, "int _cgoexp%s_%s;\n", cPrefix
, exp
.ExpName
)
927 // This code uses printer.Fprint, not conf.Fprint,
928 // because we don't want //line comments in the middle
929 // of the function types.
930 fmt
.Fprintf(fgo2
, "\n")
931 fmt
.Fprintf(fgo2
, "func %s(", goname
)
934 fmt
.Fprintf(fgo2
, "recv ")
935 printer
.Fprint(fgo2
, fset
, fn
.Recv
.List
[0].Type
)
938 forFieldList(fntype
.Params
,
939 func(i
int, aname
string, atype ast
.Expr
) {
941 fmt
.Fprintf(fgo2
, ", ")
943 fmt
.Fprintf(fgo2
, "p%d ", i
)
944 printer
.Fprint(fgo2
, fset
, atype
)
947 fmt
.Fprintf(fgo2
, ")")
948 if gccResult
!= "void" {
949 fmt
.Fprint(fgo2
, " (")
950 forFieldList(fntype
.Results
,
951 func(i
int, aname
string, atype ast
.Expr
) {
953 fmt
.Fprint(fgo2
, ", ")
955 fmt
.Fprintf(fgo2
, "r%d ", i
)
956 printer
.Fprint(fgo2
, fset
, atype
)
958 fmt
.Fprint(fgo2
, ")")
960 fmt
.Fprint(fgo2
, " {\n")
961 if gccResult
== "void" {
962 fmt
.Fprint(fgo2
, "\t")
964 // Verify that any results don't contain any
967 forFieldList(fntype
.Results
,
968 func(i
int, aname
string, atype ast
.Expr
) {
969 if !p
.hasPointer(nil, atype
, false) {
973 fmt
.Fprint(fgo2
, "\tdefer func() {\n")
976 fmt
.Fprintf(fgo2
, "\t\t_cgoCheckResult(r%d)\n", i
)
979 fmt
.Fprint(fgo2
, "\t}()\n")
981 fmt
.Fprint(fgo2
, "\treturn ")
984 fmt
.Fprintf(fgo2
, "recv.")
986 fmt
.Fprintf(fgo2
, "%s(", exp
.Func
.Name
)
987 forFieldList(fntype
.Params
,
988 func(i
int, aname
string, atype ast
.Expr
) {
990 fmt
.Fprint(fgo2
, ", ")
992 fmt
.Fprintf(fgo2
, "p%d", i
)
994 fmt
.Fprint(fgo2
, ")\n")
995 fmt
.Fprint(fgo2
, "}\n")
998 fmt
.Fprintf(fgcch
, "%s", gccExportHeaderEpilog
)
1001 // Write out the C header allowing C code to call exported gccgo functions.
1002 func (p
*Package
) writeGccgoExports(fgo2
, fm
, fgcc
, fgcch io
.Writer
) {
1003 gccgoSymbolPrefix
:= p
.gccgoSymbolPrefix()
1005 p
.writeExportHeader(fgcch
)
1007 fmt
.Fprintf(fgcc
, "/* Created by cgo - DO NOT EDIT. */\n")
1008 fmt
.Fprintf(fgcc
, "#include \"_cgo_export.h\"\n")
1010 fmt
.Fprintf(fgcc
, "%s\n", gccgoExportFileProlog
)
1011 fmt
.Fprintf(fgcc
, "%s\n", tsanProlog
)
1013 for _
, exp
:= range p
.ExpFunc
{
1017 cdeclBuf
:= new(bytes
.Buffer
)
1019 forFieldList(fntype
.Results
,
1020 func(i
int, aname
string, atype ast
.Expr
) { resultCount
++ })
1021 switch resultCount
{
1023 fmt
.Fprintf(cdeclBuf
, "void")
1025 forFieldList(fntype
.Results
,
1026 func(i
int, aname
string, atype ast
.Expr
) {
1027 t
:= p
.cgoType(atype
)
1028 fmt
.Fprintf(cdeclBuf
, "%s", t
.C
)
1031 // Declare a result struct.
1032 fmt
.Fprintf(fgcch
, "\n/* Return type for %s */\n", exp
.ExpName
)
1033 fmt
.Fprintf(fgcch
, "struct %s_return {\n", exp
.ExpName
)
1034 forFieldList(fntype
.Results
,
1035 func(i
int, aname
string, atype ast
.Expr
) {
1036 t
:= p
.cgoType(atype
)
1037 fmt
.Fprintf(fgcch
, "\t%s r%d;", t
.C
, i
)
1039 fmt
.Fprintf(fgcch
, " /* %s */", aname
)
1041 fmt
.Fprint(fgcch
, "\n")
1043 fmt
.Fprintf(fgcch
, "};\n")
1044 fmt
.Fprintf(cdeclBuf
, "struct %s_return", exp
.ExpName
)
1047 cRet
:= cdeclBuf
.String()
1049 cdeclBuf
= new(bytes
.Buffer
)
1050 fmt
.Fprintf(cdeclBuf
, "(")
1052 fmt
.Fprintf(cdeclBuf
, "%s recv", p
.cgoType(fn
.Recv
.List
[0].Type
).C
.String())
1054 // Function parameters.
1055 forFieldList(fntype
.Params
,
1056 func(i
int, aname
string, atype ast
.Expr
) {
1057 if i
> 0 || fn
.Recv
!= nil {
1058 fmt
.Fprintf(cdeclBuf
, ", ")
1060 t
:= p
.cgoType(atype
)
1061 fmt
.Fprintf(cdeclBuf
, "%s p%d", t
.C
, i
)
1063 fmt
.Fprintf(cdeclBuf
, ")")
1064 cParams
:= cdeclBuf
.String()
1066 if len(exp
.Doc
) > 0 {
1067 fmt
.Fprintf(fgcch
, "\n%s", exp
.Doc
)
1070 fmt
.Fprintf(fgcch
, "extern %s %s%s;\n", cRet
, exp
.ExpName
, cParams
)
1072 // We need to use a name that will be exported by the
1073 // Go code; otherwise gccgo will make it static and we
1074 // will not be able to link against it from the C
1076 goName
:= "Cgoexp_" + exp
.ExpName
1077 fmt
.Fprintf(fgcc
, `extern %s %s %s __asm__("%s.%s");`, cRet
, goName
, cParams
, gccgoSymbolPrefix
, goName
)
1078 fmt
.Fprint(fgcc
, "\n")
1080 fmt
.Fprint(fgcc
, "\nCGO_NO_SANITIZE_THREAD\n")
1081 fmt
.Fprintf(fgcc
, "%s %s %s {\n", cRet
, exp
.ExpName
, cParams
)
1082 if resultCount
> 0 {
1083 fmt
.Fprintf(fgcc
, "\t%s r;\n", cRet
)
1085 fmt
.Fprintf(fgcc
, "\tif(_cgo_wait_runtime_init_done)\n")
1086 fmt
.Fprintf(fgcc
, "\t\t_cgo_wait_runtime_init_done();\n")
1087 fmt
.Fprintf(fgcc
, "\t_cgo_tsan_release();\n")
1088 fmt
.Fprint(fgcc
, "\t")
1089 if resultCount
> 0 {
1090 fmt
.Fprint(fgcc
, "r = ")
1092 fmt
.Fprintf(fgcc
, "%s(", goName
)
1094 fmt
.Fprint(fgcc
, "recv")
1096 forFieldList(fntype
.Params
,
1097 func(i
int, aname
string, atype ast
.Expr
) {
1098 if i
> 0 || fn
.Recv
!= nil {
1099 fmt
.Fprintf(fgcc
, ", ")
1101 fmt
.Fprintf(fgcc
, "p%d", i
)
1103 fmt
.Fprint(fgcc
, ");\n")
1104 fmt
.Fprintf(fgcc
, "\t_cgo_tsan_acquire();\n")
1105 if resultCount
> 0 {
1106 fmt
.Fprint(fgcc
, "\treturn r;\n")
1108 fmt
.Fprint(fgcc
, "}\n")
1110 // Dummy declaration for _cgo_main.c
1111 fmt
.Fprintf(fm
, `char %s[1] __asm__("%s.%s");`, goName
, gccgoSymbolPrefix
, goName
)
1112 fmt
.Fprint(fm
, "\n")
1114 // For gccgo we use a wrapper function in Go, in order
1115 // to call CgocallBack and CgocallBackDone.
1117 // This code uses printer.Fprint, not conf.Fprint,
1118 // because we don't want //line comments in the middle
1119 // of the function types.
1120 fmt
.Fprint(fgo2
, "\n")
1121 fmt
.Fprintf(fgo2
, "func %s(", goName
)
1123 fmt
.Fprint(fgo2
, "recv ")
1124 printer
.Fprint(fgo2
, fset
, fn
.Recv
.List
[0].Type
)
1126 forFieldList(fntype
.Params
,
1127 func(i
int, aname
string, atype ast
.Expr
) {
1128 if i
> 0 || fn
.Recv
!= nil {
1129 fmt
.Fprintf(fgo2
, ", ")
1131 fmt
.Fprintf(fgo2
, "p%d ", i
)
1132 printer
.Fprint(fgo2
, fset
, atype
)
1134 fmt
.Fprintf(fgo2
, ")")
1135 if resultCount
> 0 {
1136 fmt
.Fprintf(fgo2
, " (")
1137 forFieldList(fntype
.Results
,
1138 func(i
int, aname
string, atype ast
.Expr
) {
1140 fmt
.Fprint(fgo2
, ", ")
1142 printer
.Fprint(fgo2
, fset
, atype
)
1144 fmt
.Fprint(fgo2
, ")")
1146 fmt
.Fprint(fgo2
, " {\n")
1147 fmt
.Fprint(fgo2
, "\tsyscall.CgocallBack()\n")
1148 fmt
.Fprint(fgo2
, "\tdefer syscall.CgocallBackDone()\n")
1149 fmt
.Fprint(fgo2
, "\t")
1150 if resultCount
> 0 {
1151 fmt
.Fprint(fgo2
, "return ")
1154 fmt
.Fprint(fgo2
, "recv.")
1156 fmt
.Fprintf(fgo2
, "%s(", exp
.Func
.Name
)
1157 forFieldList(fntype
.Params
,
1158 func(i
int, aname
string, atype ast
.Expr
) {
1160 fmt
.Fprint(fgo2
, ", ")
1162 fmt
.Fprintf(fgo2
, "p%d", i
)
1164 fmt
.Fprint(fgo2
, ")\n")
1165 fmt
.Fprint(fgo2
, "}\n")
1168 fmt
.Fprintf(fgcch
, "%s", gccExportHeaderEpilog
)
1171 // writeExportHeader writes out the start of the _cgo_export.h file.
1172 func (p
*Package
) writeExportHeader(fgcch io
.Writer
) {
1173 fmt
.Fprintf(fgcch
, "/* Created by \"go tool cgo\" - DO NOT EDIT. */\n\n")
1178 fmt
.Fprintf(fgcch
, "/* package %s */\n\n", pkg
)
1179 fmt
.Fprintf(fgcch
, "%s\n", builtinExportProlog
)
1181 fmt
.Fprintf(fgcch
, "/* Start of preamble from import \"C\" comments. */\n\n")
1182 fmt
.Fprintf(fgcch
, "%s\n", p
.Preamble
)
1183 fmt
.Fprintf(fgcch
, "\n/* End of preamble from import \"C\" comments. */\n\n")
1185 fmt
.Fprintf(fgcch
, "%s\n", p
.gccExportHeaderProlog())
1188 // Return the package prefix when using gccgo.
1189 func (p
*Package
) gccgoSymbolPrefix() string {
1194 clean
:= func(r rune
) rune
{
1196 case 'A' <= r
&& r
<= 'Z', 'a' <= r
&& r
<= 'z',
1197 '0' <= r
&& r
<= '9':
1203 if *gccgopkgpath
!= "" {
1204 return strings
.Map(clean
, *gccgopkgpath
)
1206 if *gccgoprefix
== "" && p
.PackageName
== "main" {
1209 prefix
:= strings
.Map(clean
, *gccgoprefix
)
1213 return prefix
+ "." + p
.PackageName
1216 // Call a function for each entry in an ast.FieldList, passing the
1217 // index into the list, the name if any, and the type.
1218 func forFieldList(fl
*ast
.FieldList
, fn
func(int, string, ast
.Expr
)) {
1223 for _
, r
:= range fl
.List
{
1228 for _
, n
:= range r
.Names
{
1229 fn(i
, n
.Name
, r
.Type
)
1236 func c(repr
string, args
...interface{}) *TypeRepr
{
1237 return &TypeRepr
{repr
, args
}
1240 // Map predeclared Go types to Type.
1241 var goTypes
= map[string]*Type
{
1242 "bool": {Size
: 1, Align
: 1, C
: c("GoUint8")},
1243 "byte": {Size
: 1, Align
: 1, C
: c("GoUint8")},
1244 "int": {Size
: 0, Align
: 0, C
: c("GoInt")},
1245 "uint": {Size
: 0, Align
: 0, C
: c("GoUint")},
1246 "rune": {Size
: 4, Align
: 4, C
: c("GoInt32")},
1247 "int8": {Size
: 1, Align
: 1, C
: c("GoInt8")},
1248 "uint8": {Size
: 1, Align
: 1, C
: c("GoUint8")},
1249 "int16": {Size
: 2, Align
: 2, C
: c("GoInt16")},
1250 "uint16": {Size
: 2, Align
: 2, C
: c("GoUint16")},
1251 "int32": {Size
: 4, Align
: 4, C
: c("GoInt32")},
1252 "uint32": {Size
: 4, Align
: 4, C
: c("GoUint32")},
1253 "int64": {Size
: 8, Align
: 8, C
: c("GoInt64")},
1254 "uint64": {Size
: 8, Align
: 8, C
: c("GoUint64")},
1255 "float32": {Size
: 4, Align
: 4, C
: c("GoFloat32")},
1256 "float64": {Size
: 8, Align
: 8, C
: c("GoFloat64")},
1257 "complex64": {Size
: 8, Align
: 4, C
: c("GoComplex64")},
1258 "complex128": {Size
: 16, Align
: 8, C
: c("GoComplex128")},
1261 // Map an ast type to a Type.
1262 func (p
*Package
) cgoType(e ast
.Expr
) *Type
{
1263 switch t
:= e
.(type) {
1266 return &Type
{Size
: p
.PtrSize
, Align
: p
.PtrSize
, C
: c("%s*", x
.C
)}
1267 case *ast
.ArrayType
:
1269 // Slice: pointer, len, cap.
1270 return &Type
{Size
: p
.PtrSize
* 3, Align
: p
.PtrSize
, C
: c("GoSlice")}
1272 // Non-slice array types are not supported.
1273 case *ast
.StructType
:
1276 return &Type
{Size
: p
.PtrSize
, Align
: p
.PtrSize
, C
: c("void*")}
1277 case *ast
.InterfaceType
:
1278 return &Type
{Size
: 2 * p
.PtrSize
, Align
: p
.PtrSize
, C
: c("GoInterface")}
1280 return &Type
{Size
: p
.PtrSize
, Align
: p
.PtrSize
, C
: c("GoMap")}
1282 return &Type
{Size
: p
.PtrSize
, Align
: p
.PtrSize
, C
: c("GoChan")}
1284 // Look up the type in the top level declarations.
1285 // TODO: Handle types defined within a function.
1286 for _
, d
:= range p
.Decl
{
1287 gd
, ok
:= d
.(*ast
.GenDecl
)
1288 if !ok || gd
.Tok
!= token
.TYPE
{
1291 for _
, spec
:= range gd
.Specs
{
1292 ts
, ok
:= spec
.(*ast
.TypeSpec
)
1296 if ts
.Name
.Name
== t
.Name
{
1297 return p
.cgoType(ts
.Type
)
1301 if def
:= typedef
[t
.Name
]; def
!= nil {
1304 if t
.Name
== "uintptr" {
1305 return &Type
{Size
: p
.PtrSize
, Align
: p
.PtrSize
, C
: c("GoUintptr")}
1307 if t
.Name
== "string" {
1308 // The string data is 1 pointer + 1 (pointer-sized) int.
1309 return &Type
{Size
: 2 * p
.PtrSize
, Align
: p
.PtrSize
, C
: c("GoString")}
1311 if t
.Name
== "error" {
1312 return &Type
{Size
: 2 * p
.PtrSize
, Align
: p
.PtrSize
, C
: c("GoInterface")}
1314 if r
, ok
:= goTypes
[t
.Name
]; ok
{
1315 if r
.Size
== 0 { // int or uint
1319 rr
.Align
= p
.IntSize
1322 if r
.Align
> p
.PtrSize
{
1327 error_(e
.Pos(), "unrecognized Go type %s", t
.Name
)
1328 return &Type
{Size
: 4, Align
: 4, C
: c("int")}
1329 case *ast
.SelectorExpr
:
1330 id
, ok
:= t
.X
.(*ast
.Ident
)
1331 if ok
&& id
.Name
== "unsafe" && t
.Sel
.Name
== "Pointer" {
1332 return &Type
{Size
: p
.PtrSize
, Align
: p
.PtrSize
, C
: c("void*")}
1335 error_(e
.Pos(), "Go type not supported in export: %s", gofmt(e
))
1336 return &Type
{Size
: 4, Align
: 4, C
: c("int")}
1340 #line 1 "cgo-gcc-prolog"
1342 If x and y are not equal, the type will be invalid
1343 (have a negative array count) and an inscrutable error will come
1344 out of the compiler and hopefully mention "name".
1346 #define __cgo_compile_assert_eq(x, y, name) typedef char name[(x-y)*(x-y)*-2+1];
1348 /* Check at compile time that the sizes we use match our expectations. */
1349 #define __cgo_size_assert(t, n) __cgo_compile_assert_eq(sizeof(t), n, _cgo_sizeof_##t##_is_not_##n)
1351 __cgo_size_assert(char, 1)
1352 __cgo_size_assert(short, 2)
1353 __cgo_size_assert(int, 4)
1354 typedef long long __cgo_long_long;
1355 __cgo_size_assert(__cgo_long_long, 8)
1356 __cgo_size_assert(float, 4)
1357 __cgo_size_assert(double, 8)
1359 extern char* _cgo_topofstack(void);
1365 // Prologue defining TSAN functions in C.
1366 const noTsanProlog
= `
1367 #define CGO_NO_SANITIZE_THREAD
1368 #define _cgo_tsan_acquire()
1369 #define _cgo_tsan_release()
1372 // This must match the TSAN code in runtime/cgo/libcgo.h.
1373 // This is used when the code is built with the C/C++ Thread SANitizer,
1374 // which is not the same as the Go race detector.
1375 // __tsan_acquire tells TSAN that we are acquiring a lock on a variable,
1376 // in this case _cgo_sync. __tsan_release releases the lock.
1377 // (There is no actual lock, we are just telling TSAN that there is.)
1379 // When we call from Go to C we call _cgo_tsan_acquire.
1380 // When the C function returns we call _cgo_tsan_release.
1381 // Similarly, when C calls back into Go we call _cgo_tsan_release
1382 // and then call _cgo_tsan_acquire when we return to C.
1383 // These calls tell TSAN that there is a serialization point at the C call.
1385 // This is necessary because TSAN, which is a C/C++ tool, can not see
1386 // the synchronization in the Go code. Without these calls, when
1387 // multiple goroutines call into C code, TSAN does not understand
1388 // that the calls are properly synchronized on the Go side.
1390 // To be clear, if the calls are not properly synchronized on the Go side,
1391 // we will be hiding races. But when using TSAN on mixed Go C/C++ code
1392 // it is more important to avoid false positives, which reduce confidence
1393 // in the tool, than to avoid false negatives.
1394 const yesTsanProlog
= `
1395 #line 1 "cgo-tsan-prolog"
1396 #define CGO_NO_SANITIZE_THREAD __attribute__ ((no_sanitize_thread))
1398 long long _cgo_sync __attribute__ ((common));
1400 extern void __tsan_acquire(void*);
1401 extern void __tsan_release(void*);
1403 __attribute__ ((unused))
1404 static void _cgo_tsan_acquire() {
1405 __tsan_acquire(&_cgo_sync);
1408 __attribute__ ((unused))
1409 static void _cgo_tsan_release() {
1410 __tsan_release(&_cgo_sync);
1414 // Set to yesTsanProlog if we see -fsanitize=thread in the flags for gcc.
1415 var tsanProlog
= noTsanProlog
1417 const builtinProlog
= `
1418 #line 1 "cgo-builtin-prolog"
1419 #include <stddef.h> /* for ptrdiff_t and size_t below */
1421 /* Define intgo when compiling with GCC. */
1422 typedef ptrdiff_t intgo;
1424 typedef struct { const char *p; intgo n; } _GoString_;
1425 typedef struct { char *p; intgo n; intgo c; } _GoBytes_;
1426 _GoString_ GoString(char *p);
1427 _GoString_ GoStringN(char *p, int l);
1428 _GoBytes_ GoBytes(void *p, int n);
1429 char *CString(_GoString_);
1430 void *CBytes(_GoBytes_);
1431 void *_CMalloc(size_t);
1433 __attribute__ ((unused))
1434 static size_t _GoStringLen(_GoString_ s) { return s.n; }
1436 __attribute__ ((unused))
1437 static const char *_GoStringPtr(_GoString_ s) { return s.p; }
1441 //go:linkname _cgo_runtime_cgocall runtime.cgocall
1442 func _cgo_runtime_cgocall(unsafe.Pointer, uintptr) int32
1444 //go:linkname _cgo_runtime_cgocallback runtime.cgocallback
1445 func _cgo_runtime_cgocallback(unsafe.Pointer, unsafe.Pointer, uintptr, uintptr)
1447 //go:linkname _cgoCheckPointer runtime.cgoCheckPointer
1448 func _cgoCheckPointer(interface{}, ...interface{})
1450 //go:linkname _cgoCheckResult runtime.cgoCheckResult
1451 func _cgoCheckResult(interface{})
1454 const gccgoGoProlog
= `
1455 func _cgoCheckPointer(interface{}, ...interface{})
1457 func _cgoCheckResult(interface{})
1460 const goStringDef
= `
1461 //go:linkname _cgo_runtime_gostring runtime.gostring
1462 func _cgo_runtime_gostring(*_Ctype_char) string
1464 func _Cfunc_GoString(p *_Ctype_char) string {
1465 return _cgo_runtime_gostring(p)
1469 const goStringNDef
= `
1470 //go:linkname _cgo_runtime_gostringn runtime.gostringn
1471 func _cgo_runtime_gostringn(*_Ctype_char, int) string
1473 func _Cfunc_GoStringN(p *_Ctype_char, l _Ctype_int) string {
1474 return _cgo_runtime_gostringn(p, int(l))
1478 const goBytesDef
= `
1479 //go:linkname _cgo_runtime_gobytes runtime.gobytes
1480 func _cgo_runtime_gobytes(unsafe.Pointer, int) []byte
1482 func _Cfunc_GoBytes(p unsafe.Pointer, l _Ctype_int) []byte {
1483 return _cgo_runtime_gobytes(p, int(l))
1487 const cStringDef
= `
1488 func _Cfunc_CString(s string) *_Ctype_char {
1489 p := _cgo_cmalloc(uint64(len(s)+1))
1490 pp := (*[1<<30]byte)(p)
1493 return (*_Ctype_char)(p)
1498 func _Cfunc_CBytes(b []byte) unsafe.Pointer {
1499 p := _cgo_cmalloc(uint64(len(b)))
1500 pp := (*[1<<30]byte)(p)
1506 const cMallocDef
= `
1507 func _Cfunc__CMalloc(n _Ctype_size_t) unsafe.Pointer {
1508 return _cgo_cmalloc(uint64(n))
1512 var builtinDefs
= map[string]string{
1513 "GoString": goStringDef
,
1514 "GoStringN": goStringNDef
,
1515 "GoBytes": goBytesDef
,
1516 "CString": cStringDef
,
1517 "CBytes": cBytesDef
,
1518 "_CMalloc": cMallocDef
,
1521 // Definitions for C.malloc in Go and in C. We define it ourselves
1522 // since we call it from functions we define, such as C.CString.
1523 // Also, we have historically ensured that C.malloc does not return
1524 // nil even for an allocation of 0.
1526 const cMallocDefGo
= `
1527 //go:cgo_import_static _cgoPREFIX_Cfunc__Cmalloc
1528 //go:linkname __cgofn__cgoPREFIX_Cfunc__Cmalloc _cgoPREFIX_Cfunc__Cmalloc
1529 var __cgofn__cgoPREFIX_Cfunc__Cmalloc byte
1530 var _cgoPREFIX_Cfunc__Cmalloc = unsafe.Pointer(&__cgofn__cgoPREFIX_Cfunc__Cmalloc)
1532 //go:linkname runtime_throw runtime.throw
1533 func runtime_throw(string)
1535 //go:cgo_unsafe_args
1536 func _cgo_cmalloc(p0 uint64) (r1 unsafe.Pointer) {
1537 _cgo_runtime_cgocall(_cgoPREFIX_Cfunc__Cmalloc, uintptr(unsafe.Pointer(&p0)))
1539 runtime_throw("runtime: C malloc failed")
1545 // cMallocDefC defines the C version of C.malloc for the gc compiler.
1546 // It is defined here because C.CString and friends need a definition.
1547 // We define it by hand, rather than simply inventing a reference to
1548 // C.malloc, because <stdlib.h> may not have been included.
1549 // This is approximately what writeOutputFunc would generate, but
1550 // skips the cgo_topofstack code (which is only needed if the C code
1551 // calls back into Go). This also avoids returning nil for an
1552 // allocation of 0 bytes.
1553 const cMallocDefC
= `
1554 CGO_NO_SANITIZE_THREAD
1555 void _cgoPREFIX_Cfunc__Cmalloc(void *v) {
1557 unsigned long long p0;
1561 _cgo_tsan_acquire();
1562 ret = malloc(a->p0);
1563 if (ret == 0 && a->p0 == 0) {
1567 _cgo_tsan_release();
1571 func (p
*Package
) cPrologGccgo() string {
1572 return strings
.Replace(strings
.Replace(cPrologGccgo
, "PREFIX", cPrefix
, -1),
1573 "GCCGOSYMBOLPREF", p
.gccgoSymbolPrefix(), -1)
1576 const cPrologGccgo
= `
1577 #line 1 "cgo-c-prolog-gccgo"
1582 typedef unsigned char byte;
1583 typedef intptr_t intgo;
1585 struct __go_string {
1586 const unsigned char *__data;
1590 typedef struct __go_open_array {
1596 struct __go_string __go_byte_array_to_string(const void* p, intgo len);
1597 struct __go_open_array __go_string_to_byte_array (struct __go_string str);
1599 const char *_cgoPREFIX_Cfunc_CString(struct __go_string s) {
1600 char *p = malloc(s.__length+1);
1601 memmove(p, s.__data, s.__length);
1606 void *_cgoPREFIX_Cfunc_CBytes(struct __go_open_array b) {
1607 char *p = malloc(b.__count);
1608 memmove(p, b.__values, b.__count);
1612 struct __go_string _cgoPREFIX_Cfunc_GoString(char *p) {
1613 intgo len = (p != NULL) ? strlen(p) : 0;
1614 return __go_byte_array_to_string(p, len);
1617 struct __go_string _cgoPREFIX_Cfunc_GoStringN(char *p, int32_t n) {
1618 return __go_byte_array_to_string(p, n);
1621 Slice _cgoPREFIX_Cfunc_GoBytes(char *p, int32_t n) {
1622 struct __go_string s = { (const unsigned char *)p, n };
1623 return __go_string_to_byte_array(s);
1626 extern void runtime_throw(const char *);
1627 void *_cgoPREFIX_Cfunc__CMalloc(size_t n) {
1628 void *p = malloc(n);
1629 if(p == NULL && n == 0)
1632 runtime_throw("runtime: C malloc failed");
1636 struct __go_type_descriptor;
1637 typedef struct __go_empty_interface {
1638 const struct __go_type_descriptor *__type_descriptor;
1642 extern void runtimeCgoCheckPointer(Eface, Slice)
1643 __asm__("runtime.cgoCheckPointer")
1644 __attribute__((weak));
1646 extern void localCgoCheckPointer(Eface, Slice)
1647 __asm__("GCCGOSYMBOLPREF._cgoCheckPointer");
1649 void localCgoCheckPointer(Eface ptr, Slice args) {
1650 if(runtimeCgoCheckPointer) {
1651 runtimeCgoCheckPointer(ptr, args);
1655 extern void runtimeCgoCheckResult(Eface)
1656 __asm__("runtime.cgoCheckResult")
1657 __attribute__((weak));
1659 extern void localCgoCheckResult(Eface)
1660 __asm__("GCCGOSYMBOLPREF._cgoCheckResult");
1662 void localCgoCheckResult(Eface val) {
1663 if(runtimeCgoCheckResult) {
1664 runtimeCgoCheckResult(val);
1669 // builtinExportProlog is a shorter version of builtinProlog,
1670 // to be put into the _cgo_export.h file.
1671 // For historical reasons we can't use builtinProlog in _cgo_export.h,
1672 // because _cgo_export.h defines GoString as a struct while builtinProlog
1673 // defines it as a function. We don't change this to avoid unnecessarily
1674 // breaking existing code.
1675 const builtinExportProlog
= `
1676 #line 1 "cgo-builtin-prolog"
1678 #include <stddef.h> /* for ptrdiff_t below */
1680 #ifndef GO_CGO_EXPORT_PROLOGUE_H
1681 #define GO_CGO_EXPORT_PROLOGUE_H
1683 typedef ptrdiff_t intgo;
1685 typedef struct { const char *p; intgo n; } _GoString_;
1690 func (p
*Package
) gccExportHeaderProlog() string {
1691 return strings
.Replace(gccExportHeaderProlog
, "GOINTBITS", fmt
.Sprint(8*p
.IntSize
), -1)
1694 const gccExportHeaderProlog
= `
1695 /* Start of boilerplate cgo prologue. */
1696 #line 1 "cgo-gcc-export-header-prolog"
1698 #ifndef GO_CGO_PROLOGUE_H
1699 #define GO_CGO_PROLOGUE_H
1701 typedef signed char GoInt8;
1702 typedef unsigned char GoUint8;
1703 typedef short GoInt16;
1704 typedef unsigned short GoUint16;
1705 typedef int GoInt32;
1706 typedef unsigned int GoUint32;
1707 typedef long long GoInt64;
1708 typedef unsigned long long GoUint64;
1709 typedef GoIntGOINTBITS GoInt;
1710 typedef GoUintGOINTBITS GoUint;
1711 typedef __SIZE_TYPE__ GoUintptr;
1712 typedef float GoFloat32;
1713 typedef double GoFloat64;
1714 typedef float _Complex GoComplex64;
1715 typedef double _Complex GoComplex128;
1718 static assertion to make sure the file is being used on architecture
1719 at least with matching size of GoInt.
1721 typedef char _check_for_GOINTBITS_bit_pointer_matching_GoInt[sizeof(void*)==GOINTBITS/8 ? 1:-1];
1723 typedef _GoString_ GoString;
1724 typedef void *GoMap;
1725 typedef void *GoChan;
1726 typedef struct { void *t; void *v; } GoInterface;
1727 typedef struct { void *data; GoInt len; GoInt cap; } GoSlice;
1731 /* End of boilerplate cgo prologue. */
1738 // gccExportHeaderEpilog goes at the end of the generated header file.
1739 const gccExportHeaderEpilog
= `
1745 // gccgoExportFileProlog is written to the _cgo_export.c file when
1747 // We use weak declarations, and test the addresses, so that this code
1748 // works with older versions of gccgo.
1749 const gccgoExportFileProlog
= `
1750 #line 1 "cgo-gccgo-export-file-prolog"
1751 extern _Bool runtime_iscgo __attribute__ ((weak));
1753 static void GoInit(void) __attribute__ ((constructor));
1754 static void GoInit(void) {
1759 extern __SIZE_TYPE__ _cgo_wait_runtime_init_done() __attribute__ ((weak));