out.go 42.8 KB
Newer Older
1
// Copyright 2009 The Go Authors. All rights reserved.
Russ Cox's avatar
Russ Cox committed
2 3 4 5 6 7
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main

import (
Russ Cox's avatar
Russ Cox committed
8
	"bytes"
Russ Cox's avatar
Russ Cox committed
9 10
	"debug/elf"
	"debug/macho"
Wei Guangjing's avatar
Wei Guangjing committed
11
	"debug/pe"
12 13 14
	"fmt"
	"go/ast"
	"go/printer"
Ian Lance Taylor's avatar
Ian Lance Taylor committed
15
	"go/token"
16
	"io"
17
	"os"
18
	"sort"
19
	"strings"
Russ Cox's avatar
Russ Cox committed
20 21
)

22 23
var conf = printer.Config{Mode: printer.SourcePos, Tabwidth: 8}

24
// writeDefs creates output files to be compiled by gc and gcc.
Russ Cox's avatar
Russ Cox committed
25
func (p *Package) writeDefs() {
26 27 28 29 30 31 32 33 34
	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
	}
Russ Cox's avatar
Russ Cox committed
35
	fm := creat(*objDir + "_cgo_main.c")
36

37 38
	var gccgoInit bytes.Buffer

Russ Cox's avatar
Russ Cox committed
39
	fflg := creat(*objDir + "_cgo_flags")
40
	for k, v := range p.CgoFlags {
41
		fmt.Fprintf(fflg, "_CGO_%s=%s\n", k, strings.Join(v, " "))
42
		if k == "LDFLAGS" && !*gccgo {
43
			for _, arg := range v {
44
				fmt.Fprintf(fgo2, "//go:cgo_ldflag %q\n", arg)
45 46
			}
		}
47 48 49
	}
	fflg.Close()

50 51
	// Write C main file for using gcc to resolve imports.
	fmt.Fprintf(fm, "int main() { return 0; }\n")
Russ Cox's avatar
Russ Cox committed
52 53
	if *importRuntimeCgo {
		fmt.Fprintf(fm, "void crosscall2(void(*fn)(void*, int), void *a, int c) { }\n")
54
		fmt.Fprintf(fm, "void _cgo_wait_runtime_init_done() { }\n")
55
		fmt.Fprintf(fm, "char* _cgo_topofstack(void) { return (char*)0; }\n")
Russ Cox's avatar
Russ Cox committed
56 57
	} else {
		// If we're not importing runtime/cgo, we *are* runtime/cgo,
58
		// which provides these functions.  We just need a prototype.
59
		fmt.Fprintf(fm, "void crosscall2(void(*fn)(void*, int), void *a, int c);\n")
60
		fmt.Fprintf(fm, "void _cgo_wait_runtime_init_done();\n")
Russ Cox's avatar
Russ Cox committed
61
	}
62 63
	fmt.Fprintf(fm, "void _cgo_allocate(void *a, int c) { }\n")
	fmt.Fprintf(fm, "void _cgo_panic(void *a, int c) { }\n")
64
	fmt.Fprintf(fm, "void _cgo_reginit(void) { }\n")
Russ Cox's avatar
Russ Cox committed
65 66 67 68

	// Write second Go output: definitions of _C_xxx.
	// In a separate file so that the import of "unsafe" does not
	// pollute the original file.
69
	fmt.Fprintf(fgo2, "// Created by cgo - DO NOT EDIT\n\n")
Russ Cox's avatar
Russ Cox committed
70
	fmt.Fprintf(fgo2, "package %s\n\n", p.PackageName)
71
	fmt.Fprintf(fgo2, "import \"unsafe\"\n\n")
Russ Cox's avatar
Russ Cox committed
72
	if !*gccgo && *importRuntimeCgo {
73 74
		fmt.Fprintf(fgo2, "import _ \"runtime/cgo\"\n\n")
	}
Dmitriy Vyukov's avatar
Dmitriy Vyukov committed
75
	if *importSyscall {
76 77
		fmt.Fprintf(fgo2, "import \"syscall\"\n\n")
		fmt.Fprintf(fgo2, "var _ syscall.Errno\n")
Dmitriy Vyukov's avatar
Dmitriy Vyukov committed
78
	}
79
	fmt.Fprintf(fgo2, "func _Cgo_ptr(ptr unsafe.Pointer) unsafe.Pointer { return ptr }\n\n")
Russ Cox's avatar
Russ Cox committed
80

81 82 83 84 85 86 87
	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")
	}

88 89 90 91 92 93 94
	typedefNames := make([]string, 0, len(typedef))
	for name := range typedef {
		typedefNames = append(typedefNames, name)
	}
	sort.Strings(typedefNames)
	for _, name := range typedefNames {
		def := typedef[name]
95
		fmt.Fprintf(fgo2, "type %s ", name)
Russ Cox's avatar
Russ Cox committed
96
		conf.Fprint(fgo2, fset, def.Go)
97
		fmt.Fprintf(fgo2, "\n\n")
Russ Cox's avatar
Russ Cox committed
98
	}
99 100 101 102 103
	if *gccgo {
		fmt.Fprintf(fgo2, "type _Ctype_void byte\n")
	} else {
		fmt.Fprintf(fgo2, "type _Ctype_void [0]byte\n")
	}
Russ Cox's avatar
Russ Cox committed
104

105
	if *gccgo {
106
		fmt.Fprint(fgo2, gccgoGoProlog)
107
		fmt.Fprint(fc, p.cPrologGccgo())
108
	} else {
109
		fmt.Fprint(fgo2, goProlog)
110
	}
Russ Cox's avatar
Russ Cox committed
111

112 113 114 115 116 117 118
	for i, t := range p.CgoChecks {
		n := p.unsafeCheckPointerNameIndex(i)
		fmt.Fprintf(fgo2, "\nfunc %s(p interface{}, args ...interface{}) %s {\n", n, t)
		fmt.Fprintf(fgo2, "\treturn _cgoCheckPointer(p, args...).(%s)\n", t)
		fmt.Fprintf(fgo2, "}\n")
	}

119 120
	gccgoSymbolPrefix := p.gccgoSymbolPrefix()

121
	cVars := make(map[string]bool)
122 123
	for _, key := range nameKeys(p.Name) {
		n := p.Name[key]
124
		if !n.IsVar() {
Russ Cox's avatar
Russ Cox committed
125 126
			continue
		}
Russ Cox's avatar
Russ Cox committed
127

128
		if !cVars[n.C] {
129 130 131
			if *gccgo {
				fmt.Fprintf(fc, "extern byte *%s;\n", n.C)
			} else {
132 133
				fmt.Fprintf(fm, "extern char %s[];\n", n.C)
				fmt.Fprintf(fm, "void *_cgohack_%s = %s;\n\n", n.C, n.C)
134 135 136
				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)
137
			}
138 139
			cVars[n.C] = true
		}
140

141 142 143 144 145 146 147 148
		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))
		}
149 150
		if *gccgo {
			fmt.Fprintf(fc, `extern void *%s __asm__("%s.%s");`, n.Mangle, gccgoSymbolPrefix, n.Mangle)
151 152
			fmt.Fprintf(&gccgoInit, "\t%s = &%s;\n", n.Mangle, n.C)
			fmt.Fprintf(fc, "\n")
153
		}
Russ Cox's avatar
Russ Cox committed
154

Russ Cox's avatar
Russ Cox committed
155
		fmt.Fprintf(fgo2, "var %s ", n.Mangle)
156
		conf.Fprint(fgo2, fset, node)
157 158 159 160 161
		if !*gccgo {
			fmt.Fprintf(fgo2, " = (")
			conf.Fprint(fgo2, fset, node)
			fmt.Fprintf(fgo2, ")(unsafe.Pointer(&__cgo_%s))", n.C)
		}
162
		fmt.Fprintf(fgo2, "\n")
Russ Cox's avatar
Russ Cox committed
163
	}
164 165 166
	if *gccgo {
		fmt.Fprintf(fc, "\n")
	}
Russ Cox's avatar
Russ Cox committed
167

168 169
	for _, key := range nameKeys(p.Name) {
		n := p.Name[key]
Russ Cox's avatar
Russ Cox committed
170 171 172
		if n.Const != "" {
			fmt.Fprintf(fgo2, "const _Cconst_%s = %s\n", n.Go, n.Const)
		}
173 174 175
	}
	fmt.Fprintf(fgo2, "\n")

176 177
	for _, key := range nameKeys(p.Name) {
		n := p.Name[key]
Russ Cox's avatar
Russ Cox committed
178
		if n.FuncType != nil {
179
			p.writeDefsFunc(fgo2, n)
180
		}
Russ Cox's avatar
Russ Cox committed
181
	}
Russ Cox's avatar
Russ Cox committed
182

