github.com/hlts2/go@v0.0.0-20170904000733-812b34efaed8/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  	"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 == objabi.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 = ctxt.Syms.Lookup(local, 0)
   191  			if s.Type == 0 || s.Type == SXREF || s.Type == SHOSTOBJ {
   192  				s.Dynimplib = lib
   193  				s.Extname = remote
   194  				s.Dynimpvers = q
   195  				if s.Type != SHOSTOBJ {
   196  					s.Type = SDYNIMPORT
   197  				}
   198  				havedynamic = 1
   199  			}
   200  
   201  			continue
   202  		}
   203  
   204  		if f[0] == "cgo_import_static" {
   205  			if len(f) != 2 {
   206  				goto err
   207  			}
   208  			local = f[1]
   209  			s = ctxt.Syms.Lookup(local, 0)
   210  			s.Type = SHOSTOBJ
   211  			s.Size = 0
   212  			continue
   213  		}
   214  
   215  		if f[0] == "cgo_export_static" || f[0] == "cgo_export_dynamic" {
   216  			if len(f) < 2 || len(f) > 3 {
   217  				goto err
   218  			}
   219  			local = f[1]
   220  			if len(f) > 2 {
   221  				remote = f[2]
   222  			} else {
   223  				remote = local
   224  			}
   225  			local = expandpkg(local, pkg)
   226  			s = ctxt.Syms.Lookup(local, 0)
   227  
   228  			switch Buildmode {
   229  			case BuildmodeCShared, BuildmodeCArchive, BuildmodePlugin:
   230  				if s == ctxt.Syms.Lookup("main", 0) {
   231  					continue
   232  				}
   233  			}
   234  
   235  			// export overrides import, for openbsd/cgo.
   236  			// see issue 4878.
   237  			if s.Dynimplib != "" {
   238  				s.Dynimplib = ""
   239  				s.Extname = ""
   240  				s.Dynimpvers = ""
   241  				s.Type = 0
   242  			}
   243  
   244  			if !s.Attr.CgoExport() {
   245  				s.Extname = remote
   246  				dynexp = append(dynexp, s)
   247  			} else if s.Extname != remote {
   248  				fmt.Fprintf(os.Stderr, "%s: conflicting cgo_export directives: %s as %s and %s\n", os.Args[0], s.Name, s.Extname, remote)
   249  				nerrors++
   250  				return
   251  			}
   252  
   253  			if f[0] == "cgo_export_static" {
   254  				s.Attr |= AttrCgoExportStatic
   255  			} else {
   256  				s.Attr |= AttrCgoExportDynamic
   257  			}
   258  			continue
   259  		}
   260  
   261  		if f[0] == "cgo_dynamic_linker" {
   262  			if len(f) != 2 {
   263  				goto err
   264  			}
   265  
   266  			if *flagInterpreter == "" {
   267  				if interpreter != "" && interpreter != f[1] {
   268  					fmt.Fprintf(os.Stderr, "%s: conflict dynlinker: %s and %s\n", os.Args[0], interpreter, f[1])
   269  					nerrors++
   270  					return
   271  				}
   272  
   273  				interpreter = f[1]
   274  			}
   275  
   276  			continue
   277  		}
   278  
   279  		if f[0] == "cgo_ldflag" {
   280  			if len(f) != 2 {
   281  				goto err
   282  			}
   283  			ldflag = append(ldflag, f[1])
   284  			continue
   285  		}
   286  	}
   287  
   288  	return
   289  
   290  err:
   291  	fmt.Fprintf(os.Stderr, "%s: %s: invalid dynimport line: %s\n", os.Args[0], file, p0)
   292  	nerrors++
   293  }
   294  
   295  var seenlib = make(map[string]bool)
   296  
   297  func adddynlib(ctxt *Link, lib string) {
   298  	if seenlib[lib] || Linkmode == LinkExternal {
   299  		return
   300  	}
   301  	seenlib[lib] = true
   302  
   303  	if Iself {
   304  		s := ctxt.Syms.Lookup(".dynstr", 0)
   305  		if s.Size == 0 {
   306  			Addstring(s, "")
   307  		}
   308  		Elfwritedynent(ctxt, ctxt.Syms.Lookup(".dynamic", 0), DT_NEEDED, uint64(Addstring(s, lib)))
   309  	} else {
   310  		Errorf(nil, "adddynlib: unsupported binary format")
   311  	}
   312  }
   313  
   314  func Adddynsym(ctxt *Link, s *Symbol) {
   315  	if s.Dynid >= 0 || Linkmode == LinkExternal {
   316  		return
   317  	}
   318  
   319  	if Iself {
   320  		elfadddynsym(ctxt, s)
   321  	} else if Headtype == objabi.Hdarwin {
   322  		Errorf(s, "adddynsym: missed symbol (Extname=%s)", s.Extname)
   323  	} else if Headtype == objabi.Hwindows {
   324  		// already taken care of
   325  	} else {
   326  		Errorf(s, "adddynsym: unsupported binary format")
   327  	}
   328  }
   329  
   330  func fieldtrack(ctxt *Link) {
   331  	// record field tracking references
   332  	var buf bytes.Buffer
   333  	for _, s := range ctxt.Syms.Allsym {
   334  		if strings.HasPrefix(s.Name, "go.track.") {
   335  			s.Attr |= AttrSpecial // do not lay out in data segment
   336  			s.Attr |= AttrNotInSymbolTable
   337  			if s.Attr.Reachable() {
   338  				buf.WriteString(s.Name[9:])
   339  				for p := s.Reachparent; p != nil; p = p.Reachparent {
   340  					buf.WriteString("\t")
   341  					buf.WriteString(p.Name)
   342  				}
   343  				buf.WriteString("\n")
   344  			}
   345  
   346  			s.Type = SCONST
   347  			s.Value = 0
   348  		}
   349  	}
   350  
   351  	if *flagFieldTrack == "" {
   352  		return
   353  	}
   354  	s := ctxt.Syms.Lookup(*flagFieldTrack, 0)
   355  	if !s.Attr.Reachable() {
   356  		return
   357  	}
   358  	addstrdata(ctxt, *flagFieldTrack, buf.String())
   359  	s.Type = SDATA
   360  }
   361  
   362  func (ctxt *Link) addexport() {
   363  	if Headtype == objabi.Hdarwin {
   364  		return
   365  	}
   366  
   367  	for _, exp := range dynexp {
   368  		Adddynsym(ctxt, exp)
   369  	}
   370  	for _, lib := range dynlib {
   371  		adddynlib(ctxt, lib)
   372  	}
   373  }
   374  
   375  type Pkg struct {
   376  	mark    bool
   377  	checked bool
   378  	path    string
   379  	impby   []*Pkg
   380  }
   381  
   382  var pkgall []*Pkg
   383  
   384  func (p *Pkg) cycle() *Pkg {
   385  	if p.checked {
   386  		return nil
   387  	}
   388  
   389  	if p.mark {
   390  		nerrors++
   391  		fmt.Printf("import cycle:\n")
   392  		fmt.Printf("\t%s\n", p.path)
   393  		return p
   394  	}
   395  
   396  	p.mark = true
   397  	for _, q := range p.impby {
   398  		if bad := q.cycle(); bad != nil {
   399  			p.mark = false
   400  			p.checked = true
   401  			fmt.Printf("\timports %s\n", p.path)
   402  			if bad == p {
   403  				return nil
   404  			}
   405  			return bad
   406  		}
   407  	}
   408  
   409  	p.checked = true
   410  	p.mark = false
   411  	return nil
   412  }
   413  
   414  func importcycles() {
   415  	for _, p := range pkgall {
   416  		p.cycle()
   417  	}
   418  }