1
2
3
4
5
6
7 package obj
8
9 import (
10 "bytes"
11 "cmd/internal/bio"
12 "cmd/internal/goobj"
13 "cmd/internal/hash"
14 "cmd/internal/objabi"
15 "cmd/internal/sys"
16 "cmp"
17 "encoding/binary"
18 "fmt"
19 "internal/abi"
20 "io"
21 "log"
22 "os"
23 "path/filepath"
24 "slices"
25 "sort"
26 "strings"
27 )
28
29 const UnlinkablePkg = "<unlinkable>"
30
31
32 func WriteObjFile(ctxt *Link, b *bio.Writer) {
33
34 debugAsmEmit(ctxt)
35
36 genFuncInfoSyms(ctxt)
37
38 w := writer{
39 Writer: goobj.NewWriter(b),
40 ctxt: ctxt,
41 pkgpath: objabi.PathToPrefix(ctxt.Pkgpath),
42 }
43
44 start := b.Offset()
45 w.init()
46
47
48
49 flags := uint32(0)
50 if ctxt.Flag_shared {
51 flags |= goobj.ObjFlagShared
52 }
53 if w.pkgpath == UnlinkablePkg {
54 flags |= goobj.ObjFlagUnlinkable
55 }
56 if w.pkgpath == "" {
57 log.Fatal("empty package path")
58 }
59 if ctxt.IsAsm {
60 flags |= goobj.ObjFlagFromAssembly
61 }
62 if ctxt.Std {
63 flags |= goobj.ObjFlagStd
64 }
65 h := goobj.Header{
66 Magic: goobj.Magic,
67 Fingerprint: ctxt.Fingerprint,
68 Flags: flags,
69 }
70 h.Write(w.Writer)
71
72
73 w.StringTable()
74
75
76 h.Offsets[goobj.BlkAutolib] = w.Offset()
77 for i := range ctxt.Imports {
78 ctxt.Imports[i].Write(w.Writer)
79 }
80
81
82 h.Offsets[goobj.BlkPkgIdx] = w.Offset()
83 for _, pkg := range w.pkglist {
84 w.StringRef(pkg)
85 }
86
87
88 h.Offsets[goobj.BlkFile] = w.Offset()
89 for _, f := range ctxt.PosTable.FileTable() {
90 w.StringRef(filepath.ToSlash(f))
91 }
92
93
94 h.Offsets[goobj.BlkSymdef] = w.Offset()
95 for _, s := range ctxt.defs {
96 w.Sym(s)
97 }
98
99
100 h.Offsets[goobj.BlkHashed64def] = w.Offset()
101 for _, s := range ctxt.hashed64defs {
102 w.Sym(s)
103 }
104
105
106 h.Offsets[goobj.BlkHasheddef] = w.Offset()
107 for _, s := range ctxt.hasheddefs {
108 w.Sym(s)
109 }
110
111
112 h.Offsets[goobj.BlkNonpkgdef] = w.Offset()
113 for _, s := range ctxt.nonpkgdefs {
114 w.Sym(s)
115 }
116
117
118 h.Offsets[goobj.BlkNonpkgref] = w.Offset()
119 for _, s := range ctxt.nonpkgrefs {
120 w.Sym(s)
121 }
122
123
124 h.Offsets[goobj.BlkRefFlags] = w.Offset()
125 w.refFlags()
126
127
128 h.Offsets[goobj.BlkHash64] = w.Offset()
129 for _, s := range ctxt.hashed64defs {
130 w.Hash64(s)
131 }
132 h.Offsets[goobj.BlkHash] = w.Offset()
133 for _, s := range ctxt.hasheddefs {
134 w.Hash(s)
135 }
136
137
138
139 h.Offsets[goobj.BlkRelocIdx] = w.Offset()
140 nreloc := uint32(0)
141 lists := [][]*LSym{ctxt.defs, ctxt.hashed64defs, ctxt.hasheddefs, ctxt.nonpkgdefs}
142 for _, list := range lists {
143 for _, s := range list {
144 w.Uint32(nreloc)
145 nreloc += uint32(len(s.R))
146 }
147 }
148 w.Uint32(nreloc)
149
150
151 h.Offsets[goobj.BlkAuxIdx] = w.Offset()
152 naux := uint32(0)
153 for _, list := range lists {
154 for _, s := range list {
155 w.Uint32(naux)
156 naux += uint32(nAuxSym(s))
157 }
158 }
159 w.Uint32(naux)
160
161
162 h.Offsets[goobj.BlkDataIdx] = w.Offset()
163 dataOff := int64(0)
164 for _, list := range lists {
165 for _, s := range list {
166 w.Uint32(uint32(dataOff))
167 dataOff += int64(len(s.P))
168 if file := s.File(); file != nil {
169 dataOff += int64(file.Size)
170 }
171 }
172 }
173 if int64(uint32(dataOff)) != dataOff {
174 log.Fatalf("data too large")
175 }
176 w.Uint32(uint32(dataOff))
177
178
179 h.Offsets[goobj.BlkReloc] = w.Offset()
180 for _, list := range lists {
181 for _, s := range list {
182 slices.SortFunc(s.R, relocByOffCmp)
183 for i := range s.R {
184 w.Reloc(&s.R[i])
185 }
186 }
187 }
188
189
190 h.Offsets[goobj.BlkAux] = w.Offset()
191 for _, list := range lists {
192 for _, s := range list {
193 w.Aux(s)
194 }
195 }
196
197
198 h.Offsets[goobj.BlkData] = w.Offset()
199 for _, list := range lists {
200 for _, s := range list {
201 w.Bytes(s.P)
202 if file := s.File(); file != nil {
203 w.writeFile(ctxt, file)
204 }
205 }
206 }
207
208
209
210
211 h.Offsets[goobj.BlkRefName] = w.Offset()
212 w.refNames()
213
214 h.Offsets[goobj.BlkEnd] = w.Offset()
215
216
217 end := start + int64(w.Offset())
218 b.MustSeek(start, 0)
219 h.Write(w.Writer)
220 b.MustSeek(end, 0)
221 }
222
223 type writer struct {
224 *goobj.Writer
225 filebuf []byte
226 ctxt *Link
227 pkgpath string
228 pkglist []string
229
230
231
232 tmpSym goobj.Sym
233 tmpReloc goobj.Reloc
234 tmpAux goobj.Aux
235 tmpHash64 goobj.Hash64Type
236 tmpHash goobj.HashType
237 tmpRefFlags goobj.RefFlags
238 tmpRefName goobj.RefName
239 }
240
241
242 func (w *writer) init() {
243 w.pkglist = make([]string, len(w.ctxt.pkgIdx)+1)
244 w.pkglist[0] = ""
245 for pkg, i := range w.ctxt.pkgIdx {
246 w.pkglist[i] = pkg
247 }
248 }
249
250 func (w *writer) writeFile(ctxt *Link, file *FileInfo) {
251 f, err := os.Open(file.Name)
252 if err != nil {
253 ctxt.Diag("%v", err)
254 return
255 }
256 defer f.Close()
257 if w.filebuf == nil {
258 w.filebuf = make([]byte, 1024)
259 }
260 buf := w.filebuf
261 written := int64(0)
262 for {
263 n, err := f.Read(buf)
264 w.Bytes(buf[:n])
265 written += int64(n)
266 if err == io.EOF {
267 break
268 }
269 if err != nil {
270 ctxt.Diag("%v", err)
271 return
272 }
273 }
274 if written != file.Size {
275 ctxt.Diag("copy %s: unexpected length %d != %d", file.Name, written, file.Size)
276 }
277 }
278
279 func (w *writer) StringTable() {
280 w.AddString("")
281 for _, p := range w.ctxt.Imports {
282 w.AddString(p.Pkg)
283 }
284 for _, pkg := range w.pkglist {
285 w.AddString(pkg)
286 }
287 w.ctxt.traverseSyms(traverseAll, func(s *LSym) {
288
289
290 if s.PkgIdx == goobj.PkgIdxBuiltin {
291 return
292 }
293
294
295
296 if w.ctxt.Flag_noRefName && s.PkgIdx < goobj.PkgIdxSpecial {
297
298 return
299 }
300 if strings.HasPrefix(s.Name, `"".`) {
301 w.ctxt.Diag("unqualified symbol name: %v", s.Name)
302 }
303 w.AddString(s.Name)
304 })
305
306
307 for _, f := range w.ctxt.PosTable.FileTable() {
308 w.AddString(filepath.ToSlash(f))
309 }
310 }
311
312
313
314 const cutoff = int64(2e9)
315
316 func (w *writer) Sym(s *LSym) {
317 name := s.Name
318 abi := uint16(s.ABI())
319 if s.Static() {
320 abi = goobj.SymABIstatic
321 }
322 flag := uint8(0)
323 if s.DuplicateOK() {
324 flag |= goobj.SymFlagDupok
325 }
326 if s.Local() {
327 flag |= goobj.SymFlagLocal
328 }
329 if s.MakeTypelink() {
330 flag |= goobj.SymFlagTypelink
331 }
332 if s.Leaf() {
333 flag |= goobj.SymFlagLeaf
334 }
335 if s.NoSplit() {
336 flag |= goobj.SymFlagNoSplit
337 }
338 if s.ReflectMethod() {
339 flag |= goobj.SymFlagReflectMethod
340 }
341 if strings.HasPrefix(s.Name, "type:") && s.Name[5] != '.' && s.Type == objabi.SRODATA {
342 flag |= goobj.SymFlagGoType
343 }
344 flag2 := uint8(0)
345 if s.UsedInIface() {
346 flag2 |= goobj.SymFlagUsedInIface
347 }
348 if strings.HasPrefix(s.Name, "go:itab.") && s.Type == objabi.SRODATA {
349 flag2 |= goobj.SymFlagItab
350 }
351 if strings.HasPrefix(s.Name, w.ctxt.Pkgpath) && strings.HasPrefix(s.Name[len(w.ctxt.Pkgpath):], ".") && strings.HasPrefix(s.Name[len(w.ctxt.Pkgpath)+1:], objabi.GlobalDictPrefix) {
352 flag2 |= goobj.SymFlagDict
353 }
354 if s.IsPkgInit() {
355 flag2 |= goobj.SymFlagPkgInit
356 }
357 if s.IsLinkname() || (w.ctxt.IsAsm && name != "") || name == "main.main" {
358
359
360
361 flag2 |= goobj.SymFlagLinkname
362 }
363 if s.ABIWrapper() {
364 flag2 |= goobj.SymFlagABIWrapper
365 }
366 if s.Func() != nil && s.Func().WasmExport != nil {
367 flag2 |= goobj.SymFlagWasmExport
368 }
369 if strings.HasPrefix(name, "gofile..") {
370 name = filepath.ToSlash(name)
371 }
372 var align uint32
373 if fn := s.Func(); fn != nil {
374 align = uint32(fn.Align)
375 }
376 if s.ContentAddressable() && s.Size != 0 {
377
378
379
380
381
382
383
384 switch {
385 case strings.HasPrefix(s.Name, "go:string."),
386 strings.HasPrefix(name, "type:.namedata."),
387 strings.HasPrefix(name, "type:.importpath."),
388 strings.HasSuffix(name, ".opendefer"),
389 strings.HasSuffix(name, ".arginfo0"),
390 strings.HasSuffix(name, ".arginfo1"),
391 strings.HasSuffix(name, ".argliveinfo"):
392
393 align = 1
394 case strings.HasPrefix(name, "gclocals·"):
395
396 align = 4
397 default:
398 switch {
399 case w.ctxt.Arch.PtrSize == 8 && s.Size%8 == 0:
400 align = 8
401 case s.Size%4 == 0:
402 align = 4
403 case s.Size%2 == 0:
404 align = 2
405 default:
406 align = 1
407 }
408 }
409 }
410 if s.Size > cutoff {
411 w.ctxt.Diag("%s: symbol too large (%d bytes > %d bytes)", s.Name, s.Size, cutoff)
412 }
413 o := &w.tmpSym
414 o.SetName(name, w.Writer)
415 o.SetABI(abi)
416 o.SetType(uint8(s.Type))
417 o.SetFlag(flag)
418 o.SetFlag2(flag2)
419 o.SetSiz(uint32(s.Size))
420 o.SetAlign(align)
421 o.Write(w.Writer)
422 }
423
424 func (w *writer) Hash64(s *LSym) {
425 if !s.ContentAddressable() || len(s.R) != 0 {
426 panic("Hash of non-content-addressable symbol")
427 }
428 w.tmpHash64 = contentHash64(s)
429 w.Bytes(w.tmpHash64[:])
430 }
431
432 func (w *writer) Hash(s *LSym) {
433 if !s.ContentAddressable() {
434 panic("Hash of non-content-addressable symbol")
435 }
436 w.tmpHash = w.contentHash(s)
437 w.Bytes(w.tmpHash[:])
438 }
439
440
441
442
443
444
445
446
447
448 func contentHashSection(s *LSym) byte {
449 name := s.Name
450 if s.IsPcdata() {
451 return 'P'
452 }
453 if strings.HasPrefix(name, "gcargs.") ||
454 strings.HasPrefix(name, "gclocals.") ||
455 strings.HasPrefix(name, "gclocals·") ||
456 strings.HasSuffix(name, ".opendefer") ||
457 strings.HasSuffix(name, ".arginfo0") ||
458 strings.HasSuffix(name, ".arginfo1") ||
459 strings.HasSuffix(name, ".argliveinfo") ||
460 strings.HasSuffix(name, ".wrapinfo") ||
461 strings.HasSuffix(name, ".args_stackmap") ||
462 strings.HasSuffix(name, ".stkobj") {
463 return 'F'
464 }
465 if strings.HasPrefix(name, "type:") {
466 return 'T'
467 }
468 return 0
469 }
470
471 func contentHash64(s *LSym) goobj.Hash64Type {
472 if contentHashSection(s) != 0 {
473 panic("short hash of non-default-section sym " + s.Name)
474 }
475 var b goobj.Hash64Type
476 copy(b[:], s.P)
477 return b
478 }
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496 func (w *writer) contentHash(s *LSym) goobj.HashType {
497 h := hash.New20()
498 var tmp [14]byte
499
500
501
502
503
504
505
506
507
508 binary.LittleEndian.PutUint64(tmp[:8], uint64(s.Size))
509
510 tmp[8] = contentHashSection(s)
511 h.Write(tmp[:9])
512
513
514
515 h.Write(bytes.TrimRight(s.P, "\x00"))
516 for i := range s.R {
517 r := &s.R[i]
518 binary.LittleEndian.PutUint32(tmp[:4], uint32(r.Off))
519 tmp[4] = r.Siz
520 tmp[5] = uint8(r.Type)
521 binary.LittleEndian.PutUint64(tmp[6:14], uint64(r.Add))
522 h.Write(tmp[:])
523 rs := r.Sym
524 if rs == nil {
525 fmt.Printf("symbol: %s\n", s)
526 fmt.Printf("relocation: %#v\n", r)
527 panic("nil symbol target in relocation")
528 }
529 switch rs.PkgIdx {
530 case goobj.PkgIdxHashed64:
531 h.Write([]byte{0})
532 t := contentHash64(rs)
533 h.Write(t[:])
534 case goobj.PkgIdxHashed:
535 h.Write([]byte{1})
536 t := w.contentHash(rs)
537 h.Write(t[:])
538 case goobj.PkgIdxNone:
539 h.Write([]byte{2})
540 io.WriteString(h, rs.Name)
541 case goobj.PkgIdxBuiltin:
542 h.Write([]byte{3})
543 binary.LittleEndian.PutUint32(tmp[:4], uint32(rs.SymIdx))
544 h.Write(tmp[:4])
545 case goobj.PkgIdxSelf:
546 io.WriteString(h, w.pkgpath)
547 binary.LittleEndian.PutUint32(tmp[:4], uint32(rs.SymIdx))
548 h.Write(tmp[:4])
549 default:
550 io.WriteString(h, rs.Pkg)
551 binary.LittleEndian.PutUint32(tmp[:4], uint32(rs.SymIdx))
552 h.Write(tmp[:4])
553 }
554 }
555 var b goobj.HashType
556 copy(b[:], h.Sum(nil))
557 return b
558 }
559
560 func makeSymRef(s *LSym) goobj.SymRef {
561 if s == nil {
562 return goobj.SymRef{}
563 }
564 if s.PkgIdx == 0 || !s.Indexed() {
565 fmt.Printf("unindexed symbol reference: %v\n", s)
566 panic("unindexed symbol reference")
567 }
568 return goobj.SymRef{PkgIdx: uint32(s.PkgIdx), SymIdx: uint32(s.SymIdx)}
569 }
570
571 func (w *writer) Reloc(r *Reloc) {
572 o := &w.tmpReloc
573 o.SetOff(r.Off)
574 o.SetSiz(r.Siz)
575 o.SetType(uint16(r.Type))
576 o.SetAdd(r.Add)
577 o.SetSym(makeSymRef(r.Sym))
578 o.Write(w.Writer)
579 }
580
581 func (w *writer) aux1(typ uint8, rs *LSym) {
582 o := &w.tmpAux
583 o.SetType(typ)
584 o.SetSym(makeSymRef(rs))
585 o.Write(w.Writer)
586 }
587
588 func (w *writer) Aux(s *LSym) {
589 if s.Gotype != nil {
590 w.aux1(goobj.AuxGotype, s.Gotype)
591 }
592 if fn := s.Func(); fn != nil {
593 w.aux1(goobj.AuxFuncInfo, fn.FuncInfoSym)
594
595 for _, d := range fn.Pcln.Funcdata {
596 w.aux1(goobj.AuxFuncdata, d)
597 }
598
599 if fn.dwarfInfoSym != nil && fn.dwarfInfoSym.Size != 0 {
600 w.aux1(goobj.AuxDwarfInfo, fn.dwarfInfoSym)
601 }
602 if fn.dwarfLocSym != nil && fn.dwarfLocSym.Size != 0 {
603 w.aux1(goobj.AuxDwarfLoc, fn.dwarfLocSym)
604 }
605 if fn.dwarfRangesSym != nil && fn.dwarfRangesSym.Size != 0 {
606 w.aux1(goobj.AuxDwarfRanges, fn.dwarfRangesSym)
607 }
608 if fn.dwarfDebugLinesSym != nil && fn.dwarfDebugLinesSym.Size != 0 {
609 w.aux1(goobj.AuxDwarfLines, fn.dwarfDebugLinesSym)
610 }
611 if fn.Pcln.Pcsp != nil && fn.Pcln.Pcsp.Size != 0 {
612 w.aux1(goobj.AuxPcsp, fn.Pcln.Pcsp)
613 }
614 if fn.Pcln.Pcfile != nil && fn.Pcln.Pcfile.Size != 0 {
615 w.aux1(goobj.AuxPcfile, fn.Pcln.Pcfile)
616 }
617 if fn.Pcln.Pcline != nil && fn.Pcln.Pcline.Size != 0 {
618 w.aux1(goobj.AuxPcline, fn.Pcln.Pcline)
619 }
620 if fn.Pcln.Pcinline != nil && fn.Pcln.Pcinline.Size != 0 {
621 w.aux1(goobj.AuxPcinline, fn.Pcln.Pcinline)
622 }
623 if fn.sehUnwindInfoSym != nil && fn.sehUnwindInfoSym.Size != 0 {
624 w.aux1(goobj.AuxSehUnwindInfo, fn.sehUnwindInfoSym)
625 }
626 for _, pcSym := range fn.Pcln.Pcdata {
627 w.aux1(goobj.AuxPcdata, pcSym)
628 }
629 if fn.WasmImport != nil {
630 if fn.WasmImport.AuxSym.Size == 0 {
631 panic("wasmimport aux sym must have non-zero size")
632 }
633 w.aux1(goobj.AuxWasmImport, fn.WasmImport.AuxSym)
634 }
635 if fn.WasmExport != nil {
636 w.aux1(goobj.AuxWasmType, fn.WasmExport.AuxSym)
637 }
638 } else if v := s.VarInfo(); v != nil {
639 if v.dwarfInfoSym != nil && v.dwarfInfoSym.Size != 0 {
640 w.aux1(goobj.AuxDwarfInfo, v.dwarfInfoSym)
641 }
642 }
643 }
644
645
646 func (w *writer) refFlags() {
647 seen := make(map[*LSym]bool)
648 w.ctxt.traverseSyms(traverseRefs, func(rs *LSym) {
649 switch rs.PkgIdx {
650 case goobj.PkgIdxNone, goobj.PkgIdxHashed64, goobj.PkgIdxHashed, goobj.PkgIdxBuiltin, goobj.PkgIdxSelf:
651 return
652 case goobj.PkgIdxInvalid:
653 panic("unindexed symbol reference")
654 }
655 if seen[rs] {
656 return
657 }
658 seen[rs] = true
659 symref := makeSymRef(rs)
660 flag2 := uint8(0)
661 if rs.UsedInIface() {
662 flag2 |= goobj.SymFlagUsedInIface
663 }
664 if flag2 == 0 {
665 return
666 }
667 o := &w.tmpRefFlags
668 o.SetSym(symref)
669 o.SetFlag2(flag2)
670 o.Write(w.Writer)
671 })
672 }
673
674
675
676 func (w *writer) refNames() {
677 if w.ctxt.Flag_noRefName {
678 return
679 }
680 seen := make(map[*LSym]bool)
681 w.ctxt.traverseSyms(traverseRefs, func(rs *LSym) {
682 switch rs.PkgIdx {
683 case goobj.PkgIdxNone, goobj.PkgIdxHashed64, goobj.PkgIdxHashed, goobj.PkgIdxBuiltin, goobj.PkgIdxSelf:
684 return
685 case goobj.PkgIdxInvalid:
686 panic("unindexed symbol reference")
687 }
688 if seen[rs] {
689 return
690 }
691 seen[rs] = true
692 symref := makeSymRef(rs)
693 o := &w.tmpRefName
694 o.SetSym(symref)
695 o.SetName(rs.Name, w.Writer)
696 o.Write(w.Writer)
697 })
698
699
700
701
702
703 }
704
705
706 func nAuxSym(s *LSym) int {
707 n := 0
708 if s.Gotype != nil {
709 n++
710 }
711 if fn := s.Func(); fn != nil {
712
713 n += 1 + len(fn.Pcln.Funcdata)
714 if fn.dwarfInfoSym != nil && fn.dwarfInfoSym.Size != 0 {
715 n++
716 }
717 if fn.dwarfLocSym != nil && fn.dwarfLocSym.Size != 0 {
718 n++
719 }
720 if fn.dwarfRangesSym != nil && fn.dwarfRangesSym.Size != 0 {
721 n++
722 }
723 if fn.dwarfDebugLinesSym != nil && fn.dwarfDebugLinesSym.Size != 0 {
724 n++
725 }
726 if fn.Pcln.Pcsp != nil && fn.Pcln.Pcsp.Size != 0 {
727 n++
728 }
729 if fn.Pcln.Pcfile != nil && fn.Pcln.Pcfile.Size != 0 {
730 n++
731 }
732 if fn.Pcln.Pcline != nil && fn.Pcln.Pcline.Size != 0 {
733 n++
734 }
735 if fn.Pcln.Pcinline != nil && fn.Pcln.Pcinline.Size != 0 {
736 n++
737 }
738 if fn.sehUnwindInfoSym != nil && fn.sehUnwindInfoSym.Size != 0 {
739 n++
740 }
741 n += len(fn.Pcln.Pcdata)
742 if fn.WasmImport != nil {
743 if fn.WasmImport.AuxSym == nil || fn.WasmImport.AuxSym.Size == 0 {
744 panic("wasmimport aux sym must exist and have non-zero size")
745 }
746 n++
747 }
748 if fn.WasmExport != nil {
749 n++
750 }
751 } else if v := s.VarInfo(); v != nil {
752 if v.dwarfInfoSym != nil && v.dwarfInfoSym.Size != 0 {
753 n++
754 }
755 }
756 return n
757 }
758
759
760 func genFuncInfoSyms(ctxt *Link) {
761 infosyms := make([]*LSym, 0, len(ctxt.Text))
762 var b bytes.Buffer
763 symidx := int32(len(ctxt.defs))
764 for _, s := range ctxt.Text {
765 fn := s.Func()
766 if fn == nil {
767 continue
768 }
769 o := goobj.FuncInfo{
770 Args: uint32(fn.Args),
771 Locals: uint32(fn.Locals),
772 FuncID: fn.FuncID,
773 FuncFlag: fn.FuncFlag,
774 StartLine: fn.StartLine,
775 }
776 pc := &fn.Pcln
777 i := 0
778 o.File = make([]goobj.CUFileIndex, len(pc.UsedFiles))
779 for f := range pc.UsedFiles {
780 o.File[i] = f
781 i++
782 }
783 sort.Slice(o.File, func(i, j int) bool { return o.File[i] < o.File[j] })
784 o.InlTree = make([]goobj.InlTreeNode, len(pc.InlTree.nodes))
785 for i, inl := range pc.InlTree.nodes {
786 f, l := ctxt.getFileIndexAndLine(inl.Pos)
787 o.InlTree[i] = goobj.InlTreeNode{
788 Parent: int32(inl.Parent),
789 File: goobj.CUFileIndex(f),
790 Line: l,
791 Func: makeSymRef(inl.Func),
792 ParentPC: inl.ParentPC,
793 }
794 }
795
796 o.Write(&b)
797 p := b.Bytes()
798 isym := &LSym{
799 Type: objabi.SDATA,
800 PkgIdx: goobj.PkgIdxSelf,
801 SymIdx: symidx,
802 P: append([]byte(nil), p...),
803 Size: int64(len(p)),
804 }
805 isym.Set(AttrIndexed, true)
806 symidx++
807 infosyms = append(infosyms, isym)
808 fn.FuncInfoSym = isym
809 b.Reset()
810
811 auxsyms := []*LSym{fn.dwarfRangesSym, fn.dwarfLocSym, fn.dwarfDebugLinesSym, fn.dwarfInfoSym}
812 if wi := fn.WasmImport; wi != nil {
813 auxsyms = append(auxsyms, wi.AuxSym)
814 }
815 if we := fn.WasmExport; we != nil {
816 auxsyms = append(auxsyms, we.AuxSym)
817 }
818 for _, s := range auxsyms {
819 if s == nil || s.Size == 0 {
820 continue
821 }
822 if s.OnList() {
823 panic("a symbol is added to defs multiple times")
824 }
825 s.PkgIdx = goobj.PkgIdxSelf
826 s.SymIdx = symidx
827 s.Set(AttrIndexed, true)
828 s.Set(AttrOnList, true)
829 symidx++
830 infosyms = append(infosyms, s)
831 }
832 }
833 ctxt.defs = append(ctxt.defs, infosyms...)
834 }
835
836 func writeAuxSymDebug(ctxt *Link, par *LSym, aux *LSym) {
837
838
839 switch aux.Type {
840 case objabi.SDWARFLOC,
841 objabi.SDWARFFCN,
842 objabi.SDWARFABSFCN,
843 objabi.SDWARFLINES,
844 objabi.SDWARFRANGE,
845 objabi.SDWARFVAR:
846 default:
847 return
848 }
849 ctxt.writeSymDebugNamed(aux, "aux for "+par.Name)
850 }
851
852 func debugAsmEmit(ctxt *Link) {
853 if ctxt.Debugasm > 0 {
854 ctxt.traverseSyms(traverseDefs, ctxt.writeSymDebug)
855 if ctxt.Debugasm > 1 {
856 fn := func(par *LSym, aux *LSym) {
857 writeAuxSymDebug(ctxt, par, aux)
858 }
859 ctxt.traverseAuxSyms(traverseAux, fn)
860 }
861 }
862 }
863
864 func (ctxt *Link) writeSymDebug(s *LSym) {
865 ctxt.writeSymDebugNamed(s, s.Name)
866 }
867
868 func (ctxt *Link) writeSymDebugNamed(s *LSym, name string) {
869 ver := ""
870 if ctxt.Debugasm > 1 {
871 ver = fmt.Sprintf("<%d>", s.ABI())
872 if ctxt.Debugasm > 2 {
873 ver += fmt.Sprintf("<idx %d %d>", s.PkgIdx, s.SymIdx)
874 }
875 }
876 fmt.Fprintf(ctxt.Bso, "%s%s ", name, ver)
877 if s.Type != 0 {
878 fmt.Fprintf(ctxt.Bso, "%v ", s.Type)
879 }
880 if s.Static() {
881 fmt.Fprint(ctxt.Bso, "static ")
882 }
883 if s.DuplicateOK() {
884 fmt.Fprintf(ctxt.Bso, "dupok ")
885 }
886 if s.CFunc() {
887 fmt.Fprintf(ctxt.Bso, "cfunc ")
888 }
889 if s.NoSplit() {
890 fmt.Fprintf(ctxt.Bso, "nosplit ")
891 }
892 if s.Func() != nil && s.Func().FuncFlag&abi.FuncFlagTopFrame != 0 {
893 fmt.Fprintf(ctxt.Bso, "topframe ")
894 }
895 if s.Func() != nil && s.Func().FuncFlag&abi.FuncFlagAsm != 0 {
896 fmt.Fprintf(ctxt.Bso, "asm ")
897 }
898 fmt.Fprintf(ctxt.Bso, "size=%d", s.Size)
899 if s.Type.IsText() {
900 fn := s.Func()
901 fmt.Fprintf(ctxt.Bso, " args=%#x locals=%#x funcid=%#x align=%#x", uint64(fn.Args), uint64(fn.Locals), uint64(fn.FuncID), uint64(fn.Align))
902 if s.Leaf() {
903 fmt.Fprintf(ctxt.Bso, " leaf")
904 }
905 }
906 fmt.Fprintf(ctxt.Bso, "\n")
907 if s.Type.IsText() {
908 for p := s.Func().Text; p != nil; p = p.Link {
909 fmt.Fprintf(ctxt.Bso, "\t%#04x ", uint(int(p.Pc)))
910 if ctxt.Debugasm > 1 {
911 io.WriteString(ctxt.Bso, p.String())
912 } else {
913 p.InnermostString(ctxt.Bso)
914 }
915 fmt.Fprintln(ctxt.Bso)
916 }
917 }
918 for i := 0; i < len(s.P); i += 16 {
919 fmt.Fprintf(ctxt.Bso, "\t%#04x", uint(i))
920 j := i
921 for ; j < i+16 && j < len(s.P); j++ {
922 fmt.Fprintf(ctxt.Bso, " %02x", s.P[j])
923 }
924 for ; j < i+16; j++ {
925 fmt.Fprintf(ctxt.Bso, " ")
926 }
927 fmt.Fprintf(ctxt.Bso, " ")
928 for j = i; j < i+16 && j < len(s.P); j++ {
929 c := int(s.P[j])
930 b := byte('.')
931 if ' ' <= c && c <= 0x7e {
932 b = byte(c)
933 }
934 ctxt.Bso.WriteByte(b)
935 }
936
937 fmt.Fprintf(ctxt.Bso, "\n")
938 }
939
940 slices.SortFunc(s.R, relocByOffCmp)
941 for _, r := range s.R {
942 name := ""
943 ver := ""
944 if r.Sym != nil {
945 name = r.Sym.Name
946 if ctxt.Debugasm > 1 {
947 ver = fmt.Sprintf("<%d>", r.Sym.ABI())
948 }
949 } else if r.Type == objabi.R_TLS_LE {
950 name = "TLS"
951 }
952 if ctxt.Arch.InFamily(sys.ARM, sys.PPC64) {
953 fmt.Fprintf(ctxt.Bso, "\trel %d+%d t=%v %s%s+%x\n", int(r.Off), r.Siz, r.Type, name, ver, uint64(r.Add))
954 } else {
955 fmt.Fprintf(ctxt.Bso, "\trel %d+%d t=%v %s%s+%d\n", int(r.Off), r.Siz, r.Type, name, ver, r.Add)
956 }
957 }
958 }
959
960
961 func relocByOffCmp(x, y Reloc) int {
962 return cmp.Compare(x.Off, y.Off)
963 }
964
View as plain text