out.go 30.7 KB
Newer Older
Russ Cox's avatar
Russ Cox committed
1 2 3 4 5 6 7
// Copyright 2009 The Go Authors.  All rights reserved.
// 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
	"os"
17
	"sort"
18
	"strings"
Russ Cox's avatar
Russ Cox committed
19 20
)

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

23
// writeDefs creates output files to be compiled by 6g, 6c, and gcc.
Russ Cox's avatar
Russ Cox committed
24
// (The comments here say 6g and 6c but the code applies to the 8 and 5 tools too.)
Russ Cox's avatar
Russ Cox committed
25
func (p *Package) writeDefs() {
Russ Cox's avatar
Russ Cox committed
26 27 28
	fgo2 := creat(*objDir + "_cgo_gotypes.go")
	fc := creat(*objDir + "_cgo_defun.c")
	fm := creat(*objDir + "_cgo_main.c")
29

30 31
	var gccgoInit bytes.Buffer

Russ Cox's avatar
Russ Cox committed
32
	fflg := creat(*objDir + "_cgo_flags")
33 34 35 36 37
	for k, v := range p.CgoFlags {
		fmt.Fprintf(fflg, "_CGO_%s=%s\n", k, v)
	}
	fflg.Close()

38 39
	// 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
40 41 42 43 44 45 46
	if *importRuntimeCgo {
		fmt.Fprintf(fm, "void crosscall2(void(*fn)(void*, int), void *a, int c) { }\n")
	} else {
		// If we're not importing runtime/cgo, we *are* runtime/cgo,
		// which provides crosscall2.  We just need a prototype.
		fmt.Fprintf(fm, "void crosscall2(void(*fn)(void*, int), void *a, int c);")
	}
47 48
	fmt.Fprintf(fm, "void _cgo_allocate(void *a, int c) { }\n")
	fmt.Fprintf(fm, "void _cgo_panic(void *a, int c) { }\n")
Russ Cox's avatar
Russ Cox committed
49 50 51 52

	// Write second Go output: definitions of _C_xxx.
	// In a separate file so that the import of "unsafe" does not
	// pollute the original file.
53
	fmt.Fprintf(fgo2, "// Created by cgo - DO NOT EDIT\n\n")
Russ Cox's avatar
Russ Cox committed
54
	fmt.Fprintf(fgo2, "package %s\n\n", p.PackageName)
55
	fmt.Fprintf(fgo2, "import \"unsafe\"\n\n")
Dmitriy Vyukov's avatar
Dmitriy Vyukov committed
56 57 58
	if *importSyscall {
		fmt.Fprintf(fgo2, "import \"syscall\"\n\n")
	}
Russ Cox's avatar
Russ Cox committed
59
	if !*gccgo && *importRuntimeCgo {
60 61
		fmt.Fprintf(fgo2, "import _ \"runtime/cgo\"\n\n")
	}
62
	fmt.Fprintf(fgo2, "type _ unsafe.Pointer\n\n")
Dmitriy Vyukov's avatar
Dmitriy Vyukov committed
63
	if *importSyscall {
Russ Cox's avatar
Russ Cox committed
64
		fmt.Fprintf(fgo2, "func _Cerrno(dst *error, x int32) { *dst = syscall.Errno(x) }\n")
Dmitriy Vyukov's avatar
Dmitriy Vyukov committed
65
	}
Russ Cox's avatar
Russ Cox committed
66

67 68 69 70 71 72 73
	typedefNames := make([]string, 0, len(typedef))
	for name := range typedef {
		typedefNames = append(typedefNames, name)
	}
	sort.Strings(typedefNames)
	for _, name := range typedefNames {
		def := typedef[name]
74
		fmt.Fprintf(fgo2, "type %s ", name)
Russ Cox's avatar
Russ Cox committed
75
		conf.Fprint(fgo2, fset, def.Go)
76
		fmt.Fprintf(fgo2, "\n\n")
Russ Cox's avatar
Russ Cox committed
77
	}
78 79 80 81 82
	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
83

84 85 86 87 88
	if *gccgo {
		fmt.Fprintf(fc, cPrologGccgo)
	} else {
		fmt.Fprintf(fc, cProlog)
	}
Russ Cox's avatar
Russ Cox committed
89

90 91
	gccgoSymbolPrefix := p.gccgoSymbolPrefix()

92
	cVars := make(map[string]bool)
93 94
	for _, key := range nameKeys(p.Name) {
		n := p.Name[key]
Russ Cox's avatar
Russ Cox committed
95 96 97
		if n.Kind != "var" {
			continue
		}
Russ Cox's avatar
Russ Cox committed
98

99 100 101 102 103 104 105 106
		if !cVars[n.C] {
			fmt.Fprintf(fm, "extern char %s[];\n", n.C)
			fmt.Fprintf(fm, "void *_cgohack_%s = %s;\n\n", n.C, n.C)

			fmt.Fprintf(fc, "extern byte *%s;\n", n.C)

			cVars[n.C] = true
		}
107

108 109 110 111 112 113
		if *gccgo {
			fmt.Fprintf(fc, `extern void *%s __asm__("%s.%s");`, n.Mangle, gccgoSymbolPrefix, n.Mangle)
			fmt.Fprintf(&gccgoInit, "\t%s = &%s;\n", n.Mangle, n.C)
		} else {
			fmt.Fprintf(fc, "void *·%s = &%s;\n", n.Mangle, n.C)
		}
Russ Cox's avatar
Russ Cox committed
114 115
		fmt.Fprintf(fc, "\n")

Russ Cox's avatar
Russ Cox committed
116
		fmt.Fprintf(fgo2, "var %s ", n.Mangle)
117
		conf.Fprint(fgo2, fset, &ast.StarExpr{X: n.Type.Go})
118
		fmt.Fprintf(fgo2, "\n")
Russ Cox's avatar
Russ Cox committed
119
	}
120
	fmt.Fprintf(fc, "\n")
Russ Cox's avatar
Russ Cox committed
121

122 123
	for _, key := range nameKeys(p.Name) {
		n := p.Name[key]
Russ Cox's avatar
Russ Cox committed
124 125 126
		if n.Const != "" {
			fmt.Fprintf(fgo2, "const _Cconst_%s = %s\n", n.Go, n.Const)
		}
127 128 129
	}
	fmt.Fprintf(fgo2, "\n")

130 131
	for _, key := range nameKeys(p.Name) {
		n := p.Name[key]
Russ Cox's avatar
Russ Cox committed
132
		if n.FuncType != nil {
133
			p.writeDefsFunc(fc, fgo2, n)
134
		}
Russ Cox's avatar
Russ Cox committed
135
	}
Russ Cox's avatar
Russ Cox committed
136

137 138 139 140 141
	if *gccgo {
		p.writeGccgoExports(fgo2, fc, fm)
	} else {
		p.writeExports(fgo2, fc, fm)
	}
Russ Cox's avatar
Russ Cox committed
142

143 144 145 146 147 148 149 150
	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
151 152 153 154
	fgo2.Close()
	fc.Close()
}

