github.com/gagliardetto/golang-go@v0.0.0-20201020153340-53909ea70814/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 "github.com/gagliardetto/golang-go/cmd/internal/bio" 12 "github.com/gagliardetto/golang-go/cmd/internal/objabi" 13 "github.com/gagliardetto/golang-go/cmd/link/internal/sym" 14 "encoding/json" 15 "fmt" 16 "io" 17 "os" 18 "strings" 19 ) 20 21 // go-specific code shared across loaders (5l, 6l, 8l). 22 23 // replace all "". with pkg. 24 func expandpkg(t0 string, pkg string) string { 25 return strings.Replace(t0, `"".`, pkg+".", -1) 26 } 27 28 func resolveABIAlias(s *sym.Symbol) *sym.Symbol { 29 if s.Type != sym.SABIALIAS { 30 return s 31 } 32 target := s.R[0].Sym 33 if target.Type == sym.SABIALIAS { 34 panic(fmt.Sprintf("ABI alias %s references another ABI alias %s", s, target)) 35 } 36 return target 37 } 38 39 // TODO: 40 // generate debugging section in binary. 41 // once the dust settles, try to move some code to 42 // libmach, so that other linkers and ar can share. 43 44 func ldpkg(ctxt *Link, f *bio.Reader, lib *sym.Library, length int64, filename string) { 45 if *flagG { 46 return 47 } 48 49 if int64(int(length)) != length { 50 fmt.Fprintf(os.Stderr, "%s: too much pkg data in %s\n", os.Args[0], filename) 51 if *flagU { 52 errorexit() 53 } 54 return 55 } 56 57 bdata := make([]byte, length) 58 if _, err := io.ReadFull(f, bdata); err != nil { 59 fmt.Fprintf(os.Stderr, "%s: short pkg read %s\n", os.Args[0], filename) 60 if *flagU { 61 errorexit() 62 } 63 return 64 } 65 data := string(bdata) 66 67 // process header lines 68 for data != "" { 69 var line string 70 if i := strings.Index(data, "\n"); i >= 0 { 71 line, data = data[:i], data[i+1:] 72 } else { 73 line, data = data, "" 74 } 75 if line == "safe" { 76 lib.Safe = true 77 } 78 if line == "main" { 79 lib.Main = true 80 } 81 if line == "" { 82 break 83 } 84 } 85 86 // look for cgo section 87 p0 := strings.Index(data, "\n$$ // cgo") 88 var p1 int 89 if p0 >= 0 { 90 p0 += p1 91 i := strings.IndexByte(data[p0+1:], '\n') 92 if i < 0 { 93 fmt.Fprintf(os.Stderr, "%s: found $$ // cgo but no newline in %s\n", os.Args[0], filename) 94 if *flagU { 95 errorexit() 96 } 97 return 98 } 99 p0 += 1 + i 100 101 p1 = strings.Index(data[p0:], "\n$$") 102 if p1 < 0 { 103 p1 = strings.Index(data[p0:], "\n!\n") 104 } 105 if p1 < 0 { 106 fmt.Fprintf(os.Stderr, "%s: cannot find end of // cgo section in %s\n", os.Args[0], filename) 107 if *flagU { 108 errorexit() 109 } 110 return 111 } 112 p1 += p0 113 loadcgo(ctxt, filename, objabi.PathToPrefix(lib.Pkg), data[p0:p1]) 114 } 115 } 116 117 func loadcgo(ctxt *Link, file string, pkg string, p string) { 118 var directives [][]string 119 if err := json.NewDecoder(strings.NewReader(p)).Decode(&directives); err != nil { 120 fmt.Fprintf(os.Stderr, "%s: %s: failed decoding cgo directives: %v\n", os.Args[0], file, err) 121 nerrors++ 122 return 123 } 124 125 // Find cgo_export symbols. They are roots in the deadcode pass. 126 for _, f := range directives { 127 switch f[0] { 128 case "cgo_export_static", "cgo_export_dynamic": 129 if len(f) < 2 || len(f) > 3 { 130 continue 131 } 132 local := f[1] 133 switch ctxt.BuildMode { 134 case BuildModeCShared, BuildModeCArchive, BuildModePlugin: 135 if local == "main" { 136 continue 137 } 138 } 139 local = expandpkg(local, pkg) 140 if f[0] == "cgo_export_static" { 141 ctxt.cgo_export_static[local] = true 142 } else { 143 ctxt.cgo_export_dynamic[local] = true 144 } 145 } 146 } 147 148 if *flagNewobj { 149 // Record the directives. We'll process them later after Symbols are created. 150 ctxt.cgodata = append(ctxt.cgodata, cgodata{file, pkg, directives}) 151 } else { 152 setCgoAttr(ctxt, ctxt.Syms.Lookup, file, pkg, directives) 153 } 154 } 155 156 // Set symbol attributes or flags based on cgo directives. 157 func setCgoAttr(ctxt *Link, lookup func(string, int) *sym.Symbol, file string, pkg string, directives [][]string) { 158 for _, f := range directives { 159 switch f[0] { 160 case "cgo_import_dynamic": 161 if len(f) < 2 || len(f) > 4 { 162 break 163 } 164 165 local := f[1] 166 remote := local 167 if len(f) > 2 { 168 remote = f[2] 169 } 170 lib := "" 171 if len(f) > 3 { 172 lib = f[3] 173 } 174 175 if *FlagD { 176 fmt.Fprintf(os.Stderr, "%s: %s: cannot use dynamic imports with -d flag\n", os.Args[0], file) 177 nerrors++ 178 return 179 } 180 181 if local == "_" && remote == "_" { 182 // allow #pragma dynimport _ _ "foo.so" 183 // to force a link of foo.so. 184 havedynamic = 1 185 186 if ctxt.HeadType == objabi.Hdarwin { 187 machoadddynlib(lib, ctxt.LinkMode) 188 } else { 189 dynlib = append(dynlib, lib) 190 } 191 continue 192 } 193 194 local = expandpkg(local, pkg) 195 q := "" 196 if i := strings.Index(remote, "#"); i >= 0 { 197 remote, q = remote[:i], remote[i+1:] 198 } 199 s := lookup(local, 0) 200 if s.Type == 0 || s.Type == sym.SXREF || s.Type == sym.SBSS || s.Type == sym.SNOPTRBSS || s.Type == sym.SHOSTOBJ { 201 s.SetDynimplib(lib) 202 s.SetExtname(remote) 203 s.SetDynimpvers(q) 204 if s.Type != sym.SHOSTOBJ { 205 s.Type = sym.SDYNIMPORT 206 } 207 havedynamic = 1 208 } 209 210 continue 211 212 case "cgo_import_static": 213 if len(f) != 2 { 214 break 215 } 216 local := f[1] 217 218 s := lookup(local, 0) 219 s.Type = sym.SHOSTOBJ 220 s.Size = 0 221 continue 222 223 case "cgo_export_static", "cgo_export_dynamic": 224 if len(f) < 2 || len(f) > 3 { 225 break 226 } 227 local := f[1] 228 remote := local 229 if len(f) > 2 { 230 remote = f[2] 231 } 232 local = expandpkg(local, pkg) 233 234 // The compiler arranges for an ABI0 wrapper 235 // to be available for all cgo-exported 236 // functions. Link.loadlib will resolve any 237 // ABI aliases we find here (since we may not 238 // yet know it's an alias). 239 s := lookup(local, 0) 240 241 switch ctxt.BuildMode { 242 case BuildModeCShared, BuildModeCArchive, BuildModePlugin: 243 if s == lookup("main", 0) { 244 continue 245 } 246 } 247 248 // export overrides import, for openbsd/cgo. 249 // see issue 4878. 250 if s.Dynimplib() != "" { 251 s.ResetDyninfo() 252 s.SetExtname("") 253 s.Type = 0 254 } 255 256 if !s.Attr.CgoExport() { 257 s.SetExtname(remote) 258 } else if s.Extname() != remote { 259 fmt.Fprintf(os.Stderr, "%s: conflicting cgo_export directives: %s as %s and %s\n", os.Args[0], s.Name, s.Extname(), remote) 260 nerrors++ 261 return 262 } 263 264 if f[0] == "cgo_export_static" { 265 s.Attr |= sym.AttrCgoExportStatic 266 } else { 267 s.Attr |= sym.AttrCgoExportDynamic 268 } 269 continue 270 271 case "cgo_dynamic_linker": 272 if len(f) != 2 { 273 break 274 } 275 276 if *flagInterpreter == "" { 277 if interpreter != "" && interpreter != f[1] { 278 fmt.Fprintf(os.Stderr, "%s: conflict dynlinker: %s and %s\n", os.Args[0], interpreter, f[1]) 279 nerrors++ 280 return 281 } 282 283 interpreter = f[1] 284 } 285 continue 286 287 case "cgo_ldflag": 288 if len(f) != 2 { 289 break 290 } 291 ldflag = append(ldflag, f[1]) 292 continue 293 } 294 295 fmt.Fprintf(os.Stderr, "%s: %s: invalid cgo directive: %q\n", os.Args[0], file, f) 296 nerrors++ 297 } 298 } 299 300 var seenlib = make(map[string]bool) 301 302 func adddynlib(ctxt *Link, lib string) { 303 if seenlib[lib] || ctxt.LinkMode == LinkExternal { 304 return 305 } 306 seenlib[lib] = true 307 308 if ctxt.IsELF { 309 s := ctxt.Syms.Lookup(".dynstr", 0) 310 if s.Size == 0 { 311 Addstring(s, "") 312 } 313 Elfwritedynent(ctxt, ctxt.Syms.Lookup(".dynamic", 0), DT_NEEDED, uint64(Addstring(s, lib))) 314 } else { 315 Errorf(nil, "adddynlib: unsupported binary format") 316 } 317 } 318 319 func Adddynsym(ctxt *Link, s *sym.Symbol) { 320 if s.Dynid >= 0 || ctxt.LinkMode == LinkExternal { 321 return 322 } 323 324 if ctxt.IsELF { 325 elfadddynsym(ctxt, s) 326 } else if ctxt.HeadType == objabi.Hdarwin { 327 Errorf(s, "adddynsym: missed symbol (Extname=%s)", s.Extname()) 328 } else if ctxt.HeadType == objabi.Hwindows { 329 // already taken care of 330 } else { 331 Errorf(s, "adddynsym: unsupported binary format") 332 } 333 } 334 335 func fieldtrack(ctxt *Link) { 336 // record field tracking references 337 var buf bytes.Buffer 338 for _, s := range ctxt.Syms.Allsym { 339 if strings.HasPrefix(s.Name, "go.track.") { 340 s.Attr |= sym.AttrSpecial // do not lay out in data segment 341 s.Attr |= sym.AttrNotInSymbolTable 342 if s.Attr.Reachable() { 343 buf.WriteString(s.Name[9:]) 344 for p := ctxt.Reachparent[s]; p != nil; p = ctxt.Reachparent[p] { 345 buf.WriteString("\t") 346 buf.WriteString(p.Name) 347 } 348 buf.WriteString("\n") 349 } 350 351 s.Type = sym.SCONST 352 s.Value = 0 353 } 354 } 355 356 if *flagFieldTrack == "" { 357 return 358 } 359 s := ctxt.Syms.ROLookup(*flagFieldTrack, 0) 360 if s == nil || !s.Attr.Reachable() { 361 return 362 } 363 s.Type = sym.SDATA 364 addstrdata(ctxt, *flagFieldTrack, buf.String()) 365 } 366 367 func (ctxt *Link) addexport() { 368 // Track undefined external symbols during external link. 369 if ctxt.LinkMode == LinkExternal { 370 for _, s := range ctxt.Syms.Allsym { 371 if !s.Attr.Reachable() || s.Attr.Special() || s.Attr.SubSymbol() { 372 continue 373 } 374 if s.Type != sym.STEXT { 375 continue 376 } 377 for i := range s.R { 378 r := &s.R[i] 379 if r.Sym != nil && r.Sym.Type == sym.Sxxx { 380 r.Sym.Type = sym.SUNDEFEXT 381 } 382 } 383 } 384 } 385 386 // TODO(aix) 387 if ctxt.HeadType == objabi.Hdarwin || ctxt.HeadType == objabi.Haix { 388 return 389 } 390 391 for _, exp := range dynexp { 392 Adddynsym(ctxt, exp) 393 } 394 for _, lib := range dynlib { 395 adddynlib(ctxt, lib) 396 } 397 } 398 399 type Pkg struct { 400 mark bool 401 checked bool 402 path string 403 impby []*Pkg 404 } 405 406 var pkgall []*Pkg 407 408 func (p *Pkg) cycle() *Pkg { 409 if p.checked { 410 return nil 411 } 412 413 if p.mark { 414 nerrors++ 415 fmt.Printf("import cycle:\n") 416 fmt.Printf("\t%s\n", p.path) 417 return p 418 } 419 420 p.mark = true 421 for _, q := range p.impby { 422 if bad := q.cycle(); bad != nil { 423 p.mark = false 424 p.checked = true 425 fmt.Printf("\timports %s\n", p.path) 426 if bad == p { 427 return nil 428 } 429 return bad 430 } 431 } 432 433 p.checked = true 434 p.mark = false 435 return nil 436 } 437 438 func importcycles() { 439 for _, p := range pkgall { 440 p.cycle() 441 } 442 }