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