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