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) 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 // Adjust opcode [sic]. 21 switch inst.Op { 22 case FDIV, FDIVR, FSUB, FSUBR, FDIVP, FDIVRP, FSUBP, FSUBRP: 23 // DC E0, DC F0: libopcodes swaps FSUBR/FSUB and FDIVR/FDIV, at least 24 // if you believe the Intel manual is correct (the encoding is irregular as given; 25 // libopcodes uses the more regular expected encoding). 26 // TODO(rsc): Test to ensure Intel manuals are correct and report to libopcodes maintainers? 27 // NOTE: iant thinks this is deliberate, but we can't find the history. 28 _, reg1 := inst.Args[0].(Reg) 29 _, reg2 := inst.Args[1].(Reg) 30 if reg1 && reg2 && (inst.Opcode>>24 == 0xDC || inst.Opcode>>24 == 0xDE) { 31 switch inst.Op { 32 case FDIV: 33 inst.Op = FDIVR 34 case FDIVR: 35 inst.Op = FDIV 36 case FSUB: 37 inst.Op = FSUBR 38 case FSUBR: 39 inst.Op = FSUB 40 case FDIVP: 41 inst.Op = FDIVRP 42 case FDIVRP: 43 inst.Op = FDIVP 44 case FSUBP: 45 inst.Op = FSUBRP 46 case FSUBRP: 47 inst.Op = FSUBP 48 } 49 } 50 51 case MOVNTSD: 52 // MOVNTSD is F2 0F 2B /r. 53 // MOVNTSS is F3 0F 2B /r (supposedly; not in manuals). 54 // Usually inner prefixes win for display, 55 // so that F3 F2 0F 2B 11 is REP MOVNTSD 56 // and F2 F3 0F 2B 11 is REPN MOVNTSS. 57 // Libopcodes always prefers MOVNTSS regardless of prefix order. 58 if countPrefix(&inst, 0xF3) > 0 { 59 found := false 60 for i := len(inst.Prefix) - 1; i >= 0; i-- { 61 switch inst.Prefix[i] & 0xFF { 62 case 0xF3: 63 if !found { 64 found = true 65 inst.Prefix[i] |= PrefixImplicit 66 } 67 case 0xF2: 68 inst.Prefix[i] &^= PrefixImplicit 69 } 70 } 71 inst.Op = MOVNTSS 72 } 73 } 74 75 // Add implicit arguments. 76 switch inst.Op { 77 case MONITOR: 78 inst.Args[0] = EDX 79 inst.Args[1] = ECX 80 inst.Args[2] = EAX 81 if inst.AddrSize == 16 { 82 inst.Args[2] = AX 83 } 84 85 case MWAIT: 86 if inst.Mode == 64 { 87 inst.Args[0] = RCX 88 inst.Args[1] = RAX 89 } else { 90 inst.Args[0] = ECX 91 inst.Args[1] = EAX 92 } 93 } 94 95 // Adjust which prefixes will be displayed. 96 // The rule is to display all the prefixes not implied by 97 // the usual instruction display, that is, all the prefixes 98 // except the ones with PrefixImplicit set. 99 // However, of course, there are exceptions to the rule. 100 switch inst.Op { 101 case CRC32: 102 // CRC32 has a mandatory F2 prefix. 103 // If there are multiple F2s and no F3s, the extra F2s do not print. 104 // (And Decode has already marked them implicit.) 105 // However, if there is an F3 anywhere, then the extra F2s do print. 106 // If there are multiple F2 prefixes *and* an (ignored) F3, 107 // then libopcodes prints the extra F2s as REPNs. 108 if countPrefix(&inst, 0xF2) > 1 { 109 unmarkImplicit(&inst, 0xF2) 110 markLastImplicit(&inst, 0xF2) 111 } 112 113 // An unused data size override should probably be shown, 114 // to distinguish DATA16 CRC32B from plain CRC32B, 115 // but libopcodes always treats the final override as implicit 116 // and the others as explicit. 117 unmarkImplicit(&inst, PrefixDataSize) 118 markLastImplicit(&inst, PrefixDataSize) 119 120 case CVTSI2SD, CVTSI2SS: 121 if !isMem(inst.Args[1]) { 122 markLastImplicit(&inst, PrefixDataSize) 123 } 124 125 case CVTSD2SI, CVTSS2SI, CVTTSD2SI, CVTTSS2SI, 126 ENTER, FLDENV, FNSAVE, FNSTENV, FRSTOR, LGDT, LIDT, LRET, 127 POP, PUSH, RET, SGDT, SIDT, SYSRET, XBEGIN: 128 markLastImplicit(&inst, PrefixDataSize) 129 130 case LOOP, LOOPE, LOOPNE, MONITOR: 131 markLastImplicit(&inst, PrefixAddrSize) 132 133 case MOV: 134 // The 16-bit and 32-bit forms of MOV Sreg, dst and MOV src, Sreg 135 // cannot be distinguished when src or dst refers to memory, because 136 // Sreg is always a 16-bit value, even when we're doing a 32-bit 137 // instruction. Because the instruction tables distinguished these two, 138 // any operand size prefix has been marked as used (to decide which 139 // branch to take). Unmark it, so that it will show up in disassembly, 140 // so that the reader can tell the size of memory operand. 141 // up with the same arguments 142 dst, _ := inst.Args[0].(Reg) 143 src, _ := inst.Args[1].(Reg) 144 if ES <= src && src <= GS && isMem(inst.Args[0]) || ES <= dst && dst <= GS && isMem(inst.Args[1]) { 145 unmarkImplicit(&inst, PrefixDataSize) 146 } 147 148 case MOVDQU: 149 if countPrefix(&inst, 0xF3) > 1 { 150 unmarkImplicit(&inst, 0xF3) 151 markLastImplicit(&inst, 0xF3) 152 } 153 154 case MOVQ2DQ: 155 markLastImplicit(&inst, PrefixDataSize) 156 157 case SLDT, SMSW, STR, FXRSTOR, XRSTOR, XSAVE, XSAVEOPT, CMPXCHG8B: 158 if isMem(inst.Args[0]) { 159 unmarkImplicit(&inst, PrefixDataSize) 160 } 161 162 case SYSEXIT: 163 unmarkImplicit(&inst, PrefixDataSize) 164 } 165 166 if isCondJmp[inst.Op] || isLoop[inst.Op] || inst.Op == JCXZ || inst.Op == JECXZ || inst.Op == JRCXZ { 167 if countPrefix(&inst, PrefixCS) > 0 && countPrefix(&inst, PrefixDS) > 0 { 168 for i, p := range inst.Prefix { 169 switch p & 0xFFF { 170 case PrefixPN, PrefixPT: 171 inst.Prefix[i] &= 0xF0FF // cut interpretation bits, producing original segment prefix 172 } 173 } 174 } 175 } 176 177 // XACQUIRE/XRELEASE adjustment. 178 if inst.Op == MOV { 179 // MOV into memory is a candidate for turning REP into XRELEASE. 180 // However, if the REP is followed by a REPN, that REPN blocks the 181 // conversion. 182 haveREPN := false 183 for i := len(inst.Prefix) - 1; i >= 0; i-- { 184 switch inst.Prefix[i] &^ PrefixIgnored { 185 case PrefixREPN: 186 haveREPN = true 187 case PrefixXRELEASE: 188 if haveREPN { 189 inst.Prefix[i] = PrefixREP 190 } 191 } 192 } 193 } 194 195 // We only format the final F2/F3 as XRELEASE/XACQUIRE. 196 haveXA := false 197 haveXR := false 198 for i := len(inst.Prefix) - 1; i >= 0; i-- { 199 switch inst.Prefix[i] &^ PrefixIgnored { 200 case PrefixXRELEASE: 201 if !haveXR { 202 haveXR = true 203 } else { 204 inst.Prefix[i] = PrefixREP 205 } 206 207 case PrefixXACQUIRE: 208 if !haveXA { 209 haveXA = true 210 } else { 211 inst.Prefix[i] = PrefixREPN 212 } 213 } 214 } 215 216 // Determine opcode. 217 op := strings.ToLower(inst.Op.String()) 218 if alt := gnuOp[inst.Op]; alt != "" { 219 op = alt 220 } 221 222 // Determine opcode suffix. 223 // Libopcodes omits the suffix if the width of the operation 224 // can be inferred from a register arguments. For example, 225 // add $1, %ebx has no suffix because you can tell from the 226 // 32-bit register destination that it is a 32-bit add, 227 // but in addl $1, (%ebx), the destination is memory, so the 228 // size is not evident without the l suffix. 229 needSuffix := true 230 SuffixLoop: 231 for i, a := range inst.Args { 232 if a == nil { 233 break 234 } 235 switch a := a.(type) { 236 case Reg: 237 switch inst.Op { 238 case MOVSX, MOVZX: 239 continue 240 241 case SHL, SHR, RCL, RCR, ROL, ROR, SAR: 242 if i == 1 { 243 // shift count does not tell us operand size 244 continue 245 } 246 247 case CRC32: 248 // The source argument does tell us operand size, 249 // but libopcodes still always puts a suffix on crc32. 250 continue 251 252 case PUSH, POP: 253 // Even though segment registers are 16-bit, push and pop 254 // can save/restore them from 32-bit slots, so they 255 // do not imply operand size. 256 if ES <= a && a <= GS { 257 continue 258 } 259 260 case CVTSI2SD, CVTSI2SS: 261 // The integer register argument takes priority. 262 if X0 <= a && a <= X15 { 263 continue 264 } 265 } 266 267 if AL <= a && a <= R15 || ES <= a && a <= GS || X0 <= a && a <= X15 || M0 <= a && a <= M7 { 268 needSuffix = false 269 break SuffixLoop 270 } 271 } 272 } 273 274 if needSuffix { 275 switch inst.Op { 276 case CMPXCHG8B, FLDCW, FNSTCW, FNSTSW, LDMXCSR, LLDT, LMSW, LTR, PCLMULQDQ, 277 SETA, SETAE, SETB, SETBE, SETE, SETG, SETGE, SETL, SETLE, SETNE, SETNO, SETNP, SETNS, SETO, SETP, SETS, 278 SLDT, SMSW, STMXCSR, STR, VERR, VERW: 279 // For various reasons, libopcodes emits no suffix for these instructions. 280 281 case CRC32: 282 op += byteSizeSuffix(argBytes(&inst, inst.Args[1])) 283 284 case LGDT, LIDT, SGDT, SIDT: 285 op += byteSizeSuffix(inst.DataSize / 8) 286 287 case MOVZX, MOVSX: 288 // Integer size conversions get two suffixes. 289 op = op[:4] + byteSizeSuffix(argBytes(&inst, inst.Args[1])) + byteSizeSuffix(argBytes(&inst, inst.Args[0])) 290 291 case LOOP, LOOPE, LOOPNE: 292 // Add w suffix to indicate use of CX register instead of ECX. 293 if inst.AddrSize == 16 { 294 op += "w" 295 } 296 297 case CALL, ENTER, JMP, LCALL, LEAVE, LJMP, LRET, RET, SYSRET, XBEGIN: 298 // Add w suffix to indicate use of 16-bit target. 299 // Exclude JMP rel8. 300 if inst.Opcode>>24 == 0xEB { 301 break 302 } 303 if inst.DataSize == 16 && inst.Mode != 16 { 304 markLastImplicit(&inst, PrefixDataSize) 305 op += "w" 306 } else if inst.Mode == 64 { 307 op += "q" 308 } 309 310 case FRSTOR, FNSAVE, FNSTENV, FLDENV: 311 // Add s suffix to indicate shortened FPU state (I guess). 312 if inst.DataSize == 16 { 313 op += "s" 314 } 315 316 case PUSH, POP: 317 if markLastImplicit(&inst, PrefixDataSize) { 318 op += byteSizeSuffix(inst.DataSize / 8) 319 } else if inst.Mode == 64 { 320 op += "q" 321 } else { 322 op += byteSizeSuffix(inst.MemBytes) 323 } 324 325 default: 326 if isFloat(inst.Op) { 327 // I can't explain any of this, but it's what libopcodes does. 328 switch inst.MemBytes { 329 default: 330 if (inst.Op == FLD || inst.Op == FSTP) && isMem(inst.Args[0]) { 331 op += "t" 332 } 333 case 4: 334 if isFloatInt(inst.Op) { 335 op += "l" 336 } else { 337 op += "s" 338 } 339 case 8: 340 if isFloatInt(inst.Op) { 341 op += "ll" 342 } else { 343 op += "l" 344 } 345 } 346 break 347 } 348 349 op += byteSizeSuffix(inst.MemBytes) 350 } 351 } 352 353 // Adjust special case opcodes. 354 switch inst.Op { 355 case 0: 356 if inst.Prefix[0] != 0 { 357 return strings.ToLower(inst.Prefix[0].String()) 358 } 359 360 case INT: 361 if inst.Opcode>>24 == 0xCC { 362 inst.Args[0] = nil 363 op = "int3" 364 } 365 366 case CMPPS, CMPPD, CMPSD_XMM, CMPSS: 367 imm, ok := inst.Args[2].(Imm) 368 if ok && 0 <= imm && imm < 8 { 369 inst.Args[2] = nil 370 op = cmppsOps[imm] + op[3:] 371 } 372 373 case PCLMULQDQ: 374 imm, ok := inst.Args[2].(Imm) 375 if ok && imm&^0x11 == 0 { 376 inst.Args[2] = nil 377 op = pclmulqOps[(imm&0x10)>>3|(imm&1)] 378 } 379 380 case XLATB: 381 if markLastImplicit(&inst, PrefixAddrSize) { 382 op = "xlat" // not xlatb 383 } 384 } 385 386 // Build list of argument strings. 387 var ( 388 usedPrefixes bool // segment prefixes consumed by Mem formatting 389 args []string // formatted arguments 390 ) 391 for i, a := range inst.Args { 392 if a == nil { 393 break 394 } 395 switch inst.Op { 396 case MOVSB, MOVSW, MOVSD, MOVSQ, OUTSB, OUTSW, OUTSD: 397 if i == 0 { 398 usedPrefixes = true // disable use of prefixes for first argument 399 } else { 400 usedPrefixes = false 401 } 402 } 403 if a == Imm(1) && (inst.Opcode>>24)&^1 == 0xD0 { 404 continue 405 } 406 args = append(args, gnuArg(&inst, a, &usedPrefixes)) 407 } 408 409 // The default is to print the arguments in reverse Intel order. 410 // A few instructions inhibit this behavior. 411 switch inst.Op { 412 case BOUND, LCALL, ENTER, LJMP: 413 // no reverse 414 default: 415 // reverse args 416 for i, j := 0, len(args)-1; i < j; i, j = i+1, j-1 { 417 args[i], args[j] = args[j], args[i] 418 } 419 } 420 421 // Build prefix string. 422 // Must be after argument formatting, which can turn off segment prefixes. 423 var ( 424 prefix = "" // output string 425 numAddr = 0 426 numData = 0 427 implicitData = false 428 ) 429 for _, p := range inst.Prefix { 430 if p&0xFF == PrefixDataSize && p&PrefixImplicit != 0 { 431 implicitData = true 432 } 433 } 434 for _, p := range inst.Prefix { 435 if p == 0 { 436 break 437 } 438 if p&PrefixImplicit != 0 { 439 continue 440 } 441 switch p &^ (PrefixIgnored | PrefixInvalid) { 442 default: 443 if p.IsREX() { 444 if p&0xFF == PrefixREX { 445 prefix += "rex " 446 } else { 447 prefix += "rex." + p.String()[4:] + " " 448 } 449 break 450 } 451 prefix += strings.ToLower(p.String()) + " " 452 453 case PrefixPN: 454 op += ",pn" 455 continue 456 457 case PrefixPT: 458 op += ",pt" 459 continue 460 461 case PrefixAddrSize, PrefixAddr16, PrefixAddr32: 462 // For unknown reasons, if the addr16 prefix is repeated, 463 // libopcodes displays all but the last as addr32, even though 464 // the addressing form used in a memory reference is clearly 465 // still 16-bit. 466 n := 32 467 if inst.Mode == 32 { 468 n = 16 469 } 470 numAddr++ 471 if countPrefix(&inst, PrefixAddrSize) > numAddr { 472 n = inst.Mode 473 } 474 prefix += fmt.Sprintf("addr%d ", n) 475 continue 476 477 case PrefixData16, PrefixData32: 478 if implicitData && countPrefix(&inst, PrefixDataSize) > 1 { 479 // Similar to the addr32 logic above, but it only kicks in 480 // when something used the data size prefix (one is implicit). 481 n := 16 482 if inst.Mode == 16 { 483 n = 32 484 } 485 numData++ 486 if countPrefix(&inst, PrefixDataSize) > numData { 487 if inst.Mode == 16 { 488 n = 16 489 } else { 490 n = 32 491 } 492 } 493 prefix += fmt.Sprintf("data%d ", n) 494 continue 495 } 496 prefix += strings.ToLower(p.String()) + " " 497 } 498 } 499 500 // Finally! Put it all together. 501 text := prefix + op 502 if args != nil { 503 text += " " 504 // Indirect call/jmp gets a star to distinguish from direct jump address. 505 if (inst.Op == CALL || inst.Op == JMP || inst.Op == LJMP || inst.Op == LCALL) && (isMem(inst.Args[0]) || isReg(inst.Args[0])) { 506 text += "*" 507 } 508 text += strings.Join(args, ",") 509 } 510 return text 511 } 512 513 // gnuArg returns the GNU syntax for the argument x from the instruction inst. 514 // If *usedPrefixes is false and x is a Mem, then the formatting 515 // includes any segment prefixes and sets *usedPrefixes to true. 516 func gnuArg(inst *Inst, x Arg, usedPrefixes *bool) string { 517 if x == nil { 518 return "<nil>" 519 } 520 switch x := x.(type) { 521 case Reg: 522 switch inst.Op { 523 case CVTSI2SS, CVTSI2SD, CVTSS2SI, CVTSD2SI, CVTTSD2SI, CVTTSS2SI: 524 if inst.DataSize == 16 && EAX <= x && x <= R15L { 525 x -= EAX - AX 526 } 527 528 case IN, INSB, INSW, INSD, OUT, OUTSB, OUTSW, OUTSD: 529 // DX is the port, but libopcodes prints it as if it were a memory reference. 530 if x == DX { 531 return "(%dx)" 532 } 533 } 534 return gccRegName[x] 535 case Mem: 536 seg := "" 537 var haveCS, haveDS, haveES, haveFS, haveGS, haveSS bool 538 switch x.Segment { 539 case CS: 540 haveCS = true 541 case DS: 542 haveDS = true 543 case ES: 544 haveES = true 545 case FS: 546 haveFS = true 547 case GS: 548 haveGS = true 549 case SS: 550 haveSS = true 551 } 552 switch inst.Op { 553 case INSB, INSW, INSD, STOSB, STOSW, STOSD, STOSQ, SCASB, SCASW, SCASD, SCASQ: 554 // These do not accept segment prefixes, at least in the GNU rendering. 555 default: 556 if *usedPrefixes { 557 break 558 } 559 for i := len(inst.Prefix) - 1; i >= 0; i-- { 560 p := inst.Prefix[i] &^ PrefixIgnored 561 if p == 0 { 562 continue 563 } 564 switch p { 565 case PrefixCS: 566 if !haveCS { 567 haveCS = true 568 inst.Prefix[i] |= PrefixImplicit 569 } 570 case PrefixDS: 571 if !haveDS { 572 haveDS = true 573 inst.Prefix[i] |= PrefixImplicit 574 } 575 case PrefixES: 576 if !haveES { 577 haveES = true 578 inst.Prefix[i] |= PrefixImplicit 579 } 580 case PrefixFS: 581 if !haveFS { 582 haveFS = true 583 inst.Prefix[i] |= PrefixImplicit 584 } 585 case PrefixGS: 586 if !haveGS { 587 haveGS = true 588 inst.Prefix[i] |= PrefixImplicit 589 } 590 case PrefixSS: 591 if !haveSS { 592 haveSS = true 593 inst.Prefix[i] |= PrefixImplicit 594 } 595 } 596 } 597 *usedPrefixes = true 598 } 599 if haveCS { 600 seg += "%cs:" 601 } 602 if haveDS { 603 seg += "%ds:" 604 } 605 if haveSS { 606 seg += "%ss:" 607 } 608 if haveES { 609 seg += "%es:" 610 } 611 if haveFS { 612 seg += "%fs:" 613 } 614 if haveGS { 615 seg += "%gs:" 616 } 617 disp := "" 618 if x.Disp != 0 { 619 disp = fmt.Sprintf("%#x", x.Disp) 620 } 621 if x.Scale == 0 || x.Index == 0 && x.Scale == 1 && (x.Base == ESP || x.Base == RSP || x.Base == 0 && inst.Mode == 64) { 622 if x.Base == 0 { 623 return seg + disp 624 } 625 return fmt.Sprintf("%s%s(%s)", seg, disp, gccRegName[x.Base]) 626 } 627 base := gccRegName[x.Base] 628 if x.Base == 0 { 629 base = "" 630 } 631 index := gccRegName[x.Index] 632 if x.Index == 0 { 633 if inst.AddrSize == 64 { 634 index = "%riz" 635 } else { 636 index = "%eiz" 637 } 638 } 639 if AX <= x.Base && x.Base <= DI { 640 // 16-bit addressing - no scale 641 return fmt.Sprintf("%s%s(%s,%s)", seg, disp, base, index) 642 } 643 return fmt.Sprintf("%s%s(%s,%s,%d)", seg, disp, base, index, x.Scale) 644 case Rel: 645 return fmt.Sprintf(".%+#x", int32(x)) 646 case Imm: 647 if inst.Mode == 32 { 648 return fmt.Sprintf("$%#x", uint32(x)) 649 } 650 return fmt.Sprintf("$%#x", int64(x)) 651 } 652 return x.String() 653 } 654 655 var gccRegName = [...]string{ 656 0: "REG0", 657 AL: "%al", 658 CL: "%cl", 659 BL: "%bl", 660 DL: "%dl", 661 AH: "%ah", 662 CH: "%ch", 663 BH: "%bh", 664 DH: "%dh", 665 SPB: "%spl", 666 BPB: "%bpl", 667 SIB: "%sil", 668 DIB: "%dil", 669 R8B: "%r8b", 670 R9B: "%r9b", 671 R10B: "%r10b", 672 R11B: "%r11b", 673 R12B: "%r12b", 674 R13B: "%r13b", 675 R14B: "%r14b", 676 R15B: "%r15b", 677 AX: "%ax", 678 CX: "%cx", 679 BX: "%bx", 680 DX: "%dx", 681 SP: "%sp", 682 BP: "%bp", 683 SI: "%si", 684 DI: "%di", 685 R8W: "%r8w", 686 R9W: "%r9w", 687 R10W: "%r10w", 688 R11W: "%r11w", 689 R12W: "%r12w", 690 R13W: "%r13w", 691 R14W: "%r14w", 692 R15W: "%r15w", 693 EAX: "%eax", 694 ECX: "%ecx", 695 EDX: "%edx", 696 EBX: "%ebx", 697 ESP: "%esp", 698 EBP: "%ebp", 699 ESI: "%esi", 700 EDI: "%edi", 701 R8L: "%r8d", 702 R9L: "%r9d", 703 R10L: "%r10d", 704 R11L: "%r11d", 705 R12L: "%r12d", 706 R13L: "%r13d", 707 R14L: "%r14d", 708 R15L: "%r15d", 709 RAX: "%rax", 710 RCX: "%rcx", 711 RDX: "%rdx", 712 RBX: "%rbx", 713 RSP: "%rsp", 714 RBP: "%rbp", 715 RSI: "%rsi", 716 RDI: "%rdi", 717 R8: "%r8", 718 R9: "%r9", 719 R10: "%r10", 720 R11: "%r11", 721 R12: "%r12", 722 R13: "%r13", 723 R14: "%r14", 724 R15: "%r15", 725 IP: "%ip", 726 EIP: "%eip", 727 RIP: "%rip", 728 F0: "%st", 729 F1: "%st(1)", 730 F2: "%st(2)", 731 F3: "%st(3)", 732 F4: "%st(4)", 733 F5: "%st(5)", 734 F6: "%st(6)", 735 F7: "%st(7)", 736 M0: "%mm0", 737 M1: "%mm1", 738 M2: "%mm2", 739 M3: "%mm3", 740 M4: "%mm4", 741 M5: "%mm5", 742 M6: "%mm6", 743 M7: "%mm7", 744 X0: "%xmm0", 745 X1: "%xmm1", 746 X2: "%xmm2", 747 X3: "%xmm3", 748 X4: "%xmm4", 749 X5: "%xmm5", 750 X6: "%xmm6", 751 X7: "%xmm7", 752 X8: "%xmm8", 753 X9: "%xmm9", 754 X10: "%xmm10", 755 X11: "%xmm11", 756 X12: "%xmm12", 757 X13: "%xmm13", 758 X14: "%xmm14", 759 X15: "%xmm15", 760 CS: "%cs", 761 SS: "%ss", 762 DS: "%ds", 763 ES: "%es", 764 FS: "%fs", 765 GS: "%gs", 766 GDTR: "%gdtr", 767 IDTR: "%idtr", 768 LDTR: "%ldtr", 769 MSW: "%msw", 770 TASK: "%task", 771 CR0: "%cr0", 772 CR1: "%cr1", 773 CR2: "%cr2", 774 CR3: "%cr3", 775 CR4: "%cr4", 776 CR5: "%cr5", 777 CR6: "%cr6", 778 CR7: "%cr7", 779 CR8: "%cr8", 780 CR9: "%cr9", 781 CR10: "%cr10", 782 CR11: "%cr11", 783 CR12: "%cr12", 784 CR13: "%cr13", 785 CR14: "%cr14", 786 CR15: "%cr15", 787 DR0: "%db0", 788 DR1: "%db1", 789 DR2: "%db2", 790 DR3: "%db3", 791 DR4: "%db4", 792 DR5: "%db5", 793 DR6: "%db6", 794 DR7: "%db7", 795 TR0: "%tr0", 796 TR1: "%tr1", 797 TR2: "%tr2", 798 TR3: "%tr3", 799 TR4: "%tr4", 800 TR5: "%tr5", 801 TR6: "%tr6", 802 TR7: "%tr7", 803 } 804 805 var gnuOp = map[Op]string{ 806 CBW: "cbtw", 807 CDQ: "cltd", 808 CMPSD: "cmpsl", 809 CMPSD_XMM: "cmpsd", 810 CWD: "cwtd", 811 CWDE: "cwtl", 812 CQO: "cqto", 813 INSD: "insl", 814 IRET: "iretw", 815 IRETD: "iret", 816 IRETQ: "iretq", 817 LODSB: "lods", 818 LODSD: "lods", 819 LODSQ: "lods", 820 LODSW: "lods", 821 MOVSD: "movsl", 822 MOVSD_XMM: "movsd", 823 OUTSD: "outsl", 824 POPA: "popaw", 825 POPAD: "popa", 826 POPF: "popfw", 827 POPFD: "popf", 828 PUSHA: "pushaw", 829 PUSHAD: "pusha", 830 PUSHF: "pushfw", 831 PUSHFD: "pushf", 832 SCASB: "scas", 833 SCASD: "scas", 834 SCASQ: "scas", 835 SCASW: "scas", 836 STOSB: "stos", 837 STOSD: "stos", 838 STOSQ: "stos", 839 STOSW: "stos", 840 XLATB: "xlat", 841 } 842 843 var cmppsOps = []string{ 844 "cmpeq", 845 "cmplt", 846 "cmple", 847 "cmpunord", 848 "cmpneq", 849 "cmpnlt", 850 "cmpnle", 851 "cmpord", 852 } 853 854 var pclmulqOps = []string{ 855 "pclmullqlqdq", 856 "pclmulhqlqdq", 857 "pclmullqhqdq", 858 "pclmulhqhqdq", 859 } 860 861 func countPrefix(inst *Inst, target Prefix) int { 862 n := 0 863 for _, p := range inst.Prefix { 864 if p&0xFF == target&0xFF { 865 n++ 866 } 867 } 868 return n 869 } 870 871 func markLastImplicit(inst *Inst, prefix Prefix) bool { 872 for i := len(inst.Prefix) - 1; i >= 0; i-- { 873 p := inst.Prefix[i] 874 if p&0xFF == prefix { 875 inst.Prefix[i] |= PrefixImplicit 876 return true 877 } 878 } 879 return false 880 } 881 882 func unmarkImplicit(inst *Inst, prefix Prefix) { 883 for i := len(inst.Prefix) - 1; i >= 0; i-- { 884 p := inst.Prefix[i] 885 if p&0xFF == prefix { 886 inst.Prefix[i] &^= PrefixImplicit 887 } 888 } 889 } 890 891 func byteSizeSuffix(b int) string { 892 switch b { 893 case 1: 894 return "b" 895 case 2: 896 return "w" 897 case 4: 898 return "l" 899 case 8: 900 return "q" 901 } 902 return "" 903 } 904 905 func argBytes(inst *Inst, arg Arg) int { 906 if isMem(arg) { 907 return inst.MemBytes 908 } 909 return regBytes(arg) 910 } 911 912 func isFloat(op Op) bool { 913 switch op { 914 case FADD, FCOM, FCOMP, FDIV, FDIVR, FIADD, FICOM, FICOMP, FIDIV, FIDIVR, FILD, FIMUL, FIST, FISTP, FISTTP, FISUB, FISUBR, FLD, FMUL, FST, FSTP, FSUB, FSUBR: 915 return true 916 } 917 return false 918 } 919 920 func isFloatInt(op Op) bool { 921 switch op { 922 case FIADD, FICOM, FICOMP, FIDIV, FIDIVR, FILD, FIMUL, FIST, FISTP, FISTTP, FISUB, FISUBR: 923 return true 924 } 925 return false 926 } 927