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

View as plain text