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