183 184
	fgcc := creat(*objDir + "_cgo_export.c")
	fgcch := creat(*objDir + "_cgo_export.h")
185
	if *gccgo {
186
		p.writeGccgoExports(fgo2, fm, fgcc, fgcch)
187
	} else {
188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209
		p.writeExports(fgo2, fm, fgcc, fgcch)
	}
	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)
		}
		_, err = io.Copy(fexp, fgcch)
		if err != nil {
			fatalf("%s", err)
		}
		if err = fexp.Close(); err != nil {
			fatalf("%s", err)
		}
210
	}
Russ Cox's avatar
Russ Cox committed
211

212 213 214 215 216 217 218
	init := gccgoInit.String()
	if init != "" {
		fmt.Fprintln(fc, "static void init(void) __attribute__ ((constructor));")
		fmt.Fprintln(fc, "static void init(void) {")
		fmt.Fprint(fc, init)
		fmt.Fprintln(fc, "}")
	}
Russ Cox's avatar
Russ Cox committed
219 220
}

Russ Cox's avatar
Russ Cox committed
221
func dynimport(obj string) {
Russ Cox's avatar
Russ Cox committed
222 223 224 225 226 227 228 229 230
	stdout := os.Stdout
	if *dynout != "" {
		f, err := os.Create(*dynout)
		if err != nil {
			fatalf("%s", err)
		}
		stdout = f
	}

231 232
	fmt.Fprintf(stdout, "package %s\n", *dynpackage)

Russ Cox's avatar
Russ Cox committed
233
	if f, err := elf.Open(obj); err == nil {
234 235
		if *dynlinker {
			// Emit the cgo_dynamic_linker line.
236 237 238
			if sec := f.Section(".interp"); sec != nil {
				if data, err := sec.Data(); err == nil && len(data) > 1 {
					// skip trailing \0 in data
239
					fmt.Fprintf(stdout, "//go:cgo_dynamic_linker %q\n", string(data[:len(data)-1]))
240
				}
241 242
			}
		}
Russ Cox's avatar
Russ Cox committed
243 244 245 246 247 248 249
		sym, err := f.ImportedSymbols()
		if err != nil {
			fatalf("cannot load imported symbols from ELF file %s: %v", obj, err)
		}
		for _, s := range sym {
			targ := s.Name
			if s.Version != "" {
250
				targ += "#" + s.Version
Wei Guangjing's avatar
Wei Guangjing committed
251
			}
252
			fmt.Fprintf(stdout, "//go:cgo_import_dynamic %s %s %q\n", s.Name, targ, s.Library)
Russ Cox's avatar
Russ Cox committed
253 254 255 256
		}
		lib, err := f.ImportedLibraries()
		if err != nil {
			fatalf("cannot load imported libraries from ELF file %s: %v", obj, err)
Russ Cox's avatar
Russ Cox committed
257
		}
Russ Cox's avatar
Russ Cox committed
258
		for _, l := range lib {
259
			fmt.Fprintf(stdout, "//go:cgo_import_dynamic _ _ %q\n", l)
Russ Cox's avatar
Russ Cox committed
260 261
		}
		return
Russ Cox's avatar
Russ Cox committed
262 263
	}

Russ Cox's avatar
Russ Cox committed
264 265 266 267 268 269 270 271
	if f, err := macho.Open(obj); err == nil {
		sym, err := f.ImportedSymbols()
		if err != nil {
			fatalf("cannot load imported symbols from Mach-O file %s: %v", obj, err)
		}
		for _, s := range sym {
			if len(s) > 0 && s[0] == '_' {
				s = s[1:]
Russ Cox's avatar
Russ Cox committed
272
			}
273
			fmt.Fprintf(stdout, "//go:cgo_import_dynamic %s %s %q\n", s, s, "")
Russ Cox's avatar
Russ Cox committed
274 275 276 277 278 279
		}
		lib, err := f.ImportedLibraries()
		if err != nil {
			fatalf("cannot load imported libraries from Mach-O file %s: %v", obj, err)
		}
		for _, l := range lib {
280
			fmt.Fprintf(stdout, "//go:cgo_import_dynamic _ _ %q\n", l)
Russ Cox's avatar
Russ Cox committed
281
		}
Russ Cox's avatar
Russ Cox committed
282
		return
Russ Cox's avatar
Russ Cox committed
283 284
	}

Russ Cox's avatar
Russ Cox committed
285 286 287
	if f, err := pe.Open(obj); err == nil {
		sym, err := f.ImportedSymbols()
		if err != nil {
Robert Hencke's avatar
Robert Hencke committed
288
			fatalf("cannot load imported symbols from PE file %s: %v", obj, err)
Russ Cox's avatar
Russ Cox committed
289 290
		}
		for _, s := range sym {
291
			ss := strings.Split(s, ":")
292
			name := strings.Split(ss[0], "@")[0]
293
			fmt.Fprintf(stdout, "//go:cgo_import_dynamic %s %s %q\n", name, ss[0], strings.ToLower(ss[1]))
Russ Cox's avatar
Russ Cox committed
294 295
		}
		return
Russ Cox's avatar
Russ Cox committed
296 297
	}

Russ Cox's avatar
Russ Cox committed
298
	fatalf("cannot parse %s as ELF, Mach-O or PE", obj)
Russ Cox's avatar
Russ Cox committed
299 300
}

301
// Construct a gcc struct matching the gc argument frame.
Russ Cox's avatar
Russ Cox committed
302 303
// 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.
304
// Also assumes that gc convention is to word-align the
Russ Cox's avatar
Russ Cox committed
305 306 307 308 309 310 311 312 313
// 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)
314
			off += pad
Russ Cox's avatar
Russ Cox committed
315
		}
Russ Cox's avatar
Russ Cox committed
316 317 318 319 320
		c := t.Typedef
		if c == "" {
			c = t.C.String()
		}
		fmt.Fprintf(&buf, "\t\t%s p%d;\n", c, i)
Russ Cox's avatar
Russ Cox committed
321 322 323 324 325 326 327 328 329 330 331
		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)
332
			off += pad
Russ Cox's avatar
Russ Cox committed
333
		}
334
		qual := ""
Gustavo Niemeyer's avatar
Gustavo Niemeyer committed
335
		if c := t.C.String(); c[len(c)-1] == '*' {
336 337 338
			qual = "const "
		}
		fmt.Fprintf(&buf, "\t\t%s%s r;\n", qual, t.C)
Russ Cox's avatar
Russ Cox committed
339 340 341 342 343 344 345 346 347 348
		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
	}
Gustavo Niemeyer's avatar
Gustavo Niemeyer committed
349
	fmt.Fprintf(&buf, "\t}")
Russ Cox's avatar
Russ Cox committed
350 351 352
	return buf.String(), off
}

353
func (p *Package) writeDefsFunc(fgo2 io.Writer, n *Name) {
Russ Cox's avatar
Russ Cox committed
354 355
	name := n.Go
	gtype := n.FuncType.Go
356
	void := gtype.Results == nil || len(gtype.Results.List) == 0
Russ Cox's avatar
Russ Cox committed
357
	if n.AddError {
358
		// Add "error" to return type list.
Russ Cox's avatar
Russ Cox committed
359
		// Type list is known to be 0 or 1 element - it's a C function.
360
		err := &ast.Field{Type: ast.NewIdent("error")}
Russ Cox's avatar
Russ Cox committed
361 362 363 364 365
		l := gtype.Results.List
		if len(l) == 0 {
			l = []*ast.Field{err}
		} else {
			l = []*ast.Field{l[0], err}
Russ Cox's avatar
Russ Cox committed
366
		}
Russ Cox's avatar
Russ Cox committed
367 368 369 370
		t := new(ast.FuncType)
		*t = *gtype
		t.Results = &ast.FieldList{List: l}
		gtype = t
371 372
	}

Russ Cox's avatar
Russ Cox committed
373 374 375 376 377
	// Go func declaration.
	d := &ast.FuncDecl{
		Name: ast.NewIdent(n.Mangle),
		Type: gtype,
	}
378

Ian Lance Taylor's avatar
Ian Lance Taylor committed
379
	// Builtins defined in the C prolog.
380 381 382 383 384 385 386 387
	inProlog := builtinDefs[name] != ""
	cname := fmt.Sprintf("_cgo%s%s", cPrefix, n.Mangle)
	paramnames := []string(nil)
	for i, param := range d.Type.Params.List {
		paramName := fmt.Sprintf("p%d", i)
		param.Names = []*ast.Ident{ast.NewIdent(paramName)}
		paramnames = append(paramnames, paramName)
	}
Ian Lance Taylor's avatar
Ian Lance Taylor committed
388

389
	if *gccgo {
390
		// Gccgo style hooks.
391 392 393
		fmt.Fprint(fgo2, "\n")
		conf.Fprint(fgo2, fset, d)
		fmt.Fprint(fgo2, " {\n")
Ian Lance Taylor's avatar
Ian Lance Taylor committed
394 395 396 397
		if !inProlog {
			fmt.Fprint(fgo2, "\tdefer syscall.CgocallDone()\n")
			fmt.Fprint(fgo2, "\tsyscall.Cgocall()\n")
		}
398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418
		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, ")
419
			}
420 421 422 423 424 425 426 427
			fmt.Fprint(fgo2, "nil\n")
		} else if !void {
			fmt.Fprint(fgo2, "\treturn r\n")
		}

		fmt.Fprint(fgo2, "}\n")

		// declare the C function.
