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