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