428
		fmt.Fprintf(fgo2, "//extern %s\n", cname)
429 430
		d.Name = ast.NewIdent(cname)
		if n.AddError {
431 432 433
			l := d.Type.Results.List
			d.Type.Results.List = l[:len(l)-1]
		}
434 435 436
		conf.Fprint(fgo2, fset, d)
		fmt.Fprint(fgo2, "\n")

437
		return
438
	}
Ian Lance Taylor's avatar
Ian Lance Taylor committed
439

Ian Lance Taylor's avatar
Ian Lance Taylor committed
440
	if inProlog {
441
		fmt.Fprint(fgo2, builtinDefs[name])
Russ Cox's avatar
Russ Cox committed
442 443 444
		return
	}

445
	// Wrapper calls into gcc, passing a pointer to the argument frame.
446 447 448 449
	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)
450 451 452 453 454

	nret := 0
	if !void {
		d.Type.Results.List[0].Names = []*ast.Ident{ast.NewIdent("r1")}
		nret = 1
455
	}
456 457
	if n.AddError {
		d.Type.Results.List[nret].Names = []*ast.Ident{ast.NewIdent("r2")}
458
	}
459 460

	fmt.Fprint(fgo2, "\n")
461
	fmt.Fprint(fgo2, "//go:cgo_unsafe_args\n")
462 463 464 465 466 467 468 469 470
	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))"
471
	}
472 473

	prefix := ""
Russ Cox's avatar
Russ Cox committed
474
	if n.AddError {
475
		prefix = "errno := "
Russ Cox's avatar
Russ Cox committed
476
	}
477
	fmt.Fprintf(fgo2, "\t%s_cgo_runtime_cgocall(%s, %s)\n", prefix, cname, arg)
478 479 480
	if n.AddError {
		fmt.Fprintf(fgo2, "\tif errno != 0 { r2 = syscall.Errno(errno) }\n")
	}
481 482 483 484 485
	fmt.Fprintf(fgo2, "\tif _Cgo_always_false {\n")
	for i := range d.Type.Params.List {
		fmt.Fprintf(fgo2, "\t\t_Cgo_use(p%d)\n", i)
	}
	fmt.Fprintf(fgo2, "\t}\n")
486 487
	fmt.Fprintf(fgo2, "\treturn\n")
	fmt.Fprintf(fgo2, "}\n")
488 489
}

490
// writeOutput creates stubs for a specific source file to be compiled by gc
Russ Cox's avatar
Russ Cox committed
491
func (p *Package) writeOutput(f *File, srcfile string) {
492 493 494 495
	base := srcfile
	if strings.HasSuffix(base, ".go") {
		base = base[0 : len(base)-3]
	}
Russ Cox's avatar
Russ Cox committed
496
	base = strings.Map(slashToUnderscore, base)
Russ Cox's avatar
Russ Cox committed
497 498
	fgo1 := creat(*objDir + base + ".cgo1.go")
	fgcc := creat(*objDir + base + ".cgo2.c")
499

Russ Cox's avatar
Russ Cox committed
500 501 502
	p.GoFiles = append(p.GoFiles, base+".cgo1.go")
	p.GccFiles = append(p.GccFiles, base+".cgo2.c")

503
	// Write Go output: Go input with rewrites of C.xxx to _C_xxx.
504
	fmt.Fprintf(fgo1, "// Created by cgo - DO NOT EDIT\n\n")
505
	conf.Fprint(fgo1, fset, f.AST)
506

507
	// While we process the vars and funcs, also write gcc output.
508
	// Gcc output starts with the preamble.
Russ Cox's avatar
Russ Cox committed
509
	fmt.Fprintf(fgcc, "%s\n", f.Preamble)
510
	fmt.Fprintf(fgcc, "%s\n", gccProlog)
511
	fmt.Fprintf(fgcc, "%s\n", tsanProlog)
512

513 514
	for _, key := range nameKeys(f.Name) {
		n := f.Name[key]
Russ Cox's avatar
Russ Cox committed
515 516
		if n.FuncType != nil {
			p.writeOutputFunc(fgcc, n)
Russ Cox's avatar
Russ Cox committed
517 518
		}
	}
Russ Cox's avatar
Russ Cox committed
519

520 521
	fgo1.Close()
	fgcc.Close()
Russ Cox's avatar
Russ Cox committed
522 523
}

Robert Hencke's avatar
Robert Hencke committed
524
// fixGo converts the internal Name.Go field into the name we should show
525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541
// to users in error messages. There's only one for now: on input we rewrite
// C.malloc into C._CMalloc, so change it back here.
func fixGo(name string) string {
	if name == "_CMalloc" {
		return "malloc"
	}
	return name
}

var isBuiltin = map[string]bool{
	"_Cfunc_CString":   true,
	"_Cfunc_GoString":  true,
	"_Cfunc_GoStringN": true,
	"_Cfunc_GoBytes":   true,
	"_Cfunc__CMalloc":  true,
}

Russ Cox's avatar
Russ Cox committed
542 543
func (p *Package) writeOutputFunc(fgcc *os.File, n *Name) {
	name := n.Mangle
544
	if isBuiltin[name] || p.Written[name] {
Russ Cox's avatar
Russ Cox committed
545 546 547 548 549 550
		// 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

551
	if *gccgo {
Ian Lance Taylor's avatar
Ian Lance Taylor committed
552
		p.writeGccgoOutputFunc(fgcc, n)
553 554 555
		return
	}

Shenghou Ma's avatar
Shenghou Ma committed
556
	ctype, _ := p.structType(n)
Russ Cox's avatar
Russ Cox committed
557 558 559

	// Gcc wrapper unpacks the C argument struct
	// and calls the actual C function.
560 561 562 563 564
	if n.AddError {
		fmt.Fprintf(fgcc, "int\n")
	} else {
		fmt.Fprintf(fgcc, "void\n")
	}
565
	fmt.Fprintf(fgcc, "_cgo%s%s(void *v)\n", cPrefix, n.Mangle)
Russ Cox's avatar
Russ Cox committed
566 567 568 569
	fmt.Fprintf(fgcc, "{\n")
	if n.AddError {
		fmt.Fprintf(fgcc, "\terrno = 0;\n")
	}
570
	// We're trying to write a gcc struct that matches gc's layout.
571
	// Use packed attribute to force no padding in this struct in case
572
	// gcc has different packing requirements.
Shenghou Ma's avatar
Shenghou Ma committed
573
	fmt.Fprintf(fgcc, "\t%s %v *a = v;\n", ctype, p.packedAttribute())
574 575
	if n.FuncType.Result != nil {
		// Save the stack top for use below.
576
		fmt.Fprintf(fgcc, "\tchar *stktop = _cgo_topofstack();\n")
577
	}
578
	fmt.Fprintf(fgcc, "\t_cgo_tsan_acquire();\n")
Russ Cox's avatar
Russ Cox committed
579
	fmt.Fprintf(fgcc, "\t")
580
	if t := n.FuncType.Result; t != nil {
581
		fmt.Fprintf(fgcc, "__typeof__(a->r) r = ")
582
		if c := t.C.String(); c[len(c)-1] == '*' {
583
			fmt.Fprint(fgcc, "(__typeof__(a->r)) ")
584
		}
Russ Cox's avatar
Russ Cox committed
585 586
	}
	fmt.Fprintf(fgcc, "%s(", n.C)
Russ Cox's avatar
Russ Cox committed
587
	for i, t := range n.FuncType.Params {
Russ Cox's avatar
Russ Cox committed
588 589 590
		if i > 0 {
			fmt.Fprintf(fgcc, ", ")
		}
Russ Cox's avatar
Russ Cox committed
591 592 593 594 595 596 597 598 599 600
		// We know the type params are correct, because
		// the Go equivalents had good type params.
		// However, our version of the type omits the magic
		// words const and volatile, which can provoke
		// C compiler warnings.  Silence them by casting
		// all pointers to void*.  (Eventually that will produce
		// other warnings.)
		if c := t.C.String(); c[len(c)-1] == '*' {
			fmt.Fprintf(fgcc, "(void*)")
		}
Russ Cox's avatar
Russ Cox committed
601 602 603
		fmt.Fprintf(fgcc, "a->p%d", i)
	}
	fmt.Fprintf(fgcc, ");\n")
604
	fmt.Fprintf(fgcc, "\t_cgo_tsan_release();\n")
605 606 607
	if n.FuncType.Result != nil {
		// The cgo call may have caused a stack copy (via a callback).
		// Adjust the return value pointer appropriately.
608
		fmt.Fprintf(fgcc, "\ta = (void*)((char*)a + (_cgo_topofstack() - stktop));\n")
609 610 611
		// Save the return value.
		fmt.Fprintf(fgcc, "\ta->r = r;\n")
	}
Russ Cox's avatar
Russ Cox committed
612
	if n.AddError {
613
		fmt.Fprintf(fgcc, "\treturn errno;\n")
Russ Cox's avatar
Russ Cox committed
614 615 616 617 618
	}
	fmt.Fprintf(fgcc, "}\n")
	fmt.Fprintf(fgcc, "\n")
}

Ian Lance Taylor's avatar
Ian Lance Taylor committed
619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642
// 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
// 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) {
	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")
643 644 645 646
	if t := n.FuncType.Result; t != nil {
		fmt.Fprintf(fgcc, "\t%s r;\n", t.C.String())
	}
	fmt.Fprintf(fgcc, "\t_cgo_tsan_acquire();\n")
Ian Lance Taylor's avatar
Ian Lance Taylor committed
647 648
	fmt.Fprintf(fgcc, "\t")
	if t := n.FuncType.Result; t != nil {
649
		fmt.Fprintf(fgcc, "r = ")
Ian Lance Taylor's avatar
Ian Lance Taylor committed
650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666
		// Cast to void* to avoid warnings due to omitted qualifiers.
		if c := t.C.String(); c[len(c)-1] == '*' {
			fmt.Fprintf(fgcc, "(void*)")
		}
	}
	fmt.Fprintf(fgcc, "%s(", n.C)
	for i, t := range n.FuncType.Params {
		if i > 0 {
			fmt.Fprintf(fgcc, ", ")
		}
		// Cast to void* to avoid warnings due to omitted qualifiers.
		if c := t.C.String(); c[len(c)-1] == '*' {
			fmt.Fprintf(fgcc, "(void*)")
		}
		fmt.Fprintf(fgcc, "p%d", i)
	}
	fmt.Fprintf(fgcc, ");\n")
667 668 669 670 671 672 673 674 675 676
	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*)")
		}
		fmt.Fprintf(fgcc, "r;\n")
	}
