github.com/nvi-inc/fsgo@v0.2.1/versions/utils/cgo/out.go (about) 1 // Copyright 2009 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package main 6 7 import ( 8 "bytes" 9 "debug/elf" 10 "debug/macho" 11 "debug/pe" 12 "fmt" 13 "go/ast" 14 "go/printer" 15 "go/token" 16 "io" 17 "os" 18 "sort" 19 "strings" 20 ) 21 22 var conf = printer.Config{Mode: printer.SourcePos, Tabwidth: 8} 23 24 // writeDefs creates output files to be compiled by gc and gcc. 25 func (p *Package) writeDefs() { 26 var fgo2, fc io.Writer 27 f := creat(*objDir + "_cgo_gotypes.go") 28 defer f.Close() 29 fgo2 = f 30 if *gccgo { 31 f := creat(*objDir + "_cgo_defun.c") 32 defer f.Close() 33 fc = f 34 } 35 fm := creat(*objDir + "_cgo_main.c") 36 37 var gccgoInit bytes.Buffer 38 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 fflg.Close() 49 50 // Write C main file for using gcc to resolve imports. 51 fmt.Fprintf(fm, "int main() { return 0; }\n") 52 if *importRuntimeCgo { 53 fmt.Fprintf(fm, "void crosscall2(void(*fn)(void*, int, __SIZE_TYPE__), void *a, int c, __SIZE_TYPE__ ctxt) { }\n") 54 fmt.Fprintf(fm, "__SIZE_TYPE__ _cgo_wait_runtime_init_done() { return 0; }\n") 55 fmt.Fprintf(fm, "void _cgo_release_context(__SIZE_TYPE__ ctxt) { }\n") 56 fmt.Fprintf(fm, "char* _cgo_topofstack(void) { return (char*)0; }\n") 57 } else { 58 // If we're not importing runtime/cgo, we *are* runtime/cgo, 59 // which provides these functions. We just need a prototype. 60 fmt.Fprintf(fm, "void crosscall2(void(*fn)(void*, int, __SIZE_TYPE__), void *a, int c, __SIZE_TYPE__ ctxt);\n") 61 fmt.Fprintf(fm, "__SIZE_TYPE__ _cgo_wait_runtime_init_done();\n") 62 fmt.Fprintf(fm, "void _cgo_release_context(__SIZE_TYPE__);\n") 63 } 64 fmt.Fprintf(fm, "void _cgo_allocate(void *a, int c) { }\n") 65 fmt.Fprintf(fm, "void _cgo_panic(void *a, int c) { }\n") 66 fmt.Fprintf(fm, "void _cgo_reginit(void) { }\n") 67 68 // Write second Go output: definitions of _C_xxx. 69 // In a separate file so that the import of "unsafe" does not 70 // pollute the original file. 71 fmt.Fprintf(fgo2, "// Created by cgo - DO NOT EDIT\n\n") 72 fmt.Fprintf(fgo2, "package %s\n\n", p.PackageName) 73 fmt.Fprintf(fgo2, "import \"unsafe\"\n\n") 74 if !*gccgo && *importRuntimeCgo { 75 fmt.Fprintf(fgo2, "import _ \"runtime/cgo\"\n\n") 76 } 77 if *importSyscall { 78 fmt.Fprintf(fgo2, "import \"syscall\"\n\n") 79 fmt.Fprintf(fgo2, "var _ syscall.Errno\n") 80 } 81 fmt.Fprintf(fgo2, "func _Cgo_ptr(ptr unsafe.Pointer) unsafe.Pointer { return ptr }\n\n") 82 83 if !*gccgo { 84 fmt.Fprintf(fgo2, "//go:linkname _Cgo_always_false runtime.cgoAlwaysFalse\n") 85 fmt.Fprintf(fgo2, "var _Cgo_always_false bool\n") 86 fmt.Fprintf(fgo2, "//go:linkname _Cgo_use runtime.cgoUse\n") 87 fmt.Fprintf(fgo2, "func _Cgo_use(interface{})\n") 88 } 89 90 typedefNames := make([]string, 0, len(typedef)) 91 for name := range typedef { 92 typedefNames = append(typedefNames, name) 93 } 94 sort.Strings(typedefNames) 95 for _, name := range typedefNames { 96 def := typedef[name] 97 fmt.Fprintf(fgo2, "type %s ", name) 98 conf.Fprint(fgo2, fset, def.Go) 99 fmt.Fprintf(fgo2, "\n\n") 100 } 101 if *gccgo { 102 fmt.Fprintf(fgo2, "type _Ctype_void byte\n") 103 } else { 104 fmt.Fprintf(fgo2, "type _Ctype_void [0]byte\n") 105 } 106 107 if *gccgo { 108 fmt.Fprint(fgo2, gccgoGoProlog) 109 fmt.Fprint(fc, p.cPrologGccgo()) 110 } else { 111 fmt.Fprint(fgo2, goProlog) 112 } 113 114 for i, t := range p.CgoChecks { 115 n := p.unsafeCheckPointerNameIndex(i, false) 116 fmt.Fprintf(fgo2, "\nfunc %s(p %s, args ...interface{}) %s {\n", n, t, t) 117 fmt.Fprintf(fgo2, "\treturn _cgoCheckPointer(p, args...).(%s)\n", t) 118 fmt.Fprintf(fgo2, "}\n") 119 } 120 for i, t := range p.DeferredCgoChecks { 121 n := p.unsafeCheckPointerNameIndex(i, true) 122 fmt.Fprintf(fgo2, "\nfunc %s(p interface{}, args ...interface{}) %s {\n", n, t) 123 fmt.Fprintf(fgo2, "\treturn _cgoCheckPointer(p, args...).(%s)\n", t) 124 fmt.Fprintf(fgo2, "}\n") 125 } 126 127 gccgoSymbolPrefix := p.gccgoSymbolPrefix() 128 129 cVars := make(map[string]bool) 130 for _, key := range nameKeys(p.Name) { 131 n := p.Name[key] 132 if !n.IsVar() { 133 continue 134 } 135 136 if !cVars[n.C] { 137 if *gccgo { 138 fmt.Fprintf(fc, "extern byte *%s;\n", n.C) 139 } else { 140 fmt.Fprintf(fm, "extern char %s[];\n", n.C) 141 fmt.Fprintf(fm, "void *_cgohack_%s = %s;\n\n", n.C, n.C) 142 fmt.Fprintf(fgo2, "//go:linkname __cgo_%s %s\n", n.C, n.C) 143 fmt.Fprintf(fgo2, "//go:cgo_import_static %s\n", n.C) 144 fmt.Fprintf(fgo2, "var __cgo_%s byte\n", n.C) 145 } 146 cVars[n.C] = true 147 } 148 149 var node ast.Node 150 if n.Kind == "var" { 151 node = &ast.StarExpr{X: n.Type.Go} 152 } else if n.Kind == "fpvar" { 153 node = n.Type.Go 154 } else { 155 panic(fmt.Errorf("invalid var kind %q", n.Kind)) 156 } 157 if *gccgo { 158 fmt.Fprintf(fc, `extern void *%s __asm__("%s.%s");`, n.Mangle, gccgoSymbolPrefix, n.Mangle) 159 fmt.Fprintf(&gccgoInit, "\t%s = &%s;\n", n.Mangle, n.C) 160 fmt.Fprintf(fc, "\n") 161 } 162 163 fmt.Fprintf(fgo2, "var %s ", n.Mangle) 164 conf.Fprint(fgo2, fset, node) 165 if !*gccgo { 166 fmt.Fprintf(fgo2, " = (") 167 conf.Fprint(fgo2, fset, node) 168 fmt.Fprintf(fgo2, ")(unsafe.Pointer(&__cgo_%s))", n.C) 169 } 170 fmt.Fprintf(fgo2, "\n") 171 } 172 if *gccgo { 173 fmt.Fprintf(fc, "\n") 174 } 175 176 for _, key := range nameKeys(p.Name) { 177 n := p.Name[key] 178 if n.Const != "" { 179 fmt.Fprintf(fgo2, "const _Cconst_%s = %s\n", n.Go, n.Const) 180 } 181 } 182 fmt.Fprintf(fgo2, "\n") 183 184 callsMalloc := false 185 for _, key := range nameKeys(p.Name) { 186 n := p.Name[key] 187 if n.FuncType != nil { 188 p.writeDefsFunc(fgo2, n, &callsMalloc) 189 } 190 } 191 192 fgcc := creat(*objDir + "_cgo_export.c") 193 fgcch := creat(*objDir + "_cgo_export.h") 194 if *gccgo { 195 p.writeGccgoExports(fgo2, fm, fgcc, fgcch) 196 } else { 197 p.writeExports(fgo2, fm, fgcc, fgcch) 198 } 199 200 if callsMalloc && !*gccgo { 201 fmt.Fprint(fgo2, strings.Replace(cMallocDefGo, "PREFIX", cPrefix, -1)) 202 fmt.Fprint(fgcc, strings.Replace(strings.Replace(cMallocDefC, "PREFIX", cPrefix, -1), "PACKED", p.packedAttribute(), -1)) 203 } 204 205 if err := fgcc.Close(); err != nil { 206 fatalf("%s", err) 207 } 208 if err := fgcch.Close(); err != nil { 209 fatalf("%s", err) 210 } 211 212 if *exportHeader != "" && len(p.ExpFunc) > 0 { 213 fexp := creat(*exportHeader) 214 fgcch, err := os.Open(*objDir + "_cgo_export.h") 215 if err != nil { 216 fatalf("%s", err) 217 } 218 _, err = io.Copy(fexp, fgcch) 219 if err != nil { 220 fatalf("%s", err) 221 } 222 if err = fexp.Close(); err != nil { 223 fatalf("%s", err) 224 } 225 } 226 227 init := gccgoInit.String() 228 if init != "" { 229 fmt.Fprintln(fc, "static void init(void) __attribute__ ((constructor));") 230 fmt.Fprintln(fc, "static void init(void) {") 231 fmt.Fprint(fc, init) 232 fmt.Fprintln(fc, "}") 233 } 234 } 235 236 func dynimport(obj string) { 237 stdout := os.Stdout 238 if *dynout != "" { 239 f, err := os.Create(*dynout) 240 if err != nil { 241 fatalf("%s", err) 242 } 243 stdout = f 244 } 245 246 fmt.Fprintf(stdout, "package %s\n", *dynpackage) 247 248 if f, err := elf.Open(obj); err == nil { 249 if *dynlinker { 250 // Emit the cgo_dynamic_linker line. 251 if sec := f.Section(".interp"); sec != nil { 252 if data, err := sec.Data(); err == nil && len(data) > 1 { 253 // skip trailing \0 in data 254 fmt.Fprintf(stdout, "//go:cgo_dynamic_linker %q\n", string(data[:len(data)-1])) 255 } 256 } 257 } 258 sym, err := f.ImportedSymbols() 259 if err != nil { 260 fatalf("cannot load imported symbols from ELF file %s: %v", obj, err) 261 } 262 for _, s := range sym { 263 targ := s.Name 264 if s.Version != "" { 265 targ += "#" + s.Version 266 } 267 fmt.Fprintf(stdout, "//go:cgo_import_dynamic %s %s %q\n", s.Name, targ, s.Library) 268 } 269 lib, err := f.ImportedLibraries() 270 if err != nil { 271 fatalf("cannot load imported libraries from ELF file %s: %v", obj, err) 272 } 273 for _, l := range lib { 274 fmt.Fprintf(stdout, "//go:cgo_import_dynamic _ _ %q\n", l) 275 } 276 return 277 } 278 279 if f, err := macho.Open(obj); err == nil { 280 sym, err := f.ImportedSymbols() 281 if err != nil { 282 fatalf("cannot load imported symbols from Mach-O file %s: %v", obj, err) 283 } 284 for _, s := range sym { 285 if len(s) > 0 && s[0] == '_' { 286 s = s[1:] 287 } 288 fmt.Fprintf(stdout, "//go:cgo_import_dynamic %s %s %q\n", s, s, "") 289 } 290 lib, err := f.ImportedLibraries() 291 if err != nil { 292 fatalf("cannot load imported libraries from Mach-O file %s: %v", obj, err) 293 } 294 for _, l := range lib { 295 fmt.Fprintf(stdout, "//go:cgo_import_dynamic _ _ %q\n", l) 296 } 297 return 298 } 299 300 if f, err := pe.Open(obj); err == nil { 301 sym, err := f.ImportedSymbols() 302 if err != nil { 303 fatalf("cannot load imported symbols from PE file %s: %v", obj, err) 304 } 305 for _, s := range sym { 306 ss := strings.Split(s, ":") 307 name := strings.Split(ss[0], "@")[0] 308 fmt.Fprintf(stdout, "//go:cgo_import_dynamic %s %s %q\n", name, ss[0], strings.ToLower(ss[1])) 309 } 310 return 311 } 312 313 fatalf("cannot parse %s as ELF, Mach-O or PE", obj) 314 } 315 316 // Construct a gcc struct matching the gc argument frame. 317 // Assumes that in gcc, char is 1 byte, short 2 bytes, int 4 bytes, long long 8 bytes. 318 // These assumptions are checked by the gccProlog. 319 // Also assumes that gc convention is to word-align the 320 // input and output parameters. 321 func (p *Package) structType(n *Name) (string, int64) { 322 var buf bytes.Buffer 323 fmt.Fprint(&buf, "struct {\n") 324 off := int64(0) 325 for i, t := range n.FuncType.Params { 326 if off%t.Align != 0 { 327 pad := t.Align - off%t.Align 328 fmt.Fprintf(&buf, "\t\tchar __pad%d[%d];\n", off, pad) 329 off += pad 330 } 331 c := t.Typedef 332 if c == "" { 333 c = t.C.String() 334 } 335 fmt.Fprintf(&buf, "\t\t%s p%d;\n", c, i) 336 off += t.Size 337 } 338 if off%p.PtrSize != 0 { 339 pad := p.PtrSize - off%p.PtrSize 340 fmt.Fprintf(&buf, "\t\tchar __pad%d[%d];\n", off, pad) 341 off += pad 342 } 343 if t := n.FuncType.Result; t != nil { 344 if off%t.Align != 0 { 345 pad := t.Align - off%t.Align 346 fmt.Fprintf(&buf, "\t\tchar __pad%d[%d];\n", off, pad) 347 off += pad 348 } 349 qual := "" 350 if c := t.C.String(); c[len(c)-1] == '*' { 351 qual = "const " 352 } 353 fmt.Fprintf(&buf, "\t\t%s%s r;\n", qual, t.C) 354 off += t.Size 355 } 356 if off%p.PtrSize != 0 { 357 pad := p.PtrSize - off%p.PtrSize 358 fmt.Fprintf(&buf, "\t\tchar __pad%d[%d];\n", off, pad) 359 off += pad 360 } 361 if off == 0 { 362 fmt.Fprintf(&buf, "\t\tchar unused;\n") // avoid empty struct 363 } 364 fmt.Fprintf(&buf, "\t}") 365 return buf.String(), off 366 } 367 368 func (p *Package) writeDefsFunc(fgo2 io.Writer, n *Name, callsMalloc *bool) { 369 name := n.Go 370 gtype := n.FuncType.Go 371 void := gtype.Results == nil || len(gtype.Results.List) == 0 372 if n.AddError { 373 // Add "error" to return type list. 374 // Type list is known to be 0 or 1 element - it's a C function. 375 err := &ast.Field{Type: ast.NewIdent("error")} 376 l := gtype.Results.List 377 if len(l) == 0 { 378 l = []*ast.Field{err} 379 } else { 380 l = []*ast.Field{l[0], err} 381 } 382 t := new(ast.FuncType) 383 *t = *gtype 384 t.Results = &ast.FieldList{List: l} 385 gtype = t 386 } 387 388 // Go func declaration. 389 d := &ast.FuncDecl{ 390 Name: ast.NewIdent(n.Mangle), 391 Type: gtype, 392 } 393 394 // Builtins defined in the C prolog. 395 inProlog := builtinDefs[name] != "" 396 cname := fmt.Sprintf("_cgo%s%s", cPrefix, n.Mangle) 397 paramnames := []string(nil) 398 for i, param := range d.Type.Params.List { 399 paramName := fmt.Sprintf("p%d", i) 400 param.Names = []*ast.Ident{ast.NewIdent(paramName)} 401 paramnames = append(paramnames, paramName) 402 } 403 404 if *gccgo { 405 // Gccgo style hooks. 406 fmt.Fprint(fgo2, "\n") 407 conf.Fprint(fgo2, fset, d) 408 fmt.Fprint(fgo2, " {\n") 409 if !inProlog { 410 fmt.Fprint(fgo2, "\tdefer syscall.CgocallDone()\n") 411 fmt.Fprint(fgo2, "\tsyscall.Cgocall()\n") 412 } 413 if n.AddError { 414 fmt.Fprint(fgo2, "\tsyscall.SetErrno(0)\n") 415 } 416 fmt.Fprint(fgo2, "\t") 417 if !void { 418 fmt.Fprint(fgo2, "r := ") 419 } 420 fmt.Fprintf(fgo2, "%s(%s)\n", cname, strings.Join(paramnames, ", ")) 421 422 if n.AddError { 423 fmt.Fprint(fgo2, "\te := syscall.GetErrno()\n") 424 fmt.Fprint(fgo2, "\tif e != 0 {\n") 425 fmt.Fprint(fgo2, "\t\treturn ") 426 if !void { 427 fmt.Fprint(fgo2, "r, ") 428 } 429 fmt.Fprint(fgo2, "e\n") 430 fmt.Fprint(fgo2, "\t}\n") 431 fmt.Fprint(fgo2, "\treturn ") 432 if !void { 433 fmt.Fprint(fgo2, "r, ") 434 } 435 fmt.Fprint(fgo2, "nil\n") 436 } else if !void { 437 fmt.Fprint(fgo2, "\treturn r\n") 438 } 439 440 fmt.Fprint(fgo2, "}\n") 441 442 // declare the C function. 443 fmt.Fprintf(fgo2, "//extern %s\n", cname) 444 d.Name = ast.NewIdent(cname) 445 if n.AddError { 446 l := d.Type.Results.List 447 d.Type.Results.List = l[:len(l)-1] 448 } 449 conf.Fprint(fgo2, fset, d) 450 fmt.Fprint(fgo2, "\n") 451 452 return 453 } 454 455 if inProlog { 456 fmt.Fprint(fgo2, builtinDefs[name]) 457 if strings.Contains(builtinDefs[name], "_cgo_cmalloc") { 458 *callsMalloc = true 459 } 460 return 461 } 462 463 // Wrapper calls into gcc, passing a pointer to the argument frame. 464 fmt.Fprintf(fgo2, "//go:cgo_import_static %s\n", cname) 465 fmt.Fprintf(fgo2, "//go:linkname __cgofn_%s %s\n", cname, cname) 466 fmt.Fprintf(fgo2, "var __cgofn_%s byte\n", cname) 467 fmt.Fprintf(fgo2, "var %s = unsafe.Pointer(&__cgofn_%s)\n", cname, cname) 468 469 nret := 0 470 if !void { 471 d.Type.Results.List[0].Names = []*ast.Ident{ast.NewIdent("r1")} 472 nret = 1 473 } 474 if n.AddError { 475 d.Type.Results.List[nret].Names = []*ast.Ident{ast.NewIdent("r2")} 476 } 477 478 fmt.Fprint(fgo2, "\n") 479 fmt.Fprint(fgo2, "//go:cgo_unsafe_args\n") 480 conf.Fprint(fgo2, fset, d) 481 fmt.Fprint(fgo2, " {\n") 482 483 // NOTE: Using uintptr to hide from escape analysis. 484 arg := "0" 485 if len(paramnames) > 0 { 486 arg = "uintptr(unsafe.Pointer(&p0))" 487 } else if !void { 488 arg = "uintptr(unsafe.Pointer(&r1))" 489 } 490 491 prefix := "" 492 if n.AddError { 493 prefix = "errno := " 494 } 495 fmt.Fprintf(fgo2, "\t%s_cgo_runtime_cgocall(%s, %s)\n", prefix, cname, arg) 496 if n.AddError { 497 fmt.Fprintf(fgo2, "\tif errno != 0 { r2 = syscall.Errno(errno) }\n") 498 } 499 fmt.Fprintf(fgo2, "\tif _Cgo_always_false {\n") 500 for i := range d.Type.Params.List { 501 fmt.Fprintf(fgo2, "\t\t_Cgo_use(p%d)\n", i) 502 } 503 fmt.Fprintf(fgo2, "\t}\n") 504 fmt.Fprintf(fgo2, "\treturn\n") 505 fmt.Fprintf(fgo2, "}\n") 506 } 507 508 // writeOutput creates stubs for a specific source file to be compiled by gc 509 func (p *Package) writeOutput(f *File, srcfile string) { 510 base := srcfile 511 if strings.HasSuffix(base, ".go") { 512 base = base[0 : len(base)-3] 513 } 514 base = strings.Map(slashToUnderscore, base) 515 fgo1 := creat(*objDir + base + ".cgo1.go") 516 fgcc := creat(*objDir + base + ".cgo2.c") 517 518 p.GoFiles = append(p.GoFiles, base+".cgo1.go") 519 p.GccFiles = append(p.GccFiles, base+".cgo2.c") 520 521 // Write Go output: Go input with rewrites of C.xxx to _C_xxx. 522 fmt.Fprintf(fgo1, "// Created by cgo - DO NOT EDIT\n\n") 523 conf.Fprint(fgo1, fset, f.AST) 524 525 // While we process the vars and funcs, also write gcc output. 526 // Gcc output starts with the preamble. 527 fmt.Fprintf(fgcc, "%s\n", f.Preamble) 528 fmt.Fprintf(fgcc, "%s\n", gccProlog) 529 fmt.Fprintf(fgcc, "%s\n", tsanProlog) 530 531 for _, key := range nameKeys(f.Name) { 532 n := f.Name[key] 533 if n.FuncType != nil { 534 p.writeOutputFunc(fgcc, n) 535 } 536 } 537 538 fgo1.Close() 539 fgcc.Close() 540 } 541 542 // fixGo converts the internal Name.Go field into the name we should show 543 // to users in error messages. There's only one for now: on input we rewrite 544 // C.malloc into C._CMalloc, so change it back here. 545 func fixGo(name string) string { 546 if name == "_CMalloc" { 547 return "malloc" 548 } 549 return name 550 } 551 552 var isBuiltin = map[string]bool{ 553 "_Cfunc_CString": true, 554 "_Cfunc_CBytes": true, 555 "_Cfunc_GoString": true, 556 "_Cfunc_GoStringN": true, 557 "_Cfunc_GoBytes": true, 558 "_Cfunc__CMalloc": true, 559 } 560 561 func (p *Package) writeOutputFunc(fgcc *os.File, n *Name) { 562 name := n.Mangle 563 if isBuiltin[name] || p.Written[name] { 564 // The builtins are already defined in the C prolog, and we don't 565 // want to duplicate function definitions we've already done. 566 return 567 } 568 p.Written[name] = true 569 570 if *gccgo { 571 p.writeGccgoOutputFunc(fgcc, n) 572 return 573 } 574 575 ctype, _ := p.structType(n) 576 577 // Gcc wrapper unpacks the C argument struct 578 // and calls the actual C function. 579 fmt.Fprintf(fgcc, "CGO_NO_SANITIZE_THREAD\n") 580 if n.AddError { 581 fmt.Fprintf(fgcc, "int\n") 582 } else { 583 fmt.Fprintf(fgcc, "void\n") 584 } 585 fmt.Fprintf(fgcc, "_cgo%s%s(void *v)\n", cPrefix, n.Mangle) 586 fmt.Fprintf(fgcc, "{\n") 587 if n.AddError { 588 fmt.Fprintf(fgcc, "\tint _cgo_errno;\n") 589 } 590 // We're trying to write a gcc struct that matches gc's layout. 591 // Use packed attribute to force no padding in this struct in case 592 // gcc has different packing requirements. 593 fmt.Fprintf(fgcc, "\t%s %v *a = v;\n", ctype, p.packedAttribute()) 594 if n.FuncType.Result != nil { 595 // Save the stack top for use below. 596 fmt.Fprintf(fgcc, "\tchar *stktop = _cgo_topofstack();\n") 597 } 598 tr := n.FuncType.Result 599 if tr != nil { 600 fmt.Fprintf(fgcc, "\t__typeof__(a->r) r;\n") 601 } 602 fmt.Fprintf(fgcc, "\t_cgo_tsan_acquire();\n") 603 if n.AddError { 604 fmt.Fprintf(fgcc, "\terrno = 0;\n") 605 } 606 fmt.Fprintf(fgcc, "\t") 607 if tr != nil { 608 fmt.Fprintf(fgcc, "r = ") 609 if c := tr.C.String(); c[len(c)-1] == '*' { 610 fmt.Fprint(fgcc, "(__typeof__(a->r)) ") 611 } 612 } 613 fmt.Fprintf(fgcc, "%s(", n.C) 614 for i, t := range n.FuncType.Params { 615 if i > 0 { 616 fmt.Fprintf(fgcc, ", ") 617 } 618 // We know the type params are correct, because 619 // the Go equivalents had good type params. 620 // However, our version of the type omits the magic 621 // words const and volatile, which can provoke 622 // C compiler warnings. Silence them by casting 623 // all pointers to void*. (Eventually that will produce 624 // other warnings.) 625 if c := t.C.String(); c[len(c)-1] == '*' { 626 fmt.Fprintf(fgcc, "(void*)") 627 } 628 fmt.Fprintf(fgcc, "a->p%d", i) 629 } 630 fmt.Fprintf(fgcc, ");\n") 631 if n.AddError { 632 fmt.Fprintf(fgcc, "\t_cgo_errno = errno;\n") 633 } 634 fmt.Fprintf(fgcc, "\t_cgo_tsan_release();\n") 635 if n.FuncType.Result != nil { 636 // The cgo call may have caused a stack copy (via a callback). 637 // Adjust the return value pointer appropriately. 638 fmt.Fprintf(fgcc, "\ta = (void*)((char*)a + (_cgo_topofstack() - stktop));\n") 639 // Save the return value. 640 fmt.Fprintf(fgcc, "\ta->r = r;\n") 641 } 642 if n.AddError { 643 fmt.Fprintf(fgcc, "\treturn _cgo_errno;\n") 644 } 645 fmt.Fprintf(fgcc, "}\n") 646 fmt.Fprintf(fgcc, "\n") 647 } 648 649 // Write out a wrapper for a function when using gccgo. This is a 650 // simple wrapper that just calls the real function. We only need a 651 // wrapper to support static functions in the prologue--without a 652 // wrapper, we can't refer to the function, since the reference is in 653 // a different file. 654 func (p *Package) writeGccgoOutputFunc(fgcc *os.File, n *Name) { 655 fmt.Fprintf(fgcc, "CGO_NO_SANITIZE_THREAD\n") 656 if t := n.FuncType.Result; t != nil { 657 fmt.Fprintf(fgcc, "%s\n", t.C.String()) 658 } else { 659 fmt.Fprintf(fgcc, "void\n") 660 } 661 fmt.Fprintf(fgcc, "_cgo%s%s(", cPrefix, n.Mangle) 662 for i, t := range n.FuncType.Params { 663 if i > 0 { 664 fmt.Fprintf(fgcc, ", ") 665 } 666 c := t.Typedef 667 if c == "" { 668 c = t.C.String() 669 } 670 fmt.Fprintf(fgcc, "%s p%d", c, i) 671 } 672 fmt.Fprintf(fgcc, ")\n") 673 fmt.Fprintf(fgcc, "{\n") 674 if t := n.FuncType.Result; t != nil { 675 fmt.Fprintf(fgcc, "\t%s r;\n", t.C.String()) 676 } 677 fmt.Fprintf(fgcc, "\t_cgo_tsan_acquire();\n") 678 fmt.Fprintf(fgcc, "\t") 679 if t := n.FuncType.Result; t != nil { 680 fmt.Fprintf(fgcc, "r = ") 681 // Cast to void* to avoid warnings due to omitted qualifiers. 682 if c := t.C.String(); c[len(c)-1] == '*' { 683 fmt.Fprintf(fgcc, "(void*)") 684 } 685 } 686 fmt.Fprintf(fgcc, "%s(", n.C) 687 for i, t := range n.FuncType.Params { 688 if i > 0 { 689 fmt.Fprintf(fgcc, ", ") 690 } 691 // Cast to void* to avoid warnings due to omitted qualifiers. 692 if c := t.C.String(); c[len(c)-1] == '*' { 693 fmt.Fprintf(fgcc, "(void*)") 694 } 695 fmt.Fprintf(fgcc, "p%d", i) 696 } 697 fmt.Fprintf(fgcc, ");\n") 698 fmt.Fprintf(fgcc, "\t_cgo_tsan_release();\n") 699 if t := n.FuncType.Result; t != nil { 700 fmt.Fprintf(fgcc, "\treturn ") 701 // Cast to void* to avoid warnings due to omitted qualifiers 702 // and explicit incompatible struct types. 703 if c := t.C.String(); c[len(c)-1] == '*' { 704 fmt.Fprintf(fgcc, "(void*)") 705 } 706 fmt.Fprintf(fgcc, "r;\n") 707 } 708 fmt.Fprintf(fgcc, "}\n") 709 fmt.Fprintf(fgcc, "\n") 710 } 711 712 // packedAttribute returns host compiler struct attribute that will be 713 // used to match gc's struct layout. For example, on 386 Windows, 714 // gcc wants to 8-align int64s, but gc does not. 715 // Use __gcc_struct__ to work around http://gcc.gnu.org/PR52991 on x86, 716 // and https://golang.org/issue/5603. 717 func (p *Package) packedAttribute() string { 718 s := "__attribute__((__packed__" 719 if !p.GccIsClang && (goarch == "amd64" || goarch == "386") { 720 s += ", __gcc_struct__" 721 } 722 return s + "))" 723 } 724 725 // Write out the various stubs we need to support functions exported 726 // from Go so that they are callable from C. 727 func (p *Package) writeExports(fgo2, fm, fgcc, fgcch io.Writer) { 728 p.writeExportHeader(fgcch) 729 730 fmt.Fprintf(fgcc, "/* Created by cgo - DO NOT EDIT. */\n") 731 fmt.Fprintf(fgcc, "#include <stdlib.h>\n") 732 fmt.Fprintf(fgcc, "#include \"_cgo_export.h\"\n\n") 733 734 fmt.Fprintf(fgcc, "extern void crosscall2(void (*fn)(void *, int, __SIZE_TYPE__), void *, int, __SIZE_TYPE__);\n") 735 fmt.Fprintf(fgcc, "extern __SIZE_TYPE__ _cgo_wait_runtime_init_done();\n") 736 fmt.Fprintf(fgcc, "extern void _cgo_release_context(__SIZE_TYPE__);\n\n") 737 fmt.Fprintf(fgcc, "extern char* _cgo_topofstack(void);") 738 fmt.Fprintf(fgcc, "%s\n", tsanProlog) 739 740 for _, exp := range p.ExpFunc { 741 fn := exp.Func 742 743 // Construct a gcc struct matching the gc argument and 744 // result frame. The gcc struct will be compiled with 745 // __attribute__((packed)) so all padding must be accounted 746 // for explicitly. 747 ctype := "struct {\n" 748 off := int64(0) 749 npad := 0 750 if fn.Recv != nil { 751 t := p.cgoType(fn.Recv.List[0].Type) 752 ctype += fmt.Sprintf("\t\t%s recv;\n", t.C) 753 off += t.Size 754 } 755 fntype := fn.Type 756 forFieldList(fntype.Params, 757 func(i int, aname string, atype ast.Expr) { 758 t := p.cgoType(atype) 759 if off%t.Align != 0 { 760 pad := t.Align - off%t.Align 761 ctype += fmt.Sprintf("\t\tchar __pad%d[%d];\n", npad, pad) 762 off += pad 763 npad++ 764 } 765 ctype += fmt.Sprintf("\t\t%s p%d;\n", t.C, i) 766 off += t.Size 767 }) 768 if off%p.PtrSize != 0 { 769 pad := p.PtrSize - off%p.PtrSize 770 ctype += fmt.Sprintf("\t\tchar __pad%d[%d];\n", npad, pad) 771 off += pad 772 npad++ 773 } 774 forFieldList(fntype.Results, 775 func(i int, aname string, atype ast.Expr) { 776 t := p.cgoType(atype) 777 if off%t.Align != 0 { 778 pad := t.Align - off%t.Align 779 ctype += fmt.Sprintf("\t\tchar __pad%d[%d];\n", npad, pad) 780 off += pad 781 npad++ 782 } 783 ctype += fmt.Sprintf("\t\t%s r%d;\n", t.C, i) 784 off += t.Size 785 }) 786 if off%p.PtrSize != 0 { 787 pad := p.PtrSize - off%p.PtrSize 788 ctype += fmt.Sprintf("\t\tchar __pad%d[%d];\n", npad, pad) 789 off += pad 790 npad++ 791 } 792 if ctype == "struct {\n" { 793 ctype += "\t\tchar unused;\n" // avoid empty struct 794 } 795 ctype += "\t}" 796 797 // Get the return type of the wrapper function 798 // compiled by gcc. 799 gccResult := "" 800 if fntype.Results == nil || len(fntype.Results.List) == 0 { 801 gccResult = "void" 802 } else if len(fntype.Results.List) == 1 && len(fntype.Results.List[0].Names) <= 1 { 803 gccResult = p.cgoType(fntype.Results.List[0].Type).C.String() 804 } else { 805 fmt.Fprintf(fgcch, "\n/* Return type for %s */\n", exp.ExpName) 806 fmt.Fprintf(fgcch, "struct %s_return {\n", exp.ExpName) 807 forFieldList(fntype.Results, 808 func(i int, aname string, atype ast.Expr) { 809 fmt.Fprintf(fgcch, "\t%s r%d;", p.cgoType(atype).C, i) 810 if len(aname) > 0 { 811 fmt.Fprintf(fgcch, " /* %s */", aname) 812 } 813 fmt.Fprint(fgcch, "\n") 814 }) 815 fmt.Fprintf(fgcch, "};\n") 816 gccResult = "struct " + exp.ExpName + "_return" 817 } 818 819 // Build the wrapper function compiled by gcc. 820 s := fmt.Sprintf("%s %s(", gccResult, exp.ExpName) 821 if fn.Recv != nil { 822 s += p.cgoType(fn.Recv.List[0].Type).C.String() 823 s += " recv" 824 } 825 forFieldList(fntype.Params, 826 func(i int, aname string, atype ast.Expr) { 827 if i > 0 || fn.Recv != nil { 828 s += ", " 829 } 830 s += fmt.Sprintf("%s p%d", p.cgoType(atype).C, i) 831 }) 832 s += ")" 833 834 if len(exp.Doc) > 0 { 835 fmt.Fprintf(fgcch, "\n%s", exp.Doc) 836 } 837 fmt.Fprintf(fgcch, "\nextern %s;\n", s) 838 839 fmt.Fprintf(fgcc, "extern void _cgoexp%s_%s(void *, int, __SIZE_TYPE__);\n", cPrefix, exp.ExpName) 840 fmt.Fprintf(fgcc, "\nCGO_NO_SANITIZE_THREAD") 841 fmt.Fprintf(fgcc, "\n%s\n", s) 842 fmt.Fprintf(fgcc, "{\n") 843 fmt.Fprintf(fgcc, "\t__SIZE_TYPE__ _cgo_ctxt = _cgo_wait_runtime_init_done();\n") 844 fmt.Fprintf(fgcc, "\t%s %v a;\n", ctype, p.packedAttribute()) 845 if gccResult != "void" && (len(fntype.Results.List) > 1 || len(fntype.Results.List[0].Names) > 1) { 846 fmt.Fprintf(fgcc, "\t%s r;\n", gccResult) 847 } 848 if fn.Recv != nil { 849 fmt.Fprintf(fgcc, "\ta.recv = recv;\n") 850 } 851 forFieldList(fntype.Params, 852 func(i int, aname string, atype ast.Expr) { 853 fmt.Fprintf(fgcc, "\ta.p%d = p%d;\n", i, i) 854 }) 855 fmt.Fprintf(fgcc, "\t_cgo_tsan_release();\n") 856 fmt.Fprintf(fgcc, "\tcrosscall2(_cgoexp%s_%s, &a, %d, _cgo_ctxt);\n", cPrefix, exp.ExpName, off) 857 fmt.Fprintf(fgcc, "\t_cgo_tsan_acquire();\n") 858 fmt.Fprintf(fgcc, "\t_cgo_release_context(_cgo_ctxt);\n") 859 if gccResult != "void" { 860 if len(fntype.Results.List) == 1 && len(fntype.Results.List[0].Names) <= 1 { 861 fmt.Fprintf(fgcc, "\treturn a.r0;\n") 862 } else { 863 forFieldList(fntype.Results, 864 func(i int, aname string, atype ast.Expr) { 865 fmt.Fprintf(fgcc, "\tr.r%d = a.r%d;\n", i, i) 866 }) 867 fmt.Fprintf(fgcc, "\treturn r;\n") 868 } 869 } 870 fmt.Fprintf(fgcc, "}\n") 871 872 // Build the wrapper function compiled by cmd/compile. 873 goname := "_cgoexpwrap" + cPrefix + "_" 874 if fn.Recv != nil { 875 goname += fn.Recv.List[0].Names[0].Name + "_" 876 } 877 goname += exp.Func.Name.Name 878 fmt.Fprintf(fgo2, "//go:cgo_export_dynamic %s\n", exp.ExpName) 879 fmt.Fprintf(fgo2, "//go:linkname _cgoexp%s_%s _cgoexp%s_%s\n", cPrefix, exp.ExpName, cPrefix, exp.ExpName) 880 fmt.Fprintf(fgo2, "//go:cgo_export_static _cgoexp%s_%s\n", cPrefix, exp.ExpName) 881 fmt.Fprintf(fgo2, "//go:nosplit\n") // no split stack, so no use of m or g 882 fmt.Fprintf(fgo2, "//go:norace\n") // must not have race detector calls inserted 883 fmt.Fprintf(fgo2, "func _cgoexp%s_%s(a unsafe.Pointer, n int32, ctxt uintptr) {\n", cPrefix, exp.ExpName) 884 fmt.Fprintf(fgo2, "\tfn := %s\n", goname) 885 // The indirect here is converting from a Go function pointer to a C function pointer. 886 fmt.Fprintf(fgo2, "\t_cgo_runtime_cgocallback(**(**unsafe.Pointer)(unsafe.Pointer(&fn)), a, uintptr(n), ctxt);\n") 887 fmt.Fprintf(fgo2, "}\n") 888 889 fmt.Fprintf(fm, "int _cgoexp%s_%s;\n", cPrefix, exp.ExpName) 890 891 // This code uses printer.Fprint, not conf.Fprint, 892 // because we don't want //line comments in the middle 893 // of the function types. 894 fmt.Fprintf(fgo2, "\n") 895 fmt.Fprintf(fgo2, "func %s(", goname) 896 comma := false 897 if fn.Recv != nil { 898 fmt.Fprintf(fgo2, "recv ") 899 printer.Fprint(fgo2, fset, fn.Recv.List[0].Type) 900 comma = true 901 } 902 forFieldList(fntype.Params, 903 func(i int, aname string, atype ast.Expr) { 904 if comma { 905 fmt.Fprintf(fgo2, ", ") 906 } 907 fmt.Fprintf(fgo2, "p%d ", i) 908 printer.Fprint(fgo2, fset, atype) 909 comma = true 910 }) 911 fmt.Fprintf(fgo2, ")") 912 if gccResult != "void" { 913 fmt.Fprint(fgo2, " (") 914 forFieldList(fntype.Results, 915 func(i int, aname string, atype ast.Expr) { 916 if i > 0 { 917 fmt.Fprint(fgo2, ", ") 918 } 919 fmt.Fprintf(fgo2, "r%d ", i) 920 printer.Fprint(fgo2, fset, atype) 921 }) 922 fmt.Fprint(fgo2, ")") 923 } 924 fmt.Fprint(fgo2, " {\n") 925 if gccResult == "void" { 926 fmt.Fprint(fgo2, "\t") 927 } else { 928 // Verify that any results don't contain any 929 // Go pointers. 930 addedDefer := false 931 forFieldList(fntype.Results, 932 func(i int, aname string, atype ast.Expr) { 933 if !p.hasPointer(nil, atype, false) { 934 return 935 } 936 if !addedDefer { 937 fmt.Fprint(fgo2, "\tdefer func() {\n") 938 addedDefer = true 939 } 940 fmt.Fprintf(fgo2, "\t\t_cgoCheckResult(r%d)\n", i) 941 }) 942 if addedDefer { 943 fmt.Fprint(fgo2, "\t}()\n") 944 } 945 fmt.Fprint(fgo2, "\treturn ") 946 } 947 if fn.Recv != nil { 948 fmt.Fprintf(fgo2, "recv.") 949 } 950 fmt.Fprintf(fgo2, "%s(", exp.Func.Name) 951 forFieldList(fntype.Params, 952 func(i int, aname string, atype ast.Expr) { 953 if i > 0 { 954 fmt.Fprint(fgo2, ", ") 955 } 956 fmt.Fprintf(fgo2, "p%d", i) 957 }) 958 fmt.Fprint(fgo2, ")\n") 959 fmt.Fprint(fgo2, "}\n") 960 } 961 962 fmt.Fprintf(fgcch, "%s", gccExportHeaderEpilog) 963 } 964 965 // Write out the C header allowing C code to call exported gccgo functions. 966 func (p *Package) writeGccgoExports(fgo2, fm, fgcc, fgcch io.Writer) { 967 gccgoSymbolPrefix := p.gccgoSymbolPrefix() 968 969 p.writeExportHeader(fgcch) 970 971 fmt.Fprintf(fgcc, "/* Created by cgo - DO NOT EDIT. */\n") 972 fmt.Fprintf(fgcc, "#include \"_cgo_export.h\"\n") 973 974 fmt.Fprintf(fgcc, "%s\n", gccgoExportFileProlog) 975 fmt.Fprintf(fgcc, "%s\n", tsanProlog) 976 977 for _, exp := range p.ExpFunc { 978 fn := exp.Func 979 fntype := fn.Type 980 981 cdeclBuf := new(bytes.Buffer) 982 resultCount := 0 983 forFieldList(fntype.Results, 984 func(i int, aname string, atype ast.Expr) { resultCount++ }) 985 switch resultCount { 986 case 0: 987 fmt.Fprintf(cdeclBuf, "void") 988 case 1: 989 forFieldList(fntype.Results, 990 func(i int, aname string, atype ast.Expr) { 991 t := p.cgoType(atype) 992 fmt.Fprintf(cdeclBuf, "%s", t.C) 993 }) 994 default: 995 // Declare a result struct. 996 fmt.Fprintf(fgcch, "\n/* Return type for %s */\n", exp.ExpName) 997 fmt.Fprintf(fgcch, "struct %s_result {\n", exp.ExpName) 998 forFieldList(fntype.Results, 999 func(i int, aname string, atype ast.Expr) { 1000 t := p.cgoType(atype) 1001 fmt.Fprintf(fgcch, "\t%s r%d;", t.C, i) 1002 if len(aname) > 0 { 1003 fmt.Fprintf(fgcch, " /* %s */", aname) 1004 } 1005 fmt.Fprint(fgcch, "\n") 1006 }) 1007 fmt.Fprintf(fgcch, "};\n") 1008 fmt.Fprintf(cdeclBuf, "struct %s_result", exp.ExpName) 1009 } 1010 1011 cRet := cdeclBuf.String() 1012 1013 cdeclBuf = new(bytes.Buffer) 1014 fmt.Fprintf(cdeclBuf, "(") 1015 if fn.Recv != nil { 1016 fmt.Fprintf(cdeclBuf, "%s recv", p.cgoType(fn.Recv.List[0].Type).C.String()) 1017 } 1018 // Function parameters. 1019 forFieldList(fntype.Params, 1020 func(i int, aname string, atype ast.Expr) { 1021 if i > 0 || fn.Recv != nil { 1022 fmt.Fprintf(cdeclBuf, ", ") 1023 } 1024 t := p.cgoType(atype) 1025 fmt.Fprintf(cdeclBuf, "%s p%d", t.C, i) 1026 }) 1027 fmt.Fprintf(cdeclBuf, ")") 1028 cParams := cdeclBuf.String() 1029 1030 if len(exp.Doc) > 0 { 1031 fmt.Fprintf(fgcch, "\n%s", exp.Doc) 1032 } 1033 1034 fmt.Fprintf(fgcch, "extern %s %s %s;\n", cRet, exp.ExpName, cParams) 1035 1036 // We need to use a name that will be exported by the 1037 // Go code; otherwise gccgo will make it static and we 1038 // will not be able to link against it from the C 1039 // code. 1040 goName := "Cgoexp_" + exp.ExpName 1041 fmt.Fprintf(fgcc, `extern %s %s %s __asm__("%s.%s");`, cRet, goName, cParams, gccgoSymbolPrefix, goName) 1042 fmt.Fprint(fgcc, "\n") 1043 1044 fmt.Fprint(fgcc, "\nCGO_NO_SANITIZE_THREAD\n") 1045 fmt.Fprintf(fgcc, "%s %s %s {\n", cRet, exp.ExpName, cParams) 1046 if resultCount > 0 { 1047 fmt.Fprintf(fgcc, "\t%s r;\n", cRet) 1048 } 1049 fmt.Fprintf(fgcc, "\tif(_cgo_wait_runtime_init_done)\n") 1050 fmt.Fprintf(fgcc, "\t\t_cgo_wait_runtime_init_done();\n") 1051 fmt.Fprintf(fgcc, "\t_cgo_tsan_release();\n") 1052 fmt.Fprint(fgcc, "\t") 1053 if resultCount > 0 { 1054 fmt.Fprint(fgcc, "r = ") 1055 } 1056 fmt.Fprintf(fgcc, "%s(", goName) 1057 if fn.Recv != nil { 1058 fmt.Fprint(fgcc, "recv") 1059 } 1060 forFieldList(fntype.Params, 1061 func(i int, aname string, atype ast.Expr) { 1062 if i > 0 || fn.Recv != nil { 1063 fmt.Fprintf(fgcc, ", ") 1064 } 1065 fmt.Fprintf(fgcc, "p%d", i) 1066 }) 1067 fmt.Fprint(fgcc, ");\n") 1068 fmt.Fprintf(fgcc, "\t_cgo_tsan_acquire();\n") 1069 if resultCount > 0 { 1070 fmt.Fprint(fgcc, "\treturn r;\n") 1071 } 1072 fmt.Fprint(fgcc, "}\n") 1073 1074 // Dummy declaration for _cgo_main.c 1075 fmt.Fprintf(fm, `char %s[1] __asm__("%s.%s");`, goName, gccgoSymbolPrefix, goName) 1076 fmt.Fprint(fm, "\n") 1077 1078 // For gccgo we use a wrapper function in Go, in order 1079 // to call CgocallBack and CgocallBackDone. 1080 1081 // This code uses printer.Fprint, not conf.Fprint, 1082 // because we don't want //line comments in the middle 1083 // of the function types. 1084 fmt.Fprint(fgo2, "\n") 1085 fmt.Fprintf(fgo2, "func %s(", goName) 1086 if fn.Recv != nil { 1087 fmt.Fprint(fgo2, "recv ") 1088 printer.Fprint(fgo2, fset, fn.Recv.List[0].Type) 1089 } 1090 forFieldList(fntype.Params, 1091 func(i int, aname string, atype ast.Expr) { 1092 if i > 0 || fn.Recv != nil { 1093 fmt.Fprintf(fgo2, ", ") 1094 } 1095 fmt.Fprintf(fgo2, "p%d ", i) 1096 printer.Fprint(fgo2, fset, atype) 1097 }) 1098 fmt.Fprintf(fgo2, ")") 1099 if resultCount > 0 { 1100 fmt.Fprintf(fgo2, " (") 1101 forFieldList(fntype.Results, 1102 func(i int, aname string, atype ast.Expr) { 1103 if i > 0 { 1104 fmt.Fprint(fgo2, ", ") 1105 } 1106 printer.Fprint(fgo2, fset, atype) 1107 }) 1108 fmt.Fprint(fgo2, ")") 1109 } 1110 fmt.Fprint(fgo2, " {\n") 1111 fmt.Fprint(fgo2, "\tsyscall.CgocallBack()\n") 1112 fmt.Fprint(fgo2, "\tdefer syscall.CgocallBackDone()\n") 1113 fmt.Fprint(fgo2, "\t") 1114 if resultCount > 0 { 1115 fmt.Fprint(fgo2, "return ") 1116 } 1117 if fn.Recv != nil { 1118 fmt.Fprint(fgo2, "recv.") 1119 } 1120 fmt.Fprintf(fgo2, "%s(", exp.Func.Name) 1121 forFieldList(fntype.Params, 1122 func(i int, aname string, atype ast.Expr) { 1123 if i > 0 { 1124 fmt.Fprint(fgo2, ", ") 1125 } 1126 fmt.Fprintf(fgo2, "p%d", i) 1127 }) 1128 fmt.Fprint(fgo2, ")\n") 1129 fmt.Fprint(fgo2, "}\n") 1130 } 1131 1132 fmt.Fprintf(fgcch, "%s", gccExportHeaderEpilog) 1133 } 1134 1135 // writeExportHeader writes out the start of the _cgo_export.h file. 1136 func (p *Package) writeExportHeader(fgcch io.Writer) { 1137 fmt.Fprintf(fgcch, "/* Created by \"go tool cgo\" - DO NOT EDIT. */\n\n") 1138 pkg := *importPath 1139 if pkg == "" { 1140 pkg = p.PackagePath 1141 } 1142 fmt.Fprintf(fgcch, "/* package %s */\n\n", pkg) 1143 1144 fmt.Fprintf(fgcch, "/* Start of preamble from import \"C\" comments. */\n\n") 1145 fmt.Fprintf(fgcch, "%s\n", p.Preamble) 1146 fmt.Fprintf(fgcch, "\n/* End of preamble from import \"C\" comments. */\n\n") 1147 1148 fmt.Fprintf(fgcch, "%s\n", p.gccExportHeaderProlog()) 1149 } 1150 1151 // Return the package prefix when using gccgo. 1152 func (p *Package) gccgoSymbolPrefix() string { 1153 if !*gccgo { 1154 return "" 1155 } 1156 1157 clean := func(r rune) rune { 1158 switch { 1159 case 'A' <= r && r <= 'Z', 'a' <= r && r <= 'z', 1160 '0' <= r && r <= '9': 1161 return r 1162 } 1163 return '_' 1164 } 1165 1166 if *gccgopkgpath != "" { 1167 return strings.Map(clean, *gccgopkgpath) 1168 } 1169 if *gccgoprefix == "" && p.PackageName == "main" { 1170 return "main" 1171 } 1172 prefix := strings.Map(clean, *gccgoprefix) 1173 if prefix == "" { 1174 prefix = "go" 1175 } 1176 return prefix + "." + p.PackageName 1177 } 1178 1179 // Call a function for each entry in an ast.FieldList, passing the 1180 // index into the list, the name if any, and the type. 1181 func forFieldList(fl *ast.FieldList, fn func(int, string, ast.Expr)) { 1182 if fl == nil { 1183 return 1184 } 1185 i := 0 1186 for _, r := range fl.List { 1187 if r.Names == nil { 1188 fn(i, "", r.Type) 1189 i++ 1190 } else { 1191 for _, n := range r.Names { 1192 fn(i, n.Name, r.Type) 1193 i++ 1194 } 1195 } 1196 } 1197 } 1198 1199 func c(repr string, args ...interface{}) *TypeRepr { 1200 return &TypeRepr{repr, args} 1201 } 1202 1203 // Map predeclared Go types to Type. 1204 var goTypes = map[string]*Type{ 1205 "bool": {Size: 1, Align: 1, C: c("GoUint8")}, 1206 "byte": {Size: 1, Align: 1, C: c("GoUint8")}, 1207 "int": {Size: 0, Align: 0, C: c("GoInt")}, 1208 "uint": {Size: 0, Align: 0, C: c("GoUint")}, 1209 "rune": {Size: 4, Align: 4, C: c("GoInt32")}, 1210 "int8": {Size: 1, Align: 1, C: c("GoInt8")}, 1211 "uint8": {Size: 1, Align: 1, C: c("GoUint8")}, 1212 "int16": {Size: 2, Align: 2, C: c("GoInt16")}, 1213 "uint16": {Size: 2, Align: 2, C: c("GoUint16")}, 1214 "int32": {Size: 4, Align: 4, C: c("GoInt32")}, 1215 "uint32": {Size: 4, Align: 4, C: c("GoUint32")}, 1216 "int64": {Size: 8, Align: 8, C: c("GoInt64")}, 1217 "uint64": {Size: 8, Align: 8, C: c("GoUint64")}, 1218 "float32": {Size: 4, Align: 4, C: c("GoFloat32")}, 1219 "float64": {Size: 8, Align: 8, C: c("GoFloat64")}, 1220 "complex64": {Size: 8, Align: 8, C: c("GoComplex64")}, 1221 "complex128": {Size: 16, Align: 16, C: c("GoComplex128")}, 1222 } 1223 1224 // Map an ast type to a Type. 1225 func (p *Package) cgoType(e ast.Expr) *Type { 1226 switch t := e.(type) { 1227 case *ast.StarExpr: 1228 x := p.cgoType(t.X) 1229 return &Type{Size: p.PtrSize, Align: p.PtrSize, C: c("%s*", x.C)} 1230 case *ast.ArrayType: 1231 if t.Len == nil { 1232 // Slice: pointer, len, cap. 1233 return &Type{Size: p.PtrSize * 3, Align: p.PtrSize, C: c("GoSlice")} 1234 } 1235 case *ast.StructType: 1236 // TODO 1237 case *ast.FuncType: 1238 return &Type{Size: p.PtrSize, Align: p.PtrSize, C: c("void*")} 1239 case *ast.InterfaceType: 1240 return &Type{Size: 2 * p.PtrSize, Align: p.PtrSize, C: c("GoInterface")} 1241 case *ast.MapType: 1242 return &Type{Size: p.PtrSize, Align: p.PtrSize, C: c("GoMap")} 1243 case *ast.ChanType: 1244 return &Type{Size: p.PtrSize, Align: p.PtrSize, C: c("GoChan")} 1245 case *ast.Ident: 1246 // Look up the type in the top level declarations. 1247 // TODO: Handle types defined within a function. 1248 for _, d := range p.Decl { 1249 gd, ok := d.(*ast.GenDecl) 1250 if !ok || gd.Tok != token.TYPE { 1251 continue 1252 } 1253 for _, spec := range gd.Specs { 1254 ts, ok := spec.(*ast.TypeSpec) 1255 if !ok { 1256 continue 1257 } 1258 if ts.Name.Name == t.Name { 1259 return p.cgoType(ts.Type) 1260 } 1261 } 1262 } 1263 if def := typedef[t.Name]; def != nil { 1264 return def 1265 } 1266 if t.Name == "uintptr" { 1267 return &Type{Size: p.PtrSize, Align: p.PtrSize, C: c("GoUintptr")} 1268 } 1269 if t.Name == "string" { 1270 // The string data is 1 pointer + 1 (pointer-sized) int. 1271 return &Type{Size: 2 * p.PtrSize, Align: p.PtrSize, C: c("GoString")} 1272 } 1273 if t.Name == "error" { 1274 return &Type{Size: 2 * p.PtrSize, Align: p.PtrSize, C: c("GoInterface")} 1275 } 1276 if r, ok := goTypes[t.Name]; ok { 1277 if r.Size == 0 { // int or uint 1278 rr := new(Type) 1279 *rr = *r 1280 rr.Size = p.IntSize 1281 rr.Align = p.IntSize 1282 r = rr 1283 } 1284 if r.Align > p.PtrSize { 1285 r.Align = p.PtrSize 1286 } 1287 return r 1288 } 1289 error_(e.Pos(), "unrecognized Go type %s", t.Name) 1290 return &Type{Size: 4, Align: 4, C: c("int")} 1291 case *ast.SelectorExpr: 1292 id, ok := t.X.(*ast.Ident) 1293 if ok && id.Name == "unsafe" && t.Sel.Name == "Pointer" { 1294 return &Type{Size: p.PtrSize, Align: p.PtrSize, C: c("void*")} 1295 } 1296 } 1297 error_(e.Pos(), "Go type not supported in export: %s", gofmt(e)) 1298 return &Type{Size: 4, Align: 4, C: c("int")} 1299 } 1300 1301 const gccProlog = ` 1302 /* 1303 If x and y are not equal, the type will be invalid 1304 (have a negative array count) and an inscrutable error will come 1305 out of the compiler and hopefully mention "name". 1306 */ 1307 #define __cgo_compile_assert_eq(x, y, name) typedef char name[(x-y)*(x-y)*-2+1]; 1308 1309 // Check at compile time that the sizes we use match our expectations. 1310 #define __cgo_size_assert(t, n) __cgo_compile_assert_eq(sizeof(t), n, _cgo_sizeof_##t##_is_not_##n) 1311 1312 __cgo_size_assert(char, 1) 1313 __cgo_size_assert(short, 2) 1314 __cgo_size_assert(int, 4) 1315 typedef long long __cgo_long_long; 1316 __cgo_size_assert(__cgo_long_long, 8) 1317 __cgo_size_assert(float, 4) 1318 __cgo_size_assert(double, 8) 1319 1320 extern char* _cgo_topofstack(void); 1321 1322 #include <errno.h> 1323 #include <string.h> 1324 ` 1325 1326 // Prologue defining TSAN functions in C. 1327 const noTsanProlog = ` 1328 #define CGO_NO_SANITIZE_THREAD 1329 #define _cgo_tsan_acquire() 1330 #define _cgo_tsan_release() 1331 ` 1332 1333 // This must match the TSAN code in runtime/cgo/libcgo.h. 1334 const yesTsanProlog = ` 1335 #define CGO_NO_SANITIZE_THREAD __attribute__ ((no_sanitize_thread)) 1336 1337 long long _cgo_sync __attribute__ ((common)); 1338 1339 extern void __tsan_acquire(void*); 1340 extern void __tsan_release(void*); 1341 1342 __attribute__ ((unused)) 1343 static void _cgo_tsan_acquire() { 1344 __tsan_acquire(&_cgo_sync); 1345 } 1346 1347 __attribute__ ((unused)) 1348 static void _cgo_tsan_release() { 1349 __tsan_release(&_cgo_sync); 1350 } 1351 ` 1352 1353 // Set to yesTsanProlog if we see -fsanitize=thread in the flags for gcc. 1354 var tsanProlog = noTsanProlog 1355 1356 const builtinProlog = ` 1357 #include <stddef.h> /* for ptrdiff_t and size_t below */ 1358 1359 /* Define intgo when compiling with GCC. */ 1360 typedef ptrdiff_t intgo; 1361 1362 typedef struct { char *p; intgo n; } _GoString_; 1363 typedef struct { char *p; intgo n; intgo c; } _GoBytes_; 1364 _GoString_ GoString(char *p); 1365 _GoString_ GoStringN(char *p, int l); 1366 _GoBytes_ GoBytes(void *p, int n); 1367 char *CString(_GoString_); 1368 void *CBytes(_GoBytes_); 1369 void *_CMalloc(size_t); 1370 ` 1371 1372 const goProlog = ` 1373 //go:linkname _cgo_runtime_cgocall runtime.cgocall 1374 func _cgo_runtime_cgocall(unsafe.Pointer, uintptr) int32 1375 1376 //go:linkname _cgo_runtime_cgocallback runtime.cgocallback 1377 func _cgo_runtime_cgocallback(unsafe.Pointer, unsafe.Pointer, uintptr, uintptr) 1378 1379 //go:linkname _cgoCheckPointer runtime.cgoCheckPointer 1380 func _cgoCheckPointer(interface{}, ...interface{}) interface{} 1381 1382 //go:linkname _cgoCheckResult runtime.cgoCheckResult 1383 func _cgoCheckResult(interface{}) 1384 ` 1385 1386 const gccgoGoProlog = ` 1387 func _cgoCheckPointer(interface{}, ...interface{}) interface{} 1388 1389 func _cgoCheckResult(interface{}) 1390 ` 1391 1392 const goStringDef = ` 1393 //go:linkname _cgo_runtime_gostring runtime.gostring 1394 func _cgo_runtime_gostring(*_Ctype_char) string 1395 1396 func _Cfunc_GoString(p *_Ctype_char) string { 1397 return _cgo_runtime_gostring(p) 1398 } 1399 ` 1400 1401 const goStringNDef = ` 1402 //go:linkname _cgo_runtime_gostringn runtime.gostringn 1403 func _cgo_runtime_gostringn(*_Ctype_char, int) string 1404 1405 func _Cfunc_GoStringN(p *_Ctype_char, l _Ctype_int) string { 1406 return _cgo_runtime_gostringn(p, int(l)) 1407 } 1408 ` 1409 1410 const goBytesDef = ` 1411 //go:linkname _cgo_runtime_gobytes runtime.gobytes 1412 func _cgo_runtime_gobytes(unsafe.Pointer, int) []byte 1413 1414 func _Cfunc_GoBytes(p unsafe.Pointer, l _Ctype_int) []byte { 1415 return _cgo_runtime_gobytes(p, int(l)) 1416 } 1417 ` 1418 1419 const cStringDef = ` 1420 func _Cfunc_CString(s string) *_Ctype_char { 1421 p := _cgo_cmalloc(uint64(len(s)+1)) 1422 pp := (*[1<<30]byte)(p) 1423 copy(pp[:], s) 1424 pp[len(s)] = 0 1425 return (*_Ctype_char)(p) 1426 } 1427 ` 1428 1429 const cBytesDef = ` 1430 func _Cfunc_CBytes(b []byte) unsafe.Pointer { 1431 p := _cgo_cmalloc(uint64(len(b))) 1432 pp := (*[1<<30]byte)(p) 1433 copy(pp[:], b) 1434 return p 1435 } 1436 ` 1437 1438 const cMallocDef = ` 1439 func _Cfunc__CMalloc(n _Ctype_size_t) unsafe.Pointer { 1440 return _cgo_cmalloc(uint64(n)) 1441 } 1442 ` 1443 1444 var builtinDefs = map[string]string{ 1445 "GoString": goStringDef, 1446 "GoStringN": goStringNDef, 1447 "GoBytes": goBytesDef, 1448 "CString": cStringDef, 1449 "CBytes": cBytesDef, 1450 "_CMalloc": cMallocDef, 1451 } 1452 1453 // Definitions for C.malloc in Go and in C. We define it ourselves 1454 // since we call it from functions we define, such as C.CString. 1455 // Also, we have historically ensured that C.malloc does not return 1456 // nil even for an allocation of 0. 1457 1458 const cMallocDefGo = ` 1459 //go:cgo_import_static _cgoPREFIX_Cfunc__Cmalloc 1460 //go:linkname __cgofn__cgoPREFIX_Cfunc__Cmalloc _cgoPREFIX_Cfunc__Cmalloc 1461 var __cgofn__cgoPREFIX_Cfunc__Cmalloc byte 1462 var _cgoPREFIX_Cfunc__Cmalloc = unsafe.Pointer(&__cgofn__cgoPREFIX_Cfunc__Cmalloc) 1463 1464 //go:cgo_unsafe_args 1465 func _cgo_cmalloc(p0 uint64) (r1 unsafe.Pointer) { 1466 _cgo_runtime_cgocall(_cgoPREFIX_Cfunc__Cmalloc, uintptr(unsafe.Pointer(&p0))) 1467 return 1468 } 1469 ` 1470 1471 // cMallocDefC defines the C version of C.malloc for the gc compiler. 1472 // It is defined here because C.CString and friends need a definition. 1473 // We define it by hand, rather than simply inventing a reference to 1474 // C.malloc, because <stdlib.h> may not have been included. 1475 // This is approximately what writeOutputFunc would generate, but 1476 // skips the cgo_topofstack code (which is only needed if the C code 1477 // calls back into Go). This also avoids returning nil for an 1478 // allocation of 0 bytes. 1479 const cMallocDefC = ` 1480 CGO_NO_SANITIZE_THREAD 1481 void _cgoPREFIX_Cfunc__Cmalloc(void *v) { 1482 struct { 1483 unsigned long long p0; 1484 void *r1; 1485 } PACKED *a = v; 1486 void *ret; 1487 _cgo_tsan_acquire(); 1488 ret = malloc(a->p0); 1489 if (ret == 0 && a->p0 == 0) { 1490 ret = malloc(1); 1491 } 1492 a->r1 = ret; 1493 _cgo_tsan_release(); 1494 } 1495 ` 1496 1497 func (p *Package) cPrologGccgo() string { 1498 return strings.Replace(strings.Replace(cPrologGccgo, "PREFIX", cPrefix, -1), 1499 "GCCGOSYMBOLPREF", p.gccgoSymbolPrefix(), -1) 1500 } 1501 1502 const cPrologGccgo = ` 1503 #include <stdint.h> 1504 #include <stdlib.h> 1505 #include <string.h> 1506 1507 typedef unsigned char byte; 1508 typedef intptr_t intgo; 1509 1510 struct __go_string { 1511 const unsigned char *__data; 1512 intgo __length; 1513 }; 1514 1515 typedef struct __go_open_array { 1516 void* __values; 1517 intgo __count; 1518 intgo __capacity; 1519 } Slice; 1520 1521 struct __go_string __go_byte_array_to_string(const void* p, intgo len); 1522 struct __go_open_array __go_string_to_byte_array (struct __go_string str); 1523 1524 const char *_cgoPREFIX_Cfunc_CString(struct __go_string s) { 1525 char *p = malloc(s.__length+1); 1526 memmove(p, s.__data, s.__length); 1527 p[s.__length] = 0; 1528 return p; 1529 } 1530 1531 void *_cgoPREFIX_Cfunc_CBytes(struct __go_open_array b) { 1532 char *p = malloc(b.__count); 1533 memmove(p, b.__values, b.__count); 1534 return p; 1535 } 1536 1537 struct __go_string _cgoPREFIX_Cfunc_GoString(char *p) { 1538 intgo len = (p != NULL) ? strlen(p) : 0; 1539 return __go_byte_array_to_string(p, len); 1540 } 1541 1542 struct __go_string _cgoPREFIX_Cfunc_GoStringN(char *p, int32_t n) { 1543 return __go_byte_array_to_string(p, n); 1544 } 1545 1546 Slice _cgoPREFIX_Cfunc_GoBytes(char *p, int32_t n) { 1547 struct __go_string s = { (const unsigned char *)p, n }; 1548 return __go_string_to_byte_array(s); 1549 } 1550 1551 extern void runtime_throw(const char *); 1552 void *_cgoPREFIX_Cfunc__CMalloc(size_t n) { 1553 void *p = malloc(n); 1554 if(p == NULL && n == 0) 1555 p = malloc(1); 1556 if(p == NULL) 1557 runtime_throw("runtime: C malloc failed"); 1558 return p; 1559 } 1560 1561 struct __go_type_descriptor; 1562 typedef struct __go_empty_interface { 1563 const struct __go_type_descriptor *__type_descriptor; 1564 void *__object; 1565 } Eface; 1566 1567 extern Eface runtimeCgoCheckPointer(Eface, Slice) 1568 __asm__("runtime.cgoCheckPointer") 1569 __attribute__((weak)); 1570 1571 extern Eface localCgoCheckPointer(Eface, Slice) 1572 __asm__("GCCGOSYMBOLPREF._cgoCheckPointer"); 1573 1574 Eface localCgoCheckPointer(Eface ptr, Slice args) { 1575 if(runtimeCgoCheckPointer) { 1576 return runtimeCgoCheckPointer(ptr, args); 1577 } 1578 return ptr; 1579 } 1580 1581 extern void runtimeCgoCheckResult(Eface) 1582 __asm__("runtime.cgoCheckResult") 1583 __attribute__((weak)); 1584 1585 extern void localCgoCheckResult(Eface) 1586 __asm__("GCCGOSYMBOLPREF._cgoCheckResult"); 1587 1588 void localCgoCheckResult(Eface val) { 1589 if(runtimeCgoCheckResult) { 1590 runtimeCgoCheckResult(val); 1591 } 1592 } 1593 ` 1594 1595 func (p *Package) gccExportHeaderProlog() string { 1596 return strings.Replace(gccExportHeaderProlog, "GOINTBITS", fmt.Sprint(8*p.IntSize), -1) 1597 } 1598 1599 const gccExportHeaderProlog = ` 1600 /* Start of boilerplate cgo prologue. */ 1601 1602 #ifndef GO_CGO_PROLOGUE_H 1603 #define GO_CGO_PROLOGUE_H 1604 1605 typedef signed char GoInt8; 1606 typedef unsigned char GoUint8; 1607 typedef short GoInt16; 1608 typedef unsigned short GoUint16; 1609 typedef int GoInt32; 1610 typedef unsigned int GoUint32; 1611 typedef long long GoInt64; 1612 typedef unsigned long long GoUint64; 1613 typedef GoIntGOINTBITS GoInt; 1614 typedef GoUintGOINTBITS GoUint; 1615 typedef __SIZE_TYPE__ GoUintptr; 1616 typedef float GoFloat32; 1617 typedef double GoFloat64; 1618 typedef float _Complex GoComplex64; 1619 typedef double _Complex GoComplex128; 1620 1621 /* 1622 static assertion to make sure the file is being used on architecture 1623 at least with matching size of GoInt. 1624 */ 1625 typedef char _check_for_GOINTBITS_bit_pointer_matching_GoInt[sizeof(void*)==GOINTBITS/8 ? 1:-1]; 1626 1627 typedef struct { const char *p; GoInt n; } GoString; 1628 typedef void *GoMap; 1629 typedef void *GoChan; 1630 typedef struct { void *t; void *v; } GoInterface; 1631 typedef struct { void *data; GoInt len; GoInt cap; } GoSlice; 1632 1633 #endif 1634 1635 /* End of boilerplate cgo prologue. */ 1636 1637 #ifdef __cplusplus 1638 extern "C" { 1639 #endif 1640 ` 1641 1642 // gccExportHeaderEpilog goes at the end of the generated header file. 1643 const gccExportHeaderEpilog = ` 1644 #ifdef __cplusplus 1645 } 1646 #endif 1647 ` 1648 1649 // gccgoExportFileProlog is written to the _cgo_export.c file when 1650 // using gccgo. 1651 // We use weak declarations, and test the addresses, so that this code 1652 // works with older versions of gccgo. 1653 const gccgoExportFileProlog = ` 1654 extern _Bool runtime_iscgo __attribute__ ((weak)); 1655 1656 static void GoInit(void) __attribute__ ((constructor)); 1657 static void GoInit(void) { 1658 if(&runtime_iscgo) 1659 runtime_iscgo = 1; 1660 } 1661 1662 extern __SIZE_TYPE__ _cgo_wait_runtime_init_done() __attribute__ ((weak)); 1663 `