1
2
3
4
5 package ld
6
7 import (
8 "cmd/internal/goobj"
9 "cmd/internal/objabi"
10 "cmd/internal/sys"
11 "cmd/link/internal/loader"
12 "cmd/link/internal/sym"
13 "cmp"
14 "fmt"
15 "internal/abi"
16 "internal/buildcfg"
17 "path/filepath"
18 "slices"
19 "strings"
20 )
21
22 const funcSize = 11 * 4
23
24
25 type pclntab struct {
26
27 firstFunc, lastFunc loader.Sym
28
29
30 size int64
31
32
33 carrier loader.Sym
34 pclntab loader.Sym
35 pcheader loader.Sym
36 funcnametab loader.Sym
37 findfunctab loader.Sym
38 cutab loader.Sym
39 filetab loader.Sym
40 pctab loader.Sym
41 funcdata loader.Sym
42
43
44
45
46
47
48
49
50 nfunc int32
51
52
53 nfiles uint32
54 }
55
56
57
58 func (state *pclntab) addGeneratedSym(ctxt *Link, name string, size int64, align int32, f generatorFunc) loader.Sym {
59 size = Rnd(size, int64(ctxt.Arch.PtrSize))
60 state.size += size
61 s := ctxt.createGeneratorSymbol(name, 0, sym.SPCLNTAB, size, f)
62 ldr := ctxt.loader
63 ldr.SetSymAlign(s, align)
64 ldr.SetAttrReachable(s, true)
65 ldr.SetCarrierSym(s, state.carrier)
66 ldr.SetAttrNotInSymbolTable(s, true)
67
68 if align > ldr.SymAlign(state.carrier) {
69 ldr.SetSymAlign(state.carrier, align)
70 }
71
72 return s
73 }
74
75
76
77
78
79 func makePclntab(ctxt *Link, container loader.Bitmap) (*pclntab, []*sym.CompilationUnit, []loader.Sym) {
80 ldr := ctxt.loader
81 state := new(pclntab)
82
83
84 seenCUs := make(map[*sym.CompilationUnit]struct{})
85 compUnits := []*sym.CompilationUnit{}
86 funcs := []loader.Sym{}
87
88 for _, s := range ctxt.Textp {
89 if !emitPcln(ctxt, s, container) {
90 continue
91 }
92 funcs = append(funcs, s)
93 state.nfunc++
94 if state.firstFunc == 0 {
95 state.firstFunc = s
96 }
97 state.lastFunc = s
98
99
100
101 cu := ldr.SymUnit(s)
102 if _, ok := seenCUs[cu]; cu != nil && !ok {
103 seenCUs[cu] = struct{}{}
104 cu.PclnIndex = len(compUnits)
105 compUnits = append(compUnits, cu)
106 }
107 }
108 return state, compUnits, funcs
109 }
110
111 func emitPcln(ctxt *Link, s loader.Sym, container loader.Bitmap) bool {
112 if ctxt.Target.IsRISCV64() {
113
114
115
116
117
118
119 symName := ctxt.loader.SymName(s)
120 if symName == "" || strings.HasPrefix(symName, ".L") {
121 return false
122 }
123 }
124
125
126
127 return !container.Has(s)
128 }
129
130 func computeDeferReturn(ctxt *Link, deferReturnSym, s loader.Sym) uint32 {
131 ldr := ctxt.loader
132 target := ctxt.Target
133 deferreturn := uint32(0)
134 lastWasmAddr := uint32(0)
135
136 relocs := ldr.Relocs(s)
137 for ri := 0; ri < relocs.Count(); ri++ {
138 r := relocs.At(ri)
139 if target.IsWasm() && r.Type() == objabi.R_ADDR {
140
141
142
143
144 lastWasmAddr = uint32(r.Add())
145 }
146 if r.Type().IsDirectCall() && (r.Sym() == deferReturnSym || ldr.IsDeferReturnTramp(r.Sym())) {
147 if target.IsWasm() {
148 deferreturn = lastWasmAddr - 1
149 } else {
150
151
152
153
154 deferreturn = uint32(r.Off())
155 switch target.Arch.Family {
156 case sys.I386:
157 deferreturn--
158 if ctxt.BuildMode == BuildModeShared || ctxt.linkShared || ctxt.BuildMode == BuildModePlugin {
159
160
161
162
163
164
165
166
167 deferreturn -= 11
168 }
169 case sys.AMD64:
170 deferreturn--
171
172 case sys.ARM, sys.ARM64, sys.Loong64, sys.MIPS, sys.MIPS64, sys.PPC64, sys.RISCV64:
173
174 case sys.S390X:
175 deferreturn -= 2
176 default:
177 panic(fmt.Sprint("Unhandled architecture:", target.Arch.Family))
178 }
179 }
180 break
181 }
182 }
183 return deferreturn
184 }
185
186
187
188 func genInlTreeSym(ctxt *Link, cu *sym.CompilationUnit, fi loader.FuncInfo, arch *sys.Arch, nameOffsets map[loader.Sym]uint32) loader.Sym {
189 ldr := ctxt.loader
190 its := ldr.CreateExtSym("", 0)
191 inlTreeSym := ldr.MakeSymbolUpdater(its)
192
193
194
195
196 inlTreeSym.SetType(sym.SPCLNTAB)
197 ldr.SetAttrReachable(its, true)
198 ldr.SetSymAlign(its, 4)
199 ninl := fi.NumInlTree()
200 for i := 0; i < int(ninl); i++ {
201 call := fi.InlTree(i)
202 nameOff, ok := nameOffsets[call.Func]
203 if !ok {
204 panic("couldn't find function name offset")
205 }
206
207 inlFunc := ldr.FuncInfo(call.Func)
208 var funcID abi.FuncID
209 startLine := int32(0)
210 if inlFunc.Valid() {
211 funcID = inlFunc.FuncID()
212 startLine = inlFunc.StartLine()
213 } else if !ctxt.linkShared {
214
215
216
217
218
219
220
221
222 panic(fmt.Sprintf("inlined function %s missing func info", ldr.SymName(call.Func)))
223 }
224
225
226 const size = 16
227 inlTreeSym.SetUint8(arch, int64(i*size+0), uint8(funcID))
228
229 inlTreeSym.SetUint32(arch, int64(i*size+4), nameOff)
230 inlTreeSym.SetUint32(arch, int64(i*size+8), uint32(call.ParentPC))
231 inlTreeSym.SetUint32(arch, int64(i*size+12), uint32(startLine))
232 }
233 return its
234 }
235
236
237 func makeInlSyms(ctxt *Link, funcs []loader.Sym, nameOffsets map[loader.Sym]uint32) map[loader.Sym]loader.Sym {
238 ldr := ctxt.loader
239
240 inlSyms := make(map[loader.Sym]loader.Sym)
241 for _, s := range funcs {
242 if fi := ldr.FuncInfo(s); fi.Valid() {
243 fi.Preload()
244 if fi.NumInlTree() > 0 {
245 inlSyms[s] = genInlTreeSym(ctxt, ldr.SymUnit(s), fi, ctxt.Arch, nameOffsets)
246 }
247 }
248 }
249 return inlSyms
250 }
251
252
253
254 func (state *pclntab) generatePCHeader(ctxt *Link) {
255 ldr := ctxt.loader
256 size := int64(8 + 8*ctxt.Arch.PtrSize)
257 writeHeader := func(ctxt *Link, s loader.Sym) {
258 header := ctxt.loader.MakeSymbolUpdater(s)
259
260 writeSymOffset := func(off int64, ws loader.Sym) int64 {
261 diff := ldr.SymValue(ws) - ldr.SymValue(s)
262 if diff <= 0 {
263 name := ldr.SymName(ws)
264 panic(fmt.Sprintf("expected runtime.pcheader(%x) to be placed before %s(%x)", ldr.SymValue(s), name, ldr.SymValue(ws)))
265 }
266 return header.SetUintptr(ctxt.Arch, off, uintptr(diff))
267 }
268
269
270
271 header.SetUint32(ctxt.Arch, 0, uint32(abi.CurrentPCLnTabMagic))
272 header.SetUint8(ctxt.Arch, 6, uint8(ctxt.Arch.MinLC))
273 header.SetUint8(ctxt.Arch, 7, uint8(ctxt.Arch.PtrSize))
274 off := header.SetUint(ctxt.Arch, 8, uint64(state.nfunc))
275 off = header.SetUint(ctxt.Arch, off, uint64(state.nfiles))
276 off = header.SetUintptr(ctxt.Arch, off, 0)
277 off = writeSymOffset(off, state.funcnametab)
278 off = writeSymOffset(off, state.cutab)
279 off = writeSymOffset(off, state.filetab)
280 off = writeSymOffset(off, state.pctab)
281 off = writeSymOffset(off, state.pclntab)
282 if off != size {
283 panic(fmt.Sprintf("pcHeader size: %d != %d", off, size))
284 }
285 }
286
287 state.pcheader = state.addGeneratedSym(ctxt, "runtime.pcheader", size, int32(ctxt.Arch.PtrSize), writeHeader)
288 }
289
290
291
292 func walkFuncs(ctxt *Link, funcs []loader.Sym, f func(loader.Sym)) {
293 ldr := ctxt.loader
294 seen := make(map[loader.Sym]struct{})
295 for _, s := range funcs {
296 if _, ok := seen[s]; !ok {
297 f(s)
298 seen[s] = struct{}{}
299 }
300
301 fi := ldr.FuncInfo(s)
302 if !fi.Valid() {
303 continue
304 }
305 fi.Preload()
306 for i, ni := 0, fi.NumInlTree(); i < int(ni); i++ {
307 call := fi.InlTree(i).Func
308 if _, ok := seen[call]; !ok {
309 f(call)
310 seen[call] = struct{}{}
311 }
312 }
313 }
314 }
315
316
317
318 func (state *pclntab) generateFuncnametab(ctxt *Link, funcs []loader.Sym) map[loader.Sym]uint32 {
319 nameOffsets := make(map[loader.Sym]uint32, state.nfunc)
320
321
322 writeFuncNameTab := func(ctxt *Link, s loader.Sym) {
323 symtab := ctxt.loader.MakeSymbolUpdater(s)
324 for s, off := range nameOffsets {
325 symtab.AddCStringAt(int64(off), ctxt.loader.SymName(s))
326 }
327 }
328
329
330 var size int64
331 walkFuncs(ctxt, funcs, func(s loader.Sym) {
332 nameOffsets[s] = uint32(size)
333 size += int64(len(ctxt.loader.SymName(s)) + 1)
334 })
335
336 state.funcnametab = state.addGeneratedSym(ctxt, "runtime.funcnametab", size, 1, writeFuncNameTab)
337 return nameOffsets
338 }
339
340
341
342 func walkFilenames(ctxt *Link, funcs []loader.Sym, f func(*sym.CompilationUnit, goobj.CUFileIndex)) {
343 ldr := ctxt.loader
344
345
346 for _, s := range funcs {
347 fi := ldr.FuncInfo(s)
348 if !fi.Valid() {
349 continue
350 }
351 fi.Preload()
352
353 cu := ldr.SymUnit(s)
354 for i, nf := 0, int(fi.NumFile()); i < nf; i++ {
355 f(cu, fi.File(i))
356 }
357 for i, ninl := 0, int(fi.NumInlTree()); i < ninl; i++ {
358 call := fi.InlTree(i)
359 f(cu, call.File)
360 }
361 }
362 }
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386 func (state *pclntab) generateFilenameTabs(ctxt *Link, compUnits []*sym.CompilationUnit, funcs []loader.Sym) []uint32 {
387
388
389
390
391
392
393
394
395
396
397
398 cuEntries := make([]goobj.CUFileIndex, len(compUnits))
399 fileOffsets := make(map[string]uint32)
400
401
402
403
404
405 var fileSize int64
406 walkFilenames(ctxt, funcs, func(cu *sym.CompilationUnit, i goobj.CUFileIndex) {
407
408
409 filename := cu.FileTable[i]
410 if _, ok := fileOffsets[filename]; !ok {
411 fileOffsets[filename] = uint32(fileSize)
412 fileSize += int64(len(expandFile(filename)) + 1)
413 }
414
415
416 if cuEntries[cu.PclnIndex] < i+1 {
417 cuEntries[cu.PclnIndex] = i + 1
418 }
419 })
420
421
422 var totalEntries uint32
423 cuOffsets := make([]uint32, len(cuEntries))
424 for i, entries := range cuEntries {
425
426
427
428 cuOffsets[i] = totalEntries
429 totalEntries += uint32(entries)
430 }
431
432
433 writeCutab := func(ctxt *Link, s loader.Sym) {
434 sb := ctxt.loader.MakeSymbolUpdater(s)
435
436 var off int64
437 for i, max := range cuEntries {
438
439 cu := compUnits[i]
440 for j := goobj.CUFileIndex(0); j < max; j++ {
441 fileOffset, ok := fileOffsets[cu.FileTable[j]]
442 if !ok {
443
444
445
446 fileOffset = ^uint32(0)
447 }
448 off = sb.SetUint32(ctxt.Arch, off, fileOffset)
449 }
450 }
451 }
452 state.cutab = state.addGeneratedSym(ctxt, "runtime.cutab", int64(totalEntries*4), 4, writeCutab)
453
454
455 writeFiletab := func(ctxt *Link, s loader.Sym) {
456 sb := ctxt.loader.MakeSymbolUpdater(s)
457
458
459 for filename, loc := range fileOffsets {
460 sb.AddStringAt(int64(loc), expandFile(filename))
461 }
462 }
463 state.nfiles = uint32(len(fileOffsets))
464 state.filetab = state.addGeneratedSym(ctxt, "runtime.filetab", fileSize, 1, writeFiletab)
465
466 return cuOffsets
467 }
468
469
470
471 func (state *pclntab) generatePctab(ctxt *Link, funcs []loader.Sym) {
472 ldr := ctxt.loader
473
474
475
476
477 size := int64(1)
478
479
480 seen := make(map[loader.Sym]struct{})
481 saveOffset := func(pcSym loader.Sym) {
482 if _, ok := seen[pcSym]; !ok {
483 datSize := ldr.SymSize(pcSym)
484 if datSize != 0 {
485 ldr.SetSymValue(pcSym, size)
486 } else {
487
488 ldr.SetSymValue(pcSym, 0)
489 }
490 size += datSize
491 seen[pcSym] = struct{}{}
492 }
493 }
494 var pcsp, pcline, pcfile, pcinline loader.Sym
495 var pcdata []loader.Sym
496 for _, s := range funcs {
497 fi := ldr.FuncInfo(s)
498 if !fi.Valid() {
499 continue
500 }
501 fi.Preload()
502 pcsp, pcfile, pcline, pcinline, pcdata = ldr.PcdataAuxs(s, pcdata)
503
504 pcSyms := []loader.Sym{pcsp, pcfile, pcline}
505 for _, pcSym := range pcSyms {
506 saveOffset(pcSym)
507 }
508 for _, pcSym := range pcdata {
509 saveOffset(pcSym)
510 }
511 if fi.NumInlTree() > 0 {
512 saveOffset(pcinline)
513 }
514 }
515
516
517
518
519
520 writePctab := func(ctxt *Link, s loader.Sym) {
521 ldr := ctxt.loader
522 sb := ldr.MakeSymbolUpdater(s)
523 for sym := range seen {
524 sb.SetBytesAt(ldr.SymValue(sym), ldr.Data(sym))
525 }
526 }
527
528 state.pctab = state.addGeneratedSym(ctxt, "runtime.pctab", size, 1, writePctab)
529 }
530
531
532 func (state *pclntab) generateFuncdata(ctxt *Link, funcs []loader.Sym, inlsyms map[loader.Sym]loader.Sym) {
533 ldr := ctxt.loader
534
535
536 seen := make(map[loader.Sym]struct{}, len(funcs))
537 fdSyms := make([]loader.Sym, 0, len(funcs))
538 fd := []loader.Sym{}
539 for _, s := range funcs {
540 fi := ldr.FuncInfo(s)
541 if !fi.Valid() {
542 continue
543 }
544 fi.Preload()
545 fd := funcData(ldr, s, fi, inlsyms[s], fd)
546 for j, fdSym := range fd {
547 if ignoreFuncData(ldr, s, j, fdSym) {
548 continue
549 }
550
551 if _, ok := seen[fdSym]; !ok {
552 fdSyms = append(fdSyms, fdSym)
553 seen[fdSym] = struct{}{}
554 }
555 }
556 }
557 seen = nil
558
559
560
561
562 var maxAlign int32
563 slices.SortStableFunc(fdSyms, func(a, b loader.Sym) int {
564 aAlign := symalign(ldr, a)
565 bAlign := symalign(ldr, b)
566
567
568 maxAlign = max(maxAlign, aAlign, bAlign)
569
570
571 return -cmp.Compare(aAlign, bAlign)
572 })
573
574
575
576
577
578
579
580 size := int64(0)
581
582 for _, fdSym := range fdSyms {
583 datSize := ldr.SymSize(fdSym)
584 if datSize == 0 {
585 ctxt.Errorf(fdSym, "zero size funcdata")
586 continue
587 }
588
589 size = Rnd(size, int64(symalign(ldr, fdSym)))
590 ldr.SetSymValue(fdSym, size)
591 size += datSize
592
593
594 ldr.SetAttrNotInSymbolTable(fdSym, true)
595
596
597
598 ldr.SetAttrSpecial(fdSym, true)
599 }
600
601
602
603 resolveRelocs := func(ldr *loader.Loader, fdSym loader.Sym, data []byte) {
604 relocs := ldr.Relocs(fdSym)
605 for i := 0; i < relocs.Count(); i++ {
606 r := relocs.At(i)
607 if r.Type() != objabi.R_ADDROFF {
608 ctxt.Errorf(fdSym, "unsupported reloc %d (%s) for funcdata symbol", r.Type(), sym.RelocName(ctxt.Target.Arch, r.Type()))
609 return
610 }
611 if r.Siz() != 4 {
612 ctxt.Errorf(fdSym, "unsupported ADDROFF reloc size %d for funcdata symbol", r.Siz())
613 return
614 }
615 rs := r.Sym()
616 if r.Weak() && !ldr.AttrReachable(rs) {
617 return
618 }
619 sect := ldr.SymSect(rs)
620 if sect == nil {
621 ctxt.Errorf(fdSym, "missing section for relocation target %s for funcdata symbol", ldr.SymName(rs))
622 }
623 o := ldr.SymValue(rs)
624 if sect.Name != ".text" {
625 o -= int64(sect.Vaddr)
626 } else {
627
628
629 o -= int64(Segtext.Sections[0].Vaddr)
630 if ctxt.Target.IsWasm() {
631 if o&(1<<16-1) != 0 {
632 ctxt.Errorf(fdSym, "textoff relocation does not target function entry for funcdata symbol: %s %#x", ldr.SymName(rs), o)
633 }
634 o >>= 16
635 }
636 }
637 o += r.Add()
638 if o != int64(int32(o)) && o != int64(uint32(o)) {
639 ctxt.Errorf(fdSym, "ADDROFF relocation out of range for funcdata symbol: %#x", o)
640 }
641 ctxt.Target.Arch.ByteOrder.PutUint32(data[r.Off():], uint32(o))
642 }
643 }
644
645 writeFuncData := func(ctxt *Link, s loader.Sym) {
646 ldr := ctxt.loader
647 sb := ldr.MakeSymbolUpdater(s)
648 for _, fdSym := range fdSyms {
649 off := ldr.SymValue(fdSym)
650 fdSymData := ldr.Data(fdSym)
651 sb.SetBytesAt(off, fdSymData)
652
653 resolveRelocs(ldr, fdSym, sb.Data()[off:off+int64(len(fdSymData))])
654 }
655 }
656
657 state.funcdata = state.addGeneratedSym(ctxt, "go:func.*", size, maxAlign, writeFuncData)
658
659
660
661 ldr.SetAttrNotInSymbolTable(state.funcdata, false)
662 }
663
664
665
666
667
668
669
670
671
672 func ignoreFuncData(ldr *loader.Loader, s loader.Sym, j int, fdSym loader.Sym) bool {
673 if fdSym == 0 {
674 return true
675 }
676 if (j == abi.FUNCDATA_ArgsPointerMaps || j == abi.FUNCDATA_ArgInfo) && ldr.IsFromAssembly(s) && ldr.Data(fdSym) == nil {
677 return true
678 }
679 return false
680 }
681
682
683
684 func numPCData(ldr *loader.Loader, s loader.Sym, fi loader.FuncInfo) uint32 {
685 if !fi.Valid() {
686 return 0
687 }
688 numPCData := uint32(ldr.NumPcdata(s))
689 if fi.NumInlTree() > 0 {
690 if numPCData < abi.PCDATA_InlTreeIndex+1 {
691 numPCData = abi.PCDATA_InlTreeIndex + 1
692 }
693 }
694 return numPCData
695 }
696
697
698
699
700
701
702
703 func (state *pclntab) generateFunctab(ctxt *Link, funcs []loader.Sym, inlSyms map[loader.Sym]loader.Sym, cuOffsets []uint32, nameOffsets map[loader.Sym]uint32) {
704
705 size, startLocations := state.calculateFunctabSize(ctxt, funcs)
706 writePcln := func(ctxt *Link, s loader.Sym) {
707 ldr := ctxt.loader
708 sb := ldr.MakeSymbolUpdater(s)
709
710 writePCToFunc(ctxt, sb, funcs, startLocations)
711 writeFuncs(ctxt, sb, funcs, inlSyms, startLocations, cuOffsets, nameOffsets)
712 }
713 state.pclntab = state.addGeneratedSym(ctxt, "runtime.functab", size, 4, writePcln)
714 }
715
716
717
718
719
720
721
722
723 func funcData(ldr *loader.Loader, s loader.Sym, fi loader.FuncInfo, inlSym loader.Sym, fdSyms []loader.Sym) []loader.Sym {
724 fdSyms = fdSyms[:0]
725 if fi.Valid() {
726 fdSyms = ldr.Funcdata(s, fdSyms)
727 if fi.NumInlTree() > 0 {
728 if len(fdSyms) < abi.FUNCDATA_InlTree+1 {
729 fdSyms = append(fdSyms, make([]loader.Sym, abi.FUNCDATA_InlTree+1-len(fdSyms))...)
730 }
731 fdSyms[abi.FUNCDATA_InlTree] = inlSym
732 }
733 }
734 return fdSyms
735 }
736
737
738
739 func (state pclntab) calculateFunctabSize(ctxt *Link, funcs []loader.Sym) (int64, []uint32) {
740 ldr := ctxt.loader
741 startLocations := make([]uint32, len(funcs))
742
743
744
745
746 size := int64(int(state.nfunc)*2*4 + 4)
747
748
749
750 for i, s := range funcs {
751 size = Rnd(size, int64(ctxt.Arch.PtrSize))
752 startLocations[i] = uint32(size)
753 fi := ldr.FuncInfo(s)
754 size += funcSize
755 if fi.Valid() {
756 fi.Preload()
757 numFuncData := ldr.NumFuncdata(s)
758 if fi.NumInlTree() > 0 {
759 if numFuncData < abi.FUNCDATA_InlTree+1 {
760 numFuncData = abi.FUNCDATA_InlTree + 1
761 }
762 }
763 size += int64(numPCData(ldr, s, fi) * 4)
764 size += int64(numFuncData * 4)
765 }
766 }
767
768 return size, startLocations
769 }
770
771
772
773
774 func textOff(ctxt *Link, s loader.Sym, textStart int64) uint32 {
775 ldr := ctxt.loader
776 off := ldr.SymValue(s) - textStart
777 if off < 0 {
778 panic(fmt.Sprintf("expected func %s(%x) to be placed at or after textStart (%x)", ldr.SymName(s), ldr.SymValue(s), textStart))
779 }
780 if ctxt.IsWasm() {
781
782
783
784 if off&(1<<16-1) != 0 {
785 ctxt.Errorf(s, "nonzero PC_B at function entry: %#x", off)
786 }
787 off >>= 16
788 }
789 if int64(uint32(off)) != off {
790 ctxt.Errorf(s, "textOff overflow: %#x", off)
791 }
792 return uint32(off)
793 }
794
795
796 func writePCToFunc(ctxt *Link, sb *loader.SymbolBuilder, funcs []loader.Sym, startLocations []uint32) {
797 ldr := ctxt.loader
798 textStart := ldr.SymValue(ldr.Lookup("runtime.text", 0))
799 pcOff := func(s loader.Sym) uint32 {
800 return textOff(ctxt, s, textStart)
801 }
802 for i, s := range funcs {
803 sb.SetUint32(ctxt.Arch, int64(i*2*4), pcOff(s))
804 sb.SetUint32(ctxt.Arch, int64((i*2+1)*4), startLocations[i])
805 }
806
807
808 lastFunc := funcs[len(funcs)-1]
809 lastPC := pcOff(lastFunc) + uint32(ldr.SymSize(lastFunc))
810 if ctxt.IsWasm() {
811 lastPC = pcOff(lastFunc) + 1
812 }
813 sb.SetUint32(ctxt.Arch, int64(len(funcs))*2*4, lastPC)
814 }
815
816
817 func writeFuncs(ctxt *Link, sb *loader.SymbolBuilder, funcs []loader.Sym, inlSyms map[loader.Sym]loader.Sym, startLocations, cuOffsets []uint32, nameOffsets map[loader.Sym]uint32) {
818 ldr := ctxt.loader
819 deferReturnSym := ldr.Lookup("runtime.deferreturn", abiInternalVer)
820 textStart := ldr.SymValue(ldr.Lookup("runtime.text", 0))
821 funcdata := []loader.Sym{}
822 var pcsp, pcfile, pcline, pcinline loader.Sym
823 var pcdata []loader.Sym
824
825
826 for i, s := range funcs {
827 startLine := int32(0)
828 fi := ldr.FuncInfo(s)
829 if fi.Valid() {
830 fi.Preload()
831 pcsp, pcfile, pcline, pcinline, pcdata = ldr.PcdataAuxs(s, pcdata)
832 startLine = fi.StartLine()
833 }
834
835 off := int64(startLocations[i])
836
837 entryOff := textOff(ctxt, s, textStart)
838 off = sb.SetUint32(ctxt.Arch, off, entryOff)
839
840
841 nameOff, ok := nameOffsets[s]
842 if !ok {
843 panic("couldn't find function name offset")
844 }
845 off = sb.SetUint32(ctxt.Arch, off, nameOff)
846
847
848
849 args := uint32(0)
850 if fi.Valid() {
851 args = uint32(fi.Args())
852 }
853 off = sb.SetUint32(ctxt.Arch, off, args)
854
855
856 deferreturn := computeDeferReturn(ctxt, deferReturnSym, s)
857 off = sb.SetUint32(ctxt.Arch, off, deferreturn)
858
859
860 if fi.Valid() {
861 off = sb.SetUint32(ctxt.Arch, off, uint32(ldr.SymValue(pcsp)))
862 off = sb.SetUint32(ctxt.Arch, off, uint32(ldr.SymValue(pcfile)))
863 off = sb.SetUint32(ctxt.Arch, off, uint32(ldr.SymValue(pcline)))
864 } else {
865 off += 12
866 }
867 off = sb.SetUint32(ctxt.Arch, off, numPCData(ldr, s, fi))
868
869
870 cuIdx := ^uint32(0)
871 if cu := ldr.SymUnit(s); cu != nil {
872 cuIdx = cuOffsets[cu.PclnIndex]
873 }
874 off = sb.SetUint32(ctxt.Arch, off, cuIdx)
875
876
877 off = sb.SetUint32(ctxt.Arch, off, uint32(startLine))
878
879
880 var funcID abi.FuncID
881 if fi.Valid() {
882 funcID = fi.FuncID()
883 }
884 off = sb.SetUint8(ctxt.Arch, off, uint8(funcID))
885
886
887 var flag abi.FuncFlag
888 if fi.Valid() {
889 flag = fi.FuncFlag()
890 }
891 off = sb.SetUint8(ctxt.Arch, off, uint8(flag))
892
893 off += 1
894
895
896 funcdata = funcData(ldr, s, fi, 0, funcdata)
897 off = sb.SetUint8(ctxt.Arch, off, uint8(len(funcdata)))
898
899
900 if fi.Valid() {
901 for j, pcSym := range pcdata {
902 sb.SetUint32(ctxt.Arch, off+int64(j*4), uint32(ldr.SymValue(pcSym)))
903 }
904 if fi.NumInlTree() > 0 {
905 sb.SetUint32(ctxt.Arch, off+abi.PCDATA_InlTreeIndex*4, uint32(ldr.SymValue(pcinline)))
906 }
907 }
908
909
910 funcdata = funcData(ldr, s, fi, inlSyms[s], funcdata)
911
912 off = int64(startLocations[i] + funcSize + numPCData(ldr, s, fi)*4)
913 for j := range funcdata {
914 dataoff := off + int64(4*j)
915 fdsym := funcdata[j]
916
917 if ignoreFuncData(ldr, s, j, fdsym) {
918 sb.SetUint32(ctxt.Arch, dataoff, ^uint32(0))
919 continue
920 }
921
922 sb.SetUint32(ctxt.Arch, dataoff, uint32(ldr.SymValue(fdsym)))
923 }
924 }
925 }
926
927
928
929
930
931 func (ctxt *Link) pclntab(container loader.Bitmap) *pclntab {
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969 state, compUnits, funcs := makePclntab(ctxt, container)
970
971 ldr := ctxt.loader
972 state.carrier = ldr.LookupOrCreateSym("runtime.pclntab", 0)
973 ldr.MakeSymbolUpdater(state.carrier).SetType(sym.SPCLNTAB)
974 ldr.SetAttrReachable(state.carrier, true)
975 setCarrierSym(sym.SPCLNTAB, state.carrier)
976
977
978
979 ldr.SetSymAlign(state.carrier, int32(ctxt.Arch.PtrSize))
980
981 state.generatePCHeader(ctxt)
982 nameOffsets := state.generateFuncnametab(ctxt, funcs)
983 cuOffsets := state.generateFilenameTabs(ctxt, compUnits, funcs)
984 state.generatePctab(ctxt, funcs)
985 inlSyms := makeInlSyms(ctxt, funcs, nameOffsets)
986 state.generateFunctab(ctxt, funcs, inlSyms, cuOffsets, nameOffsets)
987 state.generateFuncdata(ctxt, funcs, inlSyms)
988
989 return state
990 }
991
992 func expandGoroot(s string) string {
993 const n = len("$GOROOT")
994 if len(s) >= n+1 && s[:n] == "$GOROOT" && (s[n] == '/' || s[n] == '\\') {
995 if final := buildcfg.GOROOT; final != "" {
996 return filepath.ToSlash(filepath.Join(final, s[n:]))
997 }
998 }
999 return s
1000 }
1001
1002 const (
1003 SUBBUCKETS = 16
1004 SUBBUCKETSIZE = abi.FuncTabBucketSize / SUBBUCKETS
1005 NOIDX = 0x7fffffff
1006 )
1007
1008
1009
1010 func (ctxt *Link) findfunctab(state *pclntab, container loader.Bitmap) {
1011 ldr := ctxt.loader
1012
1013
1014 min := ldr.SymValue(ctxt.Textp[0])
1015 lastp := ctxt.Textp[len(ctxt.Textp)-1]
1016 max := ldr.SymValue(lastp) + ldr.SymSize(lastp)
1017
1018
1019
1020 n := int32((max - min + SUBBUCKETSIZE - 1) / SUBBUCKETSIZE)
1021
1022 nbuckets := int32((max - min + abi.FuncTabBucketSize - 1) / abi.FuncTabBucketSize)
1023
1024 size := 4*int64(nbuckets) + int64(n)
1025
1026 writeFindFuncTab := func(_ *Link, s loader.Sym) {
1027 t := ldr.MakeSymbolUpdater(s)
1028
1029 indexes := make([]int32, n)
1030 for i := int32(0); i < n; i++ {
1031 indexes[i] = NOIDX
1032 }
1033 idx := int32(0)
1034 for i, s := range ctxt.Textp {
1035 if !emitPcln(ctxt, s, container) {
1036 continue
1037 }
1038 p := ldr.SymValue(s)
1039 var e loader.Sym
1040 i++
1041 if i < len(ctxt.Textp) {
1042 e = ctxt.Textp[i]
1043 }
1044 for e != 0 && !emitPcln(ctxt, e, container) && i < len(ctxt.Textp) {
1045 e = ctxt.Textp[i]
1046 i++
1047 }
1048 q := max
1049 if e != 0 {
1050 q = ldr.SymValue(e)
1051 }
1052
1053
1054 for ; p < q; p += SUBBUCKETSIZE {
1055 i = int((p - min) / SUBBUCKETSIZE)
1056 if indexes[i] > idx {
1057 indexes[i] = idx
1058 }
1059 }
1060
1061 i = int((q - 1 - min) / SUBBUCKETSIZE)
1062 if indexes[i] > idx {
1063 indexes[i] = idx
1064 }
1065 idx++
1066 }
1067
1068
1069 for i := int32(0); i < nbuckets; i++ {
1070 base := indexes[i*SUBBUCKETS]
1071 if base == NOIDX {
1072 Errorf("hole in findfunctab")
1073 }
1074 t.SetUint32(ctxt.Arch, int64(i)*(4+SUBBUCKETS), uint32(base))
1075 for j := int32(0); j < SUBBUCKETS && i*SUBBUCKETS+j < n; j++ {
1076 idx = indexes[i*SUBBUCKETS+j]
1077 if idx == NOIDX {
1078 Errorf("hole in findfunctab")
1079 }
1080 if idx-base >= 256 {
1081 Errorf("too many functions in a findfunc bucket! %d/%d %d %d", i, nbuckets, j, idx-base)
1082 }
1083
1084 t.SetUint8(ctxt.Arch, int64(i)*(4+SUBBUCKETS)+4+int64(j), uint8(idx-base))
1085 }
1086 }
1087 }
1088
1089 state.findfunctab = ctxt.createGeneratorSymbol("runtime.findfunctab", 0, sym.SPCLNTAB, size, writeFindFuncTab)
1090 ldr.SetSymAlign(state.findfunctab, 4)
1091 ldr.SetAttrReachable(state.findfunctab, true)
1092 ldr.SetAttrLocal(state.findfunctab, true)
1093 }
1094
1095
1096
1097 func (ctxt *Link) findContainerSyms() loader.Bitmap {
1098 ldr := ctxt.loader
1099 container := loader.MakeBitmap(ldr.NSym())
1100
1101 for _, s := range ctxt.Textp {
1102 outer := ldr.OuterSym(s)
1103 if outer != 0 {
1104 container.Set(outer)
1105 }
1106 }
1107 return container
1108 }
1109
View as plain text