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 return plan9gpr(a)
546
547 case RegSP:
548 regno := uint16(a) & 31
549 if regno == 31 {
550 return "RSP"
551 }
552 return fmt.Sprintf("R%d", regno)
553
554 case RegExtshiftAmount:
555 reg := plan9gpr(a.reg)
556 extshift := ""
557 amount := ""
558 if a.extShift != ExtShift(0) {
559 switch a.extShift {
560 default:
561 extshift = "." + a.extShift.String()
562
563 case lsl:
564 extshift = "<<"
565 amount = fmt.Sprintf("%d", a.amount)
566 return reg + extshift + amount
567
568 case lsr:
569 extshift = ">>"
570 amount = fmt.Sprintf("%d", a.amount)
571 return reg + extshift + amount
572
573 case asr:
574 extshift = "->"
575 amount = fmt.Sprintf("%d", a.amount)
576 return reg + extshift + amount
577 case ror:
578 extshift = "@>"
579 amount = fmt.Sprintf("%d", a.amount)
580 return reg + extshift + amount
581 }
582 if a.amount != 0 {
583 amount = fmt.Sprintf("<<%d", a.amount)
584 }
585 }
586 return reg + extshift + amount
587
588 case MemImmediate:
589 off := ""
590 base := ""
591 regno := uint16(a.Base) & 31
592 if regno == 31 {
593 base = "(RSP)"
594 } else {
595 base = fmt.Sprintf("(R%d)", regno)
596 }
597 if a.imm != 0 && a.Mode != AddrPostReg {
598 off = fmt.Sprintf("%d", a.imm)
599 } else if a.Mode == AddrPostReg {
600 postR := fmt.Sprintf("(R%d)", a.imm)
601 return base + postR
602 }
603 return off + base
604
605 case MemExtend:
606 base := ""
607 index := ""
608 regno := uint16(a.Base) & 31
609 if regno == 31 {
610 base = "(RSP)"
611 } else {
612 base = fmt.Sprintf("(R%d)", regno)
613 }
614 indexreg := plan9gpr(a.Index)
615
616 if a.Extend == lsl {
617
618
619
620
621
622
623 if a.Amount != 0 && !a.ShiftMustBeZero {
624 index = fmt.Sprintf("(%s<<%d)", indexreg, a.Amount)
625 } else if a.ShiftMustBeZero && a.Amount == 1 {
626
627
628 index = fmt.Sprintf("(%s<<0)", indexreg)
629 } else {
630 index = fmt.Sprintf("(%s)", indexreg)
631 }
632 } else {
633 if a.Amount != 0 && !a.ShiftMustBeZero {
634 index = fmt.Sprintf("(%s.%s<<%d)", indexreg, a.Extend.String(), a.Amount)
635 } else {
636 index = fmt.Sprintf("(%s.%s)", indexreg, a.Extend.String())
637 }
638 }
639
640 return base + index
641
642 case Cond:
643 switch arg.String() {
644 case "CS":
645 return "HS"
646 case "CC":
647 return "LO"
648 }
649
650 case Imm_clrex:
651 return fmt.Sprintf("$%d", uint32(a))
652
653 case Imm_dcps:
654 return fmt.Sprintf("$%d", uint32(a))
655
656 case Imm_option:
657 return fmt.Sprintf("$%d", uint8(a))
658
659 case Imm_hint:
660 return fmt.Sprintf("$%d", uint8(a))
661
662 case Imm_fp:
663 var s, pre, numerator, denominator int16
664 var result float64
665 if a.s == 0 {
666 s = 1
667 } else {
668 s = -1
669 }
670 pre = s * int16(16+a.pre)
671 if a.exp > 0 {
672 numerator = (pre << uint8(a.exp))
673 denominator = 16
674 } else {
675 numerator = pre
676 denominator = (16 << uint8(-1*a.exp))
677 }
678 result = float64(numerator) / float64(denominator)
679 return strings.TrimRight(fmt.Sprintf("$%f", result), "0")
680
681 case RegisterWithArrangement:
682 result := a.r.String()
683 arrange := a.a.String()
684 c := []rune(arrange)
685 switch len(c) {
686 case 3:
687 c[1], c[2] = c[2], c[1]
688 case 4:
689 c[1], c[2], c[3] = c[3], c[1], c[2]
690 }
691 arrange = string(c)
692 result += arrange
693 if a.cnt > 0 {
694 result = "[" + result
695 for i := 1; i < int(a.cnt); i++ {
696 cur := V0 + Reg((uint16(a.r)-uint16(V0)+uint16(i))&31)
697 result += ", " + cur.String() + arrange
698 }
699 result += "]"
700 }
701 return result
702
703 case RegisterWithArrangementAndIndex:
704 result := a.r.String()
705 arrange := a.a.String()
706 result += arrange
707 if a.cnt > 1 {
708 result = "[" + result
709 for i := 1; i < int(a.cnt); i++ {
710 cur := V0 + Reg((uint16(a.r)-uint16(V0)+uint16(i))&31)
711 result += ", " + cur.String() + arrange
712 }
713 result += "]"
714 }
715 return fmt.Sprintf("%s[%d]", result, a.index)
716
717 case Systemreg:
718 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)
719
720 case Imm_prfop:
721 if strings.Contains(a.String(), "#") {
722 return fmt.Sprintf("$%d", a)
723 }
724 case sysOp:
725 result := a.op.String()
726 if a.r != 0 {
727 result += ", " + plan9gpr(a.r)
728 }
729 return result
730 }
731
732 return strings.ToUpper(arg.String())
733 }
734
735
736 func plan9gpr(r Reg) string {
737 regno := uint16(r) & 31
738 if regno == 31 {
739 return "ZR"
740 }
741 return fmt.Sprintf("R%d", regno)
742 }
743
View as plain text