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 strings.HasPrefix(s.Name, "type.") && s.Name[5] != '.' && s.Type == objabi.SRODATA {
334 flag |= goobj.SymFlagGoType
335 }
336 flag2 := uint8(0)
337 if s.UsedInIface() {
338 flag2 |= goobj.SymFlagUsedInIface
339 }
340 if strings.HasPrefix(s.Name, "go.itab.") && s.Type == objabi.SRODATA {
341 flag2 |= goobj.SymFlagItab
342 }
343 name := s.Name
344 if strings.HasPrefix(name, "gofile..") {
345 name = filepath.ToSlash(name)
346 }
347 var align uint32
348 if fn := s.Func(); fn != nil {
349 align = uint32(fn.Align)
350 }
351 if s.ContentAddressable() {
352
353
354
355
356
357
358 if s.Size != 0 && !strings.HasPrefix(s.Name, "go.string.") {
359 switch {
360 case w.ctxt.Arch.PtrSize == 8 && s.Size%8 == 0:
361 align = 8
362 case s.Size%4 == 0:
363 align = 4
364 case s.Size%2 == 0:
365 align = 2
366 }
367
368 }
369 }
370 if s.Size > cutoff {
371 w.ctxt.Diag("%s: symbol too large (%d bytes > %d bytes)", s.Name, s.Size, cutoff)
372 }
373 var o goobj.Sym
374 o.SetName(name, w.Writer)
375 o.SetABI(abi)
376 o.SetType(uint8(s.Type))
377 o.SetFlag(flag)
378 o.SetFlag2(flag2)
379 o.SetSiz(uint32(s.Size))
380 o.SetAlign(align)
381 o.Write(w.Writer)
382 }
383
384 func (w *writer) Hash64(s *LSym) {
385 if !s.ContentAddressable() || len(s.R) != 0 {
386 panic("Hash of non-content-addressable symbol")
387 }
388 b := contentHash64(s)
389 w.Bytes(b[:])
390 }
391
392 func (w *writer) Hash(s *LSym) {
393 if !s.ContentAddressable() {
394 panic("Hash of non-content-addressable symbol")
395 }
396 b := w.contentHash(s)
397 w.Bytes(b[:])
398 }
399
400 func contentHash64(s *LSym) goobj.Hash64Type {
401 var b goobj.Hash64Type
402 copy(b[:], s.P)
403 return b
404 }
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422 func (w *writer) contentHash(s *LSym) goobj.HashType {
423 h := sha1.New()
424 var tmp [14]byte
425
426
427
428
429
430
431
432
433
434 binary.LittleEndian.PutUint64(tmp[:8], uint64(s.Size))
435 h.Write(tmp[:8])
436
437
438
439 if strings.HasPrefix(s.Name, "type.") {
440 h.Write([]byte{'T'})
441 } else {
442 h.Write([]byte{0})
443 }
444
445
446 h.Write(bytes.TrimRight(s.P, "\x00"))
447 for i := range s.R {
448 r := &s.R[i]
449 binary.LittleEndian.PutUint32(tmp[:4], uint32(r.Off))
450 tmp[4] = r.Siz
451 tmp[5] = uint8(r.Type)
452 binary.LittleEndian.PutUint64(tmp[6:14], uint64(r.Add))
453 h.Write(tmp[:])
454 rs := r.Sym
455 switch rs.PkgIdx {
456 case goobj.PkgIdxHashed64:
457 h.Write([]byte{0})
458 t := contentHash64(rs)
459 h.Write(t[:])
460 case goobj.PkgIdxHashed:
461 h.Write([]byte{1})
462 t := w.contentHash(rs)
463 h.Write(t[:])
464 case goobj.PkgIdxNone:
465 h.Write([]byte{2})
466 io.WriteString(h, rs.Name)
467 case goobj.PkgIdxBuiltin:
468 h.Write([]byte{3})
469 binary.LittleEndian.PutUint32(tmp[:4], uint32(rs.SymIdx))
470 h.Write(tmp[:4])
471 case goobj.PkgIdxSelf:
472 io.WriteString(h, w.pkgpath)
473 binary.LittleEndian.PutUint32(tmp[:4], uint32(rs.SymIdx))
474 h.Write(tmp[:4])
475 default:
476 io.WriteString(h, rs.Pkg)
477 binary.LittleEndian.PutUint32(tmp[:4], uint32(rs.SymIdx))
478 h.Write(tmp[:4])
479 }
480 }
481 var b goobj.HashType
482 copy(b[:], h.Sum(nil))
483 return b
484 }
485
486 func makeSymRef(s *LSym) goobj.SymRef {
487 if s == nil {
488 return goobj.SymRef{}
489 }
490 if s.PkgIdx == 0 || !s.Indexed() {
491 fmt.Printf("unindexed symbol reference: %v\n", s)
492 panic("unindexed symbol reference")
493 }
494 return goobj.SymRef{PkgIdx: uint32(s.PkgIdx), SymIdx: uint32(s.SymIdx)}
495 }
496
497 func (w *writer) Reloc(r *Reloc) {
498 var o goobj.Reloc
499 o.SetOff(r.Off)
500 o.SetSiz(r.Siz)
501 o.SetType(uint16(r.Type))
502 o.SetAdd(r.Add)
503 o.SetSym(makeSymRef(r.Sym))
504 o.Write(w.Writer)
505 }
506
507 func (w *writer) aux1(typ uint8, rs *LSym) {
508 var o goobj.Aux
509 o.SetType(typ)
510 o.SetSym(makeSymRef(rs))
511 o.Write(w.Writer)
512 }
513
514 func (w *writer) Aux(s *LSym) {
515 if s.Gotype != nil {
516 w.aux1(goobj.AuxGotype, s.Gotype)
517 }
518 if fn := s.Func(); fn != nil {
519 w.aux1(goobj.AuxFuncInfo, fn.FuncInfoSym)
520
521 for _, d := range fn.Pcln.Funcdata {
522 w.aux1(goobj.AuxFuncdata, d)
523 }
524
525 if fn.dwarfInfoSym != nil && fn.dwarfInfoSym.Size != 0 {
526 w.aux1(goobj.AuxDwarfInfo, fn.dwarfInfoSym)
527 }
528 if fn.dwarfLocSym != nil && fn.dwarfLocSym.Size != 0 {
529 w.aux1(goobj.AuxDwarfLoc, fn.dwarfLocSym)
530 }
531 if fn.dwarfRangesSym != nil && fn.dwarfRangesSym.Size != 0 {
532 w.aux1(goobj.AuxDwarfRanges, fn.dwarfRangesSym)
533 }
534 if fn.dwarfDebugLinesSym != nil && fn.dwarfDebugLinesSym.Size != 0 {
535 w.aux1(goobj.AuxDwarfLines, fn.dwarfDebugLinesSym)
536 }
537 if fn.Pcln.Pcsp != nil && fn.Pcln.Pcsp.Size != 0 {
538 w.aux1(goobj.AuxPcsp, fn.Pcln.Pcsp)
539 }
540 if fn.Pcln.Pcfile != nil && fn.Pcln.Pcfile.Size != 0 {
541 w.aux1(goobj.AuxPcfile, fn.Pcln.Pcfile)
542 }
543 if fn.Pcln.Pcline != nil && fn.Pcln.Pcline.Size != 0 {
544 w.aux1(goobj.AuxPcline, fn.Pcln.Pcline)
545 }
546 if fn.Pcln.Pcinline != nil && fn.Pcln.Pcinline.Size != 0 {
547 w.aux1(goobj.AuxPcinline, fn.Pcln.Pcinline)
548 }
549 for _, pcSym := range fn.Pcln.Pcdata {
550 w.aux1(goobj.AuxPcdata, pcSym)
551 }
552
553 }
554 }
555
556
557 func (w *writer) refFlags() {
558 seen := make(map[*LSym]bool)
559 w.ctxt.traverseSyms(traverseRefs, func(rs *LSym) {
560 switch rs.PkgIdx {
561 case goobj.PkgIdxNone, goobj.PkgIdxHashed64, goobj.PkgIdxHashed, goobj.PkgIdxBuiltin, goobj.PkgIdxSelf:
562 return
563 case goobj.PkgIdxInvalid:
564 panic("unindexed symbol reference")
565 }
566 if seen[rs] {
567 return
568 }
569 seen[rs] = true
570 symref := makeSymRef(rs)
571 flag2 := uint8(0)
572 if rs.UsedInIface() {
573 flag2 |= goobj.SymFlagUsedInIface
574 }
575 if flag2 == 0 {
576 return
577 }
578 var o goobj.RefFlags
579 o.SetSym(symref)
580 o.SetFlag2(flag2)
581 o.Write(w.Writer)
582 })
583 }
584
585
586
587 func (w *writer) refNames() {
588 seen := make(map[*LSym]bool)
589 w.ctxt.traverseSyms(traverseRefs, func(rs *LSym) {
590 switch rs.PkgIdx {
591 case goobj.PkgIdxNone, goobj.PkgIdxHashed64, goobj.PkgIdxHashed, goobj.PkgIdxBuiltin, goobj.PkgIdxSelf:
592 return
593 case goobj.PkgIdxInvalid:
594 panic("unindexed symbol reference")
595 }
596 if seen[rs] {
597 return
598 }
599 seen[rs] = true
600 symref := makeSymRef(rs)
601 var o goobj.RefName
602 o.SetSym(symref)
603 o.SetName(rs.Name, w.Writer)
604 o.Write(w.Writer)
605 })
606
607
608
609
610
611 }
612
613
614 func nAuxSym(s *LSym) int {
615 n := 0
616 if s.Gotype != nil {
617 n++
618 }
619 if fn := s.Func(); fn != nil {
620
621 n += 1 + len(fn.Pcln.Funcdata)
622 if fn.dwarfInfoSym != nil && fn.dwarfInfoSym.Size != 0 {
623 n++
624 }
625 if fn.dwarfLocSym != nil && fn.dwarfLocSym.Size != 0 {
626 n++
627 }
628 if fn.dwarfRangesSym != nil && fn.dwarfRangesSym.Size != 0 {
629 n++
630 }
631 if fn.dwarfDebugLinesSym != nil && fn.dwarfDebugLinesSym.Size != 0 {
632 n++
633 }
634 if fn.Pcln.Pcsp != nil && fn.Pcln.Pcsp.Size != 0 {
635 n++
636 }
637 if fn.Pcln.Pcfile != nil && fn.Pcln.Pcfile.Size != 0 {
638 n++
639 }
640 if fn.Pcln.Pcline != nil && fn.Pcln.Pcline.Size != 0 {
641 n++
642 }
643 if fn.Pcln.Pcinline != nil && fn.Pcln.Pcinline.Size != 0 {
644 n++
645 }
646 n += len(fn.Pcln.Pcdata)
647 }
648 return n
649 }
650
651
652 func genFuncInfoSyms(ctxt *Link) {
653 infosyms := make([]*LSym, 0, len(ctxt.Text))
654 hashedsyms := make([]*LSym, 0, 4*len(ctxt.Text))
655 preparePcSym := func(s *LSym) *LSym {
656 if s == nil {
657 return s
658 }
659 s.PkgIdx = goobj.PkgIdxHashed
660 s.SymIdx = int32(len(hashedsyms) + len(ctxt.hasheddefs))
661 s.Set(AttrIndexed, true)
662 hashedsyms = append(hashedsyms, s)
663 return s
664 }
665 var b bytes.Buffer
666 symidx := int32(len(ctxt.defs))
667 for _, s := range ctxt.Text {
668 fn := s.Func()
669 if fn == nil {
670 continue
671 }
672 o := goobj.FuncInfo{
673 Args: uint32(fn.Args),
674 Locals: uint32(fn.Locals),
675 FuncID: fn.FuncID,
676 FuncFlag: fn.FuncFlag,
677 }
678 pc := &fn.Pcln
679 o.Pcsp = makeSymRef(preparePcSym(pc.Pcsp))
680 o.Pcfile = makeSymRef(preparePcSym(pc.Pcfile))
681 o.Pcline = makeSymRef(preparePcSym(pc.Pcline))
682 o.Pcinline = makeSymRef(preparePcSym(pc.Pcinline))
683 o.Pcdata = make([]goobj.SymRef, len(pc.Pcdata))
684 for i, pcSym := range pc.Pcdata {
685 o.Pcdata[i] = makeSymRef(preparePcSym(pcSym))
686 }
687 o.Funcdataoff = make([]uint32, len(pc.Funcdataoff))
688 for i, x := range pc.Funcdataoff {
689 o.Funcdataoff[i] = uint32(x)
690 }
691 i := 0
692 o.File = make([]goobj.CUFileIndex, len(pc.UsedFiles))
693 for f := range pc.UsedFiles {
694 o.File[i] = f
695 i++
696 }
697 sort.Slice(o.File, func(i, j int) bool { return o.File[i] < o.File[j] })
698 o.InlTree = make([]goobj.InlTreeNode, len(pc.InlTree.nodes))
699 for i, inl := range pc.InlTree.nodes {
700 f, l := getFileIndexAndLine(ctxt, inl.Pos)
701 o.InlTree[i] = goobj.InlTreeNode{
702 Parent: int32(inl.Parent),
703 File: goobj.CUFileIndex(f),
704 Line: l,
705 Func: makeSymRef(inl.Func),
706 ParentPC: inl.ParentPC,
707 }
708 }
709
710 o.Write(&b)
711 isym := &LSym{
712 Type: objabi.SDATA,
713 PkgIdx: goobj.PkgIdxSelf,
714 SymIdx: symidx,
715 P: append([]byte(nil), b.Bytes()...),
716 }
717 isym.Set(AttrIndexed, true)
718 symidx++
719 infosyms = append(infosyms, isym)
720 fn.FuncInfoSym = isym
721 b.Reset()
722
723 dwsyms := []*LSym{fn.dwarfRangesSym, fn.dwarfLocSym, fn.dwarfDebugLinesSym, fn.dwarfInfoSym}
724 for _, s := range dwsyms {
725 if s == nil || s.Size == 0 {
726 continue
727 }
728 s.PkgIdx = goobj.PkgIdxSelf
729 s.SymIdx = symidx
730 s.Set(AttrIndexed, true)
731 symidx++
732 infosyms = append(infosyms, s)
733 }
734 }
735 ctxt.defs = append(ctxt.defs, infosyms...)
736 ctxt.hasheddefs = append(ctxt.hasheddefs, hashedsyms...)
737 }
738
739 func writeAuxSymDebug(ctxt *Link, par *LSym, aux *LSym) {
740
741
742 if aux.Type != objabi.SDWARFLOC &&
743 aux.Type != objabi.SDWARFFCN &&
744 aux.Type != objabi.SDWARFABSFCN &&
745 aux.Type != objabi.SDWARFLINES &&
746 aux.Type != objabi.SDWARFRANGE {
747 return
748 }
749 ctxt.writeSymDebugNamed(aux, "aux for "+par.Name)
750 }
751
752 func debugAsmEmit(ctxt *Link) {
753 if ctxt.Debugasm > 0 {
754 ctxt.traverseSyms(traverseDefs, ctxt.writeSymDebug)
755 if ctxt.Debugasm > 1 {
756 fn := func(par *LSym, aux *LSym) {
757 writeAuxSymDebug(ctxt, par, aux)
758 }
759 ctxt.traverseAuxSyms(traverseAux, fn)
760 }
761 }
762 }
763
764 func (ctxt *Link) writeSymDebug(s *LSym) {
765 ctxt.writeSymDebugNamed(s, s.Name)
766 }
767
768 func (ctxt *Link) writeSymDebugNamed(s *LSym, name string) {
769 ver := ""
770 if ctxt.Debugasm > 1 {
771 ver = fmt.Sprintf("<%d>", s.ABI())
772 }
773 fmt.Fprintf(ctxt.Bso, "%s%s ", name, ver)
774 if s.Type != 0 {
775 fmt.Fprintf(ctxt.Bso, "%v ", s.Type)
776 }
777 if s.Static() {
778 fmt.Fprint(ctxt.Bso, "static ")
779 }
780 if s.DuplicateOK() {
781 fmt.Fprintf(ctxt.Bso, "dupok ")
782 }
783 if s.CFunc() {
784 fmt.Fprintf(ctxt.Bso, "cfunc ")
785 }
786 if s.NoSplit() {
787 fmt.Fprintf(ctxt.Bso, "nosplit ")
788 }
789 if s.Func() != nil && s.Func().FuncFlag&objabi.FuncFlag_TOPFRAME != 0 {
790 fmt.Fprintf(ctxt.Bso, "topframe ")
791 }
792 fmt.Fprintf(ctxt.Bso, "size=%d", s.Size)
793 if s.Type == objabi.STEXT {
794 fn := s.Func()
795 fmt.Fprintf(ctxt.Bso, " args=%#x locals=%#x funcid=%#x", uint64(fn.Args), uint64(fn.Locals), uint64(fn.FuncID))
796 if s.Leaf() {
797 fmt.Fprintf(ctxt.Bso, " leaf")
798 }
799 }
800 fmt.Fprintf(ctxt.Bso, "\n")
801 if s.Type == objabi.STEXT {
802 for p := s.Func().Text; p != nil; p = p.Link {
803 fmt.Fprintf(ctxt.Bso, "\t%#04x ", uint(int(p.Pc)))
804 if ctxt.Debugasm > 1 {
805 io.WriteString(ctxt.Bso, p.String())
806 } else {
807 p.InnermostString(ctxt.Bso)
808 }
809 fmt.Fprintln(ctxt.Bso)
810 }
811 }
812 for i := 0; i < len(s.P); i += 16 {
813 fmt.Fprintf(ctxt.Bso, "\t%#04x", uint(i))
814 j := i
815 for ; j < i+16 && j < len(s.P); j++ {
816 fmt.Fprintf(ctxt.Bso, " %02x", s.P[j])
817 }
818 for ; j < i+16; j++ {
819 fmt.Fprintf(ctxt.Bso, " ")
820 }
821 fmt.Fprintf(ctxt.Bso, " ")
822 for j = i; j < i+16 && j < len(s.P); j++ {
823 c := int(s.P[j])
824 b := byte('.')
825 if ' ' <= c && c <= 0x7e {
826 b = byte(c)
827 }
828 ctxt.Bso.WriteByte(b)
829 }
830
831 fmt.Fprintf(ctxt.Bso, "\n")
832 }
833
834 sort.Sort(relocByOff(s.R))
835 for _, r := range s.R {
836 name := ""
837 ver := ""
838 if r.Sym != nil {
839 name = r.Sym.Name
840 if ctxt.Debugasm > 1 {
841 ver = fmt.Sprintf("<%d>", r.Sym.ABI())
842 }
843 } else if r.Type == objabi.R_TLS_LE {
844 name = "TLS"
845 }
846 if ctxt.Arch.InFamily(sys.ARM, sys.PPC64) {
847 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))
848 } else {
849 fmt.Fprintf(ctxt.Bso, "\trel %d+%d t=%d %s%s+%d\n", int(r.Off), r.Siz, r.Type, name, ver, r.Add)
850 }
851 }
852 }
853
854
855 type relocByOff []Reloc
856
857 func (x relocByOff) Len() int { return len(x) }
858 func (x relocByOff) Less(i, j int) bool { return x[i].Off < x[j].Off }
859 func (x relocByOff) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
860
View as plain text