github.com/bir3/gocompiler@v0.9.2202/src/cmd/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/bir3/gocompiler/src/cmd/internal/goobj" 36 "github.com/bir3/gocompiler/src/cmd/internal/notsha256" 37 "github.com/bir3/gocompiler/src/cmd/internal/objabi" 38 "encoding/base64" 39 "encoding/binary" 40 "fmt" 41 "github.com/bir3/gocompiler/src/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) Float32Sym(f float32) *LSym { 141 i := math.Float32bits(f) 142 name := fmt.Sprintf("$f32.%08x", i) 143 return ctxt.LookupInit(name, func(s *LSym) { 144 s.Size = 4 145 s.WriteFloat32(ctxt, 0, f) 146 s.Type = objabi.SRODATA 147 s.Set(AttrLocal, true) 148 s.Set(AttrContentAddressable, true) 149 ctxt.constSyms = append(ctxt.constSyms, s) 150 }) 151 } 152 153 func (ctxt *Link) Float64Sym(f float64) *LSym { 154 i := math.Float64bits(f) 155 name := fmt.Sprintf("$f64.%016x", i) 156 return ctxt.LookupInit(name, func(s *LSym) { 157 s.Size = 8 158 s.WriteFloat64(ctxt, 0, f) 159 s.Type = objabi.SRODATA 160 s.Set(AttrLocal, true) 161 s.Set(AttrContentAddressable, true) 162 ctxt.constSyms = append(ctxt.constSyms, s) 163 }) 164 } 165 166 func (ctxt *Link) Int32Sym(i int64) *LSym { 167 name := fmt.Sprintf("$i32.%08x", uint64(i)) 168 return ctxt.LookupInit(name, func(s *LSym) { 169 s.Size = 4 170 s.WriteInt(ctxt, 0, 4, i) 171 s.Type = objabi.SRODATA 172 s.Set(AttrLocal, true) 173 s.Set(AttrContentAddressable, true) 174 ctxt.constSyms = append(ctxt.constSyms, s) 175 }) 176 } 177 178 func (ctxt *Link) Int64Sym(i int64) *LSym { 179 name := fmt.Sprintf("$i64.%016x", uint64(i)) 180 return ctxt.LookupInit(name, func(s *LSym) { 181 s.Size = 8 182 s.WriteInt(ctxt, 0, 8, i) 183 s.Type = objabi.SRODATA 184 s.Set(AttrLocal, true) 185 s.Set(AttrContentAddressable, true) 186 ctxt.constSyms = append(ctxt.constSyms, s) 187 }) 188 } 189 190 func (ctxt *Link) Int128Sym(hi, lo int64) *LSym { 191 name := fmt.Sprintf("$i128.%016x%016x", uint64(hi), uint64(lo)) 192 return ctxt.LookupInit(name, func(s *LSym) { 193 s.Size = 16 194 if ctxt.Arch.ByteOrder == binary.LittleEndian { 195 s.WriteInt(ctxt, 0, 8, lo) 196 s.WriteInt(ctxt, 8, 8, hi) 197 } else { 198 s.WriteInt(ctxt, 0, 8, hi) 199 s.WriteInt(ctxt, 8, 8, lo) 200 } 201 s.Type = objabi.SRODATA 202 s.Set(AttrLocal, true) 203 s.Set(AttrContentAddressable, true) 204 ctxt.constSyms = append(ctxt.constSyms, s) 205 }) 206 } 207 208 // GCLocalsSym generates a content-addressable sym containing data. 209 func (ctxt *Link) GCLocalsSym(data []byte) *LSym { 210 sum := notsha256.Sum256(data) 211 str := base64.StdEncoding.EncodeToString(sum[:16]) 212 return ctxt.LookupInit(fmt.Sprintf("gclocals·%s", str), func(lsym *LSym) { 213 lsym.P = data 214 lsym.Set(AttrContentAddressable, true) 215 }) 216 } 217 218 // Assign index to symbols. 219 // asm is set to true if this is called by the assembler (i.e. not the compiler), 220 // in which case all the symbols are non-package (for now). 221 func (ctxt *Link) NumberSyms() { 222 if ctxt.Pkgpath == "" { 223 panic("NumberSyms called without package path") 224 } 225 226 if ctxt.Headtype == objabi.Haix { 227 // Data must be in a reliable order for reproducible builds. 228 // The original entries are in a reliable order, but the TOC symbols 229 // that are added in Progedit are added by different goroutines 230 // that can be scheduled independently. We need to reorder those 231 // symbols reliably. Sort by name but use a stable sort, so that 232 // any original entries with the same name (all DWARFVAR symbols 233 // have empty names but different relocation sets) are not shuffled. 234 // TODO: Find a better place and optimize to only sort TOC symbols. 235 sort.SliceStable(ctxt.Data, func(i, j int) bool { 236 return ctxt.Data[i].Name < ctxt.Data[j].Name 237 }) 238 } 239 240 // Constant symbols are created late in the concurrent phase. Sort them 241 // to ensure a deterministic order. 242 sort.Slice(ctxt.constSyms, func(i, j int) bool { 243 return ctxt.constSyms[i].Name < ctxt.constSyms[j].Name 244 }) 245 ctxt.Data = append(ctxt.Data, ctxt.constSyms...) 246 ctxt.constSyms = nil 247 248 ctxt.pkgIdx = make(map[string]int32) 249 ctxt.defs = []*LSym{} 250 ctxt.hashed64defs = []*LSym{} 251 ctxt.hasheddefs = []*LSym{} 252 ctxt.nonpkgdefs = []*LSym{} 253 254 var idx, hashedidx, hashed64idx, nonpkgidx int32 255 ctxt.traverseSyms(traverseDefs|traversePcdata, func(s *LSym) { 256 if s.ContentAddressable() { 257 if s.Size <= 8 && len(s.R) == 0 && contentHashSection(s) == 0 { 258 // We can use short hash only for symbols without relocations. 259 // Don't use short hash for symbols that belong in a particular section 260 // or require special handling (such as type symbols). 261 s.PkgIdx = goobj.PkgIdxHashed64 262 s.SymIdx = hashed64idx 263 if hashed64idx != int32(len(ctxt.hashed64defs)) { 264 panic("bad index") 265 } 266 ctxt.hashed64defs = append(ctxt.hashed64defs, s) 267 hashed64idx++ 268 } else { 269 s.PkgIdx = goobj.PkgIdxHashed 270 s.SymIdx = hashedidx 271 if hashedidx != int32(len(ctxt.hasheddefs)) { 272 panic("bad index") 273 } 274 ctxt.hasheddefs = append(ctxt.hasheddefs, s) 275 hashedidx++ 276 } 277 } else if isNonPkgSym(ctxt, s) { 278 s.PkgIdx = goobj.PkgIdxNone 279 s.SymIdx = nonpkgidx 280 if nonpkgidx != int32(len(ctxt.nonpkgdefs)) { 281 panic("bad index") 282 } 283 ctxt.nonpkgdefs = append(ctxt.nonpkgdefs, s) 284 nonpkgidx++ 285 } else { 286 s.PkgIdx = goobj.PkgIdxSelf 287 s.SymIdx = idx 288 if idx != int32(len(ctxt.defs)) { 289 panic("bad index") 290 } 291 ctxt.defs = append(ctxt.defs, s) 292 idx++ 293 } 294 s.Set(AttrIndexed, true) 295 }) 296 297 ipkg := int32(1) // 0 is invalid index 298 nonpkgdef := nonpkgidx 299 ctxt.traverseSyms(traverseRefs|traverseAux, func(rs *LSym) { 300 if rs.PkgIdx != goobj.PkgIdxInvalid { 301 return 302 } 303 if !ctxt.Flag_linkshared { 304 // Assign special index for builtin symbols. 305 // Don't do it when linking against shared libraries, as the runtime 306 // may be in a different library. 307 if i := goobj.BuiltinIdx(rs.Name, int(rs.ABI())); i != -1 { 308 rs.PkgIdx = goobj.PkgIdxBuiltin 309 rs.SymIdx = int32(i) 310 rs.Set(AttrIndexed, true) 311 return 312 } 313 } 314 pkg := rs.Pkg 315 if rs.ContentAddressable() { 316 // for now, only support content-addressable symbols that are always locally defined. 317 panic("hashed refs unsupported for now") 318 } 319 if pkg == "" || pkg == "\"\"" || pkg == "_" || !rs.Indexed() { 320 rs.PkgIdx = goobj.PkgIdxNone 321 rs.SymIdx = nonpkgidx 322 rs.Set(AttrIndexed, true) 323 if nonpkgidx != nonpkgdef+int32(len(ctxt.nonpkgrefs)) { 324 panic("bad index") 325 } 326 ctxt.nonpkgrefs = append(ctxt.nonpkgrefs, rs) 327 nonpkgidx++ 328 return 329 } 330 if k, ok := ctxt.pkgIdx[pkg]; ok { 331 rs.PkgIdx = k 332 return 333 } 334 rs.PkgIdx = ipkg 335 ctxt.pkgIdx[pkg] = ipkg 336 ipkg++ 337 }) 338 } 339 340 // Returns whether s is a non-package symbol, which needs to be referenced 341 // by name instead of by index. 342 func isNonPkgSym(ctxt *Link, s *LSym) bool { 343 if ctxt.IsAsm && !s.Static() { 344 // asm symbols are referenced by name only, except static symbols 345 // which are file-local and can be referenced by index. 346 return true 347 } 348 if ctxt.Flag_linkshared { 349 // The referenced symbol may be in a different shared library so 350 // the linker cannot see its index. 351 return true 352 } 353 if s.Pkg == "_" { 354 // The frontend uses package "_" to mark symbols that should not 355 // be referenced by index, e.g. linkname'd symbols. 356 return true 357 } 358 if s.DuplicateOK() { 359 // Dupok symbol needs to be dedup'd by name. 360 return true 361 } 362 return false 363 } 364 365 // StaticNamePref is the prefix the front end applies to static temporary 366 // variables. When turned into LSyms, these can be tagged as static so 367 // as to avoid inserting them into the linker's name lookup tables. 368 const StaticNamePref = ".stmp_" 369 370 type traverseFlag uint32 371 372 const ( 373 traverseDefs traverseFlag = 1 << iota 374 traverseRefs 375 traverseAux 376 traversePcdata 377 378 traverseAll = traverseDefs | traverseRefs | traverseAux | traversePcdata 379 ) 380 381 // Traverse symbols based on flag, call fn for each symbol. 382 func (ctxt *Link) traverseSyms(flag traverseFlag, fn func(*LSym)) { 383 fnNoNil := func(s *LSym) { 384 if s != nil { 385 fn(s) 386 } 387 } 388 lists := [][]*LSym{ctxt.Text, ctxt.Data} 389 files := ctxt.PosTable.FileTable() 390 for _, list := range lists { 391 for _, s := range list { 392 if flag&traverseDefs != 0 { 393 fn(s) 394 } 395 if flag&traverseRefs != 0 { 396 for _, r := range s.R { 397 fnNoNil(r.Sym) 398 } 399 } 400 if flag&traverseAux != 0 { 401 fnNoNil(s.Gotype) 402 if s.Type == objabi.STEXT { 403 f := func(parent *LSym, aux *LSym) { 404 fn(aux) 405 } 406 ctxt.traverseFuncAux(flag, s, f, files) 407 } else if v := s.VarInfo(); v != nil { 408 fnNoNil(v.dwarfInfoSym) 409 } 410 } 411 if flag&traversePcdata != 0 && s.Type == objabi.STEXT { 412 fi := s.Func().Pcln 413 fnNoNil(fi.Pcsp) 414 fnNoNil(fi.Pcfile) 415 fnNoNil(fi.Pcline) 416 fnNoNil(fi.Pcinline) 417 for _, d := range fi.Pcdata { 418 fnNoNil(d) 419 } 420 } 421 } 422 } 423 } 424 425 func (ctxt *Link) traverseFuncAux(flag traverseFlag, fsym *LSym, fn func(parent *LSym, aux *LSym), files []string) { 426 fninfo := fsym.Func() 427 pc := &fninfo.Pcln 428 if flag&traverseAux == 0 { 429 // NB: should it become necessary to walk aux sym reloc references 430 // without walking the aux syms themselves, this can be changed. 431 panic("should not be here") 432 } 433 for _, d := range pc.Funcdata { 434 if d != nil { 435 fn(fsym, d) 436 } 437 } 438 usedFiles := make([]goobj.CUFileIndex, 0, len(pc.UsedFiles)) 439 for f := range pc.UsedFiles { 440 usedFiles = append(usedFiles, f) 441 } 442 sort.Slice(usedFiles, func(i, j int) bool { return usedFiles[i] < usedFiles[j] }) 443 for _, f := range usedFiles { 444 if filesym := ctxt.Lookup(files[f]); filesym != nil { 445 fn(fsym, filesym) 446 } 447 } 448 for _, call := range pc.InlTree.nodes { 449 if call.Func != nil { 450 fn(fsym, call.Func) 451 } 452 } 453 454 auxsyms := []*LSym{fninfo.dwarfRangesSym, fninfo.dwarfLocSym, fninfo.dwarfDebugLinesSym, fninfo.dwarfInfoSym, fninfo.WasmImportSym, fninfo.sehUnwindInfoSym} 455 for _, s := range auxsyms { 456 if s == nil || s.Size == 0 { 457 continue 458 } 459 fn(fsym, s) 460 if flag&traverseRefs != 0 { 461 for _, r := range s.R { 462 if r.Sym != nil { 463 fn(s, r.Sym) 464 } 465 } 466 } 467 } 468 } 469 470 // Traverse aux symbols, calling fn for each sym/aux pair. 471 func (ctxt *Link) traverseAuxSyms(flag traverseFlag, fn func(parent *LSym, aux *LSym)) { 472 lists := [][]*LSym{ctxt.Text, ctxt.Data} 473 files := ctxt.PosTable.FileTable() 474 for _, list := range lists { 475 for _, s := range list { 476 if s.Gotype != nil { 477 if flag&traverseDefs != 0 { 478 fn(s, s.Gotype) 479 } 480 } 481 if s.Type == objabi.STEXT { 482 ctxt.traverseFuncAux(flag, s, fn, files) 483 } else if v := s.VarInfo(); v != nil && v.dwarfInfoSym != nil { 484 fn(s, v.dwarfInfoSym) 485 } 486 } 487 } 488 }