Russ Cox's avatar
Russ Cox committed
155
func dynimport(obj string) {
Russ Cox's avatar
Russ Cox committed
156 157 158 159 160 161 162 163 164
	stdout := os.Stdout
	if *dynout != "" {
		f, err := os.Create(*dynout)
		if err != nil {
			fatalf("%s", err)
		}
		stdout = f
	}

Russ Cox's avatar
Russ Cox committed
165
	if f, err := elf.Open(obj); err == nil {
166 167 168 169 170 171 172
		if !*importRuntimeCgo {
			// We are runtime/cgo, so emit the cgo_dynamic_linker line.
			if sec := f.Section(".interp"); sec != nil {
				if data, err := sec.Data(); err == nil && len(data) > 1 {
					// skip trailing \0 in data
					fmt.Fprintf(stdout, "#pragma cgo_dynamic_linker %q\n", string(data[:len(data)-1]))
				}
173 174
			}
		}
Russ Cox's avatar
Russ Cox committed
175 176 177 178 179 180 181
		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 != "" {
182
				targ += "#" + s.Version
Wei Guangjing's avatar
Wei Guangjing committed
183
			}
184
			fmt.Fprintf(stdout, "#pragma cgo_import_dynamic %s %s %q\n", s.Name, targ, s.Library)
Russ Cox's avatar
Russ Cox committed
185 186 187 188
		}
		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
189
		}
Russ Cox's avatar
Russ Cox committed
190
		for _, l := range lib {
191
			fmt.Fprintf(stdout, "#pragma cgo_import_dynamic _ _ %q\n", l)
Russ Cox's avatar
Russ Cox committed
192 193
		}
		return
Russ Cox's avatar
Russ Cox committed
194 195
	}

Russ Cox's avatar
Russ Cox committed
196 197 198 199 200 201 202 203
	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
204
			}
205
			fmt.Fprintf(stdout, "#pragma cgo_import_dynamic %s %s %q\n", s, s, "")
Russ Cox's avatar
Russ Cox committed
206 207 208 209 210 211
		}
		lib, err := f.ImportedLibraries()
		if err != nil {
			fatalf("cannot load imported libraries from Mach-O file %s: %v", obj, err)
		}
		for _, l := range lib {
212
			fmt.Fprintf(stdout, "#pragma cgo_import_dynamic _ _ %q\n", l)
Russ Cox's avatar
Russ Cox committed
213
		}
Russ Cox's avatar
Russ Cox committed
214
		return
Russ Cox's avatar
Russ Cox committed
215 216
	}

Russ Cox's avatar
Russ Cox committed
217 218 219
	if f, err := pe.Open(obj); err == nil {
		sym, err := f.ImportedSymbols()
		if err != nil {
Robert Hencke's avatar
Robert Hencke committed
220
			fatalf("cannot load imported symbols from PE file %s: %v", obj, err)
Russ Cox's avatar
Russ Cox committed
221 222
		}
		for _, s := range sym {
223
			ss := strings.Split(s, ":")
224
			name := strings.Split(ss[0], "@")[0]
225
			fmt.Fprintf(stdout, "#pragma cgo_import_dynamic %s %s %q\n", name, ss[0], strings.ToLower(ss[1]))
Russ Cox's avatar
Russ Cox committed
226 227
		}
		return
Russ Cox's avatar
Russ Cox committed
228 229
	}

Russ Cox's avatar
Russ Cox committed
230
	fatalf("cannot parse %s as ELF, Mach-O or PE", obj)
Russ Cox's avatar
Russ Cox committed
231 232
}

Russ Cox's avatar
Russ Cox committed
233 234 235 236 237 238 239 240 241 242 243 244 245
// Construct a gcc struct matching the 6c argument frame.
// 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.
// Also assumes that 6c convention is to word-align the
// 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)
246
			off += pad
Russ Cox's avatar
Russ Cox committed
247
		}
Russ Cox's avatar
Russ Cox committed
248 249 250 251 252
		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
253 254 255 256 257 258 259 260 261 262 263
		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)
264
			off += pad
Russ Cox's avatar
Russ Cox committed
265
		}
266
		qual := ""
Gustavo Niemeyer's avatar
Gustavo Niemeyer committed
267
		if c := t.C.String(); c[len(c)-1] == '*' {
268 269 270
			qual = "const "
		}
		fmt.Fprintf(&buf, "\t\t%s%s r;\n", qual, t.C)
Russ Cox's avatar
Russ Cox committed
271 272 273 274 275 276 277 278
		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 n.AddError {
279
		fmt.Fprint(&buf, "\t\tvoid *e[2]; /* error */\n")
Russ Cox's avatar
Russ Cox committed
280 281 282 283 284
		off += 2 * p.PtrSize
	}
	if off == 0 {
		fmt.Fprintf(&buf, "\t\tchar unused;\n") // avoid empty struct
	}
