Home | History | Annotate | Download | only in x86asm
      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 
      5 package x86asm
      6 
      7 import (
      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.
     14 func GNUSyntax(inst Inst) 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 	// Adjust opcode [sic].
     21 	switch inst.Op {
     22 	case FDIV, FDIVR, FSUB, FSUBR, FDIVP, FDIVRP, FSUBP, FSUBRP:
     23 		// DC E0, DC F0: libopcodes swaps FSUBR/FSUB and FDIVR/FDIV, at least
     24 		// if you believe the Intel manual is correct (the encoding is irregular as given;
     25 		// libopcodes uses the more regular expected encoding).
     26 		// TODO(rsc): Test to ensure Intel manuals are correct and report to libopcodes maintainers?
     27 		// NOTE: iant thinks this is deliberate, but we can't find the history.
     28 		_, reg1 := inst.Args[0].(Reg)
     29 		_, reg2 := inst.Args[1].(Reg)
     30 		if reg1 && reg2 && (inst.Opcode>>24 == 0xDC || inst.Opcode>>24 == 0xDE) {
     31 			switch inst.Op {
     32 			case FDIV:
     33 				inst.Op = FDIVR
     34 			case FDIVR:
     35 				inst.Op = FDIV
     36 			case FSUB:
     37 				inst.Op = FSUBR
     38 			case FSUBR:
     39 				inst.Op = FSUB
     40 			case FDIVP:
     41 				inst.Op = FDIVRP
     42 			case FDIVRP:
     43 				inst.Op = FDIVP
     44 			case FSUBP:
     45 				inst.Op = FSUBRP
     46 			case FSUBRP:
     47 				inst.Op = FSUBP
     48 			}
     49 		}
     50 
     51 	case MOVNTSD:
     52 		// MOVNTSD is F2 0F 2B /r.
     53 		// MOVNTSS is F3 0F 2B /r (supposedly; not in manuals).
     54 		// Usually inner prefixes win for display,
     55 		// so that F3 F2 0F 2B 11 is REP MOVNTSD
     56 		// and F2 F3 0F 2B 11 is REPN MOVNTSS.
     57 		// Libopcodes always prefers MOVNTSS regardless of prefix order.
     58 		if countPrefix(&inst, 0xF3) > 0 {
     59 			found := false
     60 			for i := len(inst.Prefix) - 1; i >= 0; i-- {
     61 				switch inst.Prefix[i] & 0xFF {
     62 				case 0xF3:
     63 					if !found {
     64 						found = true
     65 						inst.Prefix[i] |= PrefixImplicit
     66 					}
     67 				case 0xF2:
     68 					inst.Prefix[i] &^= PrefixImplicit
     69 				}
     70 			}
     71 			inst.Op = MOVNTSS
     72 		}
     73 	}
     74 
     75 	// Add implicit arguments.
     76 	switch inst.Op {
     77 	case MONITOR:
     78 		inst.Args[0] = EDX
     79 		inst.Args[1] = ECX
     80 		inst.Args[2] = EAX
     81 		if inst.AddrSize == 16 {
     82 			inst.Args[2] = AX
     83 		}
     84 
     85 	case MWAIT:
     86 		if inst.Mode == 64 {
     87 			inst.Args[0] = RCX
     88 			inst.Args[1] = RAX
     89 		} else {
     90 			inst.Args[0] = ECX
     91 			inst.Args[1] = EAX
     92 		}
     93 	}
     94 
     95 	// Adjust which prefixes will be displayed.
     96 	// The rule is to display all the prefixes not implied by
     97 	// the usual instruction display, that is, all the prefixes
     98 	// except the ones with PrefixImplicit set.
     99 	// However, of course, there are exceptions to the rule.
    100 	switch inst.Op {
    101 	case CRC32:
    102 		// CRC32 has a mandatory F2 prefix.
    103 		// If there are multiple F2s and no F3s, the extra F2s do not print.
    104 		// (And Decode has already marked them implicit.)
    105 		// However, if there is an F3 anywhere, then the extra F2s do print.
    106 		// If there are multiple F2 prefixes *and* an (ignored) F3,
    107 		// then libopcodes prints the extra F2s as REPNs.
    108 		if countPrefix(&inst, 0xF2) > 1 {
    109 			unmarkImplicit(&inst, 0xF2)
    110 			markLastImplicit(&inst, 0xF2)
    111 		}
    112 
    113 		// An unused data size override should probably be shown,
    114 		// to distinguish DATA16 CRC32B from plain CRC32B,
    115 		// but libopcodes always treats the final override as implicit
    116 		// and the others as explicit.
    117 		unmarkImplicit(&inst, PrefixDataSize)
    118 		markLastImplicit(&inst, PrefixDataSize)
    119 
    120 	case CVTSI2SD, CVTSI2SS:
    121 		if !isMem(inst.Args[1]) {
    122 			markLastImplicit(&inst, PrefixDataSize)
    123 		}
    124 
    125 	case CVTSD2SI, CVTSS2SI, CVTTSD2SI, CVTTSS2SI,
    126 		ENTER, FLDENV, FNSAVE, FNSTENV, FRSTOR, LGDT, LIDT, LRET,
    127 		POP, PUSH, RET, SGDT, SIDT, SYSRET, XBEGIN:
    128 		markLastImplicit(&inst, PrefixDataSize)
    129 
    130 	case LOOP, LOOPE, LOOPNE, MONITOR:
    131 		markLastImplicit(&inst, PrefixAddrSize)
    132 
    133 	case MOV:
    134 		// The 16-bit and 32-bit forms of MOV Sreg, dst and MOV src, Sreg
    135 		// cannot be distinguished when src or dst refers to memory, because
    136 		// Sreg is always a 16-bit value, even when we're doing a 32-bit
    137 		// instruction. Because the instruction tables distinguished these two,
    138 		// any operand size prefix has been marked as used (to decide which
    139 		// branch to take). Unmark it, so that it will show up in disassembly,
    140 		// so that the reader can tell the size of memory operand.
    141 		// up with the same arguments
    142 		dst, _ := inst.Args[0].(Reg)
    143 		src, _ := inst.Args[1].(Reg)
    144 		if ES <= src && src <= GS && isMem(inst.Args[0]) || ES <= dst && dst <= GS && isMem(inst.Args[1]) {
    145 			unmarkImplicit(&inst, PrefixDataSize)
    146 		}
    147 
    148 	case MOVDQU:
    149 		if countPrefix(&inst, 0xF3) > 1 {
    150 			unmarkImplicit(&inst, 0xF3)
    151 			markLastImplicit(&inst, 0xF3)
    152 		}
    153 
    154 	case MOVQ2DQ:
    155 		markLastImplicit(&inst, PrefixDataSize)
    156 
    157 	case SLDT, SMSW, STR, FXRSTOR, XRSTOR, XSAVE, XSAVEOPT, CMPXCHG8B:
    158 		if isMem(inst.Args[0]) {
    159 			unmarkImplicit(&inst, PrefixDataSize)
    160 		}
    161 
    162 	case SYSEXIT:
    163 		unmarkImplicit(&inst, PrefixDataSize)
    164 	}
    165 
    166 	if isCondJmp[inst.Op] || isLoop[inst.Op] || inst.Op == JCXZ || inst.Op == JECXZ || inst.Op == JRCXZ {
    167 		if countPrefix(&inst, PrefixCS) > 0 && countPrefix(&inst, PrefixDS) > 0 {
    168 			for i, p := range inst.Prefix {
    169 				switch p & 0xFFF {
    170 				case PrefixPN, PrefixPT:
    171 					inst.Prefix[i] &= 0xF0FF // cut interpretation bits, producing original segment prefix
    172 				}
    173 			}
    174 		}
    175 	}
    176 
    177 	// XACQUIRE/XRELEASE adjustment.
    178 	if inst.Op == MOV {
    179 		// MOV into memory is a candidate for turning REP into XRELEASE.
    180 		// However, if the REP is followed by a REPN, that REPN blocks the
    181 		// conversion.
    182 		haveREPN := false
    183 		for i := len(inst.Prefix) - 1; i >= 0; i-- {
    184 			switch inst.Prefix[i] &^ PrefixIgnored {
    185 			case PrefixREPN:
    186 				haveREPN = true
    187 			case PrefixXRELEASE:
    188 				if haveREPN {
    189 					inst.Prefix[i] = PrefixREP
    190 				}
    191 			}
    192 		}
    193 	}
    194 
    195 	// We only format the final F2/F3 as XRELEASE/XACQUIRE.
    196 	haveXA := false
    197 	haveXR := false
    198 	for i := len(inst.Prefix) - 1; i >= 0; i-- {
    199 		switch inst.Prefix[i] &^ PrefixIgnored {
    200 		case PrefixXRELEASE:
    201 			if !haveXR {
    202 				haveXR = true
    203 			} else {
    204 				inst.Prefix[i] = PrefixREP
    205 			}
    206 
    207 		case PrefixXACQUIRE:
    208 			if !haveXA {
    209 				haveXA = true
    210 			} else {
    211 				inst.Prefix[i] = PrefixREPN
    212 			}
    213 		}
    214 	}
    215 
    216 	// Determine opcode.
    217 	op := strings.ToLower(inst.Op.String())
    218 	if alt := gnuOp[inst.Op]; alt != "" {
    219 		op = alt
    220 	}
    221 
    222 	// Determine opcode suffix.
    223 	// Libopcodes omits the suffix if the width of the operation
    224 	// can be inferred from a register arguments. For example,
    225 	// add $1, %ebx has no suffix because you can tell from the
    226 	// 32-bit register destination that it is a 32-bit add,
    227 	// but in addl $1, (%ebx), the destination is memory, so the
    228 	// size is not evident without the l suffix.
    229 	needSuffix := true
    230 SuffixLoop:
    231 	for i, a := range inst.Args {
    232 		if a == nil {
    233 			break
    234 		}
    235 		switch a := a.(type) {
    236 		case Reg:
    237 			switch inst.Op {
    238 			case MOVSX, MOVZX:
    239 				continue
    240 
    241 			case SHL, SHR, RCL, RCR, ROL, ROR, SAR:
    242 				if i == 1 {
    243 					// shift count does not tell us operand size
    244 					continue
    245 				}
    246 
    247 			case CRC32:
    248 				// The source argument does tell us operand size,
    249 				// but libopcodes still always puts a suffix on crc32.
    250 				continue
    251 
    252 			case PUSH, POP:
    253 				// Even though segment registers are 16-bit, push and pop
    254 				// can save/restore them from 32-bit slots, so they
    255 				// do not imply operand size.
    256 				if ES <= a && a <= GS {
    257 					continue
    258 				}
    259 
    260 			case CVTSI2SD, CVTSI2SS:
    261 				// The integer register argument takes priority.
    262 				if X0 <= a && a <= X15 {
    263 					continue
    264 				}
    265 			}
    266 
    267 			if AL <= a && a <= R15 || ES <= a && a <= GS || X0 <= a && a <= X15 || M0 <= a && a <= M7 {
    268 				needSuffix = false
    269 				break SuffixLoop
    270 			}
    271 		}
    272 	}
    273 
    274 	if needSuffix {
    275 		switch inst.Op {
    276 		case CMPXCHG8B, FLDCW, FNSTCW, FNSTSW, LDMXCSR, LLDT, LMSW, LTR, PCLMULQDQ,
    277 			SETA, SETAE, SETB, SETBE, SETE, SETG, SETGE, SETL, SETLE, SETNE, SETNO, SETNP, SETNS, SETO, SETP, SETS,
    278 			SLDT, SMSW, STMXCSR, STR, VERR, VERW:
    279 			// For various reasons, libopcodes emits no suffix for these instructions.
    280 
    281 		case CRC32:
    282 			op += byteSizeSuffix(argBytes(&inst, inst.Args[1]))
    283 
    284 		case LGDT, LIDT, SGDT, SIDT:
    285 			op += byteSizeSuffix(inst.DataSize / 8)
    286 
    287 		case MOVZX, MOVSX:
    288 			// Integer size conversions get two suffixes.
    289 			op = op[:4] + byteSizeSuffix(argBytes(&inst, inst.Args[1])) + byteSizeSuffix(argBytes(&inst, inst.Args[0]))
    290 
    291 		case LOOP, LOOPE, LOOPNE:
    292 			// Add w suffix to indicate use of CX register instead of ECX.
    293 			if inst.AddrSize == 16 {
    294 				op += "w"
    295 			}
    296 
    297 		case CALL, ENTER, JMP, LCALL, LEAVE, LJMP, LRET, RET, SYSRET, XBEGIN:
    298 			// Add w suffix to indicate use of 16-bit target.
    299 			// Exclude JMP rel8.
    300 			if inst.Opcode>>24 == 0xEB {
    301 				break
    302 			}
    303 			if inst.DataSize == 16 && inst.Mode != 16 {
    304 				markLastImplicit(&inst, PrefixDataSize)
    305 				op += "w"
    306 			} else if inst.Mode == 64 {
    307 				op += "q"
    308 			}
    309 
    310 		case FRSTOR, FNSAVE, FNSTENV, FLDENV:
    311 			// Add s suffix to indicate shortened FPU state (I guess).
    312 			if inst.DataSize == 16 {
    313 				op += "s"
    314 			}
    315 
    316 		case PUSH, POP:
    317 			if markLastImplicit(&inst, PrefixDataSize) {
    318 				op += byteSizeSuffix(inst.DataSize / 8)
    319 			} else if inst.Mode == 64 {
    320 				op += "q"
    321 			} else {
    322 				op += byteSizeSuffix(inst.MemBytes)
    323 			}
    324 
    325 		default:
    326 			if isFloat(inst.Op) {
    327 				// I can't explain any of this, but it's what libopcodes does.
    328 				switch inst.MemBytes {
    329 				default:
    330 					if (inst.Op == FLD || inst.Op == FSTP) && isMem(inst.Args[0]) {
    331 						op += "t"
    332 					}
    333 				case 4:
    334 					if isFloatInt(inst.Op) {
    335 						op += "l"
    336 					} else {
    337 						op += "s"
    338 					}
    339 				case 8:
    340 					if isFloatInt(inst.Op) {
    341 						op += "ll"
    342 					} else {
    343 						op += "l"
    344 					}
    345 				}
    346 				break
    347 			}
    348 
    349 			op += byteSizeSuffix(inst.MemBytes)
    350 		}
    351 	}
    352 
    353 	// Adjust special case opcodes.
    354 	switch inst.Op {
    355 	case 0:
    356 		if inst.Prefix[0] != 0 {
    357 			return strings.ToLower(inst.Prefix[0].String())
    358 		}
    359 
    360 	case INT:
    361 		if inst.Opcode>>24 == 0xCC {
    362 			inst.Args[0] = nil
    363 			op = "int3"
    364 		}
    365 
    366 	case CMPPS, CMPPD, CMPSD_XMM, CMPSS:
    367 		imm, ok := inst.Args[2].(Imm)
    368 		if ok && 0 <= imm && imm < 8 {
    369 			inst.Args[2] = nil
    370 			op = cmppsOps[imm] + op[3:]
    371 		}
    372 
    373 	case PCLMULQDQ:
    374 		imm, ok := inst.Args[2].(Imm)
    375 		if ok && imm&^0x11 == 0 {
    376 			inst.Args[2] = nil
    377 			op = pclmulqOps[(imm&0x10)>>3|(imm&1)]
    378 		}
    379 
    380 	case XLATB:
    381 		if markLastImplicit(&inst, PrefixAddrSize) {
    382 			op = "xlat" // not xlatb
    383 		}
    384 	}
    385 
    386 	// Build list of argument strings.
    387 	var (
    388 		usedPrefixes bool     // segment prefixes consumed by Mem formatting
    389 		args         []string // formatted arguments
    390 	)
    391 	for i, a := range inst.Args {
    392 		if a == nil {
    393 			break
    394 		}
    395 		switch inst.Op {
    396 		case MOVSB, MOVSW, MOVSD, MOVSQ, OUTSB, OUTSW, OUTSD:
    397 			if i == 0 {
    398 				usedPrefixes = true // disable use of prefixes for first argument
    399 			} else {
    400 				usedPrefixes = false
    401 			}
    402 		}
    403 		if a == Imm(1) && (inst.Opcode>>24)&^1 == 0xD0 {
    404 			continue
    405 		}
    406 		args = append(args, gnuArg(&inst, a, &usedPrefixes))
    407 	}
    408 
    409 	// The default is to print the arguments in reverse Intel order.
    410 	// A few instructions inhibit this behavior.
    411 	switch inst.Op {
    412 	case BOUND, LCALL, ENTER, LJMP:
    413 		// no reverse
    414 	default:
    415 		// reverse args
    416 		for i, j := 0, len(args)-1; i < j; i, j = i+1, j-1 {
    417 			args[i], args[j] = args[j], args[i]
    418 		}
    419 	}
    420 
    421 	// Build prefix string.
    422 	// Must be after argument formatting, which can turn off segment prefixes.
    423 	var (
    424 		prefix       = "" // output string
    425 		numAddr      = 0
    426 		numData      = 0
    427 		implicitData = false
    428 	)
    429 	for _, p := range inst.Prefix {
    430 		if p&0xFF == PrefixDataSize && p&PrefixImplicit != 0 {
    431 			implicitData = true
    432 		}
    433 	}
    434 	for _, p := range inst.Prefix {
    435 		if p == 0 {
    436 			break
    437 		}
    438 		if p&PrefixImplicit != 0 {
    439 			continue
    440 		}
    441 		switch p &^ (PrefixIgnored | PrefixInvalid) {
    442 		default:
    443 			if p.IsREX() {
    444 				if p&0xFF == PrefixREX {
    445 					prefix += "rex "
    446 				} else {
    447 					prefix += "rex." + p.String()[4:] + " "
    448 				}
    449 				break
    450 			}
    451 			prefix += strings.ToLower(p.String()) + " "
    452 
    453 		case PrefixPN:
    454 			op += ",pn"
    455 			continue
    456 
    457 		case PrefixPT:
    458 			op += ",pt"
    459 			continue
    460 
    461 		case PrefixAddrSize, PrefixAddr16, PrefixAddr32:
    462 			// For unknown reasons, if the addr16 prefix is repeated,
    463 			// libopcodes displays all but the last as addr32, even though
    464 			// the addressing form used in a memory reference is clearly
    465 			// still 16-bit.
    466 			n := 32
    467 			if inst.Mode == 32 {
    468 				n = 16
    469 			}
    470 			numAddr++
    471 			if countPrefix(&inst, PrefixAddrSize) > numAddr {
    472 				n = inst.Mode
    473 			}
    474 			prefix += fmt.Sprintf("addr%d ", n)
    475 			continue
    476 
    477 		case PrefixData16, PrefixData32:
    478 			if implicitData && countPrefix(&inst, PrefixDataSize) > 1 {
    479 				// Similar to the addr32 logic above, but it only kicks in
    480 				// when something used the data size prefix (one is implicit).
    481 				n := 16
    482 				if inst.Mode == 16 {
    483 					n = 32
    484 				}
    485 				numData++
    486 				if countPrefix(&inst, PrefixDataSize) > numData {
    487 					if inst.Mode == 16 {
    488 						n = 16
    489 					} else {
    490 						n = 32
    491 					}
    492 				}
    493 				prefix += fmt.Sprintf("data%d ", n)
    494 				continue
    495 			}
    496 			prefix += strings.ToLower(p.String()) + " "
    497 		}
    498 	}
    499 
    500 	// Finally! Put it all together.
    501 	text := prefix + op
    502 	if args != nil {
    503 		text += " "
    504 		// Indirect call/jmp gets a star to distinguish from direct jump address.
    505 		if (inst.Op == CALL || inst.Op == JMP || inst.Op == LJMP || inst.Op == LCALL) && (isMem(inst.Args[0]) || isReg(inst.Args[0])) {
    506 			text += "*"
    507 		}
    508 		text += strings.Join(args, ",")
    509 	}
    510 	return text
    511 }
    512 
    513 // gnuArg returns the GNU syntax for the argument x from the instruction inst.
    514 // If *usedPrefixes is false and x is a Mem, then the formatting
    515 // includes any segment prefixes and sets *usedPrefixes to true.
    516 func gnuArg(inst *Inst, x Arg, usedPrefixes *bool) string {
    517 	if x == nil {
    518 		return "<nil>"
    519 	}
    520 	switch x := x.(type) {
    521 	case Reg:
    522 		switch inst.Op {
    523 		case CVTSI2SS, CVTSI2SD, CVTSS2SI, CVTSD2SI, CVTTSD2SI, CVTTSS2SI:
    524 			if inst.DataSize == 16 && EAX <= x && x <= R15L {
    525 				x -= EAX - AX
    526 			}
    527 
    528 		case IN, INSB, INSW, INSD, OUT, OUTSB, OUTSW, OUTSD:
    529 			// DX is the port, but libopcodes prints it as if it were a memory reference.
    530 			if x == DX {
    531 				return "(%dx)"
    532 			}
    533 		}
    534 		return gccRegName[x]
    535 	case Mem:
    536 		seg := ""
    537 		var haveCS, haveDS, haveES, haveFS, haveGS, haveSS bool
    538 		switch x.Segment {
    539 		case CS:
    540 			haveCS = true
    541 		case DS:
    542 			haveDS = true
    543 		case ES:
    544 			haveES = true
    545 		case FS:
    546 			haveFS = true
    547 		case GS:
    548 			haveGS = true
    549 		case SS:
    550 			haveSS = true
    551 		}
    552 		switch inst.Op {
    553 		case INSB, INSW, INSD, STOSB, STOSW, STOSD, STOSQ, SCASB, SCASW, SCASD, SCASQ:
    554 			// These do not accept segment prefixes, at least in the GNU rendering.
    555 		default:
    556 			if *usedPrefixes {
    557 				break
    558 			}
    559 			for i := len(inst.Prefix) - 1; i >= 0; i-- {
    560 				p := inst.Prefix[i] &^ PrefixIgnored
    561 				if p == 0 {
    562 					continue
    563 				}
    564 				switch p {
    565 				case PrefixCS:
    566 					if !haveCS {
    567 						haveCS = true
    568 						inst.Prefix[i] |= PrefixImplicit
    569 					}
    570 				case PrefixDS:
    571 					if !haveDS {
    572 						haveDS = true
    573 						inst.Prefix[i] |= PrefixImplicit
    574 					}
    575 				case PrefixES:
    576 					if !haveES {
    577 						haveES = true
    578 						inst.Prefix[i] |= PrefixImplicit
    579 					}
    580 				case PrefixFS:
    581 					if !haveFS {
    582 						haveFS = true
    583 						inst.Prefix[i] |= PrefixImplicit
    584 					}
    585 				case PrefixGS:
    586 					if !haveGS {
    587 						haveGS = true
    588 						inst.Prefix[i] |= PrefixImplicit
    589 					}
    590 				case PrefixSS:
    591 					if !haveSS {
    592 						haveSS = true
    593 						inst.Prefix[i] |= PrefixImplicit
    594 					}
    595 				}
    596 			}
    597 			*usedPrefixes = true
    598 		}
    599 		if haveCS {
    600 			seg += "%cs:"
    601 		}
    602 		if haveDS {
    603 			seg += "%ds:"
    604 		}
    605 		if haveSS {
    606 			seg += "%ss:"
    607 		}
    608 		if haveES {
    609 			seg += "%es:"
    610 		}
    611 		if haveFS {
    612 			seg += "%fs:"
    613 		}
    614 		if haveGS {
    615 			seg += "%gs:"
    616 		}
    617 		disp := ""
    618 		if x.Disp != 0 {
    619 			disp = fmt.Sprintf("%#x", x.Disp)
    620 		}
    621 		if x.Scale == 0 || x.Index == 0 && x.Scale == 1 && (x.Base == ESP || x.Base == RSP || x.Base == 0 && inst.Mode == 64) {
    622 			if x.Base == 0 {
    623 				return seg + disp
    624 			}
    625 			return fmt.Sprintf("%s%s(%s)", seg, disp, gccRegName[x.Base])
    626 		}
    627 		base := gccRegName[x.Base]
    628 		if x.Base == 0 {
    629 			base = ""
    630 		}
    631 		index := gccRegName[x.Index]
    632 		if x.Index == 0 {
    633 			if inst.AddrSize == 64 {
    634 				index = "%riz"
    635 			} else {
    636 				index = "%eiz"
    637 			}
    638 		}
    639 		if AX <= x.Base && x.Base <= DI {
    640 			// 16-bit addressing - no scale
    641 			return fmt.Sprintf("%s%s(%s,%s)", seg, disp, base, index)
    642 		}
    643 		return fmt.Sprintf("%s%s(%s,%s,%d)", seg, disp, base, index, x.Scale)
    644 	case Rel:
    645 		return fmt.Sprintf(".%+#x", int32(x))
    646 	case Imm:
    647 		if inst.Mode == 32 {
    648 			return fmt.Sprintf("$%#x", uint32(x))
    649 		}
    650 		return fmt.Sprintf("$%#x", int64(x))
    651 	}
    652 	return x.String()
    653 }
    654 
    655 var gccRegName = [...]string{
    656 	0:    "REG0",
    657 	AL:   "%al",
    658 	CL:   "%cl",
    659 	BL:   "%bl",
    660 	DL:   "%dl",
    661 	AH:   "%ah",
    662 	CH:   "%ch",
    663 	BH:   "%bh",
    664 	DH:   "%dh",
    665 	SPB:  "%spl",
    666 	BPB:  "%bpl",
    667 	SIB:  "%sil",
    668 	DIB:  "%dil",
    669 	R8B:  "%r8b",
    670 	R9B:  "%r9b",
    671 	R10B: "%r10b",
    672 	R11B: "%r11b",
    673 	R12B: "%r12b",
    674 	R13B: "%r13b",
    675 	R14B: "%r14b",
    676 	R15B: "%r15b",
    677 	AX:   "%ax",
    678 	CX:   "%cx",
    679 	BX:   "%bx",
    680 	DX:   "%dx",
    681 	SP:   "%sp",
    682 	BP:   "%bp",
    683 	SI:   "%si",
    684 	DI:   "%di",
    685 	R8W:  "%r8w",
    686 	R9W:  "%r9w",
    687 	R10W: "%r10w",
    688 	R11W: "%r11w",
    689 	R12W: "%r12w",
    690 	R13W: "%r13w",
    691 	R14W: "%r14w",
    692 	R15W: "%r15w",
    693 	EAX:  "%eax",
    694 	ECX:  "%ecx",
    695 	EDX:  "%edx",
    696 	EBX:  "%ebx",
    697 	ESP:  "%esp",
    698 	EBP:  "%ebp",
    699 	ESI:  "%esi",
    700 	EDI:  "%edi",
    701 	R8L:  "%r8d",
    702 	R9L:  "%r9d",
    703 	R10L: "%r10d",
    704 	R11L: "%r11d",
    705 	R12L: "%r12d",
    706 	R13L: "%r13d",
    707 	R14L: "%r14d",
    708 	R15L: "%r15d",
    709 	RAX:  "%rax",
    710 	RCX:  "%rcx",
    711 	RDX:  "%rdx",
    712 	RBX:  "%rbx",
    713 	RSP:  "%rsp",
    714 	RBP:  "%rbp",
    715 	RSI:  "%rsi",
    716 	RDI:  "%rdi",
    717 	R8:   "%r8",
    718 	R9:   "%r9",
    719 	R10:  "%r10",
    720 	R11:  "%r11",
    721 	R12:  "%r12",
    722 	R13:  "%r13",
    723 	R14:  "%r14",
    724 	R15:  "%r15",
    725 	IP:   "%ip",
    726 	EIP:  "%eip",
    727 	RIP:  "%rip",
    728 	F0:   "%st",
    729 	F1:   "%st(1)",
    730 	F2:   "%st(2)",
    731 	F3:   "%st(3)",
    732 	F4:   "%st(4)",
    733 	F5:   "%st(5)",
    734 	F6:   "%st(6)",
    735 	F7:   "%st(7)",
    736 	M0:   "%mm0",
    737 	M1:   "%mm1",
    738 	M2:   "%mm2",
    739 	M3:   "%mm3",
    740 	M4:   "%mm4",
    741 	M5:   "%mm5",
    742 	M6:   "%mm6",
    743 	M7:   "%mm7",
    744 	X0:   "%xmm0",
    745 	X1:   "%xmm1",
    746 	X2:   "%xmm2",
    747 	X3:   "%xmm3",
    748 	X4:   "%xmm4",
    749 	X5:   "%xmm5",
    750 	X6:   "%xmm6",
    751 	X7:   "%xmm7",
    752 	X8:   "%xmm8",
    753 	X9:   "%xmm9",
    754 	X10:  "%xmm10",
    755 	X11:  "%xmm11",
    756 	X12:  "%xmm12",
    757 	X13:  "%xmm13",
    758 	X14:  "%xmm14",
    759 	X15:  "%xmm15",
    760 	CS:   "%cs",
    761 	SS:   "%ss",
    762 	DS:   "%ds",
    763 	ES:   "%es",
    764 	FS:   "%fs",
    765 	GS:   "%gs",
    766 	GDTR: "%gdtr",
    767 	IDTR: "%idtr",
    768 	LDTR: "%ldtr",
    769 	MSW:  "%msw",
    770 	TASK: "%task",
    771 	CR0:  "%cr0",
    772 	CR1:  "%cr1",
    773 	CR2:  "%cr2",
    774 	CR3:  "%cr3",
    775 	CR4:  "%cr4",
    776 	CR5:  "%cr5",
    777 	CR6:  "%cr6",
    778 	CR7:  "%cr7",
    779 	CR8:  "%cr8",
    780 	CR9:  "%cr9",
    781 	CR10: "%cr10",
    782 	CR11: "%cr11",
    783 	CR12: "%cr12",
    784 	CR13: "%cr13",
    785 	CR14: "%cr14",
    786 	CR15: "%cr15",
    787 	DR0:  "%db0",
    788 	DR1:  "%db1",
    789 	DR2:  "%db2",
    790 	DR3:  "%db3",
    791 	DR4:  "%db4",
    792 	DR5:  "%db5",
    793 	DR6:  "%db6",
    794 	DR7:  "%db7",
    795 	TR0:  "%tr0",
    796 	TR1:  "%tr1",
    797 	TR2:  "%tr2",
    798 	TR3:  "%tr3",
    799 	TR4:  "%tr4",
    800 	TR5:  "%tr5",
    801 	TR6:  "%tr6",
    802 	TR7:  "%tr7",
    803 }
    804 
    805 var gnuOp = map[Op]string{
    806 	CBW:       "cbtw",
    807 	CDQ:       "cltd",
    808 	CMPSD:     "cmpsl",
    809 	CMPSD_XMM: "cmpsd",
    810 	CWD:       "cwtd",
    811 	CWDE:      "cwtl",
    812 	CQO:       "cqto",
    813 	INSD:      "insl",
    814 	IRET:      "iretw",
    815 	IRETD:     "iret",
    816 	IRETQ:     "iretq",
    817 	LODSB:     "lods",
    818 	LODSD:     "lods",
    819 	LODSQ:     "lods",
    820 	LODSW:     "lods",
    821 	MOVSD:     "movsl",
    822 	MOVSD_XMM: "movsd",
    823 	OUTSD:     "outsl",
    824 	POPA:      "popaw",
    825 	POPAD:     "popa",
    826 	POPF:      "popfw",
    827 	POPFD:     "popf",
    828 	PUSHA:     "pushaw",
    829 	PUSHAD:    "pusha",
    830 	PUSHF:     "pushfw",
    831 	PUSHFD:    "pushf",
    832 	SCASB:     "scas",
    833 	SCASD:     "scas",
    834 	SCASQ:     "scas",
    835 	SCASW:     "scas",
    836 	STOSB:     "stos",
    837 	STOSD:     "stos",
    838 	STOSQ:     "stos",
    839 	STOSW:     "stos",
    840 	XLATB:     "xlat",
    841 }
    842 
    843 var cmppsOps = []string{
    844 	"cmpeq",
    845 	"cmplt",
    846 	"cmple",
    847 	"cmpunord",
    848 	"cmpneq",
    849 	"cmpnlt",
    850 	"cmpnle",
    851 	"cmpord",
    852 }
    853 
    854 var pclmulqOps = []string{
    855 	"pclmullqlqdq",
    856 	"pclmulhqlqdq",
    857 	"pclmullqhqdq",
    858 	"pclmulhqhqdq",
    859 }
    860 
    861 func countPrefix(inst *Inst, target Prefix) int {
    862 	n := 0
    863 	for _, p := range inst.Prefix {
    864 		if p&0xFF == target&0xFF {
    865 			n++
    866 		}
    867 	}
    868 	return n
    869 }
    870 
    871 func markLastImplicit(inst *Inst, prefix Prefix) bool {
    872 	for i := len(inst.Prefix) - 1; i >= 0; i-- {
    873 		p := inst.Prefix[i]
    874 		if p&0xFF == prefix {
    875 			inst.Prefix[i] |= PrefixImplicit
    876 			return true
    877 		}
    878 	}
    879 	return false
    880 }
    881 
    882 func unmarkImplicit(inst *Inst, prefix Prefix) {
    883 	for i := len(inst.Prefix) - 1; i >= 0; i-- {
    884 		p := inst.Prefix[i]
    885 		if p&0xFF == prefix {
    886 			inst.Prefix[i] &^= PrefixImplicit
    887 		}
    888 	}
    889 }
    890 
    891 func byteSizeSuffix(b int) string {
    892 	switch b {
    893 	case 1:
    894 		return "b"
    895 	case 2:
    896 		return "w"
    897 	case 4:
    898 		return "l"
    899 	case 8:
    900 		return "q"
    901 	}
    902 	return ""
    903 }
    904 
    905 func argBytes(inst *Inst, arg Arg) int {
    906 	if isMem(arg) {
    907 		return inst.MemBytes
    908 	}
    909 	return regBytes(arg)
    910 }
    911 
    912 func isFloat(op Op) bool {
    913 	switch op {
    914 	case FADD, FCOM, FCOMP, FDIV, FDIVR, FIADD, FICOM, FICOMP, FIDIV, FIDIVR, FILD, FIMUL, FIST, FISTP, FISTTP, FISUB, FISUBR, FLD, FMUL, FST, FSTP, FSUB, FSUBR:
    915 		return true
    916 	}
    917 	return false
    918 }
    919 
    920 func isFloatInt(op Op) bool {
    921 	switch op {
    922 	case FIADD, FICOM, FICOMP, FIDIV, FIDIVR, FILD, FIMUL, FIST, FISTP, FISTTP, FISUB, FISUBR:
    923 		return true
    924 	}
    925 	return false
    926 }
    927