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 += 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.IsLinknameStd() {
364 flag2 |= goobj.SymFlagLinknameStd
365 }
366 if s.ABIWrapper() {
367 flag2 |= goobj.SymFlagABIWrapper
368 }
369 if s.Func() != nil && s.Func().WasmExport != nil {
370 flag2 |= goobj.SymFlagWasmExport
371 }
372 if strings.HasPrefix(name, "gofile..") {
373 name = filepath.ToSlash(name)
374 }
375 align := uint32(s.Align)
376 if s.ContentAddressable() && s.Size != 0 && align == 0 {
377
378 w.ctxt.Diag("%s: is content-addressable but alignment is not set (size is %d)", s.Name, s.Size)
379 }
380 if s.Size > cutoff {
381 w.ctxt.Diag("%s: symbol too large (%d bytes > %d bytes)", s.Name, s.Size, cutoff)
382 }
383 o := &w.tmpSym
384 o.SetName(name, w.Writer)
385 o.SetABI(abi)
386 o.SetType(uint8(s.Type))
387 o.SetFlag(flag)
388 o.SetFlag2(flag2)
389 o.SetSiz(uint32(s.Size))
390 o.SetAlign(align)
391 o.Write(w.Writer)
392 }
393
394 func (w *writer) Hash64(s *LSym) {
395 if !s.ContentAddressable() || len(s.R) != 0 {
396 panic("Hash of non-content-addressable symbol")
397 }
398 w.tmpHash64 = contentHash64(s)
399 w.Bytes(w.tmpHash64[:])
400 }
401
402 func (w *writer) Hash(s *LSym) {
403 if !s.ContentAddressable() {
404 panic("Hash of non-content-addressable symbol")
405 }
406 w.tmpHash = w.contentHash(s)
407 w.Bytes(w.tmpHash[:])
408 }
409
410
411
412
413
414
415
416
417
418 func contentHashSection(s *LSym) byte {
419 name := s.Name
420 if s.IsPcdata() {
421 return 'P'
422 }
423 if strings.HasPrefix(name, "gcargs.") ||
424 strings.HasPrefix(name, "gclocals.") ||
425 strings.HasPrefix(name, "gclocals·") ||
426 strings.HasSuffix(name, ".opendefer") ||
427 strings.HasSuffix(name, ".arginfo0") ||
428 strings.HasSuffix(name, ".arginfo1") ||
429 strings.HasSuffix(name, ".argliveinfo") ||
430 strings.HasSuffix(name, ".wrapinfo") ||
431 strings.HasSuffix(name, ".args_stackmap") ||
432 strings.HasSuffix(name, ".stkobj") {
433 return 'F'
434 }
435 if strings.HasPrefix(name, "type:") {
436 return 'T'
437 }
438 return 0
439 }
440
441 func contentHash64(s *LSym) goobj.Hash64Type {
442 if contentHashSection(s) != 0 {
443 panic("short hash of non-default-section sym " + s.Name)
444 }
445 var b goobj.Hash64Type
446 copy(b[:], s.P)
447 return b
448 }
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466 func (w *writer) contentHash(s *LSym) goobj.HashType {
467 h := hash.New32()
468 var tmp [14]byte
469
470
471
472
473
474
475
476
477
478 binary.LittleEndian.PutUint64(tmp[:8], uint64(s.Size))
479
480 tmp[8] = contentHashSection(s)
481 h.Write(tmp[:9])
482
483
484
485 h.Write(bytes.TrimRight(s.P, "\x00"))
486 for i := range s.R {
487 r := &s.R[i]
488 binary.LittleEndian.PutUint32(tmp[:4], uint32(r.Off))
489 tmp[4] = r.Siz
490 tmp[5] = uint8(r.Type)
491 binary.LittleEndian.PutUint64(tmp[6:14], uint64(r.Add))
492 h.Write(tmp[:])
493 rs := r.Sym
494 if rs == nil {
495 fmt.Printf("symbol: %s\n", s)
496 fmt.Printf("relocation: %#v\n", r)
497 panic("nil symbol target in relocation")
498 }
499 switch rs.PkgIdx {
500 case goobj.PkgIdxHashed64:
501 h.Write([]byte{0})
502 t := contentHash64(rs)
503 h.Write(t[:])
504 case goobj.PkgIdxHashed:
505 h.Write([]byte{1})
506 t := w.contentHash(rs)
507 h.Write(t[:])
508 case goobj.PkgIdxNone:
509 h.Write([]byte{2})
510 io.WriteString(h, rs.Name)
511 case goobj.PkgIdxBuiltin:
512 h.Write([]byte{3})
513 binary.LittleEndian.PutUint32(tmp[:4], uint32(rs.SymIdx))
514 h.Write(tmp[:4])
515 case goobj.PkgIdxSelf:
516 io.WriteString(h, w.pkgpath)
517 binary.LittleEndian.PutUint32(tmp[:4], uint32(rs.SymIdx))
518 h.Write(tmp[:4])
519 default:
520 io.WriteString(h, rs.Pkg)
521 binary.LittleEndian.PutUint32(tmp[:4], uint32(rs.SymIdx))
522 h.Write(tmp[:4])
523 }
524 }
525 var b goobj.HashType
526 copy(b[:], h.Sum(nil))
527 return b
528 }
529
530 func makeSymRef(s *LSym) goobj.SymRef {
531 if s == nil {
532 return goobj.SymRef{}
533 }
534 if s.PkgIdx == 0 || !s.Indexed() {
535 fmt.Printf("unindexed symbol reference: %v\n", s)
536 panic("unindexed symbol reference")
537 }
538 return goobj.SymRef{PkgIdx: uint32(s.PkgIdx), SymIdx: uint32(s.SymIdx)}
539 }
540
541 func (w *writer) Reloc(r *Reloc) {
542 o := &w.tmpReloc
543 o.SetOff(r.Off)
544 o.SetSiz(r.Siz)
545 o.SetType(uint16(r.Type))
546 o.SetAdd(r.Add)
547 o.SetSym(makeSymRef(r.Sym))
548 o.Write(w.Writer)
549 }
550
551 func (w *writer) aux1(typ uint8, rs *LSym) {
552 o := &w.tmpAux
553 o.SetType(typ)
554 o.SetSym(makeSymRef(rs))
555 o.Write(w.Writer)
556 }
557
558 func (w *writer) Aux(s *LSym) {
559 if s.Gotype != nil {
560 w.aux1(goobj.AuxGotype, s.Gotype)
561 }
562 if fn := s.Func(); fn != nil {
563 w.aux1(goobj.AuxFuncInfo, fn.FuncInfoSym)
564
565 for _, d := range fn.Pcln.Funcdata {
566 w.aux1(goobj.AuxFuncdata, d)
567 }
568
569 if fn.dwarfInfoSym != nil && fn.dwarfInfoSym.Size != 0 {
570 w.aux1(goobj.AuxDwarfInfo, fn.dwarfInfoSym)
571 }
572 if fn.dwarfLocSym != nil && fn.dwarfLocSym.Size != 0 {
573 w.aux1(goobj.AuxDwarfLoc, fn.dwarfLocSym)
574 }
575 if fn.dwarfRangesSym != nil && fn.dwarfRangesSym.Size != 0 {
576 w.aux1(goobj.AuxDwarfRanges, fn.dwarfRangesSym)
577 }
578 if fn.dwarfDebugLinesSym != nil && fn.dwarfDebugLinesSym.Size != 0 {
579 w.aux1(goobj.AuxDwarfLines, fn.dwarfDebugLinesSym)
580 }
581 if fn.Pcln.Pcsp != nil && fn.Pcln.Pcsp.Size != 0 {
582 w.aux1(goobj.AuxPcsp, fn.Pcln.Pcsp)
583 }
584 if fn.Pcln.Pcfile != nil && fn.Pcln.Pcfile.Size != 0 {
585 w.aux1(goobj.AuxPcfile, fn.Pcln.Pcfile)
586 }
587 if fn.Pcln.Pcline != nil && fn.Pcln.Pcline.Size != 0 {
588 w.aux1(goobj.AuxPcline, fn.Pcln.Pcline)
589 }
590 if fn.Pcln.Pcinline != nil && fn.Pcln.Pcinline.Size != 0 {
591 w.aux1(goobj.AuxPcinline, fn.Pcln.Pcinline)
592 }
593 if fn.sehUnwindInfoSym != nil && fn.sehUnwindInfoSym.Size != 0 {
594 w.aux1(goobj.AuxSehUnwindInfo, fn.sehUnwindInfoSym)
595 }
596 for _, pcSym := range fn.Pcln.Pcdata {
597 w.aux1(goobj.AuxPcdata, pcSym)
598 }
599 if fn.WasmImport != nil {
600 if fn.WasmImport.AuxSym.Size == 0 {
601 panic("wasmimport aux sym must have non-zero size")
602 }
603 w.aux1(goobj.AuxWasmImport, fn.WasmImport.AuxSym)
604 }
605 if fn.WasmExport != nil {
606 w.aux1(goobj.AuxWasmType, fn.WasmExport.AuxSym)
607 }
608 } else if v := s.VarInfo(); v != nil {
609 if v.dwarfInfoSym != nil && v.dwarfInfoSym.Size != 0 {
610 w.aux1(goobj.AuxDwarfInfo, v.dwarfInfoSym)
611 }
612 }
613 }
614
615
616 func (w *writer) refFlags() {
617 seen := make(map[*LSym]bool)
618 w.ctxt.traverseSyms(traverseRefs, func(rs *LSym) {
619 switch rs.PkgIdx {
620 case goobj.PkgIdxNone, goobj.PkgIdxHashed64, goobj.PkgIdxHashed, goobj.PkgIdxBuiltin, goobj.PkgIdxSelf:
621 return
622 case goobj.PkgIdxInvalid:
623 panic("unindexed symbol reference")
624 }
625 if seen[rs] {
626 return
627 }
628 seen[rs] = true
629 symref := makeSymRef(rs)
630 flag2 := uint8(0)
631 if rs.UsedInIface() {
632 flag2 |= goobj.SymFlagUsedInIface
633 }
634 if flag2 == 0 {
635 return
636 }
637 o := &w.tmpRefFlags
638 o.SetSym(symref)
639 o.SetFlag2(flag2)
640 o.Write(w.Writer)
641 })
642 }
643
644
645
646 func (w *writer) refNames() {
647 if w.ctxt.Flag_noRefName {
648 return
649 }
650 seen := make(map[*LSym]bool)
651 w.ctxt.traverseSyms(traverseRefs, func(rs *LSym) {
652 switch rs.PkgIdx {
653 case goobj.PkgIdxNone, goobj.PkgIdxHashed64, goobj.PkgIdxHashed, goobj.PkgIdxBuiltin, goobj.PkgIdxSelf:
654 return
655 case goobj.PkgIdxInvalid:
656 panic("unindexed symbol reference")
657 }
658 if seen[rs] {
659 return
660 }
661 seen[rs] = true
662 symref := makeSymRef(rs)
663 o := &w.tmpRefName
664 o.SetSym(symref)
665 o.SetName(rs.Name, w.Writer)
666 o.Write(w.Writer)
667 })
668
669
670
671
672
673 }
674
675
676 func nAuxSym(s *LSym) int {
677 n := 0
678 if s.Gotype != nil {
679 n++
680 }
681 if fn := s.Func(); fn != nil {
682
683 n += 1 + len(fn.Pcln.Funcdata)
684 if fn.dwarfInfoSym != nil && fn.dwarfInfoSym.Size != 0 {
685 n++
686 }
687 if fn.dwarfLocSym != nil && fn.dwarfLocSym.Size != 0 {
688 n++
689 }
690 if fn.dwarfRangesSym != nil && fn.dwarfRangesSym.Size != 0 {
691 n++
692 }
693 if fn.dwarfDebugLinesSym != nil && fn.dwarfDebugLinesSym.Size != 0 {
694 n++
695 }
696 if fn.Pcln.Pcsp != nil && fn.Pcln.Pcsp.Size != 0 {
697 n++
698 }
699 if fn.Pcln.Pcfile != nil && fn.Pcln.Pcfile.Size != 0 {
700 n++
701 }
702 if fn.Pcln.Pcline != nil && fn.Pcln.Pcline.Size != 0 {
703 n++
704 }
705 if fn.Pcln.Pcinline != nil && fn.Pcln.Pcinline.Size != 0 {
706 n++
707 }
708 if fn.sehUnwindInfoSym != nil && fn.sehUnwindInfoSym.Size != 0 {
709 n++
710 }
711 n += len(fn.Pcln.Pcdata)
712 if fn.WasmImport != nil {
713 if fn.WasmImport.AuxSym == nil || fn.WasmImport.AuxSym.Size == 0 {
714 panic("wasmimport aux sym must exist and have non-zero size")
715 }
716 n++
717 }
718 if fn.WasmExport != nil {
719 n++
720 }
721 } else if v := s.VarInfo(); v != nil {
722 if v.dwarfInfoSym != nil && v.dwarfInfoSym.Size != 0 {
723 n++
724 }
725 }
726 return n
727 }
728
729
730 func genFuncInfoSyms(ctxt *Link) {
731 infosyms := make([]*LSym, 0, len(ctxt.Text))
732 var b bytes.Buffer
733 symidx := int32(len(ctxt.defs))
734 for _, s := range ctxt.Text {
735 fn := s.Func()
736 if fn == nil {
737 continue
738 }
739 o := goobj.FuncInfo{
740 Args: uint32(fn.Args),
741 Locals: uint32(fn.Locals),
742 FuncID: fn.FuncID,
743 FuncFlag: fn.FuncFlag,
744 StartLine: fn.StartLine,
745 }
746 pc := &fn.Pcln
747 i := 0
748 o.File = make([]goobj.CUFileIndex, len(pc.UsedFiles))
749 for f := range pc.UsedFiles {
750 o.File[i] = f
751 i++
752 }
753 sort.Slice(o.File, func(i, j int) bool { return o.File[i] < o.File[j] })
754 o.InlTree = make([]goobj.InlTreeNode, len(pc.InlTree.nodes))
755 for i, inl := range pc.InlTree.nodes {
756 f, l := ctxt.getFileIndexAndLine(inl.Pos)
757 o.InlTree[i] = goobj.InlTreeNode{
758 Parent: int32(inl.Parent),
759 File: goobj.CUFileIndex(f),
760 Line: l,
761 Func: makeSymRef(inl.Func),
762 ParentPC: inl.ParentPC,
763 }
764 }
765
766 o.Write(&b)
767 p := b.Bytes()
768 isym := &LSym{
769 Type: objabi.SDATA,
770 PkgIdx: goobj.PkgIdxSelf,
771 SymIdx: symidx,
772 P: append([]byte(nil), p...),
773 Size: int64(len(p)),
774 }
775 isym.Set(AttrIndexed, true)
776 symidx++
777 infosyms = append(infosyms, isym)
778 fn.FuncInfoSym = isym
779 b.Reset()
780
781 auxsyms := []*LSym{fn.dwarfRangesSym, fn.dwarfLocSym, fn.dwarfDebugLinesSym, fn.dwarfInfoSym}
782 if wi := fn.WasmImport; wi != nil {
783 auxsyms = append(auxsyms, wi.AuxSym)
784 }
785 if we := fn.WasmExport; we != nil {
786 auxsyms = append(auxsyms, we.AuxSym)
787 }
788 for _, s := range auxsyms {
789 if s == nil || s.Size == 0 {
790 continue
791 }
792 if s.OnList() {
793 panic("a symbol is added to defs multiple times")
794 }
795 s.PkgIdx = goobj.PkgIdxSelf
796 s.SymIdx = symidx
797 s.Set(AttrIndexed, true)
798 s.Set(AttrOnList, true)
799 symidx++
800 infosyms = append(infosyms, s)
801 }
802 }
803 ctxt.defs = append(ctxt.defs, infosyms...)
804 }
805
806 func writeAuxSymDebug(ctxt *Link, par *LSym, aux *LSym) {
807
808
809 switch aux.Type {
810 case objabi.SDWARFLOC,
811 objabi.SDWARFFCN,
812 objabi.SDWARFABSFCN,
813 objabi.SDWARFLINES,
814 objabi.SDWARFRANGE,
815 objabi.SDWARFVAR:
816 default:
817 return
818 }
819 ctxt.writeSymDebugNamed(aux, "aux for "+par.Name)
820 }
821
822 func debugAsmEmit(ctxt *Link) {
823 if ctxt.Debugasm > 0 {
824 ctxt.traverseSyms(traverseDefs, ctxt.writeSymDebug)
825 if ctxt.Debugasm > 1 {
826 fn := func(par *LSym, aux *LSym) {
827 writeAuxSymDebug(ctxt, par, aux)
828 }
829 ctxt.traverseAuxSyms(traverseAux, fn)
830 }
831 }
832 }
833
834 func (ctxt *Link) writeSymDebug(s *LSym) {
835 ctxt.writeSymDebugNamed(s, s.Name)
836 }
837
838 func (ctxt *Link) writeSymDebugNamed(s *LSym, name string) {
839 ver := ""
840 if ctxt.Debugasm > 1 {
841 ver = fmt.Sprintf("<%d>", s.ABI())
842 if ctxt.Debugasm > 2 {
843 ver += fmt.Sprintf("<idx %d %d>", s.PkgIdx, s.SymIdx)
844 }
845 }
846 fmt.Fprintf(ctxt.Bso, "%s%s ", name, ver)
847 if s.Type != 0 {
848 fmt.Fprintf(ctxt.Bso, "%v ", s.Type)
849 }
850 if s.Static() {
851 fmt.Fprint(ctxt.Bso, "static ")
852 }
853 if s.DuplicateOK() {
854 fmt.Fprintf(ctxt.Bso, "dupok ")
855 }
856 if s.CFunc() {
857 fmt.Fprintf(ctxt.Bso, "cfunc ")
858 }
859 if s.NoSplit() {
860 fmt.Fprintf(ctxt.Bso, "nosplit ")
861 }
862 if s.Func() != nil && s.Func().FuncFlag&abi.FuncFlagTopFrame != 0 {
863 fmt.Fprintf(ctxt.Bso, "topframe ")
864 }
865 if s.Func() != nil && s.Func().FuncFlag&abi.FuncFlagAsm != 0 {
866 fmt.Fprintf(ctxt.Bso, "asm ")
867 }
868 fmt.Fprintf(ctxt.Bso, "size=%d align=%#x", s.Size, s.Align)
869 if s.Type.IsText() {
870 fn := s.Func()
871 fmt.Fprintf(ctxt.Bso, " args=%#x locals=%#x funcid=%#x", uint64(fn.Args), uint64(fn.Locals), uint64(fn.FuncID))
872 if s.Leaf() {
873 fmt.Fprintf(ctxt.Bso, " leaf")
874 }
875 }
876 fmt.Fprintf(ctxt.Bso, "\n")
877 if s.Type.IsText() {
878 for p := s.Func().Text; p != nil; p = p.Link {
879 fmt.Fprintf(ctxt.Bso, "\t%#04x ", uint(int(p.Pc)))
880 if ctxt.Debugasm > 1 {
881 io.WriteString(ctxt.Bso, p.String())
882 } else {
883 p.InnermostString(ctxt.Bso)
884 }
885 fmt.Fprintln(ctxt.Bso)
886 }
887 }
888 for i := 0; i < len(s.P); i += 16 {
889 fmt.Fprintf(ctxt.Bso, "\t%#04x", uint(i))
890 j := i
891 for ; j < i+16 && j < len(s.P); j++ {
892 fmt.Fprintf(ctxt.Bso, " %02x", s.P[j])
893 }
894 for ; j < i+16; j++ {
895 fmt.Fprintf(ctxt.Bso, " ")
896 }
897 fmt.Fprintf(ctxt.Bso, " ")
898 for j = i; j < i+16 && j < len(s.P); j++ {
899 c := int(s.P[j])
900 b := byte('.')
901 if ' ' <= c && c <= 0x7e {
902 b = byte(c)
903 }
904 ctxt.Bso.WriteByte(b)
905 }
906
907 fmt.Fprintf(ctxt.Bso, "\n")
908 }
909
910 slices.SortFunc(s.R, relocByOffCmp)
911 for _, r := range s.R {
912 name := ""
913 ver := ""
914 if r.Sym != nil {
915 name = r.Sym.Name
916 if ctxt.Debugasm > 1 {
917 ver = fmt.Sprintf("<%d>", r.Sym.ABI())
918 }
919 } else if r.Type == objabi.R_TLS_LE {
920 name = "TLS"
921 }
922 if ctxt.Arch.InFamily(sys.ARM, sys.PPC64) {
923 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))
924 } else {
925 fmt.Fprintf(ctxt.Bso, "\trel %d+%d t=%v %s%s+%d\n", int(r.Off), r.Siz, r.Type, name, ver, r.Add)
926 }
927 }
928 }
929
930
931 func relocByOffCmp(x, y Reloc) int {
932 return cmp.Compare(x.Off, y.Off)
933 }
934
View as plain text