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