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