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