github.com/stingnevermore/go@v0.0.0-20180120041312-3810f5bfed72/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  	"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  }