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