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 }