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