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