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
226
227 func Dconv(p *Prog, a *Addr) string {
228 buf := new(bytes.Buffer)
229 writeDconv(buf, p, a, false)
230 return buf.String()
231 }
232
233
234
235
236 func DconvWithABIDetail(p *Prog, a *Addr) string {
237 buf := new(bytes.Buffer)
238 writeDconv(buf, p, a, true)
239 return buf.String()
240 }
241
242
243
244 func WriteDconv(w io.Writer, p *Prog, a *Addr) {
245 writeDconv(w, p, a, false)
246 }
247
248 func writeDconv(w io.Writer, p *Prog, a *Addr, abiDetail bool) {
249 switch a.Type {
250 default:
251 fmt.Fprintf(w, "type=%d", a.Type)
252
253 case TYPE_NONE:
254 if a.Name != NAME_NONE || a.Reg != 0 || a.Sym != nil {
255 a.WriteNameTo(w)
256 fmt.Fprintf(w, "(%v)(NONE)", Rconv(int(a.Reg)))
257 }
258
259 case TYPE_REG:
260
261
262
263
264 if a.Offset != 0 && (a.Reg < RBaseARM64 || a.Reg >= RBaseMIPS) {
265 fmt.Fprintf(w, "$%d,%v", a.Offset, Rconv(int(a.Reg)))
266 return
267 }
268
269 if a.Name != NAME_NONE || a.Sym != nil {
270 a.WriteNameTo(w)
271 fmt.Fprintf(w, "(%v)(REG)", Rconv(int(a.Reg)))
272 } else {
273 io.WriteString(w, Rconv(int(a.Reg)))
274 }
275
276 if (RBaseARM64+1<<10+1<<9) <= a.Reg &&
277 a.Reg < (RBaseARM64+1<<11) {
278 fmt.Fprintf(w, "[%d]", a.Index)
279 }
280
281 if (RBaseLOONG64+(1<<10)+(1<<11)) <= a.Reg &&
282 a.Reg < (RBaseLOONG64+(1<<10)+(2<<11)) {
283 fmt.Fprintf(w, "[%d]", a.Index)
284 }
285
286 case TYPE_BRANCH:
287 if a.Sym != nil {
288 fmt.Fprintf(w, "%s%s(SB)", a.Sym.Name, abiDecorate(a, abiDetail))
289 } else if a.Target() != nil {
290 fmt.Fprint(w, a.Target().Pc)
291 } else {
292 fmt.Fprintf(w, "%d(PC)", a.Offset)
293 }
294
295 case TYPE_INDIR:
296 io.WriteString(w, "*")
297 a.writeNameTo(w, abiDetail)
298
299 case TYPE_MEM:
300 a.WriteNameTo(w)
301 if a.Index != REG_NONE {
302 if a.Scale == 0 {
303
304 fmt.Fprintf(w, "(%v)", Rconv(int(a.Index)))
305 } else {
306 fmt.Fprintf(w, "(%v*%d)", Rconv(int(a.Index)), int(a.Scale))
307 }
308 }
309
310 case TYPE_CONST:
311 io.WriteString(w, "$")
312 a.WriteNameTo(w)
313 if a.Reg != 0 {
314 fmt.Fprintf(w, "(%v)", Rconv(int(a.Reg)))
315 }
316
317 case TYPE_TEXTSIZE:
318 if a.Val.(int32) == abi.ArgsSizeUnknown {
319 fmt.Fprintf(w, "$%d", a.Offset)
320 } else {
321 fmt.Fprintf(w, "$%d-%d", a.Offset, a.Val.(int32))
322 }
323
324 case TYPE_FCONST:
325 str := fmt.Sprintf("%.17g", a.Val.(float64))
326
327 if !strings.ContainsAny(str, ".e") {
328 str += ".0"
329 }
330 fmt.Fprintf(w, "$(%s)", str)
331
332 case TYPE_SCONST:
333 fmt.Fprintf(w, "$%q", a.Val.(string))
334
335 case TYPE_ADDR:
336 io.WriteString(w, "$")
337 a.writeNameTo(w, abiDetail)
338
339 case TYPE_SHIFT:
340 v := int(a.Offset)
341 ops := "<<>>->@>"
342 switch buildcfg.GOARCH {
343 case "arm":
344 op := ops[((v>>5)&3)<<1:]
345 if v&(1<<4) != 0 {
346 fmt.Fprintf(w, "R%d%c%cR%d", v&15, op[0], op[1], (v>>8)&15)
347 } else {
348 fmt.Fprintf(w, "R%d%c%c%d", v&15, op[0], op[1], (v>>7)&31)
349 }
350 if a.Reg != 0 {
351 fmt.Fprintf(w, "(%v)", Rconv(int(a.Reg)))
352 }
353 case "arm64":
354 op := ops[((v>>22)&3)<<1:]
355 r := (v >> 16) & 31
356 fmt.Fprintf(w, "%s%c%c%d", Rconv(r+RBaseARM64), op[0], op[1], (v>>10)&63)
357 default:
358 panic("TYPE_SHIFT is not supported on " + buildcfg.GOARCH)
359 }
360
361 case TYPE_REGREG:
362 fmt.Fprintf(w, "(%v, %v)", Rconv(int(a.Reg)), Rconv(int(a.Offset)))
363
364 case TYPE_REGREG2:
365 fmt.Fprintf(w, "%v, %v", Rconv(int(a.Offset)), Rconv(int(a.Reg)))
366
367 case TYPE_REGLIST:
368 io.WriteString(w, RLconv(a.Offset))
369
370 case TYPE_SPECIAL:
371 io.WriteString(w, SPCconv(a.Offset))
372 }
373 }
374
375 func (a *Addr) WriteNameTo(w io.Writer) {
376 a.writeNameTo(w, false)
377 }
378
379 func (a *Addr) writeNameTo(w io.Writer, abiDetail bool) {
380
381 switch a.Name {
382 default:
383 fmt.Fprintf(w, "name=%d", a.Name)
384
385 case NAME_NONE:
386 switch {
387 case a.Reg == REG_NONE:
388 fmt.Fprint(w, a.Offset)
389 case a.Offset == 0:
390 fmt.Fprintf(w, "(%v)", Rconv(int(a.Reg)))
391 case a.Offset != 0:
392 fmt.Fprintf(w, "%d(%v)", a.Offset, Rconv(int(a.Reg)))
393 }
394
395
396 case NAME_EXTERN:
397 reg := "SB"
398 if a.Reg != REG_NONE {
399 reg = Rconv(int(a.Reg))
400 }
401 if a.Sym != nil {
402 fmt.Fprintf(w, "%s%s%s(%s)", a.Sym.Name, abiDecorate(a, abiDetail), offConv(a.Offset), reg)
403 } else {
404 fmt.Fprintf(w, "%s(%s)", offConv(a.Offset), reg)
405 }
406
407 case NAME_GOTREF:
408 reg := "SB"
409 if a.Reg != REG_NONE {
410 reg = Rconv(int(a.Reg))
411 }
412 if a.Sym != nil {
413 fmt.Fprintf(w, "%s%s@GOT(%s)", a.Sym.Name, offConv(a.Offset), reg)
414 } else {
415 fmt.Fprintf(w, "%s@GOT(%s)", offConv(a.Offset), reg)
416 }
417
418 case NAME_STATIC:
419 reg := "SB"
420 if a.Reg != REG_NONE {
421 reg = Rconv(int(a.Reg))
422 }
423 if a.Sym != nil {
424 fmt.Fprintf(w, "%s<>%s(%s)", a.Sym.Name, offConv(a.Offset), reg)
425 } else {
426 fmt.Fprintf(w, "<>%s(%s)", offConv(a.Offset), reg)
427 }
428
429 case NAME_AUTO:
430 reg := "SP"
431 if a.Reg != REG_NONE {
432 reg = Rconv(int(a.Reg))
433 }
434 if a.Sym != nil {
435 fmt.Fprintf(w, "%s%s(%s)", a.Sym.Name, offConv(a.Offset), reg)
436 } else {
437 fmt.Fprintf(w, "%s(%s)", offConv(a.Offset), reg)
438 }
439
440 case NAME_PARAM:
441 reg := "FP"
442 if a.Reg != REG_NONE {
443 reg = Rconv(int(a.Reg))
444 }
445 if a.Sym != nil {
446 fmt.Fprintf(w, "%s%s(%s)", a.Sym.Name, offConv(a.Offset), reg)
447 } else {
448 fmt.Fprintf(w, "%s(%s)", offConv(a.Offset), reg)
449 }
450 case NAME_TOCREF:
451 reg := "SB"
452 if a.Reg != REG_NONE {
453 reg = Rconv(int(a.Reg))
454 }
455 if a.Sym != nil {
456 fmt.Fprintf(w, "%s%s(%s)", a.Sym.Name, offConv(a.Offset), reg)
457 } else {
458 fmt.Fprintf(w, "%s(%s)", offConv(a.Offset), reg)
459 }
460 }
461 }
462
463 func offConv(off int64) string {
464 if off == 0 {
465 return ""
466 }
467 return fmt.Sprintf("%+d", off)
468 }
469
470
471
472
473
474
475
476 type opSuffixSet struct {
477 arch string
478 cconv func(suffix uint8) string
479 }
480
481 var opSuffixSpace []opSuffixSet
482
483
484
485
486
487 func RegisterOpSuffix(arch string, cconv func(uint8) string) {
488 opSuffixSpace = append(opSuffixSpace, opSuffixSet{
489 arch: arch,
490 cconv: cconv,
491 })
492 }
493
494 type regSet struct {
495 lo int
496 hi int
497 Rconv func(int) string
498 }
499
500
501
502 var regSpace []regSet
503
504
509
510 const (
511
512
513 RBase386 = 1 * 1024
514 RBaseAMD64 = 2 * 1024
515 RBaseARM = 3 * 1024
516 RBasePPC64 = 4 * 1024
517 RBaseARM64 = 8 * 1024
518 RBaseMIPS = 13 * 1024
519 RBaseS390X = 14 * 1024
520 RBaseRISCV = 15 * 1024
521 RBaseWasm = 16 * 1024
522 RBaseLOONG64 = 19 * 1024
523 )
524
525
526
527
528 func RegisterRegister(lo, hi int, Rconv func(int) string) {
529 regSpace = append(regSpace, regSet{lo, hi, Rconv})
530 }
531
532 func Rconv(reg int) string {
533 if reg == REG_NONE {
534 return "NONE"
535 }
536 for i := range regSpace {
537 rs := ®Space[i]
538 if rs.lo <= reg && reg < rs.hi {
539 return rs.Rconv(reg)
540 }
541 }
542 return fmt.Sprintf("R???%d", reg)
543 }
544
545 type regListSet struct {
546 lo int64
547 hi int64
548 RLconv func(int64) string
549 }
550
551 var regListSpace []regListSet
552
553
554
555 const (
556 RegListARMLo = 0
557 RegListARMHi = 1 << 16
558
559
560 RegListARM64Lo = 1 << 60
561 RegListARM64Hi = 1<<61 - 1
562
563
564 RegListX86Lo = 1 << 61
565 RegListX86Hi = 1<<62 - 1
566 )
567
568
569
570
571 func RegisterRegisterList(lo, hi int64, rlconv func(int64) string) {
572 regListSpace = append(regListSpace, regListSet{lo, hi, rlconv})
573 }
574
575 func RLconv(list int64) string {
576 for i := range regListSpace {
577 rls := ®ListSpace[i]
578 if rls.lo <= list && list < rls.hi {
579 return rls.RLconv(list)
580 }
581 }
582 return fmt.Sprintf("RL???%d", list)
583 }
584
585
586 type spcSet struct {
587 lo int64
588 hi int64
589 SPCconv func(int64) string
590 }
591
592 var spcSpace []spcSet
593
594
595
596
597 func RegisterSpecialOperands(lo, hi int64, rlconv func(int64) string) {
598 spcSpace = append(spcSpace, spcSet{lo, hi, rlconv})
599 }
600
601
602 func SPCconv(spc int64) string {
603 for i := range spcSpace {
604 spcs := &spcSpace[i]
605 if spcs.lo <= spc && spc < spcs.hi {
606 return spcs.SPCconv(spc)
607 }
608 }
609 return fmt.Sprintf("SPC???%d", spc)
610 }
611
612 type opSet struct {
613 lo As
614 names []string
615 }
616
617
618 var aSpace []opSet
619
620
621
622 func RegisterOpcode(lo As, Anames []string) {
623 if len(Anames) > AllowedOpCodes {
624 panic(fmt.Sprintf("too many instructions, have %d max %d", len(Anames), AllowedOpCodes))
625 }
626 aSpace = append(aSpace, opSet{lo, Anames})
627 }
628
629 func (a As) String() string {
630 if 0 <= a && int(a) < len(Anames) {
631 return Anames[a]
632 }
633 for i := range aSpace {
634 as := &aSpace[i]
635 if as.lo <= a && int(a-as.lo) < len(as.names) {
636 return as.names[a-as.lo]
637 }
638 }
639 return fmt.Sprintf("A???%d", a)
640 }
641
642 var Anames = []string{
643 "XXX",
644 "CALL",
645 "DUFFCOPY",
646 "DUFFZERO",
647 "END",
648 "FUNCDATA",
649 "JMP",
650 "NOP",
651 "PCALIGN",
652 "PCALIGNMAX",
653 "PCDATA",
654 "RET",
655 "GETCALLERPC",
656 "TEXT",
657 "UNDEF",
658 }
659
660 func Bool2int(b bool) int {
661
662
663 var i int
664 if b {
665 i = 1
666 } else {
667 i = 0
668 }
669 return i
670 }
671
672 func abiDecorate(a *Addr, abiDetail bool) string {
673 if !abiDetail || a.Sym == nil {
674 return ""
675 }
676 return fmt.Sprintf("<%s>", a.Sym.ABI())
677 }
678
679
680
681
682
683
684
685
686
687
688 func AlignmentPadding(pc int32, p *Prog, ctxt *Link, cursym *LSym) int {
689 v := AlignmentPaddingLength(pc, p, ctxt)
690 requireAlignment(p.From.Offset, ctxt, cursym)
691 return v
692 }
693
694
695
696
697
698
699
700
701
702
703 func AlignmentPaddingLength(pc int32, p *Prog, ctxt *Link) int {
704 a := p.From.Offset
705 if !((a&(a-1) == 0) && 8 <= a && a <= 2048) {
706 ctxt.Diag("alignment value of an instruction must be a power of two and in the range [8, 2048], got %d\n", a)
707 return 0
708 }
709 pc64 := int64(pc)
710 lob := pc64 & (a - 1)
711 if p.As == APCALIGN {
712 if lob != 0 {
713 return int(a - lob)
714 }
715 return 0
716 }
717
718 s := p.To.Offset
719 if s < 0 || s >= a {
720 ctxt.Diag("PCALIGNMAX 'amount' %d must be non-negative and smaller than the aligment %d\n", s, a)
721 return 0
722 }
723 if s >= a-lob {
724 return int(a - lob)
725 }
726 return 0
727 }
728
729
730
731 func requireAlignment(a int64, ctxt *Link, cursym *LSym) {
732
733 if ctxt.Headtype != objabi.Haix && cursym.Func().Align < int32(a) {
734 cursym.Func().Align = int32(a)
735 }
736 }
737
View as plain text