github.com/Rookout/GoSDK@v0.1.48/pkg/services/assembler/internal/obj/sym.go (about)

     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  	"github.com/Rookout/GoSDK/pkg/services/assembler/internal/goobj"
    36  	"crypto/sha256"
    37  	"github.com/Rookout/GoSDK/pkg/services/assembler/internal/objabi"
    38  	"encoding/base64"
    39  	"fmt"
    40  	"github.com/Rookout/GoSDK/pkg/services/assembler/internal/buildcfg"
    41  	"log"
    42  	"math"
    43  	"sort"
    44  )
    45  
    46  func Linknew(arch *LinkArch) *Link {
    47  	ctxt := new(Link)
    48  	ctxt.hash = make(map[string]*LSym)
    49  	ctxt.funchash = make(map[string]*LSym)
    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  
    63  
    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  
    72  
    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  
    83  
    84  func (ctxt *Link) LookupABI(name string, abi ABI) *LSym {
    85  	return ctxt.LookupABIInit(name, abi, nil)
    86  }
    87  
    88  
    89  
    90  
    91  func (ctxt *Link) LookupABIInit(name string, abi ABI, init func(s *LSym)) *LSym {
    92  	var hash map[string]*LSym
    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  	ctxt.hashmu.Lock()
   103  	s := hash[name]
   104  	if s == nil {
   105  		s = &LSym{Name: name}
   106  		s.SetABI(abi)
   107  		hash[name] = s
   108  		if init != nil {
   109  			init(s)
   110  		}
   111  	}
   112  	ctxt.hashmu.Unlock()
   113  	return s
   114  }
   115  
   116  
   117  
   118  func (ctxt *Link) Lookup(name string) *LSym {
   119  	return ctxt.LookupInit(name, nil)
   120  }
   121  
   122  
   123  
   124  
   125  func (ctxt *Link) LookupInit(name string, init func(s *LSym)) *LSym {
   126  	ctxt.hashmu.Lock()
   127  	s := ctxt.hash[name]
   128  	if s == nil {
   129  		s = &LSym{Name: name}
   130  		ctxt.hash[name] = s
   131  		if init != nil {
   132  			init(s)
   133  		}
   134  	}
   135  	ctxt.hashmu.Unlock()
   136  	return s
   137  }
   138  
   139  func (ctxt *Link) Float32Sym(f float32) *LSym {
   140  	i := math.Float32bits(f)
   141  	name := fmt.Sprintf("$f32.%08x", i)
   142  	return ctxt.LookupInit(name, func(s *LSym) {
   143  		s.Size = 4
   144  		s.WriteFloat32(ctxt, 0, f)
   145  		s.Type = objabi.SRODATA
   146  		s.Set(AttrLocal, true)
   147  		s.Set(AttrContentAddressable, true)
   148  		ctxt.constSyms = append(ctxt.constSyms, s)
   149  	})
   150  }
   151  
   152  func (ctxt *Link) Float64Sym(f float64) *LSym {
   153  	i := math.Float64bits(f)
   154  	name := fmt.Sprintf("$f64.%016x", i)
   155  	return ctxt.LookupInit(name, func(s *LSym) {
   156  		s.Size = 8
   157  		s.WriteFloat64(ctxt, 0, f)
   158  		s.Type = objabi.SRODATA
   159  		s.Set(AttrLocal, true)
   160  		s.Set(AttrContentAddressable, true)
   161  		ctxt.constSyms = append(ctxt.constSyms, s)
   162  	})
   163  }
   164  
   165  func (ctxt *Link) Int64Sym(i int64) *LSym {
   166  	name := fmt.Sprintf("$i64.%016x", uint64(i))
   167  	return ctxt.LookupInit(name, func(s *LSym) {
   168  		s.Size = 8
   169  		s.WriteInt(ctxt, 0, 8, i)
   170  		s.Type = objabi.SRODATA
   171  		s.Set(AttrLocal, true)
   172  		s.Set(AttrContentAddressable, true)
   173  		ctxt.constSyms = append(ctxt.constSyms, s)
   174  	})
   175  }
   176  
   177  
   178  func (ctxt *Link) GCLocalsSym(data []byte) *LSym {
   179  	sum := sha256.Sum256(data)
   180  	str := base64.StdEncoding.EncodeToString(sum[:16])
   181  	return ctxt.LookupInit(fmt.Sprintf("gclocals·%s", str), func(lsym *LSym) {
   182  		lsym.P = data
   183  		lsym.Set(AttrContentAddressable, true)
   184  	})
   185  }
   186  
   187  
   188  
   189  
   190  func (ctxt *Link) NumberSyms() {
   191  	if ctxt.Headtype == objabi.Haix {
   192  		
   193  		
   194  		
   195  		
   196  		sort.Slice(ctxt.Data, func(i, j int) bool {
   197  			return ctxt.Data[i].Name < ctxt.Data[j].Name
   198  		})
   199  	}
   200  
   201  	
   202  	
   203  	sort.Slice(ctxt.constSyms, func(i, j int) bool {
   204  		return ctxt.constSyms[i].Name < ctxt.constSyms[j].Name
   205  	})
   206  	ctxt.Data = append(ctxt.Data, ctxt.constSyms...)
   207  	ctxt.constSyms = nil
   208  
   209  	ctxt.pkgIdx = make(map[string]int32)
   210  	ctxt.defs = []*LSym{}
   211  	ctxt.hashed64defs = []*LSym{}
   212  	ctxt.hasheddefs = []*LSym{}
   213  	ctxt.nonpkgdefs = []*LSym{}
   214  
   215  	var idx, hashedidx, hashed64idx, nonpkgidx int32
   216  	ctxt.traverseSyms(traverseDefs|traversePcdata, func(s *LSym) {
   217  		
   218  		
   219  		if s.ContentAddressable() && (ctxt.Pkgpath != "" || len(s.R) == 0) {
   220  			if s.Size <= 8 && len(s.R) == 0 && contentHashSection(s) == 0 {
   221  				
   222  				
   223  				
   224  				s.PkgIdx = goobj.PkgIdxHashed64
   225  				s.SymIdx = hashed64idx
   226  				if hashed64idx != int32(len(ctxt.hashed64defs)) {
   227  					panic("bad index")
   228  				}
   229  				ctxt.hashed64defs = append(ctxt.hashed64defs, s)
   230  				hashed64idx++
   231  			} else {
   232  				s.PkgIdx = goobj.PkgIdxHashed
   233  				s.SymIdx = hashedidx
   234  				if hashedidx != int32(len(ctxt.hasheddefs)) {
   235  					panic("bad index")
   236  				}
   237  				ctxt.hasheddefs = append(ctxt.hasheddefs, s)
   238  				hashedidx++
   239  			}
   240  		} else if isNonPkgSym(ctxt, s) {
   241  			s.PkgIdx = goobj.PkgIdxNone
   242  			s.SymIdx = nonpkgidx
   243  			if nonpkgidx != int32(len(ctxt.nonpkgdefs)) {
   244  				panic("bad index")
   245  			}
   246  			ctxt.nonpkgdefs = append(ctxt.nonpkgdefs, s)
   247  			nonpkgidx++
   248  		} else {
   249  			s.PkgIdx = goobj.PkgIdxSelf
   250  			s.SymIdx = idx
   251  			if idx != int32(len(ctxt.defs)) {
   252  				panic("bad index")
   253  			}
   254  			ctxt.defs = append(ctxt.defs, s)
   255  			idx++
   256  		}
   257  		s.Set(AttrIndexed, true)
   258  	})
   259  
   260  	ipkg := int32(1) 
   261  	nonpkgdef := nonpkgidx
   262  	ctxt.traverseSyms(traverseRefs|traverseAux, func(rs *LSym) {
   263  		if rs.PkgIdx != goobj.PkgIdxInvalid {
   264  			return
   265  		}
   266  		if !ctxt.Flag_linkshared {
   267  			
   268  			
   269  			
   270  			if i := goobj.BuiltinIdx(rs.Name, int(rs.ABI())); i != -1 {
   271  				rs.PkgIdx = goobj.PkgIdxBuiltin
   272  				rs.SymIdx = int32(i)
   273  				rs.Set(AttrIndexed, true)
   274  				return
   275  			}
   276  		}
   277  		pkg := rs.Pkg
   278  		if rs.ContentAddressable() {
   279  			
   280  			panic("hashed refs unsupported for now")
   281  		}
   282  		if pkg == "" || pkg == "\"\"" || pkg == "_" || !rs.Indexed() {
   283  			rs.PkgIdx = goobj.PkgIdxNone
   284  			rs.SymIdx = nonpkgidx
   285  			rs.Set(AttrIndexed, true)
   286  			if nonpkgidx != nonpkgdef+int32(len(ctxt.nonpkgrefs)) {
   287  				panic("bad index")
   288  			}
   289  			ctxt.nonpkgrefs = append(ctxt.nonpkgrefs, rs)
   290  			nonpkgidx++
   291  			return
   292  		}
   293  		if k, ok := ctxt.pkgIdx[pkg]; ok {
   294  			rs.PkgIdx = k
   295  			return
   296  		}
   297  		rs.PkgIdx = ipkg
   298  		ctxt.pkgIdx[pkg] = ipkg
   299  		ipkg++
   300  	})
   301  }
   302  
   303  
   304  
   305  func isNonPkgSym(ctxt *Link, s *LSym) bool {
   306  	if ctxt.IsAsm && !s.Static() {
   307  		
   308  		
   309  		return true
   310  	}
   311  	if ctxt.Flag_linkshared {
   312  		
   313  		
   314  		return true
   315  	}
   316  	if s.Pkg == "_" {
   317  		
   318  		
   319  		return true
   320  	}
   321  	if s.DuplicateOK() {
   322  		
   323  		return true
   324  	}
   325  	return false
   326  }
   327  
   328  
   329  
   330  
   331  const StaticNamePref = ".stmp_"
   332  
   333  type traverseFlag uint32
   334  
   335  const (
   336  	traverseDefs traverseFlag = 1 << iota
   337  	traverseRefs
   338  	traverseAux
   339  	traversePcdata
   340  
   341  	traverseAll = traverseDefs | traverseRefs | traverseAux | traversePcdata
   342  )
   343  
   344  
   345  func (ctxt *Link) traverseSyms(flag traverseFlag, fn func(*LSym)) {
   346  	fnNoNil := func(s *LSym) {
   347  		if s != nil {
   348  			fn(s)
   349  		}
   350  	}
   351  	lists := [][]*LSym{ctxt.Text, ctxt.Data}
   352  	files := ctxt.PosTable.FileTable()
   353  	for _, list := range lists {
   354  		for _, s := range list {
   355  			if flag&traverseDefs != 0 {
   356  				fn(s)
   357  			}
   358  			if flag&traverseRefs != 0 {
   359  				for _, r := range s.R {
   360  					fnNoNil(r.Sym)
   361  				}
   362  			}
   363  			if flag&traverseAux != 0 {
   364  				fnNoNil(s.Gotype)
   365  				if s.Type == objabi.STEXT {
   366  					f := func(parent *LSym, aux *LSym) {
   367  						fn(aux)
   368  					}
   369  					ctxt.traverseFuncAux(flag, s, f, files)
   370  				} else if v := s.VarInfo(); v != nil {
   371  					fnNoNil(v.dwarfInfoSym)
   372  				}
   373  			}
   374  			if flag&traversePcdata != 0 && s.Type == objabi.STEXT {
   375  				fi := s.Func().Pcln
   376  				fnNoNil(fi.Pcsp)
   377  				fnNoNil(fi.Pcfile)
   378  				fnNoNil(fi.Pcline)
   379  				fnNoNil(fi.Pcinline)
   380  				for _, d := range fi.Pcdata {
   381  					fnNoNil(d)
   382  				}
   383  			}
   384  		}
   385  	}
   386  }
   387  
   388  func (ctxt *Link) traverseFuncAux(flag traverseFlag, fsym *LSym, fn func(parent *LSym, aux *LSym), files []string) {
   389  	fninfo := fsym.Func()
   390  	pc := &fninfo.Pcln
   391  	if flag&traverseAux == 0 {
   392  		
   393  		
   394  		panic("should not be here")
   395  	}
   396  	for _, d := range pc.Funcdata {
   397  		if d != nil {
   398  			fn(fsym, d)
   399  		}
   400  	}
   401  	usedFiles := make([]goobj.CUFileIndex, 0, len(pc.UsedFiles))
   402  	for f := range pc.UsedFiles {
   403  		usedFiles = append(usedFiles, f)
   404  	}
   405  	sort.Slice(usedFiles, func(i, j int) bool { return usedFiles[i] < usedFiles[j] })
   406  	for _, f := range usedFiles {
   407  		if filesym := ctxt.Lookup(files[f]); filesym != nil {
   408  			fn(fsym, filesym)
   409  		}
   410  	}
   411  	for _, call := range pc.InlTree.nodes {
   412  		if call.Func != nil {
   413  			fn(fsym, call.Func)
   414  		}
   415  		f, _ := ctxt.getFileSymbolAndLine(call.Pos)
   416  		if filesym := ctxt.Lookup(f); filesym != nil {
   417  			fn(fsym, filesym)
   418  		}
   419  	}
   420  
   421  	auxsyms := []*LSym{fninfo.dwarfRangesSym, fninfo.dwarfLocSym, fninfo.dwarfDebugLinesSym, fninfo.dwarfInfoSym, fninfo.WasmImportSym, fninfo.sehUnwindInfoSym}
   422  	for _, s := range auxsyms {
   423  		if s == nil || s.Size == 0 {
   424  			continue
   425  		}
   426  		fn(fsym, s)
   427  		if flag&traverseRefs != 0 {
   428  			for _, r := range s.R {
   429  				if r.Sym != nil {
   430  					fn(s, r.Sym)
   431  				}
   432  			}
   433  		}
   434  	}
   435  }
   436  
   437  
   438  func (ctxt *Link) traverseAuxSyms(flag traverseFlag, fn func(parent *LSym, aux *LSym)) {
   439  	lists := [][]*LSym{ctxt.Text, ctxt.Data}
   440  	files := ctxt.PosTable.FileTable()
   441  	for _, list := range lists {
   442  		for _, s := range list {
   443  			if s.Gotype != nil {
   444  				if flag&traverseDefs != 0 {
   445  					fn(s, s.Gotype)
   446  				}
   447  			}
   448  			if s.Type == objabi.STEXT {
   449  				ctxt.traverseFuncAux(flag, s, fn, files)
   450  			} else if v := s.VarInfo(); v != nil && v.dwarfInfoSym != nil {
   451  				fn(s, v.dwarfInfoSym)
   452  			}
   453  		}
   454  	}
   455  }