gtsocial-umbx

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

intel.go (11954B)


      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 // IntelSyntax returns the Intel assembler syntax for the instruction, as defined by Intel's XED tool.
     13 func IntelSyntax(inst Inst, pc uint64, symname SymLookup) string {
     14 	if symname == nil {
     15 		symname = func(uint64) (string, uint64) { return "", 0 }
     16 	}
     17 
     18 	var iargs []Arg
     19 	for _, a := range inst.Args {
     20 		if a == nil {
     21 			break
     22 		}
     23 		iargs = append(iargs, a)
     24 	}
     25 
     26 	switch inst.Op {
     27 	case INSB, INSD, INSW, OUTSB, OUTSD, OUTSW, LOOPNE, JCXZ, JECXZ, JRCXZ, LOOP, LOOPE, MOV, XLATB:
     28 		if inst.Op == MOV && (inst.Opcode>>16)&0xFFFC != 0x0F20 {
     29 			break
     30 		}
     31 		for i, p := range inst.Prefix {
     32 			if p&0xFF == PrefixAddrSize {
     33 				inst.Prefix[i] &^= PrefixImplicit
     34 			}
     35 		}
     36 	}
     37 
     38 	switch inst.Op {
     39 	case MOV:
     40 		dst, _ := inst.Args[0].(Reg)
     41 		src, _ := inst.Args[1].(Reg)
     42 		if ES <= dst && dst <= GS && EAX <= src && src <= R15L {
     43 			src -= EAX - AX
     44 			iargs[1] = src
     45 		}
     46 		if ES <= dst && dst <= GS && RAX <= src && src <= R15 {
     47 			src -= RAX - AX
     48 			iargs[1] = src
     49 		}
     50 
     51 		if inst.Opcode>>24&^3 == 0xA0 {
     52 			for i, p := range inst.Prefix {
     53 				if p&0xFF == PrefixAddrSize {
     54 					inst.Prefix[i] |= PrefixImplicit
     55 				}
     56 			}
     57 		}
     58 	}
     59 
     60 	switch inst.Op {
     61 	case AAM, AAD:
     62 		if imm, ok := iargs[0].(Imm); ok {
     63 			if inst.DataSize == 32 {
     64 				iargs[0] = Imm(uint32(int8(imm)))
     65 			} else if inst.DataSize == 16 {
     66 				iargs[0] = Imm(uint16(int8(imm)))
     67 			}
     68 		}
     69 
     70 	case PUSH:
     71 		if imm, ok := iargs[0].(Imm); ok {
     72 			iargs[0] = Imm(uint32(imm))
     73 		}
     74 	}
     75 
     76 	for _, p := range inst.Prefix {
     77 		if p&PrefixImplicit != 0 {
     78 			for j, pj := range inst.Prefix {
     79 				if pj&0xFF == p&0xFF {
     80 					inst.Prefix[j] |= PrefixImplicit
     81 				}
     82 			}
     83 		}
     84 	}
     85 
     86 	if inst.Op != 0 {
     87 		for i, p := range inst.Prefix {
     88 			switch p &^ PrefixIgnored {
     89 			case PrefixData16, PrefixData32, PrefixCS, PrefixDS, PrefixES, PrefixSS:
     90 				inst.Prefix[i] |= PrefixImplicit
     91 			}
     92 			if p.IsREX() {
     93 				inst.Prefix[i] |= PrefixImplicit
     94 			}
     95 			if p.IsVEX() {
     96 				if p == PrefixVEX3Bytes {
     97 					inst.Prefix[i+2] |= PrefixImplicit
     98 				}
     99 				inst.Prefix[i] |= PrefixImplicit
    100 				inst.Prefix[i+1] |= PrefixImplicit
    101 			}
    102 		}
    103 	}
    104 
    105 	if isLoop[inst.Op] || inst.Op == JCXZ || inst.Op == JECXZ || inst.Op == JRCXZ {
    106 		for i, p := range inst.Prefix {
    107 			if p == PrefixPT || p == PrefixPN {
    108 				inst.Prefix[i] |= PrefixImplicit
    109 			}
    110 		}
    111 	}
    112 
    113 	switch inst.Op {
    114 	case AAA, AAS, CBW, CDQE, CLC, CLD, CLI, CLTS, CMC, CPUID, CQO, CWD, DAA, DAS,
    115 		FDECSTP, FINCSTP, FNCLEX, FNINIT, FNOP, FWAIT, HLT,
    116 		ICEBP, INSB, INSD, INSW, INT, INTO, INVD, IRET, IRETQ,
    117 		LAHF, LEAVE, LRET, MONITOR, MWAIT, NOP, OUTSB, OUTSD, OUTSW,
    118 		PAUSE, POPA, POPF, POPFQ, PUSHA, PUSHF, PUSHFQ,
    119 		RDMSR, RDPMC, RDTSC, RDTSCP, RET, RSM,
    120 		SAHF, STC, STD, STI, SYSENTER, SYSEXIT, SYSRET,
    121 		UD2, WBINVD, WRMSR, XEND, XLATB, XTEST:
    122 
    123 		if inst.Op == NOP && inst.Opcode>>24 != 0x90 {
    124 			break
    125 		}
    126 		if inst.Op == RET && inst.Opcode>>24 != 0xC3 {
    127 			break
    128 		}
    129 		if inst.Op == INT && inst.Opcode>>24 != 0xCC {
    130 			break
    131 		}
    132 		if inst.Op == LRET && inst.Opcode>>24 != 0xcb {
    133 			break
    134 		}
    135 		for i, p := range inst.Prefix {
    136 			if p&0xFF == PrefixDataSize {
    137 				inst.Prefix[i] &^= PrefixImplicit | PrefixIgnored
    138 			}
    139 		}
    140 
    141 	case 0:
    142 		// ok
    143 	}
    144 
    145 	switch inst.Op {
    146 	case INSB, INSD, INSW, OUTSB, OUTSD, OUTSW, MONITOR, MWAIT, XLATB:
    147 		iargs = nil
    148 
    149 	case STOSB, STOSW, STOSD, STOSQ:
    150 		iargs = iargs[:1]
    151 
    152 	case LODSB, LODSW, LODSD, LODSQ, SCASB, SCASW, SCASD, SCASQ:
    153 		iargs = iargs[1:]
    154 	}
    155 
    156 	const (
    157 		haveData16 = 1 << iota
    158 		haveData32
    159 		haveAddr16
    160 		haveAddr32
    161 		haveXacquire
    162 		haveXrelease
    163 		haveLock
    164 		haveHintTaken
    165 		haveHintNotTaken
    166 		haveBnd
    167 	)
    168 	var prefixBits uint32
    169 	prefix := ""
    170 	for _, p := range inst.Prefix {
    171 		if p == 0 {
    172 			break
    173 		}
    174 		if p&0xFF == 0xF3 {
    175 			prefixBits &^= haveBnd
    176 		}
    177 		if p&(PrefixImplicit|PrefixIgnored) != 0 {
    178 			continue
    179 		}
    180 		switch p {
    181 		default:
    182 			prefix += strings.ToLower(p.String()) + " "
    183 		case PrefixCS, PrefixDS, PrefixES, PrefixFS, PrefixGS, PrefixSS:
    184 			if inst.Op == 0 {
    185 				prefix += strings.ToLower(p.String()) + " "
    186 			}
    187 		case PrefixREPN:
    188 			prefix += "repne "
    189 		case PrefixLOCK:
    190 			prefixBits |= haveLock
    191 		case PrefixData16, PrefixDataSize:
    192 			prefixBits |= haveData16
    193 		case PrefixData32:
    194 			prefixBits |= haveData32
    195 		case PrefixAddrSize, PrefixAddr16:
    196 			prefixBits |= haveAddr16
    197 		case PrefixAddr32:
    198 			prefixBits |= haveAddr32
    199 		case PrefixXACQUIRE:
    200 			prefixBits |= haveXacquire
    201 		case PrefixXRELEASE:
    202 			prefixBits |= haveXrelease
    203 		case PrefixPT:
    204 			prefixBits |= haveHintTaken
    205 		case PrefixPN:
    206 			prefixBits |= haveHintNotTaken
    207 		case PrefixBND:
    208 			prefixBits |= haveBnd
    209 		}
    210 	}
    211 	switch inst.Op {
    212 	case JMP:
    213 		if inst.Opcode>>24 == 0xEB {
    214 			prefixBits &^= haveBnd
    215 		}
    216 	case RET, LRET:
    217 		prefixBits &^= haveData16 | haveData32
    218 	}
    219 
    220 	if prefixBits&haveXacquire != 0 {
    221 		prefix += "xacquire "
    222 	}
    223 	if prefixBits&haveXrelease != 0 {
    224 		prefix += "xrelease "
    225 	}
    226 	if prefixBits&haveLock != 0 {
    227 		prefix += "lock "
    228 	}
    229 	if prefixBits&haveBnd != 0 {
    230 		prefix += "bnd "
    231 	}
    232 	if prefixBits&haveHintTaken != 0 {
    233 		prefix += "hint-taken "
    234 	}
    235 	if prefixBits&haveHintNotTaken != 0 {
    236 		prefix += "hint-not-taken "
    237 	}
    238 	if prefixBits&haveAddr16 != 0 {
    239 		prefix += "addr16 "
    240 	}
    241 	if prefixBits&haveAddr32 != 0 {
    242 		prefix += "addr32 "
    243 	}
    244 	if prefixBits&haveData16 != 0 {
    245 		prefix += "data16 "
    246 	}
    247 	if prefixBits&haveData32 != 0 {
    248 		prefix += "data32 "
    249 	}
    250 
    251 	if inst.Op == 0 {
    252 		if prefix == "" {
    253 			return "<no instruction>"
    254 		}
    255 		return prefix[:len(prefix)-1]
    256 	}
    257 
    258 	var args []string
    259 	for _, a := range iargs {
    260 		if a == nil {
    261 			break
    262 		}
    263 		args = append(args, intelArg(&inst, pc, symname, a))
    264 	}
    265 
    266 	var op string
    267 	switch inst.Op {
    268 	case NOP:
    269 		if inst.Opcode>>24 == 0x0F {
    270 			if inst.DataSize == 16 {
    271 				args = append(args, "ax")
    272 			} else {
    273 				args = append(args, "eax")
    274 			}
    275 		}
    276 
    277 	case BLENDVPD, BLENDVPS, PBLENDVB:
    278 		args = args[:2]
    279 
    280 	case INT:
    281 		if inst.Opcode>>24 == 0xCC {
    282 			args = nil
    283 			op = "int3"
    284 		}
    285 
    286 	case LCALL, LJMP:
    287 		if len(args) == 2 {
    288 			args[0], args[1] = args[1], args[0]
    289 		}
    290 
    291 	case FCHS, FABS, FTST, FLDPI, FLDL2E, FLDLG2, F2XM1, FXAM, FLD1, FLDL2T, FSQRT, FRNDINT, FCOS, FSIN:
    292 		if len(args) == 0 {
    293 			args = append(args, "st0")
    294 		}
    295 
    296 	case FPTAN, FSINCOS, FUCOMPP, FCOMPP, FYL2X, FPATAN, FXTRACT, FPREM1, FPREM, FYL2XP1, FSCALE:
    297 		if len(args) == 0 {
    298 			args = []string{"st0", "st1"}
    299 		}
    300 
    301 	case FST, FSTP, FISTTP, FIST, FISTP, FBSTP:
    302 		if len(args) == 1 {
    303 			args = append(args, "st0")
    304 		}
    305 
    306 	case FLD, FXCH, FCOM, FCOMP, FIADD, FIMUL, FICOM, FICOMP, FISUBR, FIDIV, FUCOM, FUCOMP, FILD, FBLD, FADD, FMUL, FSUB, FSUBR, FISUB, FDIV, FDIVR, FIDIVR:
    307 		if len(args) == 1 {
    308 			args = []string{"st0", args[0]}
    309 		}
    310 
    311 	case MASKMOVDQU, MASKMOVQ, XLATB, OUTSB, OUTSW, OUTSD:
    312 	FixSegment:
    313 		for i := len(inst.Prefix) - 1; i >= 0; i-- {
    314 			p := inst.Prefix[i] & 0xFF
    315 			switch p {
    316 			case PrefixCS, PrefixES, PrefixFS, PrefixGS, PrefixSS:
    317 				if inst.Mode != 64 || p == PrefixFS || p == PrefixGS {
    318 					args = append(args, strings.ToLower((inst.Prefix[i] & 0xFF).String()))
    319 					break FixSegment
    320 				}
    321 			case PrefixDS:
    322 				if inst.Mode != 64 {
    323 					break FixSegment
    324 				}
    325 			}
    326 		}
    327 	}
    328 
    329 	if op == "" {
    330 		op = intelOp[inst.Op]
    331 	}
    332 	if op == "" {
    333 		op = strings.ToLower(inst.Op.String())
    334 	}
    335 	if args != nil {
    336 		op += " " + strings.Join(args, ", ")
    337 	}
    338 	return prefix + op
    339 }
    340 
    341 func intelArg(inst *Inst, pc uint64, symname SymLookup, arg Arg) string {
    342 	switch a := arg.(type) {
    343 	case Imm:
    344 		if s, base := symname(uint64(a)); s != "" {
    345 			suffix := ""
    346 			if uint64(a) != base {
    347 				suffix = fmt.Sprintf("%+d", uint64(a)-base)
    348 			}
    349 			return fmt.Sprintf("$%s%s", s, suffix)
    350 		}
    351 		if inst.Mode == 32 {
    352 			return fmt.Sprintf("%#x", uint32(a))
    353 		}
    354 		if Imm(int32(a)) == a {
    355 			return fmt.Sprintf("%#x", int64(a))
    356 		}
    357 		return fmt.Sprintf("%#x", uint64(a))
    358 	case Mem:
    359 		if a.Base == EIP {
    360 			a.Base = RIP
    361 		}
    362 		prefix := ""
    363 		switch inst.MemBytes {
    364 		case 1:
    365 			prefix = "byte "
    366 		case 2:
    367 			prefix = "word "
    368 		case 4:
    369 			prefix = "dword "
    370 		case 8:
    371 			prefix = "qword "
    372 		case 16:
    373 			prefix = "xmmword "
    374 		case 32:
    375 			prefix = "ymmword "
    376 		}
    377 		switch inst.Op {
    378 		case INVLPG:
    379 			prefix = "byte "
    380 		case STOSB, MOVSB, CMPSB, LODSB, SCASB:
    381 			prefix = "byte "
    382 		case STOSW, MOVSW, CMPSW, LODSW, SCASW:
    383 			prefix = "word "
    384 		case STOSD, MOVSD, CMPSD, LODSD, SCASD:
    385 			prefix = "dword "
    386 		case STOSQ, MOVSQ, CMPSQ, LODSQ, SCASQ:
    387 			prefix = "qword "
    388 		case LAR:
    389 			prefix = "word "
    390 		case BOUND:
    391 			if inst.Mode == 32 {
    392 				prefix = "qword "
    393 			} else {
    394 				prefix = "dword "
    395 			}
    396 		case PREFETCHW, PREFETCHNTA, PREFETCHT0, PREFETCHT1, PREFETCHT2, CLFLUSH:
    397 			prefix = "zmmword "
    398 		}
    399 		switch inst.Op {
    400 		case MOVSB, MOVSW, MOVSD, MOVSQ, CMPSB, CMPSW, CMPSD, CMPSQ, STOSB, STOSW, STOSD, STOSQ, SCASB, SCASW, SCASD, SCASQ, LODSB, LODSW, LODSD, LODSQ:
    401 			switch a.Base {
    402 			case DI, EDI, RDI:
    403 				if a.Segment == ES {
    404 					a.Segment = 0
    405 				}
    406 			case SI, ESI, RSI:
    407 				if a.Segment == DS {
    408 					a.Segment = 0
    409 				}
    410 			}
    411 		case LEA:
    412 			a.Segment = 0
    413 		default:
    414 			switch a.Base {
    415 			case SP, ESP, RSP, BP, EBP, RBP:
    416 				if a.Segment == SS {
    417 					a.Segment = 0
    418 				}
    419 			default:
    420 				if a.Segment == DS {
    421 					a.Segment = 0
    422 				}
    423 			}
    424 		}
    425 
    426 		if inst.Mode == 64 && a.Segment != FS && a.Segment != GS {
    427 			a.Segment = 0
    428 		}
    429 
    430 		prefix += "ptr "
    431 		if s, disp := memArgToSymbol(a, pc, inst.Len, symname); s != "" {
    432 			suffix := ""
    433 			if disp != 0 {
    434 				suffix = fmt.Sprintf("%+d", disp)
    435 			}
    436 			return prefix + fmt.Sprintf("[%s%s]", s, suffix)
    437 		}
    438 		if a.Segment != 0 {
    439 			prefix += strings.ToLower(a.Segment.String()) + ":"
    440 		}
    441 		prefix += "["
    442 		if a.Base != 0 {
    443 			prefix += intelArg(inst, pc, symname, a.Base)
    444 		}
    445 		if a.Scale != 0 && a.Index != 0 {
    446 			if a.Base != 0 {
    447 				prefix += "+"
    448 			}
    449 			prefix += fmt.Sprintf("%s*%d", intelArg(inst, pc, symname, a.Index), a.Scale)
    450 		}
    451 		if a.Disp != 0 {
    452 			if prefix[len(prefix)-1] == '[' && (a.Disp >= 0 || int64(int32(a.Disp)) != a.Disp) {
    453 				prefix += fmt.Sprintf("%#x", uint64(a.Disp))
    454 			} else {
    455 				prefix += fmt.Sprintf("%+#x", a.Disp)
    456 			}
    457 		}
    458 		prefix += "]"
    459 		return prefix
    460 	case Rel:
    461 		if pc == 0 {
    462 			return fmt.Sprintf(".%+#x", int64(a))
    463 		} else {
    464 			addr := pc + uint64(inst.Len) + uint64(a)
    465 			if s, base := symname(addr); s != "" && addr == base {
    466 				return fmt.Sprintf("%s", s)
    467 			} else {
    468 				addr := pc + uint64(inst.Len) + uint64(a)
    469 				return fmt.Sprintf("%#x", addr)
    470 			}
    471 		}
    472 	case Reg:
    473 		if int(a) < len(intelReg) && intelReg[a] != "" {
    474 			switch inst.Op {
    475 			case VMOVDQA, VMOVDQU, VMOVNTDQA, VMOVNTDQ:
    476 				return strings.Replace(intelReg[a], "xmm", "ymm", -1)
    477 			default:
    478 				return intelReg[a]
    479 			}
    480 		}
    481 	}
    482 	return strings.ToLower(arg.String())
    483 }
    484 
    485 var intelOp = map[Op]string{
    486 	JAE:       "jnb",
    487 	JA:        "jnbe",
    488 	JGE:       "jnl",
    489 	JNE:       "jnz",
    490 	JG:        "jnle",
    491 	JE:        "jz",
    492 	SETAE:     "setnb",
    493 	SETA:      "setnbe",
    494 	SETGE:     "setnl",
    495 	SETNE:     "setnz",
    496 	SETG:      "setnle",
    497 	SETE:      "setz",
    498 	CMOVAE:    "cmovnb",
    499 	CMOVA:     "cmovnbe",
    500 	CMOVGE:    "cmovnl",
    501 	CMOVNE:    "cmovnz",
    502 	CMOVG:     "cmovnle",
    503 	CMOVE:     "cmovz",
    504 	LCALL:     "call far",
    505 	LJMP:      "jmp far",
    506 	LRET:      "ret far",
    507 	ICEBP:     "int1",
    508 	MOVSD_XMM: "movsd",
    509 	XLATB:     "xlat",
    510 }
    511 
    512 var intelReg = [...]string{
    513 	F0:  "st0",
    514 	F1:  "st1",
    515 	F2:  "st2",
    516 	F3:  "st3",
    517 	F4:  "st4",
    518 	F5:  "st5",
    519 	F6:  "st6",
    520 	F7:  "st7",
    521 	M0:  "mmx0",
    522 	M1:  "mmx1",
    523 	M2:  "mmx2",
    524 	M3:  "mmx3",
    525 	M4:  "mmx4",
    526 	M5:  "mmx5",
    527 	M6:  "mmx6",
    528 	M7:  "mmx7",
    529 	X0:  "xmm0",
    530 	X1:  "xmm1",
    531 	X2:  "xmm2",
    532 	X3:  "xmm3",
    533 	X4:  "xmm4",
    534 	X5:  "xmm5",
    535 	X6:  "xmm6",
    536 	X7:  "xmm7",
    537 	X8:  "xmm8",
    538 	X9:  "xmm9",
    539 	X10: "xmm10",
    540 	X11: "xmm11",
    541 	X12: "xmm12",
    542 	X13: "xmm13",
    543 	X14: "xmm14",
    544 	X15: "xmm15",
    545 
    546 	// TODO: Maybe the constants are named wrong.
    547 	SPB: "spl",
    548 	BPB: "bpl",
    549 	SIB: "sil",
    550 	DIB: "dil",
    551 
    552 	R8L:  "r8d",
    553 	R9L:  "r9d",
    554 	R10L: "r10d",
    555 	R11L: "r11d",
    556 	R12L: "r12d",
    557 	R13L: "r13d",
    558 	R14L: "r14d",
    559 	R15L: "r15d",
    560 }