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