Gustavo Niemeyer's avatar
Gustavo Niemeyer committed
285
	fmt.Fprintf(&buf, "\t}")
Russ Cox's avatar
Russ Cox committed
286 287 288
	return buf.String(), off
}

289
func (p *Package) writeDefsFunc(fc, fgo2 *os.File, n *Name) {
Russ Cox's avatar
Russ Cox committed
290 291
	name := n.Go
	gtype := n.FuncType.Go
292
	void := gtype.Results == nil || len(gtype.Results.List) == 0
Russ Cox's avatar
Russ Cox committed
293
	if n.AddError {
294
		// Add "error" to return type list.
Russ Cox's avatar
Russ Cox committed
295
		// Type list is known to be 0 or 1 element - it's a C function.
296
		err := &ast.Field{Type: ast.NewIdent("error")}
Russ Cox's avatar
Russ Cox committed
297 298 299 300 301
		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
302
		}
Russ Cox's avatar
Russ Cox committed
303 304 305 306
		t := new(ast.FuncType)
		*t = *gtype
		t.Results = &ast.FieldList{List: l}
		gtype = t
307 308
	}

Russ Cox's avatar
Russ Cox committed
309 310 311 312 313
	// Go func declaration.
	d := &ast.FuncDecl{
		Name: ast.NewIdent(n.Mangle),
		Type: gtype,
	}
314

315
	if *gccgo {
316
		// Gccgo style hooks.
317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350
		fmt.Fprint(fgo2, "\n")
		cname := fmt.Sprintf("_cgo%s%s", cPrefix, n.Mangle)
		paramnames := []string(nil)
		for i, param := range d.Type.Params.List {
			paramName := fmt.Sprintf("p%d", i)
			param.Names = []*ast.Ident{ast.NewIdent(paramName)}
			paramnames = append(paramnames, paramName)
		}

		conf.Fprint(fgo2, fset, d)
		fmt.Fprint(fgo2, " {\n")
		fmt.Fprint(fgo2, "\tdefer syscall.CgocallDone()\n")
		fmt.Fprint(fgo2, "\tsyscall.Cgocall()\n")
		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, ")
351
			}
352 353 354 355 356 357 358 359 360 361 362
			fmt.Fprint(fgo2, "nil\n")
		} else if !void {
			fmt.Fprint(fgo2, "\treturn r\n")
		}

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

		// declare the C function.
		fmt.Fprintf(fgo2, "//extern %s\n", n.C)
		d.Name = ast.NewIdent(cname)
		if n.AddError {
363 364 365
			l := d.Type.Results.List
			d.Type.Results.List = l[:len(l)-1]
		}
366 367 368
		conf.Fprint(fgo2, fset, d)
		fmt.Fprint(fgo2, "\n")

369
		return
370
	}
371 372
	conf.Fprint(fgo2, fset, d)
	fmt.Fprint(fgo2, "\n")
Ian Lance Taylor's avatar
Ian Lance Taylor committed
373

Russ Cox's avatar
Russ Cox committed
374
	if name == "CString" || name == "GoString" || name == "GoStringN" || name == "GoBytes" {
Russ Cox's avatar
Russ Cox committed
375 376 377 378 379 380 381 382
		// The builtins are already defined in the C prolog.
		return
	}

	var argSize int64
	_, argSize = p.structType(n)

	// C wrapper calls into gcc, passing a pointer to the argument frame.
383
	fmt.Fprintf(fc, "#pragma cgo_import_static _cgo%s%s\n", cPrefix, n.Mangle)
384
	fmt.Fprintf(fc, "void _cgo%s%s(void*);\n", cPrefix, n.Mangle)
Russ Cox's avatar
Russ Cox committed
385 386
	fmt.Fprintf(fc, "\n")
	fmt.Fprintf(fc, "void\n")
387 388 389
	if argSize == 0 {
		argSize++
	}
Russ Cox's avatar
Russ Cox committed
390 391
	fmt.Fprintf(fc, "·%s(struct{uint8 x[%d];}p)\n", n.Mangle, argSize)
	fmt.Fprintf(fc, "{\n")
392
	fmt.Fprintf(fc, "\truntime·cgocall(_cgo%s%s, &p);\n", cPrefix, n.Mangle)
Russ Cox's avatar
Russ Cox committed
393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410
	if n.AddError {
		// gcc leaves errno in first word of interface at end of p.
		// check whether it is zero; if so, turn interface into nil.
		// if not, turn interface into errno.
		// Go init function initializes ·_Cerrno with an os.Errno
		// for us to copy.
		fmt.Fprintln(fc, `	{
			int32 e;
			void **v;
			v = (void**)(&p+1) - 2;	/* v = final two void* of p */
			e = *(int32*)v;
			v[0] = (void*)0xdeadbeef;
			v[1] = (void*)0xdeadbeef;
			if(e == 0) {
				/* nil interface */
				v[0] = 0;
				v[1] = 0;
			} else {
411
				·_Cerrno(v, e);	/* fill in v as error for errno e */
Russ Cox's avatar
Russ Cox committed
412 413 414 415 416
			}
		}`)
	}
	fmt.Fprintf(fc, "}\n")
	fmt.Fprintf(fc, "\n")
417 418 419 420
}