Ian Lance Taylor's avatar
Ian Lance Taylor committed
677 678 679 680
	fmt.Fprintf(fgcc, "}\n")
	fmt.Fprintf(fgcc, "\n")
}

681
// packedAttribute returns host compiler struct attribute that will be
682 683
// used to match gc's struct layout. For example, on 386 Windows,
// gcc wants to 8-align int64s, but gc does not.
684
// Use __gcc_struct__ to work around http://gcc.gnu.org/PR52991 on x86,
685
// and https://golang.org/issue/5603.
686 687
func (p *Package) packedAttribute() string {
	s := "__attribute__((__packed__"
688
	if !p.GccIsClang && (goarch == "amd64" || goarch == "386") {
689 690 691 692 693
		s += ", __gcc_struct__"
	}
	return s + "))"
}

Ian Lance Taylor's avatar
Ian Lance Taylor committed
694 695
// Write out the various stubs we need to support functions exported
// from Go so that they are callable from C.
696
func (p *Package) writeExports(fgo2, fm, fgcc, fgcch io.Writer) {
697
	p.writeExportHeader(fgcch)
Ian Lance Taylor's avatar
Ian Lance Taylor committed
698 699

	fmt.Fprintf(fgcc, "/* Created by cgo - DO NOT EDIT. */\n")
700
	fmt.Fprintf(fgcc, "#include \"_cgo_export.h\"\n\n")
Ian Lance Taylor's avatar
Ian Lance Taylor committed
701

702 703
	fmt.Fprintf(fgcc, "extern void crosscall2(void (*fn)(void *, int), void *, int);\n")
	fmt.Fprintf(fgcc, "extern void _cgo_wait_runtime_init_done();\n\n")
704
	fmt.Fprintf(fgcc, "%s\n", tsanProlog)
705

Russ Cox's avatar
Russ Cox committed
706
	for _, exp := range p.ExpFunc {
Ian Lance Taylor's avatar
Ian Lance Taylor committed
707 708
		fn := exp.Func

709
		// Construct a gcc struct matching the gc argument and
710 711 712
		// result frame.  The gcc struct will be compiled with
		// __attribute__((packed)) so all padding must be accounted
		// for explicitly.
Russ Cox's avatar
Russ Cox committed
713
		ctype := "struct {\n"
Ian Lance Taylor's avatar
Ian Lance Taylor committed
714 715 716 717
		off := int64(0)
		npad := 0
		if fn.Recv != nil {
			t := p.cgoType(fn.Recv.List[0].Type)
Russ Cox's avatar
Russ Cox committed
718
			ctype += fmt.Sprintf("\t\t%s recv;\n", t.C)
Ian Lance Taylor's avatar
Ian Lance Taylor committed
719 720 721 722
			off += t.Size
		}
		fntype := fn.Type
		forFieldList(fntype.Params,
723
			func(i int, aname string, atype ast.Expr) {
Ian Lance Taylor's avatar
Ian Lance Taylor committed
724 725 726
				t := p.cgoType(atype)
				if off%t.Align != 0 {
					pad := t.Align - off%t.Align
Russ Cox's avatar
Russ Cox committed
727
					ctype += fmt.Sprintf("\t\tchar __pad%d[%d];\n", npad, pad)
Ian Lance Taylor's avatar
Ian Lance Taylor committed
728 729 730
					off += pad
					npad++
				}
Russ Cox's avatar
Russ Cox committed
731
				ctype += fmt.Sprintf("\t\t%s p%d;\n", t.C, i)
Ian Lance Taylor's avatar
Ian Lance Taylor committed
732 733 734 735
				off += t.Size
			})
		if off%p.PtrSize != 0 {
			pad := p.PtrSize - off%p.PtrSize
Russ Cox's avatar
Russ Cox committed
736
			ctype += fmt.Sprintf("\t\tchar __pad%d[%d];\n", npad, pad)
Ian Lance Taylor's avatar
Ian Lance Taylor committed
737 738 739 740
			off += pad
			npad++
		}
		forFieldList(fntype.Results,
741
			func(i int, aname string, atype ast.Expr) {
Ian Lance Taylor's avatar
Ian Lance Taylor committed
742 743 744
				t := p.cgoType(atype)
				if off%t.Align != 0 {
					pad := t.Align - off%t.Align
745
					ctype += fmt.Sprintf("\t\tchar __pad%d[%d];\n", npad, pad)
Ian Lance Taylor's avatar
Ian Lance Taylor committed
746 747 748
					off += pad
					npad++
				}
Russ Cox's avatar
Russ Cox committed
749
				ctype += fmt.Sprintf("\t\t%s r%d;\n", t.C, i)
Ian Lance Taylor's avatar
Ian Lance Taylor committed
750 751 752 753
				off += t.Size
			})
		if off%p.PtrSize != 0 {
			pad := p.PtrSize - off%p.PtrSize
Russ Cox's avatar
Russ Cox committed
754
			ctype += fmt.Sprintf("\t\tchar __pad%d[%d];\n", npad, pad)
Ian Lance Taylor's avatar
Ian Lance Taylor committed
755 756 757
			off += pad
			npad++
		}
Russ Cox's avatar
Russ Cox committed
758 759
		if ctype == "struct {\n" {
			ctype += "\t\tchar unused;\n" // avoid empty struct
Ian Lance Taylor's avatar
Ian Lance Taylor committed
760
		}
Russ Cox's avatar
Russ Cox committed
761
		ctype += "\t}"
Ian Lance Taylor's avatar
Ian Lance Taylor committed
762 763 764 765 766 767 768

		// 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 {
Gustavo Niemeyer's avatar
Gustavo Niemeyer committed
769
			gccResult = p.cgoType(fntype.Results.List[0].Type).C.String()
Ian Lance Taylor's avatar
Ian Lance Taylor committed
770 771 772 773
		} else {
			fmt.Fprintf(fgcch, "\n/* Return type for %s */\n", exp.ExpName)
			fmt.Fprintf(fgcch, "struct %s_return {\n", exp.ExpName)
			forFieldList(fntype.Results,
774 775 776 777 778 779
				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")
Ian Lance Taylor's avatar
Ian Lance Taylor committed
780 781 782 783 784 785 786 787
				})
			fmt.Fprintf(fgcch, "};\n")
			gccResult = "struct " + exp.ExpName + "_return"
		}

		// Build the wrapper function compiled by gcc.
		s := fmt.Sprintf("%s %s(", gccResult, exp.ExpName)
		if fn.Recv != nil {
Gustavo Niemeyer's avatar
Gustavo Niemeyer committed
788
			s += p.cgoType(fn.Recv.List[0].Type).C.String()
Ian Lance Taylor's avatar
Ian Lance Taylor committed
789 790 791
			s += " recv"
		}
		forFieldList(fntype.Params,
792
			func(i int, aname string, atype ast.Expr) {
Ian Lance Taylor's avatar
Ian Lance Taylor committed
793 794 795 796 797 798
				if i > 0 || fn.Recv != nil {
					s += ", "
				}
				s += fmt.Sprintf("%s p%d", p.cgoType(atype).C, i)
			})
		s += ")"
