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
198
199 h.Offsets[goobj.BlkRefName] = w.Offset()
200 w.refNames()
201
202 h.Offsets[goobj.BlkEnd] = w.Offset()
203
204
205 end := start + int64(w.Offset())
206 b.MustSeek(start, 0)
207 h.Write(w.Writer)
208 b.MustSeek(end, 0)
209 }
210
211 type writer struct {
212 *goobj.Writer
213 filebuf []byte
214 ctxt *Link
215 pkgpath string
216 pkglist []string
217 }
218
219
220 func (w *writer) init() {
221 w.pkglist = make([]string, len(w.ctxt.pkgIdx)+1)
222 w.pkglist[0] = ""
223 for pkg, i := range w.ctxt.pkgIdx {
224 w.pkglist[i] = pkg
225 }
226 }
227
228 func (w *writer) writeFile(ctxt *Link, file *FileInfo) {
229 f, err := os.Open(file.Name)
230 if err != nil {
231 ctxt.Diag("%v", err)
232 return
233 }
234 defer f.Close()
235 if w.filebuf == nil {
236 w.filebuf = make([]byte, 1024)
237 }
238 buf := w.filebuf
239 written := int64(0)
240 for {
241 n, err := f.Read(buf)
242 w.Bytes(buf[:n])
243 written += int64(n)
244 if err == io.EOF {
245 break
246 }
247 if err != nil {
248 ctxt.Diag("%v", err)
249 return
250 }
251 }
252 if written != file.Size {
253 ctxt.Diag("copy %s: unexpected length %d != %d", file.Name, written, file.Size)
254 }
255 }
256
257 func (w *writer) StringTable() {
258 w.AddString("")
259 for _, p := range w.ctxt.Imports {
260 w.AddString(p.Pkg)
261 }
262 for _, pkg := range w.pkglist {
263 w.AddString(pkg)
264 }
265 w.ctxt.traverseSyms(traverseAll, func(s *LSym) {
266
267
268
269 if w.pkgpath != "" {
270 s.Name = strings.Replace(s.Name, "\"\".", w.pkgpath+".", -1)
271 }
272
273
274 if s.PkgIdx == goobj.PkgIdxBuiltin {
275 return
276 }
277 w.AddString(s.Name)
278 })
279
280
281 for _, f := range w.ctxt.PosTable.FileTable() {
282 w.AddString(filepath.ToSlash(f))
283 }
284 }
285
286
287
288 const cutoff = int64(2e9)
289
290 func (w *writer) Sym(s *LSym) {
291 abi := uint16(s.ABI())
292 if s.Static() {
293 abi = goobj.SymABIstatic
294 }
295 flag := uint8(0)
296 if s.DuplicateOK() {
297 flag |= goobj.SymFlagDupok
298 }
299 if s.Local() {
300 flag |= goobj.SymFlagLocal
301 }
302 if s.MakeTypelink() {
303 flag |= goobj.SymFlagTypelink
304 }
305 if s.Leaf() {
306 flag |= goobj.SymFlagLeaf
307 }
308 if s.NoSplit() {
309 flag |= goobj.SymFlagNoSplit
310 }
311 if s.ReflectMethod() {
312 flag |= goobj.SymFlagReflectMethod
313 }
314 if strings.HasPrefix(s.Name, "type.") && s.Name[5] != '.' && s.Type == objabi.SRODATA {
315 flag |= goobj.SymFlagGoType
316 }
317 flag2 := uint8(0)
318 if s.UsedInIface() {
319 flag2 |= goobj.SymFlagUsedInIface
320 }
321 if strings.HasPrefix(s.Name, "go.itab.") && s.Type == objabi.SRODATA {
322 flag2 |= goobj.SymFlagItab
323 }
324 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) {
325 flag2 |= goobj.SymFlagDict
326 }
327 name := s.Name
328 if strings.HasPrefix(name, "gofile..") {
329 name = filepath.ToSlash(name)
330 }
331 var align uint32
332 if fn := s.Func(); fn != nil {
333 align = uint32(fn.Align)
334 }
335 if s.ContentAddressable() && s.Size != 0 {
336
337
338
339
340
341
342
343 switch {
344 case strings.HasPrefix(s.Name, "go.string."),
345 strings.HasPrefix(name, "type..namedata."),
346 strings.HasPrefix(name, "type..importpath."),
347 strings.HasPrefix(name, "runtime.gcbits."),
348 strings.HasSuffix(name, ".opendefer"),
349 strings.HasSuffix(name, ".arginfo0"),
350 strings.HasSuffix(name, ".arginfo1"),
351 strings.HasSuffix(name, ".argliveinfo"):
352
353 align = 1
354 case strings.HasPrefix(name, "gclocals·"):
355
356 align = 4
357 default:
358 switch {
359 case w.ctxt.Arch.PtrSize == 8 && s.Size%8 == 0:
360 align = 8
361 case s.Size%4 == 0:
362 align = 4
363 case s.Size%2 == 0:
364 align = 2
365 default:
366 align = 1
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
401
402
403
404
405
406
407
408 func contentHashSection(s *LSym) byte {
409 name := s.Name
410 if s.IsPcdata() {
411 return 'P'
412 }
413 if strings.HasPrefix(name, "gcargs.") ||
414 strings.HasPrefix(name, "gclocals.") ||
415 strings.HasPrefix(name, "gclocals·") ||
416 strings.HasSuffix(name, ".opendefer") ||
417 strings.HasSuffix(name, ".arginfo0") ||
418 strings.HasSuffix(name, ".arginfo1") ||
419 strings.HasSuffix(name, ".argliveinfo") ||
420 strings.HasSuffix(name, ".wrapinfo") ||
421 strings.HasSuffix(name, ".args_stackmap") ||
422 strings.HasSuffix(name, ".stkobj") {
423 return 'F'
424 }
425 if strings.HasPrefix(name, "type.") {
426 return 'T'
427 }
428 return 0
429 }
430
431 func contentHash64(s *LSym) goobj.Hash64Type {
432 if contentHashSection(s) != 0 {
433 panic("short hash of non-default-section sym " + s.Name)
434 }
435 var b goobj.Hash64Type
436 copy(b[:], s.P)
437 return b
438 }
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456 func (w *writer) contentHash(s *LSym) goobj.HashType {
457 h := sha1.New()
458 var tmp [14]byte
459
460
461
462
463
464
465
466
467
468 binary.LittleEndian.PutUint64(tmp[:8], uint64(s.Size))
469
470 tmp[8] = contentHashSection(s)
471 h.Write(tmp[:9])
472
473
474
475 h.Write(bytes.TrimRight(s.P, "\x00"))
476 for i := range s.R {
477 r := &s.R[i]
478 binary.LittleEndian.PutUint32(tmp[:4], uint32(r.Off))
479 tmp[4] = r.Siz
480 tmp[5] = uint8(r.Type)
481 binary.LittleEndian.PutUint64(tmp[6:14], uint64(r.Add))
482 h.Write(tmp[:])
483 rs := r.Sym
484 if rs == nil {
485 fmt.Printf("symbol: %s\n", s)
486 fmt.Printf("relocation: %#v\n", r)
487 panic("nil symbol target in relocation")
488 }
489 switch rs.PkgIdx {
490 case goobj.PkgIdxHashed64:
491 h.Write([]byte{0})
492 t := contentHash64(rs)
493 h.Write(t[:])
494 case goobj.PkgIdxHashed:
495 h.Write([]byte{1})
496 t := w.contentHash(rs)
497 h.Write(t[:])
498 case goobj.PkgIdxNone:
499 h.Write([]byte{2})
500 io.WriteString(h, rs.Name)
501 case goobj.PkgIdxBuiltin:
502 h.Write([]byte{3})
503 binary.LittleEndian.PutUint32(tmp[:4], uint32(rs.SymIdx))
504 h.Write(tmp[:4])
505 case goobj.PkgIdxSelf:
506 io.WriteString(h, w.pkgpath)
507 binary.LittleEndian.PutUint32(tmp[:4], uint32(rs.SymIdx))
508 h.Write(tmp[:4])
509 default:
510 io.WriteString(h, rs.Pkg)
511 binary.LittleEndian.PutUint32(tmp[:4], uint32(rs.SymIdx))
512 h.Write(tmp[:4])
513 }
514 }
515 var b goobj.HashType
516 copy(b[:], h.Sum(nil))
517 return b
518 }
519
520 func makeSymRef(s *LSym) goobj.SymRef {
521 if s == nil {
522 return goobj.SymRef{}
523 }
524 if s.PkgIdx == 0 || !s.Indexed() {
525 fmt.Printf("unindexed symbol reference: %v\n", s)
526 panic("unindexed symbol reference")
527 }
528 return goobj.SymRef{PkgIdx: uint32(s.PkgIdx), SymIdx: uint32(s.SymIdx)}
529 }
530
531 func (w *writer) Reloc(r *Reloc) {
532 var o goobj.Reloc
533 o.SetOff(r.Off)
534 o.SetSiz(r.Siz)
535 o.SetType(uint16(r.Type))
536 o.SetAdd(r.Add)
537 o.SetSym(makeSymRef(r.Sym))
538 o.Write(w.Writer)
539 }
540
541 func (w *writer) aux1(typ uint8, rs *LSym) {
542 var o goobj.Aux
543 o.SetType(typ)
544 o.SetSym(makeSymRef(rs))
545 o.Write(w.Writer)
546 }
547
548 func (w *writer) Aux(s *LSym) {
549 if s.Gotype != nil {
550 w.aux1(goobj.AuxGotype, s.Gotype)
551 }
552 if fn := s.Func(); fn != nil {
553 w.aux1(goobj.AuxFuncInfo, fn.FuncInfoSym)
554
555 for _, d := range fn.Pcln.Funcdata {
556 w.aux1(goobj.AuxFuncdata, d)
557 }
558
559 if fn.dwarfInfoSym != nil && fn.dwarfInfoSym.Size != 0 {
560 w.aux1(goobj.AuxDwarfInfo, fn.dwarfInfoSym)
561 }
562 if fn.dwarfLocSym != nil && fn.dwarfLocSym.Size != 0 {
563 w.aux1(goobj.AuxDwarfLoc, fn.dwarfLocSym)
564 }
565 if fn.dwarfRangesSym != nil && fn.dwarfRangesSym.Size != 0 {
566 w.aux1(goobj.AuxDwarfRanges, fn.dwarfRangesSym)
567 }
568 if fn.dwarfDebugLinesSym != nil && fn.dwarfDebugLinesSym.Size != 0 {
569 w.aux1(goobj.AuxDwarfLines, fn.dwarfDebugLinesSym)
570 }
571 if fn.Pcln.Pcsp != nil && fn.Pcln.Pcsp.Size != 0 {
572 w.aux1(goobj.AuxPcsp, fn.Pcln.Pcsp)
573 }
574 if fn.Pcln.Pcfile != nil && fn.Pcln.Pcfile.Size != 0 {
575 w.aux1(goobj.AuxPcfile, fn.Pcln.Pcfile)
576 }
577 if fn.Pcln.Pcline != nil && fn.Pcln.Pcline.Size != 0 {
578 w.aux1(goobj.AuxPcline, fn.Pcln.Pcline)
579 }
580 if fn.Pcln.Pcinline != nil && fn.Pcln.Pcinline.Size != 0 {
581 w.aux1(goobj.AuxPcinline, fn.Pcln.Pcinline)
582 }
583 for _, pcSym := range fn.Pcln.Pcdata {
584 w.aux1(goobj.AuxPcdata, pcSym)
585 }
586
587 }
588 }
589
590
591 func (w *writer) refFlags() {
592 seen := make(map[*LSym]bool)
593 w.ctxt.traverseSyms(traverseRefs, func(rs *LSym) {
594 switch rs.PkgIdx {
595 case goobj.PkgIdxNone, goobj.PkgIdxHashed64, goobj.PkgIdxHashed, goobj.PkgIdxBuiltin, goobj.PkgIdxSelf:
596 return
597 case goobj.PkgIdxInvalid:
598 panic("unindexed symbol reference")
599 }
600 if seen[rs] {
601 return
602 }
603 seen[rs] = true
604 symref := makeSymRef(rs)
605 flag2 := uint8(0)
606 if rs.UsedInIface() {
607 flag2 |= goobj.SymFlagUsedInIface
608 }
609 if flag2 == 0 {
610 return
611 }
612 var o goobj.RefFlags
613 o.SetSym(symref)
614 o.SetFlag2(flag2)
615 o.Write(w.Writer)
616 })
617 }
618
619
620
621 func (w *writer) refNames() {
622 seen := make(map[*LSym]bool)
623 w.ctxt.traverseSyms(traverseRefs, func(rs *LSym) {
624 switch rs.PkgIdx {
625 case goobj.PkgIdxNone, goobj.PkgIdxHashed64, goobj.PkgIdxHashed, goobj.PkgIdxBuiltin, goobj.PkgIdxSelf:
626 return
627 case goobj.PkgIdxInvalid:
628 panic("unindexed symbol reference")
629 }
630 if seen[rs] {
631 return
632 }
633 seen[rs] = true
634 symref := makeSymRef(rs)
635 var o goobj.RefName
636 o.SetSym(symref)
637 o.SetName(rs.Name, w.Writer)
638 o.Write(w.Writer)
639 })
640
641
642
643
644
645 }
646
647
648 func nAuxSym(s *LSym) int {
649 n := 0
650 if s.Gotype != nil {
651 n++
652 }
653 if fn := s.Func(); fn != nil {
654
655 n += 1 + len(fn.Pcln.Funcdata)
656 if fn.dwarfInfoSym != nil && fn.dwarfInfoSym.Size != 0 {
657 n++
658 }
659 if fn.dwarfLocSym != nil && fn.dwarfLocSym.Size != 0 {
660 n++
661 }
662 if fn.dwarfRangesSym != nil && fn.dwarfRangesSym.Size != 0 {
663 n++
664 }
665 if fn.dwarfDebugLinesSym != nil && fn.dwarfDebugLinesSym.Size != 0 {
666 n++
667 }
668 if fn.Pcln.Pcsp != nil && fn.Pcln.Pcsp.Size != 0 {
669 n++
670 }
671 if fn.Pcln.Pcfile != nil && fn.Pcln.Pcfile.Size != 0 {
672 n++
673 }
674 if fn.Pcln.Pcline != nil && fn.Pcln.Pcline.Size != 0 {
675 n++
676 }
677 if fn.Pcln.Pcinline != nil && fn.Pcln.Pcinline.Size != 0 {
678 n++
679 }
680 n += len(fn.Pcln.Pcdata)
681 }
682 return n
683 }
684
685
686 func genFuncInfoSyms(ctxt *Link) {
687 infosyms := make([]*LSym, 0, len(ctxt.Text))
688 hashedsyms := make([]*LSym, 0, 4*len(ctxt.Text))
689 var b bytes.Buffer
690 symidx := int32(len(ctxt.defs))
691 for _, s := range ctxt.Text {
692 fn := s.Func()
693 if fn == nil {
694 continue
695 }
696 o := goobj.FuncInfo{
697 Args: uint32(fn.Args),
698 Locals: uint32(fn.Locals),
699 FuncID: fn.FuncID,
700 FuncFlag: fn.FuncFlag,
701 }
702 pc := &fn.Pcln
703 i := 0
704 o.File = make([]goobj.CUFileIndex, len(pc.UsedFiles))
705 for f := range pc.UsedFiles {
706 o.File[i] = f
707 i++
708 }
709 sort.Slice(o.File, func(i, j int) bool { return o.File[i] < o.File[j] })
710 o.InlTree = make([]goobj.InlTreeNode, len(pc.InlTree.nodes))
711 for i, inl := range pc.InlTree.nodes {
712 f, l := getFileIndexAndLine(ctxt, inl.Pos)
713 o.InlTree[i] = goobj.InlTreeNode{
714 Parent: int32(inl.Parent),
715 File: goobj.CUFileIndex(f),
716 Line: l,
717 Func: makeSymRef(inl.Func),
718 ParentPC: inl.ParentPC,
719 }
720 }
721
722 o.Write(&b)
723 isym := &LSym{
724 Type: objabi.SDATA,
725 PkgIdx: goobj.PkgIdxSelf,
726 SymIdx: symidx,
727 P: append([]byte(nil), b.Bytes()...),
728 }
729 isym.Set(AttrIndexed, true)
730 symidx++
731 infosyms = append(infosyms, isym)
732 fn.FuncInfoSym = isym
733 b.Reset()
734
735 dwsyms := []*LSym{fn.dwarfRangesSym, fn.dwarfLocSym, fn.dwarfDebugLinesSym, fn.dwarfInfoSym}
736 for _, s := range dwsyms {
737 if s == nil || s.Size == 0 {
738 continue
739 }
740 s.PkgIdx = goobj.PkgIdxSelf
741 s.SymIdx = symidx
742 s.Set(AttrIndexed, true)
743 symidx++
744 infosyms = append(infosyms, s)
745 }
746 }
747 ctxt.defs = append(ctxt.defs, infosyms...)
748 ctxt.hasheddefs = append(ctxt.hasheddefs, hashedsyms...)
749 }
750
751 func writeAuxSymDebug(ctxt *Link, par *LSym, aux *LSym) {
752
753
754 if aux.Type != objabi.SDWARFLOC &&
755 aux.Type != objabi.SDWARFFCN &&
756 aux.Type != objabi.SDWARFABSFCN &&
757 aux.Type != objabi.SDWARFLINES &&
758 aux.Type != objabi.SDWARFRANGE {
759 return
760 }
761 ctxt.writeSymDebugNamed(aux, "aux for "+par.Name)
762 }
763
764 func debugAsmEmit(ctxt *Link) {
765 if ctxt.Debugasm > 0 {
766 ctxt.traverseSyms(traverseDefs, ctxt.writeSymDebug)
767 if ctxt.Debugasm > 1 {
768 fn := func(par *LSym, aux *LSym) {
769 writeAuxSymDebug(ctxt, par, aux)
770 }
771 ctxt.traverseAuxSyms(traverseAux, fn)
772 }
773 }
774 }
775
776 func (ctxt *Link) writeSymDebug(s *LSym) {
777 ctxt.writeSymDebugNamed(s, s.Name)
778 }
779
780 func (ctxt *Link) writeSymDebugNamed(s *LSym, name string) {
781 ver := ""
782 if ctxt.Debugasm > 1 {
783 ver = fmt.Sprintf("<%d>", s.ABI())
784 }
785 fmt.Fprintf(ctxt.Bso, "%s%s ", name, ver)
786 if s.Type != 0 {
787 fmt.Fprintf(ctxt.Bso, "%v ", s.Type)
788 }
789 if s.Static() {
790 fmt.Fprint(ctxt.Bso, "static ")
791 }
792 if s.DuplicateOK() {
793 fmt.Fprintf(ctxt.Bso, "dupok ")
794 }
795 if s.CFunc() {
796 fmt.Fprintf(ctxt.Bso, "cfunc ")
797 }
798 if s.NoSplit() {
799 fmt.Fprintf(ctxt.Bso, "nosplit ")
800 }
801 if s.Func() != nil && s.Func().FuncFlag&objabi.FuncFlag_TOPFRAME != 0 {
802 fmt.Fprintf(ctxt.Bso, "topframe ")
803 }
804 if s.Func() != nil && s.Func().FuncFlag&objabi.FuncFlag_ASM != 0 {
805 fmt.Fprintf(ctxt.Bso, "asm ")
806 }
807 fmt.Fprintf(ctxt.Bso, "size=%d", s.Size)
808 if s.Type == objabi.STEXT {
809 fn := s.Func()
810 fmt.Fprintf(ctxt.Bso, " args=%#x locals=%#x funcid=%#x align=%#x", uint64(fn.Args), uint64(fn.Locals), uint64(fn.FuncID), uint64(fn.Align))
811 if s.Leaf() {
812 fmt.Fprintf(ctxt.Bso, " leaf")
813 }
814 }
815 fmt.Fprintf(ctxt.Bso, "\n")
816 if s.Type == objabi.STEXT {
817 for p := s.Func().Text; p != nil; p = p.Link {
818 fmt.Fprintf(ctxt.Bso, "\t%#04x ", uint(int(p.Pc)))
819 if ctxt.Debugasm > 1 {
820 io.WriteString(ctxt.Bso, p.String())
821 } else {
822 p.InnermostString(ctxt.Bso)
823 }
824 fmt.Fprintln(ctxt.Bso)
825 }
826 }
827 for i := 0; i < len(s.P); i += 16 {
828 fmt.Fprintf(ctxt.Bso, "\t%#04x", uint(i))
829 j := i
830 for ; j < i+16 && j < len(s.P); j++ {
831 fmt.Fprintf(ctxt.Bso, " %02x", s.P[j])
832 }
833 for ; j < i+16; j++ {
834 fmt.Fprintf(ctxt.Bso, " ")
835 }
836 fmt.Fprintf(ctxt.Bso, " ")
837 for j = i; j < i+16 && j < len(s.P); j++ {
838 c := int(s.P[j])
839 b := byte('.')
840 if ' ' <= c && c <= 0x7e {
841 b = byte(c)
842 }
843 ctxt.Bso.WriteByte(b)
844 }
845
846 fmt.Fprintf(ctxt.Bso, "\n")
847 }
848
849 sort.Sort(relocByOff(s.R))
850 for _, r := range s.R {
851 name := ""
852 ver := ""
853 if r.Sym != nil {
854 name = r.Sym.Name
855 if ctxt.Debugasm > 1 {
856 ver = fmt.Sprintf("<%d>", r.Sym.ABI())
857 }
858 } else if r.Type == objabi.R_TLS_LE {
859 name = "TLS"
860 }
861 if ctxt.Arch.InFamily(sys.ARM, sys.PPC64) {
862 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))
863 } else {
864 fmt.Fprintf(ctxt.Bso, "\trel %d+%d t=%d %s%s+%d\n", int(r.Off), r.Siz, r.Type, name, ver, r.Add)
865 }
866 }
867 }
868
869
870 type relocByOff []Reloc
871
872 func (x relocByOff) Len() int { return len(x) }
873 func (x relocByOff) Less(i, j int) bool { return x[i].Off < x[j].Off }
874 func (x relocByOff) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
875
View as plain text