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