Source file src/cmd/link/internal/ld/pcln.go

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

View as plain text