github.com/rsc/go@v0.0.0-20150416155037-e040fd465409/src/cmd/internal/ld/go.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 ld 6 7 import ( 8 "bytes" 9 "cmd/internal/obj" 10 "fmt" 11 "os" 12 "strconv" 13 "strings" 14 ) 15 16 // go-specific code shared across loaders (5l, 6l, 8l). 17 18 // replace all "". with pkg. 19 func expandpkg(t0 string, pkg string) string { 20 return strings.Replace(t0, `"".`, pkg+".", -1) 21 } 22 23 // Copyright 2009 The Go Authors. All rights reserved. 24 // Use of this source code is governed by a BSD-style 25 // license that can be found in the LICENSE file. 26 27 // go-specific code shared across loaders (5l, 6l, 8l). 28 29 // accumulate all type information from .6 files. 30 // check for inconsistencies. 31 32 // TODO: 33 // generate debugging section in binary. 34 // once the dust settles, try to move some code to 35 // libmach, so that other linkers and ar can share. 36 37 /* 38 * package import data 39 */ 40 type Import struct { 41 prefix string // "type", "var", "func", "const" 42 name string 43 def string 44 file string 45 } 46 47 // importmap records type information about imported symbols to detect inconsistencies. 48 // Entries are keyed by qualified symbol name (e.g., "runtime.Callers" or "net/url.Error"). 49 var importmap = map[string]*Import{} 50 51 func lookupImport(name string) *Import { 52 if x, ok := importmap[name]; ok { 53 return x 54 } 55 x := &Import{name: name} 56 importmap[name] = x 57 return x 58 } 59 60 func ldpkg(f *Biobuf, pkg string, length int64, filename string, whence int) { 61 var p0, p1 int 62 63 if Debug['g'] != 0 { 64 return 65 } 66 67 if int64(int(length)) != length { 68 fmt.Fprintf(os.Stderr, "%s: too much pkg data in %s\n", os.Args[0], filename) 69 if Debug['u'] != 0 { 70 Errorexit() 71 } 72 return 73 } 74 75 bdata := make([]byte, length) 76 if int64(Bread(f, bdata)) != length { 77 fmt.Fprintf(os.Stderr, "%s: short pkg read %s\n", os.Args[0], filename) 78 if Debug['u'] != 0 { 79 Errorexit() 80 } 81 return 82 } 83 data := string(bdata) 84 85 // first \n$$ marks beginning of exports - skip rest of line 86 p0 = strings.Index(data, "\n$$") 87 if p0 < 0 { 88 if Debug['u'] != 0 && whence != ArchiveObj { 89 fmt.Fprintf(os.Stderr, "%s: cannot find export data in %s\n", os.Args[0], filename) 90 Errorexit() 91 } 92 return 93 } 94 95 p0 += 3 96 for p0 < len(data) && data[p0] != '\n' { 97 p0++ 98 } 99 100 // second marks end of exports / beginning of local data 101 p1 = strings.Index(data[p0:], "\n$$") 102 if p1 < 0 { 103 fmt.Fprintf(os.Stderr, "%s: cannot find end of exports in %s\n", os.Args[0], filename) 104 if Debug['u'] != 0 { 105 Errorexit() 106 } 107 return 108 } 109 p1 += p0 110 111 for p0 < p1 && (data[p0] == ' ' || data[p0] == '\t' || data[p0] == '\n') { 112 p0++ 113 } 114 if p0 < p1 { 115 if !strings.HasPrefix(data[p0:], "package ") { 116 fmt.Fprintf(os.Stderr, "%s: bad package section in %s - %.20s\n", os.Args[0], filename, data[p0:]) 117 if Debug['u'] != 0 { 118 Errorexit() 119 } 120 return 121 } 122 123 p0 += 8 124 for p0 < p1 && (data[p0] == ' ' || data[p0] == '\t' || data[p0] == '\n') { 125 p0++ 126 } 127 pname := p0 128 for p0 < p1 && data[p0] != ' ' && data[p0] != '\t' && data[p0] != '\n' { 129 p0++ 130 } 131 if Debug['u'] != 0 && whence != ArchiveObj && (p0+6 > p1 || !strings.HasPrefix(data[p0:], " safe\n")) { 132 fmt.Fprintf(os.Stderr, "%s: load of unsafe package %s\n", os.Args[0], filename) 133 nerrors++ 134 Errorexit() 135 } 136 137 name := data[pname:p0] 138 for p0 < p1 && data[p0] != '\n' { 139 p0++ 140 } 141 if p0 < p1 { 142 p0++ 143 } 144 145 if pkg == "main" && name != "main" { 146 fmt.Fprintf(os.Stderr, "%s: %s: not package main (package %s)\n", os.Args[0], filename, name) 147 nerrors++ 148 Errorexit() 149 } 150 151 loadpkgdata(filename, pkg, data[p0:p1]) 152 } 153 154 // __.PKGDEF has no cgo section - those are in the C compiler-generated object files. 155 if whence == Pkgdef { 156 return 157 } 158 159 // look for cgo section 160 p0 = strings.Index(data[p1:], "\n$$ // cgo") 161 if p0 >= 0 { 162 p0 += p1 163 i := strings.IndexByte(data[p0+1:], '\n') 164 if i < 0 { 165 fmt.Fprintf(os.Stderr, "%s: found $$ // cgo but no newline in %s\n", os.Args[0], filename) 166 if Debug['u'] != 0 { 167 Errorexit() 168 } 169 return 170 } 171 p0 += 1 + i 172 173 p1 = strings.Index(data[p0:], "\n$$") 174 if p1 < 0 { 175 p1 = strings.Index(data[p0:], "\n!\n") 176 } 177 if p1 < 0 { 178 fmt.Fprintf(os.Stderr, "%s: cannot find end of // cgo section in %s\n", os.Args[0], filename) 179 if Debug['u'] != 0 { 180 Errorexit() 181 } 182 return 183 } 184 p1 += p0 185 186 loadcgo(filename, pkg, data[p0:p1]) 187 } 188 } 189 190 func loadpkgdata(file string, pkg string, data string) { 191 var prefix string 192 var name string 193 var def string 194 195 p := data 196 for parsepkgdata(file, pkg, &p, &prefix, &name, &def) > 0 { 197 x := lookupImport(name) 198 if x.prefix == "" { 199 x.prefix = prefix 200 x.def = def 201 x.file = file 202 } else if x.prefix != prefix { 203 fmt.Fprintf(os.Stderr, "%s: conflicting definitions for %s\n", os.Args[0], name) 204 fmt.Fprintf(os.Stderr, "%s:\t%s %s ...\n", x.file, x.prefix, name) 205 fmt.Fprintf(os.Stderr, "%s:\t%s %s ...\n", file, prefix, name) 206 nerrors++ 207 } else if x.def != def { 208 fmt.Fprintf(os.Stderr, "%s: conflicting definitions for %s\n", os.Args[0], name) 209 fmt.Fprintf(os.Stderr, "%s:\t%s %s %s\n", x.file, x.prefix, name, x.def) 210 fmt.Fprintf(os.Stderr, "%s:\t%s %s %s\n", file, prefix, name, def) 211 nerrors++ 212 } 213 } 214 } 215 216 func parsepkgdata(file string, pkg string, pp *string, prefixp *string, namep *string, defp *string) int { 217 // skip white space 218 p := *pp 219 220 loop: 221 for len(p) > 0 && (p[0] == ' ' || p[0] == '\t' || p[0] == '\n') { 222 p = p[1:] 223 } 224 if len(p) == 0 || strings.HasPrefix(p, "$$\n") { 225 return 0 226 } 227 228 // prefix: (var|type|func|const) 229 prefix := p 230 231 if len(p) < 7 { 232 return -1 233 } 234 if strings.HasPrefix(p, "var ") { 235 p = p[4:] 236 } else if strings.HasPrefix(p, "type ") { 237 p = p[5:] 238 } else if strings.HasPrefix(p, "func ") { 239 p = p[5:] 240 } else if strings.HasPrefix(p, "const ") { 241 p = p[6:] 242 } else if strings.HasPrefix(p, "import ") { 243 p = p[7:] 244 for len(p) > 0 && p[0] != ' ' { 245 p = p[1:] 246 } 247 p = p[1:] 248 line := p 249 for len(p) > 0 && p[0] != '\n' { 250 p = p[1:] 251 } 252 if len(p) == 0 { 253 fmt.Fprintf(os.Stderr, "%s: %s: confused in import line\n", os.Args[0], file) 254 nerrors++ 255 return -1 256 } 257 line = line[:len(line)-len(p)] 258 line = strings.TrimSuffix(line, " // indirect") 259 path, err := strconv.Unquote(line) 260 if err != nil { 261 fmt.Fprintf(os.Stderr, "%s: %s: confused in import path: %q\n", os.Args[0], file, line) 262 nerrors++ 263 return -1 264 } 265 p = p[1:] 266 imported(pkg, path) 267 goto loop 268 } else { 269 fmt.Fprintf(os.Stderr, "%s: %s: confused in pkg data near <<%.40s>>\n", os.Args[0], file, prefix) 270 nerrors++ 271 return -1 272 } 273 274 prefix = prefix[:len(prefix)-len(p)-1] 275 276 // name: a.b followed by space 277 name := p 278 279 inquote := false 280 for len(p) > 0 { 281 if p[0] == ' ' && !inquote { 282 break 283 } 284 285 if p[0] == '\\' { 286 p = p[1:] 287 } else if p[0] == '"' { 288 inquote = !inquote 289 } 290 291 p = p[1:] 292 } 293 294 if len(p) == 0 { 295 return -1 296 } 297 name = name[:len(name)-len(p)] 298 p = p[1:] 299 300 // def: free form to new line 301 def := p 302 303 for len(p) > 0 && p[0] != '\n' { 304 p = p[1:] 305 } 306 if len(p) == 0 { 307 return -1 308 } 309 def = def[:len(def)-len(p)] 310 var defbuf *bytes.Buffer 311 p = p[1:] 312 313 // include methods on successive lines in def of named type 314 var meth string 315 for parsemethod(&p, &meth) > 0 { 316 if defbuf == nil { 317 defbuf = new(bytes.Buffer) 318 defbuf.WriteString(def) 319 } 320 defbuf.WriteString("\n\t") 321 defbuf.WriteString(meth) 322 } 323 if defbuf != nil { 324 def = defbuf.String() 325 } 326 327 name = expandpkg(name, pkg) 328 def = expandpkg(def, pkg) 329 330 // done 331 *pp = p 332 333 *prefixp = prefix 334 *namep = name 335 *defp = def 336 return 1 337 } 338 339 func parsemethod(pp *string, methp *string) int { 340 // skip white space 341 p := *pp 342 343 for len(p) > 0 && (p[0] == ' ' || p[0] == '\t') { 344 p = p[1:] 345 } 346 if len(p) == 0 { 347 return 0 348 } 349 350 // might be a comment about the method 351 if strings.HasPrefix(p, "//") { 352 goto useline 353 } 354 355 // if it says "func (", it's a method 356 if strings.HasPrefix(p, "func (") { 357 goto useline 358 } 359 return 0 360 361 // definition to end of line 362 useline: 363 *methp = p 364 365 for len(p) > 0 && p[0] != '\n' { 366 p = p[1:] 367 } 368 if len(p) == 0 { 369 fmt.Fprintf(os.Stderr, "%s: lost end of line in method definition\n", os.Args[0]) 370 *pp = "" 371 return -1 372 } 373 374 *methp = (*methp)[:len(*methp)-len(p)] 375 *pp = p[1:] 376 return 1 377 } 378 379 func loadcgo(file string, pkg string, p string) { 380 var next string 381 var q string 382 var f []string 383 var local string 384 var remote string 385 var lib string 386 var s *LSym 387 388 p0 := "" 389 for ; p != ""; p = next { 390 if i := strings.Index(p, "\n"); i >= 0 { 391 p, next = p[:i], p[i+1:] 392 } else { 393 next = "" 394 } 395 396 p0 = p // save for error message 397 f = tokenize(p) 398 if len(f) == 0 { 399 continue 400 } 401 402 if f[0] == "cgo_import_dynamic" { 403 if len(f) < 2 || len(f) > 4 { 404 goto err 405 } 406 407 local = f[1] 408 remote = local 409 if len(f) > 2 { 410 remote = f[2] 411 } 412 lib = "" 413 if len(f) > 3 { 414 lib = f[3] 415 } 416 417 if Debug['d'] != 0 { 418 fmt.Fprintf(os.Stderr, "%s: %s: cannot use dynamic imports with -d flag\n", os.Args[0], file) 419 nerrors++ 420 return 421 } 422 423 if local == "_" && remote == "_" { 424 // allow #pragma dynimport _ _ "foo.so" 425 // to force a link of foo.so. 426 havedynamic = 1 427 428 Thearch.Adddynlib(lib) 429 continue 430 } 431 432 local = expandpkg(local, pkg) 433 q = "" 434 if i := strings.Index(remote, "#"); i >= 0 { 435 remote, q = remote[:i], remote[i+1:] 436 } 437 s = Linklookup(Ctxt, local, 0) 438 if local != f[1] { 439 } 440 if s.Type == 0 || s.Type == SXREF || s.Type == SHOSTOBJ { 441 s.Dynimplib = lib 442 s.Extname = remote 443 s.Dynimpvers = q 444 if s.Type != SHOSTOBJ { 445 s.Type = SDYNIMPORT 446 } 447 havedynamic = 1 448 } 449 450 continue 451 } 452 453 if f[0] == "cgo_import_static" { 454 if len(f) != 2 { 455 goto err 456 } 457 local = f[1] 458 s = Linklookup(Ctxt, local, 0) 459 s.Type = SHOSTOBJ 460 s.Size = 0 461 continue 462 } 463 464 if f[0] == "cgo_export_static" || f[0] == "cgo_export_dynamic" { 465 if len(f) < 2 || len(f) > 3 { 466 goto err 467 } 468 local = f[1] 469 if len(f) > 2 { 470 remote = f[2] 471 } else { 472 remote = local 473 } 474 local = expandpkg(local, pkg) 475 s = Linklookup(Ctxt, local, 0) 476 477 switch Buildmode { 478 case BuildmodeCShared, BuildmodeCArchive: 479 if s == Linklookup(Ctxt, "main", 0) { 480 continue 481 } 482 } 483 484 // export overrides import, for openbsd/cgo. 485 // see issue 4878. 486 if s.Dynimplib != "" { 487 s.Dynimplib = "" 488 s.Extname = "" 489 s.Dynimpvers = "" 490 s.Type = 0 491 } 492 493 if s.Cgoexport == 0 { 494 s.Extname = remote 495 dynexp = append(dynexp, s) 496 } else if s.Extname != remote { 497 fmt.Fprintf(os.Stderr, "%s: conflicting cgo_export directives: %s as %s and %s\n", os.Args[0], s.Name, s.Extname, remote) 498 nerrors++ 499 return 500 } 501 502 if f[0] == "cgo_export_static" { 503 s.Cgoexport |= CgoExportStatic 504 } else { 505 s.Cgoexport |= CgoExportDynamic 506 } 507 if local != f[1] { 508 } 509 continue 510 } 511 512 if f[0] == "cgo_dynamic_linker" { 513 if len(f) != 2 { 514 goto err 515 } 516 517 if Debug['I'] == 0 { 518 if interpreter != "" && interpreter != f[1] { 519 fmt.Fprintf(os.Stderr, "%s: conflict dynlinker: %s and %s\n", os.Args[0], interpreter, f[1]) 520 nerrors++ 521 return 522 } 523 524 interpreter = f[1] 525 } 526 527 continue 528 } 529 530 if f[0] == "cgo_ldflag" { 531 if len(f) != 2 { 532 goto err 533 } 534 ldflag = append(ldflag, f[1]) 535 continue 536 } 537 } 538 539 return 540 541 err: 542 fmt.Fprintf(os.Stderr, "%s: %s: invalid dynimport line: %s\n", os.Args[0], file, p0) 543 nerrors++ 544 } 545 546 var markq *LSym 547 548 var emarkq *LSym 549 550 func mark1(s *LSym, parent *LSym) { 551 if s == nil || s.Reachable { 552 return 553 } 554 if strings.HasPrefix(s.Name, "go.weak.") { 555 return 556 } 557 s.Reachable = true 558 s.Reachparent = parent 559 if markq == nil { 560 markq = s 561 } else { 562 emarkq.Queue = s 563 } 564 emarkq = s 565 } 566 567 func mark(s *LSym) { 568 mark1(s, nil) 569 } 570 571 func markflood() { 572 var a *Auto 573 var i int 574 575 for s := markq; s != nil; s = s.Queue { 576 if s.Type == STEXT { 577 if Debug['v'] > 1 { 578 fmt.Fprintf(&Bso, "marktext %s\n", s.Name) 579 } 580 for a = s.Autom; a != nil; a = a.Link { 581 mark1(a.Gotype, s) 582 } 583 } 584 585 for i = 0; i < len(s.R); i++ { 586 mark1(s.R[i].Sym, s) 587 } 588 if s.Pcln != nil { 589 for i = 0; i < s.Pcln.Nfuncdata; i++ { 590 mark1(s.Pcln.Funcdata[i], s) 591 } 592 } 593 594 mark1(s.Gotype, s) 595 mark1(s.Sub, s) 596 mark1(s.Outer, s) 597 } 598 } 599 600 var markextra = []string{ 601 "runtime.morestack", 602 "runtime.morestackx", 603 "runtime.morestack00", 604 "runtime.morestack10", 605 "runtime.morestack01", 606 "runtime.morestack11", 607 "runtime.morestack8", 608 "runtime.morestack16", 609 "runtime.morestack24", 610 "runtime.morestack32", 611 "runtime.morestack40", 612 "runtime.morestack48", 613 // on arm, lock in the div/mod helpers too 614 "_div", 615 "_divu", 616 "_mod", 617 "_modu", 618 } 619 620 func deadcode() { 621 if Debug['v'] != 0 { 622 fmt.Fprintf(&Bso, "%5.2f deadcode\n", obj.Cputime()) 623 } 624 625 if Buildmode == BuildmodeShared || Buildmode == BuildmodeCArchive { 626 // Mark all symbols as reachable when building a 627 // shared library. 628 for s := Ctxt.Allsym; s != nil; s = s.Allsym { 629 if s.Type != 0 { 630 mark(s) 631 } 632 } 633 mark(Linkrlookup(Ctxt, "main.main", 0)) 634 mark(Linkrlookup(Ctxt, "main.init", 0)) 635 } else { 636 mark(Linklookup(Ctxt, INITENTRY, 0)) 637 if Linkshared && Buildmode == BuildmodeExe { 638 mark(Linkrlookup(Ctxt, "main.main", 0)) 639 mark(Linkrlookup(Ctxt, "main.init", 0)) 640 } 641 for i := 0; i < len(markextra); i++ { 642 mark(Linklookup(Ctxt, markextra[i], 0)) 643 } 644 645 for i := 0; i < len(dynexp); i++ { 646 mark(dynexp[i]) 647 } 648 markflood() 649 650 // keep each beginning with 'typelink.' if the symbol it points at is being kept. 651 for s := Ctxt.Allsym; s != nil; s = s.Allsym { 652 if strings.HasPrefix(s.Name, "go.typelink.") { 653 s.Reachable = len(s.R) == 1 && s.R[0].Sym.Reachable 654 } 655 } 656 657 // remove dead text but keep file information (z symbols). 658 var last *LSym 659 660 for s := Ctxt.Textp; s != nil; s = s.Next { 661 if !s.Reachable { 662 continue 663 } 664 665 // NOTE: Removing s from old textp and adding to new, shorter textp. 666 if last == nil { 667 Ctxt.Textp = s 668 } else { 669 last.Next = s 670 } 671 last = s 672 } 673 674 if last == nil { 675 Ctxt.Textp = nil 676 Ctxt.Etextp = nil 677 } else { 678 last.Next = nil 679 Ctxt.Etextp = last 680 } 681 } 682 683 for s := Ctxt.Allsym; s != nil; s = s.Allsym { 684 if strings.HasPrefix(s.Name, "go.weak.") { 685 s.Special = 1 // do not lay out in data segment 686 s.Reachable = true 687 s.Hide = 1 688 } 689 } 690 691 // record field tracking references 692 var buf bytes.Buffer 693 var p *LSym 694 for s := Ctxt.Allsym; s != nil; s = s.Allsym { 695 if strings.HasPrefix(s.Name, "go.track.") { 696 s.Special = 1 // do not lay out in data segment 697 s.Hide = 1 698 if s.Reachable { 699 buf.WriteString(s.Name[9:]) 700 for p = s.Reachparent; p != nil; p = p.Reachparent { 701 buf.WriteString("\t") 702 buf.WriteString(p.Name) 703 } 704 buf.WriteString("\n") 705 } 706 707 s.Type = SCONST 708 s.Value = 0 709 } 710 } 711 712 if tracksym == "" { 713 return 714 } 715 s := Linklookup(Ctxt, tracksym, 0) 716 if !s.Reachable { 717 return 718 } 719 addstrdata(tracksym, buf.String()) 720 } 721 722 func doweak() { 723 var t *LSym 724 725 // resolve weak references only if 726 // target symbol will be in binary anyway. 727 for s := Ctxt.Allsym; s != nil; s = s.Allsym { 728 if strings.HasPrefix(s.Name, "go.weak.") { 729 t = Linkrlookup(Ctxt, s.Name[8:], int(s.Version)) 730 if t != nil && t.Type != 0 && t.Reachable { 731 s.Value = t.Value 732 s.Type = t.Type 733 s.Outer = t 734 } else { 735 s.Type = SCONST 736 s.Value = 0 737 } 738 739 continue 740 } 741 } 742 } 743 744 func addexport() { 745 if HEADTYPE == Hdarwin { 746 return 747 } 748 749 for i := 0; i < len(dynexp); i++ { 750 Thearch.Adddynsym(Ctxt, dynexp[i]) 751 } 752 } 753 754 type Pkg struct { 755 mark bool 756 checked bool 757 path string 758 impby []*Pkg 759 } 760 761 var ( 762 // pkgmap records the imported-by relationship between packages. 763 // Entries are keyed by package path (e.g., "runtime" or "net/url"). 764 pkgmap = map[string]*Pkg{} 765 766 pkgall []*Pkg 767 ) 768 769 func lookupPkg(path string) *Pkg { 770 if p, ok := pkgmap[path]; ok { 771 return p 772 } 773 p := &Pkg{path: path} 774 pkgmap[path] = p 775 pkgall = append(pkgall, p) 776 return p 777 } 778 779 // imported records that package pkg imports package imp. 780 func imported(pkg, imp string) { 781 // everyone imports runtime, even runtime. 782 if imp == "runtime" { 783 return 784 } 785 786 p := lookupPkg(pkg) 787 i := lookupPkg(imp) 788 i.impby = append(i.impby, p) 789 } 790 791 func (p *Pkg) cycle() *Pkg { 792 if p.checked { 793 return nil 794 } 795 796 if p.mark { 797 nerrors++ 798 fmt.Printf("import cycle:\n") 799 fmt.Printf("\t%s\n", p.path) 800 return p 801 } 802 803 p.mark = true 804 for _, q := range p.impby { 805 if bad := q.cycle(); bad != nil { 806 p.mark = false 807 p.checked = true 808 fmt.Printf("\timports %s\n", p.path) 809 if bad == p { 810 return nil 811 } 812 return bad 813 } 814 } 815 816 p.checked = true 817 p.mark = false 818 return nil 819 } 820 821 func importcycles() { 822 for _, p := range pkgall { 823 p.cycle() 824 } 825 } 826 827 func setlinkmode(arg string) { 828 if arg == "internal" { 829 Linkmode = LinkInternal 830 } else if arg == "external" { 831 Linkmode = LinkExternal 832 } else if arg == "auto" { 833 Linkmode = LinkAuto 834 } else { 835 fmt.Fprintf(os.Stderr, "unknown link mode -linkmode %s\n", arg) 836 Errorexit() 837 } 838 }