// writeOutput creates stubs for a specific source file to be compiled by 6g
// (The comments here say 6g and 6c but the code applies to the 8 and 5 tools too.)
Russ Cox's avatar
Russ Cox committed
421
func (p *Package) writeOutput(f *File, srcfile string) {
422 423 424 425
	base := srcfile
	if strings.HasSuffix(base, ".go") {
		base = base[0 : len(base)-3]
	}
Russ Cox's avatar
Russ Cox committed
426
	base = strings.Map(slashToUnderscore, base)
Russ Cox's avatar
Russ Cox committed
427 428
	fgo1 := creat(*objDir + base + ".cgo1.go")
	fgcc := creat(*objDir + base + ".cgo2.c")
429

Russ Cox's avatar
Russ Cox committed
430 431 432
	p.GoFiles = append(p.GoFiles, base+".cgo1.go")
	p.GccFiles = append(p.GccFiles, base+".cgo2.c")

433
	// Write Go output: Go input with rewrites of C.xxx to _C_xxx.
434
	fmt.Fprintf(fgo1, "// Created by cgo - DO NOT EDIT\n\n")
435
	conf.Fprint(fgo1, fset, f.AST)
436 437 438

	// While we process the vars and funcs, also write 6c and gcc output.
	// Gcc output starts with the preamble.
Russ Cox's avatar
Russ Cox committed
439
	fmt.Fprintf(fgcc, "%s\n", f.Preamble)
440 441
	fmt.Fprintf(fgcc, "%s\n", gccProlog)

442 443
	for _, key := range nameKeys(f.Name) {
		n := f.Name[key]
Russ Cox's avatar
Russ Cox committed
444 445
		if n.FuncType != nil {
			p.writeOutputFunc(fgcc, n)
Russ Cox's avatar
Russ Cox committed
446 447
		}
	}
Russ Cox's avatar
Russ Cox committed
448

449 450
	fgo1.Close()
	fgcc.Close()
Russ Cox's avatar
Russ Cox committed
451 452
}

