...

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

     1	// Derived from Inferno utils/6l/obj.c and utils/6l/span.c
     2	// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/6l/obj.c
     3	// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/6l/span.c
     4	//
     5	//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
     6	//	Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
     7	//	Portions Copyright © 1997-1999 Vita Nuova Limited
     8	//	Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
     9	//	Portions Copyright © 2004,2006 Bruce Ellis
    10	//	Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
    11	//	Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
    12	//	Portions Copyright © 2009 The Go Authors. All rights reserved.
    13	//
    14	// Permission is hereby granted, free of charge, to any person obtaining a copy
    15	// of this software and associated documentation files (the "Software"), to deal
    16	// in the Software without restriction, including without limitation the rights
    17	// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
    18	// copies of the Software, and to permit persons to whom the Software is
    19	// furnished to do so, subject to the following conditions:
    20	//
    21	// The above copyright notice and this permission notice shall be included in
    22	// all copies or substantial portions of the Software.
    23	//
    24	// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    25	// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    26	// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
    27	// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    28	// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    29	// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    30	// THE SOFTWARE.
    31	
    32	package ld
    33	
    34	import (
    35		"cmd/link/internal/sym"
    36		"io/ioutil"
    37		"log"
    38		"os"
    39		"path"
    40		"path/filepath"
    41		"strconv"
    42		"strings"
    43	)
    44	
    45	func (ctxt *Link) readImportCfg(file string) {
    46		ctxt.PackageFile = make(map[string]string)
    47		ctxt.PackageShlib = make(map[string]string)
    48		data, err := ioutil.ReadFile(file)
    49		if err != nil {
    50			log.Fatalf("-importcfg: %v", err)
    51		}
    52	
    53		for lineNum, line := range strings.Split(string(data), "\n") {
    54			lineNum++ // 1-based
    55			line = strings.TrimSpace(line)
    56			if line == "" {
    57				continue
    58			}
    59			if line == "" || strings.HasPrefix(line, "#") {
    60				continue
    61			}
    62	
    63			var verb, args string
    64			if i := strings.Index(line, " "); i < 0 {
    65				verb = line
    66			} else {
    67				verb, args = line[:i], strings.TrimSpace(line[i+1:])
    68			}
    69			var before, after string
    70			if i := strings.Index(args, "="); i >= 0 {
    71				before, after = args[:i], args[i+1:]
    72			}
    73			switch verb {
    74			default:
    75				log.Fatalf("%s:%d: unknown directive %q", file, lineNum, verb)
    76			case "packagefile":
    77				if before == "" || after == "" {
    78					log.Fatalf(`%s:%d: invalid packagefile: syntax is "packagefile path=filename"`, file, lineNum)
    79				}
    80				ctxt.PackageFile[before] = after
    81			case "packageshlib":
    82				if before == "" || after == "" {
    83					log.Fatalf(`%s:%d: invalid packageshlib: syntax is "packageshlib path=filename"`, file, lineNum)
    84				}
    85				ctxt.PackageShlib[before] = after
    86			}
    87		}
    88	}
    89	
    90	func pkgname(ctxt *Link, lib string) string {
    91		name := path.Clean(lib)
    92	
    93		// When using importcfg, we have the final package name.
    94		if ctxt.PackageFile != nil {
    95			return name
    96		}
    97	
    98		// runtime.a -> runtime, runtime.6 -> runtime
    99		pkg := name
   100		if len(pkg) >= 2 && pkg[len(pkg)-2] == '.' {
   101			pkg = pkg[:len(pkg)-2]
   102		}
   103		return pkg
   104	}
   105	
   106	func findlib(ctxt *Link, lib string) (string, bool) {
   107		name := path.Clean(lib)
   108	
   109		var pname string
   110		isshlib := false
   111	
   112		if ctxt.linkShared && ctxt.PackageShlib[name] != "" {
   113			pname = ctxt.PackageShlib[name]
   114			isshlib = true
   115		} else if ctxt.PackageFile != nil {
   116			pname = ctxt.PackageFile[name]
   117			if pname == "" {
   118				ctxt.Logf("cannot find package %s (using -importcfg)\n", name)
   119				return "", false
   120			}
   121		} else {
   122			if filepath.IsAbs(name) {
   123				pname = name
   124			} else {
   125				pkg := pkgname(ctxt, lib)
   126				// Add .a if needed; the new -importcfg modes
   127				// do not put .a into the package name anymore.
   128				// This only matters when people try to mix
   129				// compiles using -importcfg with links not using -importcfg,
   130				// such as when running quick things like
   131				// 'go tool compile x.go && go tool link x.o'
   132				// by hand against a standard library built using -importcfg.
   133				if !strings.HasSuffix(name, ".a") && !strings.HasSuffix(name, ".o") {
   134					name += ".a"
   135				}
   136				// try dot, -L "libdir", and then goroot.
   137				for _, dir := range ctxt.Libdir {
   138					if ctxt.linkShared {
   139						pname = filepath.Join(dir, pkg+".shlibname")
   140						if _, err := os.Stat(pname); err == nil {
   141							isshlib = true
   142							break
   143						}
   144					}
   145					pname = filepath.Join(dir, name)
   146					if _, err := os.Stat(pname); err == nil {
   147						break
   148					}
   149				}
   150			}
   151			pname = path.Clean(pname)
   152		}
   153	
   154		return pname, isshlib
   155	}
   156	
   157	func addlib(ctxt *Link, src string, obj string, lib string) *sym.Library {
   158		pkg := pkgname(ctxt, lib)
   159	
   160		// already loaded?
   161		if l := ctxt.LibraryByPkg[pkg]; l != nil {
   162			return l
   163		}
   164	
   165		pname, isshlib := findlib(ctxt, lib)
   166	
   167		if ctxt.Debugvlog > 1 {
   168			ctxt.Logf("%5.2f addlib: %s %s pulls in %s isshlib %v\n", elapsed(), obj, src, pname, isshlib)
   169		}
   170	
   171		if isshlib {
   172			return addlibpath(ctxt, src, obj, "", pkg, pname)
   173		}
   174		return addlibpath(ctxt, src, obj, pname, pkg, "")
   175	}
   176	
   177	/*
   178	 * add library to library list, return added library.
   179	 *	srcref: src file referring to package
   180	 *	objref: object file referring to package
   181	 *	file: object file, e.g., /home/rsc/go/pkg/container/vector.a
   182	 *	pkg: package import path, e.g. container/vector
   183	 *	shlib: path to shared library, or .shlibname file holding path
   184	 */
   185	func addlibpath(ctxt *Link, srcref string, objref string, file string, pkg string, shlib string) *sym.Library {
   186		if l := ctxt.LibraryByPkg[pkg]; l != nil {
   187			return l
   188		}
   189	
   190		if ctxt.Debugvlog > 1 {
   191			ctxt.Logf("%5.2f addlibpath: srcref: %s objref: %s file: %s pkg: %s shlib: %s\n", Cputime(), srcref, objref, file, pkg, shlib)
   192		}
   193	
   194		l := &sym.Library{}
   195		ctxt.LibraryByPkg[pkg] = l
   196		ctxt.Library = append(ctxt.Library, l)
   197		l.Objref = objref
   198		l.Srcref = srcref
   199		l.File = file
   200		l.Pkg = pkg
   201		if shlib != "" {
   202			if strings.HasSuffix(shlib, ".shlibname") {
   203				data, err := ioutil.ReadFile(shlib)
   204				if err != nil {
   205					Errorf(nil, "cannot read %s: %v", shlib, err)
   206				}
   207				shlib = strings.TrimSpace(string(data))
   208			}
   209			l.Shlib = shlib
   210		}
   211		return l
   212	}
   213	
   214	func atolwhex(s string) int64 {
   215		n, _ := strconv.ParseInt(s, 0, 64)
   216		return n
   217	}
   218	

View as plain text