1
2
3
4
5 package arm64asm
6
7 import (
8 "fmt"
9 "io"
10 "sort"
11 "strings"
12 )
13
14
15
16
17
18
19
20
21
22
23
24 func GoSyntax(inst Inst, pc uint64, symname func(uint64) (string, uint64), text io.ReaderAt) string {
25 if symname == nil {
26 symname = func(uint64) (string, uint64) { return "", 0 }
27 }
28
29 var args []string
30 for _, a := range inst.Args {
31 if a == nil {
32 break
33 }
34 args = append(args, plan9Arg(&inst, pc, symname, a))
35 }
36
37 op := inst.Op.String()
38
39 switch inst.Op {
40 case LDR, LDRB, LDRH, LDRSB, LDRSH, LDRSW:
41
42 if offset, ok := inst.Args[1].(PCRel); ok {
43 addr := pc + uint64(offset)
44 if _, ok := inst.Args[0].(Reg); !ok {
45 break
46 }
47 if s, base := symname(addr); s != "" && addr == base {
48 args[1] = fmt.Sprintf("$%s(SB)", s)
49 }
50 }
51 }
52
53
54 suffix := ""
55 for i := range inst.Args {
56 switch mem := inst.Args[i].(type) {
57 case MemImmediate:
58 switch mem.Mode {
59 case AddrOffset:
60
61 case AddrPreIndex:
62 suffix += ".W"
63 case AddrPostIndex, AddrPostReg:
64 suffix += ".P"
65 }
66
67 }
68 }
69
70 switch inst.Op {
71 case BL:
72 return "CALL " + args[0]
73
74 case BLR:
75 r := inst.Args[0].(Reg)
76 regno := uint16(r) & 31
77 return fmt.Sprintf("CALL (R%d)", regno)
78
79 case RET:
80 if r, ok := inst.Args[0].(Reg); ok && r == X30 {
81 return "RET"
82 }
83
84 case B:
85 if cond, ok := inst.Args[0].(Cond); ok {
86 return "B" + cond.String() + " " + args[1]
87 }
88 return "JMP" + " " + args[0]
89
90 case BR:
91 r := inst.Args[0].(Reg)
92 regno := uint16(r) & 31
93 return fmt.Sprintf("JMP (R%d)", regno)
94
95 case MOV:
96 rno := -1
97 switch a := inst.Args[0].(type) {
98 case Reg:
99 rno = int(a)
100 case RegSP:
101 rno = int(a)
102 case RegisterWithArrangementAndIndex:
103 op = "VMOV"
104 case RegisterWithArrangement:
105 op = "VMOV"
106 }
107 if rno >= 0 && rno <= int(WZR) {
108 op = "MOVW"
109 } else if rno >= int(X0) && rno <= int(XZR) {
110 op = "MOVD"
111 }
112 if _, ok := inst.Args[1].(RegisterWithArrangementAndIndex); ok {
113 op = "VMOV"
114 }
115
116 case LDR, LDUR:
117 var rno uint16
118 if r, ok := inst.Args[0].(Reg); ok {
119 rno = uint16(r)
120 } else {
121 rno = uint16(inst.Args[0].(RegSP))
122 }
123 if rno <= uint16(WZR) {
124 op = "MOVWU" + suffix
125 } else if rno >= uint16(B0) && rno <= uint16(B31) {
126 op = "FMOVB" + suffix
127 args[0] = fmt.Sprintf("F%d", rno&31)
128 } else if rno >= uint16(H0) && rno <= uint16(H31) {
129 op = "FMOVH" + suffix
130 args[0] = fmt.Sprintf("F%d", rno&31)
131 } else if rno >= uint16(S0) && rno <= uint16(S31) {
132 op = "FMOVS" + suffix
133 args[0] = fmt.Sprintf("F%d", rno&31)
134 } else if rno >= uint16(D0) && rno <= uint16(D31) {
135 op = "FMOVD" + suffix
136 args[0] = fmt.Sprintf("F%d", rno&31)
137 } else if rno >= uint16(Q0) && rno <= uint16(Q31) {
138 op = "FMOVQ" + suffix
139 args[0] = fmt.Sprintf("F%d", rno&31)
140 } else {
141 op = "MOVD" + suffix
142 }
143
144 case LDRB:
145 op = "MOVBU" + suffix
146
147 case LDRH:
148 op = "MOVHU" + suffix
149
150 case LDRSW:
151 op = "MOVW" + suffix
152
153 case LDRSB:
154 if r, ok := inst.Args[0].(Reg); ok {
155 rno := uint16(r)
156 if rno <= uint16(WZR) {
157 op = "MOVBW" + suffix
158 } else {
159 op = "MOVB" + suffix
160 }
161 }
162 case LDRSH:
163 if r, ok := inst.Args[0].(Reg); ok {
164 rno := uint16(r)
165 if rno <= uint16(WZR) {
166 op = "MOVHW" + suffix
167 } else {
168 op = "MOVH" + suffix
169 }
170 }
171 case STR, STUR:
172 var rno uint16
173 if r, ok := inst.Args[0].(Reg); ok {
174 rno = uint16(r)
175 } else {
176 rno = uint16(inst.Args[0].(RegSP))
177 }
178 if rno <= uint16(WZR) {
179 op = "MOVW" + suffix
180 } else if rno >= uint16(B0) && rno <= uint16(B31) {
181 op = "FMOVB" + suffix
182 args[0] = fmt.Sprintf("F%d", rno&31)
183 } else if rno >= uint16(H0) && rno <= uint16(H31) {
184 op = "FMOVH" + suffix
185 args[0] = fmt.Sprintf("F%d", rno&31)
186 } else if rno >= uint16(S0) && rno <= uint16(S31) {
187 op = "FMOVS" + suffix
188 args[0] = fmt.Sprintf("F%d", rno&31)
189 } else if rno >= uint16(D0) && rno <= uint16(D31) {
190 op = "FMOVD" + suffix
191 args[0] = fmt.Sprintf("F%d", rno&31)
192 } else if rno >= uint16(Q0) && rno <= uint16(Q31) {
193 op = "FMOVQ" + suffix
194 args[0] = fmt.Sprintf("F%d", rno&31)
195 } else {
196 op = "MOVD" + suffix
197 }
198 args[0], args[1] = args[1], args[0]
199
200 case STRB, STURB:
201 op = "MOVB" + suffix
202 args[0], args[1] = args[1], args[0]
203
204 case STRH, STURH:
205 op = "MOVH" + suffix
206 args[0], args[1] = args[1], args[0]
207
208 case TBNZ, TBZ:
209 args[0], args[1], args[2] = args[2], args[0], args[1]
210
211 case MADD, MSUB, SMADDL, SMSUBL, UMADDL, UMSUBL:
212 if r, ok := inst.Args[0].(Reg); ok {
213 rno := uint16(r)
214 if rno <= uint16(WZR) {
215 op += "W"
216 }
217 }
218 args[2], args[3] = args[3], args[2]
219 case STLR:
220 if r, ok := inst.Args[0].(Reg); ok {
221 rno := uint16(r)
222 if rno <= uint16(WZR) {
223 op += "W"
224 }
225 }
226 args[0], args[1] = args[1], args[0]
227
228 case STLRB, STLRH:
229 args[0], args[1] = args[1], args[0]
230
231 case STLXR, STXR:
232 if r, ok := inst.Args[1].(Reg); ok {
233 rno := uint16(r)
234 if rno <= uint16(WZR) {
235 op += "W"
236 }
237 }
238 args[1], args[2] = args[2], args[1]
239
240 case STLXRB, STLXRH, STXRB, STXRH:
241 args[1], args[2] = args[2], args[1]
242
243 case BFI, BFXIL, SBFIZ, SBFX, UBFIZ, UBFX:
244 if r, ok := inst.Args[0].(Reg); ok {
245 rno := uint16(r)
246 if rno <= uint16(WZR) {
247 op += "W"
248 }
249 }
250 args[1], args[2], args[3] = args[3], args[1], args[2]
251
252 case LDAXP, LDXP:
253 if r, ok := inst.Args[0].(Reg); ok {
254 rno := uint16(r)
255 if rno <= uint16(WZR) {
256 op += "W"
257 }
258 }
259 args[0] = fmt.Sprintf("(%s, %s)", args[0], args[1])
260 args[1] = args[2]
261 return op + " " + args[1] + ", " + args[0]
262
263 case STP, LDP:
264 args[0] = fmt.Sprintf("(%s, %s)", args[0], args[1])
265 args[1] = args[2]
266
267 rno, ok := inst.Args[0].(Reg)
268 if !ok {
269 rno = Reg(inst.Args[0].(RegSP))
270 }
271 if rno <= WZR {
272 op = op + "W"
273 } else if rno >= S0 && rno <= S31 {
274 op = "F" + op + "S"
275 } else if rno >= D0 && rno <= D31 {
276 op = "F" + op + "D"
277 } else if rno >= Q0 && rno <= Q31 {
278 op = "F" + op + "Q"
279 }
280 op = op + suffix
281 if inst.Op.String() == "STP" {
282 return op + " " + args[0] + ", " + args[1]
283 } else {
284 return op + " " + args[1] + ", " + args[0]
285 }
286
287 case STLXP, STXP:
288 if r, ok := inst.Args[1].(Reg); ok {
289 rno := uint16(r)
290 if rno <= uint16(WZR) {
291 op += "W"
292 }
293 }
294 args[1] = fmt.Sprintf("(%s, %s)", args[1], args[2])
295 args[2] = args[3]
296 return op + " " + args[1] + ", " + args[2] + ", " + args[0]
297
298 case FCCMP, FCCMPE:
299 args[0], args[1] = args[1], args[0]
300 fallthrough
301
302 case FCMP, FCMPE:
303 if _, ok := inst.Args[1].(Imm); ok {
304 args[1] = "$(0.0)"
305 }
306 fallthrough
307
308 case FADD, FSUB, FMUL, FNMUL, FDIV, FMAX, FMIN, FMAXNM, FMINNM, FCSEL, FMADD, FMSUB, FNMADD, FNMSUB:
309 if strings.HasSuffix(op, "MADD") || strings.HasSuffix(op, "MSUB") {
310 args[2], args[3] = args[3], args[2]
311 }
312 if r, ok := inst.Args[0].(Reg); ok {
313 rno := uint16(r)
314 if rno >= uint16(S0) && rno <= uint16(S31) {
315 op = fmt.Sprintf("%sS", op)
316 } else if rno >= uint16(D0) && rno <= uint16(D31) {
317 op = fmt.Sprintf("%sD", op)
318 }
319 }
320
321 case FCVT:
322 for i := 1; i >= 0; i-- {
323 if r, ok := inst.Args[i].(Reg); ok {
324 rno := uint16(r)
325 if rno >= uint16(H0) && rno <= uint16(H31) {
326 op = fmt.Sprintf("%sH", op)
327 } else if rno >= uint16(S0) && rno <= uint16(S31) {
328 op = fmt.Sprintf("%sS", op)
329 } else if rno >= uint16(D0) && rno <= uint16(D31) {
330 op = fmt.Sprintf("%sD", op)
331 }
332 }
333 }
334
335 case FABS, FNEG, FSQRT, FRINTN, FRINTP, FRINTM, FRINTZ, FRINTA, FRINTX, FRINTI:
336 if r, ok := inst.Args[1].(Reg); ok {
337 rno := uint16(r)
338 if rno >= uint16(S0) && rno <= uint16(S31) {
339 op = fmt.Sprintf("%sS", op)
340 } else if rno >= uint16(D0) && rno <= uint16(D31) {
341 op = fmt.Sprintf("%sD", op)
342 }
343 }
344
345 case FCVTZS, FCVTZU, SCVTF, UCVTF:
346 if _, ok := inst.Args[2].(Imm); !ok {
347 for i := 1; i >= 0; i-- {
348 if r, ok := inst.Args[i].(Reg); ok {
349 rno := uint16(r)
350 if rno >= uint16(S0) && rno <= uint16(S31) {
351 op = fmt.Sprintf("%sS", op)
352 } else if rno >= uint16(D0) && rno <= uint16(D31) {
353 op = fmt.Sprintf("%sD", op)
354 } else if rno <= uint16(WZR) {
355 op += "W"
356 }
357 }
358 }
359 }
360
361 case FMOV:
362 for i := 0; i <= 1; i++ {
363 if r, ok := inst.Args[i].(Reg); ok {
364 rno := uint16(r)
365 if rno >= uint16(S0) && rno <= uint16(S31) {
366 op = fmt.Sprintf("%sS", op)
367 break
368 } else if rno >= uint16(D0) && rno <= uint16(D31) {
369 op = fmt.Sprintf("%sD", op)
370 break
371 }
372 }
373 }
374
375 case SYSL:
376 op1 := int(inst.Args[1].(Imm).Imm)
377 cn := int(inst.Args[2].(Imm_c))
378 cm := int(inst.Args[3].(Imm_c))
379 op2 := int(inst.Args[4].(Imm).Imm)
380 sysregno := int32(op1<<16 | cn<<12 | cm<<8 | op2<<5)
381 args[1] = fmt.Sprintf("$%d", sysregno)
382 return op + " " + args[1] + ", " + args[0]
383
384 case CBNZ, CBZ:
385 if r, ok := inst.Args[0].(Reg); ok {
386 rno := uint16(r)
387 if rno <= uint16(WZR) {
388 op += "W"
389 }
390 }
391 args[0], args[1] = args[1], args[0]
392
393 case ADR, ADRP:
394 addr := int64(inst.Args[1].(PCRel))
395 args[1] = fmt.Sprintf("%d(PC)", addr)
396
397 case MSR:
398 args[0] = inst.Args[0].String()
399
400 case ST1:
401 op = fmt.Sprintf("V%s", op) + suffix
402 args[0], args[1] = args[1], args[0]
403
404 case LD1:
405 op = fmt.Sprintf("V%s", op) + suffix
406
407 case UMOV:
408 op = "VMOV"
409 case NOP:
410 op = "NOOP"
411
412 default:
413 index := sort.SearchStrings(noSuffixOpSet, op)
414 if !(index < len(noSuffixOpSet) && noSuffixOpSet[index] == op) {
415 rno := -1
416 switch a := inst.Args[0].(type) {
417 case Reg:
418 rno = int(a)
419 case RegSP:
420 rno = int(a)
421 case RegisterWithArrangement:
422 op = fmt.Sprintf("V%s", op)
423 }
424
425 if rno >= int(B0) && rno <= int(Q31) && !strings.HasPrefix(op, "F") {
426 op = fmt.Sprintf("V%s", op)
427 }
428 if rno >= 0 && rno <= int(WZR) {
429
430 op += "W"
431 }
432 }
433 op = op + suffix
434 }
435
436
437 if _, ok := inst.Args[3].(Cond); ok {
438 if _, ok := inst.Args[2].(Reg); ok {
439 args[1], args[2] = args[2], args[1]
440 } else {
441 args[0], args[2] = args[2], args[0]
442 }
443 }
444
445 for i, j := 0, len(args)-1; i < j; i, j = i+1, j-1 {
446 args[i], args[j] = args[j], args[i]
447 }
448
449 if args != nil {
450 op += " " + strings.Join(args, ", ")
451 }
452
453 return op
454 }
455
456
457
458 var noSuffixOpSet = strings.Fields(`
459 AESD
460 AESE
461 AESIMC
462 AESMC
463 CRC32B
464 CRC32CB
465 CRC32CH
466 CRC32CW
467 CRC32CX
468 CRC32H
469 CRC32W
470 CRC32X
471 LDARB
472 LDARH
473 LDAXRB
474 LDAXRH
475 LDTRH
476 LDXRB
477 LDXRH
478 SHA1C
479 SHA1H
480 SHA1M
481 SHA1P
482 SHA1SU0
483 SHA1SU1
484 SHA256H
485 SHA256H2
486 SHA256SU0
487 SHA256SU1
488 `)
489
490
491 var fOpsWithoutFPrefix = map[Op]bool{
492 LDP: true,
493 STP: true,
494 }
495
496 func plan9Arg(inst *Inst, pc uint64, symname func(uint64) (string, uint64), arg Arg) string {
497 switch a := arg.(type) {
498 case Imm:
499 return fmt.Sprintf("$%d", uint32(a.Imm))
500
501 case Imm64:
502 return fmt.Sprintf("$%d", int64(a.Imm))
503
504 case ImmShift:
505 if a.shift == 0 {
506 return fmt.Sprintf("$%d", a.imm)
507 }
508 return fmt.Sprintf("$(%d<<%d)", a.imm, a.shift)
509
510 case PCRel:
511 addr := int64(pc) + int64(a)
512 if s, base := symname(uint64(addr)); s != "" && uint64(addr) == base {
513 return fmt.Sprintf("%s(SB)", s)
514 }
515 return fmt.Sprintf("%d(PC)", a/4)
516
517 case Reg:
518 regenum := uint16(a)
519 regno := uint16(a) & 31
520
521 if regenum >= uint16(B0) && regenum <= uint16(Q31) {
522 if strings.HasPrefix(inst.Op.String(), "F") || strings.HasSuffix(inst.Op.String(), "CVTF") || fOpsWithoutFPrefix[inst.Op] {
523
524
525 return fmt.Sprintf("F%d", regno)
526 } else {
527
528 return fmt.Sprintf("V%d", regno)
529 }
530
531 }
532 return plan9gpr(a)
533
534 case RegSP:
535 regno := uint16(a) & 31
536 if regno == 31 {
537 return "RSP"
538 }
539 return fmt.Sprintf("R%d", regno)
540
541 case RegExtshiftAmount:
542 reg := plan9gpr(a.reg)
543 extshift := ""
544 amount := ""
545 if a.extShift != ExtShift(0) {
546 switch a.extShift {
547 default:
548 extshift = "." + a.extShift.String()
549
550 case lsl:
551 extshift = "<<"
552 amount = fmt.Sprintf("%d", a.amount)
553 return reg + extshift + amount
554
555 case lsr:
556 extshift = ">>"
557 amount = fmt.Sprintf("%d", a.amount)
558 return reg + extshift + amount
559
560 case asr:
561 extshift = "->"
562 amount = fmt.Sprintf("%d", a.amount)
563 return reg + extshift + amount
564 case ror:
565 extshift = "@>"
566 amount = fmt.Sprintf("%d", a.amount)
567 return reg + extshift + amount
568 }
569 if a.amount != 0 {
570 amount = fmt.Sprintf("<<%d", a.amount)
571 }
572 }
573 return reg + extshift + amount
574
575 case MemImmediate:
576 off := ""
577 base := ""
578 regno := uint16(a.Base) & 31
579 if regno == 31 {
580 base = "(RSP)"
581 } else {
582 base = fmt.Sprintf("(R%d)", regno)
583 }
584 if a.imm != 0 && a.Mode != AddrPostReg {
585 off = fmt.Sprintf("%d", a.imm)
586 } else if a.Mode == AddrPostReg {
587 postR := fmt.Sprintf("(R%d)", a.imm)
588 return base + postR
589 }
590 return off + base
591
592 case MemExtend:
593 base := ""
594 index := ""
595 regno := uint16(a.Base) & 31
596 if regno == 31 {
597 base = "(RSP)"
598 } else {
599 base = fmt.Sprintf("(R%d)", regno)
600 }
601 indexreg := plan9gpr(a.Index)
602
603 if a.Extend == lsl {
604
605
606
607
608
609
610 if a.Amount != 0 && !a.ShiftMustBeZero {
611 index = fmt.Sprintf("(%s<<%d)", indexreg, a.Amount)
612 } else if a.ShiftMustBeZero && a.Amount == 1 {
613
614
615 index = fmt.Sprintf("(%s<<0)", indexreg)
616 } else {
617 index = fmt.Sprintf("(%s)", indexreg)
618 }
619 } else {
620 if a.Amount != 0 && !a.ShiftMustBeZero {
621 index = fmt.Sprintf("(%s.%s<<%d)", indexreg, a.Extend.String(), a.Amount)
622 } else {
623 index = fmt.Sprintf("(%s.%s)", indexreg, a.Extend.String())
624 }
625 }
626
627 return base + index
628
629 case Cond:
630 switch arg.String() {
631 case "CS":
632 return "HS"
633 case "CC":
634 return "LO"
635 }
636
637 case Imm_clrex:
638 return fmt.Sprintf("$%d", uint32(a))
639
640 case Imm_dcps:
641 return fmt.Sprintf("$%d", uint32(a))
642
643 case Imm_option:
644 return fmt.Sprintf("$%d", uint8(a))
645
646 case Imm_hint:
647 return fmt.Sprintf("$%d", uint8(a))
648
649 case Imm_fp:
650 var s, pre, numerator, denominator int16
651 var result float64
652 if a.s == 0 {
653 s = 1
654 } else {
655 s = -1
656 }
657 pre = s * int16(16+a.pre)
658 if a.exp > 0 {
659 numerator = (pre << uint8(a.exp))
660 denominator = 16
661 } else {
662 numerator = pre
663 denominator = (16 << uint8(-1*a.exp))
664 }
665 result = float64(numerator) / float64(denominator)
666 return strings.TrimRight(fmt.Sprintf("$%f", result), "0")
667
668 case RegisterWithArrangement:
669 result := a.r.String()
670 arrange := a.a.String()
671 c := []rune(arrange)
672 switch len(c) {
673 case 3:
674 c[1], c[2] = c[2], c[1]
675 case 4:
676 c[1], c[2], c[3] = c[3], c[1], c[2]
677 }
678 arrange = string(c)
679 result += arrange
680 if a.cnt > 0 {
681 result = "[" + result
682 for i := 1; i < int(a.cnt); i++ {
683 cur := V0 + Reg((uint16(a.r)-uint16(V0)+uint16(i))&31)
684 result += ", " + cur.String() + arrange
685 }
686 result += "]"
687 }
688 return result
689
690 case RegisterWithArrangementAndIndex:
691 result := a.r.String()
692 arrange := a.a.String()
693 result += arrange
694 if a.cnt > 1 {
695 result = "[" + result
696 for i := 1; i < int(a.cnt); i++ {
697 cur := V0 + Reg((uint16(a.r)-uint16(V0)+uint16(i))&31)
698 result += ", " + cur.String() + arrange
699 }
700 result += "]"
701 }
702 return fmt.Sprintf("%s[%d]", result, a.index)
703
704 case Systemreg:
705 return fmt.Sprintf("$%d", uint32(a.op0&1)<<14|uint32(a.op1&7)<<11|uint32(a.cn&15)<<7|uint32(a.cm&15)<<3|uint32(a.op2)&7)
706
707 case Imm_prfop:
708 if strings.Contains(a.String(), "#") {
709 return fmt.Sprintf("$%d", a)
710 }
711 case sysOp:
712 result := a.op.String()
713 if a.r != 0 {
714 result += ", " + plan9gpr(a.r)
715 }
716 return result
717 }
718
719 return strings.ToUpper(arg.String())
720 }
721
722
723 func plan9gpr(r Reg) string {
724 regno := uint16(r) & 31
725 if regno == 31 {
726 return "ZR"
727 }
728 return fmt.Sprintf("R%d", regno)
729 }
730
View as plain text