github.com/bir3/gocompiler@v0.9.2202/src/cmd/link/internal/ld/pcln.go (about) 1 // Copyright 2013 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package ld 6 7 import ( 8 "github.com/bir3/gocompiler/src/cmd/internal/goobj" 9 "github.com/bir3/gocompiler/src/cmd/internal/objabi" 10 "github.com/bir3/gocompiler/src/cmd/internal/sys" 11 "github.com/bir3/gocompiler/src/cmd/link/internal/loader" 12 "github.com/bir3/gocompiler/src/cmd/link/internal/sym" 13 "fmt" 14 "github.com/bir3/gocompiler/src/internal/abi" 15 "github.com/bir3/gocompiler/src/internal/buildcfg" 16 "os" 17 "path/filepath" 18 "strings" 19 ) 20 21 const funcSize = 11 * 4 // funcSize is the size of the _func object in runtime/runtime2.go 22 23 // pclntab holds the state needed for pclntab generation. 24 type pclntab struct { 25 // The first and last functions found. 26 firstFunc, lastFunc loader.Sym 27 28 // Running total size of pclntab. 29 size int64 30 31 // runtime.pclntab's symbols 32 carrier loader.Sym 33 pclntab loader.Sym 34 pcheader loader.Sym 35 funcnametab loader.Sym 36 findfunctab loader.Sym 37 cutab loader.Sym 38 filetab loader.Sym 39 pctab loader.Sym 40 41 // The number of functions + number of TEXT sections - 1. This is such an 42 // unexpected value because platforms that have more than one TEXT section 43 // get a dummy function inserted between because the external linker can place 44 // functions in those areas. We mark those areas as not covered by the Go 45 // runtime. 46 // 47 // On most platforms this is the number of reachable functions. 48 nfunc int32 49 50 // The number of filenames in runtime.filetab. 51 nfiles uint32 52 } 53 54 // addGeneratedSym adds a generator symbol to pclntab, returning the new Sym. 55 // It is the caller's responsibility to save the symbol in state. 56 func (state *pclntab) addGeneratedSym(ctxt *Link, name string, size int64, f generatorFunc) loader.Sym { 57 size = Rnd(size, int64(ctxt.Arch.PtrSize)) 58 state.size += size 59 s := ctxt.createGeneratorSymbol(name, 0, sym.SPCLNTAB, size, f) 60 ctxt.loader.SetAttrReachable(s, true) 61 ctxt.loader.SetCarrierSym(s, state.carrier) 62 ctxt.loader.SetAttrNotInSymbolTable(s, true) 63 return s 64 } 65 66 // makePclntab makes a pclntab object, and assembles all the compilation units 67 // we'll need to write pclntab. Returns the pclntab structure, a slice of the 68 // CompilationUnits we need, and a slice of the function symbols we need to 69 // generate pclntab. 70 func makePclntab(ctxt *Link, container loader.Bitmap) (*pclntab, []*sym.CompilationUnit, []loader.Sym) { 71 ldr := ctxt.loader 72 state := new(pclntab) 73 74 // Gather some basic stats and info. 75 seenCUs := make(map[*sym.CompilationUnit]struct{}) 76 compUnits := []*sym.CompilationUnit{} 77 funcs := []loader.Sym{} 78 79 for _, s := range ctxt.Textp { 80 if !emitPcln(ctxt, s, container) { 81 continue 82 } 83 funcs = append(funcs, s) 84 state.nfunc++ 85 if state.firstFunc == 0 { 86 state.firstFunc = s 87 } 88 state.lastFunc = s 89 90 // We need to keep track of all compilation units we see. Some symbols 91 // (eg, go.buildid, _cgoexp_, etc) won't have a compilation unit. 92 cu := ldr.SymUnit(s) 93 if _, ok := seenCUs[cu]; cu != nil && !ok { 94 seenCUs[cu] = struct{}{} 95 cu.PclnIndex = len(compUnits) 96 compUnits = append(compUnits, cu) 97 } 98 } 99 return state, compUnits, funcs 100 } 101 102 func emitPcln(ctxt *Link, s loader.Sym, container loader.Bitmap) bool { 103 if ctxt.Target.IsRISCV64() { 104 // Avoid adding local symbols to the pcln table - RISC-V 105 // linking generates a very large number of these, particularly 106 // for HI20 symbols (which we need to load in order to be able 107 // to resolve relocations). Unnecessarily including all of 108 // these symbols quickly blows out the size of the pcln table 109 // and overflows hash buckets. 110 symName := ctxt.loader.SymName(s) 111 if symName == "" || strings.HasPrefix(symName, ".L") { 112 return false 113 } 114 } 115 116 // We want to generate func table entries only for the "lowest 117 // level" symbols, not containers of subsymbols. 118 return !container.Has(s) 119 } 120 121 func computeDeferReturn(ctxt *Link, deferReturnSym, s loader.Sym) uint32 { 122 ldr := ctxt.loader 123 target := ctxt.Target 124 deferreturn := uint32(0) 125 lastWasmAddr := uint32(0) 126 127 relocs := ldr.Relocs(s) 128 for ri := 0; ri < relocs.Count(); ri++ { 129 r := relocs.At(ri) 130 if target.IsWasm() && r.Type() == objabi.R_ADDR { 131 // wasm/ssa.go generates an ARESUMEPOINT just 132 // before the deferreturn call. The "PC" of 133 // the deferreturn call is stored in the 134 // R_ADDR relocation on the ARESUMEPOINT. 135 lastWasmAddr = uint32(r.Add()) 136 } 137 if r.Type().IsDirectCall() && (r.Sym() == deferReturnSym || ldr.IsDeferReturnTramp(r.Sym())) { 138 if target.IsWasm() { 139 deferreturn = lastWasmAddr - 1 140 } else { 141 // Note: the relocation target is in the call instruction, but 142 // is not necessarily the whole instruction (for instance, on 143 // x86 the relocation applies to bytes [1:5] of the 5 byte call 144 // instruction). 145 deferreturn = uint32(r.Off()) 146 switch target.Arch.Family { 147 case sys.AMD64, sys.I386: 148 deferreturn-- 149 case sys.ARM, sys.ARM64, sys.Loong64, sys.MIPS, sys.MIPS64, sys.PPC64, sys.RISCV64: 150 // no change 151 case sys.S390X: 152 deferreturn -= 2 153 default: 154 panic(fmt.Sprint("Unhandled architecture:", target.Arch.Family)) 155 } 156 } 157 break // only need one 158 } 159 } 160 return deferreturn 161 } 162 163 // genInlTreeSym generates the InlTree sym for a function with the 164 // specified FuncInfo. 165 func genInlTreeSym(ctxt *Link, cu *sym.CompilationUnit, fi loader.FuncInfo, arch *sys.Arch, nameOffsets map[loader.Sym]uint32) loader.Sym { 166 ldr := ctxt.loader 167 its := ldr.CreateExtSym("", 0) 168 inlTreeSym := ldr.MakeSymbolUpdater(its) 169 // Note: the generated symbol is given a type of sym.SGOFUNC, as a 170 // signal to the symtab() phase that it needs to be grouped in with 171 // other similar symbols (gcdata, etc); the dodata() phase will 172 // eventually switch the type back to SRODATA. 173 inlTreeSym.SetType(sym.SGOFUNC) 174 ldr.SetAttrReachable(its, true) 175 ldr.SetSymAlign(its, 4) // it has 32-bit fields 176 ninl := fi.NumInlTree() 177 for i := 0; i < int(ninl); i++ { 178 call := fi.InlTree(i) 179 nameOff, ok := nameOffsets[call.Func] 180 if !ok { 181 panic("couldn't find function name offset") 182 } 183 184 inlFunc := ldr.FuncInfo(call.Func) 185 var funcID abi.FuncID 186 startLine := int32(0) 187 if inlFunc.Valid() { 188 funcID = inlFunc.FuncID() 189 startLine = inlFunc.StartLine() 190 } else if !ctxt.linkShared { 191 // Inlined functions are always Go functions, and thus 192 // must have FuncInfo. 193 // 194 // Unfortunately, with -linkshared, the inlined 195 // function may be external symbols (from another 196 // shared library), and we don't load FuncInfo from the 197 // shared library. We will report potentially incorrect 198 // FuncID in this case. See https://go.dev/issue/55954. 199 panic(fmt.Sprintf("inlined function %s missing func info", ldr.SymName(call.Func))) 200 } 201 202 // Construct runtime.inlinedCall value. 203 const size = 16 204 inlTreeSym.SetUint8(arch, int64(i*size+0), uint8(funcID)) 205 // Bytes 1-3 are unused. 206 inlTreeSym.SetUint32(arch, int64(i*size+4), uint32(nameOff)) 207 inlTreeSym.SetUint32(arch, int64(i*size+8), uint32(call.ParentPC)) 208 inlTreeSym.SetUint32(arch, int64(i*size+12), uint32(startLine)) 209 } 210 return its 211 } 212 213 // makeInlSyms returns a map of loader.Sym that are created inlSyms. 214 func makeInlSyms(ctxt *Link, funcs []loader.Sym, nameOffsets map[loader.Sym]uint32) map[loader.Sym]loader.Sym { 215 ldr := ctxt.loader 216 // Create the inline symbols we need. 217 inlSyms := make(map[loader.Sym]loader.Sym) 218 for _, s := range funcs { 219 if fi := ldr.FuncInfo(s); fi.Valid() { 220 fi.Preload() 221 if fi.NumInlTree() > 0 { 222 inlSyms[s] = genInlTreeSym(ctxt, ldr.SymUnit(s), fi, ctxt.Arch, nameOffsets) 223 } 224 } 225 } 226 return inlSyms 227 } 228 229 // generatePCHeader creates the runtime.pcheader symbol, setting it up as a 230 // generator to fill in its data later. 231 func (state *pclntab) generatePCHeader(ctxt *Link) { 232 ldr := ctxt.loader 233 textStartOff := int64(8 + 2*ctxt.Arch.PtrSize) 234 size := int64(8 + 8*ctxt.Arch.PtrSize) 235 writeHeader := func(ctxt *Link, s loader.Sym) { 236 header := ctxt.loader.MakeSymbolUpdater(s) 237 238 writeSymOffset := func(off int64, ws loader.Sym) int64 { 239 diff := ldr.SymValue(ws) - ldr.SymValue(s) 240 if diff <= 0 { 241 name := ldr.SymName(ws) 242 panic(fmt.Sprintf("expected runtime.pcheader(%x) to be placed before %s(%x)", ldr.SymValue(s), name, ldr.SymValue(ws))) 243 } 244 return header.SetUintptr(ctxt.Arch, off, uintptr(diff)) 245 } 246 247 // Write header. 248 // Keep in sync with runtime/symtab.go:pcHeader and package debug/gosym. 249 header.SetUint32(ctxt.Arch, 0, 0xfffffff1) 250 header.SetUint8(ctxt.Arch, 6, uint8(ctxt.Arch.MinLC)) 251 header.SetUint8(ctxt.Arch, 7, uint8(ctxt.Arch.PtrSize)) 252 off := header.SetUint(ctxt.Arch, 8, uint64(state.nfunc)) 253 off = header.SetUint(ctxt.Arch, off, uint64(state.nfiles)) 254 if off != textStartOff { 255 panic(fmt.Sprintf("pcHeader textStartOff: %d != %d", off, textStartOff)) 256 } 257 off += int64(ctxt.Arch.PtrSize) // skip runtimeText relocation 258 off = writeSymOffset(off, state.funcnametab) 259 off = writeSymOffset(off, state.cutab) 260 off = writeSymOffset(off, state.filetab) 261 off = writeSymOffset(off, state.pctab) 262 off = writeSymOffset(off, state.pclntab) 263 if off != size { 264 panic(fmt.Sprintf("pcHeader size: %d != %d", off, size)) 265 } 266 } 267 268 state.pcheader = state.addGeneratedSym(ctxt, "runtime.pcheader", size, writeHeader) 269 // Create the runtimeText relocation. 270 sb := ldr.MakeSymbolUpdater(state.pcheader) 271 sb.SetAddr(ctxt.Arch, textStartOff, ldr.Lookup("runtime.text", 0)) 272 } 273 274 // walkFuncs iterates over the funcs, calling a function for each unique 275 // function and inlined function. 276 func walkFuncs(ctxt *Link, funcs []loader.Sym, f func(loader.Sym)) { 277 ldr := ctxt.loader 278 seen := make(map[loader.Sym]struct{}) 279 for _, s := range funcs { 280 if _, ok := seen[s]; !ok { 281 f(s) 282 seen[s] = struct{}{} 283 } 284 285 fi := ldr.FuncInfo(s) 286 if !fi.Valid() { 287 continue 288 } 289 fi.Preload() 290 for i, ni := 0, fi.NumInlTree(); i < int(ni); i++ { 291 call := fi.InlTree(i).Func 292 if _, ok := seen[call]; !ok { 293 f(call) 294 seen[call] = struct{}{} 295 } 296 } 297 } 298 } 299 300 // generateFuncnametab creates the function name table. Returns a map of 301 // func symbol to the name offset in runtime.funcnamtab. 302 func (state *pclntab) generateFuncnametab(ctxt *Link, funcs []loader.Sym) map[loader.Sym]uint32 { 303 nameOffsets := make(map[loader.Sym]uint32, state.nfunc) 304 305 // Write the null terminated strings. 306 writeFuncNameTab := func(ctxt *Link, s loader.Sym) { 307 symtab := ctxt.loader.MakeSymbolUpdater(s) 308 for s, off := range nameOffsets { 309 symtab.AddCStringAt(int64(off), ctxt.loader.SymName(s)) 310 } 311 } 312 313 // Loop through the CUs, and calculate the size needed. 314 var size int64 315 walkFuncs(ctxt, funcs, func(s loader.Sym) { 316 nameOffsets[s] = uint32(size) 317 size += int64(len(ctxt.loader.SymName(s)) + 1) // NULL terminate 318 }) 319 320 state.funcnametab = state.addGeneratedSym(ctxt, "runtime.funcnametab", size, writeFuncNameTab) 321 return nameOffsets 322 } 323 324 // walkFilenames walks funcs, calling a function for each filename used in each 325 // function's line table. 326 func walkFilenames(ctxt *Link, funcs []loader.Sym, f func(*sym.CompilationUnit, goobj.CUFileIndex)) { 327 ldr := ctxt.loader 328 329 // Loop through all functions, finding the filenames we need. 330 for _, s := range funcs { 331 fi := ldr.FuncInfo(s) 332 if !fi.Valid() { 333 continue 334 } 335 fi.Preload() 336 337 cu := ldr.SymUnit(s) 338 for i, nf := 0, int(fi.NumFile()); i < nf; i++ { 339 f(cu, fi.File(i)) 340 } 341 for i, ninl := 0, int(fi.NumInlTree()); i < ninl; i++ { 342 call := fi.InlTree(i) 343 f(cu, call.File) 344 } 345 } 346 } 347 348 // generateFilenameTabs creates LUTs needed for filename lookup. Returns a slice 349 // of the index at which each CU begins in runtime.cutab. 350 // 351 // Function objects keep track of the files they reference to print the stack. 352 // This function creates a per-CU list of filenames if CU[M] references 353 // files[1-N], the following is generated: 354 // 355 // runtime.cutab: 356 // CU[M] 357 // offsetToFilename[0] 358 // offsetToFilename[1] 359 // .. 360 // 361 // runtime.filetab 362 // filename[0] 363 // filename[1] 364 // 365 // Looking up a filename then becomes: 366 // 0. Given a func, and filename index [K] 367 // 1. Get Func.CUIndex: M := func.cuOffset 368 // 2. Find filename offset: fileOffset := runtime.cutab[M+K] 369 // 3. Get the filename: getcstring(runtime.filetab[fileOffset]) 370 func (state *pclntab) generateFilenameTabs(ctxt *Link, compUnits []*sym.CompilationUnit, funcs []loader.Sym) []uint32 { 371 // On a per-CU basis, keep track of all the filenames we need. 372 // 373 // Note, that we store the filenames in a separate section in the object 374 // files, and deduplicate based on the actual value. It would be better to 375 // store the filenames as symbols, using content addressable symbols (and 376 // then not loading extra filenames), and just use the hash value of the 377 // symbol name to do this cataloging. 378 // 379 // TODO: Store filenames as symbols. (Note this would be easiest if you 380 // also move strings to ALWAYS using the larger content addressable hash 381 // function, and use that hash value for uniqueness testing.) 382 cuEntries := make([]goobj.CUFileIndex, len(compUnits)) 383 fileOffsets := make(map[string]uint32) 384 385 // Walk the filenames. 386 // We store the total filename string length we need to load, and the max 387 // file index we've seen per CU so we can calculate how large the 388 // CU->global table needs to be. 389 var fileSize int64 390 walkFilenames(ctxt, funcs, func(cu *sym.CompilationUnit, i goobj.CUFileIndex) { 391 // Note we use the raw filename for lookup, but use the expanded filename 392 // when we save the size. 393 filename := cu.FileTable[i] 394 if _, ok := fileOffsets[filename]; !ok { 395 fileOffsets[filename] = uint32(fileSize) 396 fileSize += int64(len(expandFile(filename)) + 1) // NULL terminate 397 } 398 399 // Find the maximum file index we've seen. 400 if cuEntries[cu.PclnIndex] < i+1 { 401 cuEntries[cu.PclnIndex] = i + 1 // Store max + 1 402 } 403 }) 404 405 // Calculate the size of the runtime.cutab variable. 406 var totalEntries uint32 407 cuOffsets := make([]uint32, len(cuEntries)) 408 for i, entries := range cuEntries { 409 // Note, cutab is a slice of uint32, so an offset to a cu's entry is just the 410 // running total of all cu indices we've needed to store so far, not the 411 // number of bytes we've stored so far. 412 cuOffsets[i] = totalEntries 413 totalEntries += uint32(entries) 414 } 415 416 // Write cutab. 417 writeCutab := func(ctxt *Link, s loader.Sym) { 418 sb := ctxt.loader.MakeSymbolUpdater(s) 419 420 var off int64 421 for i, max := range cuEntries { 422 // Write the per CU LUT. 423 cu := compUnits[i] 424 for j := goobj.CUFileIndex(0); j < max; j++ { 425 fileOffset, ok := fileOffsets[cu.FileTable[j]] 426 if !ok { 427 // We're looping through all possible file indices. It's possible a file's 428 // been deadcode eliminated, and although it's a valid file in the CU, it's 429 // not needed in this binary. When that happens, use an invalid offset. 430 fileOffset = ^uint32(0) 431 } 432 off = sb.SetUint32(ctxt.Arch, off, fileOffset) 433 } 434 } 435 } 436 state.cutab = state.addGeneratedSym(ctxt, "runtime.cutab", int64(totalEntries*4), writeCutab) 437 438 // Write filetab. 439 writeFiletab := func(ctxt *Link, s loader.Sym) { 440 sb := ctxt.loader.MakeSymbolUpdater(s) 441 442 // Write the strings. 443 for filename, loc := range fileOffsets { 444 sb.AddStringAt(int64(loc), expandFile(filename)) 445 } 446 } 447 state.nfiles = uint32(len(fileOffsets)) 448 state.filetab = state.addGeneratedSym(ctxt, "runtime.filetab", fileSize, writeFiletab) 449 450 return cuOffsets 451 } 452 453 // generatePctab creates the runtime.pctab variable, holding all the 454 // deduplicated pcdata. 455 func (state *pclntab) generatePctab(ctxt *Link, funcs []loader.Sym) { 456 ldr := ctxt.loader 457 458 // Pctab offsets of 0 are considered invalid in the runtime. We respect 459 // that by just padding a single byte at the beginning of runtime.pctab, 460 // that way no real offsets can be zero. 461 size := int64(1) 462 463 // Walk the functions, finding offset to store each pcdata. 464 seen := make(map[loader.Sym]struct{}) 465 saveOffset := func(pcSym loader.Sym) { 466 if _, ok := seen[pcSym]; !ok { 467 datSize := ldr.SymSize(pcSym) 468 if datSize != 0 { 469 ldr.SetSymValue(pcSym, size) 470 } else { 471 // Invalid PC data, record as zero. 472 ldr.SetSymValue(pcSym, 0) 473 } 474 size += datSize 475 seen[pcSym] = struct{}{} 476 } 477 } 478 var pcsp, pcline, pcfile, pcinline loader.Sym 479 var pcdata []loader.Sym 480 for _, s := range funcs { 481 fi := ldr.FuncInfo(s) 482 if !fi.Valid() { 483 continue 484 } 485 fi.Preload() 486 pcsp, pcfile, pcline, pcinline, pcdata = ldr.PcdataAuxs(s, pcdata) 487 488 pcSyms := []loader.Sym{pcsp, pcfile, pcline} 489 for _, pcSym := range pcSyms { 490 saveOffset(pcSym) 491 } 492 for _, pcSym := range pcdata { 493 saveOffset(pcSym) 494 } 495 if fi.NumInlTree() > 0 { 496 saveOffset(pcinline) 497 } 498 } 499 500 // TODO: There is no reason we need a generator for this variable, and it 501 // could be moved to a carrier symbol. However, carrier symbols containing 502 // carrier symbols don't work yet (as of Aug 2020). Once this is fixed, 503 // runtime.pctab could just be a carrier sym. 504 writePctab := func(ctxt *Link, s loader.Sym) { 505 ldr := ctxt.loader 506 sb := ldr.MakeSymbolUpdater(s) 507 for sym := range seen { 508 sb.SetBytesAt(ldr.SymValue(sym), ldr.Data(sym)) 509 } 510 } 511 512 state.pctab = state.addGeneratedSym(ctxt, "runtime.pctab", size, writePctab) 513 } 514 515 // numPCData returns the number of PCData syms for the FuncInfo. 516 // NB: Preload must be called on valid FuncInfos before calling this function. 517 func numPCData(ldr *loader.Loader, s loader.Sym, fi loader.FuncInfo) uint32 { 518 if !fi.Valid() { 519 return 0 520 } 521 numPCData := uint32(ldr.NumPcdata(s)) 522 if fi.NumInlTree() > 0 { 523 if numPCData < abi.PCDATA_InlTreeIndex+1 { 524 numPCData = abi.PCDATA_InlTreeIndex + 1 525 } 526 } 527 return numPCData 528 } 529 530 // generateFunctab creates the runtime.functab 531 // 532 // runtime.functab contains two things: 533 // 534 // - pc->func look up table. 535 // - array of func objects, interleaved with pcdata and funcdata 536 func (state *pclntab) generateFunctab(ctxt *Link, funcs []loader.Sym, inlSyms map[loader.Sym]loader.Sym, cuOffsets []uint32, nameOffsets map[loader.Sym]uint32) { 537 // Calculate the size of the table. 538 size, startLocations := state.calculateFunctabSize(ctxt, funcs) 539 writePcln := func(ctxt *Link, s loader.Sym) { 540 ldr := ctxt.loader 541 sb := ldr.MakeSymbolUpdater(s) 542 // Write the data. 543 writePCToFunc(ctxt, sb, funcs, startLocations) 544 writeFuncs(ctxt, sb, funcs, inlSyms, startLocations, cuOffsets, nameOffsets) 545 } 546 state.pclntab = state.addGeneratedSym(ctxt, "runtime.functab", size, writePcln) 547 } 548 549 // funcData returns the funcdata and offsets for the FuncInfo. 550 // The funcdata are written into runtime.functab after each func 551 // object. This is a helper function to make querying the FuncInfo object 552 // cleaner. 553 // 554 // NB: Preload must be called on the FuncInfo before calling. 555 // NB: fdSyms is used as scratch space. 556 func funcData(ldr *loader.Loader, s loader.Sym, fi loader.FuncInfo, inlSym loader.Sym, fdSyms []loader.Sym) []loader.Sym { 557 fdSyms = fdSyms[:0] 558 if fi.Valid() { 559 fdSyms = ldr.Funcdata(s, fdSyms) 560 if fi.NumInlTree() > 0 { 561 if len(fdSyms) < abi.FUNCDATA_InlTree+1 { 562 fdSyms = append(fdSyms, make([]loader.Sym, abi.FUNCDATA_InlTree+1-len(fdSyms))...) 563 } 564 fdSyms[abi.FUNCDATA_InlTree] = inlSym 565 } 566 } 567 return fdSyms 568 } 569 570 // calculateFunctabSize calculates the size of the pclntab, and the offsets in 571 // the output buffer for individual func entries. 572 func (state pclntab) calculateFunctabSize(ctxt *Link, funcs []loader.Sym) (int64, []uint32) { 573 ldr := ctxt.loader 574 startLocations := make([]uint32, len(funcs)) 575 576 // Allocate space for the pc->func table. This structure consists of a pc offset 577 // and an offset to the func structure. After that, we have a single pc 578 // value that marks the end of the last function in the binary. 579 size := int64(int(state.nfunc)*2*4 + 4) 580 581 // Now find the space for the func objects. We do this in a running manner, 582 // so that we can find individual starting locations. 583 for i, s := range funcs { 584 size = Rnd(size, int64(ctxt.Arch.PtrSize)) 585 startLocations[i] = uint32(size) 586 fi := ldr.FuncInfo(s) 587 size += funcSize 588 if fi.Valid() { 589 fi.Preload() 590 numFuncData := ldr.NumFuncdata(s) 591 if fi.NumInlTree() > 0 { 592 if numFuncData < abi.FUNCDATA_InlTree+1 { 593 numFuncData = abi.FUNCDATA_InlTree + 1 594 } 595 } 596 size += int64(numPCData(ldr, s, fi) * 4) 597 size += int64(numFuncData * 4) 598 } 599 } 600 601 return size, startLocations 602 } 603 604 // writePCToFunc writes the PC->func lookup table. 605 func writePCToFunc(ctxt *Link, sb *loader.SymbolBuilder, funcs []loader.Sym, startLocations []uint32) { 606 ldr := ctxt.loader 607 textStart := ldr.SymValue(ldr.Lookup("runtime.text", 0)) 608 pcOff := func(s loader.Sym) uint32 { 609 off := ldr.SymValue(s) - textStart 610 if off < 0 { 611 panic(fmt.Sprintf("expected func %s(%x) to be placed at or after textStart (%x)", ldr.SymName(s), ldr.SymValue(s), textStart)) 612 } 613 return uint32(off) 614 } 615 for i, s := range funcs { 616 sb.SetUint32(ctxt.Arch, int64(i*2*4), pcOff(s)) 617 sb.SetUint32(ctxt.Arch, int64((i*2+1)*4), startLocations[i]) 618 } 619 620 // Final entry of table is just end pc offset. 621 lastFunc := funcs[len(funcs)-1] 622 sb.SetUint32(ctxt.Arch, int64(len(funcs))*2*4, pcOff(lastFunc)+uint32(ldr.SymSize(lastFunc))) 623 } 624 625 // writeFuncs writes the func structures and pcdata to runtime.functab. 626 func writeFuncs(ctxt *Link, sb *loader.SymbolBuilder, funcs []loader.Sym, inlSyms map[loader.Sym]loader.Sym, startLocations, cuOffsets []uint32, nameOffsets map[loader.Sym]uint32) { 627 ldr := ctxt.loader 628 deferReturnSym := ldr.Lookup("runtime.deferreturn", abiInternalVer) 629 gofunc := ldr.Lookup("go:func.*", 0) 630 gofuncBase := ldr.SymValue(gofunc) 631 textStart := ldr.SymValue(ldr.Lookup("runtime.text", 0)) 632 funcdata := []loader.Sym{} 633 var pcsp, pcfile, pcline, pcinline loader.Sym 634 var pcdata []loader.Sym 635 636 // Write the individual func objects. 637 for i, s := range funcs { 638 startLine := int32(0) 639 fi := ldr.FuncInfo(s) 640 if fi.Valid() { 641 fi.Preload() 642 pcsp, pcfile, pcline, pcinline, pcdata = ldr.PcdataAuxs(s, pcdata) 643 startLine = fi.StartLine() 644 } 645 646 off := int64(startLocations[i]) 647 // entryOff uint32 (offset of func entry PC from textStart) 648 entryOff := ldr.SymValue(s) - textStart 649 if entryOff < 0 { 650 panic(fmt.Sprintf("expected func %s(%x) to be placed before or at textStart (%x)", ldr.SymName(s), ldr.SymValue(s), textStart)) 651 } 652 off = sb.SetUint32(ctxt.Arch, off, uint32(entryOff)) 653 654 // nameOff int32 655 nameOff, ok := nameOffsets[s] 656 if !ok { 657 panic("couldn't find function name offset") 658 } 659 off = sb.SetUint32(ctxt.Arch, off, uint32(nameOff)) 660 661 // args int32 662 // TODO: Move into funcinfo. 663 args := uint32(0) 664 if fi.Valid() { 665 args = uint32(fi.Args()) 666 } 667 off = sb.SetUint32(ctxt.Arch, off, args) 668 669 // deferreturn 670 deferreturn := computeDeferReturn(ctxt, deferReturnSym, s) 671 off = sb.SetUint32(ctxt.Arch, off, deferreturn) 672 673 // pcdata 674 if fi.Valid() { 675 off = sb.SetUint32(ctxt.Arch, off, uint32(ldr.SymValue(pcsp))) 676 off = sb.SetUint32(ctxt.Arch, off, uint32(ldr.SymValue(pcfile))) 677 off = sb.SetUint32(ctxt.Arch, off, uint32(ldr.SymValue(pcline))) 678 } else { 679 off += 12 680 } 681 off = sb.SetUint32(ctxt.Arch, off, uint32(numPCData(ldr, s, fi))) 682 683 // Store the offset to compilation unit's file table. 684 cuIdx := ^uint32(0) 685 if cu := ldr.SymUnit(s); cu != nil { 686 cuIdx = cuOffsets[cu.PclnIndex] 687 } 688 off = sb.SetUint32(ctxt.Arch, off, cuIdx) 689 690 // startLine int32 691 off = sb.SetUint32(ctxt.Arch, off, uint32(startLine)) 692 693 // funcID uint8 694 var funcID abi.FuncID 695 if fi.Valid() { 696 funcID = fi.FuncID() 697 } 698 off = sb.SetUint8(ctxt.Arch, off, uint8(funcID)) 699 700 // flag uint8 701 var flag abi.FuncFlag 702 if fi.Valid() { 703 flag = fi.FuncFlag() 704 } 705 off = sb.SetUint8(ctxt.Arch, off, uint8(flag)) 706 707 off += 1 // pad 708 709 // nfuncdata must be the final entry. 710 funcdata = funcData(ldr, s, fi, 0, funcdata) 711 off = sb.SetUint8(ctxt.Arch, off, uint8(len(funcdata))) 712 713 // Output the pcdata. 714 if fi.Valid() { 715 for j, pcSym := range pcdata { 716 sb.SetUint32(ctxt.Arch, off+int64(j*4), uint32(ldr.SymValue(pcSym))) 717 } 718 if fi.NumInlTree() > 0 { 719 sb.SetUint32(ctxt.Arch, off+abi.PCDATA_InlTreeIndex*4, uint32(ldr.SymValue(pcinline))) 720 } 721 } 722 723 // Write funcdata refs as offsets from go:func.* and go:funcrel.*. 724 funcdata = funcData(ldr, s, fi, inlSyms[s], funcdata) 725 // Missing funcdata will be ^0. See runtime/symtab.go:funcdata. 726 off = int64(startLocations[i] + funcSize + numPCData(ldr, s, fi)*4) 727 for j := range funcdata { 728 dataoff := off + int64(4*j) 729 fdsym := funcdata[j] 730 731 // cmd/internal/obj optimistically populates ArgsPointerMaps and 732 // ArgInfo for assembly functions, hoping that the compiler will 733 // emit appropriate symbols from their Go stub declarations. If 734 // it didn't though, just ignore it. 735 // 736 // TODO(cherryyz): Fix arg map generation (see discussion on CL 523335). 737 if fdsym != 0 && (j == abi.FUNCDATA_ArgsPointerMaps || j == abi.FUNCDATA_ArgInfo) && ldr.IsFromAssembly(s) && ldr.Data(fdsym) == nil { 738 fdsym = 0 739 } 740 741 if fdsym == 0 { 742 sb.SetUint32(ctxt.Arch, dataoff, ^uint32(0)) // ^0 is a sentinel for "no value" 743 continue 744 } 745 746 if outer := ldr.OuterSym(fdsym); outer != gofunc { 747 panic(fmt.Sprintf("bad carrier sym for symbol %s (funcdata %s#%d), want go:func.* got %s", ldr.SymName(fdsym), ldr.SymName(s), j, ldr.SymName(outer))) 748 } 749 sb.SetUint32(ctxt.Arch, dataoff, uint32(ldr.SymValue(fdsym)-gofuncBase)) 750 } 751 } 752 } 753 754 // pclntab initializes the pclntab symbol with 755 // runtime function and file name information. 756 757 // pclntab generates the pcln table for the link output. 758 func (ctxt *Link) pclntab(container loader.Bitmap) *pclntab { 759 // Go 1.2's symtab layout is documented in golang.org/s/go12symtab, but the 760 // layout and data has changed since that time. 761 // 762 // As of August 2020, here's the layout of pclntab: 763 // 764 // .gopclntab/__gopclntab [elf/macho section] 765 // runtime.pclntab 766 // Carrier symbol for the entire pclntab section. 767 // 768 // runtime.pcheader (see: runtime/symtab.go:pcHeader) 769 // 8-byte magic 770 // nfunc [thearch.ptrsize bytes] 771 // offset to runtime.funcnametab from the beginning of runtime.pcheader 772 // offset to runtime.pclntab_old from beginning of runtime.pcheader 773 // 774 // runtime.funcnametab 775 // []list of null terminated function names 776 // 777 // runtime.cutab 778 // for i=0..#CUs 779 // for j=0..#max used file index in CU[i] 780 // uint32 offset into runtime.filetab for the filename[j] 781 // 782 // runtime.filetab 783 // []null terminated filename strings 784 // 785 // runtime.pctab 786 // []byte of deduplicated pc data. 787 // 788 // runtime.functab 789 // function table, alternating PC and offset to func struct [each entry thearch.ptrsize bytes] 790 // end PC [thearch.ptrsize bytes] 791 // func structures, pcdata offsets, func data. 792 793 state, compUnits, funcs := makePclntab(ctxt, container) 794 795 ldr := ctxt.loader 796 state.carrier = ldr.LookupOrCreateSym("runtime.pclntab", 0) 797 ldr.MakeSymbolUpdater(state.carrier).SetType(sym.SPCLNTAB) 798 ldr.SetAttrReachable(state.carrier, true) 799 setCarrierSym(sym.SPCLNTAB, state.carrier) 800 801 state.generatePCHeader(ctxt) 802 nameOffsets := state.generateFuncnametab(ctxt, funcs) 803 cuOffsets := state.generateFilenameTabs(ctxt, compUnits, funcs) 804 state.generatePctab(ctxt, funcs) 805 inlSyms := makeInlSyms(ctxt, funcs, nameOffsets) 806 state.generateFunctab(ctxt, funcs, inlSyms, cuOffsets, nameOffsets) 807 808 return state 809 } 810 811 func gorootFinal() string { 812 root := buildcfg.GOROOT 813 if final := os.Getenv("GOROOT_FINAL"); final != "" { 814 root = final 815 } 816 return root 817 } 818 819 func expandGoroot(s string) string { 820 const n = len("$GOROOT") 821 if len(s) >= n+1 && s[:n] == "$GOROOT" && (s[n] == '/' || s[n] == '\\') { 822 if final := gorootFinal(); final != "" { 823 return filepath.ToSlash(filepath.Join(final, s[n:])) 824 } 825 } 826 return s 827 } 828 829 const ( 830 BUCKETSIZE = 256 * MINFUNC 831 SUBBUCKETS = 16 832 SUBBUCKETSIZE = BUCKETSIZE / SUBBUCKETS 833 NOIDX = 0x7fffffff 834 ) 835 836 // findfunctab generates a lookup table to quickly find the containing 837 // function for a pc. See src/runtime/symtab.go:findfunc for details. 838 func (ctxt *Link) findfunctab(state *pclntab, container loader.Bitmap) { 839 ldr := ctxt.loader 840 841 // find min and max address 842 min := ldr.SymValue(ctxt.Textp[0]) 843 lastp := ctxt.Textp[len(ctxt.Textp)-1] 844 max := ldr.SymValue(lastp) + ldr.SymSize(lastp) 845 846 // for each subbucket, compute the minimum of all symbol indexes 847 // that map to that subbucket. 848 n := int32((max - min + SUBBUCKETSIZE - 1) / SUBBUCKETSIZE) 849 850 nbuckets := int32((max - min + BUCKETSIZE - 1) / BUCKETSIZE) 851 852 size := 4*int64(nbuckets) + int64(n) 853 854 writeFindFuncTab := func(_ *Link, s loader.Sym) { 855 t := ldr.MakeSymbolUpdater(s) 856 857 indexes := make([]int32, n) 858 for i := int32(0); i < n; i++ { 859 indexes[i] = NOIDX 860 } 861 idx := int32(0) 862 for i, s := range ctxt.Textp { 863 if !emitPcln(ctxt, s, container) { 864 continue 865 } 866 p := ldr.SymValue(s) 867 var e loader.Sym 868 i++ 869 if i < len(ctxt.Textp) { 870 e = ctxt.Textp[i] 871 } 872 for e != 0 && !emitPcln(ctxt, e, container) && i < len(ctxt.Textp) { 873 e = ctxt.Textp[i] 874 i++ 875 } 876 q := max 877 if e != 0 { 878 q = ldr.SymValue(e) 879 } 880 881 //print("%d: [%lld %lld] %s\n", idx, p, q, s->name); 882 for ; p < q; p += SUBBUCKETSIZE { 883 i = int((p - min) / SUBBUCKETSIZE) 884 if indexes[i] > idx { 885 indexes[i] = idx 886 } 887 } 888 889 i = int((q - 1 - min) / SUBBUCKETSIZE) 890 if indexes[i] > idx { 891 indexes[i] = idx 892 } 893 idx++ 894 } 895 896 // fill in table 897 for i := int32(0); i < nbuckets; i++ { 898 base := indexes[i*SUBBUCKETS] 899 if base == NOIDX { 900 Errorf(nil, "hole in findfunctab") 901 } 902 t.SetUint32(ctxt.Arch, int64(i)*(4+SUBBUCKETS), uint32(base)) 903 for j := int32(0); j < SUBBUCKETS && i*SUBBUCKETS+j < n; j++ { 904 idx = indexes[i*SUBBUCKETS+j] 905 if idx == NOIDX { 906 Errorf(nil, "hole in findfunctab") 907 } 908 if idx-base >= 256 { 909 Errorf(nil, "too many functions in a findfunc bucket! %d/%d %d %d", i, nbuckets, j, idx-base) 910 } 911 912 t.SetUint8(ctxt.Arch, int64(i)*(4+SUBBUCKETS)+4+int64(j), uint8(idx-base)) 913 } 914 } 915 } 916 917 state.findfunctab = ctxt.createGeneratorSymbol("runtime.findfunctab", 0, sym.SRODATA, size, writeFindFuncTab) 918 ldr.SetAttrReachable(state.findfunctab, true) 919 ldr.SetAttrLocal(state.findfunctab, true) 920 } 921 922 // findContainerSyms returns a bitmap, indexed by symbol number, where there's 923 // a 1 for every container symbol. 924 func (ctxt *Link) findContainerSyms() loader.Bitmap { 925 ldr := ctxt.loader 926 container := loader.MakeBitmap(ldr.NSym()) 927 // Find container symbols and mark them as such. 928 for _, s := range ctxt.Textp { 929 outer := ldr.OuterSym(s) 930 if outer != 0 { 931 container.Set(outer) 932 } 933 } 934 return container 935 }