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