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