github.com/hikaru7719/go@v0.0.0-20181025140707-c8b2ac68906a/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/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 // 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 if *flagU { 41 errorexit() 42 } 43 return 44 } 45 46 bdata := make([]byte, length) 47 if _, err := io.ReadFull(f, bdata); err != nil { 48 fmt.Fprintf(os.Stderr, "%s: short pkg read %s\n", os.Args[0], filename) 49 if *flagU { 50 errorexit() 51 } 52 return 53 } 54 data := string(bdata) 55 56 // process header lines 57 for data != "" { 58 var line string 59 if i := strings.Index(data, "\n"); i >= 0 { 60 line, data = data[:i], data[i+1:] 61 } else { 62 line, data = data, "" 63 } 64 if line == "safe" { 65 lib.Safe = true 66 } 67 if line == "main" { 68 lib.Main = true 69 } 70 if line == "" { 71 break 72 } 73 } 74 75 // look for cgo section 76 p0 := strings.Index(data, "\n$$ // cgo") 77 var p1 int 78 if p0 >= 0 { 79 p0 += p1 80 i := strings.IndexByte(data[p0+1:], '\n') 81 if i < 0 { 82 fmt.Fprintf(os.Stderr, "%s: found $$ // cgo but no newline in %s\n", os.Args[0], filename) 83 if *flagU { 84 errorexit() 85 } 86 return 87 } 88 p0 += 1 + i 89 90 p1 = strings.Index(data[p0:], "\n$$") 91 if p1 < 0 { 92 p1 = strings.Index(data[p0:], "\n!\n") 93 } 94 if p1 < 0 { 95 fmt.Fprintf(os.Stderr, "%s: cannot find end of // cgo section in %s\n", os.Args[0], filename) 96 if *flagU { 97 errorexit() 98 } 99 return 100 } 101 p1 += p0 102 103 loadcgo(ctxt, filename, objabi.PathToPrefix(lib.Pkg), data[p0:p1]) 104 } 105 } 106 107 func loadcgo(ctxt *Link, file string, pkg string, p string) { 108 var directives [][]string 109 if err := json.NewDecoder(strings.NewReader(p)).Decode(&directives); err != nil { 110 fmt.Fprintf(os.Stderr, "%s: %s: failed decoding cgo directives: %v\n", os.Args[0], file, err) 111 nerrors++ 112 return 113 } 114 115 for _, f := range directives { 116 switch f[0] { 117 case "cgo_import_dynamic": 118 if len(f) < 2 || len(f) > 4 { 119 break 120 } 121 122 local := f[1] 123 remote := local 124 if len(f) > 2 { 125 remote = f[2] 126 } 127 lib := "" 128 if len(f) > 3 { 129 lib = f[3] 130 } 131 132 if *FlagD { 133 fmt.Fprintf(os.Stderr, "%s: %s: cannot use dynamic imports with -d flag\n", os.Args[0], file) 134 nerrors++ 135 return 136 } 137 138 if local == "_" && remote == "_" { 139 // allow #pragma dynimport _ _ "foo.so" 140 // to force a link of foo.so. 141 havedynamic = 1 142 143 if ctxt.HeadType == objabi.Hdarwin { 144 machoadddynlib(lib, ctxt.LinkMode) 145 } else { 146 dynlib = append(dynlib, lib) 147 } 148 continue 149 } 150 151 local = expandpkg(local, pkg) 152 q := "" 153 if i := strings.Index(remote, "#"); i >= 0 { 154 remote, q = remote[:i], remote[i+1:] 155 } 156 s := ctxt.Syms.Lookup(local, 0) 157 if s.Type == 0 || s.Type == sym.SXREF || s.Type == sym.SHOSTOBJ { 158 s.SetDynimplib(lib) 159 s.SetExtname(remote) 160 s.SetDynimpvers(q) 161 if s.Type != sym.SHOSTOBJ { 162 s.Type = sym.SDYNIMPORT 163 } 164 havedynamic = 1 165 } 166 if ctxt.HeadType == objabi.Haix { 167 xcoffadddynimpsym(ctxt, s) 168 } 169 170 continue 171 172 case "cgo_import_static": 173 if len(f) != 2 { 174 break 175 } 176 local := f[1] 177 178 s := ctxt.Syms.Lookup(local, 0) 179 s.Type = sym.SHOSTOBJ 180 s.Size = 0 181 continue 182 183 case "cgo_export_static", "cgo_export_dynamic": 184 if len(f) < 2 || len(f) > 3 { 185 break 186 } 187 local := f[1] 188 remote := local 189 if len(f) > 2 { 190 remote = f[2] 191 } 192 local = expandpkg(local, pkg) 193 194 s := ctxt.Syms.Lookup(local, 0) 195 196 switch ctxt.BuildMode { 197 case BuildModeCShared, BuildModeCArchive, BuildModePlugin: 198 if s == ctxt.Syms.Lookup("main", 0) { 199 continue 200 } 201 } 202 203 // export overrides import, for openbsd/cgo. 204 // see issue 4878. 205 if s.Dynimplib() != "" { 206 s.ResetDyninfo() 207 s.SetExtname("") 208 s.Type = 0 209 } 210 211 if !s.Attr.CgoExport() { 212 s.SetExtname(remote) 213 dynexp = append(dynexp, s) 214 } else if s.Extname() != remote { 215 fmt.Fprintf(os.Stderr, "%s: conflicting cgo_export directives: %s as %s and %s\n", os.Args[0], s.Name, s.Extname(), remote) 216 nerrors++ 217 return 218 } 219 220 if f[0] == "cgo_export_static" { 221 s.Attr |= sym.AttrCgoExportStatic 222 } else { 223 s.Attr |= sym.AttrCgoExportDynamic 224 } 225 continue 226 227 case "cgo_dynamic_linker": 228 if len(f) != 2 { 229 break 230 } 231 232 if *flagInterpreter == "" { 233 if interpreter != "" && interpreter != f[1] { 234 fmt.Fprintf(os.Stderr, "%s: conflict dynlinker: %s and %s\n", os.Args[0], interpreter, f[1]) 235 nerrors++ 236 return 237 } 238 239 interpreter = f[1] 240 } 241 continue 242 243 case "cgo_ldflag": 244 if len(f) != 2 { 245 break 246 } 247 ldflag = append(ldflag, f[1]) 248 continue 249 } 250 251 fmt.Fprintf(os.Stderr, "%s: %s: invalid cgo directive: %q\n", os.Args[0], file, f) 252 nerrors++ 253 } 254 } 255 256 var seenlib = make(map[string]bool) 257 258 func adddynlib(ctxt *Link, lib string) { 259 if seenlib[lib] || ctxt.LinkMode == LinkExternal { 260 return 261 } 262 seenlib[lib] = true 263 264 if ctxt.IsELF { 265 s := ctxt.Syms.Lookup(".dynstr", 0) 266 if s.Size == 0 { 267 Addstring(s, "") 268 } 269 Elfwritedynent(ctxt, ctxt.Syms.Lookup(".dynamic", 0), DT_NEEDED, uint64(Addstring(s, lib))) 270 } else { 271 Errorf(nil, "adddynlib: unsupported binary format") 272 } 273 } 274 275 func Adddynsym(ctxt *Link, s *sym.Symbol) { 276 if s.Dynid >= 0 || ctxt.LinkMode == LinkExternal { 277 return 278 } 279 280 if ctxt.IsELF { 281 elfadddynsym(ctxt, s) 282 } else if ctxt.HeadType == objabi.Hdarwin { 283 Errorf(s, "adddynsym: missed symbol (Extname=%s)", s.Extname()) 284 } else if ctxt.HeadType == objabi.Hwindows { 285 // already taken care of 286 } else { 287 Errorf(s, "adddynsym: unsupported binary format") 288 } 289 } 290 291 func fieldtrack(ctxt *Link) { 292 // record field tracking references 293 var buf bytes.Buffer 294 for _, s := range ctxt.Syms.Allsym { 295 if strings.HasPrefix(s.Name, "go.track.") { 296 s.Attr |= sym.AttrSpecial // do not lay out in data segment 297 s.Attr |= sym.AttrNotInSymbolTable 298 if s.Attr.Reachable() { 299 buf.WriteString(s.Name[9:]) 300 for p := ctxt.Reachparent[s]; p != nil; p = ctxt.Reachparent[p] { 301 buf.WriteString("\t") 302 buf.WriteString(p.Name) 303 } 304 buf.WriteString("\n") 305 } 306 307 s.Type = sym.SCONST 308 s.Value = 0 309 } 310 } 311 312 if *flagFieldTrack == "" { 313 return 314 } 315 s := ctxt.Syms.ROLookup(*flagFieldTrack, 0) 316 if s == nil || !s.Attr.Reachable() { 317 return 318 } 319 s.Type = sym.SDATA 320 addstrdata(ctxt, *flagFieldTrack, buf.String()) 321 } 322 323 func (ctxt *Link) addexport() { 324 // TODO(aix) 325 if ctxt.HeadType == objabi.Hdarwin || ctxt.HeadType == objabi.Haix { 326 return 327 } 328 329 for _, exp := range dynexp { 330 Adddynsym(ctxt, exp) 331 } 332 for _, lib := range dynlib { 333 adddynlib(ctxt, lib) 334 } 335 } 336 337 type Pkg struct { 338 mark bool 339 checked bool 340 path string 341 impby []*Pkg 342 } 343 344 var pkgall []*Pkg 345 346 func (p *Pkg) cycle() *Pkg { 347 if p.checked { 348 return nil 349 } 350 351 if p.mark { 352 nerrors++ 353 fmt.Printf("import cycle:\n") 354 fmt.Printf("\t%s\n", p.path) 355 return p 356 } 357 358 p.mark = true 359 for _, q := range p.impby { 360 if bad := q.cycle(); bad != nil { 361 p.mark = false 362 p.checked = true 363 fmt.Printf("\timports %s\n", p.path) 364 if bad == p { 365 return nil 366 } 367 return bad 368 } 369 } 370 371 p.checked = true 372 p.mark = false 373 return nil 374 } 375 376 func importcycles() { 377 for _, p := range pkgall { 378 p.cycle() 379 } 380 }