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