github.com/q45/go@v0.0.0-20151101211701-a4fb8c13db3f/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/obj"
    12  	"fmt"
    13  	"os"
    14  	"strconv"
    15  	"strings"
    16  )
    17  
    18  // go-specific code shared across loaders (5l, 6l, 8l).
    19  
    20  // replace all "". with pkg.
    21  func expandpkg(t0 string, pkg string) string {
    22  	return strings.Replace(t0, `"".`, pkg+".", -1)
    23  }
    24  
    25  // accumulate all type information from .6 files.
    26  // check for inconsistencies.
    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  /*
    34   *	package import data
    35   */
    36  type Import struct {
    37  	prefix string // "type", "var", "func", "const"
    38  	name   string
    39  	def    string
    40  	file   string
    41  }
    42  
    43  // importmap records type information about imported symbols to detect inconsistencies.
    44  // Entries are keyed by qualified symbol name (e.g., "runtime.Callers" or "net/url.Error").
    45  var importmap = map[string]*Import{}
    46  
    47  func lookupImport(name string) *Import {
    48  	if x, ok := importmap[name]; ok {
    49  		return x
    50  	}
    51  	x := &Import{name: name}
    52  	importmap[name] = x
    53  	return x
    54  }
    55  
    56  func ldpkg(f *obj.Biobuf, pkg string, length int64, filename string, whence int) {
    57  	var p0, p1 int
    58  
    59  	if Debug['g'] != 0 {
    60  		return
    61  	}
    62  
    63  	if int64(int(length)) != length {
    64  		fmt.Fprintf(os.Stderr, "%s: too much pkg data in %s\n", os.Args[0], filename)
    65  		if Debug['u'] != 0 {
    66  			errorexit()
    67  		}
    68  		return
    69  	}
    70  
    71  	bdata := make([]byte, length)
    72  	if int64(obj.Bread(f, bdata)) != length {
    73  		fmt.Fprintf(os.Stderr, "%s: short pkg read %s\n", os.Args[0], filename)
    74  		if Debug['u'] != 0 {
    75  			errorexit()
    76  		}
    77  		return
    78  	}
    79  	data := string(bdata)
    80  
    81  	// first \n$$ marks beginning of exports - skip rest of line
    82  	p0 = strings.Index(data, "\n$$")
    83  	if p0 < 0 {
    84  		if Debug['u'] != 0 && whence != ArchiveObj {
    85  			Exitf("cannot find export data in %s", filename)
    86  		}
    87  		return
    88  	}
    89  
    90  	// \n$$B marks the beginning of binary export data - don't skip over the B
    91  	p0 += 3
    92  	for p0 < len(data) && data[p0] != '\n' && data[p0] != 'B' {
    93  		p0++
    94  	}
    95  
    96  	// second marks end of exports / beginning of local data
    97  	p1 = strings.Index(data[p0:], "\n$$\n")
    98  	if p1 < 0 {
    99  		fmt.Fprintf(os.Stderr, "%s: cannot find end of exports in %s\n", os.Args[0], filename)
   100  		if Debug['u'] != 0 {
   101  			errorexit()
   102  		}
   103  		return
   104  	}
   105  	p1 += p0
   106  
   107  	for p0 < p1 && data[p0] != 'B' && (data[p0] == ' ' || data[p0] == '\t' || data[p0] == '\n') {
   108  		p0++
   109  	}
   110  	// don't check this section if we have binary (B) export data
   111  	// TODO fix this eventually
   112  	if p0 < p1 && data[p0] != 'B' {
   113  		if !strings.HasPrefix(data[p0:], "package ") {
   114  			fmt.Fprintf(os.Stderr, "%s: bad package section in %s - %.20s\n", os.Args[0], filename, data[p0:])
   115  			if Debug['u'] != 0 {
   116  				errorexit()
   117  			}
   118  			return
   119  		}
   120  
   121  		p0 += 8
   122  		for p0 < p1 && (data[p0] == ' ' || data[p0] == '\t' || data[p0] == '\n') {
   123  			p0++
   124  		}
   125  		pname := p0
   126  		for p0 < p1 && data[p0] != ' ' && data[p0] != '\t' && data[p0] != '\n' {
   127  			p0++
   128  		}
   129  		if Debug['u'] != 0 && whence != ArchiveObj && (p0+6 > p1 || !strings.HasPrefix(data[p0:], " safe\n")) {
   130  			Exitf("load of unsafe package %s", filename)
   131  		}
   132  
   133  		name := data[pname:p0]
   134  		for p0 < p1 && data[p0] != '\n' {
   135  			p0++
   136  		}
   137  		if p0 < p1 {
   138  			p0++
   139  		}
   140  
   141  		if pkg == "main" && name != "main" {
   142  			Exitf("%s: not package main (package %s)", filename, name)
   143  		}
   144  
   145  		loadpkgdata(filename, pkg, data[p0:p1])
   146  	}
   147  
   148  	// __.PKGDEF has no cgo section - those are in the C compiler-generated object files.
   149  	if whence == Pkgdef {
   150  		return
   151  	}
   152  
   153  	// look for cgo section
   154  	p0 = strings.Index(data[p1:], "\n$$  // cgo")
   155  	if p0 >= 0 {
   156  		p0 += p1
   157  		i := strings.IndexByte(data[p0+1:], '\n')
   158  		if i < 0 {
   159  			fmt.Fprintf(os.Stderr, "%s: found $$ // cgo but no newline in %s\n", os.Args[0], filename)
   160  			if Debug['u'] != 0 {
   161  				errorexit()
   162  			}
   163  			return
   164  		}
   165  		p0 += 1 + i
   166  
   167  		p1 = strings.Index(data[p0:], "\n$$")
   168  		if p1 < 0 {
   169  			p1 = strings.Index(data[p0:], "\n!\n")
   170  		}
   171  		if p1 < 0 {
   172  			fmt.Fprintf(os.Stderr, "%s: cannot find end of // cgo section in %s\n", os.Args[0], filename)
   173  			if Debug['u'] != 0 {
   174  				errorexit()
   175  			}
   176  			return
   177  		}
   178  		p1 += p0
   179  
   180  		loadcgo(filename, pkg, data[p0:p1])
   181  	}
   182  }
   183  
   184  func loadpkgdata(file string, pkg string, data string) {
   185  	var prefix string
   186  	var name string
   187  	var def string
   188  
   189  	p := data
   190  	for parsepkgdata(file, pkg, &p, &prefix, &name, &def) > 0 {
   191  		x := lookupImport(name)
   192  		if x.prefix == "" {
   193  			x.prefix = prefix
   194  			x.def = def
   195  			x.file = file
   196  		} else if x.prefix != prefix {
   197  			fmt.Fprintf(os.Stderr, "%s: conflicting definitions for %s\n", os.Args[0], name)
   198  			fmt.Fprintf(os.Stderr, "%s:\t%s %s ...\n", x.file, x.prefix, name)
   199  			fmt.Fprintf(os.Stderr, "%s:\t%s %s ...\n", file, prefix, name)
   200  			nerrors++
   201  		} else if x.def != def {
   202  			fmt.Fprintf(os.Stderr, "%s: conflicting definitions for %s\n", os.Args[0], name)
   203  			fmt.Fprintf(os.Stderr, "%s:\t%s %s %s\n", x.file, x.prefix, name, x.def)
   204  			fmt.Fprintf(os.Stderr, "%s:\t%s %s %s\n", file, prefix, name, def)
   205  			nerrors++
   206  		}
   207  	}
   208  }
   209  
   210  func parsepkgdata(file string, pkg string, pp *string, prefixp *string, namep *string, defp *string) int {
   211  	// skip white space
   212  	p := *pp
   213  
   214  loop:
   215  	for len(p) > 0 && (p[0] == ' ' || p[0] == '\t' || p[0] == '\n') {
   216  		p = p[1:]
   217  	}
   218  	if len(p) == 0 || strings.HasPrefix(p, "$$\n") {
   219  		return 0
   220  	}
   221  
   222  	// prefix: (var|type|func|const)
   223  	prefix := p
   224  
   225  	if len(p) < 7 {
   226  		return -1
   227  	}
   228  	if strings.HasPrefix(p, "var ") {
   229  		p = p[4:]
   230  	} else if strings.HasPrefix(p, "type ") {
   231  		p = p[5:]
   232  	} else if strings.HasPrefix(p, "func ") {
   233  		p = p[5:]
   234  	} else if strings.HasPrefix(p, "const ") {
   235  		p = p[6:]
   236  	} else if strings.HasPrefix(p, "import ") {
   237  		p = p[7:]
   238  		for len(p) > 0 && p[0] != ' ' {
   239  			p = p[1:]
   240  		}
   241  		p = p[1:]
   242  		line := p
   243  		for len(p) > 0 && p[0] != '\n' {
   244  			p = p[1:]
   245  		}
   246  		if len(p) == 0 {
   247  			fmt.Fprintf(os.Stderr, "%s: %s: confused in import line\n", os.Args[0], file)
   248  			nerrors++
   249  			return -1
   250  		}
   251  		line = line[:len(line)-len(p)]
   252  		line = strings.TrimSuffix(line, " // indirect")
   253  		path, err := strconv.Unquote(line)
   254  		if err != nil {
   255  			fmt.Fprintf(os.Stderr, "%s: %s: confused in import path: %q\n", os.Args[0], file, line)
   256  			nerrors++
   257  			return -1
   258  		}
   259  		p = p[1:]
   260  		imported(pkg, path)
   261  		goto loop
   262  	} else {
   263  		fmt.Fprintf(os.Stderr, "%s: %s: confused in pkg data near <<%.40s>>\n", os.Args[0], file, prefix)
   264  		nerrors++
   265  		return -1
   266  	}
   267  
   268  	prefix = prefix[:len(prefix)-len(p)-1]
   269  
   270  	// name: a.b followed by space
   271  	name := p
   272  
   273  	inquote := false
   274  	for len(p) > 0 {
   275  		if p[0] == ' ' && !inquote {
   276  			break
   277  		}
   278  
   279  		if p[0] == '\\' {
   280  			p = p[1:]
   281  		} else if p[0] == '"' {
   282  			inquote = !inquote
   283  		}
   284  
   285  		p = p[1:]
   286  	}
   287  
   288  	if len(p) == 0 {
   289  		return -1
   290  	}
   291  	name = name[:len(name)-len(p)]
   292  	p = p[1:]
   293  
   294  	// def: free form to new line
   295  	def := p
   296  
   297  	for len(p) > 0 && p[0] != '\n' {
   298  		p = p[1:]
   299  	}
   300  	if len(p) == 0 {
   301  		return -1
   302  	}
   303  	def = def[:len(def)-len(p)]
   304  	var defbuf *bytes.Buffer
   305  	p = p[1:]
   306  
   307  	// include methods on successive lines in def of named type
   308  	var meth string
   309  	for parsemethod(&p, &meth) > 0 {
   310  		if defbuf == nil {
   311  			defbuf = new(bytes.Buffer)
   312  			defbuf.WriteString(def)
   313  		}
   314  		defbuf.WriteString("\n\t")
   315  		defbuf.WriteString(meth)
   316  	}
   317  	if defbuf != nil {
   318  		def = defbuf.String()
   319  	}
   320  
   321  	name = expandpkg(name, pkg)
   322  	def = expandpkg(def, pkg)
   323  
   324  	// done
   325  	*pp = p
   326  
   327  	*prefixp = prefix
   328  	*namep = name
   329  	*defp = def
   330  	return 1
   331  }
   332  
   333  func parsemethod(pp *string, methp *string) int {
   334  	// skip white space
   335  	p := *pp
   336  
   337  	for len(p) > 0 && (p[0] == ' ' || p[0] == '\t') {
   338  		p = p[1:]
   339  	}
   340  	if len(p) == 0 {
   341  		return 0
   342  	}
   343  
   344  	// might be a comment about the method
   345  	if strings.HasPrefix(p, "//") {
   346  		goto useline
   347  	}
   348  
   349  	// if it says "func (", it's a method
   350  	if strings.HasPrefix(p, "func (") {
   351  		goto useline
   352  	}
   353  	return 0
   354  
   355  	// definition to end of line
   356  useline:
   357  	*methp = p
   358  
   359  	for len(p) > 0 && p[0] != '\n' {
   360  		p = p[1:]
   361  	}
   362  	if len(p) == 0 {
   363  		fmt.Fprintf(os.Stderr, "%s: lost end of line in method definition\n", os.Args[0])
   364  		*pp = ""
   365  		return -1
   366  	}
   367  
   368  	*methp = (*methp)[:len(*methp)-len(p)]
   369  	*pp = p[1:]
   370  	return 1
   371  }
   372  
   373  func loadcgo(file string, pkg string, p string) {
   374  	var next string
   375  	var q string
   376  	var f []string
   377  	var local string
   378  	var remote string
   379  	var lib string
   380  	var s *LSym
   381  
   382  	p0 := ""
   383  	for ; p != ""; p = next {
   384  		if i := strings.Index(p, "\n"); i >= 0 {
   385  			p, next = p[:i], p[i+1:]
   386  		} else {
   387  			next = ""
   388  		}
   389  
   390  		p0 = p // save for error message
   391  		f = tokenize(p)
   392  		if len(f) == 0 {
   393  			continue
   394  		}
   395  
   396  		if f[0] == "cgo_import_dynamic" {
   397  			if len(f) < 2 || len(f) > 4 {
   398  				goto err
   399  			}
   400  
   401  			local = f[1]
   402  			remote = local
   403  			if len(f) > 2 {
   404  				remote = f[2]
   405  			}
   406  			lib = ""
   407  			if len(f) > 3 {
   408  				lib = f[3]
   409  			}
   410  
   411  			if Debug['d'] != 0 {
   412  				fmt.Fprintf(os.Stderr, "%s: %s: cannot use dynamic imports with -d flag\n", os.Args[0], file)
   413  				nerrors++
   414  				return
   415  			}
   416  
   417  			if local == "_" && remote == "_" {
   418  				// allow #pragma dynimport _ _ "foo.so"
   419  				// to force a link of foo.so.
   420  				havedynamic = 1
   421  
   422  				if HEADTYPE == obj.Hdarwin {
   423  					Machoadddynlib(lib)
   424  				} else {
   425  					dynlib = append(dynlib, lib)
   426  				}
   427  				continue
   428  			}
   429  
   430  			local = expandpkg(local, pkg)
   431  			q = ""
   432  			if i := strings.Index(remote, "#"); i >= 0 {
   433  				remote, q = remote[:i], remote[i+1:]
   434  			}
   435  			s = Linklookup(Ctxt, local, 0)
   436  			if local != f[1] {
   437  			}
   438  			if s.Type == 0 || s.Type == obj.SXREF || s.Type == obj.SHOSTOBJ {
   439  				s.Dynimplib = lib
   440  				s.Extname = remote
   441  				s.Dynimpvers = q
   442  				if s.Type != obj.SHOSTOBJ {
   443  					s.Type = obj.SDYNIMPORT
   444  				}
   445  				havedynamic = 1
   446  			}
   447  
   448  			continue
   449  		}
   450  
   451  		if f[0] == "cgo_import_static" {
   452  			if len(f) != 2 {
   453  				goto err
   454  			}
   455  			local = f[1]
   456  			s = Linklookup(Ctxt, local, 0)
   457  			s.Type = obj.SHOSTOBJ
   458  			s.Size = 0
   459  			continue
   460  		}
   461  
   462  		if f[0] == "cgo_export_static" || f[0] == "cgo_export_dynamic" {
   463  			if len(f) < 2 || len(f) > 3 {
   464  				goto err
   465  			}
   466  			local = f[1]
   467  			if len(f) > 2 {
   468  				remote = f[2]
   469  			} else {
   470  				remote = local
   471  			}
   472  			local = expandpkg(local, pkg)
   473  			s = Linklookup(Ctxt, local, 0)
   474  
   475  			switch Buildmode {
   476  			case BuildmodeCShared, BuildmodeCArchive:
   477  				if s == Linklookup(Ctxt, "main", 0) {
   478  					continue
   479  				}
   480  			}
   481  
   482  			// export overrides import, for openbsd/cgo.
   483  			// see issue 4878.
   484  			if s.Dynimplib != "" {
   485  				s.Dynimplib = ""
   486  				s.Extname = ""
   487  				s.Dynimpvers = ""
   488  				s.Type = 0
   489  			}
   490  
   491  			if s.Cgoexport == 0 {
   492  				s.Extname = remote
   493  				dynexp = append(dynexp, s)
   494  			} else if s.Extname != remote {
   495  				fmt.Fprintf(os.Stderr, "%s: conflicting cgo_export directives: %s as %s and %s\n", os.Args[0], s.Name, s.Extname, remote)
   496  				nerrors++
   497  				return
   498  			}
   499  
   500  			if f[0] == "cgo_export_static" {
   501  				s.Cgoexport |= CgoExportStatic
   502  			} else {
   503  				s.Cgoexport |= CgoExportDynamic
   504  			}
   505  			if local != f[1] {
   506  			}
   507  			continue
   508  		}
   509  
   510  		if f[0] == "cgo_dynamic_linker" {
   511  			if len(f) != 2 {
   512  				goto err
   513  			}
   514  
   515  			if Debug['I'] == 0 {
   516  				if interpreter != "" && interpreter != f[1] {
   517  					fmt.Fprintf(os.Stderr, "%s: conflict dynlinker: %s and %s\n", os.Args[0], interpreter, f[1])
   518  					nerrors++
   519  					return
   520  				}
   521  
   522  				interpreter = f[1]
   523  			}
   524  
   525  			continue
   526  		}
   527  
   528  		if f[0] == "cgo_ldflag" {
   529  			if len(f) != 2 {
   530  				goto err
   531  			}
   532  			ldflag = append(ldflag, f[1])
   533  			continue
   534  		}
   535  	}
   536  
   537  	return
   538  
   539  err:
   540  	fmt.Fprintf(os.Stderr, "%s: %s: invalid dynimport line: %s\n", os.Args[0], file, p0)
   541  	nerrors++
   542  }
   543  
   544  var seenlib = make(map[string]bool)
   545  
   546  func adddynlib(lib string) {
   547  	if seenlib[lib] || Linkmode == LinkExternal {
   548  		return
   549  	}
   550  	seenlib[lib] = true
   551  
   552  	if Iself {
   553  		s := Linklookup(Ctxt, ".dynstr", 0)
   554  		if s.Size == 0 {
   555  			Addstring(s, "")
   556  		}
   557  		Elfwritedynent(Linklookup(Ctxt, ".dynamic", 0), DT_NEEDED, uint64(Addstring(s, lib)))
   558  	} else {
   559  		Diag("adddynlib: unsupported binary format")
   560  	}
   561  }
   562  
   563  func Adddynsym(ctxt *Link, s *LSym) {
   564  	if s.Dynid >= 0 || Linkmode == LinkExternal {
   565  		return
   566  	}
   567  
   568  	if Iself {
   569  		Elfadddynsym(ctxt, s)
   570  	} else if HEADTYPE == obj.Hdarwin {
   571  		Diag("adddynsym: missed symbol %s (%s)", s.Name, s.Extname)
   572  	} else if HEADTYPE == obj.Hwindows {
   573  		// already taken care of
   574  	} else {
   575  		Diag("adddynsym: unsupported binary format")
   576  	}
   577  }
   578  
   579  var markq *LSym
   580  
   581  var emarkq *LSym
   582  
   583  func mark1(s *LSym, parent *LSym) {
   584  	if s == nil || s.Reachable {
   585  		return
   586  	}
   587  	if strings.HasPrefix(s.Name, "go.weak.") {
   588  		return
   589  	}
   590  	s.Reachable = true
   591  	s.Reachparent = parent
   592  	if markq == nil {
   593  		markq = s
   594  	} else {
   595  		emarkq.Queue = s
   596  	}
   597  	emarkq = s
   598  }
   599  
   600  func mark(s *LSym) {
   601  	mark1(s, nil)
   602  }
   603  
   604  func markflood() {
   605  	var a *Auto
   606  	var i int
   607  
   608  	for s := markq; s != nil; s = s.Queue {
   609  		if s.Type == obj.STEXT {
   610  			if Debug['v'] > 1 {
   611  				fmt.Fprintf(&Bso, "marktext %s\n", s.Name)
   612  			}
   613  			for a = s.Autom; a != nil; a = a.Link {
   614  				mark1(a.Gotype, s)
   615  			}
   616  		}
   617  
   618  		for i = 0; i < len(s.R); i++ {
   619  			mark1(s.R[i].Sym, s)
   620  		}
   621  		if s.Pcln != nil {
   622  			for i = 0; i < s.Pcln.Nfuncdata; i++ {
   623  				mark1(s.Pcln.Funcdata[i], s)
   624  			}
   625  		}
   626  
   627  		mark1(s.Gotype, s)
   628  		mark1(s.Sub, s)
   629  		mark1(s.Outer, s)
   630  	}
   631  }
   632  
   633  var markextra = []string{
   634  	"runtime.morestack",
   635  	"runtime.morestackx",
   636  	"runtime.morestack00",
   637  	"runtime.morestack10",
   638  	"runtime.morestack01",
   639  	"runtime.morestack11",
   640  	"runtime.morestack8",
   641  	"runtime.morestack16",
   642  	"runtime.morestack24",
   643  	"runtime.morestack32",
   644  	"runtime.morestack40",
   645  	"runtime.morestack48",
   646  	// on arm, lock in the div/mod helpers too
   647  	"_div",
   648  	"_divu",
   649  	"_mod",
   650  	"_modu",
   651  }
   652  
   653  func deadcode() {
   654  	if Debug['v'] != 0 {
   655  		fmt.Fprintf(&Bso, "%5.2f deadcode\n", obj.Cputime())
   656  	}
   657  
   658  	if Buildmode == BuildmodeShared {
   659  		// Mark all symbols defined in this library as reachable when
   660  		// building a shared library.
   661  		for s := Ctxt.Allsym; s != nil; s = s.Allsym {
   662  			if s.Type != 0 && s.Type != obj.SDYNIMPORT {
   663  				mark(s)
   664  			}
   665  		}
   666  		markflood()
   667  	} else {
   668  		mark(Linklookup(Ctxt, INITENTRY, 0))
   669  		if Linkshared && Buildmode == BuildmodeExe {
   670  			mark(Linkrlookup(Ctxt, "main.main", 0))
   671  			mark(Linkrlookup(Ctxt, "main.init", 0))
   672  		}
   673  		for i := 0; i < len(markextra); i++ {
   674  			mark(Linklookup(Ctxt, markextra[i], 0))
   675  		}
   676  
   677  		for i := 0; i < len(dynexp); i++ {
   678  			mark(dynexp[i])
   679  		}
   680  		markflood()
   681  
   682  		// keep each beginning with 'typelink.' if the symbol it points at is being kept.
   683  		for s := Ctxt.Allsym; s != nil; s = s.Allsym {
   684  			if strings.HasPrefix(s.Name, "go.typelink.") {
   685  				s.Reachable = len(s.R) == 1 && s.R[0].Sym.Reachable
   686  			}
   687  		}
   688  
   689  		// remove dead text but keep file information (z symbols).
   690  		var last *LSym
   691  
   692  		for s := Ctxt.Textp; s != nil; s = s.Next {
   693  			if !s.Reachable {
   694  				continue
   695  			}
   696  
   697  			// NOTE: Removing s from old textp and adding to new, shorter textp.
   698  			if last == nil {
   699  				Ctxt.Textp = s
   700  			} else {
   701  				last.Next = s
   702  			}
   703  			last = s
   704  		}
   705  
   706  		if last == nil {
   707  			Ctxt.Textp = nil
   708  			Ctxt.Etextp = nil
   709  		} else {
   710  			last.Next = nil
   711  			Ctxt.Etextp = last
   712  		}
   713  	}
   714  
   715  	for s := Ctxt.Allsym; s != nil; s = s.Allsym {
   716  		if strings.HasPrefix(s.Name, "go.weak.") {
   717  			s.Special = 1 // do not lay out in data segment
   718  			s.Reachable = true
   719  			s.Hide = 1
   720  		}
   721  	}
   722  
   723  	// record field tracking references
   724  	var buf bytes.Buffer
   725  	var p *LSym
   726  	for s := Ctxt.Allsym; s != nil; s = s.Allsym {
   727  		if strings.HasPrefix(s.Name, "go.track.") {
   728  			s.Special = 1 // do not lay out in data segment
   729  			s.Hide = 1
   730  			if s.Reachable {
   731  				buf.WriteString(s.Name[9:])
   732  				for p = s.Reachparent; p != nil; p = p.Reachparent {
   733  					buf.WriteString("\t")
   734  					buf.WriteString(p.Name)
   735  				}
   736  				buf.WriteString("\n")
   737  			}
   738  
   739  			s.Type = obj.SCONST
   740  			s.Value = 0
   741  		}
   742  	}
   743  
   744  	if tracksym == "" {
   745  		return
   746  	}
   747  	s := Linklookup(Ctxt, tracksym, 0)
   748  	if !s.Reachable {
   749  		return
   750  	}
   751  	addstrdata(tracksym, buf.String())
   752  }
   753  
   754  func doweak() {
   755  	var t *LSym
   756  
   757  	// resolve weak references only if
   758  	// target symbol will be in binary anyway.
   759  	for s := Ctxt.Allsym; s != nil; s = s.Allsym {
   760  		if strings.HasPrefix(s.Name, "go.weak.") {
   761  			t = Linkrlookup(Ctxt, s.Name[8:], int(s.Version))
   762  			if t != nil && t.Type != 0 && t.Reachable {
   763  				s.Value = t.Value
   764  				s.Type = t.Type
   765  				s.Outer = t
   766  			} else {
   767  				s.Type = obj.SCONST
   768  				s.Value = 0
   769  			}
   770  
   771  			continue
   772  		}
   773  	}
   774  }
   775  
   776  func addexport() {
   777  	if HEADTYPE == obj.Hdarwin {
   778  		return
   779  	}
   780  
   781  	for _, exp := range dynexp {
   782  		Adddynsym(Ctxt, exp)
   783  	}
   784  	for _, lib := range dynlib {
   785  		adddynlib(lib)
   786  	}
   787  }
   788  
   789  type Pkg struct {
   790  	mark    bool
   791  	checked bool
   792  	path    string
   793  	impby   []*Pkg
   794  }
   795  
   796  var (
   797  	// pkgmap records the imported-by relationship between packages.
   798  	// Entries are keyed by package path (e.g., "runtime" or "net/url").
   799  	pkgmap = map[string]*Pkg{}
   800  
   801  	pkgall []*Pkg
   802  )
   803  
   804  func lookupPkg(path string) *Pkg {
   805  	if p, ok := pkgmap[path]; ok {
   806  		return p
   807  	}
   808  	p := &Pkg{path: path}
   809  	pkgmap[path] = p
   810  	pkgall = append(pkgall, p)
   811  	return p
   812  }
   813  
   814  // imported records that package pkg imports package imp.
   815  func imported(pkg, imp string) {
   816  	// everyone imports runtime, even runtime.
   817  	if imp == "runtime" {
   818  		return
   819  	}
   820  
   821  	p := lookupPkg(pkg)
   822  	i := lookupPkg(imp)
   823  	i.impby = append(i.impby, p)
   824  }
   825  
   826  func (p *Pkg) cycle() *Pkg {
   827  	if p.checked {
   828  		return nil
   829  	}
   830  
   831  	if p.mark {
   832  		nerrors++
   833  		fmt.Printf("import cycle:\n")
   834  		fmt.Printf("\t%s\n", p.path)
   835  		return p
   836  	}
   837  
   838  	p.mark = true
   839  	for _, q := range p.impby {
   840  		if bad := q.cycle(); bad != nil {
   841  			p.mark = false
   842  			p.checked = true
   843  			fmt.Printf("\timports %s\n", p.path)
   844  			if bad == p {
   845  				return nil
   846  			}
   847  			return bad
   848  		}
   849  	}
   850  
   851  	p.checked = true
   852  	p.mark = false
   853  	return nil
   854  }
   855  
   856  func importcycles() {
   857  	for _, p := range pkgall {
   858  		p.cycle()
   859  	}
   860  }
   861  
   862  func setlinkmode(arg string) {
   863  	if arg == "internal" {
   864  		Linkmode = LinkInternal
   865  	} else if arg == "external" {
   866  		Linkmode = LinkExternal
   867  	} else if arg == "auto" {
   868  		Linkmode = LinkAuto
   869  	} else {
   870  		Exitf("unknown link mode -linkmode %s", arg)
   871  	}
   872  }