github.com/euank/go@v0.0.0-20160829210321-495514729181/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  }