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