gtsocial-umbx

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

sym.go (12293B)


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