799 800 801 802

		if len(exp.Doc) > 0 {
			fmt.Fprintf(fgcch, "\n%s", exp.Doc)
		}
Ian Lance Taylor's avatar
Ian Lance Taylor committed
803 804
		fmt.Fprintf(fgcch, "\nextern %s;\n", s)

805
		fmt.Fprintf(fgcc, "extern void _cgoexp%s_%s(void *, int);\n", cPrefix, exp.ExpName)
Ian Lance Taylor's avatar
Ian Lance Taylor committed
806 807
		fmt.Fprintf(fgcc, "\n%s\n", s)
		fmt.Fprintf(fgcc, "{\n")
808
		fmt.Fprintf(fgcc, "\t_cgo_wait_runtime_init_done();\n")
809
		fmt.Fprintf(fgcc, "\t%s %v a;\n", ctype, p.packedAttribute())
Ian Lance Taylor's avatar
Ian Lance Taylor committed
810 811 812 813 814 815 816
		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 {
			fmt.Fprintf(fgcc, "\ta.recv = recv;\n")
		}
		forFieldList(fntype.Params,
817
			func(i int, aname string, atype ast.Expr) {
Ian Lance Taylor's avatar
Ian Lance Taylor committed
818 819
				fmt.Fprintf(fgcc, "\ta.p%d = p%d;\n", i, i)
			})
820
		fmt.Fprintf(fgcc, "\t_cgo_tsan_release();\n")
821
		fmt.Fprintf(fgcc, "\tcrosscall2(_cgoexp%s_%s, &a, %d);\n", cPrefix, exp.ExpName, off)
822
		fmt.Fprintf(fgcc, "\t_cgo_tsan_acquire();\n")
Ian Lance Taylor's avatar
Ian Lance Taylor committed
823 824 825 826 827
		if gccResult != "void" {
			if len(fntype.Results.List) == 1 && len(fntype.Results.List[0].Names) <= 1 {
				fmt.Fprintf(fgcc, "\treturn a.r0;\n")
			} else {
				forFieldList(fntype.Results,
828
					func(i int, aname string, atype ast.Expr) {
Ian Lance Taylor's avatar
Ian Lance Taylor committed
829 830 831 832 833 834 835
						fmt.Fprintf(fgcc, "\tr.r%d = a.r%d;\n", i, i)
					})
				fmt.Fprintf(fgcc, "\treturn r;\n")
			}
		}
		fmt.Fprintf(fgcc, "}\n")

836 837
		// Build the wrapper function compiled by cmd/compile.
		goname := "_cgoexpwrap" + cPrefix + "_"
Ian Lance Taylor's avatar
Ian Lance Taylor committed
838
		if fn.Recv != nil {
839
			goname += fn.Recv.List[0].Names[0].Name + "_"
Ian Lance Taylor's avatar
Ian Lance Taylor committed
840
		}
841
		goname += exp.Func.Name.Name
842
		fmt.Fprintf(fgo2, "//go:cgo_export_dynamic %s\n", exp.ExpName)
843 844 845
		fmt.Fprintf(fgo2, "//go:linkname _cgoexp%s_%s _cgoexp%s_%s\n", cPrefix, exp.ExpName, cPrefix, exp.ExpName)
		fmt.Fprintf(fgo2, "//go:cgo_export_static _cgoexp%s_%s\n", cPrefix, exp.ExpName)
		fmt.Fprintf(fgo2, "//go:nosplit\n") // no split stack, so no use of m or g
846
		fmt.Fprintf(fgo2, "//go:norace\n")  // must not have race detector calls inserted
847
		fmt.Fprintf(fgo2, "func _cgoexp%s_%s(a unsafe.Pointer, n int32) {\n", cPrefix, exp.ExpName)
848 849 850 851
		fmt.Fprintf(fgo2, "\tfn := %s\n", goname)
		// The indirect here is converting from a Go function pointer to a C function pointer.
		fmt.Fprintf(fgo2, "\t_cgo_runtime_cgocallback(**(**unsafe.Pointer)(unsafe.Pointer(&fn)), a, uintptr(n));\n")
		fmt.Fprintf(fgo2, "}\n")
Ian Lance Taylor's avatar
Ian Lance Taylor committed
852

853 854
		fmt.Fprintf(fm, "int _cgoexp%s_%s;\n", cPrefix, exp.ExpName)

855 856 857 858 859 860
		// This code uses printer.Fprint, not conf.Fprint,
		// because we don't want //line comments in the middle
		// of the function types.
		fmt.Fprintf(fgo2, "\n")
		fmt.Fprintf(fgo2, "func %s(", goname)
		comma := false
Ian Lance Taylor's avatar
Ian Lance Taylor committed
861
		if fn.Recv != nil {
862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878
			fmt.Fprintf(fgo2, "recv ")
			printer.Fprint(fgo2, fset, fn.Recv.List[0].Type)
			comma = true
		}
		forFieldList(fntype.Params,
			func(i int, aname string, atype ast.Expr) {
				if comma {
					fmt.Fprintf(fgo2, ", ")
				}
				fmt.Fprintf(fgo2, "p%d ", i)
				printer.Fprint(fgo2, fset, atype)
				comma = true
			})
		fmt.Fprintf(fgo2, ")")
		if gccResult != "void" {
			fmt.Fprint(fgo2, " (")
			forFieldList(fntype.Results,
879
				func(i int, aname string, atype ast.Expr) {
880 881 882 883 884
					if i > 0 {
						fmt.Fprint(fgo2, ", ")
					}
					fmt.Fprintf(fgo2, "r%d ", i)
					printer.Fprint(fgo2, fset, atype)
Ian Lance Taylor's avatar
Ian Lance Taylor committed
885
				})
886 887 888 889
			fmt.Fprint(fgo2, ")")
		}
		fmt.Fprint(fgo2, " {\n")
		if gccResult == "void" {
Ian Lance Taylor's avatar
Ian Lance Taylor committed
890
			fmt.Fprint(fgo2, "\t")
891 892 893 894 895
		} else {
			// Verify that any results don't contain any
			// Go pointers.
			addedDefer := false
			forFieldList(fntype.Results,
896
				func(i int, aname string, atype ast.Expr) {
897 898 899 900 901 902
					if !p.hasPointer(nil, atype, false) {
						return
					}
					if !addedDefer {
						fmt.Fprint(fgo2, "\tdefer func() {\n")
						addedDefer = true
Ian Lance Taylor's avatar
Ian Lance Taylor committed
903
					}
904
					fmt.Fprintf(fgo2, "\t\t_cgoCheckResult(r%d)\n", i)
Ian Lance Taylor's avatar
Ian Lance Taylor committed
905
				})
906 907 908 909 910 911 912
			if addedDefer {
				fmt.Fprint(fgo2, "\t}()\n")
			}
			fmt.Fprint(fgo2, "\treturn ")
		}
		if fn.Recv != nil {
			fmt.Fprintf(fgo2, "recv.")
Ian Lance Taylor's avatar
Ian Lance Taylor committed
913
		}
914 915 916 917 918 919 920 921 922 923
		fmt.Fprintf(fgo2, "%s(", exp.Func.Name)
		forFieldList(fntype.Params,
			func(i int, aname string, atype ast.Expr) {
				if i > 0 {
					fmt.Fprint(fgo2, ", ")
				}
				fmt.Fprintf(fgo2, "p%d", i)
			})
		fmt.Fprint(fgo2, ")\n")
		fmt.Fprint(fgo2, "}\n")
Ian Lance Taylor's avatar
Ian Lance Taylor committed
924
	}
925 926

	fmt.Fprintf(fgcch, "%s", gccExportHeaderEpilog)
Ian Lance Taylor's avatar
Ian Lance Taylor committed
927 928
}

