1
2
3
4
5 package obj
6
7 import (
8 "bytes"
9 "cmd/internal/objabi"
10 "fmt"
11 "internal/abi"
12 "internal/buildcfg"
13 "io"
14 "strings"
15 )
16
17 const REG_NONE = 0
18
19
20 func (p *Prog) Line() string {
21 return p.Ctxt.OutermostPos(p.Pos).Format(false, true)
22 }
23 func (p *Prog) InnermostLine(w io.Writer) {
24 p.Ctxt.InnermostPos(p.Pos).WriteTo(w, false, true)
25 }
26
27
28
29 func (p *Prog) InnermostLineNumber() string {
30 return p.Ctxt.InnermostPos(p.Pos).LineNumber()
31 }
32
33
34
35 func (p *Prog) InnermostLineNumberHTML() string {
36 return p.Ctxt.InnermostPos(p.Pos).LineNumberHTML()
37 }
38
39
40
41 func (p *Prog) InnermostFilename() string {
42
43
44 pos := p.Ctxt.InnermostPos(p.Pos)
45 if !pos.IsKnown() {
46 return "<unknown file name>"
47 }
48 return pos.Filename()
49 }
50
51 var armCondCode = []string{
52 ".EQ",
53 ".NE",
54 ".CS",
55 ".CC",
56 ".MI",
57 ".PL",
58 ".VS",
59 ".VC",
60 ".HI",
61 ".LS",
62 ".GE",
63 ".LT",
64 ".GT",
65 ".LE",
66 "",
67 ".NV",
68 }
69
70
71 const (
72 C_SCOND = (1 << 4) - 1
73 C_SBIT = 1 << 4
74 C_PBIT = 1 << 5
75 C_WBIT = 1 << 6
76 C_FBIT = 1 << 7
77 C_UBIT = 1 << 7
78 C_SCOND_XOR = 14
79 )
80
81
82 func CConv(s uint8) string {
83 if s == 0 {
84 return ""
85 }
86 for i := range opSuffixSpace {
87 sset := &opSuffixSpace[i]
88 if sset.arch == buildcfg.GOARCH {
89 return sset.cconv(s)
90 }
91 }
92 return fmt.Sprintf("SC???%d", s)
93 }
94
95
96 func CConvARM(s uint8) string {
97
98
99
100
101 sc := armCondCode[(s&C_SCOND)^C_SCOND_XOR]
102 if s&C_SBIT != 0 {
103 sc += ".S"
104 }
105 if s&C_PBIT != 0 {
106 sc += ".P"
107 }
108 if s&C_WBIT != 0 {
109 sc += ".W"
110 }
111 if s&C_UBIT != 0 {
112 sc += ".U"
113 }
114 return sc
115 }
116
117 func (p *Prog) String() string {
118 if p == nil {
119 return "<nil Prog>"
120 }
121 if p.Ctxt == nil {
122 return "<Prog without ctxt>"
123 }
124 return fmt.Sprintf("%.5d (%v)\t%s", p.Pc, p.Line(), p.InstructionString())
125 }
126
127 func (p *Prog) InnermostString(w io.Writer) {
128 if p == nil {
129 io.WriteString(w, "<nil Prog>")
130 return
131 }
132 if p.Ctxt == nil {
133 io.WriteString(w, "<Prog without ctxt>")
134 return
135 }
136 fmt.Fprintf(w, "%.5d (", p.Pc)
137 p.InnermostLine(w)
138 io.WriteString(w, ")\t")
139 p.WriteInstructionString(w)
140 }
141
142
143
144 func (p *Prog) InstructionString() string {
145 buf := new(bytes.Buffer)
146 p.WriteInstructionString(buf)
147 return buf.String()
148 }
149
150
151
152 func (p *Prog) WriteInstructionString(w io.Writer) {
153 if p == nil {
154 io.WriteString(w, "<nil Prog>")
155 return
156 }
157
158 if p.Ctxt == nil {
159 io.WriteString(w, "<Prog without ctxt>")
160 return
161 }
162
163 sc := CConv(p.Scond)
164
165 io.WriteString(w, p.As.String())
166 io.WriteString(w, sc)
167 sep := "\t"
168
169 if p.From.Type != TYPE_NONE {
170 io.WriteString(w, sep)
171 WriteDconv(w, p, &p.From)
172 sep = ", "
173 }
174 if p.Reg != REG_NONE {
175
176 fmt.Fprintf(w, "%s%v", sep, Rconv(int(p.Reg)))
177 sep = ", "
178 }
179 for i := range p.RestArgs {
180 if p.RestArgs[i].Pos == Source {
181 io.WriteString(w, sep)
182 WriteDconv(w, p, &p.RestArgs[i].Addr)
183 sep = ", "
184 }
185 }
186
187 if p.As == ATEXT {
188
189
190
191
192 s := p.From.Sym.TextAttrString()
193 if s != "" {
194 fmt.Fprintf(w, "%s%s", sep, s)
195 sep = ", "
196 }
197 }
198 if p.To.Type != TYPE_NONE {
199 io.WriteString(w, sep)
200 WriteDconv(w, p, &p.To)
201 sep = ", "
202 }
203 if p.RegTo2 != REG_NONE {
204 fmt.Fprintf(w, "%s%v", sep, Rconv(int(p.RegTo2)))
205 }
206 for i := range p.RestArgs {
207 if p.RestArgs[i].Pos == Destination {
208 io.WriteString(w, sep)
209 WriteDconv(w, p, &p.RestArgs[i].Addr)
210 sep = ", "
211 }
212 }
213 }
214
215 func (ctxt *Link) NewProg() *Prog {
216 p := new(Prog)
217 p.Ctxt = ctxt
218 return p
219 }
220
221 func (ctxt *Link) CanReuseProgs() bool {
222 return ctxt.Debugasm == 0
223 }
224
225 func isZReg(r int) bool {
226 return (r >= RBaseARM64+96 && r <= RBaseARM64+127) ||
227 (r >= RBaseARM64+2048 && r < RBaseARM64+3072)
228 }
229
230
231
232 func Dconv(p *Prog, a *Addr) string {
233 buf := new(bytes.Buffer)
234 writeDconv(buf, p, a, false)
235 return buf.String()
236 }
237
238
239
240
241 func DconvWithABIDetail(p *Prog, a *Addr) string {
242 buf := new(bytes.Buffer)
243 writeDconv(buf, p, a, true)
244 return buf.String()
245 }
246
247
248
249 func WriteDconv(w io.Writer, p *Prog, a *Addr) {
250 writeDconv(w, p, a, false)
251 }
252
253 func writeDconv(w io.Writer, p *Prog, a *Addr, abiDetail bool) {
254 switch a.Type {
255 default:
256 fmt.Fprintf(w, "type=%d", a.Type)
257
258 case TYPE_NONE:
259 if a.Name != NAME_NONE || a.Reg != 0 || a.Sym != nil {
260 a.WriteNameTo(w)
261 fmt.Fprintf(w, "(%v)(NONE)", Rconv(int(a.Reg)))
262 }
263
264 case TYPE_REG:
265 if buildcfg.GOARCH == "arm64" && a.Offset&(int64(1)<<62) != 0 {
266 preg := int((a.Offset)&31) + RBaseARM64 + 128
267 arng2 := (a.Offset >> 5) & 15
268 selreg := int((a.Offset>>9)&31) + RBaseARM64
269 idximm := (a.Offset >> 14) & 63
270
271 arngStr := ""
272 switch arng2 {
273 case 9:
274 arngStr = ".B"
275 case 10:
276 arngStr = ".H"
277 case 11:
278 arngStr = ".S"
279 case 12:
280 arngStr = ".D"
281 case 13:
282 arngStr = ".Q"
283 }
284
285 fmt.Fprintf(w, "[%s,$%d](%s%s)", Rconv(selreg), idximm, Rconv(preg), arngStr)
286 return
287 }
288
289
290
291
292
293 if a.Offset != 0 && (a.Reg < RBaseARM64 || a.Reg >= RBaseMIPS) {
294 fmt.Fprintf(w, "$%d,%v", a.Offset, Rconv(int(a.Reg)))
295 return
296 }
297
298 if a.Name != NAME_NONE || a.Sym != nil {
299 a.WriteNameTo(w)
300 fmt.Fprintf(w, "(%v)(REG)", Rconv(int(a.Reg)))
301 } else {
302 io.WriteString(w, Rconv(int(a.Reg)))
303 }
304
305 if ((RBaseARM64+1<<10+1<<9) <= a.Reg && a.Reg < (RBaseARM64+1<<11) ) ||
306 ((RBaseARM64+1<<11+1<<9) <= a.Reg && a.Reg < (RBaseARM64+1<<11+1<<10+1<<9) ) {
307 fmt.Fprintf(w, "[%d]", a.Index)
308 }
309
310 if (RBaseLOONG64+(1<<10)+(1<<11)) <= a.Reg &&
311 a.Reg < (RBaseLOONG64+(1<<10)+(2<<11)) {
312 fmt.Fprintf(w, "[%d]", a.Index)
313 }
314
315 case TYPE_BRANCH:
316 if a.Sym != nil {
317 fmt.Fprintf(w, "%s%s(SB)", a.Sym.Name, abiDecorate(a, abiDetail))
318 } else if a.Target() != nil {
319 fmt.Fprint(w, a.Target().Pc)
320 } else {
321 fmt.Fprintf(w, "%d(PC)", a.Offset)
322 }
323
324 case TYPE_INDIR:
325 io.WriteString(w, "*")
326 a.writeNameTo(w, abiDetail)
327
328 case TYPE_MEM:
329 if buildcfg.GOARCH == "arm64" && (a.Scale < 0 || (a.Index != REG_NONE && (isZReg(int(a.Reg)) || isZReg(int(a.Index))))) {
330
331 if a.Index == REG_NONE {
332 if a.Offset < 0 {
333 fmt.Fprintf(w, "(-VL*%d)(%v)", -a.Offset, Rconv(int(a.Reg)))
334 } else {
335 fmt.Fprintf(w, "(VL*%d)(%v)", a.Offset, Rconv(int(a.Reg)))
336 }
337 } else {
338 amount := 0
339 mod := 0
340 if a.Scale < 0 {
341 amount = int((a.Scale >> 12) & 0x7)
342 mod = int((a.Scale >> 9) & 0x7)
343 }
344 modStr := ""
345 switch mod {
346 case 1:
347 modStr = ".UXTW"
348 case 2:
349 modStr = ".SXTW"
350 }
351 amountStr := ""
352 if amount != 0 {
353 amountStr = fmt.Sprintf("<<%d", amount)
354 }
355 fmt.Fprintf(w, "(%v%s%s)(%v)", Rconv(int(a.Reg)), modStr, amountStr, Rconv(int(a.Index)))
356 }
357 } else {
358 a.WriteNameTo(w)
359 if a.Index != REG_NONE {
360 if a.Scale == 0 {
361
362 fmt.Fprintf(w, "(%v)", Rconv(int(a.Index)))
363 } else {
364 fmt.Fprintf(w, "(%v*%d)", Rconv(int(a.Index)), int(a.Scale))
365 }
366 }
367 }
368
369 case TYPE_CONST:
370 io.WriteString(w, "$")
371 a.WriteNameTo(w)
372 if a.Reg != 0 {
373 fmt.Fprintf(w, "(%v)", Rconv(int(a.Reg)))
374 }
375
376 case TYPE_TEXTSIZE:
377 if a.Val.(int32) == abi.ArgsSizeUnknown {
378 fmt.Fprintf(w, "$%d", a.Offset)
379 } else {
380 fmt.Fprintf(w, "$%d-%d", a.Offset, a.Val.(int32))
381 }
382
383 case TYPE_FCONST:
384 str := fmt.Sprintf("%.17g", a.Val.(float64))
385
386 if !strings.ContainsAny(str, ".e") {
387 str += ".0"
388 }
389 fmt.Fprintf(w, "$(%s)", str)
390
391 case TYPE_SCONST:
392 fmt.Fprintf(w, "$%q", a.Val.(string))
393
394 case TYPE_ADDR:
395 io.WriteString(w, "$")
396 a.writeNameTo(w, abiDetail)
397
398 case TYPE_SHIFT:
399 v := int(a.Offset)
400 ops := "<<>>->@>"
401 switch buildcfg.GOARCH {
402 case "arm":
403 op := ops[((v>>5)&3)<<1:]
404 if v&(1<<4) != 0 {
405 fmt.Fprintf(w, "R%d%c%cR%d", v&15, op[0], op[1], (v>>8)&15)
406 } else {
407 fmt.Fprintf(w, "R%d%c%c%d", v&15, op[0], op[1], (v>>7)&31)
408 }
409 if a.Reg != 0 {
410 fmt.Fprintf(w, "(%v)", Rconv(int(a.Reg)))
411 }
412 case "arm64":
413 op := ops[((v>>22)&3)<<1:]
414 r := (v >> 16) & 31
415 fmt.Fprintf(w, "%s%c%c%d", Rconv(r+RBaseARM64), op[0], op[1], (v>>10)&63)
416 default:
417 panic("TYPE_SHIFT is not supported on " + buildcfg.GOARCH)
418 }
419
420 case TYPE_REGREG:
421 fmt.Fprintf(w, "(%v, %v)", Rconv(int(a.Reg)), Rconv(int(a.Offset)))
422
423 case TYPE_REGREG2:
424 fmt.Fprintf(w, "%v, %v", Rconv(int(a.Offset)), Rconv(int(a.Reg)))
425
426 case TYPE_REGLIST:
427 io.WriteString(w, RLconv(a.Offset))
428
429 case TYPE_SPECIAL:
430 io.WriteString(w, SPCconv(a.Offset))
431 }
432 }
433
434 func (a *Addr) WriteNameTo(w io.Writer) {
435 a.writeNameTo(w, false)
436 }
437
438 func (a *Addr) writeNameTo(w io.Writer, abiDetail bool) {
439
440 switch a.Name {
441 default:
442 fmt.Fprintf(w, "name=%d", a.Name)
443
444 case NAME_NONE:
445 switch {
446 case a.Reg == REG_NONE:
447 fmt.Fprint(w, a.Offset)
448 case a.Offset == 0:
449 fmt.Fprintf(w, "(%v)", Rconv(int(a.Reg)))
450 case a.Offset != 0:
451 fmt.Fprintf(w, "%d(%v)", a.Offset, Rconv(int(a.Reg)))
452 }
453
454
455 case NAME_EXTERN:
456 reg := "SB"
457 if a.Reg != REG_NONE {
458 reg = Rconv(int(a.Reg))
459 }
460 if a.Sym != nil {
461 fmt.Fprintf(w, "%s%s%s(%s)", a.Sym.Name, abiDecorate(a, abiDetail), offConv(a.Offset), reg)
462 } else {
463 fmt.Fprintf(w, "%s(%s)", offConv(a.Offset), reg)
464 }
465
466 case NAME_GOTREF:
467 reg := "SB"
468 if a.Reg != REG_NONE {
469 reg = Rconv(int(a.Reg))
470 }
471 if a.Sym != nil {
472 fmt.Fprintf(w, "%s%s@GOT(%s)", a.Sym.Name, offConv(a.Offset), reg)
473 } else {
474 fmt.Fprintf(w, "%s@GOT(%s)", offConv(a.Offset), reg)
475 }
476
477 case NAME_STATIC:
478 reg := "SB"
479 if a.Reg != REG_NONE {
480 reg = Rconv(int(a.Reg))
481 }
482 if a.Sym != nil {
483 fmt.Fprintf(w, "%s<>%s(%s)", a.Sym.Name, offConv(a.Offset), reg)
484 } else {
485 fmt.Fprintf(w, "<>%s(%s)", offConv(a.Offset), reg)
486 }
487
488 case NAME_AUTO:
489 reg := "SP"
490 if a.Reg != REG_NONE {
491 reg = Rconv(int(a.Reg))
492 }
493 if a.Sym != nil {
494 fmt.Fprintf(w, "%s%s(%s)", a.Sym.Name, offConv(a.Offset), reg)
495 } else {
496 fmt.Fprintf(w, "%s(%s)", offConv(a.Offset), reg)
497 }
498
499 case NAME_PARAM:
500 reg := "FP"
501 if a.Reg != REG_NONE {
502 reg = Rconv(int(a.Reg))
503 }
504 if a.Sym != nil {
505 fmt.Fprintf(w, "%s%s(%s)", a.Sym.Name, offConv(a.Offset), reg)
506 } else {
507 fmt.Fprintf(w, "%s(%s)", offConv(a.Offset), reg)
508 }
509 case NAME_TOCREF:
510 reg := "SB"
511 if a.Reg != REG_NONE {
512 reg = Rconv(int(a.Reg))
513 }
514 if a.Sym != nil {
515 fmt.Fprintf(w, "%s%s(%s)", a.Sym.Name, offConv(a.Offset), reg)
516 } else {
517 fmt.Fprintf(w, "%s(%s)", offConv(a.Offset), reg)
518 }
519 }
520 }
521
522 func offConv(off int64) string {
523 if off == 0 {
524 return ""
525 }
526 return fmt.Sprintf("%+d", off)
527 }
528
529
530
531
532
533
534
535 type opSuffixSet struct {
536 arch string
537 cconv func(suffix uint8) string
538 }
539
540 var opSuffixSpace []opSuffixSet
541
542
543
544
545
546 func RegisterOpSuffix(arch string, cconv func(uint8) string) {
547 opSuffixSpace = append(opSuffixSpace, opSuffixSet{
548 arch: arch,
549 cconv: cconv,
550 })
551 }
552
553 type regSet struct {
554 lo int
555 hi int
556 Rconv func(int) string
557 }
558
559
560
561 var regSpace []regSet
562
563
568
569 const (
570
571
572 RBase386 = 1 * 1024
573 RBaseAMD64 = 2 * 1024
574 RBaseARM = 3 * 1024
575 RBasePPC64 = 4 * 1024
576 RBaseARM64 = 8 * 1024
577 RBaseMIPS = 18 * 1024
578 RBaseS390X = 19 * 1024
579 RBaseRISCV = 20 * 1024
580 RBaseWasm = 21 * 1024
581 RBaseLOONG64 = 22 * 1024
582 )
583
584
585
586
587 func RegisterRegister(lo, hi int, Rconv func(int) string) {
588 regSpace = append(regSpace, regSet{lo, hi, Rconv})
589 }
590
591 func Rconv(reg int) string {
592 if reg == REG_NONE {
593 return "NONE"
594 }
595 for i := range regSpace {
596 rs := ®Space[i]
597 if rs.lo <= reg && reg < rs.hi {
598 return rs.Rconv(reg)
599 }
600 }
601 return fmt.Sprintf("R???%d", reg)
602 }
603
604 type regListSet struct {
605 lo int64
606 hi int64
607 RLconv func(int64) string
608 }
609
610 var regListSpace []regListSet
611
612
613
614 const (
615 RegListARMLo = 0
616 RegListARMHi = 1 << 16
617
618
619 RegListARM64Lo = 1 << 60
620 RegListARM64Hi = 1<<61 - 1
621
622
623 RegListX86Lo = 1 << 61
624 RegListX86Hi = 1<<62 - 1
625 )
626
627
628
629
630 func RegisterRegisterList(lo, hi int64, rlconv func(int64) string) {
631 regListSpace = append(regListSpace, regListSet{lo, hi, rlconv})
632 }
633
634 func RLconv(list int64) string {
635 for i := range regListSpace {
636 rls := ®ListSpace[i]
637 if rls.lo <= list && list < rls.hi {
638 return rls.RLconv(list)
639 }
640 }
641 return fmt.Sprintf("RL???%d", list)
642 }
643
644
645 type spcSet struct {
646 lo int64
647 hi int64
648 SPCconv func(int64) string
649 }
650
651 var spcSpace []spcSet
652
653
654
655 const (
656 SpecialOperandARM64Base = 0 << 16
657 SpecialOperandRISCVBase = 1 << 16
658 )
659
660
661
662
663 func RegisterSpecialOperands(lo, hi int64, rlconv func(int64) string) {
664 spcSpace = append(spcSpace, spcSet{lo, hi, rlconv})
665 }
666
667
668 func SPCconv(spc int64) string {
669 for i := range spcSpace {
670 spcs := &spcSpace[i]
671 if spcs.lo <= spc && spc < spcs.hi {
672 return spcs.SPCconv(spc)
673 }
674 }
675 return fmt.Sprintf("SPC???%d", spc)
676 }
677
678 type opSet struct {
679 lo As
680 names []string
681 }
682
683
684 var aSpace []opSet
685
686
687
688 func RegisterOpcode(lo As, Anames []string) {
689 if len(Anames) > AllowedOpCodes {
690 panic(fmt.Sprintf("too many instructions, have %d max %d", len(Anames), AllowedOpCodes))
691 }
692 aSpace = append(aSpace, opSet{lo, Anames})
693 }
694
695 func (a As) String() string {
696 if 0 <= a && int(a) < len(Anames) {
697 return Anames[a]
698 }
699 for i := range aSpace {
700 as := &aSpace[i]
701 if as.lo <= a && int(a-as.lo) < len(as.names) {
702 return as.names[a-as.lo]
703 }
704 }
705 return fmt.Sprintf("A???%d", a)
706 }
707
708 var Anames = []string{
709 "XXX",
710 "CALL",
711 "DUFFCOPY",
712 "DUFFZERO",
713 "END",
714 "FUNCDATA",
715 "JMP",
716 "NOP",
717 "PCALIGN",
718 "PCALIGNMAX",
719 "PCDATA",
720 "RET",
721 "GETCALLERPC",
722 "TEXT",
723 "UNDEF",
724 }
725
726 func Bool2int(b bool) int {
727
728
729 var i int
730 if b {
731 i = 1
732 } else {
733 i = 0
734 }
735 return i
736 }
737
738 func abiDecorate(a *Addr, abiDetail bool) string {
739 if !abiDetail || a.Sym == nil {
740 return ""
741 }
742 return fmt.Sprintf("<%s>", a.Sym.ABI())
743 }
744
745
746
747
748
749
750
751
752
753
754 func AlignmentPadding(pc int32, p *Prog, ctxt *Link, cursym *LSym) int {
755 v := AlignmentPaddingLength(pc, p, ctxt)
756 requireAlignment(p.From.Offset, ctxt, cursym)
757 return v
758 }
759
760
761
762
763
764
765
766
767
768
769 func AlignmentPaddingLength(pc int32, p *Prog, ctxt *Link) int {
770 a := p.From.Offset
771 if !((a&(a-1) == 0) && 8 <= a && a <= 2048) {
772 ctxt.Diag("alignment value of an instruction must be a power of two and in the range [8, 2048], got %d\n", a)
773 return 0
774 }
775 pc64 := int64(pc)
776 lob := pc64 & (a - 1)
777 if p.As == APCALIGN {
778 if lob != 0 {
779 return int(a - lob)
780 }
781 return 0
782 }
783
784 s := p.To.Offset
785 if s < 0 || s >= a {
786 ctxt.Diag("PCALIGNMAX 'amount' %d must be non-negative and smaller than the alignment %d\n", s, a)
787 return 0
788 }
789 if s >= a-lob {
790 return int(a - lob)
791 }
792 return 0
793 }
794
795
796
797 func requireAlignment(a int64, ctxt *Link, cursym *LSym) {
798
799 if ctxt.Headtype != objabi.Haix && cursym.Align < int16(a) {
800 cursym.Align = int16(a)
801 }
802 }
803
View as plain text