golang.org/x/arch@v0.17.0/x86/x86asm/gnu.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 // 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 (inst.Op == MOV || inst.Op == PUSH) && inst.DataSize == 32 { // See comment in plan9x.go. 671 if s, base := symname(uint64(x)); s != "" { 672 suffix := "" 673 if uint64(x) != base { 674 suffix = fmt.Sprintf("%+d", uint64(x)-base) 675 } 676 return fmt.Sprintf("$%s%s", s, suffix) 677 } 678 } 679 if inst.Mode == 32 { 680 return fmt.Sprintf("$%#x", uint32(x)) 681 } 682 return fmt.Sprintf("$%#x", int64(x)) 683 } 684 return x.String() 685 } 686 687 var gccRegName = [...]string{ 688 0: "REG0", 689 AL: "%al", 690 CL: "%cl", 691 BL: "%bl", 692 DL: "%dl", 693 AH: "%ah", 694 CH: "%ch", 695 BH: "%bh", 696 DH: "%dh", 697 SPB: "%spl", 698 BPB: "%bpl", 699 SIB: "%sil", 700 DIB: "%dil", 701 R8B: "%r8b", 702 R9B: "%r9b", 703 R10B: "%r10b", 704 R11B: "%r11b", 705 R12B: "%r12b", 706 R13B: "%r13b", 707 R14B: "%r14b", 708 R15B: "%r15b", 709 AX: "%ax", 710 CX: "%cx", 711 BX: "%bx", 712 DX: "%dx", 713 SP: "%sp", 714 BP: "%bp", 715 SI: "%si", 716 DI: "%di", 717 R8W: "%r8w", 718 R9W: "%r9w", 719 R10W: "%r10w", 720 R11W: "%r11w", 721 R12W: "%r12w", 722 R13W: "%r13w", 723 R14W: "%r14w", 724 R15W: "%r15w", 725 EAX: "%eax", 726 ECX: "%ecx", 727 EDX: "%edx", 728 EBX: "%ebx", 729 ESP: "%esp", 730 EBP: "%ebp", 731 ESI: "%esi", 732 EDI: "%edi", 733 R8L: "%r8d", 734 R9L: "%r9d", 735 R10L: "%r10d", 736 R11L: "%r11d", 737 R12L: "%r12d", 738 R13L: "%r13d", 739 R14L: "%r14d", 740 R15L: "%r15d", 741 RAX: "%rax", 742 RCX: "%rcx", 743 RDX: "%rdx", 744 RBX: "%rbx", 745 RSP: "%rsp", 746 RBP: "%rbp", 747 RSI: "%rsi", 748 RDI: "%rdi", 749 R8: "%r8", 750 R9: "%r9", 751 R10: "%r10", 752 R11: "%r11", 753 R12: "%r12", 754 R13: "%r13", 755 R14: "%r14", 756 R15: "%r15", 757 IP: "%ip", 758 EIP: "%eip", 759 RIP: "%rip", 760 F0: "%st", 761 F1: "%st(1)", 762 F2: "%st(2)", 763 F3: "%st(3)", 764 F4: "%st(4)", 765 F5: "%st(5)", 766 F6: "%st(6)", 767 F7: "%st(7)", 768 M0: "%mm0", 769 M1: "%mm1", 770 M2: "%mm2", 771 M3: "%mm3", 772 M4: "%mm4", 773 M5: "%mm5", 774 M6: "%mm6", 775 M7: "%mm7", 776 X0: "%xmm0", 777 X1: "%xmm1", 778 X2: "%xmm2", 779 X3: "%xmm3", 780 X4: "%xmm4", 781 X5: "%xmm5", 782 X6: "%xmm6", 783 X7: "%xmm7", 784 X8: "%xmm8", 785 X9: "%xmm9", 786 X10: "%xmm10", 787 X11: "%xmm11", 788 X12: "%xmm12", 789 X13: "%xmm13", 790 X14: "%xmm14", 791 X15: "%xmm15", 792 CS: "%cs", 793 SS: "%ss", 794 DS: "%ds", 795 ES: "%es", 796 FS: "%fs", 797 GS: "%gs", 798 GDTR: "%gdtr", 799 IDTR: "%idtr", 800 LDTR: "%ldtr", 801 MSW: "%msw", 802 TASK: "%task", 803 CR0: "%cr0", 804 CR1: "%cr1", 805 CR2: "%cr2", 806 CR3: "%cr3", 807 CR4: "%cr4", 808 CR5: "%cr5", 809 CR6: "%cr6", 810 CR7: "%cr7", 811 CR8: "%cr8", 812 CR9: "%cr9", 813 CR10: "%cr10", 814 CR11: "%cr11", 815 CR12: "%cr12", 816 CR13: "%cr13", 817 CR14: "%cr14", 818 CR15: "%cr15", 819 DR0: "%db0", 820 DR1: "%db1", 821 DR2: "%db2", 822 DR3: "%db3", 823 DR4: "%db4", 824 DR5: "%db5", 825 DR6: "%db6", 826 DR7: "%db7", 827 TR0: "%tr0", 828 TR1: "%tr1", 829 TR2: "%tr2", 830 TR3: "%tr3", 831 TR4: "%tr4", 832 TR5: "%tr5", 833 TR6: "%tr6", 834 TR7: "%tr7", 835 } 836 837 var gnuOp = map[Op]string{ 838 CBW: "cbtw", 839 CDQ: "cltd", 840 CMPSD: "cmpsl", 841 CMPSD_XMM: "cmpsd", 842 CWD: "cwtd", 843 CWDE: "cwtl", 844 CQO: "cqto", 845 INSD: "insl", 846 IRET: "iretw", 847 IRETD: "iret", 848 IRETQ: "iretq", 849 LODSB: "lods", 850 LODSD: "lods", 851 LODSQ: "lods", 852 LODSW: "lods", 853 MOVSD: "movsl", 854 MOVSD_XMM: "movsd", 855 OUTSD: "outsl", 856 POPA: "popaw", 857 POPAD: "popa", 858 POPF: "popfw", 859 POPFD: "popf", 860 PUSHA: "pushaw", 861 PUSHAD: "pusha", 862 PUSHF: "pushfw", 863 PUSHFD: "pushf", 864 SCASB: "scas", 865 SCASD: "scas", 866 SCASQ: "scas", 867 SCASW: "scas", 868 STOSB: "stos", 869 STOSD: "stos", 870 STOSQ: "stos", 871 STOSW: "stos", 872 XLATB: "xlat", 873 } 874 875 var cmppsOps = []string{ 876 "cmpeq", 877 "cmplt", 878 "cmple", 879 "cmpunord", 880 "cmpneq", 881 "cmpnlt", 882 "cmpnle", 883 "cmpord", 884 } 885 886 var pclmulqOps = []string{ 887 "pclmullqlqdq", 888 "pclmulhqlqdq", 889 "pclmullqhqdq", 890 "pclmulhqhqdq", 891 } 892 893 func countPrefix(inst *Inst, target Prefix) int { 894 n := 0 895 for _, p := range inst.Prefix { 896 if p&0xFF == target&0xFF { 897 n++ 898 } 899 } 900 return n 901 } 902 903 func markLastImplicit(inst *Inst, prefix Prefix) bool { 904 for i := len(inst.Prefix) - 1; i >= 0; i-- { 905 p := inst.Prefix[i] 906 if p&0xFF == prefix { 907 inst.Prefix[i] |= PrefixImplicit 908 return true 909 } 910 } 911 return false 912 } 913 914 func unmarkImplicit(inst *Inst, prefix Prefix) { 915 for i := len(inst.Prefix) - 1; i >= 0; i-- { 916 p := inst.Prefix[i] 917 if p&0xFF == prefix { 918 inst.Prefix[i] &^= PrefixImplicit 919 } 920 } 921 } 922 923 func byteSizeSuffix(b int) string { 924 switch b { 925 case 1: 926 return "b" 927 case 2: 928 return "w" 929 case 4: 930 return "l" 931 case 8: 932 return "q" 933 } 934 return "" 935 } 936 937 func argBytes(inst *Inst, arg Arg) int { 938 if isMem(arg) { 939 return inst.MemBytes 940 } 941 return regBytes(arg) 942 } 943 944 func isFloat(op Op) bool { 945 switch op { 946 case FADD, FCOM, FCOMP, FDIV, FDIVR, FIADD, FICOM, FICOMP, FIDIV, FIDIVR, FILD, FIMUL, FIST, FISTP, FISTTP, FISUB, FISUBR, FLD, FMUL, FST, FSTP, FSUB, FSUBR: 947 return true 948 } 949 return false 950 } 951 952 func isFloatInt(op Op) bool { 953 switch op { 954 case FIADD, FICOM, FICOMP, FIDIV, FIDIVR, FILD, FIMUL, FIST, FISTP, FISTTP, FISUB, FISUBR: 955 return true 956 } 957 return false 958 }