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