1
2
3
4
5 package obj
6
7 import (
8 "bytes"
9 "cmd/internal/objabi"
10 "fmt"
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 }
201 if p.RegTo2 != REG_NONE {
202 fmt.Fprintf(w, "%s%v", sep, Rconv(int(p.RegTo2)))
203 }
204 for i := range p.RestArgs {
205 if p.RestArgs[i].Pos == Destination {
206 io.WriteString(w, sep)
207 WriteDconv(w, p, &p.RestArgs[i].Addr)
208 sep = ", "
209 }
210 }
211 }
212
213 func (ctxt *Link) NewProg() *Prog {
214 p := new(Prog)
215 p.Ctxt = ctxt
216 return p
217 }
218
219 func (ctxt *Link) CanReuseProgs() bool {
220 return ctxt.Debugasm == 0
221 }
222
223
224
225 func Dconv(p *Prog, a *Addr) string {
226 buf := new(bytes.Buffer)
227 writeDconv(buf, p, a, false)
228 return buf.String()
229 }
230
231
232
233
234 func DconvWithABIDetail(p *Prog, a *Addr) string {
235 buf := new(bytes.Buffer)
236 writeDconv(buf, p, a, true)
237 return buf.String()
238 }
239
240
241
242 func WriteDconv(w io.Writer, p *Prog, a *Addr) {
243 writeDconv(w, p, a, false)
244 }
245
246 func writeDconv(w io.Writer, p *Prog, a *Addr, abiDetail bool) {
247 switch a.Type {
248 default:
249 fmt.Fprintf(w, "type=%d", a.Type)
250
251 case TYPE_NONE:
252 if a.Name != NAME_NONE || a.Reg != 0 || a.Sym != nil {
253 a.WriteNameTo(w)
254 fmt.Fprintf(w, "(%v)(NONE)", Rconv(int(a.Reg)))
255 }
256
257 case TYPE_REG:
258
259
260
261
262 if a.Offset != 0 && (a.Reg < RBaseARM64 || a.Reg >= RBaseMIPS) {
263 fmt.Fprintf(w, "$%d,%v", a.Offset, Rconv(int(a.Reg)))
264 return
265 }
266
267 if a.Name != NAME_NONE || a.Sym != nil {
268 a.WriteNameTo(w)
269 fmt.Fprintf(w, "(%v)(REG)", Rconv(int(a.Reg)))
270 } else {
271 io.WriteString(w, Rconv(int(a.Reg)))
272 }
273 if (RBaseARM64+1<<10+1<<9) <= a.Reg &&
274 a.Reg < (RBaseARM64+1<<11) {
275 fmt.Fprintf(w, "[%d]", a.Index)
276 }
277
278 case TYPE_BRANCH:
279 if a.Sym != nil {
280 fmt.Fprintf(w, "%s%s(SB)", a.Sym.Name, abiDecorate(a, abiDetail))
281 } else if a.Target() != nil {
282 fmt.Fprint(w, a.Target().Pc)
283 } else {
284 fmt.Fprintf(w, "%d(PC)", a.Offset)
285 }
286
287 case TYPE_INDIR:
288 io.WriteString(w, "*")
289 a.writeNameTo(w, abiDetail)
290
291 case TYPE_MEM:
292 a.WriteNameTo(w)
293 if a.Index != REG_NONE {
294 if a.Scale == 0 {
295
296 fmt.Fprintf(w, "(%v)", Rconv(int(a.Index)))
297 } else {
298 fmt.Fprintf(w, "(%v*%d)", Rconv(int(a.Index)), int(a.Scale))
299 }
300 }
301
302 case TYPE_CONST:
303 io.WriteString(w, "$")
304 a.WriteNameTo(w)
305 if a.Reg != 0 {
306 fmt.Fprintf(w, "(%v)", Rconv(int(a.Reg)))
307 }
308
309 case TYPE_TEXTSIZE:
310 if a.Val.(int32) == objabi.ArgsSizeUnknown {
311 fmt.Fprintf(w, "$%d", a.Offset)
312 } else {
313 fmt.Fprintf(w, "$%d-%d", a.Offset, a.Val.(int32))
314 }
315
316 case TYPE_FCONST:
317 str := fmt.Sprintf("%.17g", a.Val.(float64))
318
319 if !strings.ContainsAny(str, ".e") {
320 str += ".0"
321 }
322 fmt.Fprintf(w, "$(%s)", str)
323
324 case TYPE_SCONST:
325 fmt.Fprintf(w, "$%q", a.Val.(string))
326
327 case TYPE_ADDR:
328 io.WriteString(w, "$")
329 a.writeNameTo(w, abiDetail)
330
331 case TYPE_SHIFT:
332 v := int(a.Offset)
333 ops := "<<>>->@>"
334 switch buildcfg.GOARCH {
335 case "arm":
336 op := ops[((v>>5)&3)<<1:]
337 if v&(1<<4) != 0 {
338 fmt.Fprintf(w, "R%d%c%cR%d", v&15, op[0], op[1], (v>>8)&15)
339 } else {
340 fmt.Fprintf(w, "R%d%c%c%d", v&15, op[0], op[1], (v>>7)&31)
341 }
342 if a.Reg != 0 {
343 fmt.Fprintf(w, "(%v)", Rconv(int(a.Reg)))
344 }
345 case "arm64":
346 op := ops[((v>>22)&3)<<1:]
347 r := (v >> 16) & 31
348 fmt.Fprintf(w, "%s%c%c%d", Rconv(r+RBaseARM64), op[0], op[1], (v>>10)&63)
349 default:
350 panic("TYPE_SHIFT is not supported on " + buildcfg.GOARCH)
351 }
352
353 case TYPE_REGREG:
354 fmt.Fprintf(w, "(%v, %v)", Rconv(int(a.Reg)), Rconv(int(a.Offset)))
355
356 case TYPE_REGREG2:
357 fmt.Fprintf(w, "%v, %v", Rconv(int(a.Offset)), Rconv(int(a.Reg)))
358
359 case TYPE_REGLIST:
360 io.WriteString(w, RLconv(a.Offset))
361 }
362 }
363
364 func (a *Addr) WriteNameTo(w io.Writer) {
365 a.writeNameTo(w, false)
366 }
367
368 func (a *Addr) writeNameTo(w io.Writer, abiDetail bool) {
369
370 switch a.Name {
371 default:
372 fmt.Fprintf(w, "name=%d", a.Name)
373
374 case NAME_NONE:
375 switch {
376 case a.Reg == REG_NONE:
377 fmt.Fprint(w, a.Offset)
378 case a.Offset == 0:
379 fmt.Fprintf(w, "(%v)", Rconv(int(a.Reg)))
380 case a.Offset != 0:
381 fmt.Fprintf(w, "%d(%v)", a.Offset, Rconv(int(a.Reg)))
382 }
383
384
385 case NAME_EXTERN:
386 reg := "SB"
387 if a.Reg != REG_NONE {
388 reg = Rconv(int(a.Reg))
389 }
390 if a.Sym != nil {
391 fmt.Fprintf(w, "%s%s%s(%s)", a.Sym.Name, abiDecorate(a, abiDetail), offConv(a.Offset), reg)
392 } else {
393 fmt.Fprintf(w, "%s(%s)", offConv(a.Offset), reg)
394 }
395
396 case NAME_GOTREF:
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@GOT(%s)", a.Sym.Name, offConv(a.Offset), reg)
403 } else {
404 fmt.Fprintf(w, "%s@GOT(%s)", offConv(a.Offset), reg)
405 }
406
407 case NAME_STATIC:
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(%s)", a.Sym.Name, offConv(a.Offset), reg)
414 } else {
415 fmt.Fprintf(w, "<>%s(%s)", offConv(a.Offset), reg)
416 }
417
418 case NAME_AUTO:
419 reg := "SP"
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_PARAM:
430 reg := "FP"
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 case NAME_TOCREF:
440 reg := "SB"
441 if a.Reg != REG_NONE {
442 reg = Rconv(int(a.Reg))
443 }
444 if a.Sym != nil {
445 fmt.Fprintf(w, "%s%s(%s)", a.Sym.Name, offConv(a.Offset), reg)
446 } else {
447 fmt.Fprintf(w, "%s(%s)", offConv(a.Offset), reg)
448 }
449 }
450 }
451
452 func offConv(off int64) string {
453 if off == 0 {
454 return ""
455 }
456 return fmt.Sprintf("%+d", off)
457 }
458
459
460
461
462
463
464
465 type opSuffixSet struct {
466 arch string
467 cconv func(suffix uint8) string
468 }
469
470 var opSuffixSpace []opSuffixSet
471
472
473
474
475
476 func RegisterOpSuffix(arch string, cconv func(uint8) string) {
477 opSuffixSpace = append(opSuffixSpace, opSuffixSet{
478 arch: arch,
479 cconv: cconv,
480 })
481 }
482
483 type regSet struct {
484 lo int
485 hi int
486 Rconv func(int) string
487 }
488
489
490
491 var regSpace []regSet
492
493
498
499 const (
500
501
502 RBase386 = 1 * 1024
503 RBaseAMD64 = 2 * 1024
504 RBaseARM = 3 * 1024
505 RBasePPC64 = 4 * 1024
506 RBaseARM64 = 8 * 1024
507 RBaseMIPS = 13 * 1024
508 RBaseS390X = 14 * 1024
509 RBaseRISCV = 15 * 1024
510 RBaseWasm = 16 * 1024
511 )
512
513
514
515
516 func RegisterRegister(lo, hi int, Rconv func(int) string) {
517 regSpace = append(regSpace, regSet{lo, hi, Rconv})
518 }
519
520 func Rconv(reg int) string {
521 if reg == REG_NONE {
522 return "NONE"
523 }
524 for i := range regSpace {
525 rs := ®Space[i]
526 if rs.lo <= reg && reg < rs.hi {
527 return rs.Rconv(reg)
528 }
529 }
530 return fmt.Sprintf("R???%d", reg)
531 }
532
533 type regListSet struct {
534 lo int64
535 hi int64
536 RLconv func(int64) string
537 }
538
539 var regListSpace []regListSet
540
541
542
543 const (
544 RegListARMLo = 0
545 RegListARMHi = 1 << 16
546
547
548 RegListARM64Lo = 1 << 60
549 RegListARM64Hi = 1<<61 - 1
550
551
552 RegListX86Lo = 1 << 61
553 RegListX86Hi = 1<<62 - 1
554 )
555
556
557
558
559 func RegisterRegisterList(lo, hi int64, rlconv func(int64) string) {
560 regListSpace = append(regListSpace, regListSet{lo, hi, rlconv})
561 }
562
563 func RLconv(list int64) string {
564 for i := range regListSpace {
565 rls := ®ListSpace[i]
566 if rls.lo <= list && list < rls.hi {
567 return rls.RLconv(list)
568 }
569 }
570 return fmt.Sprintf("RL???%d", list)
571 }
572
573 type opSet struct {
574 lo As
575 names []string
576 }
577
578
579 var aSpace []opSet
580
581
582
583 func RegisterOpcode(lo As, Anames []string) {
584 if len(Anames) > AllowedOpCodes {
585 panic(fmt.Sprintf("too many instructions, have %d max %d", len(Anames), AllowedOpCodes))
586 }
587 aSpace = append(aSpace, opSet{lo, Anames})
588 }
589
590 func (a As) String() string {
591 if 0 <= a && int(a) < len(Anames) {
592 return Anames[a]
593 }
594 for i := range aSpace {
595 as := &aSpace[i]
596 if as.lo <= a && int(a-as.lo) < len(as.names) {
597 return as.names[a-as.lo]
598 }
599 }
600 return fmt.Sprintf("A???%d", a)
601 }
602
603 var Anames = []string{
604 "XXX",
605 "CALL",
606 "DUFFCOPY",
607 "DUFFZERO",
608 "END",
609 "FUNCDATA",
610 "JMP",
611 "NOP",
612 "PCALIGN",
613 "PCDATA",
614 "RET",
615 "GETCALLERPC",
616 "TEXT",
617 "UNDEF",
618 }
619
620 func Bool2int(b bool) int {
621
622
623 var i int
624 if b {
625 i = 1
626 } else {
627 i = 0
628 }
629 return i
630 }
631
632 func abiDecorate(a *Addr, abiDetail bool) string {
633 if !abiDetail || a.Sym == nil {
634 return ""
635 }
636 return fmt.Sprintf("<%s>", a.Sym.ABI())
637 }
638
View as plain text