Russ Cox's avatar
Russ Cox committed
453 454
func (p *Package) writeOutputFunc(fgcc *os.File, n *Name) {
	name := n.Mangle
Russ Cox's avatar
Russ Cox committed
455
	if name == "_Cfunc_CString" || name == "_Cfunc_GoString" || name == "_Cfunc_GoStringN" || name == "_Cfunc_GoBytes" || p.Written[name] {
Russ Cox's avatar
Russ Cox committed
456 457 458 459 460 461
		// 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

462 463 464 465 466
	if *gccgo {
		// we don't use wrappers with gccgo.
		return
	}

Russ Cox's avatar
Russ Cox committed
467 468 469 470 471
	ctype, _ := p.structType(n)

	// Gcc wrapper unpacks the C argument struct
	// and calls the actual C function.
	fmt.Fprintf(fgcc, "void\n")
472
	fmt.Fprintf(fgcc, "_cgo%s%s(void *v)\n", cPrefix, n.Mangle)
Russ Cox's avatar
Russ Cox committed
473 474 475 476 477
	fmt.Fprintf(fgcc, "{\n")
	if n.AddError {
		fmt.Fprintf(fgcc, "\tint e;\n") // assuming 32 bit (see comment above structType)
		fmt.Fprintf(fgcc, "\terrno = 0;\n")
	}
478 479 480 481 482
	// We're trying to write a gcc struct that matches 6c/8c/5c's layout.
	// Use packed attribute to force no padding in this struct in case
	// gcc has different packing requirements.  For example,
	// on 386 Windows, gcc wants to 8-align int64s, but 8c does not.
	fmt.Fprintf(fgcc, "\t%s __attribute__((__packed__)) *a = v;\n", ctype)
Russ Cox's avatar
Russ Cox committed
483
	fmt.Fprintf(fgcc, "\t")
484
	if t := n.FuncType.Result; t != nil {
Russ Cox's avatar
Russ Cox committed
485
		fmt.Fprintf(fgcc, "a->r = ")
486 487 488
		if c := t.C.String(); c[len(c)-1] == '*' {
			fmt.Fprintf(fgcc, "(const %s) ", t.C)
		}
Russ Cox's avatar
Russ Cox committed
489 490
	}
	fmt.Fprintf(fgcc, "%s(", n.C)
Russ Cox's avatar
Russ Cox committed
491
	for i, t := range n.FuncType.Params {
Russ Cox's avatar
Russ Cox committed
492 493 494
		if i > 0 {
			fmt.Fprintf(fgcc, ", ")
		}
Russ Cox's avatar
Russ Cox committed
495 496 497 498 499 500 501 502 503 504
		// 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
505 506 507 508 509 510 511 512 513 514
		fmt.Fprintf(fgcc, "a->p%d", i)
	}
	fmt.Fprintf(fgcc, ");\n")
	if n.AddError {
		fmt.Fprintf(fgcc, "\t*(int*)(a->e) = errno;\n")
	}
	fmt.Fprintf(fgcc, "}\n")
	fmt.Fprintf(fgcc, "\n")
}

Ian Lance Taylor's avatar
Ian Lance Taylor committed
515 516
// Write out the various stubs we need to support functions exported
// from Go so that they are callable from C.
517
func (p *Package) writeExports(fgo2, fc, fm *os.File) {
Russ Cox's avatar
Russ Cox committed
518
	fgcc := creat(*objDir + "_cgo_export.c")
519
	fgcch := creat(*objDir + "_cgo_export.h")
Ian Lance Taylor's avatar
Ian Lance Taylor committed
520 521

	fmt.Fprintf(fgcch, "/* Created by cgo - DO NOT EDIT. */\n")
Russ Cox's avatar
Russ Cox committed
522
	fmt.Fprintf(fgcch, "%s\n", p.Preamble)
Russ Cox's avatar
Russ Cox committed
523
	fmt.Fprintf(fgcch, "%s\n", p.gccExportHeaderProlog())
Ian Lance Taylor's avatar
Ian Lance Taylor committed
524 525 526 527

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

528 529
	fmt.Fprintf(fgcc, "\nextern void crosscall2(void (*fn)(void *, int), void *, int);\n\n")

Russ Cox's avatar
Russ Cox committed
530
	for _, exp := range p.ExpFunc {
Ian Lance Taylor's avatar
Ian Lance Taylor committed
531 532 533
		fn := exp.Func

		// Construct a gcc struct matching the 6c argument and
534 535 536
		// 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
537
		ctype := "struct {\n"
Ian Lance Taylor's avatar
Ian Lance Taylor committed
538 539 540 541
		off := int64(0)
		npad := 0
		if fn.Recv != nil {
			t := p.cgoType(fn.Recv.List[0].Type)
Russ Cox's avatar
Russ Cox committed
542
			ctype += fmt.Sprintf("\t\t%s recv;\n", t.C)
Ian Lance Taylor's avatar
Ian Lance Taylor committed
543 544 545 546 547 548 549 550
			off += t.Size
		}
		fntype := fn.Type
		forFieldList(fntype.Params,
			func(i int, atype ast.Expr) {
				t := p.cgoType(atype)
				if off%t.Align != 0 {
					pad := t.Align - off%t.Align
Russ Cox's avatar
Russ Cox committed
551
					ctype += fmt.Sprintf("\t\tchar __pad%d[%d];\n", npad, pad)
Ian Lance Taylor's avatar
Ian Lance Taylor committed
552 553 554
					off += pad
					npad++
				}
Russ Cox's avatar
Russ Cox committed
555
				ctype += fmt.Sprintf("\t\t%s p%d;\n", t.C, i)
Ian Lance Taylor's avatar
Ian Lance Taylor committed
556 557 558 559
				off += t.Size
			})
		if off%p.PtrSize != 0 {
			pad := p.PtrSize - off%p.PtrSize
Russ Cox's avatar
Russ Cox committed
560
			ctype += fmt.Sprintf("\t\tchar __pad%d[%d];\n", npad, pad)
Ian Lance Taylor's avatar
Ian Lance Taylor committed
561 562 563 564 565 566 567 568
			off += pad
			npad++
		}
		forFieldList(fntype.Results,
			func(i int, atype ast.Expr) {
				t := p.cgoType(atype)
				if off%t.Align != 0 {
					pad := t.Align - off%t.Align
569
					ctype += fmt.Sprintf("\t\tchar __pad%d[%d];\n", npad, pad)
Ian Lance Taylor's avatar
Ian Lance Taylor committed
570 571 572
					off += pad
					npad++
				}
Russ Cox's avatar
Russ Cox committed
573
				ctype += fmt.Sprintf("\t\t%s r%d;\n", t.C, i)
Ian Lance Taylor's avatar
Ian Lance Taylor committed
574 575 576 577
				off += t.Size
			})
		if off%p.PtrSize != 0 {
			pad := p.PtrSize - off%p.PtrSize
Russ Cox's avatar
Russ Cox committed
578
			ctype += fmt.Sprintf("\t\tchar __pad%d[%d];\n", npad, pad)
Ian Lance Taylor's avatar
Ian Lance Taylor committed
579 580 581
			off += pad
			npad++
		}
Russ Cox's avatar
Russ Cox committed
582 583
		if ctype == "struct {\n" {
			ctype += "\t\tchar unused;\n" // avoid empty struct
Ian Lance Taylor's avatar
Ian Lance Taylor committed
584
		}
Russ Cox's avatar
Russ Cox committed
585
		ctype += "\t}"
Ian Lance Taylor's avatar
Ian Lance Taylor committed
586 587 588 589 590 591 592

		// 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
593
			gccResult = p.cgoType(fntype.Results.List[0].Type).C.String()
Ian Lance Taylor's avatar
Ian Lance Taylor committed
594 595 596 597 598 599 600 601 602 603 604 605 606 607
		} else {
			fmt.Fprintf(fgcch, "\n/* Return type for %s */\n", exp.ExpName)
			fmt.Fprintf(fgcch, "struct %s_return {\n", exp.ExpName)
			forFieldList(fntype.Results,
				func(i int, atype ast.Expr) {
					fmt.Fprintf(fgcch, "\t%s r%d;\n", p.cgoType(atype).C, i)
				})
			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
608
			s += p.cgoType(fn.Recv.List[0].Type).C.String()
Ian Lance Taylor's avatar
Ian Lance Taylor committed
609 610 611 612 613 614 615 616 617 618 619 620
			s += " recv"
		}
		forFieldList(fntype.Params,
			func(i int, atype ast.Expr) {
				if i > 0 || fn.Recv != nil {
					s += ", "
				}
				s += fmt.Sprintf("%s p%d", p.cgoType(atype).C, i)
			})
		s += ")"
		fmt.Fprintf(fgcch, "\nextern %s;\n", s)

621
		fmt.Fprintf(fgcc, "extern void _cgoexp%s_%s(void *, int);\n", cPrefix, exp.ExpName)
Ian Lance Taylor's avatar
Ian Lance Taylor committed
622 623
		fmt.Fprintf(fgcc, "\n%s\n", s)
		fmt.Fprintf(fgcc, "{\n")
624
		fmt.Fprintf(fgcc, "\t%s __attribute__((packed)) a;\n", ctype)
Ian Lance Taylor's avatar
Ian Lance Taylor committed
625 626 627 628 629 630 631 632 633 634
		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,
			func(i int, atype ast.Expr) {
				fmt.Fprintf(fgcc, "\ta.p%d = p%d;\n", i, i)
			})
635
		fmt.Fprintf(fgcc, "\tcrosscall2(_cgoexp%s_%s, &a, %d);\n", cPrefix, exp.ExpName, off)
Ian Lance Taylor's avatar
Ian Lance Taylor committed
636 637 638 639 640 641 642 643 644 645 646 647 648 649
		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,
					func(i int, atype ast.Expr) {
						fmt.Fprintf(fgcc, "\tr.r%d = a.r%d;\n", i, i)
					})
				fmt.Fprintf(fgcc, "\treturn r;\n")
			}
		}
		fmt.Fprintf(fgcc, "}\n")

		// Build the wrapper function compiled by 6c/8c
650
		goname := exp.Func.Name.Name
Ian Lance Taylor's avatar
Ian Lance Taylor committed
651
		if fn.Recv != nil {
Russ Cox's avatar
Russ Cox committed
652
			goname = "_cgoexpwrap" + cPrefix + "_" + fn.Recv.List[0].Names[0].Name + "_" + goname
Ian Lance Taylor's avatar
Ian Lance Taylor committed
653
		}