929
// Write out the C header allowing C code to call exported gccgo functions.
930
func (p *Package) writeGccgoExports(fgo2, fm, fgcc, fgcch io.Writer) {
931
	gccgoSymbolPrefix := p.gccgoSymbolPrefix()
932

933
	p.writeExportHeader(fgcch)
934

935 936
	fmt.Fprintf(fgcc, "/* Created by cgo - DO NOT EDIT. */\n")
	fmt.Fprintf(fgcc, "#include \"_cgo_export.h\"\n")
937

938
	fmt.Fprintf(fgcc, "%s\n", gccgoExportFileProlog)
939
	fmt.Fprintf(fgcc, "%s\n", tsanProlog)
940

941 942 943 944 945 946 947
	for _, exp := range p.ExpFunc {
		fn := exp.Func
		fntype := fn.Type

		cdeclBuf := new(bytes.Buffer)
		resultCount := 0
		forFieldList(fntype.Results,
948
			func(i int, aname string, atype ast.Expr) { resultCount++ })
949 950 951 952 953
		switch resultCount {
		case 0:
			fmt.Fprintf(cdeclBuf, "void")
		case 1:
			forFieldList(fntype.Results,
954
				func(i int, aname string, atype ast.Expr) {
955 956 957 958 959
					t := p.cgoType(atype)
					fmt.Fprintf(cdeclBuf, "%s", t.C)
				})
		default:
			// Declare a result struct.
960
			fmt.Fprintf(fgcch, "\n/* Return type for %s */\n", exp.ExpName)
961 962
			fmt.Fprintf(fgcch, "struct %s_result {\n", exp.ExpName)
			forFieldList(fntype.Results,
963
				func(i int, aname string, atype ast.Expr) {
964
					t := p.cgoType(atype)
965 966 967 968 969
					fmt.Fprintf(fgcch, "\t%s r%d;", t.C, i)
					if len(aname) > 0 {
						fmt.Fprintf(fgcch, " /* %s */", aname)
					}
					fmt.Fprint(fgcch, "\n")
970 971 972 973 974
				})
			fmt.Fprintf(fgcch, "};\n")
			fmt.Fprintf(cdeclBuf, "struct %s_result", exp.ExpName)
		}

975 976 977 978 979 980 981
		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())
		}
982 983
		// Function parameters.
		forFieldList(fntype.Params,
984
			func(i int, aname string, atype ast.Expr) {
985
				if i > 0 || fn.Recv != nil {
986 987 988 989 990 991
					fmt.Fprintf(cdeclBuf, ", ")
				}
				t := p.cgoType(atype)
				fmt.Fprintf(cdeclBuf, "%s p%d", t.C, i)
			})
		fmt.Fprintf(cdeclBuf, ")")
992 993
		cParams := cdeclBuf.String()

994 995 996 997
		if len(exp.Doc) > 0 {
			fmt.Fprintf(fgcch, "\n%s", exp.Doc)
		}

998 999
		fmt.Fprintf(fgcch, "extern %s %s %s;\n", cRet, exp.ExpName, cParams)

1000 1001 1002 1003
		// 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.
1004
		goName := "Cgoexp_" + exp.ExpName
1005 1006
		fmt.Fprintf(fgcc, `extern %s %s %s __asm__("%s.%s");`, cRet, goName, cParams, gccgoSymbolPrefix, goName)
		fmt.Fprint(fgcc, "\n")
1007

1008 1009
		fmt.Fprint(fgcc, "\n")
		fmt.Fprintf(fgcc, "%s %s %s {\n", cRet, exp.ExpName, cParams)
1010 1011 1012
		if resultCount > 0 {
			fmt.Fprintf(fgcc, "\t%s r;\n", cRet)
		}
1013 1014
		fmt.Fprintf(fgcc, "\tif(_cgo_wait_runtime_init_done)\n")
		fmt.Fprintf(fgcc, "\t\t_cgo_wait_runtime_init_done();\n")
1015
		fmt.Fprintf(fgcc, "\t_cgo_tsan_release();\n")
1016 1017
		fmt.Fprint(fgcc, "\t")
		if resultCount > 0 {
1018
			fmt.Fprint(fgcc, "r = ")
1019 1020 1021 1022 1023 1024
		}
		fmt.Fprintf(fgcc, "%s(", goName)
		if fn.Recv != nil {
			fmt.Fprint(fgcc, "recv")
		}
		forFieldList(fntype.Params,
1025
			func(i int, aname string, atype ast.Expr) {
1026 1027 1028 1029 1030 1031
				if i > 0 || fn.Recv != nil {
					fmt.Fprintf(fgcc, ", ")
				}
				fmt.Fprintf(fgcc, "p%d", i)
			})
		fmt.Fprint(fgcc, ");\n")
1032 1033 1034 1035
		fmt.Fprintf(fgcc, "\t_cgo_tsan_acquire();\n")
		if resultCount > 0 {
			fmt.Fprint(fgcc, "\treturn r;\n")
		}
1036
		fmt.Fprint(fgcc, "}\n")
1037 1038

		// Dummy declaration for _cgo_main.c
1039 1040
		fmt.Fprintf(fm, `char %s[1] __asm__("%s.%s");`, goName, gccgoSymbolPrefix, goName)
		fmt.Fprint(fm, "\n")
1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054

		// 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,
1055
			func(i int, aname string, atype ast.Expr) {
1056 1057 1058 1059 1060 1061 1062 1063 1064 1065
				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,
1066
				func(i int, aname string, atype ast.Expr) {
1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085
					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,
1086
			func(i int, aname string, atype ast.Expr) {
1087 1088 1089 1090 1091 1092 1093
				if i > 0 {
					fmt.Fprint(fgo2, ", ")
				}
				fmt.Fprintf(fgo2, "p%d", i)
			})
		fmt.Fprint(fgo2, ")\n")
		fmt.Fprint(fgo2, "}\n")
1094
	}
1095 1096

	fmt.Fprintf(fgcch, "%s", gccExportHeaderEpilog)
1097 1098
}

1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114
// writeExportHeader writes out the start of the _cgo_export.h file.
func (p *Package) writeExportHeader(fgcch io.Writer) {
	fmt.Fprintf(fgcch, "/* Created by \"go tool cgo\" - DO NOT EDIT. */\n\n")
	pkg := *importPath
	if pkg == "" {
		pkg = p.PackagePath
	}
	fmt.Fprintf(fgcch, "/* package %s */\n\n", pkg)

	fmt.Fprintf(fgcch, "/* Start of preamble from import \"C\" comments.  */\n\n")
	fmt.Fprintf(fgcch, "%s\n", p.Preamble)
	fmt.Fprintf(fgcch, "\n/* End of preamble from import \"C\" comments.  */\n\n")

	fmt.Fprintf(fgcch, "%s\n", p.gccExportHeaderProlog())
}

1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142
// Return the package prefix when using gccgo.
func (p *Package) gccgoSymbolPrefix() string {
	if !*gccgo {
		return ""
	}

	clean := func(r rune) rune {
		switch {
		case 'A' <= r && r <= 'Z', 'a' <= r && r <= 'z',
			'0' <= r && r <= '9':
			return r
		}
		return '_'
	}

	if *gccgopkgpath != "" {
		return strings.Map(clean, *gccgopkgpath)
	}
	if *gccgoprefix == "" && p.PackageName == "main" {
		return "main"
	}
	prefix := strings.Map(clean, *gccgoprefix)
	if prefix == "" {
		prefix = "go"
	}
	return prefix + "." + p.PackageName
}

Ian Lance Taylor's avatar
Ian Lance Taylor committed
1143
// Call a function for each entry in an ast.FieldList, passing the
1144 1145
// index into the list, the name if any, and the type.
func forFieldList(fl *ast.FieldList, fn func(int, string, ast.Expr)) {
Ian Lance Taylor's avatar
Ian Lance Taylor committed
1146 1147 1148 1149 1150 1151
	if fl == nil {
		return
	}
	i := 0
	for _, r := range fl.List {
		if r.Names == nil {
1152
			fn(i, "", r.Type)
Ian Lance Taylor's avatar
Ian Lance Taylor committed
1153 1154
			i++
		} else {
1155 1156
			for _, n := range r.Names {
				fn(i, n.Name, r.Type)
Ian Lance Taylor's avatar
Ian Lance Taylor committed
1157 1158 1159 1160 1161 1162
				i++
			}
		}
	}
}

Gustavo Niemeyer's avatar
Gustavo Niemeyer committed
1163 1164 1165 1166
func c(repr string, args ...interface{}) *TypeRepr {
	return &TypeRepr{repr, args}
}

