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 <= X15 || M0 <= a && a <= M7 {
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:
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
358 switch inst.Op {
359 case 0:
360 if inst.Prefix[0] != 0 {
361 return strings.ToLower(inst.Prefix[0].String())
362 }
363
364 case INT:
365 if inst.Opcode>>24 == 0xCC {
366 inst.Args[0] = nil
367 op = "int3"
368 }
369
370 case CMPPS, CMPPD, CMPSD_XMM, CMPSS:
371 imm, ok := inst.Args[2].(Imm)
372 if ok && 0 <= imm && imm < 8 {
373 inst.Args[2] = nil
374 op = cmppsOps[imm] + op[3:]
375 }
376
377 case PCLMULQDQ:
378 imm, ok := inst.Args[2].(Imm)
379 if ok && imm&^0x11 == 0 {
380 inst.Args[2] = nil
381 op = pclmulqOps[(imm&0x10)>>3|(imm&1)]
382 }
383
384 case XLATB:
385 if markLastImplicit(&inst, PrefixAddrSize) {
386 op = "xlat"
387 }
388 }
389
390
391 var (
392 usedPrefixes bool
393 args []string
394 )
395 for i, a := range inst.Args {
396 if a == nil {
397 break
398 }
399 switch inst.Op {
400 case MOVSB, MOVSW, MOVSD, MOVSQ, OUTSB, OUTSW, OUTSD:
401 if i == 0 {
402 usedPrefixes = true
403 } else {
404 usedPrefixes = false
405 }
406 }
407 if a == Imm(1) && (inst.Opcode>>24)&^1 == 0xD0 {
408 continue
409 }
410 args = append(args, gnuArg(&inst, pc, symname, a, &usedPrefixes))
411 }
412
413
414
415 switch inst.Op {
416 case BOUND, LCALL, ENTER, LJMP:
417
418 default:
419
420 for i, j := 0, len(args)-1; i < j; i, j = i+1, j-1 {
421 args[i], args[j] = args[j], args[i]
422 }
423 }
424
425
426
427 var (
428 prefix = ""
429 numAddr = 0
430 numData = 0
431 implicitData = false
432 )
433 for _, p := range inst.Prefix {
434 if p&0xFF == PrefixDataSize && p&PrefixImplicit != 0 {
435 implicitData = true
436 }
437 }
438 for _, p := range inst.Prefix {
439 if p == 0 || p.IsVEX() {
440 break
441 }
442 if p&PrefixImplicit != 0 {
443 continue
444 }
445 switch p &^ (PrefixIgnored | PrefixInvalid) {
446 default:
447 if p.IsREX() {
448 if p&0xFF == PrefixREX {
449 prefix += "rex "
450 } else {
451 prefix += "rex." + p.String()[4:] + " "
452 }
453 break
454 }
455 prefix += strings.ToLower(p.String()) + " "
456
457 case PrefixPN:
458 op += ",pn"
459 continue
460
461 case PrefixPT:
462 op += ",pt"
463 continue
464
465 case PrefixAddrSize, PrefixAddr16, PrefixAddr32:
466
467
468
469
470 n := 32
471 if inst.Mode == 32 {
472 n = 16
473 }
474 numAddr++
475 if countPrefix(&inst, PrefixAddrSize) > numAddr {
476 n = inst.Mode
477 }
478 prefix += fmt.Sprintf("addr%d ", n)
479 continue
480
481 case PrefixData16, PrefixData32:
482 if implicitData && countPrefix(&inst, PrefixDataSize) > 1 {
483
484
485 n := 16
486 if inst.Mode == 16 {
487 n = 32
488 }
489 numData++
490 if countPrefix(&inst, PrefixDataSize) > numData {
491 if inst.Mode == 16 {
492 n = 16
493 } else {
494 n = 32
495 }
496 }
497 prefix += fmt.Sprintf("data%d ", n)
498 continue
499 }
500 prefix += strings.ToLower(p.String()) + " "
501 }
502 }
503
504
505 text := prefix + op
506 if args != nil {
507 text += " "
508
509 if (inst.Op == CALL || inst.Op == JMP || inst.Op == LJMP || inst.Op == LCALL) && (isMem(inst.Args[0]) || isReg(inst.Args[0])) {
510 text += "*"
511 }
512 text += strings.Join(args, ",")
513 }
514 return text
515 }
516
517
518
519
520 func gnuArg(inst *Inst, pc uint64, symname SymLookup, x Arg, usedPrefixes *bool) string {
521 if x == nil {
522 return "<nil>"
523 }
524 switch x := x.(type) {
525 case Reg:
526 switch inst.Op {
527 case CVTSI2SS, CVTSI2SD, CVTSS2SI, CVTSD2SI, CVTTSD2SI, CVTTSS2SI:
528 if inst.DataSize == 16 && EAX <= x && x <= R15L {
529 x -= EAX - AX
530 }
531
532 case IN, INSB, INSW, INSD, OUT, OUTSB, OUTSW, OUTSD:
533
534 if x == DX {
535 return "(%dx)"
536 }
537 case VMOVDQA, VMOVDQU, VMOVNTDQA, VMOVNTDQ:
538 return strings.Replace(gccRegName[x], "xmm", "ymm", -1)
539 }
540 return gccRegName[x]
541 case Mem:
542 if s, disp := memArgToSymbol(x, pc, inst.Len, symname); s != "" {
543 suffix := ""
544 if disp != 0 {
545 suffix = fmt.Sprintf("%+d", disp)
546 }
547 return fmt.Sprintf("%s%s", s, suffix)
548 }
549 seg := ""
550 var haveCS, haveDS, haveES, haveFS, haveGS, haveSS bool
551 switch x.Segment {
552 case CS:
553 haveCS = true
554 case DS:
555 haveDS = true
556 case ES:
557 haveES = true
558 case FS:
559 haveFS = true
560 case GS:
561 haveGS = true
562 case SS:
563 haveSS = true
564 }
565 switch inst.Op {
566 case INSB, INSW, INSD, STOSB, STOSW, STOSD, STOSQ, SCASB, SCASW, SCASD, SCASQ:
567
568 default:
569 if *usedPrefixes {
570 break
571 }
572 for i := len(inst.Prefix) - 1; i >= 0; i-- {
573 p := inst.Prefix[i] &^ PrefixIgnored
574 if p == 0 {
575 continue
576 }
577 switch p {
578 case PrefixCS:
579 if !haveCS {
580 haveCS = true
581 inst.Prefix[i] |= PrefixImplicit
582 }
583 case PrefixDS:
584 if !haveDS {
585 haveDS = true
586 inst.Prefix[i] |= PrefixImplicit
587 }
588 case PrefixES:
589 if !haveES {
590 haveES = true
591 inst.Prefix[i] |= PrefixImplicit
592 }
593 case PrefixFS:
594 if !haveFS {
595 haveFS = true
596 inst.Prefix[i] |= PrefixImplicit
597 }
598 case PrefixGS:
599 if !haveGS {
600 haveGS = true
601 inst.Prefix[i] |= PrefixImplicit
602 }
603 case PrefixSS:
604 if !haveSS {
605 haveSS = true
606 inst.Prefix[i] |= PrefixImplicit
607 }
608 }
609 }
610 *usedPrefixes = true
611 }
612 if haveCS {
613 seg += "%cs:"
614 }
615 if haveDS {
616 seg += "%ds:"
617 }
618 if haveSS {
619 seg += "%ss:"
620 }
621 if haveES {
622 seg += "%es:"
623 }
624 if haveFS {
625 seg += "%fs:"
626 }
627 if haveGS {
628 seg += "%gs:"
629 }
630 disp := ""
631 if x.Disp != 0 {
632 disp = fmt.Sprintf("%#x", x.Disp)
633 }
634 if x.Scale == 0 || x.Index == 0 && x.Scale == 1 && (x.Base == ESP || x.Base == RSP || x.Base == 0 && inst.Mode == 64) {
635 if x.Base == 0 {
636 return seg + disp
637 }
638 return fmt.Sprintf("%s%s(%s)", seg, disp, gccRegName[x.Base])
639 }
640 base := gccRegName[x.Base]
641 if x.Base == 0 {
642 base = ""
643 }
644 index := gccRegName[x.Index]
645 if x.Index == 0 {
646 if inst.AddrSize == 64 {
647 index = "%riz"
648 } else {
649 index = "%eiz"
650 }
651 }
652 if AX <= x.Base && x.Base <= DI {
653
654 return fmt.Sprintf("%s%s(%s,%s)", seg, disp, base, index)
655 }
656 return fmt.Sprintf("%s%s(%s,%s,%d)", seg, disp, base, index, x.Scale)
657 case Rel:
658 if pc == 0 {
659 return fmt.Sprintf(".%+#x", int64(x))
660 } else {
661 addr := pc + uint64(inst.Len) + uint64(x)
662 if s, base := symname(addr); s != "" && addr == base {
663 return fmt.Sprintf("%s", s)
664 } else {
665 addr := pc + uint64(inst.Len) + uint64(x)
666 return fmt.Sprintf("%#x", addr)
667 }
668 }
669 case Imm:
670 if (inst.Op == MOV || inst.Op == PUSH) && inst.DataSize == 32 {
671 if s, base := symname(uint64(x)); s != "" {
672 suffix := ""
673 if uint64(x) != base {
674 suffix = fmt.Sprintf("%+d", uint64(x)-base)
675 }
676 return fmt.Sprintf("$%s%s", s, suffix)
677 }
678 }
679 if inst.Mode == 32 {
680 return fmt.Sprintf("$%#x", uint32(x))
681 }
682 return fmt.Sprintf("$%#x", int64(x))
683 }
684 return x.String()
685 }
686
687 var gccRegName = [...]string{
688 0: "REG0",
689 AL: "%al",
690 CL: "%cl",
691 BL: "%bl",
692 DL: "%dl",
693 AH: "%ah",
694 CH: "%ch",
695 BH: "%bh",
696 DH: "%dh",
697 SPB: "%spl",
698 BPB: "%bpl",
699 SIB: "%sil",
700 DIB: "%dil",
701 R8B: "%r8b",
702 R9B: "%r9b",
703 R10B: "%r10b",
704 R11B: "%r11b",
705 R12B: "%r12b",
706 R13B: "%r13b",
707 R14B: "%r14b",
708 R15B: "%r15b",
709 AX: "%ax",
710 CX: "%cx",
711 BX: "%bx",
712 DX: "%dx",
713 SP: "%sp",
714 BP: "%bp",
715 SI: "%si",
716 DI: "%di",
717 R8W: "%r8w",
718 R9W: "%r9w",
719 R10W: "%r10w",
720 R11W: "%r11w",
721 R12W: "%r12w",
722 R13W: "%r13w",
723 R14W: "%r14w",
724 R15W: "%r15w",
725 EAX: "%eax",
726 ECX: "%ecx",
727 EDX: "%edx",
728 EBX: "%ebx",
729 ESP: "%esp",
730 EBP: "%ebp",
731 ESI: "%esi",
732 EDI: "%edi",
733 R8L: "%r8d",
734 R9L: "%r9d",
735 R10L: "%r10d",
736 R11L: "%r11d",
737 R12L: "%r12d",
738 R13L: "%r13d",
739 R14L: "%r14d",
740 R15L: "%r15d",
741 RAX: "%rax",
742 RCX: "%rcx",
743 RDX: "%rdx",
744 RBX: "%rbx",
745 RSP: "%rsp",
746 RBP: "%rbp",
747 RSI: "%rsi",
748 RDI: "%rdi",
749 R8: "%r8",
750 R9: "%r9",
751 R10: "%r10",
752 R11: "%r11",
753 R12: "%r12",
754 R13: "%r13",
755 R14: "%r14",
756 R15: "%r15",
757 IP: "%ip",
758 EIP: "%eip",
759 RIP: "%rip",
760 F0: "%st",
761 F1: "%st(1)",
762 F2: "%st(2)",
763 F3: "%st(3)",
764 F4: "%st(4)",
765 F5: "%st(5)",
766 F6: "%st(6)",
767 F7: "%st(7)",
768 M0: "%mm0",
769 M1: "%mm1",
770 M2: "%mm2",
771 M3: "%mm3",
772 M4: "%mm4",
773 M5: "%mm5",
774 M6: "%mm6",
775 M7: "%mm7",
776 X0: "%xmm0",
777 X1: "%xmm1",
778 X2: "%xmm2",
779 X3: "%xmm3",
780 X4: "%xmm4",
781 X5: "%xmm5",
782 X6: "%xmm6",
783 X7: "%xmm7",
784 X8: "%xmm8",
785 X9: "%xmm9",
786 X10: "%xmm10",
787 X11: "%xmm11",
788 X12: "%xmm12",
789 X13: "%xmm13",
790 X14: "%xmm14",
791 X15: "%xmm15",
792 CS: "%cs",
793 SS: "%ss",
794 DS: "%ds",
795 ES: "%es",
796 FS: "%fs",
797 GS: "%gs",
798 GDTR: "%gdtr",
799 IDTR: "%idtr",
800 LDTR: "%ldtr",
801 MSW: "%msw",
802 TASK: "%task",
803 CR0: "%cr0",
804 CR1: "%cr1",
805 CR2: "%cr2",
806 CR3: "%cr3",
807 CR4: "%cr4",
808 CR5: "%cr5",
809 CR6: "%cr6",
810 CR7: "%cr7",
811 CR8: "%cr8",
812 CR9: "%cr9",
813 CR10: "%cr10",
814 CR11: "%cr11",
815 CR12: "%cr12",
816 CR13: "%cr13",
817 CR14: "%cr14",
818 CR15: "%cr15",
819 DR0: "%db0",
820 DR1: "%db1",
821 DR2: "%db2",
822 DR3: "%db3",
823 DR4: "%db4",
824 DR5: "%db5",
825 DR6: "%db6",
826 DR7: "%db7",
827 TR0: "%tr0",
828 TR1: "%tr1",
829 TR2: "%tr2",
830 TR3: "%tr3",
831 TR4: "%tr4",
832 TR5: "%tr5",
833 TR6: "%tr6",
834 TR7: "%tr7",
835 }
836
837 var gnuOp = map[Op]string{
838 CBW: "cbtw",
839 CDQ: "cltd",
840 CMPSD: "cmpsl",
841 CMPSD_XMM: "cmpsd",
842 CWD: "cwtd",
843 CWDE: "cwtl",
844 CQO: "cqto",
845 INSD: "insl",
846 IRET: "iretw",
847 IRETD: "iret",
848 IRETQ: "iretq",
849 LODSB: "lods",
850 LODSD: "lods",
851 LODSQ: "lods",
852 LODSW: "lods",
853 MOVSD: "movsl",
854 MOVSD_XMM: "movsd",
855 OUTSD: "outsl",
856 POPA: "popaw",
857 POPAD: "popa",
858 POPF: "popfw",
859 POPFD: "popf",
860 PUSHA: "pushaw",
861 PUSHAD: "pusha",
862 PUSHF: "pushfw",
863 PUSHFD: "pushf",
864 SCASB: "scas",
865 SCASD: "scas",
866 SCASQ: "scas",
867 SCASW: "scas",
868 STOSB: "stos",
869 STOSD: "stos",
870 STOSQ: "stos",
871 STOSW: "stos",
872 XLATB: "xlat",
873 }
874
875 var cmppsOps = []string{
876 "cmpeq",
877 "cmplt",
878 "cmple",
879 "cmpunord",
880 "cmpneq",
881 "cmpnlt",
882 "cmpnle",
883 "cmpord",
884 }
885
886 var pclmulqOps = []string{
887 "pclmullqlqdq",
888 "pclmulhqlqdq",
889 "pclmullqhqdq",
890 "pclmulhqhqdq",
891 }
892
893 func countPrefix(inst *Inst, target Prefix) int {
894 n := 0
895 for _, p := range inst.Prefix {
896 if p&0xFF == target&0xFF {
897 n++
898 }
899 }
900 return n
901 }
902
903 func markLastImplicit(inst *Inst, prefix Prefix) bool {
904 for i := len(inst.Prefix) - 1; i >= 0; i-- {
905 p := inst.Prefix[i]
906 if p&0xFF == prefix {
907 inst.Prefix[i] |= PrefixImplicit
908 return true
909 }
910 }
911 return false
912 }
913
914 func unmarkImplicit(inst *Inst, prefix Prefix) {
915 for i := len(inst.Prefix) - 1; i >= 0; i-- {
916 p := inst.Prefix[i]
917 if p&0xFF == prefix {
918 inst.Prefix[i] &^= PrefixImplicit
919 }
920 }
921 }
922
923 func byteSizeSuffix(b int) string {
924 switch b {
925 case 1:
926 return "b"
927 case 2:
928 return "w"
929 case 4:
930 return "l"
931 case 8:
932 return "q"
933 }
934 return ""
935 }
936
937 func argBytes(inst *Inst, arg Arg) int {
938 if isMem(arg) {
939 return inst.MemBytes
940 }
941 return regBytes(arg)
942 }
943
944 func isFloat(op Op) bool {
945 switch op {
946 case FADD, FCOM, FCOMP, FDIV, FDIVR, FIADD, FICOM, FICOMP, FIDIV, FIDIVR, FILD, FIMUL, FIST, FISTP, FISTTP, FISUB, FISUBR, FLD, FMUL, FST, FSTP, FSUB, FSUBR:
947 return true
948 }
949 return false
950 }
951
952 func isFloatInt(op Op) bool {
953 switch op {
954 case FIADD, FICOM, FICOMP, FIDIV, FIDIVR, FILD, FIMUL, FIST, FISTP, FISTTP, FISUB, FISUBR:
955 return true
956 }
957 return false
958 }
959
View as plain text