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 s, base := symname(uint64(x)); s != "" {
671 suffix := ""
672 if uint64(x) != base {
673 suffix = fmt.Sprintf("%+d", uint64(x)-base)
674 }
675 return fmt.Sprintf("$%s%s", s, suffix)
676 }
677 if inst.Mode == 32 {
678 return fmt.Sprintf("$%#x", uint32(x))
679 }
680 return fmt.Sprintf("$%#x", int64(x))
681 }
682 return x.String()
683 }
684
685 var gccRegName = [...]string{
686 0: "REG0",
687 AL: "%al",
688 CL: "%cl",
689 BL: "%bl",
690 DL: "%dl",
691 AH: "%ah",
692 CH: "%ch",
693 BH: "%bh",
694 DH: "%dh",
695 SPB: "%spl",
696 BPB: "%bpl",
697 SIB: "%sil",
698 DIB: "%dil",
699 R8B: "%r8b",
700 R9B: "%r9b",
701 R10B: "%r10b",
702 R11B: "%r11b",
703 R12B: "%r12b",
704 R13B: "%r13b",
705 R14B: "%r14b",
706 R15B: "%r15b",
707 AX: "%ax",
708 CX: "%cx",
709 BX: "%bx",
710 DX: "%dx",
711 SP: "%sp",
712 BP: "%bp",
713 SI: "%si",
714 DI: "%di",
715 R8W: "%r8w",
716 R9W: "%r9w",
717 R10W: "%r10w",
718 R11W: "%r11w",
719 R12W: "%r12w",
720 R13W: "%r13w",
721 R14W: "%r14w",
722 R15W: "%r15w",
723 EAX: "%eax",
724 ECX: "%ecx",
725 EDX: "%edx",
726 EBX: "%ebx",
727 ESP: "%esp",
728 EBP: "%ebp",
729 ESI: "%esi",
730 EDI: "%edi",
731 R8L: "%r8d",
732 R9L: "%r9d",
733 R10L: "%r10d",
734 R11L: "%r11d",
735 R12L: "%r12d",
736 R13L: "%r13d",
737 R14L: "%r14d",
738 R15L: "%r15d",
739 RAX: "%rax",
740 RCX: "%rcx",
741 RDX: "%rdx",
742 RBX: "%rbx",
743 RSP: "%rsp",
744 RBP: "%rbp",
745 RSI: "%rsi",
746 RDI: "%rdi",
747 R8: "%r8",
748 R9: "%r9",
749 R10: "%r10",
750 R11: "%r11",
751 R12: "%r12",
752 R13: "%r13",
753 R14: "%r14",
754 R15: "%r15",
755 IP: "%ip",
756 EIP: "%eip",
757 RIP: "%rip",
758 F0: "%st",
759 F1: "%st(1)",
760 F2: "%st(2)",
761 F3: "%st(3)",
762 F4: "%st(4)",
763 F5: "%st(5)",
764 F6: "%st(6)",
765 F7: "%st(7)",
766 M0: "%mm0",
767 M1: "%mm1",
768 M2: "%mm2",
769 M3: "%mm3",
770 M4: "%mm4",
771 M5: "%mm5",
772 M6: "%mm6",
773 M7: "%mm7",
774 X0: "%xmm0",
775 X1: "%xmm1",
776 X2: "%xmm2",
777 X3: "%xmm3",
778 X4: "%xmm4",
779 X5: "%xmm5",
780 X6: "%xmm6",
781 X7: "%xmm7",
782 X8: "%xmm8",
783 X9: "%xmm9",
784 X10: "%xmm10",
785 X11: "%xmm11",
786 X12: "%xmm12",
787 X13: "%xmm13",
788 X14: "%xmm14",
789 X15: "%xmm15",
790 CS: "%cs",
791 SS: "%ss",
792 DS: "%ds",
793 ES: "%es",
794 FS: "%fs",
795 GS: "%gs",
796 GDTR: "%gdtr",
797 IDTR: "%idtr",
798 LDTR: "%ldtr",
799 MSW: "%msw",
800 TASK: "%task",
801 CR0: "%cr0",
802 CR1: "%cr1",
803 CR2: "%cr2",
804 CR3: "%cr3",
805 CR4: "%cr4",
806 CR5: "%cr5",
807 CR6: "%cr6",
808 CR7: "%cr7",
809 CR8: "%cr8",
810 CR9: "%cr9",
811 CR10: "%cr10",
812 CR11: "%cr11",
813 CR12: "%cr12",
814 CR13: "%cr13",
815 CR14: "%cr14",
816 CR15: "%cr15",
817 DR0: "%db0",
818 DR1: "%db1",
819 DR2: "%db2",
820 DR3: "%db3",
821 DR4: "%db4",
822 DR5: "%db5",
823 DR6: "%db6",
824 DR7: "%db7",
825 TR0: "%tr0",
826 TR1: "%tr1",
827 TR2: "%tr2",
828 TR3: "%tr3",
829 TR4: "%tr4",
830 TR5: "%tr5",
831 TR6: "%tr6",
832 TR7: "%tr7",
833 }
834
835 var gnuOp = map[Op]string{
836 CBW: "cbtw",
837 CDQ: "cltd",
838 CMPSD: "cmpsl",
839 CMPSD_XMM: "cmpsd",
840 CWD: "cwtd",
841 CWDE: "cwtl",
842 CQO: "cqto",
843 INSD: "insl",
844 IRET: "iretw",
845 IRETD: "iret",
846 IRETQ: "iretq",
847 LODSB: "lods",
848 LODSD: "lods",
849 LODSQ: "lods",
850 LODSW: "lods",
851 MOVSD: "movsl",
852 MOVSD_XMM: "movsd",
853 OUTSD: "outsl",
854 POPA: "popaw",
855 POPAD: "popa",
856 POPF: "popfw",
857 POPFD: "popf",
858 PUSHA: "pushaw",
859 PUSHAD: "pusha",
860 PUSHF: "pushfw",
861 PUSHFD: "pushf",
862 SCASB: "scas",
863 SCASD: "scas",
864 SCASQ: "scas",
865 SCASW: "scas",
866 STOSB: "stos",
867 STOSD: "stos",
868 STOSQ: "stos",
869 STOSW: "stos",
870 XLATB: "xlat",
871 }
872
873 var cmppsOps = []string{
874 "cmpeq",
875 "cmplt",
876 "cmple",
877 "cmpunord",
878 "cmpneq",
879 "cmpnlt",
880 "cmpnle",
881 "cmpord",
882 }
883
884 var pclmulqOps = []string{
885 "pclmullqlqdq",
886 "pclmulhqlqdq",
887 "pclmullqhqdq",
888 "pclmulhqhqdq",
889 }
890
891 func countPrefix(inst *Inst, target Prefix) int {
892 n := 0
893 for _, p := range inst.Prefix {
894 if p&0xFF == target&0xFF {
895 n++
896 }
897 }
898 return n
899 }
900
901 func markLastImplicit(inst *Inst, prefix Prefix) bool {
902 for i := len(inst.Prefix) - 1; i >= 0; i-- {
903 p := inst.Prefix[i]
904 if p&0xFF == prefix {
905 inst.Prefix[i] |= PrefixImplicit
906 return true
907 }
908 }
909 return false
910 }
911
912 func unmarkImplicit(inst *Inst, prefix Prefix) {
913 for i := len(inst.Prefix) - 1; i >= 0; i-- {
914 p := inst.Prefix[i]
915 if p&0xFF == prefix {
916 inst.Prefix[i] &^= PrefixImplicit
917 }
918 }
919 }
920
921 func byteSizeSuffix(b int) string {
922 switch b {
923 case 1:
924 return "b"
925 case 2:
926 return "w"
927 case 4:
928 return "l"
929 case 8:
930 return "q"
931 }
932 return ""
933 }
934
935 func argBytes(inst *Inst, arg Arg) int {
936 if isMem(arg) {
937 return inst.MemBytes
938 }
939 return regBytes(arg)
940 }
941
942 func isFloat(op Op) bool {
943 switch op {
944 case FADD, FCOM, FCOMP, FDIV, FDIVR, FIADD, FICOM, FICOMP, FIDIV, FIDIVR, FILD, FIMUL, FIST, FISTP, FISTTP, FISUB, FISUBR, FLD, FMUL, FST, FSTP, FSUB, FSUBR:
945 return true
946 }
947 return false
948 }
949
950 func isFloatInt(op Op) bool {
951 switch op {
952 case FIADD, FICOM, FICOMP, FIDIV, FIDIVR, FILD, FIMUL, FIST, FISTP, FISTTP, FISUB, FISUBR:
953 return true
954 }
955 return false
956 }
957
View as plain text