654
		fmt.Fprintf(fc, "#pragma cgo_export %s\n", goname)
655 656 657
		fmt.Fprintf(fc, "extern void ·%s();\n\n", goname)
		fmt.Fprintf(fc, "#pragma textflag 7\n") // no split stack, so no use of m or g
		fmt.Fprintf(fc, "void\n")
Russ Cox's avatar
Russ Cox committed
658
		fmt.Fprintf(fc, "_cgoexp%s_%s(void *a, int32 n)\n", cPrefix, exp.ExpName)
Ian Lance Taylor's avatar
Ian Lance Taylor committed
659
		fmt.Fprintf(fc, "{\n")
660
		fmt.Fprintf(fc, "\truntime·cgocallback(·%s, a, n);\n", goname)
Ian Lance Taylor's avatar
Ian Lance Taylor committed
661 662
		fmt.Fprintf(fc, "}\n")

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

Ian Lance Taylor's avatar
Ian Lance Taylor committed
665 666 667 668
		// Calling a function with a receiver from C requires
		// a Go wrapper function.
		if fn.Recv != nil {
			fmt.Fprintf(fgo2, "func %s(recv ", goname)
669
			conf.Fprint(fgo2, fset, fn.Recv.List[0].Type)
Ian Lance Taylor's avatar
Ian Lance Taylor committed
670 671
			forFieldList(fntype.Params,
				func(i int, atype ast.Expr) {
672
					fmt.Fprintf(fgo2, ", p%d ", i)
673
					conf.Fprint(fgo2, fset, atype)
Ian Lance Taylor's avatar
Ian Lance Taylor committed
674 675 676 677 678 679 680 681 682
				})
			fmt.Fprintf(fgo2, ")")
			if gccResult != "void" {
				fmt.Fprint(fgo2, " (")
				forFieldList(fntype.Results,
					func(i int, atype ast.Expr) {
						if i > 0 {
							fmt.Fprint(fgo2, ", ")
						}
683
						conf.Fprint(fgo2, fset, atype)
Ian Lance Taylor's avatar
Ian Lance Taylor committed
684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705
					})
				fmt.Fprint(fgo2, ")")
			}
			fmt.Fprint(fgo2, " {\n")
			fmt.Fprint(fgo2, "\t")
			if gccResult != "void" {
				fmt.Fprint(fgo2, "return ")
			}
			fmt.Fprintf(fgo2, "recv.%s(", exp.Func.Name)
			forFieldList(fntype.Params,
				func(i int, atype ast.Expr) {
					if i > 0 {
						fmt.Fprint(fgo2, ", ")
					}
					fmt.Fprintf(fgo2, "p%d", i)
				})
			fmt.Fprint(fgo2, ")\n")
			fmt.Fprint(fgo2, "}\n")
		}
	}
}

706 707 708 709
// Write out the C header allowing C code to call exported gccgo functions.
func (p *Package) writeGccgoExports(fgo2, fc, fm *os.File) {
	fgcc := creat(*objDir + "_cgo_export.c")
	fgcch := creat(*objDir + "_cgo_export.h")
710 711

	gccgoSymbolPrefix := p.gccgoSymbolPrefix()
712 713 714

	fmt.Fprintf(fgcch, "/* Created by cgo - DO NOT EDIT. */\n")
	fmt.Fprintf(fgcch, "%s\n", p.Preamble)
Russ Cox's avatar
Russ Cox committed
715
	fmt.Fprintf(fgcch, "%s\n", p.gccExportHeaderProlog())
716

717 718
	fmt.Fprintf(fgcc, "/* Created by cgo - DO NOT EDIT. */\n")
	fmt.Fprintf(fgcc, "#include \"_cgo_export.h\"\n")
719

720
	fmt.Fprintf(fm, "#include \"_cgo_export.h\"\n")
721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750

	for _, exp := range p.ExpFunc {
		fn := exp.Func
		fntype := fn.Type

		cdeclBuf := new(bytes.Buffer)
		resultCount := 0
		forFieldList(fntype.Results,
			func(i int, atype ast.Expr) { resultCount++ })
		switch resultCount {
		case 0:
			fmt.Fprintf(cdeclBuf, "void")
		case 1:
			forFieldList(fntype.Results,
				func(i int, atype ast.Expr) {
					t := p.cgoType(atype)
					fmt.Fprintf(cdeclBuf, "%s", t.C)
				})
		default:
			// Declare a result struct.
			fmt.Fprintf(fgcch, "struct %s_result {\n", exp.ExpName)
			forFieldList(fntype.Results,
				func(i int, atype ast.Expr) {
					t := p.cgoType(atype)
					fmt.Fprintf(fgcch, "\t%s r%d;\n", t.C, i)
				})
			fmt.Fprintf(fgcch, "};\n")
			fmt.Fprintf(cdeclBuf, "struct %s_result", exp.ExpName)
		}

751 752 753 754 755 756 757
		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())
		}
758 759 760
		// Function parameters.
		forFieldList(fntype.Params,
			func(i int, atype ast.Expr) {
761
				if i > 0 || fn.Recv != nil {
762 763 764 765 766 767
					fmt.Fprintf(cdeclBuf, ", ")
				}
				t := p.cgoType(atype)
				fmt.Fprintf(cdeclBuf, "%s p%d", t.C, i)
			})
		fmt.Fprintf(cdeclBuf, ")")
