1
2
3
4
5 package x86asm
6
7 import (
8 "fmt"
9 "strings"
10 )
11
12
13
14 func GNUSyntax(inst Inst, pc uint64, symname SymLookup) string {
15
16
17
18
19
20 if symname == nil {
21 symname = func(uint64) (string, uint64) { return "", 0 }
22 }
23
24
25 switch inst.Op {
26 case FDIV, FDIVR, FSUB, FSUBR, FDIVP, FDIVRP, FSUBP, FSUBRP:
27
28
29
30
31
32 _, reg1 := inst.Args[0].(Reg)
33 _, reg2 := inst.Args[1].(Reg)
34 if reg1 && reg2 && (inst.Opcode>>24 == 0xDC || inst.Opcode>>24 == 0xDE) {
35 switch inst.Op {
36 case FDIV:
37 inst.Op = FDIVR
38 case FDIVR:
39 inst.Op = FDIV
40 case FSUB:
41 inst.Op = FSUBR
42 case FSUBR:
43 inst.Op = FSUB
44 case FDIVP:
45 inst.Op = FDIVRP
46 case FDIVRP:
47 inst.Op = FDIVP
48 case FSUBP:
49 inst.Op = FSUBRP
50 case FSUBRP:
51 inst.Op = FSUBP
52 }
53 }
54
55 case MOVNTSD:
56
57
58
59
60
61
62 if countPrefix(&inst, 0xF3) > 0 {
63 found := false
64 for i := len(inst.Prefix) - 1; i >= 0; i-- {
65 switch inst.Prefix[i] & 0xFF {
66 case 0xF3:
67 if !found {
68 found = true
69 inst.Prefix[i] |= PrefixImplicit
70 }
71 case 0xF2:
72 inst.Prefix[i] &^= PrefixImplicit
73 }
74 }
75 inst.Op = MOVNTSS
76 }
77 }
78
79
80 switch inst.Op {
81 case MONITOR:
82 inst.Args[0] = EDX
83 inst.Args[1] = ECX
84 inst.Args[2] = EAX
85 if inst.AddrSize == 16 {
86 inst.Args[2] = AX
87 }
88
89 case MWAIT:
90 if inst.Mode == 64 {
91 inst.Args[0] = RCX
92 inst.Args[1] = RAX
93 } else {
94 inst.Args[0] = ECX
95 inst.Args[1] = EAX
96 }
97 }
98
99
100
101
102
103
104 switch inst.Op {
105 case CRC32:
106
107
108
109
110
111
112 if countPrefix(&inst, 0xF2) > 1 {
113 unmarkImplicit(&inst, 0xF2)
114 markLastImplicit(&inst, 0xF2)
115 }
116
117
118
119
120
121 unmarkImplicit(&inst, PrefixDataSize)
122 markLastImplicit(&inst, PrefixDataSize)
123
124 case CVTSI2SD, CVTSI2SS:
125 if !isMem(inst.Args[1]) {
126 markLastImplicit(&inst, PrefixDataSize)
127 }
128
129 case CVTSD2SI, CVTSS2SI, CVTTSD2SI, CVTTSS2SI,
130 ENTER, FLDENV, FNSAVE, FNSTENV, FRSTOR, LGDT, LIDT, LRET,
131 POP, PUSH, RET, SGDT, SIDT, SYSRET, XBEGIN:
132 markLastImplicit(&inst, PrefixDataSize)
133
134 case LOOP, LOOPE, LOOPNE, MONITOR:
135 markLastImplicit(&inst, PrefixAddrSize)
136
137 case MOV:
138
139
140
141
142
143
144
145
146 dst, _ := inst.Args[0].(Reg)
147 src, _ := inst.Args[1].(Reg)
148 if ES <= src && src <= GS && isMem(inst.Args[0]) || ES <= dst && dst <= GS && isMem(inst.Args[1]) {
149 unmarkImplicit(&inst, PrefixDataSize)
150 }
151
152 case MOVDQU:
153 if countPrefix(&inst, 0xF3) > 1 {
154 unmarkImplicit(&inst, 0xF3)
155 markLastImplicit(&inst, 0xF3)
156 }
157
158 case MOVQ2DQ:
159 markLastImplicit(&inst, PrefixDataSize)
160
161 case SLDT, SMSW, STR, FXRSTOR, XRSTOR, XSAVE, XSAVEOPT, CMPXCHG8B:
162 if isMem(inst.Args[0]) {
163 unmarkImplicit(&inst, PrefixDataSize)
164 }
165
166 case SYSEXIT:
167 unmarkImplicit(&inst, PrefixDataSize)
168 }
169
170 if isCondJmp[inst.Op] || isLoop[inst.Op] || inst.Op == JCXZ || inst.Op == JECXZ || inst.Op == JRCXZ {
171 if countPrefix(&inst, PrefixCS) > 0 && countPrefix(&inst, PrefixDS) > 0 {
172 for i, p := range inst.Prefix {
173 switch p & 0xFFF {
174 case PrefixPN, PrefixPT:
175 inst.Prefix[i] &= 0xF0FF
176 }
177 }
178 }
179 }
180
181
182 if inst.Op == MOV {
183
184
185
186 haveREPN := false
187 for i := len(inst.Prefix) - 1; i >= 0; i-- {
188 switch inst.Prefix[i] &^ PrefixIgnored {
189 case PrefixREPN:
190 haveREPN = true
191 case PrefixXRELEASE:
192 if haveREPN {
193 inst.Prefix[i] = PrefixREP
194 }
195 }
196 }
197 }
198
199
200 haveXA := false
201 haveXR := false
202 for i := len(inst.Prefix) - 1; i >= 0; i-- {
203 switch inst.Prefix[i] &^ PrefixIgnored {
204 case PrefixXRELEASE:
205 if !haveXR {
206 haveXR = true
207 } else {
208 inst.Prefix[i] = PrefixREP
209 }
210
211 case PrefixXACQUIRE:
212 if !haveXA {
213 haveXA = true
214 } else {
215 inst.Prefix[i] = PrefixREPN
216 }
217 }
218 }
219
220
221 op := strings.ToLower(inst.Op.String())
222 if alt := gnuOp[inst.Op]; alt != "" {
223 op = alt
224 }
225
226
227
228
229
230
231
232
233 needSuffix := true
234 SuffixLoop:
235 for i, a := range inst.Args {
236 if a == nil {
237 break
238 }
239 switch a := a.(type) {
240 case Reg:
241 switch inst.Op {
242 case MOVSX, MOVZX:
243 continue
244
245 case SHL, SHR, RCL, RCR, ROL, ROR, SAR:
246 if i == 1 {
247
248 continue
249 }
250
251 case CRC32:
252
253
254 continue
255
256 case PUSH, POP:
257
258
259
260 if ES <= a && a <= GS {
261 continue
262 }
263
264 case CVTSI2SD, CVTSI2SS:
265
266 if X0 <= a && a <= X15 {
267 continue
268 }
269 }
270
271 if AL <= a && a <= R15 || ES <= a && a <= GS || X0 <= a && a <= Z31 || M0 <= a && a <= M7 || K0 <= a && a <= K7 {
272 needSuffix = false
273 break SuffixLoop
274 }
275 }
276 }
277
278 if needSuffix {
279 switch inst.Op {
280 case CMPXCHG8B, FLDCW, FNSTCW, FNSTSW, LDMXCSR, LLDT, LMSW, LTR, PCLMULQDQ,
281 SETA, SETAE, SETB, SETBE, SETE, SETG, SETGE, SETL, SETLE, SETNE, SETNO, SETNP, SETNS, SETO, SETP, SETS,
282 SLDT, SMSW, STMXCSR, STR, VERR, VERW, VLDMXCSR, VSTMXCSR:
283
284
285 case CRC32:
286 op += byteSizeSuffix(argBytes(&inst, inst.Args[1]))
287
288 case LGDT, LIDT, SGDT, SIDT:
289 op += byteSizeSuffix(inst.DataSize / 8)
290
291 case MOVZX, MOVSX:
292
293 op = op[:4] + byteSizeSuffix(argBytes(&inst, inst.Args[1])) + byteSizeSuffix(argBytes(&inst, inst.Args[0]))
294
295 case LOOP, LOOPE, LOOPNE:
296
297 if inst.AddrSize == 16 {
298 op += "w"
299 }
300
301 case CALL, ENTER, JMP, LCALL, LEAVE, LJMP, LRET, RET, SYSRET, XBEGIN:
302
303
304 if inst.Opcode>>24 == 0xEB {
305 break
306 }
307 if inst.DataSize == 16 && inst.Mode != 16 {
308 markLastImplicit(&inst, PrefixDataSize)
309 op += "w"
310 } else if inst.Mode == 64 {
311 op += "q"
312 }
313
314 case FRSTOR, FNSAVE, FNSTENV, FLDENV:
315
316 if inst.DataSize == 16 {
317 op += "s"
318 }
319
320 case PUSH, POP:
321 if markLastImplicit(&inst, PrefixDataSize) {
322 op += byteSizeSuffix(inst.DataSize / 8)
323 } else if inst.Mode == 64 {
324 op += "q"
325 } else {
326 op += byteSizeSuffix(inst.MemBytes)
327 }
328
329 default:
330 if isFloat(inst.Op) {
331
332 switch inst.MemBytes {
333 default:
334 if (inst.Op == FLD || inst.Op == FSTP) && isMem(inst.Args[0]) {
335 op += "t"
336 }
337 case 4:
338 if isFloatInt(inst.Op) {
339 op += "l"
340 } else {
341 op += "s"
342 }
343 case 8:
344 if isFloatInt(inst.Op) {
345 op += "ll"
346 } else {
347 op += "l"
348 }
349 }
350 break
351 }
352
353 op += byteSizeSuffix(inst.MemBytes)
354 }
355 }
356
357 isVexOrEvex := false
358 for _, p := range inst.Prefix {
359 if p.IsVEX() || p&0xFF == 0x62 {
360 isVexOrEvex = true
361 break
362 }
363 }
364 if isVexOrEvex {
365 hasMem := false
366 for _, a := range inst.Args {
367 if _, ok := a.(Mem); ok {
368 hasMem = true
369 break
370 }
371 }
372 if hasMem {
373 if inst.Op == VFPCLASSPD || inst.Op == VFPCLASSPS || inst.Op == VCVTTPD2DQ || inst.Op == VCVTTPD2UDQ || inst.Op == VCVTTPD2QQ || inst.Op == VCVTTPD2UQQ || inst.Op == VCVTPD2DQ || inst.Op == VCVTPD2UDQ || inst.Op == VCVTPD2QQ || inst.Op == VCVTPD2UQQ || inst.Op == VCVTPD2PS {
374 vexL := 0
375 isEvex := false
376 for i, p := range inst.Prefix {
377 if p.IsEVEX() && i+3 < len(inst.Prefix) && inst.Prefix[i+3] != 0 {
378 vexL = int((inst.Prefix[i+3]&0xFF)>>5) & 3
379 isEvex = true
380 break
381 } else if p.IsVEX() && i+2 < len(inst.Prefix) {
382 if p&0xFF == 0xC4 {
383 vexL = int((inst.Prefix[i+2]&0xFF)>>2) & 1
384 } else if p&0xFF == 0xC5 {
385 vexL = int((inst.Prefix[i+1]&0xFF)>>2) & 1
386 }
387 break
388 }
389 }
390 if !isEvex || inst.Op == VFPCLASSPD || inst.Op == VFPCLASSPS || inst.Op == VCVTPD2DQ {
391 switch vexL {
392 case 0:
393 op += "x"
394 case 1:
395 if inst.Op != VCMPPD && inst.Op != VCMPPS && inst.Op != VCMPPH && inst.Op != VCMPBF16 {
396 op += "y"
397 }
398 case 2:
399 if inst.Op != VCMPPD && inst.Op != VCMPPS && inst.Op != VCMPPH && inst.Op != VCMPBF16 {
400 op += "z"
401 }
402 }
403 }
404 } else if inst.Op == VCVTSI2SD || inst.Op == VCVTSI2SS {
405 is64 := false
406 if (inst.Op == VCVTSI2SD || inst.Op == VCVTSI2SS) && inst.MemBytes == 8 {
407 is64 = true
408 } else {
409 for _, a := range inst.Args {
410 if r, ok := a.(Reg); ok && RAX <= r && r <= R15 {
411 is64 = true
412 break
413 }
414 }
415 }
416 if is64 {
417 op += "q"
418 } else {
419 op += "l"
420 }
421 }
422 }
423 }
424
425
426 switch inst.Op {
427 case 0:
428 if inst.Prefix[0] != 0 {
429 return strings.ToLower(inst.Prefix[0].String())
430 }
431
432 case INT:
433 if inst.Opcode>>24 == 0xCC {
434 inst.Args[0] = nil
435 op = "int3"
436 }
437
438 case CMPPS, CMPPD, CMPSD_XMM, CMPSS:
439 imm, ok := inst.Args[2].(Imm)
440 if ok && 0 <= imm && imm < 8 {
441 inst.Args[2] = nil
442 op = cmppsOps[imm] + op[3:]
443 }
444
445 case VCMPPD, VCMPPS, VCMPSD, VCMPSS, VCMPPH, VCMPSH, VCMPBF16:
446 for i := len(inst.Args) - 1; i >= 0; i-- {
447 if imm, ok := inst.Args[i].(Imm); ok {
448 if 0 <= imm && imm < 8 {
449 inst.Args[i] = nil
450 op = "v" + cmppsOps[imm] + op[4:]
451 }
452 break
453 }
454 if inst.Args[i] != nil {
455 break
456 }
457 }
458
459 case PCLMULQDQ:
460 imm, ok := inst.Args[2].(Imm)
461 if ok && imm&^0x11 == 0 {
462 inst.Args[2] = nil
463 op = pclmulqOps[(imm&0x10)>>3|(imm&1)]
464 }
465
466 case XLATB:
467 if markLastImplicit(&inst, PrefixAddrSize) {
468 op = "xlat"
469 }
470 }
471
472
473 var (
474 usedPrefixes bool
475 args []string
476 )
477 for i, a := range inst.Args {
478 if a == nil {
479 break
480 }
481 switch inst.Op {
482 case MOVSB, MOVSW, MOVSD, MOVSQ, OUTSB, OUTSW, OUTSD:
483 if i == 0 {
484 usedPrefixes = true
485 } else {
486 usedPrefixes = false
487 }
488 }
489 if a == Imm(1) && (inst.Opcode>>24)&^1 == 0xD0 {
490 continue
491 }
492 argStr := gnuArg(&inst, pc, symname, a, &usedPrefixes)
493 if i == 1 {
494 r, ok := a.(Reg)
495
496 if ok && K1 <= r && r <= K7 {
497 if !strings.HasPrefix(inst.Op.String(), "K") {
498 if len(args) > 0 {
499 args[0] += fmt.Sprintf(" {%s}", argStr)
500 if inst.Zeroing {
501 args[0] += " {z}"
502 }
503 }
504 continue
505 }
506 } else if ok && r == K0 {
507 if !strings.HasPrefix(inst.Op.String(), "K") {
508 if inst.Zeroing && len(args) > 0 {
509 args[0] += "{z}"
510 }
511 continue
512 }
513 }
514 }
515 if _, ok := a.(Mem); ok && inst.Broadcast && len(args) > 0 {
516 if dstReg, ok := inst.Args[0].(Reg); ok {
517 var vBytes int
518 if X0 <= dstReg && dstReg <= X31 {
519 vBytes = 16
520 } else if Y0 <= dstReg && dstReg <= Y31 {
521 vBytes = 32
522 } else if Z0 <= dstReg && dstReg <= Z31 {
523 vBytes = 64
524 }
525 if vBytes > 0 && inst.MemBytes > 0 {
526 argStr += fmt.Sprintf("{1to%d}", vBytes/inst.MemBytes)
527 }
528 }
529 }
530 args = append(args, argStr)
531 }
532
533 if inst.SAE {
534 var sae string
535 if hasRC(inst.Op) {
536 switch inst.Rounding {
537 case 0:
538 sae = "{rn-sae}"
539 case 1:
540 sae = "{rd-sae}"
541 case 2:
542 sae = "{ru-sae}"
543 case 3:
544 sae = "{rz-sae}"
545 }
546 } else {
547 sae = "{sae}"
548 }
549 args = append(args, sae)
550 }
551
552
553
554 switch inst.Op {
555 case BOUND, LCALL, ENTER, LJMP:
556
557 default:
558
559 for i, j := 0, len(args)-1; i < j; i, j = i+1, j-1 {
560 args[i], args[j] = args[j], args[i]
561 }
562 }
563
564
565
566 var (
567 prefix = ""
568 numAddr = 0
569 numData = 0
570 implicitData = false
571 )
572 for _, p := range inst.Prefix {
573 if p&0xFF == PrefixDataSize && p&PrefixImplicit != 0 {
574 implicitData = true
575 }
576 }
577 for _, p := range inst.Prefix {
578 if p == 0 || p.IsVEX() || p.IsEVEX() {
579 break
580 }
581 if p&PrefixImplicit != 0 {
582 continue
583 }
584 switch p &^ (PrefixIgnored | PrefixInvalid) {
585 default:
586 if p.IsREX() {
587 if p&0xFF == PrefixREX {
588 prefix += "rex "
589 } else {
590 prefix += "rex." + p.String()[4:] + " "
591 }
592 break
593 }
594 prefix += strings.ToLower(p.String()) + " "
595
596 case PrefixPN:
597 op += ",pn"
598 continue
599
600 case PrefixPT:
601 op += ",pt"
602 continue
603
604 case PrefixAddrSize, PrefixAddr16, PrefixAddr32:
605
606
607
608
609 n := 32
610 if inst.Mode == 32 {
611 n = 16
612 }
613 numAddr++
614 if countPrefix(&inst, PrefixAddrSize) > numAddr {
615 n = inst.Mode
616 }
617 prefix += fmt.Sprintf("addr%d ", n)
618 continue
619
620 case PrefixData16, PrefixData32:
621 if implicitData && countPrefix(&inst, PrefixDataSize) > 1 {
622
623
624 n := 16
625 if inst.Mode == 16 {
626 n = 32
627 }
628 numData++
629 if countPrefix(&inst, PrefixDataSize) > numData {
630 if inst.Mode == 16 {
631 n = 16
632 } else {
633 n = 32
634 }
635 }
636 prefix += fmt.Sprintf("data%d ", n)
637 continue
638 }
639 prefix += strings.ToLower(p.String()) + " "
640 }
641 }
642
643
644 text := prefix + op
645 if args != nil {
646 text += " "
647
648 if (inst.Op == CALL || inst.Op == JMP || inst.Op == LJMP || inst.Op == LCALL) && (isMem(inst.Args[0]) || isReg(inst.Args[0])) {
649 text += "*"
650 }
651 text += strings.Join(args, ",")
652 }
653 return text
654 }
655
656
657
658
659 func gnuArg(inst *Inst, pc uint64, symname SymLookup, x Arg, usedPrefixes *bool) string {
660 if x == nil {
661 return "<nil>"
662 }
663 switch x := x.(type) {
664 case Reg:
665 switch inst.Op {
666 case CVTSI2SS, CVTSI2SD, CVTSS2SI, CVTSD2SI, CVTTSD2SI, CVTTSS2SI:
667 if inst.DataSize == 16 && EAX <= x && x <= R15L {
668 x -= EAX - AX
669 }
670
671 case IN, INSB, INSW, INSD, OUT, OUTSB, OUTSW, OUTSD:
672
673 if x == DX {
674 return "(%dx)"
675 }
676 }
677 return gccRegName[x]
678 case Mem:
679 if s, disp := memArgToSymbol(x, pc, inst.Len, symname); s != "" {
680 suffix := ""
681 if disp != 0 {
682 suffix = fmt.Sprintf("%+d", disp)
683 }
684 return fmt.Sprintf("%s%s", s, suffix)
685 }
686 seg := ""
687 var haveCS, haveDS, haveES, haveFS, haveGS, haveSS bool
688 switch x.Segment {
689 case CS:
690 haveCS = true
691 case DS:
692 haveDS = true
693 case ES:
694 haveES = true
695 case FS:
696 haveFS = true
697 case GS:
698 haveGS = true
699 case SS:
700 haveSS = true
701 }
702 switch inst.Op {
703 case INSB, INSW, INSD, STOSB, STOSW, STOSD, STOSQ, SCASB, SCASW, SCASD, SCASQ:
704
705 default:
706 if isVSIB(inst.Op) {
707 haveCS, haveDS, haveES, haveSS = false, false, false, false
708 break
709 }
710 if *usedPrefixes {
711 break
712 }
713 for i := len(inst.Prefix) - 1; i >= 0; i-- {
714 p := inst.Prefix[i] &^ PrefixIgnored
715 if p == 0 {
716 continue
717 }
718 switch p {
719 case PrefixCS:
720 if !haveCS {
721 haveCS = true
722 inst.Prefix[i] |= PrefixImplicit
723 }
724 case PrefixDS:
725 if !haveDS {
726 haveDS = true
727 inst.Prefix[i] |= PrefixImplicit
728 }
729 case PrefixES:
730 if !haveES {
731 haveES = true
732 inst.Prefix[i] |= PrefixImplicit
733 }
734 case PrefixFS:
735 if !haveFS {
736 haveFS = true
737 inst.Prefix[i] |= PrefixImplicit
738 }
739 case PrefixGS:
740 if !haveGS {
741 haveGS = true
742 inst.Prefix[i] |= PrefixImplicit
743 }
744 case PrefixSS:
745 if !haveSS {
746 haveSS = true
747 inst.Prefix[i] |= PrefixImplicit
748 }
749 }
750 }
751 *usedPrefixes = true
752 }
753 if haveCS {
754 seg += "%cs:"
755 }
756 if haveDS {
757 seg += "%ds:"
758 }
759 if haveSS {
760 seg += "%ss:"
761 }
762 if haveES {
763 seg += "%es:"
764 }
765 if haveFS {
766 seg += "%fs:"
767 }
768 if haveGS {
769 seg += "%gs:"
770 }
771 disp := ""
772 if x.Disp != 0 {
773 disp = fmt.Sprintf("%#x", x.Disp)
774 }
775 if x.Scale == 0 || x.Index == 0 && x.Scale == 1 && (x.Base == ESP || x.Base == RSP || x.Base == 0 && inst.Mode == 64) {
776 if x.Base == 0 {
777 return seg + disp
778 }
779 return fmt.Sprintf("%s%s(%s)", seg, disp, gccRegName[x.Base])
780 }
781 base := gccRegName[x.Base]
782 if x.Base == 0 {
783 base = ""
784 }
785 index := gccRegName[x.Index]
786 if x.Index == 0 {
787 if inst.AddrSize == 64 {
788 index = "%riz"
789 } else {
790 index = "%eiz"
791 }
792 }
793 if AX <= x.Base && x.Base <= DI {
794
795 return fmt.Sprintf("%s%s(%s,%s)", seg, disp, base, index)
796 }
797 if x.Scale == 1 {
798
799
800 if inst.Op.String() == "VMOVNTDQA" {
801 return fmt.Sprintf("%s%s(%s,%s,1)", seg, disp, base, index)
802 }
803 return fmt.Sprintf("%s%s(%s,%s)", seg, disp, base, index)
804 }
805 return fmt.Sprintf("%s%s(%s,%s,%d)", seg, disp, base, index, x.Scale)
806 case Rel:
807 if pc == 0 {
808 return fmt.Sprintf(".%+#x", int64(x))
809 } else {
810 addr := pc + uint64(inst.Len) + uint64(x)
811 if s, base := symname(addr); s != "" && addr == base {
812 return fmt.Sprintf("%s", s)
813 } else {
814 addr := pc + uint64(inst.Len) + uint64(x)
815 return fmt.Sprintf("%#x", addr)
816 }
817 }
818 case Imm:
819 if (inst.Op == MOV || inst.Op == PUSH) && inst.DataSize == 32 {
820 if s, base := symname(uint64(x)); s != "" {
821 suffix := ""
822 if uint64(x) != base {
823 suffix = fmt.Sprintf("%+d", uint64(x)-base)
824 }
825 return fmt.Sprintf("$%s%s", s, suffix)
826 }
827 }
828 if inst.Mode == 32 {
829 return fmt.Sprintf("$%#x", uint32(x))
830 }
831 return fmt.Sprintf("$%#x", int64(x))
832 }
833 return x.String()
834 }
835
836 var gccRegName = [...]string{
837 0: "REG0",
838 AL: "%al",
839 CL: "%cl",
840 BL: "%bl",
841 DL: "%dl",
842 AH: "%ah",
843 CH: "%ch",
844 BH: "%bh",
845 DH: "%dh",
846 SPB: "%spl",
847 BPB: "%bpl",
848 SIB: "%sil",
849 DIB: "%dil",
850 R8B: "%r8b",
851 R9B: "%r9b",
852 R10B: "%r10b",
853 R11B: "%r11b",
854 R12B: "%r12b",
855 R13B: "%r13b",
856 R14B: "%r14b",
857 R15B: "%r15b",
858 AX: "%ax",
859 CX: "%cx",
860 BX: "%bx",
861 DX: "%dx",
862 SP: "%sp",
863 BP: "%bp",
864 SI: "%si",
865 DI: "%di",
866 R8W: "%r8w",
867 R9W: "%r9w",
868 R10W: "%r10w",
869 R11W: "%r11w",
870 R12W: "%r12w",
871 R13W: "%r13w",
872 R14W: "%r14w",
873 R15W: "%r15w",
874 EAX: "%eax",
875 ECX: "%ecx",
876 EDX: "%edx",
877 EBX: "%ebx",
878 ESP: "%esp",
879 EBP: "%ebp",
880 ESI: "%esi",
881 EDI: "%edi",
882 R8L: "%r8d",
883 R9L: "%r9d",
884 R10L: "%r10d",
885 R11L: "%r11d",
886 R12L: "%r12d",
887 R13L: "%r13d",
888 R14L: "%r14d",
889 R15L: "%r15d",
890 RAX: "%rax",
891 RCX: "%rcx",
892 RDX: "%rdx",
893 RBX: "%rbx",
894 RSP: "%rsp",
895 RBP: "%rbp",
896 RSI: "%rsi",
897 RDI: "%rdi",
898 R8: "%r8",
899 R9: "%r9",
900 R10: "%r10",
901 R11: "%r11",
902 R12: "%r12",
903 R13: "%r13",
904 R14: "%r14",
905 R15: "%r15",
906 IP: "%ip",
907 EIP: "%eip",
908 RIP: "%rip",
909 F0: "%st",
910 F1: "%st(1)",
911 F2: "%st(2)",
912 F3: "%st(3)",
913 F4: "%st(4)",
914 F5: "%st(5)",
915 F6: "%st(6)",
916 F7: "%st(7)",
917 M0: "%mm0",
918 M1: "%mm1",
919 M2: "%mm2",
920 M3: "%mm3",
921 M4: "%mm4",
922 M5: "%mm5",
923 M6: "%mm6",
924 M7: "%mm7",
925 X0: "%xmm0",
926 X1: "%xmm1",
927 X2: "%xmm2",
928 X3: "%xmm3",
929 X4: "%xmm4",
930 X5: "%xmm5",
931 X6: "%xmm6",
932 X7: "%xmm7",
933 X8: "%xmm8",
934 X9: "%xmm9",
935 X10: "%xmm10",
936 X11: "%xmm11",
937 X12: "%xmm12",
938 X13: "%xmm13",
939 X14: "%xmm14",
940 X15: "%xmm15",
941 X16: "%xmm16",
942 X17: "%xmm17",
943 X18: "%xmm18",
944 X19: "%xmm19",
945 X20: "%xmm20",
946 X21: "%xmm21",
947 X22: "%xmm22",
948 X23: "%xmm23",
949 X24: "%xmm24",
950 X25: "%xmm25",
951 X26: "%xmm26",
952 X27: "%xmm27",
953 X28: "%xmm28",
954 X29: "%xmm29",
955 X30: "%xmm30",
956 X31: "%xmm31",
957 Y0: "%ymm0",
958 Y1: "%ymm1",
959 Y2: "%ymm2",
960 Y3: "%ymm3",
961 Y4: "%ymm4",
962 Y5: "%ymm5",
963 Y6: "%ymm6",
964 Y7: "%ymm7",
965 Y8: "%ymm8",
966 Y9: "%ymm9",
967 Y10: "%ymm10",
968 Y11: "%ymm11",
969 Y12: "%ymm12",
970 Y13: "%ymm13",
971 Y14: "%ymm14",
972 Y15: "%ymm15",
973 Y16: "%ymm16",
974 Y17: "%ymm17",
975 Y18: "%ymm18",
976 Y19: "%ymm19",
977 Y20: "%ymm20",
978 Y21: "%ymm21",
979 Y22: "%ymm22",
980 Y23: "%ymm23",
981 Y24: "%ymm24",
982 Y25: "%ymm25",
983 Y26: "%ymm26",
984 Y27: "%ymm27",
985 Y28: "%ymm28",
986 Y29: "%ymm29",
987 Y30: "%ymm30",
988 Y31: "%ymm31",
989 Z0: "%zmm0",
990 Z1: "%zmm1",
991 Z2: "%zmm2",
992 Z3: "%zmm3",
993 Z4: "%zmm4",
994 Z5: "%zmm5",
995 Z6: "%zmm6",
996 Z7: "%zmm7",
997 Z8: "%zmm8",
998 Z9: "%zmm9",
999 Z10: "%zmm10",
1000 Z11: "%zmm11",
1001 Z12: "%zmm12",
1002 Z13: "%zmm13",
1003 Z14: "%zmm14",
1004 Z15: "%zmm15",
1005 Z16: "%zmm16",
1006 Z17: "%zmm17",
1007 Z18: "%zmm18",
1008 Z19: "%zmm19",
1009 Z20: "%zmm20",
1010 Z21: "%zmm21",
1011 Z22: "%zmm22",
1012 Z23: "%zmm23",
1013 Z24: "%zmm24",
1014 Z25: "%zmm25",
1015 Z26: "%zmm26",
1016 Z27: "%zmm27",
1017 Z28: "%zmm28",
1018 Z29: "%zmm29",
1019 Z30: "%zmm30",
1020 Z31: "%zmm31",
1021 K0: "%k0",
1022 K1: "%k1",
1023 K2: "%k2",
1024 K3: "%k3",
1025 K4: "%k4",
1026 K5: "%k5",
1027 K6: "%k6",
1028 K7: "%k7",
1029 CS: "%cs",
1030 SS: "%ss",
1031 DS: "%ds",
1032 ES: "%es",
1033 FS: "%fs",
1034 GS: "%gs",
1035 GDTR: "%gdtr",
1036 IDTR: "%idtr",
1037 LDTR: "%ldtr",
1038 MSW: "%msw",
1039 TASK: "%task",
1040 CR0: "%cr0",
1041 CR1: "%cr1",
1042 CR2: "%cr2",
1043 CR3: "%cr3",
1044 CR4: "%cr4",
1045 CR5: "%cr5",
1046 CR6: "%cr6",
1047 CR7: "%cr7",
1048 CR8: "%cr8",
1049 CR9: "%cr9",
1050 CR10: "%cr10",
1051 CR11: "%cr11",
1052 CR12: "%cr12",
1053 CR13: "%cr13",
1054 CR14: "%cr14",
1055 CR15: "%cr15",
1056 DR0: "%db0",
1057 DR1: "%db1",
1058 DR2: "%db2",
1059 DR3: "%db3",
1060 DR4: "%db4",
1061 DR5: "%db5",
1062 DR6: "%db6",
1063 DR7: "%db7",
1064 TR0: "%tr0",
1065 TR1: "%tr1",
1066 TR2: "%tr2",
1067 TR3: "%tr3",
1068 TR4: "%tr4",
1069 TR5: "%tr5",
1070 TR6: "%tr6",
1071 TR7: "%tr7",
1072 }
1073
1074 var gnuOp = map[Op]string{
1075 CBW: "cbtw",
1076 CDQ: "cltd",
1077 CMPSD: "cmpsl",
1078 CMPSD_XMM: "cmpsd",
1079 CWD: "cwtd",
1080 CWDE: "cwtl",
1081 CQO: "cqto",
1082 INSD: "insl",
1083 IRET: "iretw",
1084 IRETD: "iret",
1085 IRETQ: "iretq",
1086 LODSB: "lods",
1087 LODSD: "lods",
1088 LODSQ: "lods",
1089 LODSW: "lods",
1090 MOVSD: "movsl",
1091 MOVSD_XMM: "movsd",
1092 OUTSD: "outsl",
1093 POPA: "popaw",
1094 POPAD: "popa",
1095 POPF: "popfw",
1096 POPFD: "popf",
1097 PUSHA: "pushaw",
1098 PUSHAD: "pusha",
1099 PUSHF: "pushfw",
1100 PUSHFD: "pushf",
1101 SCASB: "scas",
1102 SCASD: "scas",
1103 SCASQ: "scas",
1104 SCASW: "scas",
1105 STOSB: "stos",
1106 STOSD: "stos",
1107 STOSQ: "stos",
1108 STOSW: "stos",
1109 XLATB: "xlat",
1110 }
1111
1112 var cmppsOps = []string{
1113 "cmpeq",
1114 "cmplt",
1115 "cmple",
1116 "cmpunord",
1117 "cmpneq",
1118 "cmpnlt",
1119 "cmpnle",
1120 "cmpord",
1121 }
1122
1123 var pclmulqOps = []string{
1124 "pclmullqlqdq",
1125 "pclmulhqlqdq",
1126 "pclmullqhqdq",
1127 "pclmulhqhqdq",
1128 }
1129
1130 func countPrefix(inst *Inst, target Prefix) int {
1131 n := 0
1132 for _, p := range inst.Prefix {
1133 if p&0xFF == target&0xFF {
1134 n++
1135 }
1136 }
1137 return n
1138 }
1139
1140 func markLastImplicit(inst *Inst, prefix Prefix) bool {
1141 for i := len(inst.Prefix) - 1; i >= 0; i-- {
1142 p := inst.Prefix[i]
1143 if p&0xFF == prefix {
1144 inst.Prefix[i] |= PrefixImplicit
1145 return true
1146 }
1147 }
1148 return false
1149 }
1150
1151 func unmarkImplicit(inst *Inst, prefix Prefix) {
1152 for i := len(inst.Prefix) - 1; i >= 0; i-- {
1153 p := inst.Prefix[i]
1154 if p&0xFF == prefix {
1155 inst.Prefix[i] &^= PrefixImplicit
1156 }
1157 }
1158 }
1159
1160 func byteSizeSuffix(b int) string {
1161 switch b {
1162 case 1:
1163 return "b"
1164 case 2:
1165 return "w"
1166 case 4:
1167 return "l"
1168 case 8:
1169 return "q"
1170 }
1171 return ""
1172 }
1173
1174 func argBytes(inst *Inst, arg Arg) int {
1175 if isMem(arg) {
1176 return inst.MemBytes
1177 }
1178 return regBytes(arg)
1179 }
1180
1181 func isFloat(op Op) bool {
1182 switch op {
1183 case FADD, FCOM, FCOMP, FDIV, FDIVR, FIADD, FICOM, FICOMP, FIDIV, FIDIVR, FILD, FIMUL, FIST, FISTP, FISTTP, FISUB, FISUBR, FLD, FMUL, FST, FSTP, FSUB, FSUBR:
1184 return true
1185 }
1186 return false
1187 }
1188
1189 func isFloatInt(op Op) bool {
1190 switch op {
1191 case FIADD, FICOM, FICOMP, FIDIV, FIDIVR, FILD, FIMUL, FIST, FISTP, FISTTP, FISUB, FISUBR:
1192 return true
1193 }
1194 return false
1195 }
1196
View as plain text