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