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 ([email protected]) 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 ([email protected]) 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 32package obj 33 34import ( 35 "cmd/internal/goobj" 36 "cmd/internal/notsha256" 37 "cmd/internal/objabi" 38 "encoding/base64" 39 "encoding/binary" 40 "fmt" 41 "internal/buildcfg" 42 "log" 43 "math" 44 "sort" 45) 46 47func 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. 65func (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. 74func (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. 85func (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. 92func (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. 119func (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. 126func (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 140func (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 153func (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 166func (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 178func (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 190func (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. 209func (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). 221func (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 // So are SEH symbols. 249 sort.Slice(ctxt.SEHSyms, func(i, j int) bool { 250 return ctxt.SEHSyms[i].Name < ctxt.SEHSyms[j].Name 251 }) 252 ctxt.Data = append(ctxt.Data, ctxt.SEHSyms...) 253 ctxt.SEHSyms = nil 254 255 ctxt.pkgIdx = make(map[string]int32) 256 ctxt.defs = []*LSym{} 257 ctxt.hashed64defs = []*LSym{} 258 ctxt.hasheddefs = []*LSym{} 259 ctxt.nonpkgdefs = []*LSym{} 260 261 var idx, hashedidx, hashed64idx, nonpkgidx int32 262 ctxt.traverseSyms(traverseDefs|traversePcdata, func(s *LSym) { 263 if s.ContentAddressable() { 264 if s.Size <= 8 && len(s.R) == 0 && contentHashSection(s) == 0 { 265 // We can use short hash only for symbols without relocations. 266 // Don't use short hash for symbols that belong in a particular section 267 // or require special handling (such as type symbols). 268 s.PkgIdx = goobj.PkgIdxHashed64 269 s.SymIdx = hashed64idx 270 if hashed64idx != int32(len(ctxt.hashed64defs)) { 271 panic("bad index") 272 } 273 ctxt.hashed64defs = append(ctxt.hashed64defs, s) 274 hashed64idx++ 275 } else { 276 s.PkgIdx = goobj.PkgIdxHashed 277 s.SymIdx = hashedidx 278 if hashedidx != int32(len(ctxt.hasheddefs)) { 279 panic("bad index") 280 } 281 ctxt.hasheddefs = append(ctxt.hasheddefs, s) 282 hashedidx++ 283 } 284 } else if isNonPkgSym(ctxt, s) { 285 s.PkgIdx = goobj.PkgIdxNone 286 s.SymIdx = nonpkgidx 287 if nonpkgidx != int32(len(ctxt.nonpkgdefs)) { 288 panic("bad index") 289 } 290 ctxt.nonpkgdefs = append(ctxt.nonpkgdefs, s) 291 nonpkgidx++ 292 } else { 293 s.PkgIdx = goobj.PkgIdxSelf 294 s.SymIdx = idx 295 if idx != int32(len(ctxt.defs)) { 296 panic("bad index") 297 } 298 ctxt.defs = append(ctxt.defs, s) 299 idx++ 300 } 301 s.Set(AttrIndexed, true) 302 }) 303 304 ipkg := int32(1) // 0 is invalid index 305 nonpkgdef := nonpkgidx 306 ctxt.traverseSyms(traverseRefs|traverseAux, func(rs *LSym) { 307 if rs.PkgIdx != goobj.PkgIdxInvalid { 308 return 309 } 310 if !ctxt.Flag_linkshared { 311 // Assign special index for builtin symbols. 312 // Don't do it when linking against shared libraries, as the runtime 313 // may be in a different library. 314 if i := goobj.BuiltinIdx(rs.Name, int(rs.ABI())); i != -1 { 315 rs.PkgIdx = goobj.PkgIdxBuiltin 316 rs.SymIdx = int32(i) 317 rs.Set(AttrIndexed, true) 318 return 319 } 320 } 321 pkg := rs.Pkg 322 if rs.ContentAddressable() { 323 // for now, only support content-addressable symbols that are always locally defined. 324 panic("hashed refs unsupported for now") 325 } 326 if pkg == "" || pkg == "\"\"" || pkg == "_" || !rs.Indexed() { 327 rs.PkgIdx = goobj.PkgIdxNone 328 rs.SymIdx = nonpkgidx 329 rs.Set(AttrIndexed, true) 330 if nonpkgidx != nonpkgdef+int32(len(ctxt.nonpkgrefs)) { 331 panic("bad index") 332 } 333 ctxt.nonpkgrefs = append(ctxt.nonpkgrefs, rs) 334 nonpkgidx++ 335 return 336 } 337 if k, ok := ctxt.pkgIdx[pkg]; ok { 338 rs.PkgIdx = k 339 return 340 } 341 rs.PkgIdx = ipkg 342 ctxt.pkgIdx[pkg] = ipkg 343 ipkg++ 344 }) 345} 346 347// Returns whether s is a non-package symbol, which needs to be referenced 348// by name instead of by index. 349func isNonPkgSym(ctxt *Link, s *LSym) bool { 350 if ctxt.IsAsm && !s.Static() { 351 // asm symbols are referenced by name only, except static symbols 352 // which are file-local and can be referenced by index. 353 return true 354 } 355 if ctxt.Flag_linkshared { 356 // The referenced symbol may be in a different shared library so 357 // the linker cannot see its index. 358 return true 359 } 360 if s.Pkg == "_" { 361 // The frontend uses package "_" to mark symbols that should not 362 // be referenced by index, e.g. linkname'd symbols. 363 return true 364 } 365 if s.DuplicateOK() { 366 // Dupok symbol needs to be dedup'd by name. 367 return true 368 } 369 return false 370} 371 372// StaticNamePref is the prefix the front end applies to static temporary 373// variables. When turned into LSyms, these can be tagged as static so 374// as to avoid inserting them into the linker's name lookup tables. 375const StaticNamePref = ".stmp_" 376 377type traverseFlag uint32 378 379const ( 380 traverseDefs traverseFlag = 1 << iota 381 traverseRefs 382 traverseAux 383 traversePcdata 384 385 traverseAll = traverseDefs | traverseRefs | traverseAux | traversePcdata 386) 387 388// Traverse symbols based on flag, call fn for each symbol. 389func (ctxt *Link) traverseSyms(flag traverseFlag, fn func(*LSym)) { 390 fnNoNil := func(s *LSym) { 391 if s != nil { 392 fn(s) 393 } 394 } 395 lists := [][]*LSym{ctxt.Text, ctxt.Data} 396 files := ctxt.PosTable.FileTable() 397 for _, list := range lists { 398 for _, s := range list { 399 if flag&traverseDefs != 0 { 400 fn(s) 401 } 402 if flag&traverseRefs != 0 { 403 for _, r := range s.R { 404 fnNoNil(r.Sym) 405 } 406 } 407 if flag&traverseAux != 0 { 408 fnNoNil(s.Gotype) 409 if s.Type == objabi.STEXT { 410 f := func(parent *LSym, aux *LSym) { 411 fn(aux) 412 } 413 ctxt.traverseFuncAux(flag, s, f, files) 414 } else if v := s.VarInfo(); v != nil { 415 fnNoNil(v.dwarfInfoSym) 416 } 417 } 418 if flag&traversePcdata != 0 && s.Type == objabi.STEXT { 419 fi := s.Func().Pcln 420 fnNoNil(fi.Pcsp) 421 fnNoNil(fi.Pcfile) 422 fnNoNil(fi.Pcline) 423 fnNoNil(fi.Pcinline) 424 for _, d := range fi.Pcdata { 425 fnNoNil(d) 426 } 427 } 428 } 429 } 430} 431 432func (ctxt *Link) traverseFuncAux(flag traverseFlag, fsym *LSym, fn func(parent *LSym, aux *LSym), files []string) { 433 fninfo := fsym.Func() 434 pc := &fninfo.Pcln 435 if flag&traverseAux == 0 { 436 // NB: should it become necessary to walk aux sym reloc references 437 // without walking the aux syms themselves, this can be changed. 438 panic("should not be here") 439 } 440 for _, d := range pc.Funcdata { 441 if d != nil { 442 fn(fsym, d) 443 } 444 } 445 usedFiles := make([]goobj.CUFileIndex, 0, len(pc.UsedFiles)) 446 for f := range pc.UsedFiles { 447 usedFiles = append(usedFiles, f) 448 } 449 sort.Slice(usedFiles, func(i, j int) bool { return usedFiles[i] < usedFiles[j] }) 450 for _, f := range usedFiles { 451 if filesym := ctxt.Lookup(files[f]); filesym != nil { 452 fn(fsym, filesym) 453 } 454 } 455 for _, call := range pc.InlTree.nodes { 456 if call.Func != nil { 457 fn(fsym, call.Func) 458 } 459 } 460 461 auxsyms := []*LSym{fninfo.dwarfRangesSym, fninfo.dwarfLocSym, fninfo.dwarfDebugLinesSym, fninfo.dwarfInfoSym, fninfo.WasmImportSym, fninfo.sehUnwindInfoSym} 462 for _, s := range auxsyms { 463 if s == nil || s.Size == 0 { 464 continue 465 } 466 fn(fsym, s) 467 if flag&traverseRefs != 0 { 468 for _, r := range s.R { 469 if r.Sym != nil { 470 fn(s, r.Sym) 471 } 472 } 473 } 474 } 475} 476 477// Traverse aux symbols, calling fn for each sym/aux pair. 478func (ctxt *Link) traverseAuxSyms(flag traverseFlag, fn func(parent *LSym, aux *LSym)) { 479 lists := [][]*LSym{ctxt.Text, ctxt.Data} 480 files := ctxt.PosTable.FileTable() 481 for _, list := range lists { 482 for _, s := range list { 483 if s.Gotype != nil { 484 if flag&traverseDefs != 0 { 485 fn(s, s.Gotype) 486 } 487 } 488 if s.Type == objabi.STEXT { 489 ctxt.traverseFuncAux(flag, s, fn, files) 490 } else if v := s.VarInfo(); v != nil && v.dwarfInfoSym != nil { 491 fn(s, v.dwarfInfoSym) 492 } 493 } 494 } 495} 496