gtsocial-umbx

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

gnu.go (21908B)


      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, 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
    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 					// 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.
    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 			// 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 
    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 }