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
619
620 func textOff(ctxt *Link, s loader.Sym, textStart int64) uint32 {
621 ldr := ctxt.loader
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 if ctxt.IsWasm() {
627
628
629
630 if off&(1<<16-1) != 0 {
631 ctxt.Errorf(s, "nonzero PC_B at function entry: %#x", off)
632 }
633 off >>= 16
634 }
635 if int64(uint32(off)) != off {
636 ctxt.Errorf(s, "textOff overflow: %#x", off)
637 }
638 return uint32(off)
639 }
640
641
642 func writePCToFunc(ctxt *Link, sb *loader.SymbolBuilder, funcs []loader.Sym, startLocations []uint32) {
643 ldr := ctxt.loader
644 textStart := ldr.SymValue(ldr.Lookup("runtime.text", 0))
645 pcOff := func(s loader.Sym) uint32 {
646 return textOff(ctxt, s, textStart)
647 }
648 for i, s := range funcs {
649 sb.SetUint32(ctxt.Arch, int64(i*2*4), pcOff(s))
650 sb.SetUint32(ctxt.Arch, int64((i*2+1)*4), startLocations[i])
651 }
652
653
654 lastFunc := funcs[len(funcs)-1]
655 lastPC := pcOff(lastFunc) + uint32(ldr.SymSize(lastFunc))
656 if ctxt.IsWasm() {
657 lastPC = pcOff(lastFunc) + 1
658 }
659 sb.SetUint32(ctxt.Arch, int64(len(funcs))*2*4, lastPC)
660 }
661
662
663 func writeFuncs(ctxt *Link, sb *loader.SymbolBuilder, funcs []loader.Sym, inlSyms map[loader.Sym]loader.Sym, startLocations, cuOffsets []uint32, nameOffsets map[loader.Sym]uint32) {
664 ldr := ctxt.loader
665 deferReturnSym := ldr.Lookup("runtime.deferreturn", abiInternalVer)
666 gofunc := ldr.Lookup("go:func.*", 0)
667 gofuncBase := ldr.SymValue(gofunc)
668 textStart := ldr.SymValue(ldr.Lookup("runtime.text", 0))
669 funcdata := []loader.Sym{}
670 var pcsp, pcfile, pcline, pcinline loader.Sym
671 var pcdata []loader.Sym
672
673
674 for i, s := range funcs {
675 startLine := int32(0)
676 fi := ldr.FuncInfo(s)
677 if fi.Valid() {
678 fi.Preload()
679 pcsp, pcfile, pcline, pcinline, pcdata = ldr.PcdataAuxs(s, pcdata)
680 startLine = fi.StartLine()
681 }
682
683 off := int64(startLocations[i])
684
685 entryOff := textOff(ctxt, s, textStart)
686 off = sb.SetUint32(ctxt.Arch, off, uint32(entryOff))
687
688
689 nameOff, ok := nameOffsets[s]
690 if !ok {
691 panic("couldn't find function name offset")
692 }
693 off = sb.SetUint32(ctxt.Arch, off, uint32(nameOff))
694
695
696
697 args := uint32(0)
698 if fi.Valid() {
699 args = uint32(fi.Args())
700 }
701 off = sb.SetUint32(ctxt.Arch, off, args)
702
703
704 deferreturn := computeDeferReturn(ctxt, deferReturnSym, s)
705 off = sb.SetUint32(ctxt.Arch, off, deferreturn)
706
707
708 if fi.Valid() {
709 off = sb.SetUint32(ctxt.Arch, off, uint32(ldr.SymValue(pcsp)))
710 off = sb.SetUint32(ctxt.Arch, off, uint32(ldr.SymValue(pcfile)))
711 off = sb.SetUint32(ctxt.Arch, off, uint32(ldr.SymValue(pcline)))
712 } else {
713 off += 12
714 }
715 off = sb.SetUint32(ctxt.Arch, off, uint32(numPCData(ldr, s, fi)))
716
717
718 cuIdx := ^uint32(0)
719 if cu := ldr.SymUnit(s); cu != nil {
720 cuIdx = cuOffsets[cu.PclnIndex]
721 }
722 off = sb.SetUint32(ctxt.Arch, off, cuIdx)
723
724
725 off = sb.SetUint32(ctxt.Arch, off, uint32(startLine))
726
727
728 var funcID abi.FuncID
729 if fi.Valid() {
730 funcID = fi.FuncID()
731 }
732 off = sb.SetUint8(ctxt.Arch, off, uint8(funcID))
733
734
735 var flag abi.FuncFlag
736 if fi.Valid() {
737 flag = fi.FuncFlag()
738 }
739 off = sb.SetUint8(ctxt.Arch, off, uint8(flag))
740
741 off += 1
742
743
744 funcdata = funcData(ldr, s, fi, 0, funcdata)
745 off = sb.SetUint8(ctxt.Arch, off, uint8(len(funcdata)))
746
747
748 if fi.Valid() {
749 for j, pcSym := range pcdata {
750 sb.SetUint32(ctxt.Arch, off+int64(j*4), uint32(ldr.SymValue(pcSym)))
751 }
752 if fi.NumInlTree() > 0 {
753 sb.SetUint32(ctxt.Arch, off+abi.PCDATA_InlTreeIndex*4, uint32(ldr.SymValue(pcinline)))
754 }
755 }
756
757
758 funcdata = funcData(ldr, s, fi, inlSyms[s], funcdata)
759
760 off = int64(startLocations[i] + funcSize + numPCData(ldr, s, fi)*4)
761 for j := range funcdata {
762 dataoff := off + int64(4*j)
763 fdsym := funcdata[j]
764
765
766
767
768
769
770
771 if fdsym != 0 && (j == abi.FUNCDATA_ArgsPointerMaps || j == abi.FUNCDATA_ArgInfo) && ldr.IsFromAssembly(s) && ldr.Data(fdsym) == nil {
772 fdsym = 0
773 }
774
775 if fdsym == 0 {
776 sb.SetUint32(ctxt.Arch, dataoff, ^uint32(0))
777 continue
778 }
779
780 if outer := ldr.OuterSym(fdsym); outer != gofunc {
781 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)))
782 }
783 sb.SetUint32(ctxt.Arch, dataoff, uint32(ldr.SymValue(fdsym)-gofuncBase))
784 }
785 }
786 }
787
788
789
790
791
792 func (ctxt *Link) pclntab(container loader.Bitmap) *pclntab {
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
821
822
823
824
825
826
827 state, compUnits, funcs := makePclntab(ctxt, container)
828
829 ldr := ctxt.loader
830 state.carrier = ldr.LookupOrCreateSym("runtime.pclntab", 0)
831 ldr.MakeSymbolUpdater(state.carrier).SetType(sym.SPCLNTAB)
832 ldr.SetAttrReachable(state.carrier, true)
833 setCarrierSym(sym.SPCLNTAB, state.carrier)
834
835 state.generatePCHeader(ctxt)
836 nameOffsets := state.generateFuncnametab(ctxt, funcs)
837 cuOffsets := state.generateFilenameTabs(ctxt, compUnits, funcs)
838 state.generatePctab(ctxt, funcs)
839 inlSyms := makeInlSyms(ctxt, funcs, nameOffsets)
840 state.generateFunctab(ctxt, funcs, inlSyms, cuOffsets, nameOffsets)
841
842 return state
843 }
844
845 func expandGoroot(s string) string {
846 const n = len("$GOROOT")
847 if len(s) >= n+1 && s[:n] == "$GOROOT" && (s[n] == '/' || s[n] == '\\') {
848 if final := buildcfg.GOROOT; final != "" {
849 return filepath.ToSlash(filepath.Join(final, s[n:]))
850 }
851 }
852 return s
853 }
854
855 const (
856 SUBBUCKETS = 16
857 SUBBUCKETSIZE = abi.FuncTabBucketSize / SUBBUCKETS
858 NOIDX = 0x7fffffff
859 )
860
861
862
863 func (ctxt *Link) findfunctab(state *pclntab, container loader.Bitmap) {
864 ldr := ctxt.loader
865
866
867 min := ldr.SymValue(ctxt.Textp[0])
868 lastp := ctxt.Textp[len(ctxt.Textp)-1]
869 max := ldr.SymValue(lastp) + ldr.SymSize(lastp)
870
871
872
873 n := int32((max - min + SUBBUCKETSIZE - 1) / SUBBUCKETSIZE)
874
875 nbuckets := int32((max - min + abi.FuncTabBucketSize - 1) / abi.FuncTabBucketSize)
876
877 size := 4*int64(nbuckets) + int64(n)
878
879 writeFindFuncTab := func(_ *Link, s loader.Sym) {
880 t := ldr.MakeSymbolUpdater(s)
881
882 indexes := make([]int32, n)
883 for i := int32(0); i < n; i++ {
884 indexes[i] = NOIDX
885 }
886 idx := int32(0)
887 for i, s := range ctxt.Textp {
888 if !emitPcln(ctxt, s, container) {
889 continue
890 }
891 p := ldr.SymValue(s)
892 var e loader.Sym
893 i++
894 if i < len(ctxt.Textp) {
895 e = ctxt.Textp[i]
896 }
897 for e != 0 && !emitPcln(ctxt, e, container) && i < len(ctxt.Textp) {
898 e = ctxt.Textp[i]
899 i++
900 }
901 q := max
902 if e != 0 {
903 q = ldr.SymValue(e)
904 }
905
906
907 for ; p < q; p += SUBBUCKETSIZE {
908 i = int((p - min) / SUBBUCKETSIZE)
909 if indexes[i] > idx {
910 indexes[i] = idx
911 }
912 }
913
914 i = int((q - 1 - min) / SUBBUCKETSIZE)
915 if indexes[i] > idx {
916 indexes[i] = idx
917 }
918 idx++
919 }
920
921
922 for i := int32(0); i < nbuckets; i++ {
923 base := indexes[i*SUBBUCKETS]
924 if base == NOIDX {
925 Errorf("hole in findfunctab")
926 }
927 t.SetUint32(ctxt.Arch, int64(i)*(4+SUBBUCKETS), uint32(base))
928 for j := int32(0); j < SUBBUCKETS && i*SUBBUCKETS+j < n; j++ {
929 idx = indexes[i*SUBBUCKETS+j]
930 if idx == NOIDX {
931 Errorf("hole in findfunctab")
932 }
933 if idx-base >= 256 {
934 Errorf("too many functions in a findfunc bucket! %d/%d %d %d", i, nbuckets, j, idx-base)
935 }
936
937 t.SetUint8(ctxt.Arch, int64(i)*(4+SUBBUCKETS)+4+int64(j), uint8(idx-base))
938 }
939 }
940 }
941
942 state.findfunctab = ctxt.createGeneratorSymbol("runtime.findfunctab", 0, sym.SRODATA, size, writeFindFuncTab)
943 ldr.SetAttrReachable(state.findfunctab, true)
944 ldr.SetAttrLocal(state.findfunctab, true)
945 }
946
947
948
949 func (ctxt *Link) findContainerSyms() loader.Bitmap {
950 ldr := ctxt.loader
951 container := loader.MakeBitmap(ldr.NSym())
952
953 for _, s := range ctxt.Textp {
954 outer := ldr.OuterSym(s)
955 if outer != 0 {
956 container.Set(outer)
957 }
958 }
959 return container
960 }
961
View as plain text