Black Lives Matter. Support the Equal Justice Initiative.

Source file src/cmd/link/internal/ld/go.go

Documentation: cmd/link/internal/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/obj"
    13  	"cmd/internal/objabi"
    14  	"cmd/internal/sys"
    15  	"cmd/link/internal/loader"
    16  	"cmd/link/internal/sym"
    17  	"debug/elf"
    18  	"encoding/json"
    19  	"fmt"
    20  	"io"
    21  	"os"
    22  	"sort"
    23  	"strconv"
    24  	"strings"
    25  )
    26  
    27  // go-specific code shared across loaders (5l, 6l, 8l).
    28  
    29  // replace all "". with pkg.
    30  func expandpkg(t0 string, pkg string) string {
    31  	return strings.Replace(t0, `"".`, pkg+".", -1)
    32  }
    33  
    34  // TODO:
    35  //	generate debugging section in binary.
    36  //	once the dust settles, try to move some code to
    37  //		libmach, so that other linkers and ar can share.
    38  
    39  func ldpkg(ctxt *Link, f *bio.Reader, lib *sym.Library, length int64, filename string) {
    40  	if *flagG {
    41  		return
    42  	}
    43  
    44  	if int64(int(length)) != length {
    45  		fmt.Fprintf(os.Stderr, "%s: too much pkg data in %s\n", os.Args[0], filename)
    46  		return
    47  	}
    48  
    49  	bdata := make([]byte, length)
    50  	if _, err := io.ReadFull(f, bdata); err != nil {
    51  		fmt.Fprintf(os.Stderr, "%s: short pkg read %s\n", os.Args[0], filename)
    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 == "main" {
    65  			lib.Main = true
    66  		}
    67  		if line == "" {
    68  			break
    69  		}
    70  	}
    71  
    72  	// look for cgo section
    73  	p0 := strings.Index(data, "\n$$  // cgo")
    74  	var p1 int
    75  	if p0 >= 0 {
    76  		p0 += p1
    77  		i := strings.IndexByte(data[p0+1:], '\n')
    78  		if i < 0 {
    79  			fmt.Fprintf(os.Stderr, "%s: found $$ // cgo but no newline in %s\n", os.Args[0], filename)
    80  			return
    81  		}
    82  		p0 += 1 + i
    83  
    84  		p1 = strings.Index(data[p0:], "\n$$")
    85  		if p1 < 0 {
    86  			p1 = strings.Index(data[p0:], "\n!\n")
    87  		}
    88  		if p1 < 0 {
    89  			fmt.Fprintf(os.Stderr, "%s: cannot find end of // cgo section in %s\n", os.Args[0], filename)
    90  			return
    91  		}
    92  		p1 += p0
    93  		loadcgo(ctxt, filename, objabi.PathToPrefix(lib.Pkg), data[p0:p1])
    94  	}
    95  }
    96  
    97  func loadcgo(ctxt *Link, file string, pkg string, p string) {
    98  	var directives [][]string
    99  	if err := json.NewDecoder(strings.NewReader(p)).Decode(&directives); err != nil {
   100  		fmt.Fprintf(os.Stderr, "%s: %s: failed decoding cgo directives: %v\n", os.Args[0], file, err)
   101  		nerrors++
   102  		return
   103  	}
   104  
   105  	// Record the directives. We'll process them later after Symbols are created.
   106  	ctxt.cgodata = append(ctxt.cgodata, cgodata{file, pkg, directives})
   107  }
   108  
   109  // Set symbol attributes or flags based on cgo directives.
   110  // Any newly discovered HOSTOBJ syms are added to 'hostObjSyms'.
   111  func setCgoAttr(ctxt *Link, file string, pkg string, directives [][]string, hostObjSyms map[loader.Sym]struct{}) {
   112  	l := ctxt.loader
   113  	for _, f := range directives {
   114  		switch f[0] {
   115  		case "cgo_import_dynamic":
   116  			if len(f) < 2 || len(f) > 4 {
   117  				break
   118  			}
   119  
   120  			local := f[1]
   121  			remote := local
   122  			if len(f) > 2 {
   123  				remote = f[2]
   124  			}
   125  			lib := ""
   126  			if len(f) > 3 {
   127  				lib = f[3]
   128  			}
   129  
   130  			if *FlagD {
   131  				fmt.Fprintf(os.Stderr, "%s: %s: cannot use dynamic imports with -d flag\n", os.Args[0], file)
   132  				nerrors++
   133  				return
   134  			}
   135  
   136  			if local == "_" && remote == "_" {
   137  				// allow #pragma dynimport _ _ "foo.so"
   138  				// to force a link of foo.so.
   139  				havedynamic = 1
   140  
   141  				if ctxt.HeadType == objabi.Hdarwin {
   142  					machoadddynlib(lib, ctxt.LinkMode)
   143  				} else {
   144  					dynlib = append(dynlib, lib)
   145  				}
   146  				continue
   147  			}
   148  
   149  			local = expandpkg(local, pkg)
   150  			q := ""
   151  			if i := strings.Index(remote, "#"); i >= 0 {
   152  				remote, q = remote[:i], remote[i+1:]
   153  			}
   154  			s := l.LookupOrCreateSym(local, 0)
   155  			st := l.SymType(s)
   156  			if st == 0 || st == sym.SXREF || st == sym.SBSS || st == sym.SNOPTRBSS || st == sym.SHOSTOBJ {
   157  				l.SetSymDynimplib(s, lib)
   158  				l.SetSymExtname(s, remote)
   159  				l.SetSymDynimpvers(s, q)
   160  				if st != sym.SHOSTOBJ {
   161  					su := l.MakeSymbolUpdater(s)
   162  					su.SetType(sym.SDYNIMPORT)
   163  				} else {
   164  					hostObjSyms[s] = struct{}{}
   165  				}
   166  				havedynamic = 1
   167  				if lib != "" && ctxt.IsDarwin() {
   168  					machoadddynlib(lib, ctxt.LinkMode)
   169  				}
   170  			}
   171  
   172  			continue
   173  
   174  		case "cgo_import_static":
   175  			if len(f) != 2 {
   176  				break
   177  			}
   178  			local := f[1]
   179  
   180  			s := l.LookupOrCreateSym(local, 0)
   181  			su := l.MakeSymbolUpdater(s)
   182  			su.SetType(sym.SHOSTOBJ)
   183  			su.SetSize(0)
   184  			hostObjSyms[s] = struct{}{}
   185  			continue
   186  
   187  		case "cgo_export_static", "cgo_export_dynamic":
   188  			if len(f) < 2 || len(f) > 4 {
   189  				break
   190  			}
   191  			local := f[1]
   192  			remote := local
   193  			if len(f) > 2 {
   194  				remote = f[2]
   195  			}
   196  			local = expandpkg(local, pkg)
   197  			// The compiler adds a fourth argument giving
   198  			// the definition ABI of function symbols.
   199  			abi := obj.ABI0
   200  			if len(f) > 3 {
   201  				var ok bool
   202  				abi, ok = obj.ParseABI(f[3])
   203  				if !ok {
   204  					fmt.Fprintf(os.Stderr, "%s: bad ABI in cgo_export directive %s\n", os.Args[0], f)
   205  					nerrors++
   206  					return
   207  				}
   208  			}
   209  
   210  			s := l.LookupOrCreateSym(local, sym.ABIToVersion(abi))
   211  
   212  			if l.SymType(s) == sym.SHOSTOBJ {
   213  				hostObjSyms[s] = struct{}{}
   214  			}
   215  
   216  			switch ctxt.BuildMode {
   217  			case BuildModeCShared, BuildModeCArchive, BuildModePlugin:
   218  				if s == l.Lookup("main", 0) {
   219  					continue
   220  				}
   221  			}
   222  
   223  			// export overrides import, for openbsd/cgo.
   224  			// see issue 4878.
   225  			if l.SymDynimplib(s) != "" {
   226  				l.SetSymDynimplib(s, "")
   227  				l.SetSymDynimpvers(s, "")
   228  				l.SetSymExtname(s, "")
   229  				var su *loader.SymbolBuilder
   230  				su = l.MakeSymbolUpdater(s)
   231  				su.SetType(0)
   232  			}
   233  
   234  			if !(l.AttrCgoExportStatic(s) || l.AttrCgoExportDynamic(s)) {
   235  				l.SetSymExtname(s, remote)
   236  			} else if l.SymExtname(s) != remote {
   237  				fmt.Fprintf(os.Stderr, "%s: conflicting cgo_export directives: %s as %s and %s\n", os.Args[0], l.SymName(s), l.SymExtname(s), remote)
   238  				nerrors++
   239  				return
   240  			}
   241  
   242  			// Mark exported symbols and also add them to
   243  			// the lists used for roots in the deadcode pass.
   244  			if f[0] == "cgo_export_static" {
   245  				if ctxt.LinkMode == LinkExternal && !l.AttrCgoExportStatic(s) {
   246  					// Static cgo exports appear
   247  					// in the exported symbol table.
   248  					ctxt.dynexp = append(ctxt.dynexp, s)
   249  				}
   250  				if ctxt.LinkMode == LinkInternal {
   251  					// For internal linking, we're
   252  					// responsible for resolving
   253  					// relocations from host objects.
   254  					// Record the right Go symbol
   255  					// version to use.
   256  					l.AddCgoExport(s)
   257  				}
   258  				l.SetAttrCgoExportStatic(s, true)
   259  			} else {
   260  				if ctxt.LinkMode == LinkInternal && !l.AttrCgoExportDynamic(s) {
   261  					// Dynamic cgo exports appear
   262  					// in the exported symbol table.
   263  					ctxt.dynexp = append(ctxt.dynexp, s)
   264  				}
   265  				l.SetAttrCgoExportDynamic(s, true)
   266  			}
   267  
   268  			continue
   269  
   270  		case "cgo_dynamic_linker":
   271  			if len(f) != 2 {
   272  				break
   273  			}
   274  
   275  			if *flagInterpreter == "" {
   276  				if interpreter != "" && interpreter != f[1] {
   277  					fmt.Fprintf(os.Stderr, "%s: conflict dynlinker: %s and %s\n", os.Args[0], interpreter, f[1])
   278  					nerrors++
   279  					return
   280  				}
   281  
   282  				interpreter = f[1]
   283  			}
   284  			continue
   285  
   286  		case "cgo_ldflag":
   287  			if len(f) != 2 {
   288  				break
   289  			}
   290  			ldflag = append(ldflag, f[1])
   291  			continue
   292  		}
   293  
   294  		fmt.Fprintf(os.Stderr, "%s: %s: invalid cgo directive: %q\n", os.Args[0], file, f)
   295  		nerrors++
   296  	}
   297  	return
   298  }
   299  
   300  // openbsdTrimLibVersion indicates whether a shared library is
   301  // versioned and if it is, returns the unversioned name. The
   302  // OpenBSD library naming scheme is lib<name>.so.<major>.<minor>
   303  func openbsdTrimLibVersion(lib string) (string, bool) {
   304  	parts := strings.Split(lib, ".")
   305  	if len(parts) != 4 {
   306  		return "", false
   307  	}
   308  	if parts[1] != "so" {
   309  		return "", false
   310  	}
   311  	if _, err := strconv.Atoi(parts[2]); err != nil {
   312  		return "", false
   313  	}
   314  	if _, err := strconv.Atoi(parts[3]); err != nil {
   315  		return "", false
   316  	}
   317  	return fmt.Sprintf("%s.%s", parts[0], parts[1]), true
   318  }
   319  
   320  // dedupLibrariesOpenBSD dedups a list of shared libraries, treating versioned
   321  // and unversioned libraries as equivalents. Versioned libraries are preferred
   322  // and retained over unversioned libraries. This avoids the situation where
   323  // the use of cgo results in a DT_NEEDED for a versioned library (for example,
   324  // libc.so.96.1), while a dynamic import specifies an unversioned library (for
   325  // example, libc.so) - this would otherwise result in two DT_NEEDED entries
   326  // for the same library, resulting in a failure when ld.so attempts to load
   327  // the Go binary.
   328  func dedupLibrariesOpenBSD(ctxt *Link, libs []string) []string {
   329  	libraries := make(map[string]string)
   330  	for _, lib := range libs {
   331  		if name, ok := openbsdTrimLibVersion(lib); ok {
   332  			// Record unversioned name as seen.
   333  			seenlib[name] = true
   334  			libraries[name] = lib
   335  		} else if _, ok := libraries[lib]; !ok {
   336  			libraries[lib] = lib
   337  		}
   338  	}
   339  
   340  	libs = nil
   341  	for _, lib := range libraries {
   342  		libs = append(libs, lib)
   343  	}
   344  	sort.Strings(libs)
   345  
   346  	return libs
   347  }
   348  
   349  func dedupLibraries(ctxt *Link, libs []string) []string {
   350  	if ctxt.Target.IsOpenbsd() {
   351  		return dedupLibrariesOpenBSD(ctxt, libs)
   352  	}
   353  	return libs
   354  }
   355  
   356  var seenlib = make(map[string]bool)
   357  
   358  func adddynlib(ctxt *Link, lib string) {
   359  	if seenlib[lib] || ctxt.LinkMode == LinkExternal {
   360  		return
   361  	}
   362  	seenlib[lib] = true
   363  
   364  	if ctxt.IsELF {
   365  		dsu := ctxt.loader.MakeSymbolUpdater(ctxt.DynStr)
   366  		if dsu.Size() == 0 {
   367  			dsu.Addstring("")
   368  		}
   369  		du := ctxt.loader.MakeSymbolUpdater(ctxt.Dynamic)
   370  		Elfwritedynent(ctxt.Arch, du, elf.DT_NEEDED, uint64(dsu.Addstring(lib)))
   371  	} else {
   372  		Errorf(nil, "adddynlib: unsupported binary format")
   373  	}
   374  }
   375  
   376  func Adddynsym(ldr *loader.Loader, target *Target, syms *ArchSyms, s loader.Sym) {
   377  	if ldr.SymDynid(s) >= 0 || target.LinkMode == LinkExternal {
   378  		return
   379  	}
   380  
   381  	if target.IsELF {
   382  		elfadddynsym(ldr, target, syms, s)
   383  	} else if target.HeadType == objabi.Hdarwin {
   384  		ldr.Errorf(s, "adddynsym: missed symbol (Extname=%s)", ldr.SymExtname(s))
   385  	} else if target.HeadType == objabi.Hwindows {
   386  		// already taken care of
   387  	} else {
   388  		ldr.Errorf(s, "adddynsym: unsupported binary format")
   389  	}
   390  }
   391  
   392  func fieldtrack(arch *sys.Arch, l *loader.Loader) {
   393  	var buf bytes.Buffer
   394  	for i := loader.Sym(1); i < loader.Sym(l.NSym()); i++ {
   395  		if name := l.SymName(i); strings.HasPrefix(name, "go.track.") {
   396  			if l.AttrReachable(i) {
   397  				l.SetAttrSpecial(i, true)
   398  				l.SetAttrNotInSymbolTable(i, true)
   399  				buf.WriteString(name[9:])
   400  				for p := l.Reachparent[i]; p != 0; p = l.Reachparent[p] {
   401  					buf.WriteString("\t")
   402  					buf.WriteString(l.SymName(p))
   403  				}
   404  				buf.WriteString("\n")
   405  			}
   406  		}
   407  	}
   408  	l.Reachparent = nil // we are done with it
   409  	if *flagFieldTrack == "" {
   410  		return
   411  	}
   412  	s := l.Lookup(*flagFieldTrack, 0)
   413  	if s == 0 || !l.AttrReachable(s) {
   414  		return
   415  	}
   416  	bld := l.MakeSymbolUpdater(s)
   417  	bld.SetType(sym.SDATA)
   418  	addstrdata(arch, l, *flagFieldTrack, buf.String())
   419  }
   420  
   421  func (ctxt *Link) addexport() {
   422  	// Track undefined external symbols during external link.
   423  	if ctxt.LinkMode == LinkExternal {
   424  		for _, s := range ctxt.Textp {
   425  			if ctxt.loader.AttrSpecial(s) || ctxt.loader.AttrSubSymbol(s) {
   426  				continue
   427  			}
   428  			relocs := ctxt.loader.Relocs(s)
   429  			for i := 0; i < relocs.Count(); i++ {
   430  				if rs := relocs.At(i).Sym(); rs != 0 {
   431  					if ctxt.loader.SymType(rs) == sym.Sxxx && !ctxt.loader.AttrLocal(rs) {
   432  						// sanity check
   433  						if len(ctxt.loader.Data(rs)) != 0 {
   434  							panic("expected no data on undef symbol")
   435  						}
   436  						su := ctxt.loader.MakeSymbolUpdater(rs)
   437  						su.SetType(sym.SUNDEFEXT)
   438  					}
   439  				}
   440  			}
   441  		}
   442  	}
   443  
   444  	// TODO(aix)
   445  	if ctxt.HeadType == objabi.Hdarwin || ctxt.HeadType == objabi.Haix {
   446  		return
   447  	}
   448  
   449  	// Add dynamic symbols.
   450  	for _, s := range ctxt.dynexp {
   451  		// Consistency check.
   452  		if !ctxt.loader.AttrReachable(s) {
   453  			panic("dynexp entry not reachable")
   454  		}
   455  
   456  		Adddynsym(ctxt.loader, &ctxt.Target, &ctxt.ArchSyms, s)
   457  	}
   458  
   459  	for _, lib := range dedupLibraries(ctxt, dynlib) {
   460  		adddynlib(ctxt, lib)
   461  	}
   462  }
   463  
   464  type Pkg struct {
   465  	mark    bool
   466  	checked bool
   467  	path    string
   468  	impby   []*Pkg
   469  }
   470  
   471  var pkgall []*Pkg
   472  
   473  func (p *Pkg) cycle() *Pkg {
   474  	if p.checked {
   475  		return nil
   476  	}
   477  
   478  	if p.mark {
   479  		nerrors++
   480  		fmt.Printf("import cycle:\n")
   481  		fmt.Printf("\t%s\n", p.path)
   482  		return p
   483  	}
   484  
   485  	p.mark = true
   486  	for _, q := range p.impby {
   487  		if bad := q.cycle(); bad != nil {
   488  			p.mark = false
   489  			p.checked = true
   490  			fmt.Printf("\timports %s\n", p.path)
   491  			if bad == p {
   492  				return nil
   493  			}
   494  			return bad
   495  		}
   496  	}
   497  
   498  	p.checked = true
   499  	p.mark = false
   500  	return nil
   501  }
   502  
   503  func importcycles() {
   504  	for _, p := range pkgall {
   505  		p.cycle()
   506  	}
   507  }
   508  

View as plain text