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 "fmt"
14 "internal/abi"
15 "internal/buildcfg"
16 "path/filepath"
17 "strings"
18 )
19
20 const funcSize = 11 * 4
21
22
23 type pclntab struct {
24
25 firstFunc, lastFunc loader.Sym
26
27
28 size int64
29
30
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
41
42
43
44
45
46
47 nfunc int32
48
49
50 nfiles uint32
51 }
52
53
54
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
66
67
68
69 func makePclntab(ctxt *Link, container loader.Bitmap) (*pclntab, []*sym.CompilationUnit, []loader.Sym) {
70 ldr := ctxt.loader
71 state := new(pclntab)
72
73
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
90
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 if ctxt.Target.IsRISCV64() {
103
104
105
106
107
108
109 symName := ctxt.loader.SymName(s)
110 if symName == "" || strings.HasPrefix(symName, ".L") {
111 return false
112 }
113 }
114
115
116
117 return !container.Has(s)
118 }
119
120 func computeDeferReturn(ctxt *Link, deferReturnSym, s loader.Sym) uint32 {
121 ldr := ctxt.loader
122 target := ctxt.Target
123 deferreturn := uint32(0)
124 lastWasmAddr := uint32(0)
125
126 relocs := ldr.Relocs(s)
127 for ri := 0; ri < relocs.Count(); ri++ {
128 r := relocs.At(ri)
129 if target.IsWasm() && r.Type() == objabi.R_ADDR {
130
131
132
133
134 lastWasmAddr = uint32(r.Add())
135 }
136 if r.Type().IsDirectCall() && (r.Sym() == deferReturnSym || ldr.IsDeferReturnTramp(r.Sym())) {
137 if target.IsWasm() {
138 deferreturn = lastWasmAddr - 1
139 } else {
140
141
142
143
144 deferreturn = uint32(r.Off())
145 switch target.Arch.Family {
146 case sys.AMD64, sys.I386:
147 deferreturn--
148 case sys.ARM, sys.ARM64, sys.Loong64, sys.MIPS, sys.MIPS64, sys.PPC64, sys.RISCV64:
149
150 case sys.S390X:
151 deferreturn -= 2
152 default:
153 panic(fmt.Sprint("Unhandled architecture:", target.Arch.Family))
154 }
155 }
156 break
157 }
158 }
159 return deferreturn
160 }
161
162
163
164 func genInlTreeSym(ctxt *Link, cu *sym.CompilationUnit, fi loader.FuncInfo, arch *sys.Arch, nameOffsets map[loader.Sym]uint32) loader.Sym {
165 ldr := ctxt.loader
166 its := ldr.CreateExtSym("", 0)
167 inlTreeSym := ldr.MakeSymbolUpdater(its)
168
169
170
171
172 inlTreeSym.SetType(sym.SGOFUNC)
173 ldr.SetAttrReachable(its, true)
174 ldr.SetSymAlign(its, 4)
175 ninl := fi.NumInlTree()
176 for i := 0; i < int(ninl); i++ {
177 call := fi.InlTree(i)
178 nameOff, ok := nameOffsets[call.Func]
179 if !ok {
180 panic("couldn't find function name offset")
181 }
182
183 inlFunc := ldr.FuncInfo(call.Func)
184 var funcID abi.FuncID
185 startLine := int32(0)
186 if inlFunc.Valid() {
187 funcID = inlFunc.FuncID()
188 startLine = inlFunc.StartLine()
189 } else if !ctxt.linkShared {
190
191
192
193
194
195
196
197
198 panic(fmt.Sprintf("inlined function %s missing func info", ldr.SymName(call.Func)))
199 }
200
201
202 const size = 16
203 inlTreeSym.SetUint8(arch, int64(i*size+0), uint8(funcID))
204
205 inlTreeSym.SetUint32(arch, int64(i*size+4), uint32(nameOff))
206 inlTreeSym.SetUint32(arch, int64(i*size+8), uint32(call.ParentPC))
207 inlTreeSym.SetUint32(arch, int64(i*size+12), uint32(startLine))
208 }
209 return its
210 }
211
212
213 func makeInlSyms(ctxt *Link, funcs []loader.Sym, nameOffsets map[loader.Sym]uint32) map[loader.Sym]loader.Sym {
214 ldr := ctxt.loader
215
216 inlSyms := make(map[loader.Sym]loader.Sym)
217 for _, s := range funcs {
218 if fi := ldr.FuncInfo(s); fi.Valid() {
219 fi.Preload()
220 if fi.NumInlTree() > 0 {
221 inlSyms[s] = genInlTreeSym(ctxt, ldr.SymUnit(s), fi, ctxt.Arch, nameOffsets)
222 }
223 }
224 }
225 return inlSyms
226 }
227
228
229
230 func (state *pclntab) generatePCHeader(ctxt *Link) {
231 ldr := ctxt.loader
232 textStartOff := int64(8 + 2*ctxt.Arch.PtrSize)
233 size := int64(8 + 8*ctxt.Arch.PtrSize)
234 writeHeader := func(ctxt *Link, s loader.Sym) {
235 header := ctxt.loader.MakeSymbolUpdater(s)
236
237 writeSymOffset := func(off int64, ws loader.Sym) int64 {
238 diff := ldr.SymValue(ws) - ldr.SymValue(s)
239 if diff <= 0 {
240 name := ldr.SymName(ws)
241 panic(fmt.Sprintf("expected runtime.pcheader(%x) to be placed before %s(%x)", ldr.SymValue(s), name, ldr.SymValue(ws)))
242 }
243 return header.SetUintptr(ctxt.Arch, off, uintptr(diff))
244 }
245
246
247
248 header.SetUint32(ctxt.Arch, 0, 0xfffffff1)
249 header.SetUint8(ctxt.Arch, 6, uint8(ctxt.Arch.MinLC))
250 header.SetUint8(ctxt.Arch, 7, uint8(ctxt.Arch.PtrSize))
251 off := header.SetUint(ctxt.Arch, 8, uint64(state.nfunc))
252 off = header.SetUint(ctxt.Arch, off, uint64(state.nfiles))
253 if off != textStartOff {
254 panic(fmt.Sprintf("pcHeader textStartOff: %d != %d", off, textStartOff))
255 }
256 off += int64(ctxt.Arch.PtrSize)
257 off = writeSymOffset(off, state.funcnametab)
258 off = writeSymOffset(off, state.cutab)
259 off = writeSymOffset(off, state.filetab)
260 off = writeSymOffset(off, state.pctab)
261 off = writeSymOffset(off, state.pclntab)
262 if off != size {
263 panic(fmt.Sprintf("pcHeader size: %d != %d", off, size))
264 }
265 }
266
267 state.pcheader = state.addGeneratedSym(ctxt, "runtime.pcheader", size, writeHeader)
268
269 sb := ldr.MakeSymbolUpdater(state.pcheader)
270 sb.SetAddr(ctxt.Arch, textStartOff, ldr.Lookup("runtime.text", 0))
271 }
272
273
274
275 func walkFuncs(ctxt *Link, funcs []loader.Sym, f func(loader.Sym)) {
276 ldr := ctxt.loader
277 seen := make(map[loader.Sym]struct{})
278 for _, s := range funcs {
279 if _, ok := seen[s]; !ok {
280 f(s)
281 seen[s] = struct{}{}
282 }
283
284 fi := ldr.FuncInfo(s)
285 if !fi.Valid() {
286 continue
287 }
288 fi.Preload()
289 for i, ni := 0, fi.NumInlTree(); i < int(ni); i++ {
290 call := fi.InlTree(i).Func
291 if _, ok := seen[call]; !ok {
292 f(call)
293 seen[call] = struct{}{}
294 }
295 }
296 }
297 }
298
299
300
301 func (state *pclntab) generateFuncnametab(ctxt *Link, funcs []loader.Sym) map[loader.Sym]uint32 {
302 nameOffsets := make(map[loader.Sym]uint32, state.nfunc)
303
304
305 writeFuncNameTab := func(ctxt *Link, s loader.Sym) {
306 symtab := ctxt.loader.MakeSymbolUpdater(s)
307 for s, off := range nameOffsets {
308 symtab.AddCStringAt(int64(off), ctxt.loader.SymName(s))
309 }
310 }
311
312
313 var size int64
314 walkFuncs(ctxt, funcs, func(s loader.Sym) {
315 nameOffsets[s] = uint32(size)
316 size += int64(len(ctxt.loader.SymName(s)) + 1)
317 })
318
319 state.funcnametab = state.addGeneratedSym(ctxt, "runtime.funcnametab", size, writeFuncNameTab)
320 return nameOffsets
321 }
322
323
324
325 func walkFilenames(ctxt *Link, funcs []loader.Sym, f func(*sym.CompilationUnit, goobj.CUFileIndex)) {
326 ldr := ctxt.loader
327
328
329 for _, s := range funcs {
330 fi := ldr.FuncInfo(s)
331 if !fi.Valid() {
332 continue
333 }
334 fi.Preload()
335
336 cu := ldr.SymUnit(s)
337 for i, nf := 0, int(fi.NumFile()); i < nf; i++ {
338 f(cu, fi.File(i))
339 }
340 for i, ninl := 0, int(fi.NumInlTree()); i < ninl; i++ {
341 call := fi.InlTree(i)
342 f(cu, call.File)
343 }
344 }
345 }
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369 func (state *pclntab) generateFilenameTabs(ctxt *Link, compUnits []*sym.CompilationUnit, funcs []loader.Sym) []uint32 {
370
371
372
373
374
375
376
377
378
379
380
381 cuEntries := make([]goobj.CUFileIndex, len(compUnits))
382 fileOffsets := make(map[string]uint32)
383
384
385
386
387
388 var fileSize int64
389 walkFilenames(ctxt, funcs, func(cu *sym.CompilationUnit, i goobj.CUFileIndex) {
390
391
392 filename := cu.FileTable[i]
393 if _, ok := fileOffsets[filename]; !ok {
394 fileOffsets[filename] = uint32(fileSize)
395 fileSize += int64(len(expandFile(filename)) + 1)
396 }
397
398
399 if cuEntries[cu.PclnIndex] < i+1 {
400 cuEntries[cu.PclnIndex] = i + 1
401 }
402 })
403
404
405 var totalEntries uint32
406 cuOffsets := make([]uint32, len(cuEntries))
407 for i, entries := range cuEntries {
408
409
410
411 cuOffsets[i] = totalEntries
412 totalEntries += uint32(entries)
413 }
414
415
416 writeCutab := func(ctxt *Link, s loader.Sym) {
417 sb := ctxt.loader.MakeSymbolUpdater(s)
418
419 var off int64
420 for i, max := range cuEntries {
421
422 cu := compUnits[i]
423 for j := goobj.CUFileIndex(0); j < max; j++ {
424 fileOffset, ok := fileOffsets[cu.FileTable[j]]
425 if !ok {
426
427
428
429 fileOffset = ^uint32(0)
430 }
431 off = sb.SetUint32(ctxt.Arch, off, fileOffset)
432 }
433 }
434 }
435 state.cutab = state.addGeneratedSym(ctxt, "runtime.cutab", int64(totalEntries*4), writeCutab)
436
437
438 writeFiletab := func(ctxt *Link, s loader.Sym) {
439 sb := ctxt.loader.MakeSymbolUpdater(s)
440
441
442 for filename, loc := range fileOffsets {
443 sb.AddStringAt(int64(loc), expandFile(filename))
444 }
445 }
446 state.nfiles = uint32(len(fileOffsets))
447 state.filetab = state.addGeneratedSym(ctxt, "runtime.filetab", fileSize, writeFiletab)
448
449 return cuOffsets
450 }
451
452
453
454 func (state *pclntab) generatePctab(ctxt *Link, funcs []loader.Sym) {
455 ldr := ctxt.loader
456
457
458
459
460 size := int64(1)
461
462
463 seen := make(map[loader.Sym]struct{})
464 saveOffset := func(pcSym loader.Sym) {
465 if _, ok := seen[pcSym]; !ok {
466 datSize := ldr.SymSize(pcSym)
467 if datSize != 0 {
468 ldr.SetSymValue(pcSym, size)
469 } else {
470
471 ldr.SetSymValue(pcSym, 0)
472 }
473 size += datSize
474 seen[pcSym] = struct{}{}
475 }
476 }
477 var pcsp, pcline, pcfile, pcinline loader.Sym
478 var pcdata []loader.Sym
479 for _, s := range funcs {
480 fi := ldr.FuncInfo(s)
481 if !fi.Valid() {
482 continue
483 }
484 fi.Preload()
485 pcsp, pcfile, pcline, pcinline, pcdata = ldr.PcdataAuxs(s, pcdata)
486
487 pcSyms := []loader.Sym{pcsp, pcfile, pcline}
488 for _, pcSym := range pcSyms {
489 saveOffset(pcSym)
490 }
491 for _, pcSym := range pcdata {
492 saveOffset(pcSym)
493 }
494 if fi.NumInlTree() > 0 {
495 saveOffset(pcinline)
496 }
497 }
498
499
500
501
502
503 writePctab := func(ctxt *Link, s loader.Sym) {
504 ldr := ctxt.loader
505 sb := ldr.MakeSymbolUpdater(s)
506 for sym := range seen {
507 sb.SetBytesAt(ldr.SymValue(sym), ldr.Data(sym))
508 }
509 }
510
511 state.pctab = state.addGeneratedSym(ctxt, "runtime.pctab", size, writePctab)
512 }
513
514
515
516 func numPCData(ldr *loader.Loader, s loader.Sym, fi loader.FuncInfo) uint32 {
517 if !fi.Valid() {
518 return 0
519 }
520 numPCData := uint32(ldr.NumPcdata(s))
521 if fi.NumInlTree() > 0 {
522 if numPCData < abi.PCDATA_InlTreeIndex+1 {
523 numPCData = abi.PCDATA_InlTreeIndex + 1
524 }
525 }
526 return numPCData
527 }
528
529
530
531
532
533
534
535 func (state *pclntab) generateFunctab(ctxt *Link, funcs []loader.Sym, inlSyms map[loader.Sym]loader.Sym, cuOffsets []uint32, nameOffsets map[loader.Sym]uint32) {
536
537 size, startLocations := state.calculateFunctabSize(ctxt, funcs)
538 writePcln := func(ctxt *Link, s loader.Sym) {
539 ldr := ctxt.loader
540 sb := ldr.MakeSymbolUpdater(s)
541
542 writePCToFunc(ctxt, sb, funcs, startLocations)
543 writeFuncs(ctxt, sb, funcs, inlSyms, startLocations, cuOffsets, nameOffsets)
544 }
545 state.pclntab = state.addGeneratedSym(ctxt, "runtime.functab", size, writePcln)
546 }
547
548
549
550
551
552
553
554
555 func funcData(ldr *loader.Loader, s loader.Sym, fi loader.FuncInfo, inlSym loader.Sym, fdSyms []loader.Sym) []loader.Sym {
556 fdSyms = fdSyms[:0]
557 if fi.Valid() {
558 fdSyms = ldr.Funcdata(s, fdSyms)
559 if fi.NumInlTree() > 0 {
560 if len(fdSyms) < abi.FUNCDATA_InlTree+1 {
561 fdSyms = append(fdSyms, make([]loader.Sym, abi.FUNCDATA_InlTree+1-len(fdSyms))...)
562 }
563 fdSyms[abi.FUNCDATA_InlTree] = inlSym
564 }
565 }
566 return fdSyms
567 }
568
569
570
571 func (state pclntab) calculateFunctabSize(ctxt *Link, funcs []loader.Sym) (int64, []uint32) {
572 ldr := ctxt.loader
573 startLocations := make([]uint32, len(funcs))
574
575
576
577
578 size := int64(int(state.nfunc)*2*4 + 4)
579
580
581
582 for i, s := range funcs {
583 size = Rnd(size, int64(ctxt.Arch.PtrSize))
584 startLocations[i] = uint32(size)
585 fi := ldr.FuncInfo(s)
586 size += funcSize
587 if fi.Valid() {
588 fi.Preload()
589 numFuncData := ldr.NumFuncdata(s)
590 if fi.NumInlTree() > 0 {
591 if numFuncData < abi.FUNCDATA_InlTree+1 {
592 numFuncData = abi.FUNCDATA_InlTree + 1
593 }
594 }
595 size += int64(numPCData(ldr, s, fi) * 4)
596 size += int64(numFuncData * 4)
597 }
598 }
599
600 return size, startLocations
601 }
602
603
604 func writePCToFunc(ctxt *Link, sb *loader.SymbolBuilder, funcs []loader.Sym, startLocations []uint32) {
605 ldr := ctxt.loader
606 textStart := ldr.SymValue(ldr.Lookup("runtime.text", 0))
607 pcOff := func(s loader.Sym) uint32 {
608 off := ldr.SymValue(s) - textStart
609 if off < 0 {
610 panic(fmt.Sprintf("expected func %s(%x) to be placed at or after textStart (%x)", ldr.SymName(s), ldr.SymValue(s), textStart))
611 }
612 return uint32(off)
613 }
614 for i, s := range funcs {
615 sb.SetUint32(ctxt.Arch, int64(i*2*4), pcOff(s))
616 sb.SetUint32(ctxt.Arch, int64((i*2+1)*4), startLocations[i])
617 }
618
619
620 lastFunc := funcs[len(funcs)-1]
621 sb.SetUint32(ctxt.Arch, int64(len(funcs))*2*4, pcOff(lastFunc)+uint32(ldr.SymSize(lastFunc)))
622 }
623
624
625 func writeFuncs(ctxt *Link, sb *loader.SymbolBuilder, funcs []loader.Sym, inlSyms map[loader.Sym]loader.Sym, startLocations, cuOffsets []uint32, nameOffsets map[loader.Sym]uint32) {
626 ldr := ctxt.loader
627 deferReturnSym := ldr.Lookup("runtime.deferreturn", abiInternalVer)
628 gofunc := ldr.Lookup("go:func.*", 0)
629 gofuncBase := ldr.SymValue(gofunc)
630 textStart := ldr.SymValue(ldr.Lookup("runtime.text", 0))
631 funcdata := []loader.Sym{}
632 var pcsp, pcfile, pcline, pcinline loader.Sym
633 var pcdata []loader.Sym
634
635
636 for i, s := range funcs {
637 startLine := int32(0)
638 fi := ldr.FuncInfo(s)
639 if fi.Valid() {
640 fi.Preload()
641 pcsp, pcfile, pcline, pcinline, pcdata = ldr.PcdataAuxs(s, pcdata)
642 startLine = fi.StartLine()
643 }
644
645 off := int64(startLocations[i])
646
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
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
661
662 args := uint32(0)
663 if fi.Valid() {
664 args = uint32(fi.Args())
665 }
666 off = sb.SetUint32(ctxt.Arch, off, args)
667
668
669 deferreturn := computeDeferReturn(ctxt, deferReturnSym, s)
670 off = sb.SetUint32(ctxt.Arch, off, deferreturn)
671
672
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
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
690 off = sb.SetUint32(ctxt.Arch, off, uint32(startLine))
691
692
693 var funcID abi.FuncID
694 if fi.Valid() {
695 funcID = fi.FuncID()
696 }
697 off = sb.SetUint8(ctxt.Arch, off, uint8(funcID))
698
699
700 var flag abi.FuncFlag
701 if fi.Valid() {
702 flag = fi.FuncFlag()
703 }
704 off = sb.SetUint8(ctxt.Arch, off, uint8(flag))
705
706 off += 1
707
708
709 funcdata = funcData(ldr, s, fi, 0, funcdata)
710 off = sb.SetUint8(ctxt.Arch, off, uint8(len(funcdata)))
711
712
713 if fi.Valid() {
714 for j, pcSym := range pcdata {
715 sb.SetUint32(ctxt.Arch, off+int64(j*4), uint32(ldr.SymValue(pcSym)))
716 }
717 if fi.NumInlTree() > 0 {
718 sb.SetUint32(ctxt.Arch, off+abi.PCDATA_InlTreeIndex*4, uint32(ldr.SymValue(pcinline)))
719 }
720 }
721
722
723 funcdata = funcData(ldr, s, fi, inlSyms[s], funcdata)
724
725 off = int64(startLocations[i] + funcSize + numPCData(ldr, s, fi)*4)
726 for j := range funcdata {
727 dataoff := off + int64(4*j)
728 fdsym := funcdata[j]
729
730
731
732
733
734
735
736 if fdsym != 0 && (j == abi.FUNCDATA_ArgsPointerMaps || j == abi.FUNCDATA_ArgInfo) && ldr.IsFromAssembly(s) && ldr.Data(fdsym) == nil {
737 fdsym = 0
738 }
739
740 if fdsym == 0 {
741 sb.SetUint32(ctxt.Arch, dataoff, ^uint32(0))
742 continue
743 }
744
745 if outer := ldr.OuterSym(fdsym); outer != gofunc {
746 panic(fmt.Sprintf("bad carrier sym for symbol %s (funcdata %s#%d), want go:func.* got %s", ldr.SymName(fdsym), ldr.SymName(s), j, ldr.SymName(outer)))
747 }
748 sb.SetUint32(ctxt.Arch, dataoff, uint32(ldr.SymValue(fdsym)-gofuncBase))
749 }
750 }
751 }
752
753
754
755
756
757 func (ctxt *Link) pclntab(container loader.Bitmap) *pclntab {
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792 state, compUnits, funcs := makePclntab(ctxt, container)
793
794 ldr := ctxt.loader
795 state.carrier = ldr.LookupOrCreateSym("runtime.pclntab", 0)
796 ldr.MakeSymbolUpdater(state.carrier).SetType(sym.SPCLNTAB)
797 ldr.SetAttrReachable(state.carrier, true)
798 setCarrierSym(sym.SPCLNTAB, state.carrier)
799
800 state.generatePCHeader(ctxt)
801 nameOffsets := state.generateFuncnametab(ctxt, funcs)
802 cuOffsets := state.generateFilenameTabs(ctxt, compUnits, funcs)
803 state.generatePctab(ctxt, funcs)
804 inlSyms := makeInlSyms(ctxt, funcs, nameOffsets)
805 state.generateFunctab(ctxt, funcs, inlSyms, cuOffsets, nameOffsets)
806
807 return state
808 }
809
810 func expandGoroot(s string) string {
811 const n = len("$GOROOT")
812 if len(s) >= n+1 && s[:n] == "$GOROOT" && (s[n] == '/' || s[n] == '\\') {
813 if final := buildcfg.GOROOT; final != "" {
814 return filepath.ToSlash(filepath.Join(final, s[n:]))
815 }
816 }
817 return s
818 }
819
820 const (
821 SUBBUCKETS = 16
822 SUBBUCKETSIZE = abi.FuncTabBucketSize / SUBBUCKETS
823 NOIDX = 0x7fffffff
824 )
825
826
827
828 func (ctxt *Link) findfunctab(state *pclntab, container loader.Bitmap) {
829 ldr := ctxt.loader
830
831
832 min := ldr.SymValue(ctxt.Textp[0])
833 lastp := ctxt.Textp[len(ctxt.Textp)-1]
834 max := ldr.SymValue(lastp) + ldr.SymSize(lastp)
835
836
837
838 n := int32((max - min + SUBBUCKETSIZE - 1) / SUBBUCKETSIZE)
839
840 nbuckets := int32((max - min + abi.FuncTabBucketSize - 1) / abi.FuncTabBucketSize)
841
842 size := 4*int64(nbuckets) + int64(n)
843
844 writeFindFuncTab := func(_ *Link, s loader.Sym) {
845 t := ldr.MakeSymbolUpdater(s)
846
847 indexes := make([]int32, n)
848 for i := int32(0); i < n; i++ {
849 indexes[i] = NOIDX
850 }
851 idx := int32(0)
852 for i, s := range ctxt.Textp {
853 if !emitPcln(ctxt, s, container) {
854 continue
855 }
856 p := ldr.SymValue(s)
857 var e loader.Sym
858 i++
859 if i < len(ctxt.Textp) {
860 e = ctxt.Textp[i]
861 }
862 for e != 0 && !emitPcln(ctxt, e, container) && i < len(ctxt.Textp) {
863 e = ctxt.Textp[i]
864 i++
865 }
866 q := max
867 if e != 0 {
868 q = ldr.SymValue(e)
869 }
870
871
872 for ; p < q; p += SUBBUCKETSIZE {
873 i = int((p - min) / SUBBUCKETSIZE)
874 if indexes[i] > idx {
875 indexes[i] = idx
876 }
877 }
878
879 i = int((q - 1 - min) / SUBBUCKETSIZE)
880 if indexes[i] > idx {
881 indexes[i] = idx
882 }
883 idx++
884 }
885
886
887 for i := int32(0); i < nbuckets; i++ {
888 base := indexes[i*SUBBUCKETS]
889 if base == NOIDX {
890 Errorf("hole in findfunctab")
891 }
892 t.SetUint32(ctxt.Arch, int64(i)*(4+SUBBUCKETS), uint32(base))
893 for j := int32(0); j < SUBBUCKETS && i*SUBBUCKETS+j < n; j++ {
894 idx = indexes[i*SUBBUCKETS+j]
895 if idx == NOIDX {
896 Errorf("hole in findfunctab")
897 }
898 if idx-base >= 256 {
899 Errorf("too many functions in a findfunc bucket! %d/%d %d %d", i, nbuckets, j, idx-base)
900 }
901
902 t.SetUint8(ctxt.Arch, int64(i)*(4+SUBBUCKETS)+4+int64(j), uint8(idx-base))
903 }
904 }
905 }
906
907 state.findfunctab = ctxt.createGeneratorSymbol("runtime.findfunctab", 0, sym.SRODATA, size, writeFindFuncTab)
908 ldr.SetAttrReachable(state.findfunctab, true)
909 ldr.SetAttrLocal(state.findfunctab, true)
910 }
911
912
913
914 func (ctxt *Link) findContainerSyms() loader.Bitmap {
915 ldr := ctxt.loader
916 container := loader.MakeBitmap(ldr.NSym())
917
918 for _, s := range ctxt.Textp {
919 outer := ldr.OuterSym(s)
920 if outer != 0 {
921 container.Set(outer)
922 }
923 }
924 return container
925 }
926
View as plain text