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