Ian Lance Taylor's avatar
Ian Lance Taylor committed
1167 1168
// Map predeclared Go types to Type.
var goTypes = map[string]*Type{
1169 1170
	"bool":       {Size: 1, Align: 1, C: c("GoUint8")},
	"byte":       {Size: 1, Align: 1, C: c("GoUint8")},
Russ Cox's avatar
Russ Cox committed
1171 1172
	"int":        {Size: 0, Align: 0, C: c("GoInt")},
	"uint":       {Size: 0, Align: 0, C: c("GoUint")},
1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185
	"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")},
	"float32":    {Size: 4, Align: 4, C: c("GoFloat32")},
	"float64":    {Size: 8, Align: 8, C: c("GoFloat64")},
	"complex64":  {Size: 8, Align: 8, C: c("GoComplex64")},
	"complex128": {Size: 16, Align: 16, C: c("GoComplex128")},
Ian Lance Taylor's avatar
Ian Lance Taylor committed
1186 1187 1188
}

// Map an ast type to a Type.
Russ Cox's avatar
Russ Cox committed
1189
func (p *Package) cgoType(e ast.Expr) *Type {
Ian Lance Taylor's avatar
Ian Lance Taylor committed
1190 1191 1192
	switch t := e.(type) {
	case *ast.StarExpr:
		x := p.cgoType(t.X)
Gustavo Niemeyer's avatar
Gustavo Niemeyer committed
1193
		return &Type{Size: p.PtrSize, Align: p.PtrSize, C: c("%s*", x.C)}
Ian Lance Taylor's avatar
Ian Lance Taylor committed
1194 1195
	case *ast.ArrayType:
		if t.Len == nil {
1196 1197
			// Slice: pointer, len, cap.
			return &Type{Size: p.PtrSize * 3, Align: p.PtrSize, C: c("GoSlice")}
Ian Lance Taylor's avatar
Ian Lance Taylor committed
1198 1199 1200 1201
		}
	case *ast.StructType:
		// TODO
	case *ast.FuncType:
Gustavo Niemeyer's avatar
Gustavo Niemeyer committed
1202
		return &Type{Size: p.PtrSize, Align: p.PtrSize, C: c("void*")}
Ian Lance Taylor's avatar
Ian Lance Taylor committed
1203
	case *ast.InterfaceType:
1204
		return &Type{Size: 2 * p.PtrSize, Align: p.PtrSize, C: c("GoInterface")}
Ian Lance Taylor's avatar
Ian Lance Taylor committed
1205
	case *ast.MapType:
Gustavo Niemeyer's avatar
Gustavo Niemeyer committed
1206
		return &Type{Size: p.PtrSize, Align: p.PtrSize, C: c("GoMap")}
Ian Lance Taylor's avatar
Ian Lance Taylor committed
1207
	case *ast.ChanType:
Gustavo Niemeyer's avatar
Gustavo Niemeyer committed
1208
		return &Type{Size: p.PtrSize, Align: p.PtrSize, C: c("GoChan")}
Ian Lance Taylor's avatar
Ian Lance Taylor committed
1209 1210 1211
	case *ast.Ident:
		// Look up the type in the top level declarations.
		// TODO: Handle types defined within a function.
Russ Cox's avatar
Russ Cox committed
1212
		for _, d := range p.Decl {
Ian Lance Taylor's avatar
Ian Lance Taylor committed
1213 1214 1215 1216 1217 1218 1219 1220 1221
			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
				}
1222
				if ts.Name.Name == t.Name {
Ian Lance Taylor's avatar
Ian Lance Taylor committed
1223 1224 1225 1226
					return p.cgoType(ts.Type)
				}
			}
		}
Russ Cox's avatar
Russ Cox committed
1227 1228
		if def := typedef[t.Name]; def != nil {
			return def
Ian Lance Taylor's avatar
Ian Lance Taylor committed
1229
		}
1230
		if t.Name == "uintptr" {
1231
			return &Type{Size: p.PtrSize, Align: p.PtrSize, C: c("GoUintptr")}
Ian Lance Taylor's avatar
Ian Lance Taylor committed
1232
		}
1233
		if t.Name == "string" {
1234
			// The string data is 1 pointer + 1 (pointer-sized) int.
Russ Cox's avatar
Russ Cox committed
1235
			return &Type{Size: 2 * p.PtrSize, Align: p.PtrSize, C: c("GoString")}
Ian Lance Taylor's avatar
Ian Lance Taylor committed
1236
		}
1237 1238 1239
		if t.Name == "error" {
			return &Type{Size: 2 * p.PtrSize, Align: p.PtrSize, C: c("GoInterface")}
		}
1240
		if r, ok := goTypes[t.Name]; ok {
Russ Cox's avatar
Russ Cox committed
1241 1242 1243 1244 1245 1246 1247
			if r.Size == 0 { // int or uint
				rr := new(Type)
				*rr = *r
				rr.Size = p.IntSize
				rr.Align = p.IntSize
				r = rr
			}
Ian Lance Taylor's avatar
Ian Lance Taylor committed
1248 1249 1250 1251 1252
			if r.Align > p.PtrSize {
				r.Align = p.PtrSize
			}
			return r
		}
1253
		error_(e.Pos(), "unrecognized Go type %s", t.Name)
Russ Cox's avatar
Russ Cox committed
1254
		return &Type{Size: 4, Align: 4, C: c("int")}
1255 1256 1257
	case *ast.SelectorExpr:
		id, ok := t.X.(*ast.Ident)
		if ok && id.Name == "unsafe" && t.Sel.Name == "Pointer" {
Gustavo Niemeyer's avatar
Gustavo Niemeyer committed
1258
			return &Type{Size: p.PtrSize, Align: p.PtrSize, C: c("void*")}
1259
		}
Ian Lance Taylor's avatar
Ian Lance Taylor committed
1260
	}
Russ Cox's avatar
Russ Cox committed
1261
	error_(e.Pos(), "Go type not supported in export: %s", gofmt(e))
Gustavo Niemeyer's avatar
Gustavo Niemeyer committed
1262
	return &Type{Size: 4, Align: 4, C: c("int")}
Ian Lance Taylor's avatar
Ian Lance Taylor committed
1263 1264
}

Russ Cox's avatar
Russ Cox committed
1265
const gccProlog = `
1266 1267 1268 1269 1270
/*
  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".
*/
Russ Cox's avatar
Russ Cox committed
1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282
#define __cgo_compile_assert_eq(x, y, name) typedef char name[(x-y)*(x-y)*-2+1];

// Check at compile time that the sizes we use match our expectations.
#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)
Russ Cox's avatar
Russ Cox committed
1283

1284
extern char* _cgo_topofstack(void);
1285

Russ Cox's avatar
Russ Cox committed
1286 1287
#include <errno.h>
#include <string.h>
Russ Cox's avatar
Russ Cox committed
1288 1289
`

1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314
// Prologue defining TSAN functions in C.
const tsanProlog = `
#define _cgo_tsan_acquire()
#define _cgo_tsan_release()
#if defined(__has_feature)
#if __has_feature(thread_sanitizer)
#undef _cgo_tsan_acquire
#undef _cgo_tsan_release

long long _cgo_sync __attribute__ ((common));

extern void __tsan_acquire(void*);
extern void __tsan_release(void*);

static void _cgo_tsan_acquire() {
	__tsan_acquire(&_cgo_sync);
}

static void _cgo_tsan_release() {
	__tsan_release(&_cgo_sync);
}
#endif
#endif
`

Russ Cox's avatar
Russ Cox committed
1315
const builtinProlog = `
1316
#include <stddef.h> /* for ptrdiff_t and size_t below */
1317

1318
/* Define intgo when compiling with GCC.  */
1319
typedef ptrdiff_t intgo;
1320 1321 1322

typedef struct { char *p; intgo n; } _GoString_;
typedef struct { char *p; intgo n; intgo c; } _GoBytes_;
Russ Cox's avatar
Russ Cox committed
1323
_GoString_ GoString(char *p);
1324 1325
_GoString_ GoStringN(char *p, int l);
_GoBytes_ GoBytes(void *p, int n);
Russ Cox's avatar
Russ Cox committed
1326
char *CString(_GoString_);
1327
void *_CMalloc(size_t);
Russ Cox's avatar
Russ Cox committed
1328 1329
`

1330
const goProlog = `
1331 1332
//go:linkname _cgo_runtime_cgocall runtime.cgocall
func _cgo_runtime_cgocall(unsafe.Pointer, uintptr) int32
1333 1334 1335 1336 1337 1338

//go:linkname _cgo_runtime_cmalloc runtime.cmalloc
func _cgo_runtime_cmalloc(uintptr) unsafe.Pointer

//go:linkname _cgo_runtime_cgocallback runtime.cgocallback
func _cgo_runtime_cgocallback(unsafe.Pointer, unsafe.Pointer, uintptr)
1339 1340 1341

//go:linkname _cgoCheckPointer runtime.cgoCheckPointer
func _cgoCheckPointer(interface{}, ...interface{}) interface{}
1342 1343 1344

//go:linkname _cgoCheckResult runtime.cgoCheckResult
func _cgoCheckResult(interface{})
1345 1346
`

