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