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