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 }