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

View as plain text