github.com/aloncn/graphics-go@v0.0.1/src/cmd/link/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 // 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 "strings" 15 ) 16 17 // go-specific code shared across loaders (5l, 6l, 8l). 18 19 // replace all "". with pkg. 20 func expandpkg(t0 string, pkg string) string { 21 return strings.Replace(t0, `"".`, pkg+".", -1) 22 } 23 24 // TODO: 25 // generate debugging section in binary. 26 // once the dust settles, try to move some code to 27 // libmach, so that other linkers and ar can share. 28 29 func ldpkg(f *obj.Biobuf, pkg string, length int64, filename string, whence int) { 30 var p0, p1 int 31 32 if Debug['g'] != 0 { 33 return 34 } 35 36 if int64(int(length)) != length { 37 fmt.Fprintf(os.Stderr, "%s: too much pkg data in %s\n", os.Args[0], filename) 38 if Debug['u'] != 0 { 39 errorexit() 40 } 41 return 42 } 43 44 // In a __.PKGDEF, we only care about the package name. 45 // Don't read all the export data. 46 if length > 1000 && whence == Pkgdef { 47 length = 1000 48 } 49 50 bdata := make([]byte, length) 51 if int64(obj.Bread(f, bdata)) != length { 52 fmt.Fprintf(os.Stderr, "%s: short pkg read %s\n", os.Args[0], filename) 53 if Debug['u'] != 0 { 54 errorexit() 55 } 56 return 57 } 58 data := string(bdata) 59 60 // first \n$$ marks beginning of exports - skip rest of line 61 p0 = strings.Index(data, "\n$$") 62 if p0 < 0 { 63 if Debug['u'] != 0 && whence != ArchiveObj { 64 Exitf("cannot find export data in %s", filename) 65 } 66 return 67 } 68 69 // \n$$B marks the beginning of binary export data - don't skip over the B 70 p0 += 3 71 for p0 < len(data) && data[p0] != '\n' && data[p0] != 'B' { 72 p0++ 73 } 74 75 // second marks end of exports / beginning of local data 76 p1 = strings.Index(data[p0:], "\n$$\n") 77 if p1 < 0 && whence == Pkgdef { 78 p1 = len(data) - p0 79 } 80 if p1 < 0 { 81 fmt.Fprintf(os.Stderr, "%s: cannot find end of exports in %s\n", os.Args[0], filename) 82 if Debug['u'] != 0 { 83 errorexit() 84 } 85 return 86 } 87 p1 += p0 88 89 for p0 < p1 && data[p0] != 'B' && (data[p0] == ' ' || data[p0] == '\t' || data[p0] == '\n') { 90 p0++ 91 } 92 // don't check this section if we have binary (B) export data 93 // TODO fix this eventually 94 if p0 < p1 && data[p0] != 'B' { 95 if !strings.HasPrefix(data[p0:], "package ") { 96 fmt.Fprintf(os.Stderr, "%s: bad package section in %s - %.20s\n", os.Args[0], filename, data[p0:]) 97 if Debug['u'] != 0 { 98 errorexit() 99 } 100 return 101 } 102 103 p0 += 8 104 for p0 < p1 && (data[p0] == ' ' || data[p0] == '\t' || data[p0] == '\n') { 105 p0++ 106 } 107 pname := p0 108 for p0 < p1 && data[p0] != ' ' && data[p0] != '\t' && data[p0] != '\n' { 109 p0++ 110 } 111 if Debug['u'] != 0 && whence != ArchiveObj && (p0+6 > p1 || !strings.HasPrefix(data[p0:], " safe\n")) { 112 Exitf("load of unsafe package %s", filename) 113 } 114 115 name := data[pname:p0] 116 for p0 < p1 && data[p0] != '\n' { 117 p0++ 118 } 119 if p0 < p1 { 120 p0++ 121 } 122 123 if pkg == "main" && name != "main" { 124 Exitf("%s: not package main (package %s)", filename, name) 125 } 126 } 127 128 // __.PKGDEF has no cgo section - those are in the C compiler-generated object files. 129 if whence == Pkgdef { 130 return 131 } 132 133 // look for cgo section 134 p0 = strings.Index(data[p1:], "\n$$ // cgo") 135 if p0 >= 0 { 136 p0 += p1 137 i := strings.IndexByte(data[p0+1:], '\n') 138 if i < 0 { 139 fmt.Fprintf(os.Stderr, "%s: found $$ // cgo but no newline in %s\n", os.Args[0], filename) 140 if Debug['u'] != 0 { 141 errorexit() 142 } 143 return 144 } 145 p0 += 1 + i 146 147 p1 = strings.Index(data[p0:], "\n$$") 148 if p1 < 0 { 149 p1 = strings.Index(data[p0:], "\n!\n") 150 } 151 if p1 < 0 { 152 fmt.Fprintf(os.Stderr, "%s: cannot find end of // cgo section in %s\n", os.Args[0], filename) 153 if Debug['u'] != 0 { 154 errorexit() 155 } 156 return 157 } 158 p1 += p0 159 160 loadcgo(filename, pkg, data[p0:p1]) 161 } 162 } 163 164 func loadcgo(file string, pkg string, p string) { 165 var next string 166 var q string 167 var f []string 168 var local string 169 var remote string 170 var lib string 171 var s *LSym 172 173 p0 := "" 174 for ; p != ""; p = next { 175 if i := strings.Index(p, "\n"); i >= 0 { 176 p, next = p[:i], p[i+1:] 177 } else { 178 next = "" 179 } 180 181 p0 = p // save for error message 182 f = tokenize(p) 183 if len(f) == 0 { 184 continue 185 } 186 187 if f[0] == "cgo_import_dynamic" { 188 if len(f) < 2 || len(f) > 4 { 189 goto err 190 } 191 192 local = f[1] 193 remote = local 194 if len(f) > 2 { 195 remote = f[2] 196 } 197 lib = "" 198 if len(f) > 3 { 199 lib = f[3] 200 } 201 202 if Debug['d'] != 0 { 203 fmt.Fprintf(os.Stderr, "%s: %s: cannot use dynamic imports with -d flag\n", os.Args[0], file) 204 nerrors++ 205 return 206 } 207 208 if local == "_" && remote == "_" { 209 // allow #pragma dynimport _ _ "foo.so" 210 // to force a link of foo.so. 211 havedynamic = 1 212 213 if HEADTYPE == obj.Hdarwin { 214 Machoadddynlib(lib) 215 } else { 216 dynlib = append(dynlib, lib) 217 } 218 continue 219 } 220 221 local = expandpkg(local, pkg) 222 q = "" 223 if i := strings.Index(remote, "#"); i >= 0 { 224 remote, q = remote[:i], remote[i+1:] 225 } 226 s = Linklookup(Ctxt, local, 0) 227 if local != f[1] { 228 } 229 if s.Type == 0 || s.Type == obj.SXREF || s.Type == obj.SHOSTOBJ { 230 s.Dynimplib = lib 231 s.Extname = remote 232 s.Dynimpvers = q 233 if s.Type != obj.SHOSTOBJ { 234 s.Type = obj.SDYNIMPORT 235 } 236 havedynamic = 1 237 } 238 239 continue 240 } 241 242 if f[0] == "cgo_import_static" { 243 if len(f) != 2 { 244 goto err 245 } 246 local = f[1] 247 s = Linklookup(Ctxt, local, 0) 248 s.Type = obj.SHOSTOBJ 249 s.Size = 0 250 continue 251 } 252 253 if f[0] == "cgo_export_static" || f[0] == "cgo_export_dynamic" { 254 if len(f) < 2 || len(f) > 3 { 255 goto err 256 } 257 local = f[1] 258 if len(f) > 2 { 259 remote = f[2] 260 } else { 261 remote = local 262 } 263 local = expandpkg(local, pkg) 264 s = Linklookup(Ctxt, local, 0) 265 266 switch Buildmode { 267 case BuildmodeCShared, BuildmodeCArchive: 268 if s == Linklookup(Ctxt, "main", 0) { 269 continue 270 } 271 } 272 273 // export overrides import, for openbsd/cgo. 274 // see issue 4878. 275 if s.Dynimplib != "" { 276 s.Dynimplib = "" 277 s.Extname = "" 278 s.Dynimpvers = "" 279 s.Type = 0 280 } 281 282 if s.Cgoexport == 0 { 283 s.Extname = remote 284 dynexp = append(dynexp, s) 285 } else if s.Extname != remote { 286 fmt.Fprintf(os.Stderr, "%s: conflicting cgo_export directives: %s as %s and %s\n", os.Args[0], s.Name, s.Extname, remote) 287 nerrors++ 288 return 289 } 290 291 if f[0] == "cgo_export_static" { 292 s.Cgoexport |= CgoExportStatic 293 } else { 294 s.Cgoexport |= CgoExportDynamic 295 } 296 if local != f[1] { 297 } 298 continue 299 } 300 301 if f[0] == "cgo_dynamic_linker" { 302 if len(f) != 2 { 303 goto err 304 } 305 306 if Debug['I'] == 0 { 307 if interpreter != "" && interpreter != f[1] { 308 fmt.Fprintf(os.Stderr, "%s: conflict dynlinker: %s and %s\n", os.Args[0], interpreter, f[1]) 309 nerrors++ 310 return 311 } 312 313 interpreter = f[1] 314 } 315 316 continue 317 } 318 319 if f[0] == "cgo_ldflag" { 320 if len(f) != 2 { 321 goto err 322 } 323 ldflag = append(ldflag, f[1]) 324 continue 325 } 326 } 327 328 return 329 330 err: 331 fmt.Fprintf(os.Stderr, "%s: %s: invalid dynimport line: %s\n", os.Args[0], file, p0) 332 nerrors++ 333 } 334 335 var seenlib = make(map[string]bool) 336 337 func adddynlib(lib string) { 338 if seenlib[lib] || Linkmode == LinkExternal { 339 return 340 } 341 seenlib[lib] = true 342 343 if Iself { 344 s := Linklookup(Ctxt, ".dynstr", 0) 345 if s.Size == 0 { 346 Addstring(s, "") 347 } 348 Elfwritedynent(Linklookup(Ctxt, ".dynamic", 0), DT_NEEDED, uint64(Addstring(s, lib))) 349 } else { 350 Diag("adddynlib: unsupported binary format") 351 } 352 } 353 354 func Adddynsym(ctxt *Link, s *LSym) { 355 if s.Dynid >= 0 || Linkmode == LinkExternal { 356 return 357 } 358 359 if Iself { 360 Elfadddynsym(ctxt, s) 361 } else if HEADTYPE == obj.Hdarwin { 362 Diag("adddynsym: missed symbol %s (%s)", s.Name, s.Extname) 363 } else if HEADTYPE == obj.Hwindows { 364 // already taken care of 365 } else { 366 Diag("adddynsym: unsupported binary format") 367 } 368 } 369 370 var markq *LSym 371 372 var emarkq *LSym 373 374 func mark1(s *LSym, parent *LSym) { 375 if s == nil || s.Reachable { 376 return 377 } 378 if strings.HasPrefix(s.Name, "go.weak.") { 379 return 380 } 381 s.Reachable = true 382 s.Reachparent = parent 383 if markq == nil { 384 markq = s 385 } else { 386 emarkq.Queue = s 387 } 388 emarkq = s 389 } 390 391 func mark(s *LSym) { 392 mark1(s, nil) 393 } 394 395 func markflood() { 396 var a *Auto 397 var i int 398 399 for s := markq; s != nil; s = s.Queue { 400 if s.Type == obj.STEXT { 401 if Debug['v'] > 1 { 402 fmt.Fprintf(&Bso, "marktext %s\n", s.Name) 403 } 404 for a = s.Autom; a != nil; a = a.Link { 405 mark1(a.Gotype, s) 406 } 407 } 408 409 for i = 0; i < len(s.R); i++ { 410 mark1(s.R[i].Sym, s) 411 } 412 if s.Pcln != nil { 413 for i = 0; i < s.Pcln.Nfuncdata; i++ { 414 mark1(s.Pcln.Funcdata[i], s) 415 } 416 } 417 418 mark1(s.Gotype, s) 419 mark1(s.Sub, s) 420 mark1(s.Outer, s) 421 } 422 } 423 424 var markextra = []string{ 425 "runtime.morestack", 426 "runtime.morestackx", 427 "runtime.morestack00", 428 "runtime.morestack10", 429 "runtime.morestack01", 430 "runtime.morestack11", 431 "runtime.morestack8", 432 "runtime.morestack16", 433 "runtime.morestack24", 434 "runtime.morestack32", 435 "runtime.morestack40", 436 "runtime.morestack48", 437 // on arm, lock in the div/mod helpers too 438 "_div", 439 "_divu", 440 "_mod", 441 "_modu", 442 } 443 444 func deadcode() { 445 if Debug['v'] != 0 { 446 fmt.Fprintf(&Bso, "%5.2f deadcode\n", obj.Cputime()) 447 } 448 449 if Buildmode == BuildmodeShared { 450 // Mark all symbols defined in this library as reachable when 451 // building a shared library. 452 for s := Ctxt.Allsym; s != nil; s = s.Allsym { 453 if s.Type != 0 && s.Type != obj.SDYNIMPORT { 454 mark(s) 455 } 456 } 457 markflood() 458 } else { 459 mark(Linklookup(Ctxt, INITENTRY, 0)) 460 if Linkshared && Buildmode == BuildmodeExe { 461 mark(Linkrlookup(Ctxt, "main.main", 0)) 462 mark(Linkrlookup(Ctxt, "main.init", 0)) 463 } 464 for i := 0; i < len(markextra); i++ { 465 mark(Linklookup(Ctxt, markextra[i], 0)) 466 } 467 468 for i := 0; i < len(dynexp); i++ { 469 mark(dynexp[i]) 470 } 471 markflood() 472 473 // keep each beginning with 'typelink.' if the symbol it points at is being kept. 474 for s := Ctxt.Allsym; s != nil; s = s.Allsym { 475 if strings.HasPrefix(s.Name, "go.typelink.") { 476 s.Reachable = len(s.R) == 1 && s.R[0].Sym.Reachable 477 } 478 } 479 480 // remove dead text but keep file information (z symbols). 481 var last *LSym 482 483 for s := Ctxt.Textp; s != nil; s = s.Next { 484 if !s.Reachable { 485 continue 486 } 487 488 // NOTE: Removing s from old textp and adding to new, shorter textp. 489 if last == nil { 490 Ctxt.Textp = s 491 } else { 492 last.Next = s 493 } 494 last = s 495 } 496 497 if last == nil { 498 Ctxt.Textp = nil 499 Ctxt.Etextp = nil 500 } else { 501 last.Next = nil 502 Ctxt.Etextp = last 503 } 504 } 505 506 for s := Ctxt.Allsym; s != nil; s = s.Allsym { 507 if strings.HasPrefix(s.Name, "go.weak.") { 508 s.Special = 1 // do not lay out in data segment 509 s.Reachable = true 510 s.Hide = 1 511 } 512 } 513 514 // record field tracking references 515 var buf bytes.Buffer 516 var p *LSym 517 for s := Ctxt.Allsym; s != nil; s = s.Allsym { 518 if strings.HasPrefix(s.Name, "go.track.") { 519 s.Special = 1 // do not lay out in data segment 520 s.Hide = 1 521 if s.Reachable { 522 buf.WriteString(s.Name[9:]) 523 for p = s.Reachparent; p != nil; p = p.Reachparent { 524 buf.WriteString("\t") 525 buf.WriteString(p.Name) 526 } 527 buf.WriteString("\n") 528 } 529 530 s.Type = obj.SCONST 531 s.Value = 0 532 } 533 } 534 535 if tracksym == "" { 536 return 537 } 538 s := Linklookup(Ctxt, tracksym, 0) 539 if !s.Reachable { 540 return 541 } 542 addstrdata(tracksym, buf.String()) 543 } 544 545 func doweak() { 546 var t *LSym 547 548 // resolve weak references only if 549 // target symbol will be in binary anyway. 550 for s := Ctxt.Allsym; s != nil; s = s.Allsym { 551 if strings.HasPrefix(s.Name, "go.weak.") { 552 t = Linkrlookup(Ctxt, s.Name[8:], int(s.Version)) 553 if t != nil && t.Type != 0 && t.Reachable { 554 s.Value = t.Value 555 s.Type = t.Type 556 s.Outer = t 557 } else { 558 s.Type = obj.SCONST 559 s.Value = 0 560 } 561 562 continue 563 } 564 } 565 } 566 567 func addexport() { 568 if HEADTYPE == obj.Hdarwin { 569 return 570 } 571 572 for _, exp := range dynexp { 573 Adddynsym(Ctxt, exp) 574 } 575 for _, lib := range dynlib { 576 adddynlib(lib) 577 } 578 } 579 580 type Pkg struct { 581 mark bool 582 checked bool 583 path string 584 impby []*Pkg 585 } 586 587 var ( 588 // pkgmap records the imported-by relationship between packages. 589 // Entries are keyed by package path (e.g., "runtime" or "net/url"). 590 pkgmap = map[string]*Pkg{} 591 592 pkgall []*Pkg 593 ) 594 595 func lookupPkg(path string) *Pkg { 596 if p, ok := pkgmap[path]; ok { 597 return p 598 } 599 p := &Pkg{path: path} 600 pkgmap[path] = p 601 pkgall = append(pkgall, p) 602 return p 603 } 604 605 // imported records that package pkg imports package imp. 606 func imported(pkg, imp string) { 607 // everyone imports runtime, even runtime. 608 if imp == "runtime" { 609 return 610 } 611 612 p := lookupPkg(pkg) 613 i := lookupPkg(imp) 614 i.impby = append(i.impby, p) 615 } 616 617 func (p *Pkg) cycle() *Pkg { 618 if p.checked { 619 return nil 620 } 621 622 if p.mark { 623 nerrors++ 624 fmt.Printf("import cycle:\n") 625 fmt.Printf("\t%s\n", p.path) 626 return p 627 } 628 629 p.mark = true 630 for _, q := range p.impby { 631 if bad := q.cycle(); bad != nil { 632 p.mark = false 633 p.checked = true 634 fmt.Printf("\timports %s\n", p.path) 635 if bad == p { 636 return nil 637 } 638 return bad 639 } 640 } 641 642 p.checked = true 643 p.mark = false 644 return nil 645 } 646 647 func importcycles() { 648 for _, p := range pkgall { 649 p.cycle() 650 } 651 } 652 653 func setlinkmode(arg string) { 654 if arg == "internal" { 655 Linkmode = LinkInternal 656 } else if arg == "external" { 657 Linkmode = LinkExternal 658 } else if arg == "auto" { 659 Linkmode = LinkAuto 660 } else { 661 Exitf("unknown link mode -linkmode %s", arg) 662 } 663 }