github.com/megatontech/mynoteforgo@v0.0.0-20200507084910-5d0c6ea6e890/源码/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/bio" 12 "cmd/internal/objabi" 13 "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 114 loadcgo(ctxt, filename, objabi.PathToPrefix(lib.Pkg), data[p0:p1]) 115 } 116 } 117 118 func loadcgo(ctxt *Link, file string, pkg string, p string) { 119 var directives [][]string 120 if err := json.NewDecoder(strings.NewReader(p)).Decode(&directives); err != nil { 121 fmt.Fprintf(os.Stderr, "%s: %s: failed decoding cgo directives: %v\n", os.Args[0], file, err) 122 nerrors++ 123 return 124 } 125 126 for _, f := range directives { 127 switch f[0] { 128 case "cgo_import_dynamic": 129 if len(f) < 2 || len(f) > 4 { 130 break 131 } 132 133 local := f[1] 134 remote := local 135 if len(f) > 2 { 136 remote = f[2] 137 } 138 lib := "" 139 if len(f) > 3 { 140 lib = f[3] 141 } 142 143 if *FlagD { 144 fmt.Fprintf(os.Stderr, "%s: %s: cannot use dynamic imports with -d flag\n", os.Args[0], file) 145 nerrors++ 146 return 147 } 148 149 if local == "_" && remote == "_" { 150 // allow #pragma dynimport _ _ "foo.so" 151 // to force a link of foo.so. 152 havedynamic = 1 153 154 if ctxt.HeadType == objabi.Hdarwin { 155 machoadddynlib(lib, ctxt.LinkMode) 156 } else { 157 dynlib = append(dynlib, lib) 158 } 159 continue 160 } 161 162 local = expandpkg(local, pkg) 163 q := "" 164 if i := strings.Index(remote, "#"); i >= 0 { 165 remote, q = remote[:i], remote[i+1:] 166 } 167 s := ctxt.Syms.Lookup(local, 0) 168 if s.Type == 0 || s.Type == sym.SXREF || s.Type == sym.SHOSTOBJ { 169 s.SetDynimplib(lib) 170 s.SetExtname(remote) 171 s.SetDynimpvers(q) 172 if s.Type != sym.SHOSTOBJ { 173 s.Type = sym.SDYNIMPORT 174 } 175 havedynamic = 1 176 } 177 178 continue 179 180 case "cgo_import_static": 181 if len(f) != 2 { 182 break 183 } 184 local := f[1] 185 186 s := ctxt.Syms.Lookup(local, 0) 187 s.Type = sym.SHOSTOBJ 188 s.Size = 0 189 continue 190 191 case "cgo_export_static", "cgo_export_dynamic": 192 if len(f) < 2 || len(f) > 3 { 193 break 194 } 195 local := f[1] 196 remote := local 197 if len(f) > 2 { 198 remote = f[2] 199 } 200 local = expandpkg(local, pkg) 201 202 // The compiler arranges for an ABI0 wrapper 203 // to be available for all cgo-exported 204 // functions. Link.loadlib will resolve any 205 // ABI aliases we find here (since we may not 206 // yet know it's an alias). 207 s := ctxt.Syms.Lookup(local, 0) 208 209 switch ctxt.BuildMode { 210 case BuildModeCShared, BuildModeCArchive, BuildModePlugin: 211 if s == ctxt.Syms.Lookup("main", 0) { 212 continue 213 } 214 } 215 216 // export overrides import, for openbsd/cgo. 217 // see issue 4878. 218 if s.Dynimplib() != "" { 219 s.ResetDyninfo() 220 s.SetExtname("") 221 s.Type = 0 222 } 223 224 if !s.Attr.CgoExport() { 225 s.SetExtname(remote) 226 dynexp = append(dynexp, s) 227 } else if s.Extname() != remote { 228 fmt.Fprintf(os.Stderr, "%s: conflicting cgo_export directives: %s as %s and %s\n", os.Args[0], s.Name, s.Extname(), remote) 229 nerrors++ 230 return 231 } 232 233 if f[0] == "cgo_export_static" { 234 s.Attr |= sym.AttrCgoExportStatic 235 } else { 236 s.Attr |= sym.AttrCgoExportDynamic 237 } 238 continue 239 240 case "cgo_dynamic_linker": 241 if len(f) != 2 { 242 break 243 } 244 245 if *flagInterpreter == "" { 246 if interpreter != "" && interpreter != f[1] { 247 fmt.Fprintf(os.Stderr, "%s: conflict dynlinker: %s and %s\n", os.Args[0], interpreter, f[1]) 248 nerrors++ 249 return 250 } 251 252 interpreter = f[1] 253 } 254 continue 255 256 case "cgo_ldflag": 257 if len(f) != 2 { 258 break 259 } 260 ldflag = append(ldflag, f[1]) 261 continue 262 } 263 264 fmt.Fprintf(os.Stderr, "%s: %s: invalid cgo directive: %q\n", os.Args[0], file, f) 265 nerrors++ 266 } 267 } 268 269 var seenlib = make(map[string]bool) 270 271 func adddynlib(ctxt *Link, lib string) { 272 if seenlib[lib] || ctxt.LinkMode == LinkExternal { 273 return 274 } 275 seenlib[lib] = true 276 277 if ctxt.IsELF { 278 s := ctxt.Syms.Lookup(".dynstr", 0) 279 if s.Size == 0 { 280 Addstring(s, "") 281 } 282 Elfwritedynent(ctxt, ctxt.Syms.Lookup(".dynamic", 0), DT_NEEDED, uint64(Addstring(s, lib))) 283 } else { 284 Errorf(nil, "adddynlib: unsupported binary format") 285 } 286 } 287 288 func Adddynsym(ctxt *Link, s *sym.Symbol) { 289 if s.Dynid >= 0 || ctxt.LinkMode == LinkExternal { 290 return 291 } 292 293 if ctxt.IsELF { 294 elfadddynsym(ctxt, s) 295 } else if ctxt.HeadType == objabi.Hdarwin { 296 Errorf(s, "adddynsym: missed symbol (Extname=%s)", s.Extname()) 297 } else if ctxt.HeadType == objabi.Hwindows { 298 // already taken care of 299 } else { 300 Errorf(s, "adddynsym: unsupported binary format") 301 } 302 } 303 304 func fieldtrack(ctxt *Link) { 305 // record field tracking references 306 var buf bytes.Buffer 307 for _, s := range ctxt.Syms.Allsym { 308 if strings.HasPrefix(s.Name, "go.track.") { 309 s.Attr |= sym.AttrSpecial // do not lay out in data segment 310 s.Attr |= sym.AttrNotInSymbolTable 311 if s.Attr.Reachable() { 312 buf.WriteString(s.Name[9:]) 313 for p := ctxt.Reachparent[s]; p != nil; p = ctxt.Reachparent[p] { 314 buf.WriteString("\t") 315 buf.WriteString(p.Name) 316 } 317 buf.WriteString("\n") 318 } 319 320 s.Type = sym.SCONST 321 s.Value = 0 322 } 323 } 324 325 if *flagFieldTrack == "" { 326 return 327 } 328 s := ctxt.Syms.ROLookup(*flagFieldTrack, 0) 329 if s == nil || !s.Attr.Reachable() { 330 return 331 } 332 s.Type = sym.SDATA 333 addstrdata(ctxt, *flagFieldTrack, buf.String()) 334 } 335 336 func (ctxt *Link) addexport() { 337 // TODO(aix) 338 if ctxt.HeadType == objabi.Hdarwin || ctxt.HeadType == objabi.Haix { 339 return 340 } 341 342 for _, exp := range dynexp { 343 Adddynsym(ctxt, exp) 344 } 345 for _, lib := range dynlib { 346 adddynlib(ctxt, lib) 347 } 348 } 349 350 type Pkg struct { 351 mark bool 352 checked bool 353 path string 354 impby []*Pkg 355 } 356 357 var pkgall []*Pkg 358 359 func (p *Pkg) cycle() *Pkg { 360 if p.checked { 361 return nil 362 } 363 364 if p.mark { 365 nerrors++ 366 fmt.Printf("import cycle:\n") 367 fmt.Printf("\t%s\n", p.path) 368 return p 369 } 370 371 p.mark = true 372 for _, q := range p.impby { 373 if bad := q.cycle(); bad != nil { 374 p.mark = false 375 p.checked = true 376 fmt.Printf("\timports %s\n", p.path) 377 if bad == p { 378 return nil 379 } 380 return bad 381 } 382 } 383 384 p.checked = true 385 p.mark = false 386 return nil 387 } 388 389 func importcycles() { 390 for _, p := range pkgall { 391 p.cycle() 392 } 393 }