1// Copyright 2014 The Go Authors.  All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5package x86asm
6
7import (
8	"fmt"
9	"strings"
10)
11
12// GNUSyntax returns the GNU assembler syntax for the instruction, as defined by GNU binutils.
13// This general form is often called “AT&T syntax” as a reference to AT&T System V Unix.
14func GNUSyntax(inst Inst, pc uint64, symname SymLookup) string {
15	// Rewrite instruction to mimic GNU peculiarities.
16	// Note that inst has been passed by value and contains
17	// no pointers, so any changes we make here are local
18	// and will not propagate back out to the caller.
19
20	if symname == nil {
21		symname = func(uint64) (string, uint64) { return "", 0 }
22	}
23
24	// Adjust opcode [sic].
25	switch inst.Op {
26	case FDIV, FDIVR, FSUB, FSUBR, FDIVP, FDIVRP, FSUBP, FSUBRP:
27		// DC E0, DC F0: libopcodes swaps FSUBR/FSUB and FDIVR/FDIV, at least
28		// if you believe the Intel manual is correct (the encoding is irregular as given;
29		// libopcodes uses the more regular expected encoding).
30		// TODO(rsc): Test to ensure Intel manuals are correct and report to libopcodes maintainers?
31		// NOTE: iant thinks this is deliberate, but we can't find the history.
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		// MOVNTSD is F2 0F 2B /r.
57		// MOVNTSS is F3 0F 2B /r (supposedly; not in manuals).
58		// Usually inner prefixes win for display,
59		// so that F3 F2 0F 2B 11 is REP MOVNTSD
60		// and F2 F3 0F 2B 11 is REPN MOVNTSS.
61		// Libopcodes always prefers MOVNTSS regardless of prefix order.
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	// Add implicit arguments.
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	// Adjust which prefixes will be displayed.
100	// The rule is to display all the prefixes not implied by
101	// the usual instruction display, that is, all the prefixes
102	// except the ones with PrefixImplicit set.
103	// However, of course, there are exceptions to the rule.
104	switch inst.Op {
105	case CRC32:
106		// CRC32 has a mandatory F2 prefix.
107		// If there are multiple F2s and no F3s, the extra F2s do not print.
108		// (And Decode has already marked them implicit.)
109		// However, if there is an F3 anywhere, then the extra F2s do print.
110		// If there are multiple F2 prefixes *and* an (ignored) F3,
111		// then libopcodes prints the extra F2s as REPNs.
112		if countPrefix(&inst, 0xF2) > 1 {
113			unmarkImplicit(&inst, 0xF2)
114			markLastImplicit(&inst, 0xF2)
115		}
116
117		// An unused data size override should probably be shown,
118		// to distinguish DATA16 CRC32B from plain CRC32B,
119		// but libopcodes always treats the final override as implicit
120		// and the others as explicit.
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		// The 16-bit and 32-bit forms of MOV Sreg, dst and MOV src, Sreg
139		// cannot be distinguished when src or dst refers to memory, because
140		// Sreg is always a 16-bit value, even when we're doing a 32-bit
141		// instruction. Because the instruction tables distinguished these two,
142		// any operand size prefix has been marked as used (to decide which
143		// branch to take). Unmark it, so that it will show up in disassembly,
144		// so that the reader can tell the size of memory operand.
145		// up with the same arguments
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 // cut interpretation bits, producing original segment prefix
176				}
177			}
178		}
179	}
180
181	// XACQUIRE/XRELEASE adjustment.
182	if inst.Op == MOV {
183		// MOV into memory is a candidate for turning REP into XRELEASE.
184		// However, if the REP is followed by a REPN, that REPN blocks the
185		// conversion.
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	// We only format the final F2/F3 as XRELEASE/XACQUIRE.
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	// Determine opcode.
221	op := strings.ToLower(inst.Op.String())
222	if alt := gnuOp[inst.Op]; alt != "" {
223		op = alt
224	}
225
226	// Determine opcode suffix.
227	// Libopcodes omits the suffix if the width of the operation
228	// can be inferred from a register arguments. For example,
229	// add $1, %ebx has no suffix because you can tell from the
230	// 32-bit register destination that it is a 32-bit add,
231	// but in addl $1, (%ebx), the destination is memory, so the
232	// size is not evident without the l suffix.
233	needSuffix := true
234SuffixLoop:
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					// shift count does not tell us operand size
248					continue
249				}
250
251			case CRC32:
252				// The source argument does tell us operand size,
253				// but libopcodes still always puts a suffix on crc32.
254				continue
255
256			case PUSH, POP:
257				// Even though segment registers are 16-bit, push and pop
258				// can save/restore them from 32-bit slots, so they
259				// do not imply operand size.
260				if ES <= a && a <= GS {
261					continue
262				}
263
264			case CVTSI2SD, CVTSI2SS:
265				// The integer register argument takes priority.
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			// For various reasons, libopcodes emits no suffix for these instructions.
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			// Integer size conversions get two suffixes.
293			op = op[:4] + byteSizeSuffix(argBytes(&inst, inst.Args[1])) + byteSizeSuffix(argBytes(&inst, inst.Args[0]))
294
295		case LOOP, LOOPE, LOOPNE:
296			// Add w suffix to indicate use of CX register instead of ECX.
297			if inst.AddrSize == 16 {
298				op += "w"
299			}
300
301		case CALL, ENTER, JMP, LCALL, LEAVE, LJMP, LRET, RET, SYSRET, XBEGIN:
302			// Add w suffix to indicate use of 16-bit target.
303			// Exclude JMP rel8.
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			// Add s suffix to indicate shortened FPU state (I guess).
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				// I can't explain any of this, but it's what libopcodes does.
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	// Adjust special case opcodes.
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" // not xlatb
387		}
388	}
389
390	// Build list of argument strings.
391	var (
392		usedPrefixes bool     // segment prefixes consumed by Mem formatting
393		args         []string // formatted arguments
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 // disable use of prefixes for first argument
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	// The default is to print the arguments in reverse Intel order.
414	// A few instructions inhibit this behavior.
415	switch inst.Op {
416	case BOUND, LCALL, ENTER, LJMP:
417		// no reverse
418	default:
419		// reverse args
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	// Build prefix string.
426	// Must be after argument formatting, which can turn off segment prefixes.
427	var (
428		prefix       = "" // output string
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			// For unknown reasons, if the addr16 prefix is repeated,
467			// libopcodes displays all but the last as addr32, even though
468			// the addressing form used in a memory reference is clearly
469			// still 16-bit.
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				// Similar to the addr32 logic above, but it only kicks in
484				// when something used the data size prefix (one is implicit).
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	// Finally! Put it all together.
505	text := prefix + op
506	if args != nil {
507		text += " "
508		// Indirect call/jmp gets a star to distinguish from direct jump address.
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// gnuArg returns the GNU syntax for the argument x from the instruction inst.
518// If *usedPrefixes is false and x is a Mem, then the formatting
519// includes any segment prefixes and sets *usedPrefixes to true.
520func 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			// DX is the port, but libopcodes prints it as if it were a memory reference.
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			// These do not accept segment prefixes, at least in the GNU rendering.
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			// 16-bit addressing - no scale
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
685var 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
835var 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
873var cmppsOps = []string{
874	"cmpeq",
875	"cmplt",
876	"cmple",
877	"cmpunord",
878	"cmpneq",
879	"cmpnlt",
880	"cmpnle",
881	"cmpord",
882}
883
884var pclmulqOps = []string{
885	"pclmullqlqdq",
886	"pclmulhqlqdq",
887	"pclmullqhqdq",
888	"pclmulhqhqdq",
889}
890
891func 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
901func 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
912func 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
921func 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
935func argBytes(inst *Inst, arg Arg) int {
936	if isMem(arg) {
937		return inst.MemBytes
938	}
939	return regBytes(arg)
940}
941
942func 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
950func 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