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.
11 "cmd/link/internal/loader"
12 "cmd/link/internal/sym"
20 const funcSize = 10 * 4 // funcSize is the size of the _func object in runtime/runtime2.go
22 // pclntab holds the state needed for pclntab generation.
24 // The first and last functions found.
25 firstFunc, lastFunc loader.Sym
27 // Running total size of pclntab.
30 // runtime.pclntab's symbols
34 funcnametab loader.Sym
35 findfunctab loader.Sym
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
46 // On most platforms this is the number of reachable functions.
49 // The number of filenames in runtime.filetab.
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.
55 func (state *pclntab) addGeneratedSym(ctxt *Link, name string, size int64, f generatorFunc) loader.Sym {
56 size = Rnd(size, int64(ctxt.Arch.PtrSize))
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)
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
69 func makePclntab(ctxt *Link, container loader.Bitmap) (*pclntab, []*sym.CompilationUnit, []loader.Sym) {
73 // Gather some basic stats and info.
74 seenCUs := make(map[*sym.CompilationUnit]struct{})
75 compUnits := []*sym.CompilationUnit{}
76 funcs := []loader.Sym{}
78 for _, s := range ctxt.Textp {
79 if !emitPcln(ctxt, s, container) {
82 funcs = append(funcs, s)
84 if state.firstFunc == 0 {
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.
92 if _, ok := seenCUs[cu]; cu != nil && !ok {
93 seenCUs[cu] = struct{}{}
94 cu.PclnIndex = len(compUnits)
95 compUnits = append(compUnits, cu)
98 return state, compUnits, funcs
101 func emitPcln(ctxt *Link, s loader.Sym, container loader.Bitmap) bool {
102 // We want to generate func table entries only for the "lowest
103 // level" symbols, not containers of subsymbols.
104 return !container.Has(s)
107 func computeDeferReturn(ctxt *Link, deferReturnSym, s loader.Sym) uint32 {
109 target := ctxt.Target
110 deferreturn := uint32(0)
111 lastWasmAddr := uint32(0)
113 relocs := ldr.Relocs(s)
114 for ri := 0; ri < relocs.Count(); ri++ {
116 if target.IsWasm() && r.Type() == objabi.R_ADDR {
117 // wasm/ssa.go generates an ARESUMEPOINT just
118 // before the deferreturn call. The "PC" of
119 // the deferreturn call is stored in the
120 // R_ADDR relocation on the ARESUMEPOINT.
121 lastWasmAddr = uint32(r.Add())
123 if r.Type().IsDirectCall() && (r.Sym() == deferReturnSym || ldr.IsDeferReturnTramp(r.Sym())) {
125 deferreturn = lastWasmAddr - 1
127 // Note: the relocation target is in the call instruction, but
128 // is not necessarily the whole instruction (for instance, on
129 // x86 the relocation applies to bytes [1:5] of the 5 byte call
131 deferreturn = uint32(r.Off())
132 switch target.Arch.Family {
133 case sys.AMD64, sys.I386:
135 case sys.ARM, sys.ARM64, sys.Loong64, sys.MIPS, sys.MIPS64, sys.PPC64, sys.RISCV64:
140 panic(fmt.Sprint("Unhandled architecture:", target.Arch.Family))
143 break // only need one
149 // genInlTreeSym generates the InlTree sym for a function with the
150 // specified FuncInfo.
151 func genInlTreeSym(ctxt *Link, cu *sym.CompilationUnit, fi loader.FuncInfo, arch *sys.Arch, nameOffsets map[loader.Sym]uint32) loader.Sym {
153 its := ldr.CreateExtSym("", 0)
154 inlTreeSym := ldr.MakeSymbolUpdater(its)
155 // Note: the generated symbol is given a type of sym.SGOFUNC, as a
156 // signal to the symtab() phase that it needs to be grouped in with
157 // other similar symbols (gcdata, etc); the dodata() phase will
158 // eventually switch the type back to SRODATA.
159 inlTreeSym.SetType(sym.SGOFUNC)
160 ldr.SetAttrReachable(its, true)
161 ldr.SetSymAlign(its, 4) // it has 32-bit fields
162 ninl := fi.NumInlTree()
163 for i := 0; i < int(ninl); i++ {
164 call := fi.InlTree(i)
166 nameoff, ok := nameOffsets[call.Func]
168 panic("couldn't find function name offset")
171 inlTreeSym.SetUint16(arch, int64(i*20+0), uint16(call.Parent))
172 inlFunc := ldr.FuncInfo(call.Func)
174 var funcID objabi.FuncID
176 funcID = inlFunc.FuncID()
178 inlTreeSym.SetUint8(arch, int64(i*20+2), uint8(funcID))
181 inlTreeSym.SetUint32(arch, int64(i*20+4), uint32(val))
182 inlTreeSym.SetUint32(arch, int64(i*20+8), uint32(call.Line))
183 inlTreeSym.SetUint32(arch, int64(i*20+12), uint32(nameoff))
184 inlTreeSym.SetUint32(arch, int64(i*20+16), uint32(call.ParentPC))
189 // makeInlSyms returns a map of loader.Sym that are created inlSyms.
190 func makeInlSyms(ctxt *Link, funcs []loader.Sym, nameOffsets map[loader.Sym]uint32) map[loader.Sym]loader.Sym {
192 // Create the inline symbols we need.
193 inlSyms := make(map[loader.Sym]loader.Sym)
194 for _, s := range funcs {
195 if fi := ldr.FuncInfo(s); fi.Valid() {
197 if fi.NumInlTree() > 0 {
198 inlSyms[s] = genInlTreeSym(ctxt, ldr.SymUnit(s), fi, ctxt.Arch, nameOffsets)
205 // generatePCHeader creates the runtime.pcheader symbol, setting it up as a
206 // generator to fill in its data later.
207 func (state *pclntab) generatePCHeader(ctxt *Link) {
209 textStartOff := int64(8 + 2*ctxt.Arch.PtrSize)
210 size := int64(8 + 8*ctxt.Arch.PtrSize)
211 writeHeader := func(ctxt *Link, s loader.Sym) {
212 header := ctxt.loader.MakeSymbolUpdater(s)
214 writeSymOffset := func(off int64, ws loader.Sym) int64 {
215 diff := ldr.SymValue(ws) - ldr.SymValue(s)
217 name := ldr.SymName(ws)
218 panic(fmt.Sprintf("expected runtime.pcheader(%x) to be placed before %s(%x)", ldr.SymValue(s), name, ldr.SymValue(ws)))
220 return header.SetUintptr(ctxt.Arch, off, uintptr(diff))
224 // Keep in sync with runtime/symtab.go:pcHeader and package debug/gosym.
225 header.SetUint32(ctxt.Arch, 0, 0xfffffff1)
226 header.SetUint8(ctxt.Arch, 6, uint8(ctxt.Arch.MinLC))
227 header.SetUint8(ctxt.Arch, 7, uint8(ctxt.Arch.PtrSize))
228 off := header.SetUint(ctxt.Arch, 8, uint64(state.nfunc))
229 off = header.SetUint(ctxt.Arch, off, uint64(state.nfiles))
230 if off != textStartOff {
231 panic(fmt.Sprintf("pcHeader textStartOff: %d != %d", off, textStartOff))
233 off += int64(ctxt.Arch.PtrSize) // skip runtimeText relocation
234 off = writeSymOffset(off, state.funcnametab)
235 off = writeSymOffset(off, state.cutab)
236 off = writeSymOffset(off, state.filetab)
237 off = writeSymOffset(off, state.pctab)
238 off = writeSymOffset(off, state.pclntab)
240 panic(fmt.Sprintf("pcHeader size: %d != %d", off, size))
244 state.pcheader = state.addGeneratedSym(ctxt, "runtime.pcheader", size, writeHeader)
245 // Create the runtimeText relocation.
246 sb := ldr.MakeSymbolUpdater(state.pcheader)
247 sb.SetAddr(ctxt.Arch, textStartOff, ldr.Lookup("runtime.text", 0))
250 // walkFuncs iterates over the funcs, calling a function for each unique
251 // function and inlined function.
252 func walkFuncs(ctxt *Link, funcs []loader.Sym, f func(loader.Sym)) {
254 seen := make(map[loader.Sym]struct{})
255 for _, s := range funcs {
256 if _, ok := seen[s]; !ok {
261 fi := ldr.FuncInfo(s)
266 for i, ni := 0, fi.NumInlTree(); i < int(ni); i++ {
267 call := fi.InlTree(i).Func
268 if _, ok := seen[call]; !ok {
270 seen[call] = struct{}{}
276 // generateFuncnametab creates the function name table. Returns a map of
277 // func symbol to the name offset in runtime.funcnamtab.
278 func (state *pclntab) generateFuncnametab(ctxt *Link, funcs []loader.Sym) map[loader.Sym]uint32 {
279 nameOffsets := make(map[loader.Sym]uint32, state.nfunc)
281 // The name used by the runtime is the concatenation of the 3 returned strings.
282 // For regular functions, only one returned string is nonempty.
283 // For generic functions, we use three parts so that we can print everything
284 // within the outermost "[]" as "...".
285 nameParts := func(name string) (string, string, string) {
286 i := strings.IndexByte(name, '[')
290 // TODO: use LastIndexByte once the bootstrap compiler is >= Go 1.5.
292 for j > i && name[j] != ']' {
298 return name[:i], "[...]", name[j+1:]
301 // Write the null terminated strings.
302 writeFuncNameTab := func(ctxt *Link, s loader.Sym) {
303 symtab := ctxt.loader.MakeSymbolUpdater(s)
304 for s, off := range nameOffsets {
305 a, b, c := nameParts(ctxt.loader.SymName(s))
307 o = symtab.AddStringAt(o, a)
308 o = symtab.AddStringAt(o, b)
309 _ = symtab.AddCStringAt(o, c)
313 // Loop through the CUs, and calculate the size needed.
315 walkFuncs(ctxt, funcs, func(s loader.Sym) {
316 nameOffsets[s] = uint32(size)
317 a, b, c := nameParts(ctxt.loader.SymName(s))
318 size += int64(len(a) + len(b) + len(c) + 1) // NULL terminate
321 state.funcnametab = state.addGeneratedSym(ctxt, "runtime.funcnametab", size, writeFuncNameTab)
325 // walkFilenames walks funcs, calling a function for each filename used in each
326 // function's line table.
327 func walkFilenames(ctxt *Link, funcs []loader.Sym, f func(*sym.CompilationUnit, goobj.CUFileIndex)) {
330 // Loop through all functions, finding the filenames we need.
331 for _, s := range funcs {
332 fi := ldr.FuncInfo(s)
339 for i, nf := 0, int(fi.NumFile()); i < nf; i++ {
342 for i, ninl := 0, int(fi.NumInlTree()); i < ninl; i++ {
343 call := fi.InlTree(i)
349 // generateFilenameTabs creates LUTs needed for filename lookup. Returns a slice
350 // of the index at which each CU begins in runtime.cutab.
352 // Function objects keep track of the files they reference to print the stack.
353 // This function creates a per-CU list of filenames if CU[M] references
354 // files[1-N], the following is generated:
358 // offsetToFilename[0]
359 // offsetToFilename[1]
366 // Looking up a filename then becomes:
367 // 0. Given a func, and filename index [K]
368 // 1. Get Func.CUIndex: M := func.cuOffset
369 // 2. Find filename offset: fileOffset := runtime.cutab[M+K]
370 // 3. Get the filename: getcstring(runtime.filetab[fileOffset])
371 func (state *pclntab) generateFilenameTabs(ctxt *Link, compUnits []*sym.CompilationUnit, funcs []loader.Sym) []uint32 {
372 // On a per-CU basis, keep track of all the filenames we need.
374 // Note, that we store the filenames in a separate section in the object
375 // files, and deduplicate based on the actual value. It would be better to
376 // store the filenames as symbols, using content addressable symbols (and
377 // then not loading extra filenames), and just use the hash value of the
378 // symbol name to do this cataloging.
380 // TODO: Store filenames as symbols. (Note this would be easiest if you
381 // also move strings to ALWAYS using the larger content addressable hash
382 // function, and use that hash value for uniqueness testing.)
383 cuEntries := make([]goobj.CUFileIndex, len(compUnits))
384 fileOffsets := make(map[string]uint32)
386 // Walk the filenames.
387 // We store the total filename string length we need to load, and the max
388 // file index we've seen per CU so we can calculate how large the
389 // CU->global table needs to be.
391 walkFilenames(ctxt, funcs, func(cu *sym.CompilationUnit, i goobj.CUFileIndex) {
392 // Note we use the raw filename for lookup, but use the expanded filename
393 // when we save the size.
394 filename := cu.FileTable[i]
395 if _, ok := fileOffsets[filename]; !ok {
396 fileOffsets[filename] = uint32(fileSize)
397 fileSize += int64(len(expandFile(filename)) + 1) // NULL terminate
400 // Find the maximum file index we've seen.
401 if cuEntries[cu.PclnIndex] < i+1 {
402 cuEntries[cu.PclnIndex] = i + 1 // Store max + 1
406 // Calculate the size of the runtime.cutab variable.
407 var totalEntries uint32
408 cuOffsets := make([]uint32, len(cuEntries))
409 for i, entries := range cuEntries {
410 // Note, cutab is a slice of uint32, so an offset to a cu's entry is just the
411 // running total of all cu indices we've needed to store so far, not the
412 // number of bytes we've stored so far.
413 cuOffsets[i] = totalEntries
414 totalEntries += uint32(entries)
418 writeCutab := func(ctxt *Link, s loader.Sym) {
419 sb := ctxt.loader.MakeSymbolUpdater(s)
422 for i, max := range cuEntries {
423 // Write the per CU LUT.
425 for j := goobj.CUFileIndex(0); j < max; j++ {
426 fileOffset, ok := fileOffsets[cu.FileTable[j]]
428 // We're looping through all possible file indices. It's possible a file's
429 // been deadcode eliminated, and although it's a valid file in the CU, it's
430 // not needed in this binary. When that happens, use an invalid offset.
431 fileOffset = ^uint32(0)
433 off = sb.SetUint32(ctxt.Arch, off, fileOffset)
437 state.cutab = state.addGeneratedSym(ctxt, "runtime.cutab", int64(totalEntries*4), writeCutab)
440 writeFiletab := func(ctxt *Link, s loader.Sym) {
441 sb := ctxt.loader.MakeSymbolUpdater(s)
443 // Write the strings.
444 for filename, loc := range fileOffsets {
445 sb.AddStringAt(int64(loc), expandFile(filename))
448 state.nfiles = uint32(len(fileOffsets))
449 state.filetab = state.addGeneratedSym(ctxt, "runtime.filetab", fileSize, writeFiletab)
454 // generatePctab creates the runtime.pctab variable, holding all the
455 // deduplicated pcdata.
456 func (state *pclntab) generatePctab(ctxt *Link, funcs []loader.Sym) {
459 // Pctab offsets of 0 are considered invalid in the runtime. We respect
460 // that by just padding a single byte at the beginning of runtime.pctab,
461 // that way no real offsets can be zero.
464 // Walk the functions, finding offset to store each pcdata.
465 seen := make(map[loader.Sym]struct{})
466 saveOffset := func(pcSym loader.Sym) {
467 if _, ok := seen[pcSym]; !ok {
468 datSize := ldr.SymSize(pcSym)
470 ldr.SetSymValue(pcSym, size)
472 // Invalid PC data, record as zero.
473 ldr.SetSymValue(pcSym, 0)
476 seen[pcSym] = struct{}{}
479 var pcsp, pcline, pcfile, pcinline loader.Sym
480 var pcdata []loader.Sym
481 for _, s := range funcs {
482 fi := ldr.FuncInfo(s)
487 pcsp, pcfile, pcline, pcinline, pcdata = ldr.PcdataAuxs(s, pcdata)
489 pcSyms := []loader.Sym{pcsp, pcfile, pcline}
490 for _, pcSym := range pcSyms {
493 for _, pcSym := range pcdata {
496 if fi.NumInlTree() > 0 {
501 // TODO: There is no reason we need a generator for this variable, and it
502 // could be moved to a carrier symbol. However, carrier symbols containing
503 // carrier symbols don't work yet (as of Aug 2020). Once this is fixed,
504 // runtime.pctab could just be a carrier sym.
505 writePctab := func(ctxt *Link, s loader.Sym) {
507 sb := ldr.MakeSymbolUpdater(s)
508 for sym := range seen {
509 sb.SetBytesAt(ldr.SymValue(sym), ldr.Data(sym))
513 state.pctab = state.addGeneratedSym(ctxt, "runtime.pctab", size, writePctab)
516 // numPCData returns the number of PCData syms for the FuncInfo.
517 // NB: Preload must be called on valid FuncInfos before calling this function.
518 func numPCData(ldr *loader.Loader, s loader.Sym, fi loader.FuncInfo) uint32 {
522 numPCData := uint32(ldr.NumPcdata(s))
523 if fi.NumInlTree() > 0 {
524 if numPCData < objabi.PCDATA_InlTreeIndex+1 {
525 numPCData = objabi.PCDATA_InlTreeIndex + 1
531 // generateFunctab creates the runtime.functab
533 // runtime.functab contains two things:
535 // - pc->func look up table.
536 // - array of func objects, interleaved with pcdata and funcdata
537 func (state *pclntab) generateFunctab(ctxt *Link, funcs []loader.Sym, inlSyms map[loader.Sym]loader.Sym, cuOffsets []uint32, nameOffsets map[loader.Sym]uint32) {
538 // Calculate the size of the table.
539 size, startLocations := state.calculateFunctabSize(ctxt, funcs)
540 writePcln := func(ctxt *Link, s loader.Sym) {
542 sb := ldr.MakeSymbolUpdater(s)
544 writePCToFunc(ctxt, sb, funcs, startLocations)
545 writeFuncs(ctxt, sb, funcs, inlSyms, startLocations, cuOffsets, nameOffsets)
547 state.pclntab = state.addGeneratedSym(ctxt, "runtime.functab", size, writePcln)
550 // funcData returns the funcdata and offsets for the FuncInfo.
551 // The funcdata are written into runtime.functab after each func
552 // object. This is a helper function to make querying the FuncInfo object
555 // NB: Preload must be called on the FuncInfo before calling.
556 // NB: fdSyms is used as scratch space.
557 func funcData(ldr *loader.Loader, s loader.Sym, fi loader.FuncInfo, inlSym loader.Sym, fdSyms []loader.Sym) []loader.Sym {
560 fdSyms = ldr.Funcdata(s, fdSyms)
561 if fi.NumInlTree() > 0 {
562 if len(fdSyms) < objabi.FUNCDATA_InlTree+1 {
563 fdSyms = append(fdSyms, make([]loader.Sym, objabi.FUNCDATA_InlTree+1-len(fdSyms))...)
565 fdSyms[objabi.FUNCDATA_InlTree] = inlSym
571 // calculateFunctabSize calculates the size of the pclntab, and the offsets in
572 // the output buffer for individual func entries.
573 func (state pclntab) calculateFunctabSize(ctxt *Link, funcs []loader.Sym) (int64, []uint32) {
575 startLocations := make([]uint32, len(funcs))
577 // Allocate space for the pc->func table. This structure consists of a pc offset
578 // and an offset to the func structure. After that, we have a single pc
579 // value that marks the end of the last function in the binary.
580 size := int64(int(state.nfunc)*2*4 + 4)
582 // Now find the space for the func objects. We do this in a running manner,
583 // so that we can find individual starting locations.
584 for i, s := range funcs {
585 size = Rnd(size, int64(ctxt.Arch.PtrSize))
586 startLocations[i] = uint32(size)
587 fi := ldr.FuncInfo(s)
591 numFuncData := ldr.NumFuncdata(s)
592 if fi.NumInlTree() > 0 {
593 if numFuncData < objabi.FUNCDATA_InlTree+1 {
594 numFuncData = objabi.FUNCDATA_InlTree + 1
597 size += int64(numPCData(ldr, s, fi) * 4)
598 size += int64(numFuncData * 4)
602 return size, startLocations
605 // writePCToFunc writes the PC->func lookup table.
606 func writePCToFunc(ctxt *Link, sb *loader.SymbolBuilder, funcs []loader.Sym, startLocations []uint32) {
608 textStart := ldr.SymValue(ldr.Lookup("runtime.text", 0))
609 pcOff := func(s loader.Sym) uint32 {
610 off := ldr.SymValue(s) - textStart
612 panic(fmt.Sprintf("expected func %s(%x) to be placed at or after textStart (%x)", ldr.SymName(s), ldr.SymValue(s), textStart))
616 for i, s := range funcs {
617 sb.SetUint32(ctxt.Arch, int64(i*2*4), pcOff(s))
618 sb.SetUint32(ctxt.Arch, int64((i*2+1)*4), startLocations[i])
621 // Final entry of table is just end pc offset.
622 lastFunc := funcs[len(funcs)-1]
623 sb.SetUint32(ctxt.Arch, int64(len(funcs))*2*4, pcOff(lastFunc)+uint32(ldr.SymSize(lastFunc)))
626 // writeFuncs writes the func structures and pcdata to runtime.functab.
627 func writeFuncs(ctxt *Link, sb *loader.SymbolBuilder, funcs []loader.Sym, inlSyms map[loader.Sym]loader.Sym, startLocations, cuOffsets []uint32, nameOffsets map[loader.Sym]uint32) {
629 deferReturnSym := ldr.Lookup("runtime.deferreturn", abiInternalVer)
630 gofunc := ldr.Lookup("go:func.*", 0)
631 gofuncBase := ldr.SymValue(gofunc)
632 textStart := ldr.SymValue(ldr.Lookup("runtime.text", 0))
633 funcdata := []loader.Sym{}
634 var pcsp, pcfile, pcline, pcinline loader.Sym
635 var pcdata []loader.Sym
637 // Write the individual func objects.
638 for i, s := range funcs {
639 fi := ldr.FuncInfo(s)
642 pcsp, pcfile, pcline, pcinline, pcdata = ldr.PcdataAuxs(s, pcdata)
645 off := int64(startLocations[i])
646 // entry uintptr (offset of func entry PC from textStart)
647 entryOff := ldr.SymValue(s) - textStart
649 panic(fmt.Sprintf("expected func %s(%x) to be placed before or at textStart (%x)", ldr.SymName(s), ldr.SymValue(s), textStart))
651 off = sb.SetUint32(ctxt.Arch, off, uint32(entryOff))
654 nameoff, ok := nameOffsets[s]
656 panic("couldn't find function name offset")
658 off = sb.SetUint32(ctxt.Arch, off, uint32(nameoff))
661 // TODO: Move into funcinfo.
664 args = uint32(fi.Args())
666 off = sb.SetUint32(ctxt.Arch, off, args)
669 deferreturn := computeDeferReturn(ctxt, deferReturnSym, s)
670 off = sb.SetUint32(ctxt.Arch, off, deferreturn)
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)))
680 off = sb.SetUint32(ctxt.Arch, off, uint32(numPCData(ldr, s, fi)))
682 // Store the offset to compilation unit's file table.
684 if cu := ldr.SymUnit(s); cu != nil {
685 cuIdx = cuOffsets[cu.PclnIndex]
687 off = sb.SetUint32(ctxt.Arch, off, cuIdx)
690 var funcID objabi.FuncID
694 off = sb.SetUint8(ctxt.Arch, off, uint8(funcID))
697 var flag objabi.FuncFlag
701 off = sb.SetUint8(ctxt.Arch, off, uint8(flag))
705 // nfuncdata must be the final entry.
706 funcdata = funcData(ldr, s, fi, 0, funcdata)
707 off = sb.SetUint8(ctxt.Arch, off, uint8(len(funcdata)))
709 // Output the pcdata.
711 for j, pcSym := range pcdata {
712 sb.SetUint32(ctxt.Arch, off+int64(j*4), uint32(ldr.SymValue(pcSym)))
714 if fi.NumInlTree() > 0 {
715 sb.SetUint32(ctxt.Arch, off+objabi.PCDATA_InlTreeIndex*4, uint32(ldr.SymValue(pcinline)))
719 // Write funcdata refs as offsets from go:func.* and go:funcrel.*.
720 funcdata = funcData(ldr, s, fi, inlSyms[s], funcdata)
721 // Missing funcdata will be ^0. See runtime/symtab.go:funcdata.
722 off = int64(startLocations[i] + funcSize + numPCData(ldr, s, fi)*4)
723 for j := range funcdata {
724 dataoff := off + int64(4*j)
727 sb.SetUint32(ctxt.Arch, dataoff, ^uint32(0)) // ^0 is a sentinel for "no value"
731 if outer := ldr.OuterSym(fdsym); outer != gofunc {
732 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)))
734 sb.SetUint32(ctxt.Arch, dataoff, uint32(ldr.SymValue(fdsym)-gofuncBase))
739 // pclntab initializes the pclntab symbol with
740 // runtime function and file name information.
742 // pclntab generates the pcln table for the link output.
743 func (ctxt *Link) pclntab(container loader.Bitmap) *pclntab {
744 // Go 1.2's symtab layout is documented in golang.org/s/go12symtab, but the
745 // layout and data has changed since that time.
747 // As of August 2020, here's the layout of pclntab:
749 // .gopclntab/__gopclntab [elf/macho section]
751 // Carrier symbol for the entire pclntab section.
753 // runtime.pcheader (see: runtime/symtab.go:pcHeader)
755 // nfunc [thearch.ptrsize bytes]
756 // offset to runtime.funcnametab from the beginning of runtime.pcheader
757 // offset to runtime.pclntab_old from beginning of runtime.pcheader
759 // runtime.funcnametab
760 // []list of null terminated function names
764 // for j=0..#max used file index in CU[i]
765 // uint32 offset into runtime.filetab for the filename[j]
768 // []null terminated filename strings
771 // []byte of deduplicated pc data.
774 // function table, alternating PC and offset to func struct [each entry thearch.ptrsize bytes]
775 // end PC [thearch.ptrsize bytes]
776 // func structures, pcdata offsets, func data.
778 state, compUnits, funcs := makePclntab(ctxt, container)
781 state.carrier = ldr.LookupOrCreateSym("runtime.pclntab", 0)
782 ldr.MakeSymbolUpdater(state.carrier).SetType(sym.SPCLNTAB)
783 ldr.SetAttrReachable(state.carrier, true)
784 setCarrierSym(sym.SPCLNTAB, state.carrier)
786 state.generatePCHeader(ctxt)
787 nameOffsets := state.generateFuncnametab(ctxt, funcs)
788 cuOffsets := state.generateFilenameTabs(ctxt, compUnits, funcs)
789 state.generatePctab(ctxt, funcs)
790 inlSyms := makeInlSyms(ctxt, funcs, nameOffsets)
791 state.generateFunctab(ctxt, funcs, inlSyms, cuOffsets, nameOffsets)
796 func gorootFinal() string {
797 root := buildcfg.GOROOT
798 if final := os.Getenv("GOROOT_FINAL"); final != "" {
804 func expandGoroot(s string) string {
805 const n = len("$GOROOT")
806 if len(s) >= n+1 && s[:n] == "$GOROOT" && (s[n] == '/' || s[n] == '\\') {
807 if final := gorootFinal(); final != "" {
808 return filepath.ToSlash(filepath.Join(final, s[n:]))
815 BUCKETSIZE = 256 * MINFUNC
817 SUBBUCKETSIZE = BUCKETSIZE / SUBBUCKETS
821 // findfunctab generates a lookup table to quickly find the containing
822 // function for a pc. See src/runtime/symtab.go:findfunc for details.
823 func (ctxt *Link) findfunctab(state *pclntab, container loader.Bitmap) {
826 // find min and max address
827 min := ldr.SymValue(ctxt.Textp[0])
828 lastp := ctxt.Textp[len(ctxt.Textp)-1]
829 max := ldr.SymValue(lastp) + ldr.SymSize(lastp)
831 // for each subbucket, compute the minimum of all symbol indexes
832 // that map to that subbucket.
833 n := int32((max - min + SUBBUCKETSIZE - 1) / SUBBUCKETSIZE)
835 nbuckets := int32((max - min + BUCKETSIZE - 1) / BUCKETSIZE)
837 size := 4*int64(nbuckets) + int64(n)
839 writeFindFuncTab := func(_ *Link, s loader.Sym) {
840 t := ldr.MakeSymbolUpdater(s)
842 indexes := make([]int32, n)
843 for i := int32(0); i < n; i++ {
847 for i, s := range ctxt.Textp {
848 if !emitPcln(ctxt, s, container) {
854 if i < len(ctxt.Textp) {
857 for e != 0 && !emitPcln(ctxt, e, container) && i < len(ctxt.Textp) {
866 //print("%d: [%lld %lld] %s\n", idx, p, q, s->name);
867 for ; p < q; p += SUBBUCKETSIZE {
868 i = int((p - min) / SUBBUCKETSIZE)
869 if indexes[i] > idx {
874 i = int((q - 1 - min) / SUBBUCKETSIZE)
875 if indexes[i] > idx {
882 for i := int32(0); i < nbuckets; i++ {
883 base := indexes[i*SUBBUCKETS]
885 Errorf(nil, "hole in findfunctab")
887 t.SetUint32(ctxt.Arch, int64(i)*(4+SUBBUCKETS), uint32(base))
888 for j := int32(0); j < SUBBUCKETS && i*SUBBUCKETS+j < n; j++ {
889 idx = indexes[i*SUBBUCKETS+j]
891 Errorf(nil, "hole in findfunctab")
894 Errorf(nil, "too many functions in a findfunc bucket! %d/%d %d %d", i, nbuckets, j, idx-base)
897 t.SetUint8(ctxt.Arch, int64(i)*(4+SUBBUCKETS)+4+int64(j), uint8(idx-base))
902 state.findfunctab = ctxt.createGeneratorSymbol("runtime.findfunctab", 0, sym.SRODATA, size, writeFindFuncTab)
903 ldr.SetAttrReachable(state.findfunctab, true)
904 ldr.SetAttrLocal(state.findfunctab, true)
907 // findContainerSyms returns a bitmap, indexed by symbol number, where there's
908 // a 1 for every container symbol.
909 func (ctxt *Link) findContainerSyms() loader.Bitmap {
911 container := loader.MakeBitmap(ldr.NSym())
912 // Find container symbols and mark them as such.
913 for _, s := range ctxt.Textp {
914 outer := ldr.OuterSym(s)