1
2
3
4
5 package obj
6
7 import (
8 "bytes"
9 "cmd/internal/objabi"
10 "cmd/internal/src"
11 "fmt"
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 func (p *Prog) AllPos(result []src.Pos) []src.Pos {
52 return p.Ctxt.AllPos(p.Pos, result)
53 }
54
55 var armCondCode = []string{
56 ".EQ",
57 ".NE",
58 ".CS",
59 ".CC",
60 ".MI",
61 ".PL",
62 ".VS",
63 ".VC",
64 ".HI",
65 ".LS",
66 ".GE",
67 ".LT",
68 ".GT",
69 ".LE",
70 "",
71 ".NV",
72 }
73
74
75 const (
76 C_SCOND = (1 << 4) - 1
77 C_SBIT = 1 << 4
78 C_PBIT = 1 << 5
79 C_WBIT = 1 << 6
80 C_FBIT = 1 << 7
81 C_UBIT = 1 << 7
82 C_SCOND_XOR = 14
83 )
84
85
86 func CConv(s uint8) string {
87 if s == 0 {
88 return ""
89 }
90 for i := range opSuffixSpace {
91 sset := &opSuffixSpace[i]
92 if sset.arch == buildcfg.GOARCH {
93 return sset.cconv(s)
94 }
95 }
96 return fmt.Sprintf("SC???%d", s)
97 }
98
99
100 func CConvARM(s uint8) string {
101
102
103
104
105 sc := armCondCode[(s&C_SCOND)^C_SCOND_XOR]
106 if s&C_SBIT != 0 {
107 sc += ".S"
108 }
109 if s&C_PBIT != 0 {
110 sc += ".P"
111 }
112 if s&C_WBIT != 0 {
113 sc += ".W"
114 }
115 if s&C_UBIT != 0 {
116 sc += ".U"
117 }
118 return sc
119 }
120
121 func (p *Prog) String() string {
122 if p == nil {
123 return "<nil Prog>"
124 }
125 if p.Ctxt == nil {
126 return "<Prog without ctxt>"
127 }
128 return fmt.Sprintf("%.5d (%v)\t%s", p.Pc, p.Line(), p.InstructionString())
129 }
130
131 func (p *Prog) InnermostString(w io.Writer) {
132 if p == nil {
133 io.WriteString(w, "<nil Prog>")
134 return
135 }
136 if p.Ctxt == nil {
137 io.WriteString(w, "<Prog without ctxt>")
138 return
139 }
140 fmt.Fprintf(w, "%.5d (", p.Pc)
141 p.InnermostLine(w)
142 io.WriteString(w, ")\t")
143 p.WriteInstructionString(w)
144 }
145
146
147
148 func (p *Prog) InstructionString() string {
149 buf := new(bytes.Buffer)
150 p.WriteInstructionString(buf)
151 return buf.String()
152 }
153
154
155
156 func (p *Prog) WriteInstructionString(w io.Writer) {
157 if p == nil {
158 io.WriteString(w, "<nil Prog>")
159 return
160 }
161
162 if p.Ctxt == nil {
163 io.WriteString(w, "<Prog without ctxt>")
164 return
165 }
166
167 sc := CConv(p.Scond)
168
169 io.WriteString(w, p.As.String())
170 io.WriteString(w, sc)
171 sep := "\t"
172
173 if p.From.Type != TYPE_NONE {
174 io.WriteString(w, sep)
175 WriteDconv(w, p, &p.From)
176 sep = ", "
177 }
178 if p.Reg != REG_NONE {
179
180 fmt.Fprintf(w, "%s%v", sep, Rconv(int(p.Reg)))
181 sep = ", "
182 }
183 for i := range p.RestArgs {
184 if p.RestArgs[i].Pos == Source {
185 io.WriteString(w, sep)
186 WriteDconv(w, p, &p.RestArgs[i].Addr)
187 sep = ", "
188 }
189 }
190
191 if p.As == ATEXT {
192
193
194
195
196 s := p.From.Sym.TextAttrString()
197 if s != "" {
198 fmt.Fprintf(w, "%s%s", sep, s)
199 sep = ", "
200 }
201 }
202 if p.To.Type != TYPE_NONE {
203 io.WriteString(w, sep)
204 WriteDconv(w, p, &p.To)
205 }
206 if p.RegTo2 != REG_NONE {
207 fmt.Fprintf(w, "%s%v", sep, Rconv(int(p.RegTo2)))
208 }
209 for i := range p.RestArgs {
210 if p.RestArgs[i].Pos == Destination {
211 io.WriteString(w, sep)
212 WriteDconv(w, p, &p.RestArgs[i].Addr)
213 sep = ", "
214 }
215 }
216 }
217
218 func (ctxt *Link) NewProg() *Prog {
219 p := new(Prog)
220 p.Ctxt = ctxt
221 return p
222 }
223
224 func (ctxt *Link) CanReuseProgs() bool {
225 return ctxt.Debugasm == 0
226 }
227
228
229
230 func Dconv(p *Prog, a *Addr) string {
231 buf := new(bytes.Buffer)
232 writeDconv(buf, p, a, false)
233 return buf.String()
234 }
235
236
237
238
239 func DconvWithABIDetail(p *Prog, a *Addr) string {
240 buf := new(bytes.Buffer)
241 writeDconv(buf, p, a, true)
242 return buf.String()
243 }
244
245
246
247 func WriteDconv(w io.Writer, p *Prog, a *Addr) {
248 writeDconv(w, p, a, false)
249 }
250
251 func writeDconv(w io.Writer, p *Prog, a *Addr, abiDetail bool) {
252 switch a.Type {
253 default:
254 fmt.Fprintf(w, "type=%d", a.Type)
255
256 case TYPE_NONE:
257 if a.Name != NAME_NONE || a.Reg != 0 || a.Sym != nil {
258 a.WriteNameTo(w)
259 fmt.Fprintf(w, "(%v)(NONE)", Rconv(int(a.Reg)))
260 }
261
262 case TYPE_REG:
263
264
265
266
267 if a.Offset != 0 && (a.Reg < RBaseARM64 || a.Reg >= RBaseMIPS) {
268 fmt.Fprintf(w, "$%d,%v", a.Offset, Rconv(int(a.Reg)))
269 return
270 }
271
272 if a.Name != NAME_NONE || a.Sym != nil {
273 a.WriteNameTo(w)
274 fmt.Fprintf(w, "(%v)(REG)", Rconv(int(a.Reg)))
275 } else {
276 io.WriteString(w, Rconv(int(a.Reg)))
277 }
278 if (RBaseARM64+1<<10+1<<9) <= a.Reg &&
279 a.Reg < (RBaseARM64+1<<11) {
280 fmt.Fprintf(w, "[%d]", a.Index)
281 }
282
283 case TYPE_BRANCH:
284 if a.Sym != nil {
285 fmt.Fprintf(w, "%s%s(SB)", a.Sym.Name, abiDecorate(a, abiDetail))
286 } else if a.Target() != nil {
287 fmt.Fprint(w, a.Target().Pc)
288 } else {
289 fmt.Fprintf(w, "%d(PC)", a.Offset)
290 }
291
292 case TYPE_INDIR:
293 io.WriteString(w, "*")
294 a.writeNameTo(w, abiDetail)
295
296 case TYPE_MEM:
297 a.WriteNameTo(w)
298 if a.Index != REG_NONE {
299 if a.Scale == 0 {
300
301 fmt.Fprintf(w, "(%v)", Rconv(int(a.Index)))
302 } else {
303 fmt.Fprintf(w, "(%v*%d)", Rconv(int(a.Index)), int(a.Scale))
304 }
305 }
306
307 case TYPE_CONST:
308 io.WriteString(w, "$")
309 a.WriteNameTo(w)
310 if a.Reg != 0 {
311 fmt.Fprintf(w, "(%v)", Rconv(int(a.Reg)))
312 }
313
314 case TYPE_TEXTSIZE:
315 if a.Val.(int32) == objabi.ArgsSizeUnknown {
316 fmt.Fprintf(w, "$%d", a.Offset)
317 } else {
318 fmt.Fprintf(w, "$%d-%d", a.Offset, a.Val.(int32))
319 }
320
321 case TYPE_FCONST:
322 str := fmt.Sprintf("%.17g", a.Val.(float64))
323
324 if !strings.ContainsAny(str, ".e") {
325 str += ".0"
326 }
327 fmt.Fprintf(w, "$(%s)", str)
328
329 case TYPE_SCONST:
330 fmt.Fprintf(w, "$%q", a.Val.(string))
331
332 case TYPE_ADDR:
333 io.WriteString(w, "$")
334 a.writeNameTo(w, abiDetail)
335
336 case TYPE_SHIFT:
337 v := int(a.Offset)
338 ops := "<<>>->@>"
339 switch buildcfg.GOARCH {
340 case "arm":
341 op := ops[((v>>5)&3)<<1:]
342 if v&(1<<4) != 0 {
343 fmt.Fprintf(w, "R%d%c%cR%d", v&15, op[0], op[1], (v>>8)&15)
344 } else {
345 fmt.Fprintf(w, "R%d%c%c%d", v&15, op[0], op[1], (v>>7)&31)
346 }
347 if a.Reg != 0 {
348 fmt.Fprintf(w, "(%v)", Rconv(int(a.Reg)))
349 }
350 case "arm64":
351 op := ops[((v>>22)&3)<<1:]
352 r := (v >> 16) & 31
353 fmt.Fprintf(w, "%s%c%c%d", Rconv(r+RBaseARM64), op[0], op[1], (v>>10)&63)
354 default:
355 panic("TYPE_SHIFT is not supported on " + buildcfg.GOARCH)
356 }
357
358 case TYPE_REGREG:
359 fmt.Fprintf(w, "(%v, %v)", Rconv(int(a.Reg)), Rconv(int(a.Offset)))
360
361 case TYPE_REGREG2:
362 fmt.Fprintf(w, "%v, %v", Rconv(int(a.Offset)), Rconv(int(a.Reg)))
363
364 case TYPE_REGLIST:
365 io.WriteString(w, RLconv(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 )
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 type opSet struct {
579 lo As
580 names []string
581 }
582
583
584 var aSpace []opSet
585
586
587
588 func RegisterOpcode(lo As, Anames []string) {
589 if len(Anames) > AllowedOpCodes {
590 panic(fmt.Sprintf("too many instructions, have %d max %d", len(Anames), AllowedOpCodes))
591 }
592 aSpace = append(aSpace, opSet{lo, Anames})
593 }
594
595 func (a As) String() string {
596 if 0 <= a && int(a) < len(Anames) {
597 return Anames[a]
598 }
599 for i := range aSpace {
600 as := &aSpace[i]
601 if as.lo <= a && int(a-as.lo) < len(as.names) {
602 return as.names[a-as.lo]
603 }
604 }
605 return fmt.Sprintf("A???%d", a)
606 }
607
608 var Anames = []string{
609 "XXX",
610 "CALL",
611 "DUFFCOPY",
612 "DUFFZERO",
613 "END",
614 "FUNCDATA",
615 "JMP",
616 "NOP",
617 "PCALIGN",
618 "PCDATA",
619 "RET",
620 "GETCALLERPC",
621 "TEXT",
622 "UNDEF",
623 }
624
625 func Bool2int(b bool) int {
626
627
628 var i int
629 if b {
630 i = 1
631 } else {
632 i = 0
633 }
634 return i
635 }
636
637 func abiDecorate(a *Addr, abiDetail bool) string {
638 if !abiDetail || a.Sym == nil {
639 return ""
640 }
641 return fmt.Sprintf("<%s>", a.Sym.ABI())
642 }
643
View as plain text