768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792
		cParams := cdeclBuf.String()

		goName := "Cgoexp_" + exp.ExpName
		fmt.Fprintf(fgcch, `extern %s %s %s __asm__("%s.%s");`, cRet, goName, cParams, gccgoSymbolPrefix, goName)
		fmt.Fprint(fgcch, "\n")

		fmt.Fprint(fgcc, "\n")
		fmt.Fprintf(fgcc, "%s %s %s {\n", cRet, exp.ExpName, cParams)
		fmt.Fprint(fgcc, "\t")
		if resultCount > 0 {
			fmt.Fprint(fgcc, "return ")
		}
		fmt.Fprintf(fgcc, "%s(", goName)
		if fn.Recv != nil {
			fmt.Fprint(fgcc, "recv")
		}
		forFieldList(fntype.Params,
			func(i int, atype ast.Expr) {
				if i > 0 || fn.Recv != nil {
					fmt.Fprintf(fgcc, ", ")
				}
				fmt.Fprintf(fgcc, "p%d", i)
			})
		fmt.Fprint(fgcc, ");\n")
		fmt.Fprint(fgcc, "}\n")
793 794

		// Dummy declaration for _cgo_main.c
795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848
		fmt.Fprintf(fm, "%s %s %s {}\n", cRet, goName, cParams)

		// 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,
			func(i int, atype ast.Expr) {
				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,
				func(i int, atype ast.Expr) {
					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,
			func(i int, atype ast.Expr) {
				if i > 0 {
					fmt.Fprint(fgo2, ", ")
				}
				fmt.Fprintf(fgo2, "p%d", i)
			})
		fmt.Fprint(fgo2, ")\n")
		fmt.Fprint(fgo2, "}\n")
849 850 851
	}
}

852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879
// 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
880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899
// Call a function for each entry in an ast.FieldList, passing the
// index into the list and the type.
func forFieldList(fl *ast.FieldList, fn func(int, ast.Expr)) {
	if fl == nil {
		return
	}
	i := 0
	for _, r := range fl.List {
		if r.Names == nil {
			fn(i, r.Type)
			i++
		} else {
			for _ = range r.Names {
				fn(i, r.Type)
				i++
			}
		}
	}
}

Gustavo Niemeyer's avatar
Gustavo Niemeyer committed
900 901 902 903
func c(repr string, args ...interface{}) *TypeRepr {
	return &TypeRepr{repr, args}
}

Ian Lance Taylor's avatar
Ian Lance Taylor committed
904 905
// Map predeclared Go types to Type.
var goTypes = map[string]*Type{
906 907
	"bool":       {Size: 1, Align: 1, C: c("GoUint8")},
	"byte":       {Size: 1, Align: 1, C: c("GoUint8")},
Russ Cox's avatar
Russ Cox committed
908 909
	"int":        {Size: 0, Align: 0, C: c("GoInt")},
	"uint":       {Size: 0, Align: 0, C: c("GoUint")},
910 911 912 913 914 915 916 917 918 919 920 921 922
	"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
923 924 925
}

// Map an ast type to a Type.
Russ Cox's avatar
Russ Cox committed
926
func (p *Package) cgoType(e ast.Expr) *Type {
Ian Lance Taylor's avatar
Ian Lance Taylor committed
927 928 929
	switch t := e.(type) {
	case *ast.StarExpr:
		x := p.cgoType(t.X)
Gustavo Niemeyer's avatar
Gustavo Niemeyer committed
930
		return &Type{Size: p.PtrSize, Align: p.PtrSize, C: c("%s*", x.C)}
Ian Lance Taylor's avatar
Ian Lance Taylor committed
931 932
	case *ast.ArrayType:
		if t.Len == nil {
Gustavo Niemeyer's avatar
Gustavo Niemeyer committed
933
			return &Type{Size: p.PtrSize + 8, Align: p.PtrSize, C: c("GoSlice")}
Ian Lance Taylor's avatar
Ian Lance Taylor committed
934 935 936 937
		}
	case *ast.StructType:
		// TODO
	case *ast.FuncType:
Gustavo Niemeyer's avatar
Gustavo Niemeyer committed
938
		return &Type{Size: p.PtrSize, Align: p.PtrSize, C: c("void*")}
Ian Lance Taylor's avatar
Ian Lance Taylor committed
939
	case *ast.InterfaceType:
940
		return &Type{Size: 2 * p.PtrSize, Align: p.PtrSize, C: c("GoInterface")}
Ian Lance Taylor's avatar
Ian Lance Taylor committed
941
	case *ast.MapType:
Gustavo Niemeyer's avatar
Gustavo Niemeyer committed
942
		return &Type{Size: p.PtrSize, Align: p.PtrSize, C: c("GoMap")}
Ian Lance Taylor's avatar
Ian Lance Taylor committed
943
	case *ast.ChanType:
Gustavo Niemeyer's avatar
Gustavo Niemeyer committed
944
		return &Type{Size: p.PtrSize, Align: p.PtrSize, C: c("GoChan")}
Ian Lance Taylor's avatar
Ian Lance Taylor committed
945 946 947
	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
948
		for _, d := range p.Decl {
Ian Lance Taylor's avatar
Ian Lance Taylor committed
949 950 951 952 953 954 955 956 957
			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
				}
958
				if ts.Name.Name == t.Name {
Ian Lance Taylor's avatar
Ian Lance Taylor committed
959 960 961 962
					return p.cgoType(ts.Type)
				}
			}
		}
Russ Cox's avatar
Russ Cox committed
963 964
		if def := typedef[t.Name]; def != nil {
			return def
Ian Lance Taylor's avatar
Ian Lance Taylor committed
965
		}
966
		if t.Name == "uintptr" {
967
			return &Type{Size: p.PtrSize, Align: p.PtrSize, C: c("GoUintptr")}
Ian Lance Taylor's avatar
Ian Lance Taylor committed
968
		}
969
		if t.Name == "string" {
Russ Cox's avatar
Russ Cox committed
970 971 972
			// The string data is 1 pointer + 1 int, but this always
			// rounds to 2 pointers due to alignment.
			return &Type{Size: 2 * p.PtrSize, Align: p.PtrSize, C: c("GoString")}
Ian Lance Taylor's avatar
Ian Lance Taylor committed
973
		}
974 975 976
		if t.Name == "error" {
			return &Type{Size: 2 * p.PtrSize, Align: p.PtrSize, C: c("GoInterface")}
		}
