github.com/xushiwei/go@v0.0.0-20130601165731-2b9d83f45bc9/src/cmd/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 "os" 17 "sort" 18 "strings" 19 ) 20 21 var conf = printer.Config{Mode: printer.SourcePos, Tabwidth: 8} 22 23 // writeDefs creates output files to be compiled by 6g, 6c, and gcc. 24 // (The comments here say 6g and 6c but the code applies to the 8 and 5 tools too.) 25 func (p *Package) writeDefs() { 26 fgo2 := creat(*objDir + "_cgo_gotypes.go") 27 fc := creat(*objDir + "_cgo_defun.c") 28 fm := creat(*objDir + "_cgo_main.c") 29 30 var gccgoInit bytes.Buffer 31 32 fflg := creat(*objDir + "_cgo_flags") 33 for k, v := range p.CgoFlags { 34 fmt.Fprintf(fflg, "_CGO_%s=%s\n", k, strings.Join(v, " ")) 35 if k == "LDFLAGS" { 36 for _, arg := range v { 37 fmt.Fprintf(fc, "#pragma cgo_ldflag %q\n", arg) 38 } 39 } 40 } 41 fflg.Close() 42 43 // Write C main file for using gcc to resolve imports. 44 fmt.Fprintf(fm, "int main() { return 0; }\n") 45 if *importRuntimeCgo { 46 fmt.Fprintf(fm, "void crosscall2(void(*fn)(void*, int), void *a, int c) { }\n") 47 } else { 48 // If we're not importing runtime/cgo, we *are* runtime/cgo, 49 // which provides crosscall2. We just need a prototype. 50 fmt.Fprintf(fm, "void crosscall2(void(*fn)(void*, int), void *a, int c);") 51 } 52 fmt.Fprintf(fm, "void _cgo_allocate(void *a, int c) { }\n") 53 fmt.Fprintf(fm, "void _cgo_panic(void *a, int c) { }\n") 54 55 // Write second Go output: definitions of _C_xxx. 56 // In a separate file so that the import of "unsafe" does not 57 // pollute the original file. 58 fmt.Fprintf(fgo2, "// Created by cgo - DO NOT EDIT\n\n") 59 fmt.Fprintf(fgo2, "package %s\n\n", p.PackageName) 60 fmt.Fprintf(fgo2, "import \"unsafe\"\n\n") 61 if *importSyscall { 62 fmt.Fprintf(fgo2, "import \"syscall\"\n\n") 63 } 64 if !*gccgo && *importRuntimeCgo { 65 fmt.Fprintf(fgo2, "import _ \"runtime/cgo\"\n\n") 66 } 67 fmt.Fprintf(fgo2, "type _ unsafe.Pointer\n\n") 68 if *importSyscall { 69 fmt.Fprintf(fgo2, "func _Cerrno(dst *error, x int32) { *dst = syscall.Errno(x) }\n") 70 } 71 72 typedefNames := make([]string, 0, len(typedef)) 73 for name := range typedef { 74 typedefNames = append(typedefNames, name) 75 } 76 sort.Strings(typedefNames) 77 for _, name := range typedefNames { 78 def := typedef[name] 79 fmt.Fprintf(fgo2, "type %s ", name) 80 conf.Fprint(fgo2, fset, def.Go) 81 fmt.Fprintf(fgo2, "\n\n") 82 } 83 if *gccgo { 84 fmt.Fprintf(fgo2, "type _Ctype_void byte\n") 85 } else { 86 fmt.Fprintf(fgo2, "type _Ctype_void [0]byte\n") 87 } 88 89 if *gccgo { 90 fmt.Fprintf(fc, cPrologGccgo) 91 } else { 92 fmt.Fprintf(fc, cProlog) 93 } 94 95 gccgoSymbolPrefix := p.gccgoSymbolPrefix() 96 97 cVars := make(map[string]bool) 98 for _, key := range nameKeys(p.Name) { 99 n := p.Name[key] 100 if n.Kind != "var" { 101 continue 102 } 103 104 if !cVars[n.C] { 105 fmt.Fprintf(fm, "extern char %s[];\n", n.C) 106 fmt.Fprintf(fm, "void *_cgohack_%s = %s;\n\n", n.C, n.C) 107 108 fmt.Fprintf(fc, "#pragma cgo_import_static %s\n", n.C) 109 fmt.Fprintf(fc, "extern byte *%s;\n", n.C) 110 111 cVars[n.C] = true 112 } 113 114 if *gccgo { 115 fmt.Fprintf(fc, `extern void *%s __asm__("%s.%s");`, n.Mangle, gccgoSymbolPrefix, n.Mangle) 116 fmt.Fprintf(&gccgoInit, "\t%s = &%s;\n", n.Mangle, n.C) 117 } else { 118 fmt.Fprintf(fc, "void *·%s = &%s;\n", n.Mangle, n.C) 119 } 120 fmt.Fprintf(fc, "\n") 121 122 fmt.Fprintf(fgo2, "var %s ", n.Mangle) 123 conf.Fprint(fgo2, fset, &ast.StarExpr{X: n.Type.Go}) 124 fmt.Fprintf(fgo2, "\n") 125 } 126 fmt.Fprintf(fc, "\n") 127 128 for _, key := range nameKeys(p.Name) { 129 n := p.Name[key] 130 if n.Const != "" { 131 fmt.Fprintf(fgo2, "const _Cconst_%s = %s\n", n.Go, n.Const) 132 } 133 } 134 fmt.Fprintf(fgo2, "\n") 135 136 for _, key := range nameKeys(p.Name) { 137 n := p.Name[key] 138 if n.FuncType != nil { 139 p.writeDefsFunc(fc, fgo2, n) 140 } 141 } 142 143 if *gccgo { 144 p.writeGccgoExports(fgo2, fc, fm) 145 } else { 146 p.writeExports(fgo2, fc, fm) 147 } 148 149 init := gccgoInit.String() 150 if init != "" { 151 fmt.Fprintln(fc, "static void init(void) __attribute__ ((constructor));") 152 fmt.Fprintln(fc, "static void init(void) {") 153 fmt.Fprint(fc, init) 154 fmt.Fprintln(fc, "}") 155 } 156 157 fgo2.Close() 158 fc.Close() 159 } 160 161 func dynimport(obj string) { 162 stdout := os.Stdout 163 if *dynout != "" { 164 f, err := os.Create(*dynout) 165 if err != nil { 166 fatalf("%s", err) 167 } 168 stdout = f 169 } 170 171 if f, err := elf.Open(obj); err == nil { 172 if *dynlinker { 173 // Emit the cgo_dynamic_linker line. 174 if sec := f.Section(".interp"); sec != nil { 175 if data, err := sec.Data(); err == nil && len(data) > 1 { 176 // skip trailing \0 in data 177 fmt.Fprintf(stdout, "#pragma cgo_dynamic_linker %q\n", string(data[:len(data)-1])) 178 } 179 } 180 } 181 sym, err := f.ImportedSymbols() 182 if err != nil { 183 fatalf("cannot load imported symbols from ELF file %s: %v", obj, err) 184 } 185 for _, s := range sym { 186 targ := s.Name 187 if s.Version != "" { 188 targ += "#" + s.Version 189 } 190 fmt.Fprintf(stdout, "#pragma cgo_import_dynamic %s %s %q\n", s.Name, targ, s.Library) 191 } 192 lib, err := f.ImportedLibraries() 193 if err != nil { 194 fatalf("cannot load imported libraries from ELF file %s: %v", obj, err) 195 } 196 for _, l := range lib { 197 fmt.Fprintf(stdout, "#pragma cgo_import_dynamic _ _ %q\n", l) 198 } 199 return 200 } 201 202 if f, err := macho.Open(obj); err == nil { 203 sym, err := f.ImportedSymbols() 204 if err != nil { 205 fatalf("cannot load imported symbols from Mach-O file %s: %v", obj, err) 206 } 207 for _, s := range sym { 208 if len(s) > 0 && s[0] == '_' { 209 s = s[1:] 210 } 211 fmt.Fprintf(stdout, "#pragma cgo_import_dynamic %s %s %q\n", s, s, "") 212 } 213 lib, err := f.ImportedLibraries() 214 if err != nil { 215 fatalf("cannot load imported libraries from Mach-O file %s: %v", obj, err) 216 } 217 for _, l := range lib { 218 fmt.Fprintf(stdout, "#pragma cgo_import_dynamic _ _ %q\n", l) 219 } 220 return 221 } 222 223 if f, err := pe.Open(obj); err == nil { 224 sym, err := f.ImportedSymbols() 225 if err != nil { 226 fatalf("cannot load imported symbols from PE file %s: %v", obj, err) 227 } 228 for _, s := range sym { 229 ss := strings.Split(s, ":") 230 name := strings.Split(ss[0], "@")[0] 231 fmt.Fprintf(stdout, "#pragma cgo_import_dynamic %s %s %q\n", name, ss[0], strings.ToLower(ss[1])) 232 } 233 return 234 } 235 236 fatalf("cannot parse %s as ELF, Mach-O or PE", obj) 237 } 238 239 // Construct a gcc struct matching the 6c argument frame. 240 // Assumes that in gcc, char is 1 byte, short 2 bytes, int 4 bytes, long long 8 bytes. 241 // These assumptions are checked by the gccProlog. 242 // Also assumes that 6c convention is to word-align the 243 // input and output parameters. 244 func (p *Package) structType(n *Name) (string, int64) { 245 var buf bytes.Buffer 246 fmt.Fprint(&buf, "struct {\n") 247 off := int64(0) 248 for i, t := range n.FuncType.Params { 249 if off%t.Align != 0 { 250 pad := t.Align - off%t.Align 251 fmt.Fprintf(&buf, "\t\tchar __pad%d[%d];\n", off, pad) 252 off += pad 253 } 254 c := t.Typedef 255 if c == "" { 256 c = t.C.String() 257 } 258 fmt.Fprintf(&buf, "\t\t%s p%d;\n", c, i) 259 off += t.Size 260 } 261 if off%p.PtrSize != 0 { 262 pad := p.PtrSize - off%p.PtrSize 263 fmt.Fprintf(&buf, "\t\tchar __pad%d[%d];\n", off, pad) 264 off += pad 265 } 266 if t := n.FuncType.Result; t != nil { 267 if off%t.Align != 0 { 268 pad := t.Align - off%t.Align 269 fmt.Fprintf(&buf, "\t\tchar __pad%d[%d];\n", off, pad) 270 off += pad 271 } 272 qual := "" 273 if c := t.C.String(); c[len(c)-1] == '*' { 274 qual = "const " 275 } 276 fmt.Fprintf(&buf, "\t\t%s%s r;\n", qual, t.C) 277 off += t.Size 278 } 279 if off%p.PtrSize != 0 { 280 pad := p.PtrSize - off%p.PtrSize 281 fmt.Fprintf(&buf, "\t\tchar __pad%d[%d];\n", off, pad) 282 off += pad 283 } 284 if n.AddError { 285 fmt.Fprint(&buf, "\t\tvoid *e[2]; /* error */\n") 286 off += 2 * p.PtrSize 287 } 288 if off == 0 { 289 fmt.Fprintf(&buf, "\t\tchar unused;\n") // avoid empty struct 290 } 291 fmt.Fprintf(&buf, "\t}") 292 return buf.String(), off 293 } 294 295 func (p *Package) writeDefsFunc(fc, fgo2 *os.File, n *Name) { 296 name := n.Go 297 gtype := n.FuncType.Go 298 void := gtype.Results == nil || len(gtype.Results.List) == 0 299 if n.AddError { 300 // Add "error" to return type list. 301 // Type list is known to be 0 or 1 element - it's a C function. 302 err := &ast.Field{Type: ast.NewIdent("error")} 303 l := gtype.Results.List 304 if len(l) == 0 { 305 l = []*ast.Field{err} 306 } else { 307 l = []*ast.Field{l[0], err} 308 } 309 t := new(ast.FuncType) 310 *t = *gtype 311 t.Results = &ast.FieldList{List: l} 312 gtype = t 313 } 314 315 // Go func declaration. 316 d := &ast.FuncDecl{ 317 Name: ast.NewIdent(n.Mangle), 318 Type: gtype, 319 } 320 321 if *gccgo { 322 // Gccgo style hooks. 323 fmt.Fprint(fgo2, "\n") 324 cname := fmt.Sprintf("_cgo%s%s", cPrefix, n.Mangle) 325 paramnames := []string(nil) 326 for i, param := range d.Type.Params.List { 327 paramName := fmt.Sprintf("p%d", i) 328 param.Names = []*ast.Ident{ast.NewIdent(paramName)} 329 paramnames = append(paramnames, paramName) 330 } 331 332 conf.Fprint(fgo2, fset, d) 333 fmt.Fprint(fgo2, " {\n") 334 fmt.Fprint(fgo2, "\tdefer syscall.CgocallDone()\n") 335 fmt.Fprint(fgo2, "\tsyscall.Cgocall()\n") 336 if n.AddError { 337 fmt.Fprint(fgo2, "\tsyscall.SetErrno(0)\n") 338 } 339 fmt.Fprint(fgo2, "\t") 340 if !void { 341 fmt.Fprint(fgo2, "r := ") 342 } 343 fmt.Fprintf(fgo2, "%s(%s)\n", cname, strings.Join(paramnames, ", ")) 344 345 if n.AddError { 346 fmt.Fprint(fgo2, "\te := syscall.GetErrno()\n") 347 fmt.Fprint(fgo2, "\tif e != 0 {\n") 348 fmt.Fprint(fgo2, "\t\treturn ") 349 if !void { 350 fmt.Fprint(fgo2, "r, ") 351 } 352 fmt.Fprint(fgo2, "e\n") 353 fmt.Fprint(fgo2, "\t}\n") 354 fmt.Fprint(fgo2, "\treturn ") 355 if !void { 356 fmt.Fprint(fgo2, "r, ") 357 } 358 fmt.Fprint(fgo2, "nil\n") 359 } else if !void { 360 fmt.Fprint(fgo2, "\treturn r\n") 361 } 362 363 fmt.Fprint(fgo2, "}\n") 364 365 // declare the C function. 366 fmt.Fprintf(fgo2, "//extern %s\n", n.C) 367 d.Name = ast.NewIdent(cname) 368 if n.AddError { 369 l := d.Type.Results.List 370 d.Type.Results.List = l[:len(l)-1] 371 } 372 conf.Fprint(fgo2, fset, d) 373 fmt.Fprint(fgo2, "\n") 374 375 return 376 } 377 conf.Fprint(fgo2, fset, d) 378 fmt.Fprint(fgo2, "\n") 379 380 if name == "CString" || name == "GoString" || name == "GoStringN" || name == "GoBytes" { 381 // The builtins are already defined in the C prolog. 382 return 383 } 384 385 var argSize int64 386 _, argSize = p.structType(n) 387 388 // C wrapper calls into gcc, passing a pointer to the argument frame. 389 fmt.Fprintf(fc, "#pragma cgo_import_static _cgo%s%s\n", cPrefix, n.Mangle) 390 fmt.Fprintf(fc, "void _cgo%s%s(void*);\n", cPrefix, n.Mangle) 391 fmt.Fprintf(fc, "\n") 392 fmt.Fprintf(fc, "void\n") 393 if argSize == 0 { 394 argSize++ 395 } 396 fmt.Fprintf(fc, "·%s(struct{uint8 x[%d];}p)\n", n.Mangle, argSize) 397 fmt.Fprintf(fc, "{\n") 398 fmt.Fprintf(fc, "\truntime·cgocall(_cgo%s%s, &p);\n", cPrefix, n.Mangle) 399 if n.AddError { 400 // gcc leaves errno in first word of interface at end of p. 401 // check whether it is zero; if so, turn interface into nil. 402 // if not, turn interface into errno. 403 // Go init function initializes ·_Cerrno with an os.Errno 404 // for us to copy. 405 fmt.Fprintln(fc, ` { 406 int32 e; 407 void **v; 408 v = (void**)(&p+1) - 2; /* v = final two void* of p */ 409 e = *(int32*)v; 410 v[0] = (void*)0xdeadbeef; 411 v[1] = (void*)0xdeadbeef; 412 if(e == 0) { 413 /* nil interface */ 414 v[0] = 0; 415 v[1] = 0; 416 } else { 417 ·_Cerrno(v, e); /* fill in v as error for errno e */ 418 } 419 }`) 420 } 421 fmt.Fprintf(fc, "}\n") 422 fmt.Fprintf(fc, "\n") 423 } 424 425 // writeOutput creates stubs for a specific source file to be compiled by 6g 426 // (The comments here say 6g and 6c but the code applies to the 8 and 5 tools too.) 427 func (p *Package) writeOutput(f *File, srcfile string) { 428 base := srcfile 429 if strings.HasSuffix(base, ".go") { 430 base = base[0 : len(base)-3] 431 } 432 base = strings.Map(slashToUnderscore, base) 433 fgo1 := creat(*objDir + base + ".cgo1.go") 434 fgcc := creat(*objDir + base + ".cgo2.c") 435 436 p.GoFiles = append(p.GoFiles, base+".cgo1.go") 437 p.GccFiles = append(p.GccFiles, base+".cgo2.c") 438 439 // Write Go output: Go input with rewrites of C.xxx to _C_xxx. 440 fmt.Fprintf(fgo1, "// Created by cgo - DO NOT EDIT\n\n") 441 conf.Fprint(fgo1, fset, f.AST) 442 443 // While we process the vars and funcs, also write 6c and gcc output. 444 // Gcc output starts with the preamble. 445 fmt.Fprintf(fgcc, "%s\n", f.Preamble) 446 fmt.Fprintf(fgcc, "%s\n", gccProlog) 447 448 for _, key := range nameKeys(f.Name) { 449 n := f.Name[key] 450 if n.FuncType != nil { 451 p.writeOutputFunc(fgcc, n) 452 } 453 } 454 455 fgo1.Close() 456 fgcc.Close() 457 } 458 459 func (p *Package) writeOutputFunc(fgcc *os.File, n *Name) { 460 name := n.Mangle 461 if name == "_Cfunc_CString" || name == "_Cfunc_GoString" || name == "_Cfunc_GoStringN" || name == "_Cfunc_GoBytes" || p.Written[name] { 462 // The builtins are already defined in the C prolog, and we don't 463 // want to duplicate function definitions we've already done. 464 return 465 } 466 p.Written[name] = true 467 468 if *gccgo { 469 // we don't use wrappers with gccgo. 470 return 471 } 472 473 ctype, _ := p.structType(n) 474 475 // Gcc wrapper unpacks the C argument struct 476 // and calls the actual C function. 477 fmt.Fprintf(fgcc, "void\n") 478 fmt.Fprintf(fgcc, "_cgo%s%s(void *v)\n", cPrefix, n.Mangle) 479 fmt.Fprintf(fgcc, "{\n") 480 if n.AddError { 481 fmt.Fprintf(fgcc, "\tint e;\n") // assuming 32 bit (see comment above structType) 482 fmt.Fprintf(fgcc, "\terrno = 0;\n") 483 } 484 // We're trying to write a gcc struct that matches 6c/8c/5c's layout. 485 // Use packed attribute to force no padding in this struct in case 486 // gcc has different packing requirements. For example, 487 // on 386 Windows, gcc wants to 8-align int64s, but 8c does not. 488 fmt.Fprintf(fgcc, "\t%s __attribute__((__packed__)) *a = v;\n", ctype) 489 fmt.Fprintf(fgcc, "\t") 490 if t := n.FuncType.Result; t != nil { 491 fmt.Fprintf(fgcc, "a->r = ") 492 if c := t.C.String(); c[len(c)-1] == '*' { 493 fmt.Fprintf(fgcc, "(const %s) ", t.C) 494 } 495 } 496 fmt.Fprintf(fgcc, "%s(", n.C) 497 for i, t := range n.FuncType.Params { 498 if i > 0 { 499 fmt.Fprintf(fgcc, ", ") 500 } 501 // We know the type params are correct, because 502 // the Go equivalents had good type params. 503 // However, our version of the type omits the magic 504 // words const and volatile, which can provoke 505 // C compiler warnings. Silence them by casting 506 // all pointers to void*. (Eventually that will produce 507 // other warnings.) 508 if c := t.C.String(); c[len(c)-1] == '*' { 509 fmt.Fprintf(fgcc, "(void*)") 510 } 511 fmt.Fprintf(fgcc, "a->p%d", i) 512 } 513 fmt.Fprintf(fgcc, ");\n") 514 if n.AddError { 515 fmt.Fprintf(fgcc, "\t*(int*)(a->e) = errno;\n") 516 } 517 fmt.Fprintf(fgcc, "}\n") 518 fmt.Fprintf(fgcc, "\n") 519 } 520 521 // Write out the various stubs we need to support functions exported 522 // from Go so that they are callable from C. 523 func (p *Package) writeExports(fgo2, fc, fm *os.File) { 524 fgcc := creat(*objDir + "_cgo_export.c") 525 fgcch := creat(*objDir + "_cgo_export.h") 526 527 fmt.Fprintf(fgcch, "/* Created by cgo - DO NOT EDIT. */\n") 528 fmt.Fprintf(fgcch, "%s\n", p.Preamble) 529 fmt.Fprintf(fgcch, "%s\n", p.gccExportHeaderProlog()) 530 531 fmt.Fprintf(fgcc, "/* Created by cgo - DO NOT EDIT. */\n") 532 fmt.Fprintf(fgcc, "#include \"_cgo_export.h\"\n") 533 534 fmt.Fprintf(fgcc, "\nextern void crosscall2(void (*fn)(void *, int), void *, int);\n\n") 535 536 for _, exp := range p.ExpFunc { 537 fn := exp.Func 538 539 // Construct a gcc struct matching the 6c argument and 540 // result frame. The gcc struct will be compiled with 541 // __attribute__((packed)) so all padding must be accounted 542 // for explicitly. 543 ctype := "struct {\n" 544 off := int64(0) 545 npad := 0 546 if fn.Recv != nil { 547 t := p.cgoType(fn.Recv.List[0].Type) 548 ctype += fmt.Sprintf("\t\t%s recv;\n", t.C) 549 off += t.Size 550 } 551 fntype := fn.Type 552 forFieldList(fntype.Params, 553 func(i int, atype ast.Expr) { 554 t := p.cgoType(atype) 555 if off%t.Align != 0 { 556 pad := t.Align - off%t.Align 557 ctype += fmt.Sprintf("\t\tchar __pad%d[%d];\n", npad, pad) 558 off += pad 559 npad++ 560 } 561 ctype += fmt.Sprintf("\t\t%s p%d;\n", t.C, i) 562 off += t.Size 563 }) 564 if off%p.PtrSize != 0 { 565 pad := p.PtrSize - off%p.PtrSize 566 ctype += fmt.Sprintf("\t\tchar __pad%d[%d];\n", npad, pad) 567 off += pad 568 npad++ 569 } 570 forFieldList(fntype.Results, 571 func(i int, atype ast.Expr) { 572 t := p.cgoType(atype) 573 if off%t.Align != 0 { 574 pad := t.Align - off%t.Align 575 ctype += fmt.Sprintf("\t\tchar __pad%d[%d];\n", npad, pad) 576 off += pad 577 npad++ 578 } 579 ctype += fmt.Sprintf("\t\t%s r%d;\n", t.C, i) 580 off += t.Size 581 }) 582 if off%p.PtrSize != 0 { 583 pad := p.PtrSize - off%p.PtrSize 584 ctype += fmt.Sprintf("\t\tchar __pad%d[%d];\n", npad, pad) 585 off += pad 586 npad++ 587 } 588 if ctype == "struct {\n" { 589 ctype += "\t\tchar unused;\n" // avoid empty struct 590 } 591 ctype += "\t}" 592 593 // Get the return type of the wrapper function 594 // compiled by gcc. 595 gccResult := "" 596 if fntype.Results == nil || len(fntype.Results.List) == 0 { 597 gccResult = "void" 598 } else if len(fntype.Results.List) == 1 && len(fntype.Results.List[0].Names) <= 1 { 599 gccResult = p.cgoType(fntype.Results.List[0].Type).C.String() 600 } else { 601 fmt.Fprintf(fgcch, "\n/* Return type for %s */\n", exp.ExpName) 602 fmt.Fprintf(fgcch, "struct %s_return {\n", exp.ExpName) 603 forFieldList(fntype.Results, 604 func(i int, atype ast.Expr) { 605 fmt.Fprintf(fgcch, "\t%s r%d;\n", p.cgoType(atype).C, i) 606 }) 607 fmt.Fprintf(fgcch, "};\n") 608 gccResult = "struct " + exp.ExpName + "_return" 609 } 610 611 // Build the wrapper function compiled by gcc. 612 s := fmt.Sprintf("%s %s(", gccResult, exp.ExpName) 613 if fn.Recv != nil { 614 s += p.cgoType(fn.Recv.List[0].Type).C.String() 615 s += " recv" 616 } 617 forFieldList(fntype.Params, 618 func(i int, atype ast.Expr) { 619 if i > 0 || fn.Recv != nil { 620 s += ", " 621 } 622 s += fmt.Sprintf("%s p%d", p.cgoType(atype).C, i) 623 }) 624 s += ")" 625 fmt.Fprintf(fgcch, "\nextern %s;\n", s) 626 627 fmt.Fprintf(fgcc, "extern void _cgoexp%s_%s(void *, int);\n", cPrefix, exp.ExpName) 628 fmt.Fprintf(fgcc, "\n%s\n", s) 629 fmt.Fprintf(fgcc, "{\n") 630 fmt.Fprintf(fgcc, "\t%s __attribute__((packed)) a;\n", ctype) 631 if gccResult != "void" && (len(fntype.Results.List) > 1 || len(fntype.Results.List[0].Names) > 1) { 632 fmt.Fprintf(fgcc, "\t%s r;\n", gccResult) 633 } 634 if fn.Recv != nil { 635 fmt.Fprintf(fgcc, "\ta.recv = recv;\n") 636 } 637 forFieldList(fntype.Params, 638 func(i int, atype ast.Expr) { 639 fmt.Fprintf(fgcc, "\ta.p%d = p%d;\n", i, i) 640 }) 641 fmt.Fprintf(fgcc, "\tcrosscall2(_cgoexp%s_%s, &a, %d);\n", cPrefix, exp.ExpName, off) 642 if gccResult != "void" { 643 if len(fntype.Results.List) == 1 && len(fntype.Results.List[0].Names) <= 1 { 644 fmt.Fprintf(fgcc, "\treturn a.r0;\n") 645 } else { 646 forFieldList(fntype.Results, 647 func(i int, atype ast.Expr) { 648 fmt.Fprintf(fgcc, "\tr.r%d = a.r%d;\n", i, i) 649 }) 650 fmt.Fprintf(fgcc, "\treturn r;\n") 651 } 652 } 653 fmt.Fprintf(fgcc, "}\n") 654 655 // Build the wrapper function compiled by 6c/8c 656 goname := exp.Func.Name.Name 657 if fn.Recv != nil { 658 goname = "_cgoexpwrap" + cPrefix + "_" + fn.Recv.List[0].Names[0].Name + "_" + goname 659 } 660 fmt.Fprintf(fc, "#pragma cgo_export_dynamic %s\n", goname) 661 fmt.Fprintf(fc, "extern void ·%s();\n\n", goname) 662 fmt.Fprintf(fc, "#pragma cgo_export_static _cgoexp%s_%s\n", cPrefix, exp.ExpName) 663 fmt.Fprintf(fc, "#pragma textflag 7\n") // no split stack, so no use of m or g 664 fmt.Fprintf(fc, "void\n") 665 fmt.Fprintf(fc, "_cgoexp%s_%s(void *a, int32 n)\n", cPrefix, exp.ExpName) 666 fmt.Fprintf(fc, "{\n") 667 fmt.Fprintf(fc, "\truntime·cgocallback(·%s, a, n);\n", goname) 668 fmt.Fprintf(fc, "}\n") 669 670 fmt.Fprintf(fm, "int _cgoexp%s_%s;\n", cPrefix, exp.ExpName) 671 672 // Calling a function with a receiver from C requires 673 // a Go wrapper function. 674 if fn.Recv != nil { 675 fmt.Fprintf(fgo2, "func %s(recv ", goname) 676 conf.Fprint(fgo2, fset, fn.Recv.List[0].Type) 677 forFieldList(fntype.Params, 678 func(i int, atype ast.Expr) { 679 fmt.Fprintf(fgo2, ", p%d ", i) 680 conf.Fprint(fgo2, fset, atype) 681 }) 682 fmt.Fprintf(fgo2, ")") 683 if gccResult != "void" { 684 fmt.Fprint(fgo2, " (") 685 forFieldList(fntype.Results, 686 func(i int, atype ast.Expr) { 687 if i > 0 { 688 fmt.Fprint(fgo2, ", ") 689 } 690 conf.Fprint(fgo2, fset, atype) 691 }) 692 fmt.Fprint(fgo2, ")") 693 } 694 fmt.Fprint(fgo2, " {\n") 695 fmt.Fprint(fgo2, "\t") 696 if gccResult != "void" { 697 fmt.Fprint(fgo2, "return ") 698 } 699 fmt.Fprintf(fgo2, "recv.%s(", exp.Func.Name) 700 forFieldList(fntype.Params, 701 func(i int, atype ast.Expr) { 702 if i > 0 { 703 fmt.Fprint(fgo2, ", ") 704 } 705 fmt.Fprintf(fgo2, "p%d", i) 706 }) 707 fmt.Fprint(fgo2, ")\n") 708 fmt.Fprint(fgo2, "}\n") 709 } 710 } 711 } 712 713 // Write out the C header allowing C code to call exported gccgo functions. 714 func (p *Package) writeGccgoExports(fgo2, fc, fm *os.File) { 715 fgcc := creat(*objDir + "_cgo_export.c") 716 fgcch := creat(*objDir + "_cgo_export.h") 717 718 gccgoSymbolPrefix := p.gccgoSymbolPrefix() 719 720 fmt.Fprintf(fgcch, "/* Created by cgo - DO NOT EDIT. */\n") 721 fmt.Fprintf(fgcch, "%s\n", p.Preamble) 722 fmt.Fprintf(fgcch, "%s\n", p.gccExportHeaderProlog()) 723 724 fmt.Fprintf(fgcc, "/* Created by cgo - DO NOT EDIT. */\n") 725 fmt.Fprintf(fgcc, "#include \"_cgo_export.h\"\n") 726 727 fmt.Fprintf(fm, "#include \"_cgo_export.h\"\n") 728 729 for _, exp := range p.ExpFunc { 730 fn := exp.Func 731 fntype := fn.Type 732 733 cdeclBuf := new(bytes.Buffer) 734 resultCount := 0 735 forFieldList(fntype.Results, 736 func(i int, atype ast.Expr) { resultCount++ }) 737 switch resultCount { 738 case 0: 739 fmt.Fprintf(cdeclBuf, "void") 740 case 1: 741 forFieldList(fntype.Results, 742 func(i int, atype ast.Expr) { 743 t := p.cgoType(atype) 744 fmt.Fprintf(cdeclBuf, "%s", t.C) 745 }) 746 default: 747 // Declare a result struct. 748 fmt.Fprintf(fgcch, "struct %s_result {\n", exp.ExpName) 749 forFieldList(fntype.Results, 750 func(i int, atype ast.Expr) { 751 t := p.cgoType(atype) 752 fmt.Fprintf(fgcch, "\t%s r%d;\n", t.C, i) 753 }) 754 fmt.Fprintf(fgcch, "};\n") 755 fmt.Fprintf(cdeclBuf, "struct %s_result", exp.ExpName) 756 } 757 758 cRet := cdeclBuf.String() 759 760 cdeclBuf = new(bytes.Buffer) 761 fmt.Fprintf(cdeclBuf, "(") 762 if fn.Recv != nil { 763 fmt.Fprintf(cdeclBuf, "%s recv", p.cgoType(fn.Recv.List[0].Type).C.String()) 764 } 765 // Function parameters. 766 forFieldList(fntype.Params, 767 func(i int, atype ast.Expr) { 768 if i > 0 || fn.Recv != nil { 769 fmt.Fprintf(cdeclBuf, ", ") 770 } 771 t := p.cgoType(atype) 772 fmt.Fprintf(cdeclBuf, "%s p%d", t.C, i) 773 }) 774 fmt.Fprintf(cdeclBuf, ")") 775 cParams := cdeclBuf.String() 776 777 goName := "Cgoexp_" + exp.ExpName 778 fmt.Fprintf(fgcch, `extern %s %s %s __asm__("%s.%s");`, cRet, goName, cParams, gccgoSymbolPrefix, goName) 779 fmt.Fprint(fgcch, "\n") 780 781 fmt.Fprint(fgcc, "\n") 782 fmt.Fprintf(fgcc, "%s %s %s {\n", cRet, exp.ExpName, cParams) 783 fmt.Fprint(fgcc, "\t") 784 if resultCount > 0 { 785 fmt.Fprint(fgcc, "return ") 786 } 787 fmt.Fprintf(fgcc, "%s(", goName) 788 if fn.Recv != nil { 789 fmt.Fprint(fgcc, "recv") 790 } 791 forFieldList(fntype.Params, 792 func(i int, atype ast.Expr) { 793 if i > 0 || fn.Recv != nil { 794 fmt.Fprintf(fgcc, ", ") 795 } 796 fmt.Fprintf(fgcc, "p%d", i) 797 }) 798 fmt.Fprint(fgcc, ");\n") 799 fmt.Fprint(fgcc, "}\n") 800 801 // Dummy declaration for _cgo_main.c 802 fmt.Fprintf(fm, "%s %s %s {}\n", cRet, goName, cParams) 803 804 // For gccgo we use a wrapper function in Go, in order 805 // to call CgocallBack and CgocallBackDone. 806 807 // This code uses printer.Fprint, not conf.Fprint, 808 // because we don't want //line comments in the middle 809 // of the function types. 810 fmt.Fprint(fgo2, "\n") 811 fmt.Fprintf(fgo2, "func %s(", goName) 812 if fn.Recv != nil { 813 fmt.Fprint(fgo2, "recv ") 814 printer.Fprint(fgo2, fset, fn.Recv.List[0].Type) 815 } 816 forFieldList(fntype.Params, 817 func(i int, atype ast.Expr) { 818 if i > 0 || fn.Recv != nil { 819 fmt.Fprintf(fgo2, ", ") 820 } 821 fmt.Fprintf(fgo2, "p%d ", i) 822 printer.Fprint(fgo2, fset, atype) 823 }) 824 fmt.Fprintf(fgo2, ")") 825 if resultCount > 0 { 826 fmt.Fprintf(fgo2, " (") 827 forFieldList(fntype.Results, 828 func(i int, atype ast.Expr) { 829 if i > 0 { 830 fmt.Fprint(fgo2, ", ") 831 } 832 printer.Fprint(fgo2, fset, atype) 833 }) 834 fmt.Fprint(fgo2, ")") 835 } 836 fmt.Fprint(fgo2, " {\n") 837 fmt.Fprint(fgo2, "\tsyscall.CgocallBack()\n") 838 fmt.Fprint(fgo2, "\tdefer syscall.CgocallBackDone()\n") 839 fmt.Fprint(fgo2, "\t") 840 if resultCount > 0 { 841 fmt.Fprint(fgo2, "return ") 842 } 843 if fn.Recv != nil { 844 fmt.Fprint(fgo2, "recv.") 845 } 846 fmt.Fprintf(fgo2, "%s(", exp.Func.Name) 847 forFieldList(fntype.Params, 848 func(i int, atype ast.Expr) { 849 if i > 0 { 850 fmt.Fprint(fgo2, ", ") 851 } 852 fmt.Fprintf(fgo2, "p%d", i) 853 }) 854 fmt.Fprint(fgo2, ")\n") 855 fmt.Fprint(fgo2, "}\n") 856 } 857 } 858 859 // Return the package prefix when using gccgo. 860 func (p *Package) gccgoSymbolPrefix() string { 861 if !*gccgo { 862 return "" 863 } 864 865 clean := func(r rune) rune { 866 switch { 867 case 'A' <= r && r <= 'Z', 'a' <= r && r <= 'z', 868 '0' <= r && r <= '9': 869 return r 870 } 871 return '_' 872 } 873 874 if *gccgopkgpath != "" { 875 return strings.Map(clean, *gccgopkgpath) 876 } 877 if *gccgoprefix == "" && p.PackageName == "main" { 878 return "main" 879 } 880 prefix := strings.Map(clean, *gccgoprefix) 881 if prefix == "" { 882 prefix = "go" 883 } 884 return prefix + "." + p.PackageName 885 } 886 887 // Call a function for each entry in an ast.FieldList, passing the 888 // index into the list and the type. 889 func forFieldList(fl *ast.FieldList, fn func(int, ast.Expr)) { 890 if fl == nil { 891 return 892 } 893 i := 0 894 for _, r := range fl.List { 895 if r.Names == nil { 896 fn(i, r.Type) 897 i++ 898 } else { 899 for _ = range r.Names { 900 fn(i, r.Type) 901 i++ 902 } 903 } 904 } 905 } 906 907 func c(repr string, args ...interface{}) *TypeRepr { 908 return &TypeRepr{repr, args} 909 } 910 911 // Map predeclared Go types to Type. 912 var goTypes = map[string]*Type{ 913 "bool": {Size: 1, Align: 1, C: c("GoUint8")}, 914 "byte": {Size: 1, Align: 1, C: c("GoUint8")}, 915 "int": {Size: 0, Align: 0, C: c("GoInt")}, 916 "uint": {Size: 0, Align: 0, C: c("GoUint")}, 917 "rune": {Size: 4, Align: 4, C: c("GoInt32")}, 918 "int8": {Size: 1, Align: 1, C: c("GoInt8")}, 919 "uint8": {Size: 1, Align: 1, C: c("GoUint8")}, 920 "int16": {Size: 2, Align: 2, C: c("GoInt16")}, 921 "uint16": {Size: 2, Align: 2, C: c("GoUint16")}, 922 "int32": {Size: 4, Align: 4, C: c("GoInt32")}, 923 "uint32": {Size: 4, Align: 4, C: c("GoUint32")}, 924 "int64": {Size: 8, Align: 8, C: c("GoInt64")}, 925 "uint64": {Size: 8, Align: 8, C: c("GoUint64")}, 926 "float32": {Size: 4, Align: 4, C: c("GoFloat32")}, 927 "float64": {Size: 8, Align: 8, C: c("GoFloat64")}, 928 "complex64": {Size: 8, Align: 8, C: c("GoComplex64")}, 929 "complex128": {Size: 16, Align: 16, C: c("GoComplex128")}, 930 } 931 932 // Map an ast type to a Type. 933 func (p *Package) cgoType(e ast.Expr) *Type { 934 switch t := e.(type) { 935 case *ast.StarExpr: 936 x := p.cgoType(t.X) 937 return &Type{Size: p.PtrSize, Align: p.PtrSize, C: c("%s*", x.C)} 938 case *ast.ArrayType: 939 if t.Len == nil { 940 return &Type{Size: p.PtrSize + 8, Align: p.PtrSize, C: c("GoSlice")} 941 } 942 case *ast.StructType: 943 // TODO 944 case *ast.FuncType: 945 return &Type{Size: p.PtrSize, Align: p.PtrSize, C: c("void*")} 946 case *ast.InterfaceType: 947 return &Type{Size: 2 * p.PtrSize, Align: p.PtrSize, C: c("GoInterface")} 948 case *ast.MapType: 949 return &Type{Size: p.PtrSize, Align: p.PtrSize, C: c("GoMap")} 950 case *ast.ChanType: 951 return &Type{Size: p.PtrSize, Align: p.PtrSize, C: c("GoChan")} 952 case *ast.Ident: 953 // Look up the type in the top level declarations. 954 // TODO: Handle types defined within a function. 955 for _, d := range p.Decl { 956 gd, ok := d.(*ast.GenDecl) 957 if !ok || gd.Tok != token.TYPE { 958 continue 959 } 960 for _, spec := range gd.Specs { 961 ts, ok := spec.(*ast.TypeSpec) 962 if !ok { 963 continue 964 } 965 if ts.Name.Name == t.Name { 966 return p.cgoType(ts.Type) 967 } 968 } 969 } 970 if def := typedef[t.Name]; def != nil { 971 return def 972 } 973 if t.Name == "uintptr" { 974 return &Type{Size: p.PtrSize, Align: p.PtrSize, C: c("GoUintptr")} 975 } 976 if t.Name == "string" { 977 // The string data is 1 pointer + 1 int, but this always 978 // rounds to 2 pointers due to alignment. 979 return &Type{Size: 2 * p.PtrSize, Align: p.PtrSize, C: c("GoString")} 980 } 981 if t.Name == "error" { 982 return &Type{Size: 2 * p.PtrSize, Align: p.PtrSize, C: c("GoInterface")} 983 } 984 if r, ok := goTypes[t.Name]; ok { 985 if r.Size == 0 { // int or uint 986 rr := new(Type) 987 *rr = *r 988 rr.Size = p.IntSize 989 rr.Align = p.IntSize 990 r = rr 991 } 992 if r.Align > p.PtrSize { 993 r.Align = p.PtrSize 994 } 995 return r 996 } 997 error_(e.Pos(), "unrecognized Go type %s", t.Name) 998 return &Type{Size: 4, Align: 4, C: c("int")} 999 case *ast.SelectorExpr: 1000 id, ok := t.X.(*ast.Ident) 1001 if ok && id.Name == "unsafe" && t.Sel.Name == "Pointer" { 1002 return &Type{Size: p.PtrSize, Align: p.PtrSize, C: c("void*")} 1003 } 1004 } 1005 error_(e.Pos(), "Go type not supported in export: %s", gofmt(e)) 1006 return &Type{Size: 4, Align: 4, C: c("int")} 1007 } 1008 1009 const gccProlog = ` 1010 // Usual nonsense: if x and y are not equal, the type will be invalid 1011 // (have a negative array count) and an inscrutable error will come 1012 // out of the compiler and hopefully mention "name". 1013 #define __cgo_compile_assert_eq(x, y, name) typedef char name[(x-y)*(x-y)*-2+1]; 1014 1015 // Check at compile time that the sizes we use match our expectations. 1016 #define __cgo_size_assert(t, n) __cgo_compile_assert_eq(sizeof(t), n, _cgo_sizeof_##t##_is_not_##n) 1017 1018 __cgo_size_assert(char, 1) 1019 __cgo_size_assert(short, 2) 1020 __cgo_size_assert(int, 4) 1021 typedef long long __cgo_long_long; 1022 __cgo_size_assert(__cgo_long_long, 8) 1023 __cgo_size_assert(float, 4) 1024 __cgo_size_assert(double, 8) 1025 1026 #include <errno.h> 1027 #include <string.h> 1028 ` 1029 1030 const builtinProlog = ` 1031 typedef struct { char *p; int n; } _GoString_; 1032 typedef struct { char *p; int n; int c; } _GoBytes_; 1033 _GoString_ GoString(char *p); 1034 _GoString_ GoStringN(char *p, int l); 1035 _GoBytes_ GoBytes(void *p, int n); 1036 char *CString(_GoString_); 1037 ` 1038 1039 const cProlog = ` 1040 #include "runtime.h" 1041 #include "cgocall.h" 1042 1043 void ·_Cerrno(void*, int32); 1044 1045 void 1046 ·_Cfunc_GoString(int8 *p, String s) 1047 { 1048 s = runtime·gostring((byte*)p); 1049 FLUSH(&s); 1050 } 1051 1052 void 1053 ·_Cfunc_GoStringN(int8 *p, int32 l, String s) 1054 { 1055 s = runtime·gostringn((byte*)p, l); 1056 FLUSH(&s); 1057 } 1058 1059 void 1060 ·_Cfunc_GoBytes(int8 *p, int32 l, Slice s) 1061 { 1062 s = runtime·gobytes((byte*)p, l); 1063 FLUSH(&s); 1064 } 1065 1066 void 1067 ·_Cfunc_CString(String s, int8 *p) 1068 { 1069 p = runtime·cmalloc(s.len+1); 1070 runtime·memmove((byte*)p, s.str, s.len); 1071 p[s.len] = 0; 1072 FLUSH(&p); 1073 } 1074 ` 1075 1076 const cPrologGccgo = ` 1077 #include <stdint.h> 1078 #include <string.h> 1079 1080 typedef unsigned char byte; 1081 typedef intptr_t intgo; 1082 1083 struct __go_string { 1084 const unsigned char *__data; 1085 intgo __length; 1086 }; 1087 1088 typedef struct __go_open_array { 1089 void* __values; 1090 intgo __count; 1091 intgo __capacity; 1092 } Slice; 1093 1094 struct __go_string __go_byte_array_to_string(const void* p, intgo len); 1095 struct __go_open_array __go_string_to_byte_array (struct __go_string str); 1096 1097 const char *CString(struct __go_string s) { 1098 return strndup((const char*)s.__data, s.__length); 1099 } 1100 1101 struct __go_string GoString(char *p) { 1102 intgo len = (p != NULL) ? strlen(p) : 0; 1103 return __go_byte_array_to_string(p, len); 1104 } 1105 1106 struct __go_string GoStringN(char *p, intgo n) { 1107 return __go_byte_array_to_string(p, n); 1108 } 1109 1110 Slice GoBytes(char *p, intgo n) { 1111 struct __go_string s = { (const unsigned char *)p, n }; 1112 return __go_string_to_byte_array(s); 1113 } 1114 ` 1115 1116 func (p *Package) gccExportHeaderProlog() string { 1117 return strings.Replace(gccExportHeaderProlog, "GOINTBITS", fmt.Sprint(8*p.IntSize), -1) 1118 } 1119 1120 const gccExportHeaderProlog = ` 1121 typedef signed char GoInt8; 1122 typedef unsigned char GoUint8; 1123 typedef short GoInt16; 1124 typedef unsigned short GoUint16; 1125 typedef int GoInt32; 1126 typedef unsigned int GoUint32; 1127 typedef long long GoInt64; 1128 typedef unsigned long long GoUint64; 1129 typedef GoIntGOINTBITS GoInt; 1130 typedef GoUintGOINTBITS GoUint; 1131 typedef __SIZE_TYPE__ GoUintptr; 1132 typedef float GoFloat32; 1133 typedef double GoFloat64; 1134 typedef __complex float GoComplex64; 1135 typedef __complex double GoComplex128; 1136 1137 typedef struct { char *p; int n; } GoString; 1138 typedef void *GoMap; 1139 typedef void *GoChan; 1140 typedef struct { void *t; void *v; } GoInterface; 1141 typedef struct { void *data; int len; int cap; } GoSlice; 1142 `