github.com/sbinet/go@v0.0.0-20160827155028-54d7de7dd62b/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/obj" 13 "fmt" 14 "io" 15 "os" 16 "strings" 17 ) 18 19 // go-specific code shared across loaders (5l, 6l, 8l). 20 21 // replace all "". with pkg. 22 func expandpkg(t0 string, pkg string) string { 23 return strings.Replace(t0, `"".`, pkg+".", -1) 24 } 25 26 // TODO: 27 // generate debugging section in binary. 28 // once the dust settles, try to move some code to 29 // libmach, so that other linkers and ar can share. 30 31 func ldpkg(ctxt *Link, f *bio.Reader, pkg string, length int64, filename string, whence int) { 32 var p0, p1 int 33 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 // In a __.PKGDEF, we only care about the package name. 47 // Don't read all the export data. 48 if length > 1000 && whence == Pkgdef { 49 length = 1000 50 } 51 52 bdata := make([]byte, length) 53 if _, err := io.ReadFull(f, bdata); err != nil { 54 fmt.Fprintf(os.Stderr, "%s: short pkg read %s\n", os.Args[0], filename) 55 if *flagU { 56 errorexit() 57 } 58 return 59 } 60 data := string(bdata) 61 62 // process header lines 63 isSafe := false 64 isMain := false 65 for data != "" { 66 var line string 67 if i := strings.Index(data, "\n"); i >= 0 { 68 line, data = data[:i], data[i+1:] 69 } else { 70 line, data = data, "" 71 } 72 if line == "safe" { 73 isSafe = true 74 } 75 if line == "main" { 76 isMain = true 77 } 78 if line == "" { 79 break 80 } 81 } 82 83 if whence == Pkgdef || whence == FileObj { 84 if pkg == "main" && !isMain { 85 Exitf("%s: not package main", filename) 86 } 87 if *flagU && whence != ArchiveObj && !isSafe { 88 Exitf("load of unsafe package %s", filename) 89 } 90 } 91 92 // __.PKGDEF has no cgo section - those are in the C compiler-generated object files. 93 if whence == Pkgdef { 94 return 95 } 96 97 // look for cgo section 98 p0 = strings.Index(data, "\n$$ // cgo") 99 if p0 >= 0 { 100 p0 += p1 101 i := strings.IndexByte(data[p0+1:], '\n') 102 if i < 0 { 103 fmt.Fprintf(os.Stderr, "%s: found $$ // cgo but no newline in %s\n", os.Args[0], filename) 104 if *flagU { 105 errorexit() 106 } 107 return 108 } 109 p0 += 1 + i 110 111 p1 = strings.Index(data[p0:], "\n$$") 112 if p1 < 0 { 113 p1 = strings.Index(data[p0:], "\n!\n") 114 } 115 if p1 < 0 { 116 fmt.Fprintf(os.Stderr, "%s: cannot find end of // cgo section in %s\n", os.Args[0], filename) 117 if *flagU { 118 errorexit() 119 } 120 return 121 } 122 p1 += p0 123 124 loadcgo(ctxt, filename, pkg, data[p0:p1]) 125 } 126 } 127 128 func loadcgo(ctxt *Link, file string, pkg string, p string) { 129 var next string 130 var q string 131 var f []string 132 var local string 133 var remote string 134 var lib string 135 var s *Symbol 136 137 p0 := "" 138 for ; p != ""; p = next { 139 if i := strings.Index(p, "\n"); i >= 0 { 140 p, next = p[:i], p[i+1:] 141 } else { 142 next = "" 143 } 144 145 p0 = p // save for error message 146 f = tokenize(p) 147 if len(f) == 0 { 148 continue 149 } 150 151 if f[0] == "cgo_import_dynamic" { 152 if len(f) < 2 || len(f) > 4 { 153 goto err 154 } 155 156 local = f[1] 157 remote = local 158 if len(f) > 2 { 159 remote = f[2] 160 } 161 lib = "" 162 if len(f) > 3 { 163 lib = f[3] 164 } 165 166 if *FlagD { 167 fmt.Fprintf(os.Stderr, "%s: %s: cannot use dynamic imports with -d flag\n", os.Args[0], file) 168 nerrors++ 169 return 170 } 171 172 if local == "_" && remote == "_" { 173 // allow #pragma dynimport _ _ "foo.so" 174 // to force a link of foo.so. 175 havedynamic = 1 176 177 if HEADTYPE == obj.Hdarwin { 178 Machoadddynlib(lib) 179 } else { 180 dynlib = append(dynlib, lib) 181 } 182 continue 183 } 184 185 local = expandpkg(local, pkg) 186 q = "" 187 if i := strings.Index(remote, "#"); i >= 0 { 188 remote, q = remote[:i], remote[i+1:] 189 } 190 s = Linklookup(ctxt, local, 0) 191 if local != f[1] { 192 } 193 if s.Type == 0 || s.Type == obj.SXREF || s.Type == obj.SHOSTOBJ { 194 s.Dynimplib = lib 195 s.Extname = remote 196 s.Dynimpvers = q 197 if s.Type != obj.SHOSTOBJ { 198 s.Type = obj.SDYNIMPORT 199 } 200 havedynamic = 1 201 } 202 203 continue 204 } 205 206 if f[0] == "cgo_import_static" { 207 if len(f) != 2 { 208 goto err 209 } 210 local = f[1] 211 s = Linklookup(ctxt, local, 0) 212 s.Type = obj.SHOSTOBJ 213 s.Size = 0 214 continue 215 } 216 217 if f[0] == "cgo_export_static" || f[0] == "cgo_export_dynamic" { 218 if len(f) < 2 || len(f) > 3 { 219 goto err 220 } 221 local = f[1] 222 if len(f) > 2 { 223 remote = f[2] 224 } else { 225 remote = local 226 } 227 local = expandpkg(local, pkg) 228 s = Linklookup(ctxt, local, 0) 229 230 switch Buildmode { 231 case BuildmodeCShared, BuildmodeCArchive: 232 if s == Linklookup(ctxt, "main", 0) { 233 continue 234 } 235 } 236 237 // export overrides import, for openbsd/cgo. 238 // see issue 4878. 239 if s.Dynimplib != "" { 240 s.Dynimplib = "" 241 s.Extname = "" 242 s.Dynimpvers = "" 243 s.Type = 0 244 } 245 246 if !s.Attr.CgoExport() { 247 s.Extname = remote 248 dynexp = append(dynexp, s) 249 } else if s.Extname != remote { 250 fmt.Fprintf(os.Stderr, "%s: conflicting cgo_export directives: %s as %s and %s\n", os.Args[0], s.Name, s.Extname, remote) 251 nerrors++ 252 return 253 } 254 255 if f[0] == "cgo_export_static" { 256 s.Attr |= AttrCgoExportStatic 257 } else { 258 s.Attr |= AttrCgoExportDynamic 259 } 260 if local != f[1] { 261 } 262 continue 263 } 264 265 if f[0] == "cgo_dynamic_linker" { 266 if len(f) != 2 { 267 goto err 268 } 269 270 if *flagInterpreter == "" { 271 if interpreter != "" && interpreter != f[1] { 272 fmt.Fprintf(os.Stderr, "%s: conflict dynlinker: %s and %s\n", os.Args[0], interpreter, f[1]) 273 nerrors++ 274 return 275 } 276 277 interpreter = f[1] 278 } 279 280 continue 281 } 282 283 if f[0] == "cgo_ldflag" { 284 if len(f) != 2 { 285 goto err 286 } 287 ldflag = append(ldflag, f[1]) 288 continue 289 } 290 } 291 292 return 293 294 err: 295 fmt.Fprintf(os.Stderr, "%s: %s: invalid dynimport line: %s\n", os.Args[0], file, p0) 296 nerrors++ 297 } 298 299 var seenlib = make(map[string]bool) 300 301 func adddynlib(ctxt *Link, lib string) { 302 if seenlib[lib] || Linkmode == LinkExternal { 303 return 304 } 305 seenlib[lib] = true 306 307 if Iself { 308 s := Linklookup(ctxt, ".dynstr", 0) 309 if s.Size == 0 { 310 Addstring(ctxt, s, "") 311 } 312 Elfwritedynent(ctxt, Linklookup(ctxt, ".dynamic", 0), DT_NEEDED, uint64(Addstring(ctxt, s, lib))) 313 } else { 314 ctxt.Diag("adddynlib: unsupported binary format") 315 } 316 } 317 318 func Adddynsym(ctxt *Link, s *Symbol) { 319 if s.Dynid >= 0 || Linkmode == LinkExternal { 320 return 321 } 322 323 if Iself { 324 Elfadddynsym(ctxt, s) 325 } else if HEADTYPE == obj.Hdarwin { 326 ctxt.Diag("adddynsym: missed symbol %s (%s)", s.Name, s.Extname) 327 } else if HEADTYPE == obj.Hwindows { 328 // already taken care of 329 } else { 330 ctxt.Diag("adddynsym: unsupported binary format") 331 } 332 } 333 334 func fieldtrack(ctxt *Link) { 335 // record field tracking references 336 var buf bytes.Buffer 337 for _, s := range ctxt.Allsym { 338 if strings.HasPrefix(s.Name, "go.track.") { 339 s.Attr |= AttrSpecial // do not lay out in data segment 340 s.Attr |= AttrHidden 341 if s.Attr.Reachable() { 342 buf.WriteString(s.Name[9:]) 343 for p := s.Reachparent; p != nil; p = p.Reachparent { 344 buf.WriteString("\t") 345 buf.WriteString(p.Name) 346 } 347 buf.WriteString("\n") 348 } 349 350 s.Type = obj.SCONST 351 s.Value = 0 352 } 353 } 354 355 if *flagFieldTrack == "" { 356 return 357 } 358 s := Linklookup(ctxt, *flagFieldTrack, 0) 359 if !s.Attr.Reachable() { 360 return 361 } 362 addstrdata(ctxt, *flagFieldTrack, buf.String()) 363 } 364 365 func (ctxt *Link) addexport() { 366 if HEADTYPE == obj.Hdarwin { 367 return 368 } 369 370 for _, exp := range dynexp { 371 Adddynsym(ctxt, exp) 372 } 373 for _, lib := range dynlib { 374 adddynlib(ctxt, lib) 375 } 376 } 377 378 type Pkg struct { 379 mark bool 380 checked bool 381 path string 382 impby []*Pkg 383 } 384 385 var pkgall []*Pkg 386 387 func (p *Pkg) cycle() *Pkg { 388 if p.checked { 389 return nil 390 } 391 392 if p.mark { 393 nerrors++ 394 fmt.Printf("import cycle:\n") 395 fmt.Printf("\t%s\n", p.path) 396 return p 397 } 398 399 p.mark = true 400 for _, q := range p.impby { 401 if bad := q.cycle(); bad != nil { 402 p.mark = false 403 p.checked = true 404 fmt.Printf("\timports %s\n", p.path) 405 if bad == p { 406 return nil 407 } 408 return bad 409 } 410 } 411 412 p.checked = true 413 p.mark = false 414 return nil 415 } 416 417 func importcycles() { 418 for _, p := range pkgall { 419 p.cycle() 420 } 421 } 422 423 func setlinkmode(arg string) { 424 if arg == "internal" { 425 Linkmode = LinkInternal 426 } else if arg == "external" { 427 Linkmode = LinkExternal 428 } else if arg == "auto" { 429 Linkmode = LinkAuto 430 } else { 431 Exitf("unknown link mode -linkmode %s", arg) 432 } 433 }