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