github.com/bir3/gocompiler@v0.3.205/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 "github.com/bir3/gocompiler/src/cmd/internal/bio" 11 "github.com/bir3/gocompiler/src/cmd/internal/obj" 12 "github.com/bir3/gocompiler/src/cmd/internal/objabi" 13 "github.com/bir3/gocompiler/src/cmd/internal/sys" 14 "github.com/bir3/gocompiler/src/cmd/link/internal/loader" 15 "github.com/bir3/gocompiler/src/cmd/link/internal/sym" 16 "debug/elf" 17 "encoding/json" 18 "fmt" 19 "io" 20 "os" 21 "sort" 22 "strconv" 23 "strings" 24 ) 25 26 // go-specific code shared across loaders (5l, 6l, 8l). 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 func ldpkg(ctxt *Link, f *bio.Reader, lib *sym.Library, length int64, filename string) { 34 if *flagG { 35 return 36 } 37 38 if int64(int(length)) != length { 39 fmt.Fprintf(os.Stderr, "%s: too much pkg data in %s\n", os.Args[0], filename) 40 return 41 } 42 43 bdata := make([]byte, length) 44 if _, err := io.ReadFull(f, bdata); err != nil { 45 fmt.Fprintf(os.Stderr, "%s: short pkg read %s\n", os.Args[0], filename) 46 return 47 } 48 data := string(bdata) 49 50 // process header lines 51 for data != "" { 52 var line string 53 if i := strings.Index(data, "\n"); i >= 0 { 54 line, data = data[:i], data[i+1:] 55 } else { 56 line, data = data, "" 57 } 58 if line == "main" { 59 lib.Main = true 60 } 61 if line == "" { 62 break 63 } 64 } 65 66 // look for cgo section 67 p0 := strings.Index(data, "\n$$ // cgo") 68 var p1 int 69 if p0 >= 0 { 70 p0 += p1 71 i := strings.IndexByte(data[p0+1:], '\n') 72 if i < 0 { 73 fmt.Fprintf(os.Stderr, "%s: found $$ // cgo but no newline in %s\n", os.Args[0], filename) 74 return 75 } 76 p0 += 1 + i 77 78 p1 = strings.Index(data[p0:], "\n$$") 79 if p1 < 0 { 80 p1 = strings.Index(data[p0:], "\n!\n") 81 } 82 if p1 < 0 { 83 fmt.Fprintf(os.Stderr, "%s: cannot find end of // cgo section in %s\n", os.Args[0], filename) 84 return 85 } 86 p1 += p0 87 loadcgo(ctxt, filename, objabi.PathToPrefix(lib.Pkg), data[p0:p1]) 88 } 89 } 90 91 func loadcgo(ctxt *Link, file string, pkg string, p string) { 92 var directives [][]string 93 if err := json.NewDecoder(strings.NewReader(p)).Decode(&directives); err != nil { 94 fmt.Fprintf(os.Stderr, "%s: %s: failed decoding cgo directives: %v\n", os.Args[0], file, err) 95 nerrors++ 96 return 97 } 98 99 // Record the directives. We'll process them later after Symbols are created. 100 ctxt.cgodata = append(ctxt.cgodata, cgodata{file, pkg, directives}) 101 } 102 103 // Set symbol attributes or flags based on cgo directives. 104 // Any newly discovered HOSTOBJ syms are added to 'hostObjSyms'. 105 func setCgoAttr(ctxt *Link, file string, pkg string, directives [][]string, hostObjSyms map[loader.Sym]struct{}) { 106 l := ctxt.loader 107 for _, f := range directives { 108 switch f[0] { 109 case "cgo_import_dynamic": 110 if len(f) < 2 || len(f) > 4 { 111 break 112 } 113 114 local := f[1] 115 remote := local 116 if len(f) > 2 { 117 remote = f[2] 118 } 119 lib := "" 120 if len(f) > 3 { 121 lib = f[3] 122 } 123 124 if *FlagD { 125 fmt.Fprintf(os.Stderr, "%s: %s: cannot use dynamic imports with -d flag\n", os.Args[0], file) 126 nerrors++ 127 return 128 } 129 130 if local == "_" && remote == "_" { 131 // allow #pragma dynimport _ _ "foo.so" 132 // to force a link of foo.so. 133 havedynamic = 1 134 135 if ctxt.HeadType == objabi.Hdarwin { 136 machoadddynlib(lib, ctxt.LinkMode) 137 } else { 138 dynlib = append(dynlib, lib) 139 } 140 continue 141 } 142 143 q := "" 144 if i := strings.Index(remote, "#"); i >= 0 { 145 remote, q = remote[:i], remote[i+1:] 146 } 147 s := l.LookupOrCreateSym(local, 0) 148 st := l.SymType(s) 149 if st == 0 || st == sym.SXREF || st == sym.SBSS || st == sym.SNOPTRBSS || st == sym.SHOSTOBJ { 150 l.SetSymDynimplib(s, lib) 151 l.SetSymExtname(s, remote) 152 l.SetSymDynimpvers(s, q) 153 if st != sym.SHOSTOBJ { 154 su := l.MakeSymbolUpdater(s) 155 su.SetType(sym.SDYNIMPORT) 156 } else { 157 hostObjSyms[s] = struct{}{} 158 } 159 havedynamic = 1 160 if lib != "" && ctxt.IsDarwin() { 161 machoadddynlib(lib, ctxt.LinkMode) 162 } 163 } 164 165 continue 166 167 case "cgo_import_static": 168 if len(f) != 2 { 169 break 170 } 171 local := f[1] 172 173 s := l.LookupOrCreateSym(local, 0) 174 su := l.MakeSymbolUpdater(s) 175 su.SetType(sym.SHOSTOBJ) 176 su.SetSize(0) 177 hostObjSyms[s] = struct{}{} 178 continue 179 180 case "cgo_export_static", "cgo_export_dynamic": 181 if len(f) < 2 || len(f) > 4 { 182 break 183 } 184 local := f[1] 185 remote := local 186 if len(f) > 2 { 187 remote = f[2] 188 } 189 // The compiler adds a fourth argument giving 190 // the definition ABI of function symbols. 191 abi := obj.ABI0 192 if len(f) > 3 { 193 var ok bool 194 abi, ok = obj.ParseABI(f[3]) 195 if !ok { 196 fmt.Fprintf(os.Stderr, "%s: bad ABI in cgo_export directive %s\n", os.Args[0], f) 197 nerrors++ 198 return 199 } 200 } 201 202 s := l.LookupOrCreateSym(local, sym.ABIToVersion(abi)) 203 204 if l.SymType(s) == sym.SHOSTOBJ { 205 hostObjSyms[s] = struct{}{} 206 } 207 208 switch ctxt.BuildMode { 209 case BuildModeCShared, BuildModeCArchive, BuildModePlugin: 210 if s == l.Lookup("main", 0) { 211 continue 212 } 213 } 214 215 // export overrides import, for openbsd/cgo. 216 // see issue 4878. 217 if l.SymDynimplib(s) != "" { 218 l.SetSymDynimplib(s, "") 219 l.SetSymDynimpvers(s, "") 220 l.SetSymExtname(s, "") 221 var su *loader.SymbolBuilder 222 su = l.MakeSymbolUpdater(s) 223 su.SetType(0) 224 } 225 226 if !(l.AttrCgoExportStatic(s) || l.AttrCgoExportDynamic(s)) { 227 l.SetSymExtname(s, remote) 228 } else if l.SymExtname(s) != remote { 229 fmt.Fprintf(os.Stderr, "%s: conflicting cgo_export directives: %s as %s and %s\n", os.Args[0], l.SymName(s), l.SymExtname(s), remote) 230 nerrors++ 231 return 232 } 233 234 // Mark exported symbols and also add them to 235 // the lists used for roots in the deadcode pass. 236 if f[0] == "cgo_export_static" { 237 if ctxt.LinkMode == LinkExternal && !l.AttrCgoExportStatic(s) { 238 // Static cgo exports appear 239 // in the exported symbol table. 240 ctxt.dynexp = append(ctxt.dynexp, s) 241 } 242 if ctxt.LinkMode == LinkInternal { 243 // For internal linking, we're 244 // responsible for resolving 245 // relocations from host objects. 246 // Record the right Go symbol 247 // version to use. 248 l.AddCgoExport(s) 249 } 250 l.SetAttrCgoExportStatic(s, true) 251 } else { 252 if ctxt.LinkMode == LinkInternal && !l.AttrCgoExportDynamic(s) { 253 // Dynamic cgo exports appear 254 // in the exported symbol table. 255 ctxt.dynexp = append(ctxt.dynexp, s) 256 } 257 l.SetAttrCgoExportDynamic(s, true) 258 } 259 260 continue 261 262 case "cgo_dynamic_linker": 263 if len(f) != 2 { 264 break 265 } 266 267 if *flagInterpreter == "" { 268 if interpreter != "" && interpreter != f[1] { 269 fmt.Fprintf(os.Stderr, "%s: conflict dynlinker: %s and %s\n", os.Args[0], interpreter, f[1]) 270 nerrors++ 271 return 272 } 273 274 interpreter = f[1] 275 } 276 continue 277 278 case "cgo_ldflag": 279 if len(f) != 2 { 280 break 281 } 282 ldflag = append(ldflag, f[1]) 283 continue 284 } 285 286 fmt.Fprintf(os.Stderr, "%s: %s: invalid cgo directive: %q\n", os.Args[0], file, f) 287 nerrors++ 288 } 289 return 290 } 291 292 // openbsdTrimLibVersion indicates whether a shared library is 293 // versioned and if it is, returns the unversioned name. The 294 // OpenBSD library naming scheme is lib<name>.so.<major>.<minor> 295 func openbsdTrimLibVersion(lib string) (string, bool) { 296 parts := strings.Split(lib, ".") 297 if len(parts) != 4 { 298 return "", false 299 } 300 if parts[1] != "so" { 301 return "", false 302 } 303 if _, err := strconv.Atoi(parts[2]); err != nil { 304 return "", false 305 } 306 if _, err := strconv.Atoi(parts[3]); err != nil { 307 return "", false 308 } 309 return fmt.Sprintf("%s.%s", parts[0], parts[1]), true 310 } 311 312 // dedupLibrariesOpenBSD dedups a list of shared libraries, treating versioned 313 // and unversioned libraries as equivalents. Versioned libraries are preferred 314 // and retained over unversioned libraries. This avoids the situation where 315 // the use of cgo results in a DT_NEEDED for a versioned library (for example, 316 // libc.so.96.1), while a dynamic import specifies an unversioned library (for 317 // example, libc.so) - this would otherwise result in two DT_NEEDED entries 318 // for the same library, resulting in a failure when ld.so attempts to load 319 // the Go binary. 320 func dedupLibrariesOpenBSD(ctxt *Link, libs []string) []string { 321 libraries := make(map[string]string) 322 for _, lib := range libs { 323 if name, ok := openbsdTrimLibVersion(lib); ok { 324 // Record unversioned name as seen. 325 seenlib[name] = true 326 libraries[name] = lib 327 } else if _, ok := libraries[lib]; !ok { 328 libraries[lib] = lib 329 } 330 } 331 332 libs = nil 333 for _, lib := range libraries { 334 libs = append(libs, lib) 335 } 336 sort.Strings(libs) 337 338 return libs 339 } 340 341 func dedupLibraries(ctxt *Link, libs []string) []string { 342 if ctxt.Target.IsOpenbsd() { 343 return dedupLibrariesOpenBSD(ctxt, libs) 344 } 345 return libs 346 } 347 348 var seenlib = make(map[string]bool) 349 350 func adddynlib(ctxt *Link, lib string) { 351 if seenlib[lib] || ctxt.LinkMode == LinkExternal { 352 return 353 } 354 seenlib[lib] = true 355 356 if ctxt.IsELF { 357 dsu := ctxt.loader.MakeSymbolUpdater(ctxt.DynStr) 358 if dsu.Size() == 0 { 359 dsu.Addstring("") 360 } 361 du := ctxt.loader.MakeSymbolUpdater(ctxt.Dynamic) 362 Elfwritedynent(ctxt.Arch, du, elf.DT_NEEDED, uint64(dsu.Addstring(lib))) 363 } else { 364 Errorf(nil, "adddynlib: unsupported binary format") 365 } 366 } 367 368 func Adddynsym(ldr *loader.Loader, target *Target, syms *ArchSyms, s loader.Sym) { 369 if ldr.SymDynid(s) >= 0 || target.LinkMode == LinkExternal { 370 return 371 } 372 373 if target.IsELF { 374 elfadddynsym(ldr, target, syms, s) 375 } else if target.HeadType == objabi.Hdarwin { 376 ldr.Errorf(s, "adddynsym: missed symbol (Extname=%s)", ldr.SymExtname(s)) 377 } else if target.HeadType == objabi.Hwindows { 378 // already taken care of 379 } else { 380 ldr.Errorf(s, "adddynsym: unsupported binary format") 381 } 382 } 383 384 func fieldtrack(arch *sys.Arch, l *loader.Loader) { 385 var buf strings.Builder 386 for i := loader.Sym(1); i < loader.Sym(l.NSym()); i++ { 387 if name := l.SymName(i); strings.HasPrefix(name, "go:track.") { 388 if l.AttrReachable(i) { 389 l.SetAttrSpecial(i, true) 390 l.SetAttrNotInSymbolTable(i, true) 391 buf.WriteString(name[9:]) 392 for p := l.Reachparent[i]; p != 0; p = l.Reachparent[p] { 393 buf.WriteString("\t") 394 buf.WriteString(l.SymName(p)) 395 } 396 buf.WriteString("\n") 397 } 398 } 399 } 400 l.Reachparent = nil // we are done with it 401 if *flagFieldTrack == "" { 402 return 403 } 404 s := l.Lookup(*flagFieldTrack, 0) 405 if s == 0 || !l.AttrReachable(s) { 406 return 407 } 408 bld := l.MakeSymbolUpdater(s) 409 bld.SetType(sym.SDATA) 410 addstrdata(arch, l, *flagFieldTrack, buf.String()) 411 } 412 413 func (ctxt *Link) addexport() { 414 // Track undefined external symbols during external link. 415 if ctxt.LinkMode == LinkExternal { 416 for _, s := range ctxt.Textp { 417 if ctxt.loader.AttrSpecial(s) || ctxt.loader.AttrSubSymbol(s) { 418 continue 419 } 420 relocs := ctxt.loader.Relocs(s) 421 for i := 0; i < relocs.Count(); i++ { 422 if rs := relocs.At(i).Sym(); rs != 0 { 423 if ctxt.loader.SymType(rs) == sym.Sxxx && !ctxt.loader.AttrLocal(rs) { 424 // sanity check 425 if len(ctxt.loader.Data(rs)) != 0 { 426 panic("expected no data on undef symbol") 427 } 428 su := ctxt.loader.MakeSymbolUpdater(rs) 429 su.SetType(sym.SUNDEFEXT) 430 } 431 } 432 } 433 } 434 } 435 436 // TODO(aix) 437 if ctxt.HeadType == objabi.Hdarwin || ctxt.HeadType == objabi.Haix { 438 return 439 } 440 441 // Add dynamic symbols. 442 for _, s := range ctxt.dynexp { 443 // Consistency check. 444 if !ctxt.loader.AttrReachable(s) { 445 panic("dynexp entry not reachable") 446 } 447 448 Adddynsym(ctxt.loader, &ctxt.Target, &ctxt.ArchSyms, s) 449 } 450 451 for _, lib := range dedupLibraries(ctxt, dynlib) { 452 adddynlib(ctxt, lib) 453 } 454 } 455 456 type Pkg struct { 457 mark bool 458 checked bool 459 path string 460 impby []*Pkg 461 } 462 463 var pkgall []*Pkg 464 465 func (p *Pkg) cycle() *Pkg { 466 if p.checked { 467 return nil 468 } 469 470 if p.mark { 471 nerrors++ 472 fmt.Printf("import cycle:\n") 473 fmt.Printf("\t%s\n", p.path) 474 return p 475 } 476 477 p.mark = true 478 for _, q := range p.impby { 479 if bad := q.cycle(); bad != nil { 480 p.mark = false 481 p.checked = true 482 fmt.Printf("\timports %s\n", p.path) 483 if bad == p { 484 return nil 485 } 486 return bad 487 } 488 } 489 490 p.checked = true 491 p.mark = false 492 return nil 493 } 494 495 func importcycles() { 496 for _, p := range pkgall { 497 p.cycle() 498 } 499 }