Black Lives Matter. Support the Equal Justice Initiative.

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

Documentation: cmd/link/internal/ld

     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/buildcfg"
    15  	"os"
    16  	"path/filepath"
    17  )
    18  
    19  // pclntab holds the state needed for pclntab generation.
    20  type pclntab struct {
    21  	// The size of the func object in the runtime.
    22  	funcSize uint32
    23  
    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 they 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  
    72  	state := &pclntab{
    73  		// This is the size of the _func object in runtime/runtime2.go.
    74  		funcSize: uint32(ctxt.Arch.PtrSize + 9*4),
    75  	}
    76  
    77  	// Gather some basic stats and info.
    78  	seenCUs := make(map[*sym.CompilationUnit]struct{})
    79  	prevSect := ldr.SymSect(ctxt.Textp[0])
    80  	compUnits := []*sym.CompilationUnit{}
    81  	funcs := []loader.Sym{}
    82  
    83  	for _, s := range ctxt.Textp {
    84  		if !emitPcln(ctxt, s, container) {
    85  			continue
    86  		}
    87  		funcs = append(funcs, s)
    88  		state.nfunc++
    89  		if state.firstFunc == 0 {
    90  			state.firstFunc = s
    91  		}
    92  		state.lastFunc = s
    93  		ss := ldr.SymSect(s)
    94  		if ss != prevSect {
    95  			// With multiple text sections, the external linker may
    96  			// insert functions between the sections, which are not
    97  			// known by Go. This leaves holes in the PC range covered
    98  			// by the func table. We need to generate an entry to mark
    99  			// the hole.
   100  			state.nfunc++
   101  			prevSect = ss
   102  		}
   103  
   104  		// We need to keep track of all compilation units we see. Some symbols
   105  		// (eg, go.buildid, _cgoexp_, etc) won't have a compilation unit.
   106  		cu := ldr.SymUnit(s)
   107  		if _, ok := seenCUs[cu]; cu != nil && !ok {
   108  			seenCUs[cu] = struct{}{}
   109  			cu.PclnIndex = len(compUnits)
   110  			compUnits = append(compUnits, cu)
   111  		}
   112  	}
   113  	return state, compUnits, funcs
   114  }
   115  
   116  func emitPcln(ctxt *Link, s loader.Sym, container loader.Bitmap) bool {
   117  	// We want to generate func table entries only for the "lowest
   118  	// level" symbols, not containers of subsymbols.
   119  	return !container.Has(s)
   120  }
   121  
   122  func computeDeferReturn(ctxt *Link, deferReturnSym, s loader.Sym) uint32 {
   123  	ldr := ctxt.loader
   124  	target := ctxt.Target
   125  	deferreturn := uint32(0)
   126  	lastWasmAddr := uint32(0)
   127  
   128  	relocs := ldr.Relocs(s)
   129  	for ri := 0; ri < relocs.Count(); ri++ {
   130  		r := relocs.At(ri)
   131  		if target.IsWasm() && r.Type() == objabi.R_ADDR {
   132  			// Wasm does not have a live variable set at the deferreturn
   133  			// call itself. Instead it has one identified by the
   134  			// resumption point immediately preceding the deferreturn.
   135  			// The wasm code has a R_ADDR relocation which is used to
   136  			// set the resumption point to PC_B.
   137  			lastWasmAddr = uint32(r.Add())
   138  		}
   139  		if r.Type().IsDirectCall() && (r.Sym() == deferReturnSym || ldr.IsDeferReturnTramp(r.Sym())) {
   140  			if target.IsWasm() {
   141  				deferreturn = lastWasmAddr - 1
   142  			} else {
   143  				// Note: the relocation target is in the call instruction, but
   144  				// is not necessarily the whole instruction (for instance, on
   145  				// x86 the relocation applies to bytes [1:5] of the 5 byte call
   146  				// instruction).
   147  				deferreturn = uint32(r.Off())
   148  				switch target.Arch.Family {
   149  				case sys.AMD64, sys.I386:
   150  					deferreturn--
   151  				case sys.PPC64, sys.ARM, sys.ARM64, sys.MIPS, sys.MIPS64:
   152  					// no change
   153  				case sys.RISCV64:
   154  					// TODO(jsing): The JALR instruction is marked with
   155  					// R_CALLRISCV, whereas the actual reloc is currently
   156  					// one instruction earlier starting with the AUIPC.
   157  					deferreturn -= 4
   158  				case sys.S390X:
   159  					deferreturn -= 2
   160  				default:
   161  					panic(fmt.Sprint("Unhandled architecture:", target.Arch.Family))
   162  				}
   163  			}
   164  			break // only need one
   165  		}
   166  	}
   167  	return deferreturn
   168  }
   169  
   170  // genInlTreeSym generates the InlTree sym for a function with the
   171  // specified FuncInfo.
   172  func genInlTreeSym(ctxt *Link, cu *sym.CompilationUnit, fi loader.FuncInfo, arch *sys.Arch, nameOffsets map[loader.Sym]uint32) loader.Sym {
   173  	ldr := ctxt.loader
   174  	its := ldr.CreateExtSym("", 0)
   175  	inlTreeSym := ldr.MakeSymbolUpdater(its)
   176  	// Note: the generated symbol is given a type of sym.SGOFUNC, as a
   177  	// signal to the symtab() phase that it needs to be grouped in with
   178  	// other similar symbols (gcdata, etc); the dodata() phase will
   179  	// eventually switch the type back to SRODATA.
   180  	inlTreeSym.SetType(sym.SGOFUNC)
   181  	ldr.SetAttrReachable(its, true)
   182  	ninl := fi.NumInlTree()
   183  	for i := 0; i < int(ninl); i++ {
   184  		call := fi.InlTree(i)
   185  		val := call.File
   186  		nameoff, ok := nameOffsets[call.Func]
   187  		if !ok {
   188  			panic("couldn't find function name offset")
   189  		}
   190  
   191  		inlTreeSym.SetUint16(arch, int64(i*20+0), uint16(call.Parent))
   192  		inlFunc := ldr.FuncInfo(call.Func)
   193  
   194  		var funcID objabi.FuncID
   195  		if inlFunc.Valid() {
   196  			funcID = inlFunc.FuncID()
   197  		}
   198  		inlTreeSym.SetUint8(arch, int64(i*20+2), uint8(funcID))
   199  
   200  		// byte 3 is unused
   201  		inlTreeSym.SetUint32(arch, int64(i*20+4), uint32(val))
   202  		inlTreeSym.SetUint32(arch, int64(i*20+8), uint32(call.Line))
   203  		inlTreeSym.SetUint32(arch, int64(i*20+12), uint32(nameoff))
   204  		inlTreeSym.SetUint32(arch, int64(i*20+16), uint32(call.ParentPC))
   205  	}
   206  	return its
   207  }
   208  
   209  // makeInlSyms returns a map of loader.Sym that are created inlSyms.
   210  func makeInlSyms(ctxt *Link, funcs []loader.Sym, nameOffsets map[loader.Sym]uint32) map[loader.Sym]loader.Sym {
   211  	ldr := ctxt.loader
   212  	// Create the inline symbols we need.
   213  	inlSyms := make(map[loader.Sym]loader.Sym)
   214  	for _, s := range funcs {
   215  		if fi := ldr.FuncInfo(s); fi.Valid() {
   216  			fi.Preload()
   217  			if fi.NumInlTree() > 0 {
   218  				inlSyms[s] = genInlTreeSym(ctxt, ldr.SymUnit(s), fi, ctxt.Arch, nameOffsets)
   219  			}
   220  		}
   221  	}
   222  	return inlSyms
   223  }
   224  
   225  // generatePCHeader creates the runtime.pcheader symbol, setting it up as a
   226  // generator to fill in its data later.
   227  func (state *pclntab) generatePCHeader(ctxt *Link) {
   228  	writeHeader := func(ctxt *Link, s loader.Sym) {
   229  		ldr := ctxt.loader
   230  		header := ctxt.loader.MakeSymbolUpdater(s)
   231  
   232  		writeSymOffset := func(off int64, ws loader.Sym) int64 {
   233  			diff := ldr.SymValue(ws) - ldr.SymValue(s)
   234  			if diff <= 0 {
   235  				name := ldr.SymName(ws)
   236  				panic(fmt.Sprintf("expected runtime.pcheader(%x) to be placed before %s(%x)", ldr.SymValue(s), name, ldr.SymValue(ws)))
   237  			}
   238  			return header.SetUintptr(ctxt.Arch, off, uintptr(diff))
   239  		}
   240  
   241  		// Write header.
   242  		// Keep in sync with runtime/symtab.go:pcHeader.
   243  		header.SetUint32(ctxt.Arch, 0, 0xfffffffa)
   244  		header.SetUint8(ctxt.Arch, 6, uint8(ctxt.Arch.MinLC))
   245  		header.SetUint8(ctxt.Arch, 7, uint8(ctxt.Arch.PtrSize))
   246  		off := header.SetUint(ctxt.Arch, 8, uint64(state.nfunc))
   247  		off = header.SetUint(ctxt.Arch, off, uint64(state.nfiles))
   248  		off = writeSymOffset(off, state.funcnametab)
   249  		off = writeSymOffset(off, state.cutab)
   250  		off = writeSymOffset(off, state.filetab)
   251  		off = writeSymOffset(off, state.pctab)
   252  		off = writeSymOffset(off, state.pclntab)
   253  	}
   254  
   255  	size := int64(8 + 7*ctxt.Arch.PtrSize)
   256  	state.pcheader = state.addGeneratedSym(ctxt, "runtime.pcheader", size, writeHeader)
   257  }
   258  
   259  // walkFuncs iterates over the funcs, calling a function for each unique
   260  // function and inlined function.
   261  func walkFuncs(ctxt *Link, funcs []loader.Sym, f func(loader.Sym)) {
   262  	ldr := ctxt.loader
   263  	seen := make(map[loader.Sym]struct{})
   264  	for _, s := range funcs {
   265  		if _, ok := seen[s]; !ok {
   266  			f(s)
   267  			seen[s] = struct{}{}
   268  		}
   269  
   270  		fi := ldr.FuncInfo(s)
   271  		if !fi.Valid() {
   272  			continue
   273  		}
   274  		fi.Preload()
   275  		for i, ni := 0, fi.NumInlTree(); i < int(ni); i++ {
   276  			call := fi.InlTree(i).Func
   277  			if _, ok := seen[call]; !ok {
   278  				f(call)
   279  				seen[call] = struct{}{}
   280  			}
   281  		}
   282  	}
   283  }
   284  
   285  // generateFuncnametab creates the function name table. Returns a map of
   286  // func symbol to the name offset in runtime.funcnamtab.
   287  func (state *pclntab) generateFuncnametab(ctxt *Link, funcs []loader.Sym) map[loader.Sym]uint32 {
   288  	nameOffsets := make(map[loader.Sym]uint32, state.nfunc)
   289  
   290  	// Write the null terminated strings.
   291  	writeFuncNameTab := func(ctxt *Link, s loader.Sym) {
   292  		symtab := ctxt.loader.MakeSymbolUpdater(s)
   293  		for s, off := range nameOffsets {
   294  			symtab.AddStringAt(int64(off), ctxt.loader.SymName(s))
   295  		}
   296  	}
   297  
   298  	// Loop through the CUs, and calculate the size needed.
   299  	var size int64
   300  	walkFuncs(ctxt, funcs, func(s loader.Sym) {
   301  		nameOffsets[s] = uint32(size)
   302  		size += int64(ctxt.loader.SymNameLen(s)) + 1 // NULL terminate
   303  	})
   304  
   305  	state.funcnametab = state.addGeneratedSym(ctxt, "runtime.funcnametab", size, writeFuncNameTab)
   306  	return nameOffsets
   307  }
   308  
   309  // walkFilenames walks funcs, calling a function for each filename used in each
   310  // function's line table.
   311  func walkFilenames(ctxt *Link, funcs []loader.Sym, f func(*sym.CompilationUnit, goobj.CUFileIndex)) {
   312  	ldr := ctxt.loader
   313  
   314  	// Loop through all functions, finding the filenames we need.
   315  	for _, s := range funcs {
   316  		fi := ldr.FuncInfo(s)
   317  		if !fi.Valid() {
   318  			continue
   319  		}
   320  		fi.Preload()
   321  
   322  		cu := ldr.SymUnit(s)
   323  		for i, nf := 0, int(fi.NumFile()); i < nf; i++ {
   324  			f(cu, fi.File(i))
   325  		}
   326  		for i, ninl := 0, int(fi.NumInlTree()); i < ninl; i++ {
   327  			call := fi.InlTree(i)
   328  			f(cu, call.File)
   329  		}
   330  	}
   331  }
   332  
   333  // generateFilenameTabs creates LUTs needed for filename lookup. Returns a slice
   334  // of the index at which each CU begins in runtime.cutab.
   335  //
   336  // Function objects keep track of the files they reference to print the stack.
   337  // This function creates a per-CU list of filenames if CU[M] references
   338  // files[1-N], the following is generated:
   339  //
   340  //  runtime.cutab:
   341  //    CU[M]
   342  //     offsetToFilename[0]
   343  //     offsetToFilename[1]
   344  //     ..
   345  //
   346  //  runtime.filetab
   347  //     filename[0]
   348  //     filename[1]
   349  //
   350  // Looking up a filename then becomes:
   351  //  0) Given a func, and filename index [K]
   352  //  1) Get Func.CUIndex:       M := func.cuOffset
   353  //  2) Find filename offset:   fileOffset := runtime.cutab[M+K]
   354  //  3) Get the filename:       getcstring(runtime.filetab[fileOffset])
   355  func (state *pclntab) generateFilenameTabs(ctxt *Link, compUnits []*sym.CompilationUnit, funcs []loader.Sym) []uint32 {
   356  	// On a per-CU basis, keep track of all the filenames we need.
   357  	//
   358  	// Note, that we store the filenames in a separate section in the object
   359  	// files, and deduplicate based on the actual value. It would be better to
   360  	// store the filenames as symbols, using content addressable symbols (and
   361  	// then not loading extra filenames), and just use the hash value of the
   362  	// symbol name to do this cataloging.
   363  	//
   364  	// TODO: Store filenames as symbols. (Note this would be easiest if you
   365  	// also move strings to ALWAYS using the larger content addressable hash
   366  	// function, and use that hash value for uniqueness testing.)
   367  	cuEntries := make([]goobj.CUFileIndex, len(compUnits))
   368  	fileOffsets := make(map[string]uint32)
   369  
   370  	// Walk the filenames.
   371  	// We store the total filename string length we need to load, and the max
   372  	// file index we've seen per CU so we can calculate how large the
   373  	// CU->global table needs to be.
   374  	var fileSize int64
   375  	walkFilenames(ctxt, funcs, func(cu *sym.CompilationUnit, i goobj.CUFileIndex) {
   376  		// Note we use the raw filename for lookup, but use the expanded filename
   377  		// when we save the size.
   378  		filename := cu.FileTable[i]
   379  		if _, ok := fileOffsets[filename]; !ok {
   380  			fileOffsets[filename] = uint32(fileSize)
   381  			fileSize += int64(len(expandFile(filename)) + 1) // NULL terminate
   382  		}
   383  
   384  		// Find the maximum file index we've seen.
   385  		if cuEntries[cu.PclnIndex] < i+1 {
   386  			cuEntries[cu.PclnIndex] = i + 1 // Store max + 1
   387  		}
   388  	})
   389  
   390  	// Calculate the size of the runtime.cutab variable.
   391  	var totalEntries uint32
   392  	cuOffsets := make([]uint32, len(cuEntries))
   393  	for i, entries := range cuEntries {
   394  		// Note, cutab is a slice of uint32, so an offset to a cu's entry is just the
   395  		// running total of all cu indices we've needed to store so far, not the
   396  		// number of bytes we've stored so far.
   397  		cuOffsets[i] = totalEntries
   398  		totalEntries += uint32(entries)
   399  	}
   400  
   401  	// Write cutab.
   402  	writeCutab := func(ctxt *Link, s loader.Sym) {
   403  		sb := ctxt.loader.MakeSymbolUpdater(s)
   404  
   405  		var off int64
   406  		for i, max := range cuEntries {
   407  			// Write the per CU LUT.
   408  			cu := compUnits[i]
   409  			for j := goobj.CUFileIndex(0); j < max; j++ {
   410  				fileOffset, ok := fileOffsets[cu.FileTable[j]]
   411  				if !ok {
   412  					// We're looping through all possible file indices. It's possible a file's
   413  					// been deadcode eliminated, and although it's a valid file in the CU, it's
   414  					// not needed in this binary. When that happens, use an invalid offset.
   415  					fileOffset = ^uint32(0)
   416  				}
   417  				off = sb.SetUint32(ctxt.Arch, off, fileOffset)
   418  			}
   419  		}
   420  	}
   421  	state.cutab = state.addGeneratedSym(ctxt, "runtime.cutab", int64(totalEntries*4), writeCutab)
   422  
   423  	// Write filetab.
   424  	writeFiletab := func(ctxt *Link, s loader.Sym) {
   425  		sb := ctxt.loader.MakeSymbolUpdater(s)
   426  
   427  		// Write the strings.
   428  		for filename, loc := range fileOffsets {
   429  			sb.AddStringAt(int64(loc), expandFile(filename))
   430  		}
   431  	}
   432  	state.nfiles = uint32(len(fileOffsets))
   433  	state.filetab = state.addGeneratedSym(ctxt, "runtime.filetab", fileSize, writeFiletab)
   434  
   435  	return cuOffsets
   436  }
   437  
   438  // generatePctab creates the runtime.pctab variable, holding all the
   439  // deduplicated pcdata.
   440  func (state *pclntab) generatePctab(ctxt *Link, funcs []loader.Sym) {
   441  	ldr := ctxt.loader
   442  
   443  	// Pctab offsets of 0 are considered invalid in the runtime. We respect
   444  	// that by just padding a single byte at the beginning of runtime.pctab,
   445  	// that way no real offsets can be zero.
   446  	size := int64(1)
   447  
   448  	// Walk the functions, finding offset to store each pcdata.
   449  	seen := make(map[loader.Sym]struct{})
   450  	saveOffset := func(pcSym loader.Sym) {
   451  		if _, ok := seen[pcSym]; !ok {
   452  			datSize := ldr.SymSize(pcSym)
   453  			if datSize != 0 {
   454  				ldr.SetSymValue(pcSym, size)
   455  			} else {
   456  				// Invalid PC data, record as zero.
   457  				ldr.SetSymValue(pcSym, 0)
   458  			}
   459  			size += datSize
   460  			seen[pcSym] = struct{}{}
   461  		}
   462  	}
   463  	for _, s := range funcs {
   464  		fi := ldr.FuncInfo(s)
   465  		if !fi.Valid() {
   466  			continue
   467  		}
   468  		fi.Preload()
   469  
   470  		pcSyms := []loader.Sym{fi.Pcsp(), fi.Pcfile(), fi.Pcline()}
   471  		for _, pcSym := range pcSyms {
   472  			saveOffset(pcSym)
   473  		}
   474  		for _, pcSym := range fi.Pcdata() {
   475  			saveOffset(pcSym)
   476  		}
   477  		if fi.NumInlTree() > 0 {
   478  			saveOffset(fi.Pcinline())
   479  		}
   480  	}
   481  
   482  	// TODO: There is no reason we need a generator for this variable, and it
   483  	// could be moved to a carrier symbol. However, carrier symbols containing
   484  	// carrier symbols don't work yet (as of Aug 2020). Once this is fixed,
   485  	// runtime.pctab could just be a carrier sym.
   486  	writePctab := func(ctxt *Link, s loader.Sym) {
   487  		ldr := ctxt.loader
   488  		sb := ldr.MakeSymbolUpdater(s)
   489  		for sym := range seen {
   490  			sb.SetBytesAt(ldr.SymValue(sym), ldr.Data(sym))
   491  		}
   492  	}
   493  
   494  	state.pctab = state.addGeneratedSym(ctxt, "runtime.pctab", size, writePctab)
   495  }
   496  
   497  // numPCData returns the number of PCData syms for the FuncInfo.
   498  // NB: Preload must be called on valid FuncInfos before calling this function.
   499  func numPCData(fi loader.FuncInfo) uint32 {
   500  	if !fi.Valid() {
   501  		return 0
   502  	}
   503  	numPCData := uint32(len(fi.Pcdata()))
   504  	if fi.NumInlTree() > 0 {
   505  		if numPCData < objabi.PCDATA_InlTreeIndex+1 {
   506  			numPCData = objabi.PCDATA_InlTreeIndex + 1
   507  		}
   508  	}
   509  	return numPCData
   510  }
   511  
   512  // Helper types for iterating pclntab.
   513  type pclnSetAddr func(*loader.SymbolBuilder, *sys.Arch, int64, loader.Sym, int64) int64
   514  type pclnSetUint func(*loader.SymbolBuilder, *sys.Arch, int64, uint64) int64
   515  
   516  // generateFunctab creates the runtime.functab
   517  //
   518  // runtime.functab contains two things:
   519  //
   520  //   - pc->func look up table.
   521  //   - array of func objects, interleaved with pcdata and funcdata
   522  //
   523  // Because of timing in the linker, generating this table takes two passes.
   524  // The first pass is executed early in the link, and it creates any needed
   525  // relocations to layout the data. The pieces that need relocations are:
   526  //   1) the PC->func table.
   527  //   2) The entry points in the func objects.
   528  //   3) The funcdata.
   529  // (1) and (2) are handled in walkPCToFunc. (3) is handled in walkFuncdata.
   530  //
   531  // After relocations, once we know where to write things in the output buffer,
   532  // we execute the second pass, which is actually writing the data.
   533  func (state *pclntab) generateFunctab(ctxt *Link, funcs []loader.Sym, inlSyms map[loader.Sym]loader.Sym, cuOffsets []uint32, nameOffsets map[loader.Sym]uint32) {
   534  	// Calculate the size of the table.
   535  	size, startLocations := state.calculateFunctabSize(ctxt, funcs)
   536  
   537  	// If we are internally linking a static executable, the function addresses
   538  	// are known, so we can just use them instead of emitting relocations. For
   539  	// other cases we still need to emit relocations.
   540  	//
   541  	// This boolean just helps us figure out which callback to use.
   542  	useSymValue := ctxt.IsExe() && ctxt.IsInternal()
   543  
   544  	writePcln := func(ctxt *Link, s loader.Sym) {
   545  		ldr := ctxt.loader
   546  		sb := ldr.MakeSymbolUpdater(s)
   547  
   548  		// Create our callbacks.
   549  		var setAddr pclnSetAddr
   550  		if useSymValue {
   551  			// We need to write the offset.
   552  			setAddr = func(s *loader.SymbolBuilder, arch *sys.Arch, off int64, tgt loader.Sym, add int64) int64 {
   553  				if v := ldr.SymValue(tgt); v != 0 {
   554  					s.SetUint(arch, off, uint64(v+add))
   555  				}
   556  				return 0
   557  			}
   558  		} else {
   559  			// We already wrote relocations.
   560  			setAddr = func(s *loader.SymbolBuilder, arch *sys.Arch, off int64, tgt loader.Sym, add int64) int64 { return 0 }
   561  		}
   562  
   563  		// Write the data.
   564  		writePcToFunc(ctxt, sb, funcs, startLocations, setAddr, (*loader.SymbolBuilder).SetUint)
   565  		writeFuncs(ctxt, sb, funcs, inlSyms, startLocations, cuOffsets, nameOffsets)
   566  		state.writeFuncData(ctxt, sb, funcs, inlSyms, startLocations, setAddr, (*loader.SymbolBuilder).SetUint)
   567  	}
   568  
   569  	state.pclntab = state.addGeneratedSym(ctxt, "runtime.functab", size, writePcln)
   570  
   571  	// Create the relocations we need.
   572  	ldr := ctxt.loader
   573  	sb := ldr.MakeSymbolUpdater(state.pclntab)
   574  
   575  	var setAddr pclnSetAddr
   576  	if useSymValue {
   577  		// If we should use the symbol value, and we don't have one, write a relocation.
   578  		setAddr = func(sb *loader.SymbolBuilder, arch *sys.Arch, off int64, tgt loader.Sym, add int64) int64 {
   579  			if v := ldr.SymValue(tgt); v == 0 {
   580  				sb.SetAddrPlus(arch, off, tgt, add)
   581  			}
   582  			return 0
   583  		}
   584  	} else {
   585  		// If we're externally linking, write a relocation.
   586  		setAddr = (*loader.SymbolBuilder).SetAddrPlus
   587  	}
   588  	setUintNOP := func(*loader.SymbolBuilder, *sys.Arch, int64, uint64) int64 { return 0 }
   589  	writePcToFunc(ctxt, sb, funcs, startLocations, setAddr, setUintNOP)
   590  	if !useSymValue {
   591  		// Generate relocations for funcdata when externally linking.
   592  		state.writeFuncData(ctxt, sb, funcs, inlSyms, startLocations, setAddr, setUintNOP)
   593  		sb.SortRelocs()
   594  	}
   595  }
   596  
   597  // funcData returns the funcdata and offsets for the FuncInfo.
   598  // The funcdata and offsets are written into runtime.functab after each func
   599  // object. This is a helper function to make querying the FuncInfo object
   600  // cleaner.
   601  //
   602  // Note, the majority of fdOffsets are 0, meaning there is no offset between
   603  // the compiler's generated symbol, and what the runtime needs. They are
   604  // plumbed through for no loss of generality.
   605  //
   606  // NB: Preload must be called on the FuncInfo before calling.
   607  // NB: fdSyms and fdOffs are used as scratch space.
   608  func funcData(fi loader.FuncInfo, inlSym loader.Sym, fdSyms []loader.Sym, fdOffs []int64) ([]loader.Sym, []int64) {
   609  	fdSyms, fdOffs = fdSyms[:0], fdOffs[:0]
   610  	if fi.Valid() {
   611  		numOffsets := int(fi.NumFuncdataoff())
   612  		for i := 0; i < numOffsets; i++ {
   613  			fdOffs = append(fdOffs, fi.Funcdataoff(i))
   614  		}
   615  		fdSyms = fi.Funcdata(fdSyms)
   616  		if fi.NumInlTree() > 0 {
   617  			if len(fdSyms) < objabi.FUNCDATA_InlTree+1 {
   618  				fdSyms = append(fdSyms, make([]loader.Sym, objabi.FUNCDATA_InlTree+1-len(fdSyms))...)
   619  				fdOffs = append(fdOffs, make([]int64, objabi.FUNCDATA_InlTree+1-len(fdOffs))...)
   620  			}
   621  			fdSyms[objabi.FUNCDATA_InlTree] = inlSym
   622  		}
   623  	}
   624  	return fdSyms, fdOffs
   625  }
   626  
   627  // calculateFunctabSize calculates the size of the pclntab, and the offsets in
   628  // the output buffer for individual func entries.
   629  func (state pclntab) calculateFunctabSize(ctxt *Link, funcs []loader.Sym) (int64, []uint32) {
   630  	ldr := ctxt.loader
   631  	startLocations := make([]uint32, len(funcs))
   632  
   633  	// Allocate space for the pc->func table. This structure consists of a pc
   634  	// and an offset to the func structure. After that, we have a single pc
   635  	// value that marks the end of the last function in the binary.
   636  	size := int64(int(state.nfunc)*2*ctxt.Arch.PtrSize + ctxt.Arch.PtrSize)
   637  
   638  	// Now find the space for the func objects. We do this in a running manner,
   639  	// so that we can find individual starting locations, and because funcdata
   640  	// requires alignment.
   641  	for i, s := range funcs {
   642  		size = Rnd(size, int64(ctxt.Arch.PtrSize))
   643  		startLocations[i] = uint32(size)
   644  		fi := ldr.FuncInfo(s)
   645  		size += int64(state.funcSize)
   646  		if fi.Valid() {
   647  			fi.Preload()
   648  			numFuncData := int(fi.NumFuncdataoff())
   649  			if fi.NumInlTree() > 0 {
   650  				if numFuncData < objabi.FUNCDATA_InlTree+1 {
   651  					numFuncData = objabi.FUNCDATA_InlTree + 1
   652  				}
   653  			}
   654  			size += int64(numPCData(fi) * 4)
   655  			if numFuncData > 0 { // Func data is aligned.
   656  				size = Rnd(size, int64(ctxt.Arch.PtrSize))
   657  			}
   658  			size += int64(numFuncData * ctxt.Arch.PtrSize)
   659  		}
   660  	}
   661  
   662  	return size, startLocations
   663  }
   664  
   665  // writePcToFunc writes the PC->func lookup table.
   666  // This function walks the pc->func lookup table, executing callbacks
   667  // to generate relocations and writing the values for the table.
   668  func writePcToFunc(ctxt *Link, sb *loader.SymbolBuilder, funcs []loader.Sym, startLocations []uint32, setAddr pclnSetAddr, setUint pclnSetUint) {
   669  	ldr := ctxt.loader
   670  	var prevFunc loader.Sym
   671  	prevSect := ldr.SymSect(funcs[0])
   672  	funcIndex := 0
   673  	for i, s := range funcs {
   674  		if thisSect := ldr.SymSect(s); thisSect != prevSect {
   675  			// With multiple text sections, there may be a hole here in the
   676  			// address space. We use an invalid funcoff value to mark the hole.
   677  			// See also runtime/symtab.go:findfunc
   678  			prevFuncSize := int64(ldr.SymSize(prevFunc))
   679  			setAddr(sb, ctxt.Arch, int64(funcIndex*2*ctxt.Arch.PtrSize), prevFunc, prevFuncSize)
   680  			setUint(sb, ctxt.Arch, int64((funcIndex*2+1)*ctxt.Arch.PtrSize), ^uint64(0))
   681  			funcIndex++
   682  			prevSect = thisSect
   683  		}
   684  		prevFunc = s
   685  		// TODO: We don't actually need these relocations, provided we go to a
   686  		// module->func look-up-table like we do for filenames. We could have a
   687  		// single relocation for the module, and have them all laid out as
   688  		// offsets from the beginning of that module.
   689  		setAddr(sb, ctxt.Arch, int64(funcIndex*2*ctxt.Arch.PtrSize), s, 0)
   690  		setUint(sb, ctxt.Arch, int64((funcIndex*2+1)*ctxt.Arch.PtrSize), uint64(startLocations[i]))
   691  		funcIndex++
   692  
   693  		// Write the entry location.
   694  		setAddr(sb, ctxt.Arch, int64(startLocations[i]), s, 0)
   695  	}
   696  
   697  	// Final entry of table is just end pc.
   698  	setAddr(sb, ctxt.Arch, int64(funcIndex)*2*int64(ctxt.Arch.PtrSize), prevFunc, ldr.SymSize(prevFunc))
   699  }
   700  
   701  // writeFuncData writes the funcdata tables.
   702  //
   703  // This function executes a callback for each funcdata needed in
   704  // runtime.functab. It should be called once for internally linked static
   705  // binaries, or twice (once to generate the needed relocations) for other
   706  // build modes.
   707  //
   708  // Note the output of this function is interwoven with writeFuncs, but this is
   709  // a separate function, because it's needed in different passes in
   710  // generateFunctab.
   711  func (state *pclntab) writeFuncData(ctxt *Link, sb *loader.SymbolBuilder, funcs []loader.Sym, inlSyms map[loader.Sym]loader.Sym, startLocations []uint32, setAddr pclnSetAddr, setUint pclnSetUint) {
   712  	ldr := ctxt.loader
   713  	funcdata, funcdataoff := []loader.Sym{}, []int64{}
   714  	for i, s := range funcs {
   715  		fi := ldr.FuncInfo(s)
   716  		if !fi.Valid() {
   717  			continue
   718  		}
   719  		fi.Preload()
   720  
   721  		// funcdata, must be pointer-aligned and we're only int32-aligned.
   722  		// Missing funcdata will be 0 (nil pointer).
   723  		funcdata, funcdataoff := funcData(fi, inlSyms[s], funcdata, funcdataoff)
   724  		if len(funcdata) > 0 {
   725  			off := int64(startLocations[i] + state.funcSize + numPCData(fi)*4)
   726  			off = Rnd(off, int64(ctxt.Arch.PtrSize))
   727  			for j := range funcdata {
   728  				dataoff := off + int64(ctxt.Arch.PtrSize*j)
   729  				if funcdata[j] == 0 {
   730  					setUint(sb, ctxt.Arch, dataoff, uint64(funcdataoff[j]))
   731  					continue
   732  				}
   733  				// TODO: Does this need deduping?
   734  				setAddr(sb, ctxt.Arch, dataoff, funcdata[j], funcdataoff[j])
   735  			}
   736  		}
   737  	}
   738  }
   739  
   740  // writeFuncs writes the func structures and pcdata to runtime.functab.
   741  func writeFuncs(ctxt *Link, sb *loader.SymbolBuilder, funcs []loader.Sym, inlSyms map[loader.Sym]loader.Sym, startLocations, cuOffsets []uint32, nameOffsets map[loader.Sym]uint32) {
   742  	ldr := ctxt.loader
   743  	deferReturnSym := ldr.Lookup("runtime.deferreturn", sym.SymVerABIInternal)
   744  	funcdata, funcdataoff := []loader.Sym{}, []int64{}
   745  
   746  	// Write the individual func objects.
   747  	for i, s := range funcs {
   748  		fi := ldr.FuncInfo(s)
   749  		if fi.Valid() {
   750  			fi.Preload()
   751  		}
   752  
   753  		// Note we skip the space for the entry value -- that's handled inn
   754  		// walkPCToFunc. We don't write it here, because it might require a
   755  		// relocation.
   756  		off := startLocations[i] + uint32(ctxt.Arch.PtrSize) // entry
   757  
   758  		// name int32
   759  		nameoff, ok := nameOffsets[s]
   760  		if !ok {
   761  			panic("couldn't find function name offset")
   762  		}
   763  		off = uint32(sb.SetUint32(ctxt.Arch, int64(off), uint32(nameoff)))
   764  
   765  		// args int32
   766  		// TODO: Move into funcinfo.
   767  		args := uint32(0)
   768  		if fi.Valid() {
   769  			args = uint32(fi.Args())
   770  		}
   771  		off = uint32(sb.SetUint32(ctxt.Arch, int64(off), args))
   772  
   773  		// deferreturn
   774  		deferreturn := computeDeferReturn(ctxt, deferReturnSym, s)
   775  		off = uint32(sb.SetUint32(ctxt.Arch, int64(off), deferreturn))
   776  
   777  		// pcdata
   778  		if fi.Valid() {
   779  			off = uint32(sb.SetUint32(ctxt.Arch, int64(off), uint32(ldr.SymValue(fi.Pcsp()))))
   780  			off = uint32(sb.SetUint32(ctxt.Arch, int64(off), uint32(ldr.SymValue(fi.Pcfile()))))
   781  			off = uint32(sb.SetUint32(ctxt.Arch, int64(off), uint32(ldr.SymValue(fi.Pcline()))))
   782  		} else {
   783  			off += 12
   784  		}
   785  		off = uint32(sb.SetUint32(ctxt.Arch, int64(off), uint32(numPCData(fi))))
   786  
   787  		// Store the offset to compilation unit's file table.
   788  		cuIdx := ^uint32(0)
   789  		if cu := ldr.SymUnit(s); cu != nil {
   790  			cuIdx = cuOffsets[cu.PclnIndex]
   791  		}
   792  		off = uint32(sb.SetUint32(ctxt.Arch, int64(off), cuIdx))
   793  
   794  		// funcID uint8
   795  		var funcID objabi.FuncID
   796  		if fi.Valid() {
   797  			funcID = fi.FuncID()
   798  		}
   799  		off = uint32(sb.SetUint8(ctxt.Arch, int64(off), uint8(funcID)))
   800  
   801  		// flag uint8
   802  		var flag objabi.FuncFlag
   803  		if fi.Valid() {
   804  			flag = fi.FuncFlag()
   805  		}
   806  		off = uint32(sb.SetUint8(ctxt.Arch, int64(off), uint8(flag)))
   807  
   808  		off += 1 // pad
   809  
   810  		// nfuncdata must be the final entry.
   811  		funcdata, funcdataoff = funcData(fi, 0, funcdata, funcdataoff)
   812  		off = uint32(sb.SetUint8(ctxt.Arch, int64(off), uint8(len(funcdata))))
   813  
   814  		// Output the pcdata.
   815  		if fi.Valid() {
   816  			for j, pcSym := range fi.Pcdata() {
   817  				sb.SetUint32(ctxt.Arch, int64(off+uint32(j*4)), uint32(ldr.SymValue(pcSym)))
   818  			}
   819  			if fi.NumInlTree() > 0 {
   820  				sb.SetUint32(ctxt.Arch, int64(off+objabi.PCDATA_InlTreeIndex*4), uint32(ldr.SymValue(fi.Pcinline())))
   821  			}
   822  		}
   823  	}
   824  }
   825  
   826  // pclntab initializes the pclntab symbol with
   827  // runtime function and file name information.
   828  
   829  // pclntab generates the pcln table for the link output.
   830  func (ctxt *Link) pclntab(container loader.Bitmap) *pclntab {
   831  	// Go 1.2's symtab layout is documented in golang.org/s/go12symtab, but the
   832  	// layout and data has changed since that time.
   833  	//
   834  	// As of August 2020, here's the layout of pclntab:
   835  	//
   836  	//  .gopclntab/__gopclntab [elf/macho section]
   837  	//    runtime.pclntab
   838  	//      Carrier symbol for the entire pclntab section.
   839  	//
   840  	//      runtime.pcheader  (see: runtime/symtab.go:pcHeader)
   841  	//        8-byte magic
   842  	//        nfunc [thearch.ptrsize bytes]
   843  	//        offset to runtime.funcnametab from the beginning of runtime.pcheader
   844  	//        offset to runtime.pclntab_old from beginning of runtime.pcheader
   845  	//
   846  	//      runtime.funcnametab
   847  	//        []list of null terminated function names
   848  	//
   849  	//      runtime.cutab
   850  	//        for i=0..#CUs
   851  	//          for j=0..#max used file index in CU[i]
   852  	//            uint32 offset into runtime.filetab for the filename[j]
   853  	//
   854  	//      runtime.filetab
   855  	//        []null terminated filename strings
   856  	//
   857  	//      runtime.pctab
   858  	//        []byte of deduplicated pc data.
   859  	//
   860  	//      runtime.functab
   861  	//        function table, alternating PC and offset to func struct [each entry thearch.ptrsize bytes]
   862  	//        end PC [thearch.ptrsize bytes]
   863  	//        func structures, pcdata offsets, func data.
   864  
   865  	state, compUnits, funcs := makePclntab(ctxt, container)
   866  
   867  	ldr := ctxt.loader
   868  	state.carrier = ldr.LookupOrCreateSym("runtime.pclntab", 0)
   869  	ldr.MakeSymbolUpdater(state.carrier).SetType(sym.SPCLNTAB)
   870  	ldr.SetAttrReachable(state.carrier, true)
   871  	setCarrierSym(sym.SPCLNTAB, state.carrier)
   872  
   873  	state.generatePCHeader(ctxt)
   874  	nameOffsets := state.generateFuncnametab(ctxt, funcs)
   875  	cuOffsets := state.generateFilenameTabs(ctxt, compUnits, funcs)
   876  	state.generatePctab(ctxt, funcs)
   877  	inlSyms := makeInlSyms(ctxt, funcs, nameOffsets)
   878  	state.generateFunctab(ctxt, funcs, inlSyms, cuOffsets, nameOffsets)
   879  
   880  	return state
   881  }
   882  
   883  func gorootFinal() string {
   884  	root := buildcfg.GOROOT
   885  	if final := os.Getenv("GOROOT_FINAL"); final != "" {
   886  		root = final
   887  	}
   888  	return root
   889  }
   890  
   891  func expandGoroot(s string) string {
   892  	const n = len("$GOROOT")
   893  	if len(s) >= n+1 && s[:n] == "$GOROOT" && (s[n] == '/' || s[n] == '\\') {
   894  		return filepath.ToSlash(filepath.Join(gorootFinal(), s[n:]))
   895  	}
   896  	return s
   897  }
   898  
   899  const (
   900  	BUCKETSIZE    = 256 * MINFUNC
   901  	SUBBUCKETS    = 16
   902  	SUBBUCKETSIZE = BUCKETSIZE / SUBBUCKETS
   903  	NOIDX         = 0x7fffffff
   904  )
   905  
   906  // findfunctab generates a lookup table to quickly find the containing
   907  // function for a pc. See src/runtime/symtab.go:findfunc for details.
   908  func (ctxt *Link) findfunctab(state *pclntab, container loader.Bitmap) {
   909  	ldr := ctxt.loader
   910  
   911  	// find min and max address
   912  	min := ldr.SymValue(ctxt.Textp[0])
   913  	lastp := ctxt.Textp[len(ctxt.Textp)-1]
   914  	max := ldr.SymValue(lastp) + ldr.SymSize(lastp)
   915  
   916  	// for each subbucket, compute the minimum of all symbol indexes
   917  	// that map to that subbucket.
   918  	n := int32((max - min + SUBBUCKETSIZE - 1) / SUBBUCKETSIZE)
   919  
   920  	nbuckets := int32((max - min + BUCKETSIZE - 1) / BUCKETSIZE)
   921  
   922  	size := 4*int64(nbuckets) + int64(n)
   923  
   924  	writeFindFuncTab := func(_ *Link, s loader.Sym) {
   925  		t := ldr.MakeSymbolUpdater(s)
   926  
   927  		indexes := make([]int32, n)
   928  		for i := int32(0); i < n; i++ {
   929  			indexes[i] = NOIDX
   930  		}
   931  		idx := int32(0)
   932  		for i, s := range ctxt.Textp {
   933  			if !emitPcln(ctxt, s, container) {
   934  				continue
   935  			}
   936  			p := ldr.SymValue(s)
   937  			var e loader.Sym
   938  			i++
   939  			if i < len(ctxt.Textp) {
   940  				e = ctxt.Textp[i]
   941  			}
   942  			for e != 0 && !emitPcln(ctxt, e, container) && i < len(ctxt.Textp) {
   943  				e = ctxt.Textp[i]
   944  				i++
   945  			}
   946  			q := max
   947  			if e != 0 {
   948  				q = ldr.SymValue(e)
   949  			}
   950  
   951  			//print("%d: [%lld %lld] %s\n", idx, p, q, s->name);
   952  			for ; p < q; p += SUBBUCKETSIZE {
   953  				i = int((p - min) / SUBBUCKETSIZE)
   954  				if indexes[i] > idx {
   955  					indexes[i] = idx
   956  				}
   957  			}
   958  
   959  			i = int((q - 1 - min) / SUBBUCKETSIZE)
   960  			if indexes[i] > idx {
   961  				indexes[i] = idx
   962  			}
   963  			idx++
   964  		}
   965  
   966  		// fill in table
   967  		for i := int32(0); i < nbuckets; i++ {
   968  			base := indexes[i*SUBBUCKETS]
   969  			if base == NOIDX {
   970  				Errorf(nil, "hole in findfunctab")
   971  			}
   972  			t.SetUint32(ctxt.Arch, int64(i)*(4+SUBBUCKETS), uint32(base))
   973  			for j := int32(0); j < SUBBUCKETS && i*SUBBUCKETS+j < n; j++ {
   974  				idx = indexes[i*SUBBUCKETS+j]
   975  				if idx == NOIDX {
   976  					Errorf(nil, "hole in findfunctab")
   977  				}
   978  				if idx-base >= 256 {
   979  					Errorf(nil, "too many functions in a findfunc bucket! %d/%d %d %d", i, nbuckets, j, idx-base)
   980  				}
   981  
   982  				t.SetUint8(ctxt.Arch, int64(i)*(4+SUBBUCKETS)+4+int64(j), uint8(idx-base))
   983  			}
   984  		}
   985  	}
   986  
   987  	state.findfunctab = ctxt.createGeneratorSymbol("runtime.findfunctab", 0, sym.SRODATA, size, writeFindFuncTab)
   988  	ldr.SetAttrReachable(state.findfunctab, true)
   989  	ldr.SetAttrLocal(state.findfunctab, true)
   990  }
   991  
   992  // findContainerSyms returns a bitmap, indexed by symbol number, where there's
   993  // a 1 for every container symbol.
   994  func (ctxt *Link) findContainerSyms() loader.Bitmap {
   995  	ldr := ctxt.loader
   996  	container := loader.MakeBitmap(ldr.NSym())
   997  	// Find container symbols and mark them as such.
   998  	for _, s := range ctxt.Textp {
   999  		outer := ldr.OuterSym(s)
  1000  		if outer != 0 {
  1001  			container.Set(outer)
  1002  		}
  1003  	}
  1004  	return container
  1005  }
  1006  

View as plain text