977
		if r, ok := goTypes[t.Name]; ok {
Russ Cox's avatar
Russ Cox committed
978 979 980 981 982 983 984
			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
985 986 987 988 989
			if r.Align > p.PtrSize {
				r.Align = p.PtrSize
			}
			return r
		}
990
		error_(e.Pos(), "unrecognized Go type %s", t.Name)
Russ Cox's avatar
Russ Cox committed
991
		return &Type{Size: 4, Align: 4, C: c("int")}
992 993 994
	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
995
			return &Type{Size: p.PtrSize, Align: p.PtrSize, C: c("void*")}
996
		}
Ian Lance Taylor's avatar
Ian Lance Taylor committed
997
	}
Russ Cox's avatar
Russ Cox committed
998
	error_(e.Pos(), "Go type not supported in export: %s", gofmt(e))
Gustavo Niemeyer's avatar
Gustavo Niemeyer committed
999
	return &Type{Size: 4, Align: 4, C: c("int")}
Ian Lance Taylor's avatar
Ian Lance Taylor committed
1000 1001
}

Russ Cox's avatar
Russ Cox committed
1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017
const gccProlog = `
// Usual nonsense: 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".
#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
1018 1019 1020

#include <errno.h>
#include <string.h>
Russ Cox's avatar
Russ Cox committed
1021 1022 1023 1024
`

const builtinProlog = `
typedef struct { char *p; int n; } _GoString_;
Russ Cox's avatar
Russ Cox committed
1025
typedef struct { char *p; int n; int c; } _GoBytes_;
Russ Cox's avatar
Russ Cox committed
1026
_GoString_ GoString(char *p);
Eric Clark's avatar
Eric Clark committed
1027
_GoString_ GoStringN(char *p, int l);
Russ Cox's avatar
Russ Cox committed
1028
_GoBytes_ GoBytes(void *p, int n);
Russ Cox's avatar
Russ Cox committed
1029 1030 1031 1032 1033 1034 1035
char *CString(_GoString_);
`

const cProlog = `
#include "runtime.h"
#include "cgocall.h"

Russ Cox's avatar
Russ Cox committed
1036 1037
void ·_Cerrno(void*, int32);

Russ Cox's avatar
Russ Cox committed
1038
void
Russ Cox's avatar
Russ Cox committed
1039
·_Cfunc_GoString(int8 *p, String s)
Russ Cox's avatar
Russ Cox committed
1040
{
1041
	s = runtime·gostring((byte*)p);
Russ Cox's avatar
Russ Cox committed
1042 1043 1044
	FLUSH(&s);
}

Eric Clark's avatar
Eric Clark committed
1045 1046 1047
void
·_Cfunc_GoStringN(int8 *p, int32 l, String s)
{
1048
	s = runtime·gostringn((byte*)p, l);
Eric Clark's avatar
Eric Clark committed
1049 1050 1051
	FLUSH(&s);
}

Russ Cox's avatar
Russ Cox committed
1052 1053 1054 1055 1056 1057 1058
void
·_Cfunc_GoBytes(int8 *p, int32 l, Slice s)
{
	s = runtime·gobytes((byte*)p, l);
	FLUSH(&s);
}

Russ Cox's avatar
Russ Cox committed
1059
void
Russ Cox's avatar
Russ Cox committed
1060
·_Cfunc_CString(String s, int8 *p)
Russ Cox's avatar
Russ Cox committed
1061
{
1062
	p = runtime·cmalloc(s.len+1);
1063
	runtime·memmove((byte*)p, s.str, s.len);
Russ Cox's avatar
Russ Cox committed
1064 1065 1066 1067
	p[s.len] = 0;
	FLUSH(&p);
}
`
Ian Lance Taylor's avatar
Ian Lance Taylor committed
1068

1069 1070 1071 1072
const cPrologGccgo = `
#include <stdint.h>
#include <string.h>

1073
typedef unsigned char byte;
1074
typedef intptr_t intgo;
1075

1076 1077
struct __go_string {
	const unsigned char *__data;
1078
	intgo __length;
1079 1080 1081 1082
};

typedef struct __go_open_array {
	void* __values;
1083 1084
	intgo __count;
	intgo __capacity;
1085 1086
} Slice;

1087
struct __go_string __go_byte_array_to_string(const void* p, intgo len);
1088 1089 1090
struct __go_open_array __go_string_to_byte_array (struct __go_string str);

const char *CString(struct __go_string s) {
1091
	return strndup((const char*)s.__data, s.__length);
1092 1093 1094
}

struct __go_string GoString(char *p) {
1095
	intgo len = (p != NULL) ? strlen(p) : 0;
1096
	return __go_byte_array_to_string(p, len);
1097 1098
}

1099
struct __go_string GoStringN(char *p, intgo n) {
1100 1101 1102
	return __go_byte_array_to_string(p, n);
}

1103
Slice GoBytes(char *p, intgo n) {
1104
	struct __go_string s = { (const unsigned char *)p, n };
1105 1106 1107 1108
	return __go_string_to_byte_array(s);
}
`

Russ Cox's avatar
Russ Cox committed
1109 1110 1111 1112
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
1113
const gccExportHeaderProlog = `
1114 1115 1116 1117 1118 1119 1120 1121
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
1122 1123
typedef GoIntGOINTBITS GoInt;
typedef GoUintGOINTBITS GoUint;
1124 1125 1126 1127 1128
typedef __SIZE_TYPE__ GoUintptr;
typedef float GoFloat32;
typedef double GoFloat64;
typedef __complex float GoComplex64;
typedef __complex double GoComplex128;
Ian Lance Taylor's avatar
Ian Lance Taylor committed
1129 1130 1131 1132 1133

typedef struct { char *p; int n; } GoString;
typedef void *GoMap;
typedef void *GoChan;
typedef struct { void *t; void *v; } GoInterface;
1134
typedef struct { void *data; int len; int cap; } GoSlice;
Ian Lance Taylor's avatar
Ian Lance Taylor committed
1135
`