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