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

View as plain text