1347
const gccgoGoProlog = `
1348
//extern runtime.cgoCheckPointer
1349 1350
func _cgoCheckPointer(interface{}, ...interface{}) interface{}

1351
//extern runtime.cgoCheckResult
1352 1353 1354
func _cgoCheckResult(interface{})
`

1355
const goStringDef = `
1356 1357 1358
//go:linkname _cgo_runtime_gostring runtime.gostring
func _cgo_runtime_gostring(*_Ctype_char) string

1359 1360
func _Cfunc_GoString(p *_Ctype_char) string {
	return _cgo_runtime_gostring(p)
Russ Cox's avatar
Russ Cox committed
1361
}
1362
`
Russ Cox's avatar
Russ Cox committed
1363

1364
const goStringNDef = `
1365 1366 1367
//go:linkname _cgo_runtime_gostringn runtime.gostringn
func _cgo_runtime_gostringn(*_Ctype_char, int) string

1368 1369
func _Cfunc_GoStringN(p *_Ctype_char, l _Ctype_int) string {
	return _cgo_runtime_gostringn(p, int(l))
Eric Clark's avatar
Eric Clark committed
1370
}
1371
`
Eric Clark's avatar
Eric Clark committed
1372

1373
const goBytesDef = `
1374 1375 1376
//go:linkname _cgo_runtime_gobytes runtime.gobytes
func _cgo_runtime_gobytes(unsafe.Pointer, int) []byte

1377 1378
func _Cfunc_GoBytes(p unsafe.Pointer, l _Ctype_int) []byte {
	return _cgo_runtime_gobytes(p, int(l))
Russ Cox's avatar
Russ Cox committed
1379
}
1380
`
Russ Cox's avatar
Russ Cox committed
1381

1382 1383 1384 1385 1386 1387 1388
const cStringDef = `
func _Cfunc_CString(s string) *_Ctype_char {
	p := _cgo_runtime_cmalloc(uintptr(len(s)+1))
	pp := (*[1<<30]byte)(p)
	copy(pp[:], s)
	pp[len(s)] = 0
	return (*_Ctype_char)(p)
Russ Cox's avatar
Russ Cox committed
1389
}
1390
`
1391

1392 1393 1394
const cMallocDef = `
func _Cfunc__CMalloc(n _Ctype_size_t) unsafe.Pointer {
	return _cgo_runtime_cmalloc(uintptr(n))
1395
}
Russ Cox's avatar
Russ Cox committed
1396
`
Ian Lance Taylor's avatar
Ian Lance Taylor committed
1397

1398 1399 1400 1401 1402 1403 1404 1405
var builtinDefs = map[string]string{
	"GoString":  goStringDef,
	"GoStringN": goStringNDef,
	"GoBytes":   goBytesDef,
	"CString":   cStringDef,
	"_CMalloc":  cMallocDef,
}

1406
func (p *Package) cPrologGccgo() string {
1407 1408
	return strings.Replace(strings.Replace(cPrologGccgo, "PREFIX", cPrefix, -1),
		"GCCGOSYMBOLPREF", p.gccgoSymbolPrefix(), -1)
1409 1410
}

1411 1412
const cPrologGccgo = `
#include <stdint.h>
1413
#include <stdlib.h>
1414 1415
#include <string.h>

1416
typedef unsigned char byte;
1417
typedef intptr_t intgo;
1418

1419 1420
struct __go_string {
	const unsigned char *__data;
1421
	intgo __length;
1422 1423 1424 1425
};

typedef struct __go_open_array {
	void* __values;
1426 1427
	intgo __count;
	intgo __capacity;
1428 1429
} Slice;

1430
struct __go_string __go_byte_array_to_string(const void* p, intgo len);
1431 1432
struct __go_open_array __go_string_to_byte_array (struct __go_string str);

1433
const char *_cgoPREFIX_Cfunc_CString(struct __go_string s) {
1434 1435 1436 1437
	char *p = malloc(s.__length+1);
	memmove(p, s.__data, s.__length);
	p[s.__length] = 0;
	return p;
1438 1439
}

1440
struct __go_string _cgoPREFIX_Cfunc_GoString(char *p) {
1441
	intgo len = (p != NULL) ? strlen(p) : 0;
1442
	return __go_byte_array_to_string(p, len);
1443 1444
}

1445
struct __go_string _cgoPREFIX_Cfunc_GoStringN(char *p, int32_t n) {
1446 1447 1448
	return __go_byte_array_to_string(p, n);
}

1449
Slice _cgoPREFIX_Cfunc_GoBytes(char *p, int32_t n) {
1450
	struct __go_string s = { (const unsigned char *)p, n };
1451 1452
	return __go_string_to_byte_array(s);
}
1453

1454 1455
extern void runtime_throw(const char *);
void *_cgoPREFIX_Cfunc__CMalloc(size_t n) {
1456
        void *p = malloc(n);
Russ Cox's avatar
Russ Cox committed
1457 1458
        if(p == NULL && n == 0)
                p = malloc(1);
1459 1460 1461 1462
        if(p == NULL)
                runtime_throw("runtime: C malloc failed");
        return p;
}
1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495

struct __go_type_descriptor;
typedef struct __go_empty_interface {
	const struct __go_type_descriptor *__type_descriptor;
	void *__object;
} Eface;

extern Eface runtimeCgoCheckPointer(Eface, Slice)
	__asm__("runtime.cgoCheckPointer")
	__attribute__((weak));

extern Eface localCgoCheckPointer(Eface, Slice)
	__asm__("GCCGOSYMBOLPREF._cgoCheckPointer");

Eface localCgoCheckPointer(Eface ptr, Slice args) {
	if(runtimeCgoCheckPointer) {
		return runtimeCgoCheckPointer(ptr, args);
	}
	return ptr;
}

extern void runtimeCgoCheckResult(Eface)
	__asm__("runtime.cgoCheckResult")
	__attribute__((weak));

extern void localCgoCheckResult(Eface)
	__asm__("GCCGOSYMBOLPREF._cgoCheckResult");

void localCgoCheckResult(Eface val) {
	if(runtimeCgoCheckResult) {
		runtimeCgoCheckResult(val);
	}
}
1496 1497
`

Russ Cox's avatar
Russ Cox committed
1498 1499 1500 1501
func (p *Package) gccExportHeaderProlog() string {
	return strings.Replace(gccExportHeaderProlog, "GOINTBITS", fmt.Sprint(8*p.IntSize), -1)
}

Ian Lance Taylor's avatar
Ian Lance Taylor committed
1502
const gccExportHeaderProlog = `
1503 1504
/* Start of boilerplate cgo prologue.  */

1505 1506 1507
#ifndef GO_CGO_PROLOGUE_H
#define GO_CGO_PROLOGUE_H

1508 1509 1510 1511 1512 1513 1514 1515
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;
Russ Cox's avatar
Russ Cox committed
1516 1517
typedef GoIntGOINTBITS GoInt;
typedef GoUintGOINTBITS GoUint;
1518 1519 1520
typedef __SIZE_TYPE__ GoUintptr;
typedef float GoFloat32;
typedef double GoFloat64;
1521 1522
typedef float _Complex GoComplex64;
typedef double _Complex GoComplex128;
Ian Lance Taylor's avatar
Ian Lance Taylor committed
1523

1524 1525 1526 1527
/*
  static assertion to make sure the file is being used on architecture
  at least with matching size of GoInt.
*/
1528 1529
typedef char _check_for_GOINTBITS_bit_pointer_matching_GoInt[sizeof(void*)==GOINTBITS/8 ? 1:-1];

1530
typedef struct { const char *p; GoInt n; } GoString;
Ian Lance Taylor's avatar
Ian Lance Taylor committed
1531 1532 1533
typedef void *GoMap;
typedef void *GoChan;
typedef struct { void *t; void *v; } GoInterface;
1534
typedef struct { void *data; GoInt len; GoInt cap; } GoSlice;
1535

1536 1537
#endif

1538
/* End of boilerplate cgo prologue.  */
1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549

#ifdef __cplusplus
extern "C" {
#endif
`

// gccExportHeaderEpilog goes at the end of the generated header file.
const gccExportHeaderEpilog = `
#ifdef __cplusplus
}
#endif
Ian Lance Taylor's avatar
Ian Lance Taylor committed
1550
`
1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566

// 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 = `
extern _Bool runtime_iscgo __attribute__ ((weak));

static void GoInit(void) __attribute__ ((constructor));
static void GoInit(void) {
	if(&runtime_iscgo)
		runtime_iscgo = 1;
}

extern void _cgo_wait_runtime_init_done() __attribute__ ((weak));
`