Source file src/cmd/internal/obj/sym.go

     1  // Derived from Inferno utils/6l/obj.c and utils/6l/span.c
     2  // https://bitbucket.org/inferno-os/inferno-os/src/master/utils/6l/obj.c
     3  // https://bitbucket.org/inferno-os/inferno-os/src/master/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 obj
    33  
    34  import (
    35  	"cmd/internal/goobj"
    36  	"cmd/internal/objabi"
    37  	"crypto/md5"
    38  	"fmt"
    39  	"internal/buildcfg"
    40  	"log"
    41  	"math"
    42  	"sort"
    43  )
    44  
    45  func Linknew(arch *LinkArch) *Link {
    46  	ctxt := new(Link)
    47  	ctxt.hash = make(map[string]*LSym)
    48  	ctxt.funchash = make(map[string]*LSym)
    49  	ctxt.statichash = make(map[string]*LSym)
    50  	ctxt.Arch = arch
    51  	ctxt.Pathname = objabi.WorkingDir()
    52  
    53  	if err := ctxt.Headtype.Set(buildcfg.GOOS); err != nil {
    54  		log.Fatalf("unknown goos %s", buildcfg.GOOS)
    55  	}
    56  
    57  	ctxt.Flag_optimize = true
    58  	return ctxt
    59  }
    60  
    61  // LookupDerived looks up or creates the symbol with name derived from symbol s.
    62  // The resulting symbol will be static iff s is.
    63  func (ctxt *Link) LookupDerived(s *LSym, name string) *LSym {
    64  	if s.Static() {
    65  		return ctxt.LookupStatic(name)
    66  	}
    67  	return ctxt.Lookup(name)
    68  }
    69  
    70  // LookupStatic looks up the static symbol with name name.
    71  // If it does not exist, it creates it.
    72  func (ctxt *Link) LookupStatic(name string) *LSym {
    73  	s := ctxt.statichash[name]
    74  	if s == nil {
    75  		s = &LSym{Name: name, Attribute: AttrStatic}
    76  		ctxt.statichash[name] = s
    77  	}
    78  	return s
    79  }
    80  
    81  // LookupABI looks up a symbol with the given ABI.
    82  // If it does not exist, it creates it.
    83  func (ctxt *Link) LookupABI(name string, abi ABI) *LSym {
    84  	return ctxt.LookupABIInit(name, abi, nil)
    85  }
    86  
    87  // LookupABI looks up a symbol with the given ABI.
    88  // If it does not exist, it creates it and
    89  // passes it to init for one-time initialization.
    90  func (ctxt *Link) LookupABIInit(name string, abi ABI, init func(s *LSym)) *LSym {
    91  	var hash map[string]*LSym
    92  	switch abi {
    93  	case ABI0:
    94  		hash = ctxt.hash
    95  	case ABIInternal:
    96  		hash = ctxt.funchash
    97  	default:
    98  		panic("unknown ABI")
    99  	}
   100  
   101  	ctxt.hashmu.Lock()
   102  	s := hash[name]
   103  	if s == nil {
   104  		s = &LSym{Name: name}
   105  		s.SetABI(abi)
   106  		hash[name] = s
   107  		if init != nil {
   108  			init(s)
   109  		}
   110  	}
   111  	ctxt.hashmu.Unlock()
   112  	return s
   113  }
   114  
   115  // Lookup looks up the symbol with name name.
   116  // If it does not exist, it creates it.
   117  func (ctxt *Link) Lookup(name string) *LSym {
   118  	return ctxt.LookupInit(name, nil)
   119  }
   120  
   121  // LookupInit looks up the symbol with name name.
   122  // If it does not exist, it creates it and
   123  // passes it to init for one-time initialization.
   124  func (ctxt *Link) LookupInit(name string, init func(s *LSym)) *LSym {
   125  	ctxt.hashmu.Lock()
   126  	s := ctxt.hash[name]
   127  	if s == nil {
   128  		s = &LSym{Name: name}
   129  		ctxt.hash[name] = s
   130  		if init != nil {
   131  			init(s)
   132  		}
   133  	}
   134  	ctxt.hashmu.Unlock()
   135  	return s
   136  }
   137  
   138  func (ctxt *Link) Float32Sym(f float32) *LSym {
   139  	i := math.Float32bits(f)
   140  	name := fmt.Sprintf("$f32.%08x", i)
   141  	return ctxt.LookupInit(name, func(s *LSym) {
   142  		s.Size = 4
   143  		s.WriteFloat32(ctxt, 0, f)
   144  		s.Type = objabi.SRODATA
   145  		s.Set(AttrLocal, true)
   146  		s.Set(AttrContentAddressable, true)
   147  		ctxt.constSyms = append(ctxt.constSyms, s)
   148  	})
   149  }
   150  
   151  func (ctxt *Link) Float64Sym(f float64) *LSym {
   152  	i := math.Float64bits(f)
   153  	name := fmt.Sprintf("$f64.%016x", i)
   154  	return ctxt.LookupInit(name, func(s *LSym) {
   155  		s.Size = 8
   156  		s.WriteFloat64(ctxt, 0, f)
   157  		s.Type = objabi.SRODATA
   158  		s.Set(AttrLocal, true)
   159  		s.Set(AttrContentAddressable, true)
   160  		ctxt.constSyms = append(ctxt.constSyms, s)
   161  	})
   162  }
   163  
   164  func (ctxt *Link) Int64Sym(i int64) *LSym {
   165  	name := fmt.Sprintf("$i64.%016x", uint64(i))
   166  	return ctxt.LookupInit(name, func(s *LSym) {
   167  		s.Size = 8
   168  		s.WriteInt(ctxt, 0, 8, i)
   169  		s.Type = objabi.SRODATA
   170  		s.Set(AttrLocal, true)
   171  		s.Set(AttrContentAddressable, true)
   172  		ctxt.constSyms = append(ctxt.constSyms, s)
   173  	})
   174  }
   175  
   176  // GCLocalsSym generates a content-addressable sym containing data.
   177  func (ctxt *Link) GCLocalsSym(data []byte) *LSym {
   178  	return ctxt.LookupInit(fmt.Sprintf("gclocals·%x", md5.Sum(data)), func(lsym *LSym) {
   179  		lsym.P = data
   180  		lsym.Set(AttrContentAddressable, true)
   181  	})
   182  }
   183  
   184  // Assign index to symbols.
   185  // asm is set to true if this is called by the assembler (i.e. not the compiler),
   186  // in which case all the symbols are non-package (for now).
   187  func (ctxt *Link) NumberSyms() {
   188  	if ctxt.Headtype == objabi.Haix {
   189  		// Data must be sorted to keep a constant order in TOC symbols.
   190  		// As they are created during Progedit, two symbols can be switched between
   191  		// two different compilations. Therefore, BuildID will be different.
   192  		// TODO: find a better place and optimize to only sort TOC symbols
   193  		sort.Slice(ctxt.Data, func(i, j int) bool {
   194  			return ctxt.Data[i].Name < ctxt.Data[j].Name
   195  		})
   196  	}
   197  
   198  	// Constant symbols are created late in the concurrent phase. Sort them
   199  	// to ensure a deterministic order.
   200  	sort.Slice(ctxt.constSyms, func(i, j int) bool {
   201  		return ctxt.constSyms[i].Name < ctxt.constSyms[j].Name
   202  	})
   203  	ctxt.Data = append(ctxt.Data, ctxt.constSyms...)
   204  	ctxt.constSyms = nil
   205  
   206  	ctxt.pkgIdx = make(map[string]int32)
   207  	ctxt.defs = []*LSym{}
   208  	ctxt.hashed64defs = []*LSym{}
   209  	ctxt.hasheddefs = []*LSym{}
   210  	ctxt.nonpkgdefs = []*LSym{}
   211  
   212  	var idx, hashedidx, hashed64idx, nonpkgidx int32
   213  	ctxt.traverseSyms(traverseDefs|traversePcdata, func(s *LSym) {
   214  		// if Pkgpath is unknown, cannot hash symbols with relocations, as it
   215  		// may reference named symbols whose names are not fully expanded.
   216  		if s.ContentAddressable() && (ctxt.Pkgpath != "" || len(s.R) == 0) {
   217  			if s.Size <= 8 && len(s.R) == 0 && contentHashSection(s) == 0 {
   218  				// We can use short hash only for symbols without relocations.
   219  				// Don't use short hash for symbols that belong in a particular section
   220  				// or require special handling (such as type symbols).
   221  				s.PkgIdx = goobj.PkgIdxHashed64
   222  				s.SymIdx = hashed64idx
   223  				if hashed64idx != int32(len(ctxt.hashed64defs)) {
   224  					panic("bad index")
   225  				}
   226  				ctxt.hashed64defs = append(ctxt.hashed64defs, s)
   227  				hashed64idx++
   228  			} else {
   229  				s.PkgIdx = goobj.PkgIdxHashed
   230  				s.SymIdx = hashedidx
   231  				if hashedidx != int32(len(ctxt.hasheddefs)) {
   232  					panic("bad index")
   233  				}
   234  				ctxt.hasheddefs = append(ctxt.hasheddefs, s)
   235  				hashedidx++
   236  			}
   237  		} else if isNonPkgSym(ctxt, s) {
   238  			s.PkgIdx = goobj.PkgIdxNone
   239  			s.SymIdx = nonpkgidx
   240  			if nonpkgidx != int32(len(ctxt.nonpkgdefs)) {
   241  				panic("bad index")
   242  			}
   243  			ctxt.nonpkgdefs = append(ctxt.nonpkgdefs, s)
   244  			nonpkgidx++
   245  		} else {
   246  			s.PkgIdx = goobj.PkgIdxSelf
   247  			s.SymIdx = idx
   248  			if idx != int32(len(ctxt.defs)) {
   249  				panic("bad index")
   250  			}
   251  			ctxt.defs = append(ctxt.defs, s)
   252  			idx++
   253  		}
   254  		s.Set(AttrIndexed, true)
   255  	})
   256  
   257  	ipkg := int32(1) // 0 is invalid index
   258  	nonpkgdef := nonpkgidx
   259  	ctxt.traverseSyms(traverseRefs|traverseAux, func(rs *LSym) {
   260  		if rs.PkgIdx != goobj.PkgIdxInvalid {
   261  			return
   262  		}
   263  		if !ctxt.Flag_linkshared {
   264  			// Assign special index for builtin symbols.
   265  			// Don't do it when linking against shared libraries, as the runtime
   266  			// may be in a different library.
   267  			if i := goobj.BuiltinIdx(rs.Name, int(rs.ABI())); i != -1 {
   268  				rs.PkgIdx = goobj.PkgIdxBuiltin
   269  				rs.SymIdx = int32(i)
   270  				rs.Set(AttrIndexed, true)
   271  				return
   272  			}
   273  		}
   274  		pkg := rs.Pkg
   275  		if rs.ContentAddressable() {
   276  			// for now, only support content-addressable symbols that are always locally defined.
   277  			panic("hashed refs unsupported for now")
   278  		}
   279  		if pkg == "" || pkg == "\"\"" || pkg == "_" || !rs.Indexed() {
   280  			rs.PkgIdx = goobj.PkgIdxNone
   281  			rs.SymIdx = nonpkgidx
   282  			rs.Set(AttrIndexed, true)
   283  			if nonpkgidx != nonpkgdef+int32(len(ctxt.nonpkgrefs)) {
   284  				panic("bad index")
   285  			}
   286  			ctxt.nonpkgrefs = append(ctxt.nonpkgrefs, rs)
   287  			nonpkgidx++
   288  			return
   289  		}
   290  		if k, ok := ctxt.pkgIdx[pkg]; ok {
   291  			rs.PkgIdx = k
   292  			return
   293  		}
   294  		rs.PkgIdx = ipkg
   295  		ctxt.pkgIdx[pkg] = ipkg
   296  		ipkg++
   297  	})
   298  }
   299  
   300  // Returns whether s is a non-package symbol, which needs to be referenced
   301  // by name instead of by index.
   302  func isNonPkgSym(ctxt *Link, s *LSym) bool {
   303  	if ctxt.IsAsm && !s.Static() {
   304  		// asm symbols are referenced by name only, except static symbols
   305  		// which are file-local and can be referenced by index.
   306  		return true
   307  	}
   308  	if ctxt.Flag_linkshared {
   309  		// The referenced symbol may be in a different shared library so
   310  		// the linker cannot see its index.
   311  		return true
   312  	}
   313  	if s.Pkg == "_" {
   314  		// The frontend uses package "_" to mark symbols that should not
   315  		// be referenced by index, e.g. linkname'd symbols.
   316  		return true
   317  	}
   318  	if s.DuplicateOK() {
   319  		// Dupok symbol needs to be dedup'd by name.
   320  		return true
   321  	}
   322  	return false
   323  }
   324  
   325  // StaticNamePref is the prefix the front end applies to static temporary
   326  // variables. When turned into LSyms, these can be tagged as static so
   327  // as to avoid inserting them into the linker's name lookup tables.
   328  const StaticNamePref = ".stmp_"
   329  
   330  type traverseFlag uint32
   331  
   332  const (
   333  	traverseDefs traverseFlag = 1 << iota
   334  	traverseRefs
   335  	traverseAux
   336  	traversePcdata
   337  
   338  	traverseAll = traverseDefs | traverseRefs | traverseAux | traversePcdata
   339  )
   340  
   341  // Traverse symbols based on flag, call fn for each symbol.
   342  func (ctxt *Link) traverseSyms(flag traverseFlag, fn func(*LSym)) {
   343  	fnNoNil := func(s *LSym) {
   344  		if s != nil {
   345  			fn(s)
   346  		}
   347  	}
   348  	lists := [][]*LSym{ctxt.Text, ctxt.Data}
   349  	for _, list := range lists {
   350  		for _, s := range list {
   351  			if flag&traverseDefs != 0 {
   352  				fn(s)
   353  			}
   354  			if flag&traverseRefs != 0 {
   355  				for _, r := range s.R {
   356  					fnNoNil(r.Sym)
   357  				}
   358  			}
   359  			if flag&traverseAux != 0 {
   360  				fnNoNil(s.Gotype)
   361  				if s.Type == objabi.STEXT {
   362  					f := func(parent *LSym, aux *LSym) {
   363  						fn(aux)
   364  					}
   365  					ctxt.traverseFuncAux(flag, s, f)
   366  				}
   367  			}
   368  			if flag&traversePcdata != 0 && s.Type == objabi.STEXT {
   369  				fi := s.Func().Pcln
   370  				fnNoNil(fi.Pcsp)
   371  				fnNoNil(fi.Pcfile)
   372  				fnNoNil(fi.Pcline)
   373  				fnNoNil(fi.Pcinline)
   374  				for _, d := range fi.Pcdata {
   375  					fnNoNil(d)
   376  				}
   377  			}
   378  		}
   379  	}
   380  }
   381  
   382  func (ctxt *Link) traverseFuncAux(flag traverseFlag, fsym *LSym, fn func(parent *LSym, aux *LSym)) {
   383  	fninfo := fsym.Func()
   384  	pc := &fninfo.Pcln
   385  	if flag&traverseAux == 0 {
   386  		// NB: should it become necessary to walk aux sym reloc references
   387  		// without walking the aux syms themselves, this can be changed.
   388  		panic("should not be here")
   389  	}
   390  	for _, d := range pc.Funcdata {
   391  		if d != nil {
   392  			fn(fsym, d)
   393  		}
   394  	}
   395  	files := ctxt.PosTable.FileTable()
   396  	usedFiles := make([]goobj.CUFileIndex, 0, len(pc.UsedFiles))
   397  	for f := range pc.UsedFiles {
   398  		usedFiles = append(usedFiles, f)
   399  	}
   400  	sort.Slice(usedFiles, func(i, j int) bool { return usedFiles[i] < usedFiles[j] })
   401  	for _, f := range usedFiles {
   402  		if filesym := ctxt.Lookup(files[f]); filesym != nil {
   403  			fn(fsym, filesym)
   404  		}
   405  	}
   406  	for _, call := range pc.InlTree.nodes {
   407  		if call.Func != nil {
   408  			fn(fsym, call.Func)
   409  		}
   410  		f, _ := linkgetlineFromPos(ctxt, call.Pos)
   411  		if filesym := ctxt.Lookup(f); filesym != nil {
   412  			fn(fsym, filesym)
   413  		}
   414  	}
   415  
   416  	dwsyms := []*LSym{fninfo.dwarfRangesSym, fninfo.dwarfLocSym, fninfo.dwarfDebugLinesSym, fninfo.dwarfInfoSym}
   417  	for _, dws := range dwsyms {
   418  		if dws == nil || dws.Size == 0 {
   419  			continue
   420  		}
   421  		fn(fsym, dws)
   422  		if flag&traverseRefs != 0 {
   423  			for _, r := range dws.R {
   424  				if r.Sym != nil {
   425  					fn(dws, r.Sym)
   426  				}
   427  			}
   428  		}
   429  	}
   430  }
   431  
   432  // Traverse aux symbols, calling fn for each sym/aux pair.
   433  func (ctxt *Link) traverseAuxSyms(flag traverseFlag, fn func(parent *LSym, aux *LSym)) {
   434  	lists := [][]*LSym{ctxt.Text, ctxt.Data}
   435  	for _, list := range lists {
   436  		for _, s := range list {
   437  			if s.Gotype != nil {
   438  				if flag&traverseDefs != 0 {
   439  					fn(s, s.Gotype)
   440  				}
   441  			}
   442  			if s.Type != objabi.STEXT {
   443  				continue
   444  			}
   445  			ctxt.traverseFuncAux(flag, s, fn)
   446  		}
   447  	}
   448  }
   449  

View as plain text