1 /********************************************************* 2 * X86 disassembler. Can disassemble 16, 32, and 64 bit code. Includes 3 * x87 FPU instructions and vector instructions. 4 * 5 * Copyright: Copyright (C) 1982-1998 by Symantec 6 * Copyright (C) 2000-2023 by The D Language Foundation, All Rights Reserved 7 * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) 8 * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) 9 */ 10 11 module dmd.backend.disasm86; 12 13 nothrow @nogc: 14 15 /***************************** 16 * Calculate and return the number of bytes in an instruction starting at code[c]. 17 * Params: 18 * code = machine code as array of bytes 19 * c = address of instruction (as index into code[]) 20 * pc = set to address of instruction after prefix 21 * model = memory model, 16/32/64 22 */ 23 24 public 25 addr calccodsize(ubyte[] code, addr c, out addr pc, uint model) 26 { 27 assert(model == 16 || model == 32 || model == 64); 28 Disasm disasm = Disasm(code, model); 29 return disasm.calccodsize(c, pc); 30 } 31 32 /************************ 33 * If instruction is a jump or a call, get information about 34 * where the offset is and what it is. 35 * Params: 36 * code = instruction bytes 37 * c = address of start of instruction, not including prefix. 38 * Use calccodsize() to determine start not including prefix. 39 * Updated to be address of the offset part of the instruction. 40 * Caller determines if it is relative to the start of the next 41 * instruction or not. 42 * offset = set to be address of jump target 43 * Returns: 44 * true if jump or call target 45 */ 46 @trusted 47 public 48 bool jmpTarget(ubyte[] code, ref addr c, out addr offset) 49 { 50 const op = code[c] & 0xFF; 51 if (inssize[op] & B) // byte jump 52 { 53 ++c; 54 offset = cast(byte) code[c]; 55 } 56 else if (inssize[op] & W) // word jump 57 { 58 ++c; 59 offset = cast(short)((code[c] & 0xFF) + (code[c + 1] << 8)); 60 } 61 else if (op == 0x0F && inssize2[code[c + 1]] & W) // word/dword jump 62 { 63 c += 2; 64 /* BUG: look only at 16 bits of offset */ 65 offset = cast(short)((code[c] & 0xFF) + (code[c + 1] << 8)); 66 } 67 else 68 return false; 69 return true; 70 } 71 72 /************************* 73 * Write to put() the disassembled instruction 74 * Params: 75 * put = function to write the output string to 76 * code = instruction bytes 77 * c = address (index into code[]) of start of instruction to disassemble 78 * siz = number of bytes in instruction (from calccodsize()) 79 * model = memory model, 16/32/64 80 * nearptr = use 'near ptr' when writing memory references 81 * bObjectcode = also prepend hex characters of object code 82 * mem = if not null, then function that returns a string 83 * representing the label for the memory address. Parameters are `c` 84 * for the address of the memory reference in `code[]`, `sz` for the 85 * number of bytes in the referred to memory location, and `offset` 86 * for the value to be added to any symbol referenced. 87 * immed16 = if not null, then function that returns a string 88 * representation of immediate value. 89 * Parameters are `code` is the binary instructions, 90 * `c` is the address of the memory reference in `code[]`, 91 * `sz` is the number of bytes in the instruction that form the referenece (2/4/8) 92 * labelcode = if not null, then function that returns a string 93 * representation of code label. 94 * Parameters are 95 * `c` is the address of the code reference to the label in `code[]`, 96 * `offset` is the address of the label in `code[]`, 97 * `farflag` is if `far` reference (seg:offset in 16 bit code), 98 * `is16bit` is if 16 bit reference 99 * shortlabel = if not null, then function that returns a string 100 * representing the label for the target. Parameters are `pc` 101 * for the program counter value, and `offset` for the offset 102 * of the label from the pc. 103 */ 104 @trusted 105 public 106 void getopstring(void delegate(char) nothrow @nogc put, ubyte[] code, uint c, addr siz, 107 uint model, int nearptr, ubyte bObjectcode, 108 const(char)*function(uint c, uint sz, uint offset) nothrow @nogc mem, 109 const(char)*function(ubyte[] code, uint c, int sz) nothrow @nogc immed16, 110 const(char)*function(uint c, uint offset, bool farflag, bool is16bit) nothrow @nogc labelcode, 111 const(char)*function(uint pc, int offset) nothrow @nogc shortlabel 112 ) 113 { 114 assert(model == 16 || model == 32 || model == 64); 115 auto disasm = Disasm(put, code, siz, 116 model, nearptr, bObjectcode, 117 mem, immed16, labelcode, shortlabel); 118 disasm.disassemble(c); 119 } 120 121 /************************************************************************************/ 122 private: 123 124 125 import core.stdc.stdio; 126 import core.stdc.string; 127 128 alias addr = uint; 129 alias addr64 = ulong; 130 131 enum BUFMAX = 2000; 132 133 /*********************************************** 134 * The disassembler 135 */ 136 137 struct Disasm 138 { 139 nothrow @nogc: 140 141 @trusted 142 this(void delegate(char) nothrow @nogc put, ubyte[] code, addr siz, 143 uint model, int nearptr, ubyte bObjectcode, 144 const(char)*function(uint c, uint sz, uint offset) nothrow @nogc mem, 145 const(char)*function(ubyte[] code, uint c, int sz) nothrow @nogc immed16, 146 const(char)*function(uint c, uint offset, bool farflag, bool is16bit) nothrow @nogc labelcode, 147 const(char)*function(uint pc, int offset) nothrow @nogc shortlabel 148 ) 149 { 150 this.put = put; 151 this.code = code; 152 this.siz = siz; 153 this.model = model; 154 this.nearptr = nearptr; 155 this.bObjectcode = bObjectcode; 156 157 /* Set null function pointers to default functions 158 */ 159 this.mem = mem ? mem : &memoryDefault; 160 this.immed16 = immed16 ? immed16 : &immed16Default; 161 this.labelcode = labelcode ? labelcode : &labelcodeDefault; 162 this.shortlabel = shortlabel ? shortlabel : &shortlabelDefault; 163 164 defopsize = model == 16; 165 defadsize = model == 32 || model == 64; 166 167 // Reset globals 168 opsize = defopsize; 169 adsize = defadsize; 170 fwait = 0; 171 segover = "".ptr; 172 } 173 174 /* Enough to get prefixbyte() working 175 */ 176 this(ubyte[] code, uint model) 177 { 178 this.code = code; 179 this.model = model; 180 defopsize = model == 16; 181 defadsize = model == 32 || model == 64; 182 opsize = defopsize; 183 adsize = defadsize; 184 fwait = 0; 185 segover = "".ptr; 186 } 187 188 ubyte[] code; // the code segment contents 189 void delegate(char) put; 190 addr siz; 191 int nearptr; 192 ubyte bObjectcode; 193 bool defopsize; // default value for opsize 194 char defadsize; // default value for adsize 195 bool opsize; // if 0, then 32 bit operand 196 char adsize; // if !=0, then 32 or 64 bit address 197 char fwait; // if !=0, then saw an FWAIT 198 uint model; // 16/32/64 199 const(char)* segover; // segment override string 200 201 // Callbacks provided by caller 202 const(char)*function(uint c, uint sz, addr offset) mem; 203 const(char)*function(ubyte[] code, uint c, int sz) immed16; 204 const(char)*function(uint c, uint offset, bool farflag, bool is16bit) labelcode; 205 const(char)*function(uint pc, int offset) shortlabel; 206 207 enum AX = 0; 208 209 enum REX = 0x40; // REX prefix byte, OR'd with the following bits: 210 enum REX_W = 8; // 0 = default operand size, 1 = 64 bit operand size 211 enum REX_R = 4; // high bit of reg field of modregrm 212 enum REX_X = 2; // high bit of sib index reg 213 enum REX_B = 1; // high bit of rm field, sib base reg, or opcode reg 214 215 const(char)* REGNAME(uint rex, uint reg) 216 { 217 return rex & REX_W ? rreg[reg] : (opsize ? wordreg[reg] : ereg[reg]); 218 } 219 220 const(char)* BREGNAME(uint rex, uint reg) 221 { 222 return rex ? byteregrex[reg] : bytereg[reg]; 223 } 224 225 /* Return !=0 if there is an SIB byte */ 226 bool issib(uint rm) @safe { return (rm & 7) == 4 && (rm & 0xC0) != 0xC0; } 227 228 229 addr calccodsize(addr c, out addr pc) 230 { 231 uint prefixsize = 0; 232 { 233 uint sz; 234 do 235 { 236 sz = prefixbyte(c); 237 c += sz; 238 prefixsize += sz; 239 } while (sz); 240 } 241 pc = c; // to skip over prefix 242 243 addr size; 244 uint op,rm,mod; 245 uint ins; 246 ubyte rex = 0; 247 248 op = code[c] & 0xFF; 249 250 // if VEX prefix 251 if (op == 0xC4 || op == 0xC5) 252 { 253 if (model == 64 || (code[c + 1] & 0xC0) == 0xC0) 254 { 255 if (op == 0xC4) // 3 byte VEX 256 { 257 switch (code[c + 1] & 0x1F) 258 { 259 case 1: // 0F 260 ins = inssize2[code[c + 3]] + 2; 261 break; 262 case 2: // 0F 38 263 ins = inssize2[0x38] + 1; 264 break; 265 case 3: // 0F 3A 266 ins = inssize2[0x3A] + 1; 267 break; 268 default: 269 printf("Invalid VEX at x%x\n", cast(int)c); 270 break; 271 } 272 c += 3; 273 } 274 else 275 { 276 ins = inssize2[code[c + 2]] + 1; 277 c += 2; 278 } 279 size = ins & 7; 280 goto Lmodrm; 281 } 282 } 283 284 if (model == 64) 285 { 286 if (op == 0xF3 || op == 0xF2) 287 { if ((code[c + 1] & 0xF0) == REX) 288 { 289 c++; 290 rex = code[c]; 291 } 292 } 293 else if ((op & 0xF0) == REX) 294 { rex = cast(ubyte)op; 295 c++; 296 op = code[c] & 0xFF; 297 } 298 } 299 if ((op == 0xF2 || op == 0xF3) && code[c + 1] == 0x0F) 300 { 301 addr dummy; 302 return prefixsize + (rex != 0) + 1 + calccodsize(c + 1, dummy); 303 } 304 ins = inssize[op]; 305 if (op == 0x0F) /* if 2 byte opcode */ 306 { c++; 307 ins = inssize2[code[c]]; 308 if (ins & W) /* long-disp conditional jump */ 309 return prefixsize + (opsize ? 4 : 6); 310 if (opsize != defopsize && (code[c] == 0x38 || code[c] == 0x3A)) 311 c++; 312 } 313 size = ins & 7; 314 if (opsize == true) 315 { } 316 else if (op != 0x0F) 317 size = inssize32[op]; 318 if (rex) 319 { size++; 320 if (rex & REX_W && (op & 0xF8) == 0xB8) 321 size += 4; 322 } 323 Lmodrm: 324 if (ins & M) /* if modregrm byte */ 325 { 326 rm = code[c+1] & 0xFF; 327 mod = rm & 0xC0; 328 if (adsize == 0 && model != 64) 329 { /* 16 bit addressing */ 330 if (mod == 0x40) /* 01: 8 bit displacement */ 331 size++; 332 else if (mod == 0x80 || (mod == 0 && (rm & 7) == 6)) 333 size +=2; 334 } 335 else 336 { /* 32 bit addressing */ 337 if (issib(rm)) 338 size++; 339 switch (mod) 340 { case 0: 341 if ((issib(rm) && (code[c+2] & 7) == 5) || (rm & 7) == 5) 342 size += 4; /* disp32 */ 343 break; 344 case 0x40: 345 size++; /* disp8 */ 346 break; 347 case 0x80: 348 size += 4; /* disp32 */ 349 break; 350 default: 351 break; 352 } 353 } 354 if (op == 0xF6) /* special case */ 355 { if ((rm & (7<<3)) == 0) 356 size++; 357 } 358 else if (op == 0xF7) 359 { if ((rm & (7<<3)) == 0) 360 size += opsize ? 2 : 4; 361 } 362 } 363 else if (ins & T && (op & 0xFC) == 0xA0) 364 { 365 size = adsize ? 5 : 3; 366 if (rex) 367 { size += 1; 368 if (op == 0xA1 || op == 0xA3) 369 size += 4; // 64 bit immediate value for MOV 370 } 371 } 372 //printf("op = x%02x, size = x%lx, opsize = %d\n",op,size,opsize); 373 return prefixsize + size; 374 } 375 376 /***************************** 377 * Load byte at code[c]. 378 */ 379 380 const(char)* immed8(uint c) @safe 381 { 382 return wordtostring(code[c]); 383 } 384 385 /***************************** 386 * Load byte at code[c], and sign-extend it 387 */ 388 389 const(char)* immeds(uint c) 390 { 391 return wordtostring(cast(byte) code[c]); 392 } 393 394 /************************* 395 * Return # of bytes that EA consumes. 396 */ 397 398 addr EAbytes(uint c) 399 { 400 addr a; 401 uint modrgrm,mod,rm; 402 403 a = 1; 404 modrgrm = code[c + 1]; 405 mod = modrgrm >> 6; 406 rm = modrgrm & 7; 407 if (adsize == 0) /* if 16 bit addressing */ 408 { 409 switch (mod) 410 { case 0: 411 if (rm == 6) 412 a += 2; 413 break; 414 case 1: 415 a += 1; 416 break; 417 case 2: 418 a += 2; 419 break; 420 case 3: 421 break; 422 default: 423 break; 424 } 425 } 426 else 427 { 428 if (issib(modrgrm)) 429 { ubyte sib; 430 431 a += 1; 432 sib = code[c + 2]; 433 switch (mod) 434 { 435 case 0: 436 if ((sib & 7) == 5) 437 a += 4; 438 break; 439 case 1: 440 a += 1; 441 break; 442 case 2: 443 a += 4; 444 break; 445 default: 446 break; 447 } 448 } 449 else 450 { 451 switch (mod) 452 { case 0: 453 if (rm == 5) 454 a += 4; 455 break; 456 case 1: 457 a += 1; 458 break; 459 case 2: 460 a += 4; 461 break; 462 case 3: 463 break; 464 default: 465 break; 466 } 467 } 468 } 469 return a; 470 } 471 472 473 /************************* 474 * Params: 475 * vlen = 128: XMM, 256: YMM 476 */ 477 478 479 char *getEAxmm(ubyte rex, uint c) 480 { 481 return getEAimpl(rex, c, 1, 128); 482 } 483 484 char *getEAxmmymm(ubyte rex, uint c, uint vlen) 485 { 486 return getEAimpl(rex, c, 2, vlen); 487 } 488 489 const(char)* getEAvec(ubyte rex, uint c) 490 { 491 const(char)* p; 492 if ((code[c + 1] & 0xC0) == 0xC0) 493 { 494 uint rm = code[c + 1] & 7; 495 if (rex & REX_B) 496 rm |= 8; 497 p = rex & REX_W ? rreg[rm] : ereg[rm]; 498 } 499 else 500 p = getEA(rex, c); 501 return p; 502 } 503 504 char *getEA(ubyte rex, uint c) 505 { 506 return getEAimpl(rex, c, 0, 128); 507 } 508 509 /************************* 510 * Params: 511 * vlen = 128: XMM, 256: YMM 512 */ 513 char *getEAimpl(ubyte rex, uint c, int do_xmm, uint vlen) 514 { 515 ubyte modrgrm,mod,reg,rm; 516 uint opcode; 517 const(char)* p; 518 char[BUFMAX] EA = void; 519 520 __gshared char[BUFMAX] EAb; 521 __gshared const char*[6] ptr = ["","byte ptr ","word ptr ","dword ptr ", 522 "fword ptr ", "qword ptr " ]; 523 int ptri; 524 uint mm; // != 0 if mmx opcode 525 uint xmm; // != 0 if xmm opcode 526 uint r32; // != 0 if r32 527 528 char *displacement(addr w, const(char)* postfix) 529 { 530 const(char)* s = "".ptr; 531 if (cast(short) w < 0) 532 { 533 w = -w; 534 s = "-".ptr; 535 } 536 w &= 0xFFFF; 537 snprintf(EAb.ptr, EAb.length, ((w < 10) ? "%s%s%s%ld%s" : "%s%s%s0%lXh%s"), 538 segover,ptr[ptri],s,w,postfix); 539 540 segover = "".ptr; 541 assert(strlen(EAb.ptr) < EAb.length); 542 return EAb.ptr; 543 } 544 545 char *displacementFixup(addr c, uint sz, const(char)* postfix) 546 { 547 uint value = sz == 2 ? word(code, c) : dword(code, c); 548 auto p = mem(c, sz, value); 549 if (*p == '[') // if just `[number]` 550 return displacement(value, postfix); // don't use brackets 551 snprintf(EAb.ptr, EAb.length, "%s%s%s%s",ptr[ptri],segover,p,postfix); 552 return EAb.ptr; 553 } 554 555 mm = 0; 556 xmm = (do_xmm == 2); 557 r32 = 0; 558 EA[0] = 0; 559 EAb[0] = 0; 560 opcode = code[c]; 561 if (opcode == 0x0F && do_xmm != 2) /* if 2 byte opcode */ 562 { c++; 563 opcode = 0x0F00 + code[c]; 564 //printf("opcode = %x\n", opcode); 565 if (opcode == 0x0F2A) 566 r32 = 1; 567 if (do_xmm || inssize2[code[c]] & (Y & ~M)) 568 xmm = 1; 569 else if (inssize2[code[c]] & (X & ~M)) 570 mm = 1; 571 if (opsize != defopsize && (opcode == 0x0F38 || opcode == 0x0F3A)) 572 c++; 573 } 574 modrgrm = code[c + 1]; 575 switch (opcode) 576 { 577 case 0xFF: 578 reg = (modrgrm >> 3) & 7; 579 if (reg == 3 || reg == 5) /* CALLF or JMPF */ 580 { ptri = opsize ? 3 : 4; 581 break; 582 } 583 goto case; 584 585 case 0x81: 586 case 0x83: 587 case 0xC7: 588 case 0xD1: 589 case 0xD3: 590 case 0xF7: 591 ptri = opsize ? 2 : 3; 592 if (rex & REX_W) 593 ptri = 5; // qword ptr 594 break; 595 case 0x80: 596 case 0xC6: 597 case 0xD0: 598 case 0xD2: 599 case 0xF6: 600 case 0xFE: 601 ptri = 1; 602 break; 603 case 0x0FB6: 604 case 0x0FBE: 605 ptri = 1; 606 break; 607 case 0x0FB7: 608 case 0x0FBF: 609 ptri = 2; 610 break; 611 default: 612 ptri = 0; 613 if (opcode >= 0x0F90 && opcode <= 0x0F9F) 614 ptri = 1; 615 break; 616 } 617 if (do_xmm == 2) 618 ptri = 0; 619 620 mod = modrgrm >> 6; 621 rm = modrgrm & 7; 622 if (adsize == 0 && model != 64) // if 16 bit addressing 623 { 624 __gshared const char*[8] rmstr = 625 [ "[BX+SI]","[BX+DI]","[BP+SI]","[BP+DI]","[SI]","[DI]","[BP]","[BX]" ]; 626 627 switch (mod) 628 { case 0: 629 if (rm == 6) 630 { 631 strcpy(EA.ptr, ptr[ptri]); 632 strcat(EA.ptr, segover); 633 strcat(EA.ptr, mem(c + 2, 2, word(code, c + 2))); 634 p = EA.ptr; 635 break; 636 } 637 p = rmstr[rm]; 638 break; 639 case 1: 640 return displacement(cast(byte) code[c + 2], rmstr[rm]); 641 case 2: 642 return displacementFixup(c + 2, 2, rmstr[rm]); 643 644 case 3: 645 switch (opcode) { 646 case 0x8c: 647 case 0x8e: 648 p = wordreg[rm]; 649 break; 650 case 0x0F6E: 651 case 0x0F7E: 652 p = mm ? mmreg[rm] : ereg[rm]; 653 break; 654 case 0x0FAC: 655 case 0x0FA4: 656 opcode |= 1; 657 goto default; 658 default: 659 p = (opcode & 1 || r32) ? ereg[rm] + opsize : bytereg[rm]; 660 if (mm) 661 p = mmreg[rm]; 662 else if (xmm) 663 p = vlen == 128 ? xmmreg[rm] : ymmreg[rm]; 664 break; 665 } 666 break; 667 default: 668 assert(0); 669 } 670 } 671 else /* 32 bit addressing */ 672 { ubyte sib; 673 char[5 + 5 + 2 + 1] rbuf; 674 675 const(char*)* preg = &ereg[0]; // 32 bit address size 676 if (model == 64 && adsize) 677 preg = rreg.ptr; // 64 bit address size 678 679 if (issib(modrgrm)) 680 { /* [ EAX *2 ][ EAX ] */ 681 char[1 +4 +2 +2 +4 +1 +1] base; 682 __gshared const char[3][4] scale = [ "","*2","*4","*8" ]; 683 684 sib = code[c + 2]; 685 686 uint sib_index = (sib >> 3) & 7; 687 if (rex & REX_X) 688 sib_index |= 8; 689 690 uint sib_base = (sib & 7); 691 if (rex & REX_B) 692 sib_base |= 8; 693 694 if (sib_index == 4) // REX_X is not ignored 695 snprintf(base.ptr,base.length,"[%s]",preg[sib_base]); 696 else 697 snprintf(base.ptr,base.length,"[%s%s][%s]", 698 preg[sib_index], scale[sib >> 6].ptr, preg[sib_base]); 699 strcpy(rbuf.ptr, base.ptr); 700 switch (mod) 701 { case 0: 702 if ((sib_base & 7) == 5) 703 { 704 p = mem(c + 3, 4, dword(code, c + 3)); 705 if (sib_index == 4) 706 snprintf(EAb.ptr,EAb.length,"%s%s%s",ptr[ptri],segover,p); 707 else 708 snprintf(EAb.ptr,EAb.length,"%s%s%s[%s%s]",ptr[ptri],segover,p, 709 preg[sib_index], scale[sib >> 6].ptr); 710 return EAb.ptr; 711 } 712 p = rbuf.ptr; // no displacement 713 break; 714 case 1: 715 return displacement(cast(byte)code[c + 3], rbuf.ptr); 716 case 2: 717 return displacementFixup(c + 3, 4, rbuf.ptr); 718 default: 719 assert(0); 720 } 721 } 722 else 723 { 724 snprintf(rbuf.ptr,rbuf.length,"[%s]", preg[(rex & REX_B) ? 8|rm : rm]); 725 switch (mod) 726 { case 0: 727 if (rm == 5) // ignore REX_B 728 { 729 p = mem(c + 2, 4, dword(code, c + 2)); 730 if (model == 64) 731 snprintf(EAb.ptr,EAb.length,"%s%s%s[RIP]",ptr[ptri],segover,p); 732 else 733 snprintf(EAb.ptr,EAb.length,"%s%s%s",ptr[ptri],segover,p); 734 return EAb.ptr; 735 } 736 else 737 { p = rbuf.ptr; 738 snprintf(EA.ptr,EA.length,"%s%s",ptr[ptri],p); 739 } 740 p = EA.ptr; 741 break; 742 case 1: 743 return displacement(cast(byte)code[c + 2], rbuf.ptr); 744 case 2: 745 return displacementFixup(c + 2, 4, rbuf.ptr); 746 case 3: 747 if (rex & REX_B) 748 rm |= 8; 749 switch (opcode) 750 { case 0x8C: 751 case 0x8E: 752 case 0x0FB7: /* MOVZX */ 753 case 0x0FBF: /* MOVSX */ 754 p = wordreg[rm]; 755 break; 756 case 0x0FA4: /* SHLD */ 757 case 0x0FA5: /* SHLD */ 758 case 0x0FAC: /* SHRD */ 759 case 0x0FAD: /* SHRD */ 760 p = ereg[rm] + opsize; 761 if (rex & REX_W) 762 p = rreg[rm]; 763 break; 764 case 0x0F6E: 765 case 0x0F7E: 766 case 0x0FC5: 767 case 0x0FC4: 768 if (mm) 769 p = mmreg[rm]; 770 else if (xmm) 771 p = vlen == 128 ? xmmreg[rm] : ymmreg[rm]; 772 else if (rex & REX_W) 773 p = rreg[rm]; 774 else 775 p = ereg[rm]; 776 break; 777 default: 778 if (opcode >= 0x0F90 && opcode <= 0x0F9F) 779 p = rex ? byteregrex[rm] : bytereg[rm]; 780 else if (mm) 781 p = mmreg[rm]; 782 else if (xmm) 783 p = vlen == 128 ? xmmreg[rm] : ymmreg[rm]; 784 else 785 { 786 if (opcode & 1 || r32) 787 { 788 p = ereg[rm] + opsize; 789 if (opsize && rm >= 8) 790 p = wordreg[rm]; 791 } 792 else 793 p = (rex ? byteregrex[rm] : bytereg[rm]); 794 if (rex & REX_W) 795 p = (opcode & 1 || r32) ? rreg[rm] : byteregrex[rm]; 796 } 797 break; 798 } 799 break; 800 default: 801 assert(0); 802 } 803 } 804 } 805 snprintf(EAb.ptr,EAb.length,"%s%s",segover,p); 806 segover = "".ptr; 807 assert(strlen(EA.ptr) < EA.length); 808 assert(strlen(EAb.ptr) < EAb.length); 809 return EAb.ptr; 810 } 811 812 813 /******************************** 814 * Determine if the byte at code[c] is a prefix instruction. 815 * Params: 816 * put = if not null, store hex code here 817 * Returns: 818 * number of prefix bytes 819 */ 820 int prefixbyte(uint c) 821 { 822 void printHex(uint prefix) 823 { 824 if (bObjectcode) 825 { 826 char[3 + 1] tmp; 827 snprintf(tmp.ptr, tmp.length, "%02X ", prefix); 828 puts(tmp.ptr); 829 } 830 } 831 832 if (c + 1 < code.length) 833 { 834 const prefix = code[c]; // this may be a prefix byte 835 836 /* If segment override */ 837 char s; 838 switch (prefix) 839 { 840 case 0x26: s = 'E'; goto L1; // ES 841 case 0x2E: s = 'C'; goto L1; // CS 842 case 0x36: s = 'S'; goto L1; // SS 843 case 0x3E: s = 'D'; goto L1; // DS 844 case 0x64: s = 'F'; goto L1; // FS 845 case 0x65: s = 'G'; goto L1; // GS 846 L1: 847 { 848 /* prefix is only a prefix if it is followed by the right opcode 849 */ 850 ubyte op = code[c + 1]; 851 if (model == 64 && (op & 0xF0) == REX) 852 { 853 if (c + 2 >= code.length) 854 return 0; // a label splits REX off from its instruction 855 // skip over REX to get the opcode 856 op = code[c + 2]; 857 } 858 if (inssize[op] & M || (op >= 0xA0 && op <= 0xA3)) 859 { 860 __gshared char[4] buf; 861 buf[0] = s; 862 buf[1] = 'S'; 863 buf[2] = ':'; 864 buf[3] = 0; 865 segover = &buf[0]; 866 printHex(prefix); 867 return 1; 868 } 869 break; 870 } 871 872 case 0x66: // operand size 873 opsize ^= true; 874 printHex(prefix); 875 return 1; 876 877 case 0x67: // address size 878 adsize ^= 1; 879 printHex(prefix); 880 return 1; 881 882 case 0x9B: // FWAIT 883 if (0 && code[c + 1] >= 0xD8 && code[c + 1] <= 0xDF) 884 { 885 fwait = 1; 886 printHex(prefix); 887 printHex(code[c + 1]); 888 return 2; 889 } 890 break; 891 892 default: 893 break; 894 } 895 } 896 return 0; 897 } 898 899 /********************************** 900 * Decode VEX instructions. 901 * Store in buffer the 'stringized' instruction indexed by c. 902 * Params: 903 * put = where to store output 904 * c = index into code[] of the first VEX prefix byte 905 * siz = number of bytes in instruction 906 * p0 = hex bytes dump 907 */ 908 909 void getVEXstring(addr c, addr siz, char *p0) 910 { 911 /* Parse VEX prefix, 912 * fill in the following variables, 913 * and point c at opcode byte 914 */ 915 ubyte rex = REX; 916 ubyte vreg; 917 uint vlen; 918 uint m_mmmm; // leading opcode byte 919 ubyte opext; // opcode extension 920 { 921 __gshared const ubyte[4] opexts = [ 0, 0x66, 0xF3, 0xF2 ]; 922 ubyte v1 = code[c + 1]; 923 if (!(v1 & 0x80)) 924 rex |= REX_R; 925 if (code[c] == 0xC5) 926 { 927 vreg = ~(v1 >> 3) & 0xF; 928 vlen = v1 & 4 ? 256 : 128; 929 opext = opexts[v1 & 3]; 930 m_mmmm = 0x0F; 931 c += 2; 932 } 933 else // 0xC4 934 { 935 if (!(v1 & 0x40)) 936 rex |= REX_X; 937 if (!(v1 & 0x20)) 938 rex |= REX_B; 939 switch (v1 & 0x1F) 940 { 941 case 1: m_mmmm = 0x0F; break; 942 case 2: m_mmmm = 0x0F38; break; 943 case 3: m_mmmm = 0x0F3A; break; 944 default: m_mmmm = 0; break; 945 } 946 ubyte v2 = code[c + 2]; 947 if (v2 & 0x80) 948 rex |= REX_W; 949 vreg = ~(v2 >> 3) & 0xF; 950 vlen = v2 & 4 ? 256 : 128; 951 opext = opexts[v2 & 3]; 952 c += 3; 953 } 954 } 955 956 uint opcode,reg; 957 char[5] p1buf; 958 snprintf(p1buf.ptr,p1buf.length,"0x%02x",code[c]); 959 const(char)* p1 = p1buf.ptr; 960 const(char)* p2 = "".ptr; 961 const(char)* p3 = "".ptr; 962 const(char)* p4 = "".ptr; 963 const(char)* p5 = "".ptr; 964 965 opcode = code[c]; 966 967 reg = 13; 968 if (inssize2[opcode] & M) // if modregrm byte 969 { reg = (code[c + 1] >> 3) & 7; 970 if (rex & REX_R) 971 reg |= 8; 972 } 973 974 if (m_mmmm == 0x0F && opext == 0) 975 { 976 977 switch (opcode) 978 { 979 case 0x10: p1 = "vmovups"; goto Lxmm_eax; 980 case 0x11: p1 = "vmovups"; goto Leax_xmm; 981 case 0x12: p1 = ((code[c + 1] & 0xC0) == 0xC0) ? "vmovhlps" : "vmovlps"; goto L3op; 982 case 0x13: p1 = "vmovlps"; goto Leax_xmm; 983 case 0x14: p1 = "vunpcklps"; goto L3op; 984 case 0x15: p1 = "vunpckhps"; goto L3op; 985 case 0x16: p1 = ((code[c + 1] & 0xC0) == 0xC0) ? "vmovlhps" : "vmovhps"; goto L3op; 986 case 0x17: p1 = "vmovhps"; goto Leax_xmm; 987 case 0x28: p1 = "vmovaps"; goto Lxmm_eax; 988 case 0x29: p1 = "vmovaps"; goto Leax_xmm; 989 case 0x2B: p1 = "vmovntps"; goto Leax_xmm; 990 case 0x2E: p1 = "vucomiss"; goto Lxmm_eax; 991 case 0x2F: p1 = "vcomiss"; goto Lxmm_eax; 992 case 0x50: p1 = "vmovmskps"; goto Lrxmm; 993 case 0x51: p1 = "vsqrtp2"; goto Lxmm_eax; 994 case 0x53: p1 = "vrcpps"; goto Lxmm_eax; 995 case 0x54: p1 = "vandps"; goto L3op; 996 case 0x55: p1 = "vandnps"; goto L3op; 997 case 0x56: p1 = "vorps"; goto L3op; 998 case 0x57: p1 = "vxorps"; goto L3op; 999 case 0x58: p1 = "vaddps"; goto L3op; 1000 case 0x5A: p1 = "vcvtps2pd"; goto Lymmea; 1001 case 0x5B: p1 = "vcvtdq2ps"; goto Lxmm_eax; 1002 case 0x5C: p1 = "vsubps"; goto L3op; 1003 case 0x5D: p1 = "vminps"; goto L3op; 1004 case 0x5F: p1 = "vmaxps"; goto L3op; 1005 case 0x77: p1 = vlen == 128 ? "vzeroupper" : "vzeroall"; goto Ldone; 1006 case 0xC2: p1 = "vcmpps"; goto L4op; 1007 case 0xC6: p1 = "vshufps"; goto L4op; 1008 case 0xAE: 1009 if ((code[c + 1] & 0xC0) != 0xC0) 1010 { 1011 __gshared const char[9][8] grp15 = 1012 [ "v00","v01","vldmxcsr","vstmxcsr","v04","v05","v06","v07" ]; 1013 p1 = grp15[reg].ptr; 1014 p2 = getEA(rex, c); 1015 goto Ldone; 1016 } 1017 goto Ldone; 1018 1019 default: 1020 printf("0F 00: %02x\n", opcode); 1021 break; 1022 } 1023 } 1024 else if (m_mmmm == 0x0F && opext == 0x66) 1025 { 1026 1027 switch (opcode) 1028 { 1029 case 0x10: p1 = "vmovupd"; goto Lxmm_eax; 1030 case 0x11: p1 = "vmovupd"; goto Leax_xmm; 1031 case 0x14: p1 = "vunpcklpd"; goto L3op; 1032 case 0x15: p1 = "vunpckhpd"; goto L3op; 1033 case 0x16: p1 = "vmovhpd"; goto L3op; 1034 case 0x17: p1 = "vmovhpd"; goto Leax_xmm; 1035 case 0x28: p1 = "vmovapd"; goto Lxmm_eax; 1036 case 0x29: p1 = "vmovapd"; goto Leax_xmm; 1037 case 0x2B: p1 = "vmovntpd"; goto Leax_xmm; 1038 case 0x2E: p1 = "vucomisd"; goto Lxmm_eax; 1039 case 0x2F: p1 = "vcomisd"; goto Lxmm_eax; 1040 case 0x50: p1 = "vmovmskpd"; goto Lrxmm; 1041 case 0x51: p1 = "vsqrtpd"; goto Lxmm_eax; 1042 case 0x54: p1 = "vandpd"; goto L3op; 1043 case 0x55: p1 = "vandnpd"; goto L3op; 1044 case 0x56: p1 = "vorpd"; goto L3op; 1045 case 0x57: p1 = "vxorpd"; goto L3op; 1046 case 0x58: p1 = "vaddpd"; goto L3op; 1047 case 0x5A: p1 = "vcvtpd2ps"; goto L_xmmea; 1048 case 0x5B: p1 = "vcvtps2dq"; goto Lxmm_eax; 1049 case 0x5C: p1 = "vsubpd"; goto L3op; 1050 case 0x5D: p1 = "vminpd"; goto L3op; 1051 case 0x5F: p1 = "vmaxpd"; goto L3op; 1052 case 0x60: p1 = "vunpcklbw"; goto L3op; 1053 case 0x61: p1 = "vunpcklwd"; goto L3op; 1054 case 0x62: p1 = "vunpckldq"; goto L3op; 1055 case 0x63: p1 = "vpacksswb"; goto L3op; 1056 case 0x64: p1 = "vpcmpgtb"; goto L3op; 1057 case 0x65: p1 = "vpcmpgtw"; goto L3op; 1058 case 0x66: p1 = "vpcmpgtd"; goto L3op; 1059 case 0x67: p1 = "vpackuswb"; goto L3op; 1060 case 0x68: p1 = "vunpckhbw"; goto L3op; 1061 case 0x69: p1 = "vunpckhwd"; goto L3op; 1062 case 0x6A: p1 = "vunpckhdq"; goto L3op; 1063 case 0x6B: p1 = "vpackssdw"; goto L3op; 1064 case 0x6C: p1 = "vunpcklqdq"; goto L3op; 1065 case 0x6D: p1 = "vunpckhqdq"; goto L3op; 1066 case 0x6E: p1 = rex & REX_W ? "vmovq" : "vmovd"; goto Lxmm_ea; 1067 case 0x6F: p1 = "vmovdqa"; goto Lxmm_eax; 1068 case 0x70: p1 = "vpshufd"; goto Lymmxeaimm; 1069 case 0x71: 1070 { __gshared const char*[8] reg71 = 1071 [ null, null, "vpsrlw", null, "vpsraw", null, "vpslw", null ]; 1072 const char *p = reg71[reg]; 1073 if (!p) 1074 goto Ldefault; 1075 p1 = p; 1076 goto Leax_xmm_imm; 1077 } 1078 case 0x72: 1079 { __gshared const char*[8] reg72 = 1080 [ null, null, "vpsrld", null, "vpsrad", null, "vpslld", null ]; 1081 const char *p = reg72[reg]; 1082 if (!p) 1083 goto Ldefault; 1084 p1 = p; 1085 goto Leax_xmm_imm; 1086 } 1087 case 0x73: 1088 { __gshared const char*[8] reg73 = 1089 [ null, null, "vpsrlq", "vpsrldq", null, null, "vpsllq", "vpslldq" ]; 1090 const char *p = reg73[reg]; 1091 if (!p) 1092 goto Ldefault; 1093 p1 = p; 1094 goto Leax_xmm_imm; 1095 } 1096 case 0x74: p1 = "vpcmpeqb"; goto L3op; 1097 case 0x75: p1 = "vpcmpeqw"; goto L3op; 1098 case 0x76: p1 = "vpcmpeqd"; goto L3op; 1099 case 0x7C: p1 = "vhaddpd"; goto L3op; 1100 case 0x7E: p1 = rex & REX_W ? "vmovq" : "vmovd"; goto Lea_xmm; 1101 case 0x7F: p1 = "vmovdqa"; goto Leax_xmm; 1102 case 0xC2: p1 = "vcmppd"; goto L4op; 1103 case 0xC4: p1 = "vpinsrw"; goto Lymm_ymm_ea_imm; 1104 case 0xC5: p1 = "vpextrw"; goto Lea_xmm_imm; 1105 case 0xC6: p1 = "vshufpd"; goto L4op; 1106 case 0xD0: p1 = "vaddsubpd"; goto L3op; 1107 case 0xD1: p1 = "vpsrlw"; goto L3op; 1108 case 0xD2: p1 = "vpsrld"; goto L3op; 1109 case 0xD3: p1 = "vpsrlq"; goto L3op; 1110 case 0xD4: p1 = "vpaddq"; goto L3op; 1111 case 0xD5: p1 = "vpmulld"; goto L3op; 1112 case 0xD7: p1 = "vpmovmskb"; goto Lrxmm; 1113 case 0xD8: p1 = "vpsubusb"; goto L3op; 1114 case 0xD9: p1 = "vpsubusw"; goto L3op; 1115 case 0xDA: p1 = "vpminub"; goto L3op; 1116 case 0xDB: p1 = "vpand"; goto L3op; 1117 case 0xDC: p1 = "vpaddusb"; goto L3op; 1118 case 0xDD: p1 = "vpaddusw"; goto L3op; 1119 case 0xDE: p1 = "vpmaxub"; goto L3op; 1120 case 0xDF: p1 = "vpandn"; goto L3op; 1121 case 0xE0: p1 = "vpavgb"; goto L3op; 1122 case 0xE1: p1 = "vpsraw"; goto L3op; 1123 case 0xE2: p1 = "vpsrad"; goto L3op; 1124 case 0xE3: p1 = "vpavgw"; goto L3op; 1125 case 0xE4: p1 = "vpmulhuw"; goto L3op; 1126 case 0xE5: p1 = "vpmulhw"; goto L3op; 1127 case 0xE6: p1 = "vcvttpd2dq"; goto L_xmmea; 1128 case 0x12: p1 = "vmovlpd"; goto L3op; 1129 case 0x13: p1 = "vmovlpd"; goto Leax_xmm; 1130 case 0xE7: p1 = "vmovntdq"; goto Leax_xmm; 1131 case 0xE8: p1 = "vpsubsb"; goto L3op; 1132 case 0xE9: p1 = "vpsubsw"; goto L3op; 1133 case 0xEA: p1 = "vpminsw"; goto L3op; 1134 case 0xEB: p1 = "vpor"; goto L3op; 1135 case 0xEC: p1 = "vpaddsb"; goto L3op; 1136 case 0xED: p1 = "vpaddsw"; goto L3op; 1137 case 0xEE: p1 = "vpmaxsw"; goto L3op; 1138 case 0xEF: p1 = "vpxor"; goto L3op; 1139 case 0xF1: p1 = "vpsllw"; goto L3op; 1140 case 0xF2: p1 = "vpslld"; goto L3op; 1141 case 0xF3: p1 = "vpsllq"; goto L3op; 1142 case 0xF4: p1 = "vpmuludq"; goto L3op; 1143 case 0xF5: p1 = "vpmaddwd"; goto L3op; 1144 case 0xF6: p1 = "vpsadbw"; goto L3op; 1145 case 0xF7: p1 = "vmaskmovdqu"; goto Lxmm_eax; 1146 case 0xF8: p1 = "vpsubb"; goto L3op; 1147 case 0xF9: p1 = "vpsubw"; goto L3op; 1148 case 0xFA: p1 = "vpsubd"; goto L3op; 1149 case 0xFB: p1 = "vpsubq"; goto L3op; 1150 case 0xFC: p1 = "vpaddb"; goto L3op; 1151 case 0xFD: p1 = "vpaddw"; goto L3op; 1152 case 0xFE: p1 = "vpaddd"; goto L3op; 1153 1154 default: 1155 Ldefault: 1156 printf("0F 66: %02x\n", opcode); 1157 break; 1158 } 1159 } 1160 else if (m_mmmm == 0x0F && opext == 0xF2) 1161 { 1162 1163 switch (opcode) 1164 { 1165 case 0x10: p1 = "vmovsd"; goto L3op; 1166 case 0x11: p1 = "vmovsd"; goto Leax_xmm; 1167 case 0x12: p1 = "vmovddup"; goto Lxmm_eax; 1168 case 0x2A: p1 = "vcvtsi2sd"; goto Lxmmxmmea; 1169 case 0x2C: p1 = "vcvttsd2si"; goto Lregeax; 1170 case 0x2D: p1 = "vcvtsd2si"; goto Lregeax; 1171 case 0x51: p1 = "vsqrtsd"; goto L3op; 1172 case 0x58: p1 = "vaddsd"; goto L3op; 1173 case 0x5A: p1 = "vcvtsd2ss"; goto L3op; 1174 case 0x5C: p1 = "vsubsd"; goto L3op; 1175 case 0x5D: p1 = "vminsd"; goto L3op; 1176 case 0x5F: p1 = "vmaxsd"; goto L3op; 1177 case 0x7C: p1 = "vhaddps"; goto L3op; 1178 case 0xC2: p1 = "vcmpsd"; goto L4op; 1179 case 0xD0: p1 = "vaddsubps"; goto L3op; 1180 case 0xE6: p1 = "vcvtpd2dq"; goto L_xmmea; 1181 case 0xF0: p1 = "vlddqu"; goto Lxmm_eax; 1182 case 0x70: p1 = "vpshuflw"; goto Lymmxeaimm; 1183 1184 default: 1185 printf("0F F2: %02x\n", opcode); 1186 break; 1187 } 1188 } 1189 else if (m_mmmm == 0x0F && opext == 0xF3) 1190 { 1191 switch (opcode) 1192 { 1193 case 0x10: p1 = "vmovss"; goto L3op; 1194 case 0x11: p1 = "vmovss"; goto Leax_xmm; 1195 case 0x12: p1 = "vmovsldup"; goto Lxmm_eax; 1196 case 0x16: p1 = "vmovshdup"; goto Lxmm_eax; 1197 case 0x2A: p1 = "vcvtsi2ss"; goto Lxmmxmmea; 1198 case 0x2C: p1 = "vcvttss2si"; goto Lregeax; 1199 case 0x2D: p1 = "vcvtss2si"; goto Lregeax; 1200 case 0x51: p1 = "vsqrtss"; goto L3op; 1201 case 0x53: p1 = "vrcpss"; goto L3op; 1202 case 0x58: p1 = "vaddss"; goto L3op; 1203 case 0x5B: p1 = "vcvttps2dq"; goto Lxmm_eax; 1204 case 0x5C: p1 = "vsubss"; goto L3op; 1205 case 0x5D: p1 = "vminss"; goto L3op; 1206 case 0x5F: p1 = "vmaxss"; goto L3op; 1207 case 0x6F: p1 = "vmovdqu"; goto Lxmm_eax; 1208 case 0x7F: p1 = "vmovdqu"; goto Leax_xmm; 1209 case 0xC2: p1 = "vcmpss"; goto L4op; 1210 case 0xE6: p1 = "vcvtdq2pd"; goto Lymmea; 1211 case 0x70: p1 = "vpshufhw"; goto Lymmxeaimm; 1212 default: 1213 printf("0F F3: %02x\n", opcode); 1214 break; 1215 } 1216 } 1217 else if (m_mmmm == 0x0F38 && opext == 0x66) 1218 { 1219 1220 switch (opcode) 1221 { 1222 case 0x00: p1 = "vpshufb"; goto L3op; 1223 case 0x01: p1 = "vphaddw"; goto L3op; 1224 case 0x02: p1 = "vphaddd"; goto L3op; 1225 case 0x03: p1 = "vphaddsw"; goto L3op; 1226 case 0x04: p1 = "vpmaddubsw"; goto L3op; 1227 case 0x05: p1 = "vphsubw"; goto L3op; 1228 case 0x06: p1 = "vphsubd"; goto L3op; 1229 case 0x07: p1 = "vphsubsw"; goto L3op; 1230 case 0x08: p1 = "vpsignb"; goto L3op; 1231 case 0x09: p1 = "vpsignw"; goto L3op; 1232 case 0x0A: p1 = "vpsignd"; goto L3op; 1233 case 0x0B: p1 = "vpmulhrsw"; goto L3op; 1234 case 0x0C: p1 = "vpermilps"; goto L3op; 1235 case 0x0D: p1 = "vpermilpd"; goto L3op; 1236 case 0x13: p1 = "vcvtph2ps"; goto Lxmm_eax; 1237 case 0x17: p1 = "vptest"; goto L3op; 1238 case 0x18: p1 = "vbroadcastss"; goto Lymmea; 1239 case 0x19: p1 = "vbroadcastsd"; goto Lymmea; 1240 case 0x1A: p1 = "vbroadcastf128"; goto Lymmea; 1241 case 0x1C: p1 = "vpabsb"; goto Lxmm_eax; 1242 case 0x1D: p1 = "vpabsw"; goto Lxmm_eax; 1243 case 0x1E: p1 = "vpabsd"; goto Lxmm_eax; 1244 case 0x20: p1 = "vpmovsxbw"; goto Lxmm_eax; 1245 case 0x21: p1 = "vpmovsxbd"; goto Lxmm_eax; 1246 case 0x22: p1 = "vpmovsxbq"; goto Lxmm_eax; 1247 case 0x23: p1 = "vpmovsxwd"; goto Lxmm_eax; 1248 case 0x24: p1 = "vpmovsxwq"; goto Lxmm_eax; 1249 case 0x25: p1 = "vpmovsxdq"; goto Lxmm_eax; 1250 case 0x28: p1 = "vpmuldq"; goto L3op; 1251 case 0x29: p1 = "vpcmpeqq"; goto L3op; 1252 case 0x2A: p1 = "vmovntdqa"; goto Lxmm_eax; 1253 case 0x2C: p1 = "vmaskmovps"; goto L3op; 1254 case 0x2B: p1 = "vpackusdw"; goto L3op; 1255 case 0x2D: p1 = "vmaskmovpd"; goto L3op; 1256 case 0x2E: p1 = "vmaskmovps"; goto L3opr; 1257 case 0x2F: p1 = "vmaskmovpd"; goto L3opr; 1258 case 0x30: p1 = "vpmovzxbw"; goto Lxmm_eax; 1259 case 0x31: p1 = "vpmovzxbd"; goto Lxmm_eax; 1260 case 0x32: p1 = "vpmovzxbq"; goto Lxmm_eax; 1261 case 0x33: p1 = "vpmovzxwd"; goto Lxmm_eax; 1262 case 0x34: p1 = "vpmovzxwq"; goto Lxmm_eax; 1263 case 0x35: p1 = "vpmovzxdq"; goto Lxmm_eax; 1264 case 0x37: p1 = "vpcmpgtq"; goto L3op; 1265 case 0x38: p1 = "vpminsb"; goto L3op; 1266 case 0x39: p1 = "vpminsd"; goto L3op; 1267 case 0x3A: p1 = "vpminuw"; goto L3op; 1268 case 0x3B: p1 = "vpminud"; goto L3op; 1269 case 0x3C: p1 = "vpmaxsb"; goto L3op; 1270 case 0x3D: p1 = "vpmaxsd"; goto L3op; 1271 case 0x3E: p1 = "vpmaxuw"; goto L3op; 1272 case 0x3F: p1 = "vpmaxud"; goto L3op; 1273 case 0x40: p1 = "vpmulhd"; goto L3op; 1274 case 0x41: p1 = "vpminposuw"; goto Lxmm_eax; 1275 case 0x96: p1 = rex & REX_W ? "vfmaddsub132pd" : "vfmaddsub132ps"; goto L3op; 1276 case 0x97: p1 = rex & REX_W ? "vfmaddsub132pd" : "vfmaddsub132ps"; goto L3op; 1277 case 0x98: p1 = rex & REX_W ? "vfmadd132pd" : "vfmadd132ps"; goto L3op; 1278 case 0x99: p1 = rex & REX_W ? "vfmadd132sd" : "vfmadd132ss"; goto L3op; 1279 case 0x9A: p1 = rex & REX_W ? "vfmsub132pd" : "vfmsub132ps"; goto L3op; 1280 case 0x9B: p1 = rex & REX_W ? "vfmsub132sd" : "vfmsub132ss"; goto L3op; 1281 case 0xA6: p1 = rex & REX_W ? "vfmaddsub213pd" : "vfmaddsub213ps"; goto L3op; 1282 case 0xA7: p1 = rex & REX_W ? "vfmaddsub213pd" : "vfmaddsub213ps"; goto L3op; 1283 case 0xA8: p1 = rex & REX_W ? "vfmadd213pd" : "vfmadd213ps"; goto L3op; 1284 case 0xA9: p1 = rex & REX_W ? "vfmadd213sd" : "vfmadd213ss"; goto L3op; 1285 case 0xAA: p1 = rex & REX_W ? "vfmsub213pd" : "vfmsub213ps"; goto L3op; 1286 case 0xAB: p1 = rex & REX_W ? "vfmsub213sd" : "vfmsub213ss"; goto L3op; 1287 case 0xB6: p1 = rex & REX_W ? "vfmaddsub231pd" : "vfmaddsub231ps"; goto L3op; 1288 case 0xB7: p1 = rex & REX_W ? "vfmaddsub231pd" : "vfmaddsub231ps"; goto L3op; 1289 case 0xB8: p1 = rex & REX_W ? "vfmadd231pd" : "vfmadd231ps"; goto L3op; 1290 case 0xB9: p1 = rex & REX_W ? "vfmadd231sd" : "vfmadd231ss"; goto L3op; 1291 case 0xBA: p1 = rex & REX_W ? "vfmsub231pd" : "vfmsub231ps"; goto L3op; 1292 case 0xBB: p1 = rex & REX_W ? "vfmsub231sd" : "vfmsub231ss"; goto L3op; 1293 case 0xDB: p1 = "vaesenc"; goto Lxmm_eax; 1294 case 0xDC: p1 = "vaesenc"; goto L3op; 1295 case 0xDD: p1 = "vaesenclast"; goto L3op; 1296 case 0xDE: p1 = "vaesdec"; goto L3op; 1297 case 0xDF: p1 = "vaesdeclast"; goto L3op; 1298 1299 default: 1300 printf("0F38 66: %02x\n", opcode); 1301 break; 1302 } 1303 } 1304 else if (m_mmmm == 0x0F3A && opext == 0x66) 1305 { 1306 switch (opcode) 1307 { 1308 case 0x04: p1 = "vpermilps"; goto Lymmxeaimm; 1309 case 0x06: p1 = "vperm2f128"; goto L4op; 1310 case 0x05: p1 = "vpermilpd"; goto Lymmxeaimm; 1311 case 0x08: p1 = "vroundps"; goto Leax_xmm_imm; 1312 case 0x09: p1 = "vroundpd"; goto Leax_xmm_imm; 1313 case 0x0A: p1 = "vroundss"; goto L4op; 1314 case 0x0B: p1 = "vroundsd"; goto L4op; 1315 case 0x0C: p1 = "vblendps"; goto L4op; 1316 case 0x0D: p1 = "vblendpd"; goto L4op; 1317 case 0x0E: p1 = "vpblendw"; goto L4op; 1318 case 0x0F: p1 = "vpalignr"; goto L4op; 1319 case 0x14: p1 = "vpextrb"; goto Lea_xmm_imm; 1320 case 0x15: p1 = "vpextrw"; goto Lea_xmm_imm; 1321 case 0x16: p1 = rex & REX_W ? "vpextrq" : "vpextrd"; goto Lea_xmm_imm; 1322 case 0x17: p1 = "vextractps"; goto Lea_xmm_imm; 1323 case 0x18: p1 = "vinsertf128"; goto Lymm_ymm_eax_imm; 1324 case 0x19: p1 = "vextractf128"; goto Lxeaymmimm; 1325 case 0x1D: p1 = "vcvtps2ph"; goto Leax_xmm_imm; 1326 case 0x20: p1 = "vpinsrb"; goto Lymm_ymm_ea_imm; 1327 case 0x21: p1 = "vinsertps"; goto Lymm_ymm_eax_imm; 1328 case 0x22: p1 = rex & REX_W ? "vpinsrq" : "vpinsrd"; goto Lymm_ymm_ea_imm; 1329 case 0x40: p1 = "vdpps"; goto L4op; 1330 case 0x41: p1 = "vdppd"; goto L4op; 1331 case 0x42: p1 = "vmpsadbw"; goto L4op; 1332 case 0x44: p1 = "vpclmulqdq"; goto L4op; 1333 case 0x4A: p1 = "vblendvps"; goto L4op; 1334 case 0x4B: p1 = "vblendvpd"; goto L4op; 1335 case 0x4C: p1 = "vpblendvb"; goto L4op; 1336 case 0x60: p1 = "vpcmpestrm"; goto L4op; 1337 case 0x61: p1 = "vpcmpestri"; goto L4op; 1338 case 0x62: p1 = "vpcmpistrm"; goto L4op; 1339 case 0x63: p1 = "vpcmpistri"; goto L4op; 1340 case 0xDF: p1 = "vaeskeygenassist"; goto Lxmm_eax_imm; 1341 1342 default: 1343 printf("0F3A 66: %02x\n", opcode); 1344 break; 1345 } 1346 } 1347 goto Ldone; 1348 1349 Lregeax: 1350 p2 = (rex & REX_W) ? rreg[reg] : ereg[reg]; 1351 p3 = getEAxmmymm(rex, c, 128); 1352 goto Ldone; 1353 1354 Leax_xmm_imm: 1355 p2 = getEAxmmymm(rex, c, vlen); 1356 p3 = vlen == 256 ? ymmreg[vreg] : xmmreg[vreg]; 1357 p4 = immed8(c + 1 + EAbytes(c)); 1358 goto Ldone; 1359 1360 Lxmm_eax_imm: 1361 p2 = vlen == 256 ? ymmreg[vreg] : xmmreg[vreg]; 1362 p3 = getEAxmmymm(rex, c, vlen); 1363 p4 = immed8(c + 1 + EAbytes(c)); 1364 goto Ldone; 1365 1366 Lea_xmm_imm: 1367 p2 = getEAvec(rex, c); 1368 p3 = xmmreg[reg]; 1369 p4 = immed8(c + 1 + EAbytes(c)); 1370 goto Ldone; 1371 1372 Lxmm_eax: 1373 p2 = vlen == 256 ? ymmreg[reg] : xmmreg[reg]; 1374 p3 = getEAxmmymm(rex, c, vlen); 1375 goto Ldone; 1376 1377 Leax_xmm: 1378 p2 = getEAxmmymm(rex, c, vlen); 1379 p3 = vlen == 256 ? ymmreg[reg] : xmmreg[reg]; 1380 goto Ldone; 1381 1382 Lxmm_ea: 1383 p2 = vlen == 256 ? ymmreg[reg] : xmmreg[reg]; 1384 p3 = getEAvec(rex, c); 1385 goto Ldone; 1386 1387 Lea_xmm: 1388 p2 = getEAvec(rex, c); 1389 p3 = vlen == 256 ? ymmreg[reg] : xmmreg[reg]; 1390 goto Ldone; 1391 1392 L_xmmea: 1393 p2 = xmmreg[reg]; 1394 p3 = getEAxmmymm(rex, c, vlen); 1395 goto Ldone; 1396 1397 Lymmea: 1398 p2 = vlen == 256 ? ymmreg[reg] : xmmreg[reg]; 1399 p3 = getEAxmmymm(rex, c, 128); 1400 goto Ldone; 1401 1402 Lrxmm: 1403 p2 = ereg[reg]; 1404 p3 = getEAxmmymm(rex, c, vlen); 1405 goto Ldone; 1406 1407 Lxmmxmmea: 1408 p2 = xmmreg[reg]; 1409 p3 = xmmreg[vreg]; 1410 p4 = getEAvec(rex, c); 1411 goto Ldone; 1412 1413 Lxeaymmimm: 1414 p2 = getEAxmmymm(rex, c, 128); 1415 p3 = vlen == 256 ? ymmreg[reg] : xmmreg[reg]; 1416 p4 = immed8(c + 1 + EAbytes(c)); 1417 goto Ldone; 1418 1419 Lymmxeaimm: 1420 p2 = vlen == 256 ? ymmreg[reg] : xmmreg[reg]; 1421 p3 = getEAxmmymm(rex, c, 128); 1422 p4 = immed8(c + 1 + EAbytes(c)); 1423 goto Ldone; 1424 1425 L3op: 1426 p2 = vlen == 256 ? ymmreg[reg] : xmmreg[reg]; 1427 p3 = vlen == 256 ? ymmreg[vreg] : xmmreg[vreg]; 1428 p4 = getEAxmmymm(rex, c, vlen); 1429 goto Ldone; 1430 1431 L3opr: 1432 p4 = vlen == 256 ? ymmreg[reg] : xmmreg[reg]; 1433 p3 = vlen == 256 ? ymmreg[vreg] : xmmreg[vreg]; 1434 p2 = getEAxmmymm(rex, c, vlen); 1435 goto Ldone; 1436 1437 L4op: 1438 p5 = immed8(c + 1 + EAbytes(c)); 1439 goto L3op; 1440 1441 Lymm_ymm_eax_imm: 1442 p2 = vlen == 256 ? ymmreg[reg] : xmmreg[reg]; 1443 p3 = vlen == 256 ? ymmreg[vreg] : xmmreg[vreg]; 1444 p4 = getEAxmmymm(rex, c, 128); 1445 p5 = immed8(c + 1 + EAbytes(c)); 1446 goto Ldone; 1447 1448 Lymm_ymm_ea_imm: 1449 p2 = vlen == 256 ? ymmreg[reg] : xmmreg[reg]; 1450 p3 = vlen == 256 ? ymmreg[vreg] : xmmreg[vreg]; 1451 p4 = getEAvec(rex, c); 1452 p5 = immed8(c + 1 + EAbytes(c)); 1453 goto Ldone; 1454 1455 Ldone: 1456 void puts(const(char)* s) 1457 { 1458 while (*s) 1459 { 1460 put(*s); 1461 ++s; 1462 } 1463 } 1464 1465 puts(p0); 1466 put('t'); 1467 puts(p1); 1468 if (*p2) 1469 { 1470 put('t'); 1471 puts(p2); 1472 if (*p3) 1473 { 1474 put(','); 1475 puts(p3); 1476 if (*p4) 1477 { 1478 put(','); 1479 puts(p4); 1480 if (*p5) 1481 { 1482 put(','); 1483 puts(p5); 1484 } 1485 } 1486 } 1487 } 1488 } 1489 1490 1491 /*************************** 1492 * Decipher 8087 instructions. 1493 * Input: 1494 * waitflag if 1 then generate FWAIT form of instruction 1495 */ 1496 1497 void get87string(addr c,char *p0,int waitflag) 1498 { 1499 uint opcode,reg,modrgrm,mod; 1500 const(char)* p1, p2, p3; 1501 uint MF; 1502 const(char)* mfp; 1503 immutable char* reserved = "reserved"; 1504 immutable char* fld = "fnld"; 1505 immutable char* fst = "fnst"; 1506 immutable char* fstp = "fnstp"; 1507 immutable char* fisttp = "fnisttp"; 1508 __gshared const(char)*[8] orth = 1509 [ "fnadd","fnmul","fncom","fncomp","fnsub","fnsubr","fndiv","fndivr"]; 1510 __gshared const(char)*[4] mfstring = ["float","dword","qword","word"]; 1511 __gshared const(char)*[8] op7 = 1512 [ "fnild","fnisttp","fnist","fnistp","fnbld","fnild","fnbst","fnistp"]; 1513 __gshared const(char)*[7] op7b = [ "fnfree","fnxch","fnstp","fnstp","fnstsw","fnucomip","fncomip" ]; 1514 __gshared const(char)*[4] opD9 = [ "fnldenv","fnldcw","fnstenv","fnstcw" ]; 1515 __gshared const(char)*[6] opDDb = ["fnfree","fnxch","fnst","fnstp","fnucom","fnucomp"]; 1516 __gshared const(char)*[8] opDDa = ["fnld","fnisttp","fnst","fnstp", 1517 "fnrstor","reserved","fnsave","fnstsw"]; 1518 __gshared const(char)*[5] opDBa = [ "fneni","fndisi","fnclex","fninit","fnsetpm" ]; 1519 __gshared const(char)* ST = "ST"; 1520 __gshared const(char)* STI = "ST(i)"; 1521 char[6] sti; 1522 1523 waitflag = 1; 1524 mfp = p2 = p3 = ""; 1525 p1 = reserved; 1526 opcode = code[c]; 1527 modrgrm = code[c + 1]; 1528 reg = (modrgrm >> 3) & 7; 1529 MF = (opcode >> 1) & 3; 1530 mod = (modrgrm >> 6) & 3; 1531 if (opcode == 0xDA) 1532 { 1533 switch (modrgrm & ~7) 1534 { 1535 case 0xC0: p1 = "fncmovb"; goto Lcc; 1536 case 0xC8: p1 = "fncmove"; goto Lcc; 1537 case 0xD0: p1 = "fncmovbe"; goto Lcc; 1538 case 0xD8: p1 = "fncmovu"; goto Lcc; 1539 default: 1540 break; 1541 } 1542 } 1543 else if (opcode == 0xDB) 1544 { 1545 switch (modrgrm & ~7) 1546 { 1547 case 0xC0: p1 = "fncmovnb"; goto Lcc; 1548 case 0xC8: p1 = "fncmovne"; goto Lcc; 1549 case 0xD0: p1 = "fncmovnbe"; goto Lcc; 1550 case 0xD8: p1 = "fncmovnu"; goto Lcc; 1551 Lcc: 1552 if ((modrgrm & 7) != 1) 1553 { 1554 strcpy(sti.ptr, STI); 1555 sti[3] = (modrgrm & 7) + '0'; 1556 p2 = sti.ptr; 1557 } 1558 goto L2; 1559 default: 1560 break; 1561 } 1562 } 1563 1564 if ((opcode & 1) == 0) 1565 { 1566 p1 = orth[reg]; 1567 if (mod == 3) 1568 { 1569 immutable char*[8] orthp = 1570 [ "fnaddp","fnmulp","fncomp","fncompp", 1571 "fnsubrp","fnsubp","fndivrp","fndivp" 1572 ]; 1573 1574 if (opcode == 0xDE) 1575 p1 = orthp[reg]; 1576 if (modrgrm != 0xD9) /* FNCOMPP */ 1577 { 1578 strcpy(sti.ptr, STI); 1579 sti[3] = (modrgrm & 7) + '0'; 1580 p2 = sti.ptr; 1581 if ((reg & 6) != 2) 1582 { 1583 if (opcode == 0xD8 && ((reg & 6) != 2)) 1584 { p3 = p2; 1585 p2 = ST; 1586 } 1587 else 1588 p3 = ST; 1589 } 1590 } 1591 if (opcode == 0xDA && modrgrm == 0xE9) 1592 p1 = "fnucompp"; 1593 } 1594 else 1595 { mfp = mfstring[MF]; 1596 p2 = getEA(0, c); 1597 } 1598 } 1599 else if (reg == 0 && mod != 3) 1600 { p1 = (opcode == 0xDB || opcode == 0xDF) ? op7[reg] : fld; 1601 mfp = mfstring[MF]; 1602 p2 = getEA(0, c); 1603 } 1604 else if (reg == 2 && mod != 3) 1605 { p1 = (opcode == 0xDB || opcode == 0xDF) ? op7[reg] : fst; 1606 mfp = mfstring[MF]; 1607 p2 = getEA(0, c); 1608 } 1609 else if (reg == 3 && mod != 3) 1610 { p1 = (opcode == 0xDB || opcode == 0xDF) ? op7[reg] : fstp; 1611 mfp = mfstring[MF]; 1612 p2 = getEA(0, c); 1613 } 1614 else 1615 { switch (opcode) 1616 { 1617 case 0xD9: 1618 if (mod != 3) 1619 { p1 = opD9[reg - 4]; 1620 p2 = getEA(0, c); 1621 } 1622 else if (reg <= 3) 1623 { switch (reg) 1624 { case 0: 1625 p1 = fld; 1626 goto L1; 1627 case 1: 1628 p1 = "fnxch"; 1629 goto L1; 1630 case 2: 1631 if ((modrgrm & 7) == 0) 1632 p1 = "fnnop"; 1633 else 1634 p1 = reserved; 1635 break; 1636 case 3: 1637 p1 = fstp; 1638 L1: 1639 strcpy(sti.ptr,STI); 1640 sti[3] = (modrgrm & 7) + '0'; 1641 p2 = sti.ptr; 1642 break; 1643 default: 1644 break; 1645 } 1646 } 1647 else 1648 { 1649 immutable char*[32] opuna = 1650 [ "fnchs","fnabs","reserved","reserved", 1651 "fntst","fnxam","reserved","reserved", 1652 "fnld1","fnldl2t","fnldl2e","fnldpi", 1653 "fnldlg2","fnldln2","fnldz","reserved", 1654 "fn2xm1","fnyl2x","fnptan","fnpatan", 1655 "fnxtract","fnprem1","fndecstp","fnincstp", 1656 "fnprem","fnyl2xp1","fnsqrt","fnsincos", 1657 "fnrndint","fnscale","fnsin","fncos" 1658 ]; 1659 1660 p1 = opuna[modrgrm & 0x1F]; 1661 } 1662 break; 1663 case 0xDB: 1664 if (modrgrm >= 0xE0 && modrgrm <= 0xE4) 1665 p1 = opDBa[modrgrm - 0xE0]; 1666 else if (mod != 3 && (reg == 5 || reg == 7)) 1667 { p1 = (reg == 5) ? fld : fstp; 1668 p2 = getEA(0, c); 1669 mfp = "tbyte"; 1670 } 1671 else if (mod != 3 && reg == 1) 1672 { p1 = fisttp; 1673 p2 = getEA(0, c); 1674 mfp = "word"; 1675 } 1676 else if ((modrgrm & 0xF8) == 0xF0) 1677 { p1 = "fncomi"; 1678 Lst: 1679 if ((modrgrm & 7) != 1) 1680 { 1681 strcpy(sti.ptr, STI); 1682 sti[3] = (modrgrm & 7) + '0'; 1683 p2 = sti.ptr; 1684 } 1685 } 1686 else if ((modrgrm & 0xF8) == 0xE8) 1687 { p1 = "fnucomi"; 1688 goto Lst; 1689 } 1690 break; 1691 case 0xDD: 1692 if (mod != 3) 1693 { p1 = opDDa[reg]; 1694 p2 = getEA(0, c); 1695 if (reg == 1) // if FISTTP m64int 1696 mfp = "long64"; 1697 } 1698 else if (reg <= 5) 1699 { p1 = opDDb[reg]; 1700 if (modrgrm & 7) 1701 { 1702 strcpy(sti.ptr, STI); 1703 sti[3] = (modrgrm & 7) + '0'; 1704 p2 = sti.ptr; 1705 } 1706 else 1707 p2 = ST; 1708 } 1709 break; 1710 case 0xDF: 1711 p1 = op7[reg]; 1712 if (reg == 1) 1713 mfp = "short"; 1714 else if (reg <= 3) 1715 mfp = "long"; 1716 else if (reg == 5 || reg == 7) 1717 mfp = "long64"; 1718 if ((modrgrm & 0xC0) == 0xC0) 1719 { p1 = (reg <= 6) ? op7b[reg] : reserved; 1720 if (reg == 4) 1721 p2 = "AX"; 1722 else 1723 { if (reg == 5) 1724 mfp = ""; 1725 if ((modrgrm & 7) != 1) 1726 { 1727 strcpy(sti.ptr, STI); 1728 sti[3] = (modrgrm & 7) + '0'; 1729 p2 = sti.ptr; 1730 } 1731 } 1732 } 1733 else 1734 p2 = getEA(0, c); 1735 break; 1736 default: 1737 break; 1738 } 1739 } 1740 L2: 1741 void puts(const(char)* s) 1742 { 1743 while (*s) 1744 { 1745 put(*s); 1746 ++s; 1747 } 1748 } 1749 1750 puts(p0); 1751 put('\t'); 1752 if (waitflag) 1753 puts(p1 + 2); 1754 else 1755 puts(p1); 1756 if (*p2) 1757 { 1758 put('\t'); 1759 if (*mfp) 1760 { 1761 puts(mfp); 1762 puts(" ptr "); 1763 } 1764 puts(p2); 1765 if (*p3) 1766 { 1767 put(','); 1768 puts(p3); 1769 } 1770 } 1771 } 1772 1773 void puts(const(char)* s) 1774 { 1775 while (*s) 1776 { 1777 put(*s); 1778 ++s; 1779 } 1780 } 1781 1782 /** 1783 * Holding area for functions that implement X86 instruction patterns 1784 * It's a mixin template so it can be mixed into `disassemble` to access 1785 * it's state. 1786 */ 1787 mixin template PatternFunctions() 1788 { 1789 /** 1790 * Implements `xmm1, xmm2/m128, imm8` 1791 * Params: 1792 * indexOffset = this will be called from various amounts of 1793 * lookahead into the code buffer which means an index is needed 1794 * for finding the right offset to the register. 1795 */ 1796 void xmm_xmm_imm8(uint indexOffset) 1797 { 1798 p2 = xmmreg[reg]; 1799 p3 = getEAxmm(rex, c + indexOffset); 1800 p4 = immed8(c + 2 + EAbytes(c + 1)); 1801 } 1802 } 1803 /************************* 1804 * Disassemble the instruction at `c` 1805 * Params: 1806 * c = index into code[] 1807 */ 1808 1809 void disassemble(uint c) 1810 { 1811 //printf("disassemble(c = %d, siz = %d)\n", c, siz); 1812 puts(" "); 1813 uint prefixsize = 0; 1814 uint sz; 1815 do 1816 { 1817 sz = prefixbyte(c); 1818 c += sz; 1819 prefixsize += sz; 1820 } while (sz); 1821 assert(siz > prefixsize); 1822 siz -= prefixsize; 1823 1824 uint opcode,reg = 0; 1825 ubyte rex; 1826 int i,o3; 1827 const(char)* p1, p2, p3, p4; 1828 char[80] p0; 1829 char[5] p1buf; 1830 const(char)* sep; 1831 const(char)* s2; 1832 const(char)* s3; 1833 char[BUFMAX] buf = void; 1834 1835 mixin PatternFunctions; 1836 enum MOV = "mov"; 1837 enum XCHG = "xchg"; 1838 enum IMUL = "imul"; 1839 enum SHRD = "shrd"; 1840 enum SHLD = "shld"; 1841 __gshared const char*[12] astring = 1842 [ "add","or", "adc","sbb","and","sub","xor","cmp", 1843 "inc","dec","push","pop" 1844 ]; 1845 __gshared const char*[4] bstring = [ "daa","das","aaa","aas" ]; 1846 __gshared const char*[8] mulop = 1847 [ "test","F6|7?","not","neg","mul",IMUL,"div","idiv" ]; 1848 __gshared const char*[8] segreg = [ "ES","CS","SS","DS","FS","FS","?6","?7" ]; 1849 __gshared const char*[16] jmpop = 1850 [ "jo","jno","jb","jae","je","jne","jbe","ja", 1851 "js","jns","jp","jnp","jl","jge","jle","jg" 1852 ]; 1853 __gshared const char*[0x100 - 0x90] ge90 = 1854 [ "nop",XCHG,XCHG,XCHG,XCHG,XCHG,XCHG,XCHG, 1855 "cbw","cwd","call","wait","pushf","popf","sahf","lahf", 1856 MOV,MOV,MOV,MOV,"movsb","movsw","cmpsb","cmpsw", 1857 "test","test","stosb","stosw","lodsb","lodsw","scasb","scasw", 1858 MOV,MOV,MOV,MOV,MOV,MOV,MOV,MOV, 1859 MOV,MOV,MOV,MOV,MOV,MOV,MOV,MOV, 1860 "C0","C1","ret","ret","les","lds",MOV,MOV, 1861 "enter","leave","retf","retf","int","int","into","iret", 1862 "D0","D1","D2","D3","aam","aad","D6","xlat", 1863 "D8","D9","DA","DB","DC","DD","DE","DF", /* ESC */ 1864 "loopne","loope","loop","jcxz","in","in","out","out", 1865 "call","jmp","jmp","jmp short","in","in","out","out", 1866 "lock","F1","repne","rep","hlt","cmc","F6","F7", 1867 "clc","stc","cli","sti","cld","std","FE","FF" 1868 ]; 1869 1870 buf[0] = 0; 1871 sep = ",".ptr; 1872 s2 = "".ptr; 1873 s3 = s2; 1874 opcode = code[c]; 1875 p0[0]='\0'; 1876 if (bObjectcode) { 1877 for (i=0; i<siz; i++) { 1878 snprintf( buf.ptr, buf.length, "%02X ", code[c+i] ); 1879 strcat( p0.ptr, buf.ptr ); 1880 } 1881 for (; i + prefixsize < 8; i++) 1882 strcat(p0.ptr, " "); 1883 } 1884 1885 // if VEX prefix 1886 if (siz >= 3 && 1887 (opcode == 0xC4 || opcode == 0xC5) && 1888 (model == 64 || (code[c + 1] & 0xC0) == 0xC0) 1889 ) 1890 { 1891 getVEXstring(c, siz, p0.ptr); 1892 return; 1893 } 1894 1895 rex = 0; 1896 if (model == 64) 1897 { 1898 if (opcode == 0xF3 || opcode == 0xF2) 1899 { if ((code[c + 1] & 0xF0) == REX) 1900 { 1901 c++; 1902 rex = code[c]; 1903 } 1904 } 1905 else if ((opcode & 0xF0) == REX) 1906 { rex = cast(ubyte)opcode; 1907 c++; 1908 opcode = code[c]; 1909 } 1910 } 1911 if (inssize[opcode] & M) /* if modregrm byte */ 1912 { reg = (code[c + 1] >> 3) & 7; 1913 if (rex & REX_R) 1914 reg |= 8; 1915 } 1916 snprintf(p1buf.ptr,p1buf.length,"0x%02x",opcode); 1917 p1 = p1buf.ptr; 1918 p2 = ""; 1919 p3 = ""; 1920 p4 = ""; 1921 if (opcode >= 0x90) 1922 { 1923 p1 = ge90[opcode - 0x90]; 1924 if (!opsize) /* if 32 bit operand */ 1925 { switch (opcode) 1926 { case 0x98: p1 = "cwde"; 1927 if (rex & REX_W) 1928 p1 = "cdqe"; 1929 break; 1930 case 0x99: p1 = "cdq"; 1931 if (rex & REX_W) 1932 p1 = "cqo"; 1933 break; 1934 case 0x9C: p1 = "pushfd"; break; 1935 case 0x9D: p1 = "popfd"; break; 1936 case 0xA5: p1 = "movsd"; break; 1937 case 0xA7: p1 = "cmpsd"; break; 1938 case 0xAB: p1 = "stosd"; break; 1939 case 0xAD: p1 = "lodsd"; break; 1940 case 0xAF: p1 = "scasd"; break; 1941 case 0xCF: p1 = "iretd"; break; 1942 default: 1943 break; 1944 } 1945 } 1946 if (opcode == 0xF2 && code[c + 1] == 0x0F) 1947 { 1948 reg = (code[c + 3] >> 3) & 7; 1949 switch (code[c + 2]) 1950 { 1951 case 0x10: p1 = "movsd"; goto Lsdxmm; 1952 case 0x11: p1 = "movsd"; goto Lsdxmmr; 1953 case 0x12: p1 = "movddup"; goto Lsdxmm; 1954 case 0x2A: p1 = "cvtsi2sd"; goto Lsd32; 1955 case 0x2C: p1 = "cvttsd2si"; goto Lsd4; 1956 case 0x2D: p1 = "cvtsd2si"; goto Lsd; 1957 case 0x51: p1 = "sqrtsd"; goto Lsd; 1958 case 0x58: p1 = "addsd"; goto Lsd; 1959 case 0x59: p1 = "mulsd"; goto Lsd; 1960 case 0x5A: p1 = "cvtsd2ss"; goto Lsd; 1961 case 0x5C: p1 = "subsd"; goto Lsd; 1962 case 0x5D: p1 = "minsd"; goto Lsd; 1963 case 0x5E: p1 = "divsd"; goto Lsd; 1964 case 0x5F: p1 = "maxsd"; goto Lsd; 1965 case 0x70: 1966 p1 = "pshuflw"; 1967 xmm_xmm_imm8(1); 1968 break; 1969 case 0x7C: p1 = "haddps"; goto Lsdxmm; 1970 case 0x7D: p1 = "hsubps"; goto Lsdxmm; 1971 case 0xC2: p1 = "cmpsd"; goto Lsdi; 1972 case 0xD0: p1 = "addsubps"; goto Lsdxmm; 1973 case 0xD6: p1 = "movdq2q"; goto Lsdmm; 1974 case 0xE6: p1 = "cvtpd2dq"; goto Lsd; 1975 case 0xF0: p1 = "lddqu"; goto Lsdxmm; 1976 default: 1977 break; 1978 } 1979 } 1980 if (opcode == 0xF3 && code[c + 1] == 0x0F) 1981 { 1982 reg = (code[c + 3] >> 3) & 7; 1983 switch (code[c + 2]) 1984 { 1985 case 0x10: p1 = "movss"; goto Lsdxmm; 1986 case 0x11: p1 = "movss"; goto Lsdxmmr; 1987 case 0x12: p1 = "movsldup"; goto Lsdxmm; 1988 case 0x16: p1 = "movshdup"; goto Lsdxmm; 1989 case 0x1E: 1990 if (code[c + 3] == 0xFB) 1991 p1 = "endbr32"; 1992 else if (code[c + 3] == 0xFA) 1993 p1 = "endbr64"; 1994 break; 1995 case 0x2A: p1 = "cvtsi2ss"; goto Lsd32; 1996 case 0x2C: p1 = "cvttss2si"; goto Lsd4; 1997 case 0x2D: p1 = "cvtss2si"; goto Lsd; 1998 case 0x51: p1 = "sqrtss"; goto Lsd; 1999 case 0x52: p1 = "rsqrtss"; goto Lsd; 2000 case 0x53: p1 = "rcpss"; goto Lsd; 2001 case 0x58: p1 = "addss"; goto Lsd; 2002 case 0x59: p1 = "mulss"; goto Lsd; 2003 case 0x5A: p1 = "cvtss2sd"; goto Lsd; 2004 case 0x5B: p1 = "cvttps2dq"; goto Lsd; 2005 case 0x5C: p1 = "subss"; goto Lsd; 2006 case 0x5D: p1 = "minss"; goto Lsd; 2007 case 0x5E: p1 = "divss"; goto Lsd; 2008 case 0x5F: p1 = "maxss"; goto Lsd; 2009 case 0x6F: p1 = "movdqu"; goto Lsdxmm; 2010 case 0x70: 2011 p1 = "pshufhw"; 2012 xmm_xmm_imm8(1); 2013 break; 2014 case 0xC2: 2015 p1 = "cmpss"; 2016 xmm_xmm_imm8(1); 2017 break; 2018 case 0xD6: p1 = "movq2dq"; goto Lsdmmr; 2019 case 0xE6: p1 = "cvtdq2pd"; goto Lsd; 2020 case 0x7E: p1 = "movq"; goto Lsdxmm; 2021 case 0x7F: p1 = "movdqu"; goto Lsdxmmr; 2022 Lsdi: 2023 p4 = immed8(c + 3 + EAbytes(c + 2)); 2024 Lsd: 2025 p2 = xmmreg[reg]; 2026 p3 = getEA(rex, c + 1); 2027 goto Ldone; 2028 Lsd32: 2029 p2 = xmmreg[reg]; 2030 inssize2[0x2A] = M|3; 2031 p3 = getEA(rex, c + 1); 2032 inssize2[0x2A] = X|3; 2033 goto Ldone; 2034 Lsd4: 2035 p2 = ereg[reg]; 2036 p3 = getEA(rex, c + 1); 2037 goto Ldone; 2038 Lsdxmm: 2039 p2 = xmmreg[reg]; 2040 p3 = getEAxmm(rex, c + 1); 2041 goto Ldone; 2042 2043 Lsdxmmr: 2044 p3 = xmmreg[reg]; 2045 p2 = getEAxmm(rex, c + 1); 2046 goto Ldone; 2047 Lsdmm: 2048 p2 = mmreg[reg]; 2049 p3 = getEAxmm(rex, c + 1); 2050 goto Ldone; 2051 Lsdmmr: 2052 p2 = xmmreg[reg]; 2053 p3 = getEA(rex, c + 1); 2054 goto Ldone; 2055 default: 2056 break; 2057 } 2058 } 2059 } 2060 if (opcode < 0x60) 2061 { 2062 if (opsize != defopsize && opcode == 0x0F && 2063 (code[c + 1] == 0x38 || code[c + 1] == 0x3A) 2064 ) 2065 { // SSE4 2066 opcode = code[c + 2]; 2067 2068 if (inssize2[code[c + 1]] & M) // if modregrm byte 2069 { reg = (code[c + 2] >> 3) & 7; 2070 if (rex & REX_R) 2071 reg |= 8; 2072 } 2073 switch (opcode) 2074 { 2075 case 0x40: 2076 p1 = "dpps"; 2077 goto Ldpp; 2078 case 0x41: 2079 p1 = "dppd"; 2080 Ldpp: 2081 p2 = xmmreg[reg]; 2082 p3 = getEAxmm(rex, c); 2083 p4 = immed8(c + 3 + EAbytes(c + 2)); 2084 break; 2085 default: 2086 break; 2087 } 2088 } 2089 else if (opcode == 0x0F) 2090 { opcode = code[c + 1]; 2091 2092 if (inssize2[opcode] & M) // if modregrm byte 2093 { reg = (code[c + 2] >> 3) & 7; 2094 if (rex & REX_R) 2095 reg |= 8; 2096 } 2097 2098 switch (opcode) 2099 { 2100 case 0x00: 2101 { 2102 __gshared const char*[8] pszGrp6 = [ "sldt","str","lldt","ltr", 2103 "verr", "verw", "bad6", "bad7" ]; 2104 p1 = pszGrp6[reg]; 2105 p2 = getEA(rex, c); 2106 goto Ldone; 2107 } 2108 case 0x01: 2109 if (code[c + 2] == 0xC8) 2110 { p1 = "monitor"; 2111 goto Ldone; 2112 } 2113 else if (code[c + 2] == 0xC9) 2114 { p1 = "mwait"; 2115 goto Ldone; 2116 } 2117 else if (code[c + 2] == 0xD0) 2118 { p1 = "xgetbv"; 2119 goto Ldone; 2120 } 2121 else if (code[c + 2] == 0xD1) 2122 { p1 = "xsetbv"; 2123 goto Ldone; 2124 } 2125 else if (code[c+2] == 0xF9) 2126 { 2127 //0F 01 F9 RDTSCP 2128 p1 = "rdtscp"; 2129 goto Ldone; 2130 } 2131 else 2132 { 2133 __gshared const char*[8] pszGrp7 = [ "sgdt", "sidt", "lgdt", 2134 "lidt", "smsw", "bad5", "lmsw", "invlpg" ]; 2135 p1 = pszGrp7[reg]; 2136 p2 = getEA(rex, c); 2137 goto Ldone; 2138 } 2139 case 0x02: 2140 p1 = "lar"; 2141 break; 2142 case 0x03: 2143 p1 = "lsl"; 2144 break; 2145 case 0x06: 2146 p1 = "clts"; 2147 goto Ldone; 2148 case 0x08: 2149 p1 = "invd"; 2150 goto Ldone; 2151 case 0x09: 2152 p1 = "wbinvd"; 2153 goto Ldone; 2154 case 0x0B: 2155 p1 = "ud2"; 2156 goto Ldone; 2157 case 0x0D: 2158 if (reg == 1 || reg == 2) 2159 { 2160 p1 = reg == 1 ? "prefetchw" : "prefetchwt1"; 2161 p2 = getEA(rex, c); 2162 goto Ldone; 2163 } 2164 break; 2165 case 0x0F: 2166 { __gshared const ubyte[22] imm = 2167 [ 0xBF,0x1D,0xAE,0x9E, 2168 0xB0,0x90,0xA0,0xA4, 2169 0x94,0xB4,0x8A,0x8E, 2170 0x96,0xA6,0xB6,0xA7, 2171 0x97,0x9A,0xAA,0x0D, 2172 0xB7,0xBB, 2173 ]; 2174 __gshared const char*[22] amdstring = 2175 [ 2176 "pavgusb","pf2id","pfacc","pfadd", 2177 "pfcmpeq","pfcmpge","pfcmpgt","pfmax", 2178 "pfmin","pfmul","pfnacc","pfpnacc", 2179 "pfrcp","pfrcpit1","pfrcpit2","pfrsqit1", 2180 "pfrsqrt","pfsub","pfsubr","pi2fd", 2181 "pmulhrw","pswapd", 2182 ]; 2183 2184 const opimm = code[c + 2 + EAbytes(c + 1)]; 2185 foreach (j; 0 .. imm.length) 2186 { 2187 if (imm[j] == opimm) 2188 { p1 = amdstring[j]; 2189 break; 2190 } 2191 } 2192 p2 = mmreg[reg]; 2193 p3 = getEA(rex, c); 2194 goto Ldone; 2195 } 2196 case 0x10: 2197 case 0x11: 2198 p1 = (opsize != defopsize) ? "movupd" : "movups"; 2199 if (opcode == 0x10) 2200 { 2201 goto Lxmm; 2202 } 2203 p3 = xmmreg[reg]; 2204 p2 = getEA(rex, c); 2205 goto Ldone; 2206 case 0x12: 2207 case 0x13: 2208 p1 = (opsize != defopsize) ? "movlpd" : "movlps"; 2209 if (opcode == 0x12) 2210 { 2211 if (opsize == defopsize && 2212 (code[c + 2] & 0xC0) == 0xC0) 2213 p1 = "movhlps"; 2214 goto Lxmm; 2215 } 2216 p3 = xmmreg[reg]; 2217 p2 = getEA(rex, c); 2218 goto Ldone; 2219 case 0x14: 2220 p1 = (opsize != defopsize) ? "unpcklpd" : "unpcklps"; 2221 goto Lxmm; 2222 case 0x15: 2223 p1 = (opsize != defopsize) ? "unpckhpd" : "unpckhps"; 2224 goto Lxmm; 2225 case 0x16: 2226 case 0x17: 2227 p1 = (opsize != defopsize) ? "movhpd" : "movhps"; 2228 if (opcode == 0x16) 2229 { 2230 if (opsize == defopsize && 2231 (code[c + 2] & 0xC0) == 0xC0) 2232 p1 = "movlhps"; 2233 goto Lxmm; 2234 } 2235 p3 = xmmreg[reg]; 2236 p2 = getEA(rex, c); 2237 goto Ldone; 2238 case 0x18: 2239 { __gshared const char*[4] prefetch = ["prefetchnta","prefetcht0", 2240 "prefetcht1","prefetcht2" ]; 2241 p1 = prefetch[reg]; 2242 p2 = getEA(rex, c); 2243 goto Ldone; 2244 } 2245 case 0x1F: 2246 p1 = "nop"; 2247 p2 = getEA(rex, c); 2248 goto Ldone; 2249 case 0x20: 2250 p1 = "mov"; 2251 p2 = ereg[code[c+2]&7]; 2252 strcpy( buf.ptr, "CR0" ); 2253 buf[2] += reg; 2254 p3 = buf.ptr; 2255 goto Ldone; 2256 case 0x21: 2257 p1 = "mov"; 2258 p2 = ereg[code[c+2]&7]; 2259 strcpy( buf.ptr, "DR0" ); 2260 buf[2] += reg; 2261 p3 = buf.ptr; 2262 goto Ldone; 2263 case 0x22: 2264 p1 = "mov"; 2265 strcpy( buf.ptr, "CR0" ); 2266 buf[2] += reg; 2267 p2 = buf.ptr; 2268 p3 = ereg[code[c+2]&7]; 2269 goto Ldone; 2270 case 0x23: 2271 p1 = "mov"; 2272 strcpy( buf.ptr, "DR0" ); 2273 buf[2] += reg; 2274 p2 = buf.ptr; 2275 p3 = ereg[code[c+2]&7]; 2276 goto Ldone; 2277 case 0x24: 2278 p1 = "mov"; 2279 p2 = ereg[code[c+2]&7]; 2280 strcpy( buf.ptr, "TR0" ); 2281 buf[2] += reg; 2282 p3 = buf.ptr; 2283 goto Ldone; 2284 case 0x26: 2285 p1 = "mov"; 2286 strcpy( buf.ptr, "TR0" ); 2287 buf[2] += reg; 2288 p2 = buf.ptr; 2289 p3 = ereg[code[c+2]&7]; 2290 goto Ldone; 2291 case 0x28: 2292 case 0x29: 2293 p1 = (opsize != defopsize) ? "movapd" : "movaps"; 2294 if (opcode == 0x28) 2295 goto Lxmm; 2296 p3 = xmmreg[reg]; 2297 p2 = getEA(rex, c); 2298 goto Ldone; 2299 case 0x2A: 2300 p1 = (opsize != defopsize) ? "cvtpi2pd" : "cvtpi2ps"; 2301 goto Lxmm; 2302 case 0x2B: 2303 p1 = (opsize != defopsize) ? "movntpd" : "movntps"; 2304 p3 = xmmreg[reg]; 2305 p2 = getEA(rex, c); 2306 goto Ldone; 2307 case 0x2C: 2308 p1 = (opsize != defopsize) ? "cvttpd2pi" : "cvttps2pi"; 2309 p2 = mmreg[reg]; 2310 p3 = getEA(rex, c); 2311 goto Ldone; 2312 case 0x2D: 2313 p1 = (opsize != defopsize) ? "cvtpd2pi" : "cvtps2pi"; 2314 p2 = mmreg[reg]; 2315 p3 = getEA(rex, c); 2316 goto Ldone; 2317 case 0x2E: 2318 p1 = (opsize != defopsize) ? "ucomisd" : "ucomiss"; 2319 goto Lxmm; 2320 case 0x2F: 2321 p1 = (opsize != defopsize) ? "comisd" : "comiss"; 2322 goto Lxmm; 2323 case 0x30: 2324 p1 = "wrmsr"; 2325 goto Ldone; 2326 case 0x31: 2327 p1 = "rdtsc"; 2328 goto Ldone; 2329 case 0x32: 2330 p1 = "rdmsr"; 2331 goto Ldone; 2332 case 0x33: 2333 p1 = "rdpmc"; 2334 goto Ldone; 2335 case 0x34: 2336 p1 = "sysenter"; 2337 goto Ldone; 2338 case 0x35: 2339 p1 = "sysexit"; 2340 goto Ldone; 2341 case 0x50: 2342 p1 = (opsize != defopsize) ? "movmskpd" : "movmskps"; 2343 p2 = ereg[reg]; 2344 p3 = getEA(rex, c); 2345 2346 goto Ldone; 2347 case 0x51: 2348 p1 = (opsize != defopsize) ? "sqrtpd" : "sqrtps"; 2349 goto Lxmm; 2350 case 0x52: 2351 p1 = "rsqrtps"; 2352 goto Lxmm; 2353 case 0x53: 2354 p1 = "rcpps"; 2355 goto Lxmm; 2356 case 0x54: 2357 p1 = (opsize != defopsize) ? "andpd" : "andps"; 2358 goto Lxmm; 2359 case 0x55: 2360 p1 = (opsize != defopsize) ? "andnpd" : "andnps"; 2361 goto Lxmm; 2362 case 0x56: 2363 p1 = (opsize != defopsize) ? "orpd" : "orps"; 2364 goto Lxmm; 2365 case 0x57: 2366 p1 = (opsize != defopsize) ? "xorpd" : "xorps"; 2367 goto Lxmm; 2368 case 0x58: 2369 p1 = (opsize != defopsize) ? "addpd" : "addps"; 2370 goto Lxmm; 2371 case 0x59: 2372 p1 = (opsize != defopsize) ? "mulpd" : "mulps"; 2373 goto Lxmm; 2374 case 0x5A: 2375 p1 = (opsize != defopsize) ? "cvtpd2ps" : "cvtps2pd"; 2376 goto Lxmm; 2377 case 0x5B: 2378 p1 = (opsize != defopsize) ? "cvtps2dq" : "cvtdq2ps"; 2379 goto Lxmm; 2380 case 0x5C: 2381 p1 = (opsize != defopsize) ? "subpd" : "subps"; 2382 goto Lxmm; 2383 case 0x5D: 2384 p1 = (opsize != defopsize) ? "minpd" : "minps"; 2385 goto Lxmm; 2386 case 0x5E: 2387 p1 = (opsize != defopsize) ? "divpd" : "divps"; 2388 goto Lxmm; 2389 case 0x5F: 2390 p1 = (opsize != defopsize) ? "maxpd" : "maxps"; 2391 goto Lxmm; 2392 case 0x6F: 2393 if (opsize != defopsize) 2394 { 2395 p1 = "movdqa"; 2396 p2 = xmmreg[reg]; 2397 p3 = getEAxmm(rex, c); 2398 goto Ldone; 2399 } 2400 break; 2401 case 0x70: 2402 if (opsize != defopsize) 2403 { 2404 p1 = "pshufd"; 2405 xmm_xmm_imm8(0); 2406 goto Ldone; 2407 /* p2 = xmmreg[reg]; 2408 p3 = getEAxmm(rex, c); 2409 p4 = immed8(c + 2 + EAbytes(c + 1)); 2410 goto Ldone; */ 2411 } 2412 else 2413 { p1 = "pshufw"; 2414 p2 = mmreg[reg]; 2415 p3 = getEA(rex, c); 2416 goto Ldone; 2417 } 2418 case 0x71: 2419 case 0x72: 2420 case 0x73: 2421 if (reg == 2 || (reg == 4 && opcode != 0x73) || 2422 reg == 6) 2423 { __gshared const char[6][9] opp = 2424 [ "psrlw","psraw","psllw", 2425 "psrld","psrad","pslld", 2426 "psrlq","psllq","psllq", 2427 ]; 2428 2429 p1 = opp[(opcode - 0x71) * 3 + (reg >> 2)].ptr; 2430 p2 = (opsize != defopsize) ? getEAxmm(rex, c) : getEA(rex, c); 2431 p3 = immed8(c + 2 + EAbytes(c + 1)); 2432 goto Ldone; 2433 } 2434 if (opsize != defopsize && opcode == 0x73 && (reg == 7 || reg == 3)) 2435 { 2436 p1 = (reg == 7) ? "pslldq" : "psrldq"; 2437 p2 = getEAxmm(rex, c); 2438 p3 = immed8(c + 2 + EAbytes(c + 1)); 2439 goto Ldone; 2440 } 2441 break; 2442 2443 case 0x77: 2444 p1 = "emms"; 2445 goto Ldone; 2446 2447 case 0x7C: 2448 if (opsize != defopsize) 2449 { 2450 p1 = "haddpd"; 2451 p2 = xmmreg[reg]; 2452 p3 = getEAxmm(rex, c); 2453 goto Ldone; 2454 } 2455 break; 2456 case 0x7D: 2457 if (opsize != defopsize) 2458 { 2459 p1 = "hsubpd"; 2460 p2 = xmmreg[reg]; 2461 p3 = getEAxmm(rex, c); 2462 goto Ldone; 2463 } 2464 break; 2465 case 0x7E: 2466 p1 = "movd"; 2467 if (opsize != defopsize) 2468 { 2469 p2 = getEA(rex, c); 2470 p3 = xmmreg[reg]; 2471 goto Ldone; 2472 } 2473 goto Lmovdq; 2474 case 0x7F: 2475 if (opsize != defopsize) 2476 { 2477 p1 = "movdqa"; 2478 p2 = getEAxmm(rex, c); 2479 p3 = xmmreg[(code[c + 2] >> 3) & 7]; 2480 goto Ldone; 2481 } 2482 p1 = "movq"; 2483 Lmovdq: 2484 p2 = getEA(rex, c); 2485 p3 = mmreg[reg]; 2486 goto Ldone; 2487 case 0xa0: 2488 p1 = "push"; 2489 p2 = "FS"; 2490 goto Ldone; 2491 case 0xa1: 2492 p1 = "pop"; 2493 p2 = "FS"; 2494 goto Ldone; 2495 case 0xA2: 2496 p1 = "cpuid"; 2497 goto Ldone; 2498 case 0xA3: 2499 p1 = "bt"; 2500 goto Lshd; 2501 case 0xA4: 2502 p1 = SHLD; 2503 p4 = immed8(c + 2 + EAbytes(c + 1)); 2504 goto Lshd; 2505 case 0xA5: 2506 p1 = SHLD; 2507 p4 = bytereg[1]; /* "CL" */ 2508 goto Lshd; 2509 case 0xA8: 2510 p1 = "push"; 2511 p2 = "GS"; 2512 goto Ldone; 2513 case 0xA9: 2514 p1 = "pop"; 2515 p2 = "GS"; 2516 goto Ldone; 2517 case 0xAA: 2518 p1 = "rsm"; 2519 goto Ldone; 2520 case 0xAB: 2521 p1 = "bts"; 2522 goto Lshd; 2523 case 0xAC: 2524 p1 = SHRD; 2525 p4 = immed8(c + 2 + EAbytes(c + 1)); 2526 goto Lshd; 2527 case 0xAD: 2528 p1 = SHRD; 2529 p4 = bytereg[1]; /* "CL" */ 2530 Lshd: 2531 p2 = getEA(rex, c); 2532 reg = (code[c + 2] >> 3) & 7; 2533 p3 = ereg[reg] + opsize; 2534 goto Ldone; 2535 case 0xAE: 2536 switch (code[c + 2]) 2537 { 2538 case 0xE8: p1 = "lfence"; goto Ldone; 2539 case 0xF0: p1 = "mfence"; goto Ldone; 2540 case 0xF8: p1 = "sfence"; goto Ldone; 2541 default: 2542 break; 2543 } 2544 if ((code[c + 2] & 0xC0) != 0xC0) 2545 { 2546 __gshared const char[9][8] group15 = 2547 [ "fxsave","fxrstor","ldmxcsr","stmxcsr","xsave","xrstor","xsaveopt","clflush" ]; 2548 uint regf = (code[c + 2] >> 3) & 7; 2549 p1 = group15[regf].ptr; 2550 if (regf == 4 && rex & REX_W) 2551 p1 = "xsave64"; 2552 else if (regf == 5 && rex & REX_W) 2553 p1 = "xrstor64"; 2554 else if (regf == 6 && rex & REX_W) 2555 p1 = "xsaveopt64"; 2556 else 2557 p1 = group15[regf].ptr; 2558 p2 = getEA(rex, c); 2559 goto Ldone; 2560 } 2561 goto Ldone; 2562 case 0xAF: 2563 p1 = IMUL; 2564 break; 2565 case 0xB0: 2566 case 0xB1: 2567 p1 = "cmpxchg"; 2568 goto Lshd; 2569 case 0xB2: 2570 p1 = "lss"; 2571 break; 2572 case 0xB3: 2573 p1 = "btr"; 2574 goto Lshd; 2575 case 0xB4: 2576 p1 = "lfs"; 2577 break; 2578 case 0xB5: 2579 p1 = "lgs"; 2580 break; 2581 case 0xB6: 2582 p1 = "movzx"; 2583 break; 2584 case 0xB7: 2585 case 0xBF: 2586 { 2587 const opsizesave = opsize; 2588 p1 = (opcode == 0xB7) ? "movzx" : "movsx"; 2589 p2 = ereg[reg] + opsize; 2590 opsize = true; // operand is always a word 2591 p3 = getEA(rex, c); 2592 opsize = opsizesave; 2593 goto Ldone; 2594 } 2595 case 0xBA: 2596 { 2597 __gshared const char*[8] pszGrp8 = [ "bad0", "bad1", "bad2", 2598 "bad3", "bt", "bts", "btr", "btc" ]; 2599 p1 = pszGrp8[reg]; 2600 p2 = getEA(rex, c); 2601 p3 = immed8(c + 2 + EAbytes(c + 1)); 2602 goto Ldone; 2603 } 2604 case 0xBB: 2605 p1 = "btc"; 2606 goto Lshd; 2607 case 0xBC: 2608 p1 = "bsf"; 2609 break; 2610 case 0xBD: 2611 p1 = "bsr"; 2612 break; 2613 case 0xBE: 2614 p1 = "movsx"; 2615 break; 2616 case 0xC1: 2617 case 0xC0: 2618 p1 = "xadd"; 2619 p2 = ereg[reg]; 2620 p3 = getEA(rex, c); 2621 goto Ldone; 2622 case 0xC2: 2623 p1 = (opsize != defopsize) ? "cmppd" : "cmpps"; 2624 xmm_xmm_imm8(1); 2625 goto Ldone; 2626 Lxmm: 2627 p2 = xmmreg[(code[c + 2] >> 3) & 7]; 2628 p3 = getEA(rex, c); 2629 goto Ldone; 2630 Lmm: 2631 p2 = mmreg[(code[c + 2] >> 3) & 7]; 2632 p3 = getEA(rex, c); 2633 goto Ldone; 2634 case 0xC3: 2635 p1 = "movnti"; 2636 p2 = getEA(rex, c); 2637 p3 = ereg[reg]; 2638 goto Ldone; 2639 case 0xC4: 2640 p1 = "pinsrw"; 2641 p2 = (opsize != defopsize) ? xmmreg[reg] : mmreg[reg]; 2642 p3 = getEA(rex, c); 2643 p4 = immed8(c + 2 + EAbytes(c + 1)); 2644 goto Ldone; 2645 case 0xC5: 2646 if ((code[c + 2] & 0xC0) == 0xC0) 2647 { uint m = code[c + 2] & 7; 2648 p1 = "pextrw"; 2649 p2 = ereg[reg]; 2650 p3 = (opsize != defopsize) ? xmmreg[m] : mmreg[m]; 2651 p4 = immed8(c + 2 + EAbytes(c + 1)); 2652 goto Ldone; 2653 } 2654 break; 2655 case 0xC6: 2656 p1 = (opsize != defopsize) ? "shufpd" : "shufps"; 2657 xmm_xmm_imm8(0); 2658 //p4 = immed8(c + 2 + EAbytes(c + 1)); 2659 goto Ldone; 2660 case 0xC7: 2661 if (reg == 1) 2662 { 2663 /+ 2664 0F C7 /1 CMPXCHG8B m64 2665 REX.W + 0F C7 /1 CMPXCHG16B m128 2666 +/ 2667 p1 = rex & REX_W ? "cmpxchg16b" : "cmpxchg8b"; 2668 p2 = getEA(rex, c); 2669 goto Ldone; 2670 } 2671 if ((code[c + 2] & 0xC0) != 0xC0) 2672 { 2673 __gshared const char[9][8] grp15 = 2674 [ "?0","?1","?2","?3","xsavec","?5","?6","?7" ]; 2675 uint regf = (code[c + 2] >> 3) & 7; 2676 p1 = grp15[regf].ptr; 2677 if (regf == 4 && rex & REX_W) 2678 p1 = "xsavec64"; 2679 else 2680 p1 = grp15[regf].ptr; 2681 p2 = getEA(rex, c); 2682 goto Ldone; 2683 } 2684 break; 2685 case 0xC8: 2686 case 0xC9: 2687 case 0xCA: 2688 case 0xCB: 2689 case 0xCC: 2690 case 0xCD: 2691 case 0xCE: 2692 case 0xCF: 2693 p1 = "bswap"; 2694 p2 = ereg[opcode-0xc8]; 2695 goto Ldone; 2696 case 0xD0: 2697 if (opsize != defopsize) 2698 { 2699 p1 = "addsubpd"; 2700 p2 = xmmreg[reg]; 2701 p3 = getEAxmm(rex, c); 2702 goto Ldone; 2703 } 2704 break; 2705 case 0xD6: 2706 if (opsize != defopsize) 2707 { 2708 p1 = "movq"; 2709 p2 = getEAxmm(rex, c); 2710 p3 = xmmreg[reg]; 2711 goto Ldone; 2712 } 2713 break; 2714 case 0xD7: 2715 p1 = "pmovmskb"; 2716 p2 = ereg[reg]; 2717 if (opsize == defopsize) 2718 p3 = getEA(rex, c); 2719 else 2720 p3 = getEAxmm(rex, c); 2721 goto Ldone; 2722 case 0xE7: 2723 if (opsize == defopsize) 2724 { p1 = "movntq"; 2725 p2 = getEA(rex, c); 2726 p3 = mmreg[reg]; 2727 } 2728 else 2729 { p1 = "movntdq"; 2730 p2 = getEA(rex, c); 2731 p3 = xmmreg[reg]; 2732 } 2733 goto Ldone; 2734 case 0xE6: 2735 if (opsize == defopsize) 2736 break; 2737 p1 = "cvttpd2dq"; 2738 goto Lxmm; 2739 case 0xF7: 2740 if (opsize == defopsize) 2741 { 2742 p1 = "maskmovq"; 2743 goto Lmm; 2744 } 2745 else 2746 { p1 = "maskmovdqu"; 2747 p2 = xmmreg[(code[c + 2] >> 3) & 7]; 2748 inssize2[0xF7] = Y|3; 2749 p3 = getEA(rex, c); 2750 inssize2[0xF7] = X|3; 2751 goto Ldone; 2752 } 2753 default: 2754 break; 2755 } 2756 if (opcode >= 0x40 && opcode <= 0x4F) 2757 { __gshared const char*[16] cmov = 2758 [ "cmovo","cmovno","cmovb","cmovnb","cmovz","cmovnz","cmovbe","cmovnbe", 2759 "cmovs","cmovns","cmovp","cmovnp","cmovl","cmovnl","cmovle","cmovnle", 2760 ]; 2761 2762 p1 = cmov[opcode - 0x40]; 2763 p2 = ereg[reg] + opsize; 2764 p3 = getEA(rex, c); 2765 } 2766 else if (opcode >= 0x60 && opcode <= 0x76) 2767 { __gshared const char*[24] ps = 2768 [ "punpcklbw","punpcklwd","punpckldq","packsswb", 2769 "pcmpgtb","pcmpgtw","pcmpgtd","packuswb", 2770 "punpckhbw","punpckhwd","punpckhdq","packssdw", 2771 "punpcklqdq","punpckhqdq","movd","movq", 2772 null,null,null,null, 2773 "pcmpeqb","pcmpeqw","pcmpeqd",null, 2774 ]; 2775 2776 if (ps[opcode - 0x60]) 2777 { p1 = ps[opcode - 0x60]; 2778 p2 = mmreg[reg]; 2779 p3 = getEA(rex, c); 2780 if (opsize != defopsize) 2781 { 2782 switch (opcode) 2783 { 2784 case 0x60: 2785 case 0x61: 2786 case 0x62: 2787 case 0x63: 2788 case 0x64: 2789 case 0x65: 2790 case 0x66: 2791 case 0x67: 2792 case 0x68: 2793 case 0x69: 2794 case 0x6A: 2795 case 0x6B: 2796 case 0x6C: 2797 case 0x6D: 2798 case 0x74: 2799 case 0x75: 2800 case 0x76: 2801 p2 = xmmreg[reg]; 2802 p3 = getEAxmm(rex, c); 2803 break; 2804 2805 case 0x6E: 2806 p2 = xmmreg[reg]; 2807 break; 2808 2809 default: 2810 break; 2811 } 2812 } 2813 } 2814 } 2815 else if (opcode >= 0x90 && opcode <= 0x9F) 2816 { __gshared const char*[16] set = 2817 [ "seto","setno","setb","setnb","setz","setnz","setbe","setnbe", 2818 "sets","setns","setp","setnp","setl","setnl","setle","setnle", 2819 ]; 2820 2821 p1 = set[opcode - 0x90]; 2822 p2 = getEA(rex, c); 2823 } 2824 else if (opcode >= 0xD0) 2825 { 2826 enum .string dash = "----"; 2827 __gshared const char*[48] psx = 2828 [ dash,"psrlw","psrld","psrlq","paddq","pmullw",dash,dash, 2829 "psubusb","psubusw","pminub","pand","paddusb","paddusw","pmaxub","pandn", 2830 "pavgb","psraw","psrad","pavgw","pmulhuw","pmulhw",dash,dash, 2831 "psubsb","psubsw","pminsw","por","paddsb","paddsw","pmaxsw","pxor", 2832 dash,"psllw","pslld","psllq","pmuludq","pmaddwd","psadbw",dash, 2833 "psubb","psubw","psubd","psubq","paddb","paddw","paddd",dash, 2834 ]; 2835 2836 if (psx[opcode - 0xD0]) 2837 { 2838 p1 = psx[opcode - 0xD0]; 2839 p2 = mmreg[reg]; 2840 p3 = getEA(rex, c); 2841 if (opsize != defopsize) 2842 { 2843 switch (opcode) 2844 { 2845 case 0xD1: 2846 case 0xD2: 2847 case 0xD3: 2848 case 0xD4: 2849 case 0xD5: 2850 case 0xD8: 2851 case 0xD9: 2852 case 0xDA: 2853 case 0xDB: 2854 case 0xDC: 2855 case 0xDD: 2856 case 0xDE: 2857 case 0xDF: 2858 case 0xE0: 2859 case 0xE1: 2860 case 0xE2: 2861 case 0xE3: 2862 case 0xE4: 2863 case 0xE5: 2864 case 0xE8: 2865 case 0xE9: 2866 case 0xEA: 2867 case 0xEB: 2868 case 0xEC: 2869 case 0xED: 2870 case 0xEE: 2871 case 0xEF: 2872 case 0xF1: 2873 case 0xF2: 2874 case 0xF3: 2875 case 0xF4: 2876 case 0xF5: 2877 case 0xF6: 2878 case 0xF8: 2879 case 0xF9: 2880 case 0xFA: 2881 case 0xFB: 2882 case 0xFC: 2883 case 0xFD: 2884 case 0xFE: 2885 p2 = xmmreg[reg]; 2886 p3 = getEAxmm(rex, c); 2887 break; 2888 default: 2889 break; 2890 } 2891 } 2892 } 2893 } 2894 else if (inssize2[opcode] & W) /* conditional jump */ 2895 { p1 = jmpop[opcode & 0x0F]; 2896 uint offset = opsize ? word(code, c) : dword(code, c); 2897 p2 = labelcode(c + 2, offset, 0, opsize); 2898 } 2899 else 2900 { 2901 //printf("ereg = %p, reg = %d, opsize = %d opcode = %02x\n", ereg, reg, opsize, opcode); 2902 p2 = ereg[reg] + opsize; 2903 if (rex & REX_W) 2904 p2 = rreg[reg]; 2905 p3 = getEA(rex, c); 2906 } 2907 Ldone: 2908 } 2909 else 2910 { 2911 o3 = opcode >> 3; 2912 p1 = astring[o3]; 2913 i = (opcode & 7); 2914 //printf("test1: o3 = %d, i = %d\n", o3, i); 2915 if (i >= 6 && opcode < 0x40) 2916 { p1 = (i == 7) ? "pop" : "push"; 2917 p2 = segreg[o3 & 3]; 2918 if (o3 >= 4) 2919 { if (i == 6) 2920 p1 = "seg"; 2921 else 2922 { p1 = bstring[o3 - 4]; 2923 p2 = ""; 2924 } 2925 } 2926 } 2927 else if (opcode >= 0x40) 2928 { if (rex & REX_B) 2929 i += 8; 2930 p2 = ereg[i] + opsize; 2931 if ((o3 == 10 || o3 == 11) && model == 64) 2932 p2 = rreg[i]; // PUSH/POP rreg 2933 } 2934 else 2935 { switch (i) 2936 { case 0: p2 = getEA(rex, c); 2937 p3 = BREGNAME(rex, reg); 2938 break; 2939 case 1: p2 = getEA(rex, c); 2940 p3 = REGNAME(rex, reg); 2941 break; 2942 case 2: p2 = BREGNAME(rex, reg); 2943 p3 = getEA(rex, c); 2944 break; 2945 case 3: p2 = REGNAME(rex, reg); 2946 p3 = getEA(rex, c); 2947 break; 2948 case 4: p2 = "AL"; 2949 p3 = immed8(c + 1); 2950 break; 2951 case 5: p2 = ereg[0] + opsize; 2952 p3 = immed16(code, c + 1, opsize ? 2 : 4); 2953 break; 2954 default: 2955 break; 2956 } 2957 } 2958 } 2959 } 2960 else if ((opcode & 0xF0) == 0x70) 2961 { p1 = jmpop[opcode & 0xF]; 2962 p2 = shortlabel(c + 2, cast(byte)code[c + 1]); 2963 } 2964 else if (opcode >= 0x80 && opcode < 0x84) 2965 { 2966 __gshared const char*[8] regstring = 2967 [ "add","or","adc","sbb","and","sub","xor","cmp" ]; 2968 2969 i = c + 1 + EAbytes(c); 2970 p1 = regstring[reg]; 2971 p2 = getEA(rex, c); 2972 switch (opcode & 3) 2973 { case 0: 2974 case 2: p3 = immed8(i); break; 2975 case 3: p3 = immeds(i); break; 2976 case 1: p3 = immed16(code, i, opsize ? 2 : 4); break; 2977 default: assert(0); 2978 } 2979 } 2980 else if (opcode >= 0x84 && opcode < 0x8C) 2981 { 2982 p1 = (opcode <= 0x85) ? "test" : 2983 (opcode <= 0x87) ? XCHG : MOV; 2984 if (rex & REX_R) 2985 reg |= 8; 2986 switch (opcode & 3) 2987 { case 0: p2 = getEA(rex, c); p3 = BREGNAME(rex, reg); break; 2988 case 1: p2 = getEA(rex, c); p3 = REGNAME(rex, reg); break; 2989 case 2: p2 = BREGNAME(rex, reg); p3 = getEA(rex, c); break; 2990 case 3: p2 = REGNAME(rex, reg); p3 = getEA(rex, c); break; 2991 default: assert(0); 2992 } 2993 } 2994 else if (opcode >= 0x91 && opcode <= 0x97) /* XCHG */ 2995 { 2996 p2 = REGNAME(rex, 0); 2997 p3 = ereg[opcode & 7] + opsize; 2998 } 2999 else if (opcode >= 0xB0 && opcode < 0xB8) 3000 { 3001 uint r = opcode & 7; 3002 if (rex & REX_B) 3003 r |= 8; 3004 p2 = BREGNAME(rex, r); 3005 p3 = immed8(c + 1); 3006 } 3007 else if (opcode >= 0xB8 && opcode < 0xC0) /* MOV reg,iw */ 3008 { 3009 uint r = opcode & 7; 3010 int sz2 = opsize ? 2 : 4; 3011 if (rex & REX_B) 3012 r |= 8; 3013 if (rex & REX_W) 3014 { p2 = rreg[r]; 3015 sz2 = 8; 3016 } 3017 else 3018 p2 = ereg[r] + opsize; 3019 p3 = immed16(code, c + 1, sz2); 3020 } 3021 else if (opcode >= 0xD8 && opcode <= 0xDF) 3022 { 3023 get87string(c,p0.ptr,fwait); 3024 return; 3025 } 3026 else 3027 { 3028 switch (opcode) 3029 { 3030 case 0xC0: 3031 case 0xC1: p3 = immed8(c + 1 + EAbytes(c)); goto shifts; 3032 case 0xD0: 3033 case 0xD1: p3 = "1"; goto shifts; 3034 case 0xD2: 3035 case 0xD3: p3 = "CL"; goto shifts; 3036 shifts: 3037 { __gshared const char*[8] shift = 3038 [ "rol","ror","rcl","rcr","shl","shr","?6","sar" ]; 3039 3040 p1 = shift[reg]; 3041 p2 = getEA(rex, c); 3042 } 3043 break; 3044 case 0x60: 3045 if (opsize) 3046 p1 = "pusha"; 3047 else 3048 p1 = "pushad"; 3049 break; 3050 case 0x61: 3051 if (opsize) 3052 p1 = "popa"; 3053 else 3054 p1 = "popad"; 3055 break; 3056 case 0x62: 3057 p1 = "bound"; 3058 p2 = ereg[reg]+opsize; 3059 p3 = getEA(rex, c); 3060 break; 3061 case 0x63: 3062 if (model == 64) 3063 { p1 = "movsxd"; 3064 p2 = rreg[reg]; 3065 p3 = getEA(rex, c); 3066 } 3067 else 3068 { p1 = "arpl"; 3069 p2 = getEA(rex, c); 3070 p3 = wordreg[reg]; 3071 } 3072 break; 3073 3074 case 0x64: 3075 p1 = "seg"; 3076 p2 = "FS"; 3077 break; 3078 case 0x65: 3079 p1 = "seg"; 3080 p2 = "GS"; 3081 break; 3082 case 0x66: 3083 p1 = "opsize"; 3084 break; 3085 case 0x67: 3086 p1 = "adsize"; 3087 break; 3088 case 0x68: 3089 p2 = immed16(code, c + 1, opsize ? 2 : 4); 3090 goto Lpush; 3091 case 0x69: 3092 case 0x6B: 3093 p1 = IMUL; 3094 p2 = ereg[reg] + opsize; 3095 p3 = getEA(rex, c); 3096 i = c + 1 + EAbytes(c); 3097 p4 = (opcode == 0x69) ? immed16(code, i, opsize ? 2 : 4) 3098 : immeds(i); 3099 break; 3100 case 0x6C: 3101 p1 = "insb"; 3102 break; 3103 case 0x6d: 3104 if (opsize) 3105 p1 = "insw"; 3106 else 3107 p1 = "insd"; 3108 break; 3109 case 0x6e: 3110 p1 = "outsb"; 3111 break; 3112 case 0x6f: 3113 if (opsize) 3114 p1 = "outsw"; 3115 else 3116 p1 = "outsd"; 3117 break; 3118 case 0x6A: 3119 p2 = immeds(c + 1); 3120 Lpush: 3121 p1 = "push"; 3122 if (opsize != defopsize) 3123 { snprintf(buf.ptr,buf.length,"dword ptr %s",p2); 3124 p2 = buf.ptr + opsize; 3125 } 3126 break; 3127 case 0x8C: 3128 p1 = MOV; 3129 p2 = getEA(rex, c); 3130 p3 = segreg[reg]; 3131 break; 3132 case 0x8D: 3133 p1 = "lea"; 3134 if (rex & REX_W) 3135 p2 = rreg[reg]; 3136 else 3137 p2 = ereg[reg] + opsize; 3138 p3 = getEA(rex, c); 3139 break; 3140 case 0x8E: 3141 p1 = MOV; 3142 p2 = segreg[reg]; 3143 p3 = getEA(rex, c); 3144 break; 3145 case 0x8F: 3146 if (reg == 0) 3147 { p1 = "pop"; 3148 p2 = getEA(rex, c); 3149 } 3150 break; 3151 case 0x9A: 3152 case 0xEA: 3153 p2 = "far ptr"; 3154 sep = " "; 3155 uint offset = opsize ? word(code, c) : dword(code, c); 3156 p3 = labelcode(c + 1, offset, 1, opsize); 3157 break; 3158 case 0xA0: 3159 p2 = "AL"; 3160 s3 = segover; 3161 uint value = adsize ? dword(code, c + 1) : word(code, c + 1); 3162 p3 = mem(c + 1, adsize ? 4 : 2, value); 3163 break; 3164 case 0xA1: 3165 p2 = ereg[AX] + opsize; 3166 s3 = segover; 3167 uint value = adsize ? dword(code, c + 1) : word(code, c + 1); 3168 p3 = mem(c + 1, adsize ? 4 : 2, value); 3169 break; 3170 case 0xA2: 3171 s2 = segover; 3172 uint value = adsize ? dword(code, c + 1) : word(code, c + 1); 3173 p2 = mem(c + 1, adsize ? 4 : 2, value); 3174 p3 = "AL"; 3175 break; 3176 case 0xA3: 3177 s2 = segover; 3178 uint value = adsize ? dword(code, c + 1) : word(code, c + 1); 3179 p2 = mem(c + 1, adsize ? 4 : 2, value); 3180 p3 = ereg[AX] + opsize; 3181 break; 3182 case 0xA8: 3183 case 0xE4: 3184 p2 = "AL"; 3185 p3 = immed8(c + 1); 3186 break; 3187 case 0xE6: 3188 p2 = immed8(c + 1); 3189 p3 = "AL"; 3190 break; 3191 case 0xA9: /* TEST */ 3192 p2 = ereg[AX] + opsize; 3193 p3 = immed16(code, c + 1, opsize ? 2 : 4); 3194 break; 3195 case 0xC2: /* RETN */ 3196 case 0xCA: /* RETF */ 3197 { const opsizesave = opsize; 3198 opsize = 1; // operand is always a word 3199 p2 = immed16(code, c + 1, 2); 3200 opsize = opsizesave; 3201 break; 3202 } 3203 case 0xC4: /* LES */ 3204 case 0xC5: /* LDS */ 3205 p2 = ereg[reg] + opsize; 3206 p3 = getEA(rex, c); 3207 break; 3208 case 0xC6: 3209 if (reg == 0) 3210 { 3211 p1 = MOV; 3212 p2 = getEA(rex, c); 3213 p3 = immed8(c + 1 + EAbytes(c)); 3214 } 3215 break; 3216 case 0xC7: 3217 if (reg == 0) 3218 { 3219 p1 = MOV; 3220 p2 = getEA(rex, c); 3221 p3 = immed16(code, c + 1 + EAbytes(c), opsize ? 2 : 4); 3222 } 3223 break; 3224 case 0xC8: /* ENTER imm16,imm8 */ 3225 { 3226 __gshared char[2+4+1] tmp; 3227 3228 p2 = strcpy(tmp.ptr,wordtostring(word(code, c + 1))); 3229 p3 = immed8(c + 3); 3230 break; 3231 } 3232 case 0xCC: /* INT 3 */ 3233 p2 = "3"; 3234 break; 3235 case 0xCD: /* INT */ 3236 p2 = immed8(c + 1); 3237 break; 3238 case 0xE0: /* LOOPNZ */ 3239 case 0xE1: /* LOOPZ */ 3240 case 0xE2: /* LOOP */ 3241 case 0xE3: /* JCXZ */ 3242 case 0xEB: /* JMP SHORT */ 3243 p2 = shortlabel(c + 2, cast(byte)code[c + 1]); 3244 break; 3245 case 0xE5: 3246 p2 = ereg[AX] + opsize; 3247 p3 = immed8(c + 1); 3248 break; 3249 case 0xE7: 3250 p2 = immed8(c + 1); 3251 p3 = ereg[AX] + opsize; 3252 break; 3253 case 0xE8: 3254 case 0xE9: 3255 p2 = nearptr ? "near ptr" : " "; 3256 sep = ""; 3257 uint offset = opsize ? word(code, c + 1) : dword(code, c + 1); 3258 p3 = labelcode(c + 1, offset, 0, opsize); 3259 break; 3260 case 0xEC: 3261 p2 = "AL,DX"; 3262 break; 3263 case 0xED: 3264 p2 = ereg[AX] + opsize; 3265 p3 = "DX"; 3266 break; 3267 case 0xEE: 3268 p2 = "DX,AL"; 3269 break; 3270 case 0xEF: 3271 p2 = "DX"; 3272 p3 = ereg[AX] + opsize; 3273 break; 3274 case 0xF6: 3275 case 0xF7: 3276 p1 = mulop[reg]; 3277 p2 = getEA(rex, c); 3278 if (reg == 0) 3279 { p3 = (opcode == 0xF6) ? 3280 immed8(c + 1 + EAbytes(c)) : 3281 immed16(code, c + 1 + EAbytes(c), opsize ? 2 : 4); 3282 } 3283 break; 3284 case 0xFE: 3285 case 0xFF: 3286 if (reg < 2) 3287 { p1 = (reg == 0) ? "inc" : "dec"; 3288 } 3289 else if (reg < 7 && opcode == 0xFF) 3290 { 3291 __gshared const char*[5] op = 3292 [ "call","callf","jmp","jmpf","push" ]; 3293 3294 p1 = op[reg - 2]; 3295 } 3296 p2 = getEA(rex, c); 3297 break; 3298 default: 3299 break; 3300 } 3301 } 3302 puts(p0.ptr); 3303 put(' '); 3304 puts(p1); 3305 if (*p2) 3306 { 3307 for (int len1 = cast(int)strlen(p1); len1 < 9; ++len1) 3308 put(' '); 3309 put(' '); 3310 puts(s2); 3311 if (*p2 != ' ') 3312 puts(p2); 3313 if (*p3) 3314 { 3315 puts(sep); 3316 puts(s3); 3317 puts(p3); 3318 if (*p4) 3319 { 3320 put(','); 3321 puts(p4); 3322 } 3323 } 3324 } 3325 } 3326 3327 } 3328 3329 /*********************** 3330 * Default version. 3331 * Creates string representation of memory location. 3332 * Params: 3333 * c = the address of the memory reference in `code[]` 3334 * sz = the number of bytes in the referred to memory location 3335 * offset = the value to be added to any symbolic reference 3336 * Returns: 3337 * string representation of the memory address 3338 */ 3339 @trusted 3340 const(char)* memoryDefault(uint c, uint sz, addr offset) 3341 { 3342 __gshared char[12 + 1] EA; 3343 snprintf(EA.ptr,EA.length,"[0%Xh]",offset); 3344 return EA.ptr; 3345 } 3346 3347 /*********************** 3348 * Default version. 3349 * Creates string representation of immediate value. 3350 * Params: 3351 * code = the binary instructions 3352 * c = the address of the memory reference in `code[]` 3353 * sz = the number of bytes in the instruction that form the referenece (2/4/8) 3354 * Returns: 3355 * string representation of the memory address 3356 */ 3357 @trusted 3358 const(char)* immed16Default(ubyte[] code, uint c, int sz) 3359 { 3360 ulong offset; 3361 switch (sz) 3362 { 3363 case 8: 3364 offset = dword(code, c) + (cast(ulong)dword(code, c + 4) << 32); 3365 break; 3366 3367 case 4: 3368 offset = dword(code, c); 3369 break; 3370 3371 case 2: 3372 offset = word(code, c); 3373 break; 3374 3375 default: 3376 assert(0); 3377 } 3378 __gshared char[1 + offset.sizeof * 3 + 1 + 1] buf; 3379 3380 snprintf(buf.ptr, buf.length,((cast(long)offset < 10) ? "%lld" : "0%llXh"), offset); 3381 return buf.ptr; 3382 } 3383 3384 /*********************** 3385 * Default version. 3386 * Creates string representation of code label. 3387 * Params: 3388 * c = the address of the code reference to the label in `code[]` 3389 * offset = address of the label in `code[]` 3390 * farflag = if `far` reference 3391 * is16bit = if 16 bit reference 3392 * Returns: 3393 * string representation of the memory address 3394 */ 3395 @trusted 3396 const(char)* labelcodeDefault(uint c, uint offset, bool farflag, bool is16bit) 3397 { 3398 //printf("offset = %x\n", offset); 3399 __gshared char[1 + uint.sizeof * 3 + 1] buf; 3400 snprintf(buf.ptr, buf.length, "L%x", offset); 3401 return buf.ptr; 3402 } 3403 3404 /*********************** 3405 * Default version. 3406 * Params: 3407 * pc = program counter 3408 * offset = add to pc to get address of target 3409 * Returns: 3410 * string representation of the memory address 3411 */ 3412 @trusted 3413 const(char)* shortlabelDefault(uint pc, int offset) 3414 { 3415 __gshared char[1 + ulong.sizeof * 3 + 1] buf; 3416 snprintf(buf.ptr, buf.length, "L%x", pc + offset); 3417 return buf.ptr; 3418 } 3419 3420 /***************************** 3421 * Load word at code[c]. 3422 */ 3423 3424 uint word(ubyte[] code, uint c) @safe 3425 { 3426 return code[c] + (code[c + 1] << 8); 3427 } 3428 3429 /***************************** 3430 * Load dword at code[c]. 3431 */ 3432 3433 addr dword(ubyte[] code, uint c) 3434 { 3435 return word(code, c) + (cast(addr) word(code, c + 2) << 16); 3436 } 3437 3438 /************************************* 3439 */ 3440 @trusted 3441 const(char)* wordtostring(uint w) 3442 { 3443 __gshared char[1 + w.sizeof * 3 + 1 + 1] EA; 3444 3445 snprintf(EA.ptr, EA.length, ((w < 10) ? "%ld" : "0%lXh"), w); 3446 return EA.ptr; 3447 } 3448 3449 3450 /************* 3451 * Size in bytes of each instruction. 3452 * 0 means illegal instruction. 3453 * X: EA is MMX register 3454 * Y: EA is XMM register 3455 * B: transfer with byte offset 3456 * W: transfer with word/dword offset 3457 * U: unconditional transfer (jmps and returns) 3458 * M: if there is a modregrm field (EV1 is reserved for modregrm) 3459 * T: if there is a second operand (EV2) 3460 * E: if second operand is only 8 bits 3461 * A: a short version exists for the AX reg 3462 * R: a short version exists for regs 3463 * bits 2..0: size of instruction (excluding optional bytes) 3464 */ 3465 3466 enum X = (0x800 | M); 3467 enum Y = (0x1000 | M); 3468 enum B = 0x400; 3469 enum R = 0x200; 3470 enum U = 0x100; 3471 enum M = 0x80; 3472 enum T = 0x40; 3473 enum E = 0x20; 3474 enum A = 0x10; 3475 enum W = 0x08; 3476 3477 __gshared uint[256] inssize = 3478 [ 3479 M|2,M|2,M|2,M|2, T|E|2,T|3,1,1, /* 00 */ 3480 M|2,M|2,M|2,M|2, T|E|2,T|3,1,1, /* 08 */ 3481 M|2,M|2,M|2,M|2, T|E|2,T|3,1,1, /* 10 */ 3482 M|2,M|2,M|2,M|2, T|E|2,T|3,1,1, /* 18 */ 3483 M|2,M|2,M|2,M|2, T|E|2,T|3,1,1, /* 20 */ 3484 M|2,M|2,M|2,M|2, T|E|2,T|3,1,1, /* 28 */ 3485 M|2,M|2,M|2,M|2, T|E|2,T|3,1,1, /* 30 */ 3486 M|2,M|2,M|2,M|2, T|E|2,T|3,1,1, /* 38 */ 3487 1,1,1,1, 1,1,1,1, /* 40 */ 3488 1,1,1,1, 1,1,1,1, /* 48 */ 3489 1,1,1,1, 1,1,1,1, /* 50 */ 3490 1,1,1,1, 1,1,1,1, /* 58 */ 3491 1,1,M|2,M|2, 1,1,1,1, /* 60 */ 3492 T|3,M|T|4,T|E|2,M|T|E|3, 1,1,1,1, /* 68 */ 3493 B|T|E|2,B|T|E|2,B|T|E|2,B|T|E|2, B|T|E|2,B|T|E|2,B|T|E|2,B|T|E|2, 3494 B|T|E|2,B|T|E|2,B|T|E|2,B|T|E|2, B|T|E|2,B|T|E|2,B|T|E|2,B|T|E|2, 3495 M|T|E|A|3,M|T|A|4,M|T|E|3,M|T|E|3, M|2,M|2,M|2,M|A|R|2, /* 80 */ 3496 M|A|2,M|A|2,M|A|2,M|A|2, M|2,M|2,M|2,M|R|2, /* 88 */ 3497 1,1,1,1, 1,1,1,1, /* 90 */ 3498 1,1,T|5,1, 1,1,1,1, /* 98 */ 3499 T|3,T|3,T|3,T|3, 1,1,1,1, /* A0 */ 3500 T|E|2,T|3,1,1, 1,1,1,1, /* A8 */ 3501 T|E|2,T|E|2,T|E|2,T|E|2, T|E|2,T|E|2,T|E|2,T|E|2, /* B0 */ 3502 T|3,T|3,T|3,T|3, T|3,T|3,T|3,T|3, /* B8 */ 3503 M|T|E|3,M|T|E|3,U|T|3,U|1, M|2,M|2,M|T|E|R|3,M|T|R|4, /* C0 */ 3504 T|E|4,1,U|T|3,U|1, 1,T|E|2,1,U|1, /* C8 */ 3505 M|2,M|2,M|2,M|2, T|E|2,T|E|2,1,1, /* D0 */ 3506 M|2,M|2,M|2,M|2, M|2,M|2,M|2,M|2, /* D8 */ 3507 B|T|E|2,B|T|E|2,B|T|E|2,B|T|E|2, T|E|2,T|E|2,T|E|2,T|E|2, /* E0 */ 3508 W|T|3,W|U|T|3,U|T|5,B|U|T|E|2, 1,1,1,1, /* E8 */ 3509 1,1,1,1, 1,1,M|A|2,M|A|2, /* F0 */ 3510 1,1,1,1, 1,1,M|2,M|R|2 /* F8 */ 3511 ]; 3512 3513 /* 386 instruction sizes */ 3514 3515 __gshared const ubyte[256] inssize32 = 3516 [ 3517 2,2,2,2, 2,5,1,1, /* 00 */ 3518 2,2,2,2, 2,5,1,1, /* 08 */ 3519 2,2,2,2, 2,5,1,1, /* 10 */ 3520 2,2,2,2, 2,5,1,1, /* 18 */ 3521 2,2,2,2, 2,5,1,1, /* 20 */ 3522 2,2,2,2, 2,5,1,1, /* 28 */ 3523 2,2,2,2, 2,5,1,1, /* 30 */ 3524 2,2,2,2, 2,5,1,1, /* 38 */ 3525 1,1,1,1, 1,1,1,1, /* 40 */ 3526 1,1,1,1, 1,1,1,1, /* 48 */ 3527 1,1,1,1, 1,1,1,1, /* 50 */ 3528 1,1,1,1, 1,1,1,1, /* 58 */ 3529 1,1,2,2, 1,1,1,1, /* 60 */ 3530 5,6,2,3, 1,1,1,1, /* 68 */ 3531 2,2,2,2, 2,2,2,2, /* 70 */ 3532 2,2,2,2, 2,2,2,2, /* 78 */ 3533 3,6,3,3, 2,2,2,2, /* 80 */ 3534 2,2,2,2, 2,2,2,2, /* 88 */ 3535 1,1,1,1, 1,1,1,1, /* 90 */ 3536 1,1,7,1, 1,1,1,1, /* 98 */ 3537 5,5,5,5, 1,1,1,1, /* A0 */ 3538 2,5,1,1, 1,1,1,1, /* A8 */ 3539 2,2,2,2, 2,2,2,2, /* B0 */ 3540 5,5,5,5, 5,5,5,5, /* B8 */ 3541 3,3,3,1, 2,2,3,6, /* C0 */ 3542 4,1,3,1, 1,2,1,1, /* C8 */ 3543 2,2,2,2, 2,2,1,1, /* D0 */ 3544 /* For the floating instructions, don't leave room for the FWAIT */ 3545 2,2,2,2, 2,2,2,2, /* D8 */ 3546 3547 2,2,2,2, 2,2,2,2, /* E0 */ 3548 5,5,7,2, 1,1,1,1, /* E8 */ 3549 1,1,1,1, 1,1,2,2, /* F0 */ 3550 1,1,1,1, 1,1,2,2 /* F8 */ 3551 ]; 3552 3553 /* For 2 byte opcodes starting with 0x0F */ 3554 __gshared uint[256] inssize2 = 3555 [ 3556 M|3,M|3,M|3,M|3, M|3,M|3,M|3,M|3, // 00 3557 M|3,M|3,M|3,2, M|3,M|3,M|3,X|T|E|4, // 08 3558 Y|3,Y|3,Y|3,Y|3, Y|3,Y|3,Y|3,Y|3, // 10 3559 M|3,M|3,M|3,2, M|3,M|3,M|3,M|3, // 18 3560 M|3,M|3,M|3,M|3, M|3,M|3,M|3,2, // 20 3561 Y|3,Y|3,X|3,Y|3, Y|3,Y|3,Y|3,Y|3, // 28 3562 2,2,2,2, 2,2,2,2, // 30 3563 Y|4,M|3,Y|T|E|5,M|3, M|3,M|3,M|3,M|3, // 38 3564 M|3,M|3,M|3,M|3, M|3,M|3,M|3,M|3, // 40 3565 M|3,M|3,M|3,M|3, M|3,M|3,M|3,M|3, // 48 3566 Y|3,Y|3,Y|3,Y|3, Y|3,Y|3,Y|3,Y|3, // 50 3567 Y|3,Y|3,Y|3,Y|3, Y|3,Y|3,Y|3,Y|3, // 58 3568 X|3,X|3,X|3,X|3, X|3,X|3,X|3,X|3, // 60 3569 X|3,X|3,X|3,X|3, X|3,X|3,M|3,X|3, // 68 3570 X|T|E|4,X|T|E|4,X|T|E|4,X|T|E|4, X|3,X|3,X|3,2, // 70 3571 2,2,2,2, X|3,X|3,M|3,X|3, // 78 3572 W|T|4,W|T|4,W|T|4,W|T|4, W|T|4,W|T|4,W|T|4,W|T|4, // 80 3573 W|T|4,W|T|4,W|T|4,W|T|4, W|T|4,W|T|4,W|T|4,W|T|4, // 88 3574 M|3,M|3,M|3,M|3, M|3,M|3,M|3,M|3, // 90 3575 M|3,M|3,M|3,M|3, M|3,M|3,M|3,M|3, // 98 3576 2,2,2,M|3, M|T|E|4,M|3,M|3,M|3, // A0 3577 M|3,M|3,M|3,M|3, M|T|E|4,M|3,M|3,M|3, // A8 3578 M|E|3,M|3,M|3,M|3, M|3,M|3,M|3,M|3, // B0 3579 M|3,M|3,M|T|E|4,M|3, M|3,M|3,M|3,M|3, // B8 3580 M|3,M|3,Y|T|E|4,M|3, M|T|E|4,M|T|E|4,Y|T|E|4,M|3, // C0 3581 2,2,2,2, 2,2,2,2, // C8 3582 X|3,X|3,X|3,X|3, X|3,X|3,X|3,X|3, // D0 3583 X|3,X|3,X|3,X|3, X|3,X|3,Y|3,X|3, // D8 3584 X|3,X|3,X|3,X|3, X|3,X|3,Y|3,Y|3, // E0 3585 X|3,X|3,X|3,X|3, X|3,X|3,Y|3,X|3, // E8 3586 Y|3,X|3,X|3,X|3, X|3,X|3,X|3,X|3, // F0 3587 X|3,X|3,X|3,X|3, X|3,X|3,X|3,2 // F8 3588 ]; 3589 3590 __gshared const 3591 { 3592 char*[16] rreg = [ "RAX","RCX","RDX","RBX","RSP","RBP","RSI","RDI", 3593 "R8","R9","R10","R11","R12","R13","R14","R15" ]; 3594 char*[16] ereg = [ "EAX","ECX","EDX","EBX","ESP","EBP","ESI","EDI", 3595 "R8D","R9D","R10D","R11D","R12D","R13D","R14D","R15D" ]; 3596 char*[16] wordreg = [ "AX","CX","DX","BX","SP","BP","SI","DI", 3597 "R8W","R9W","R10W","R11W","R12W","R13W","R14W","R15W" ]; 3598 char*[16] byteregrex = [ "AL","CL","DL","BL","SPL","BPL","SIL","DIL", 3599 "R8B","R9B","R10B","R11B","R12B","R13B","R14B","R15B" ]; 3600 char*[8] bytereg = [ "AL","CL","DL","BL","AH","CH","DH","BH" ]; 3601 char*[8] mmreg = [ "MM0","MM1","MM2","MM3","MM4","MM5","MM6","MM7" ]; 3602 char*[16] xmmreg = [ "XMM0","XMM1","XMM2","XMM3","XMM4","XMM5","XMM6","XMM7", 3603 "XMM8","XMM9","XMM10","XMM11","XMM12","XMM13","XMM14","XMM15" ]; 3604 char*[16] ymmreg = [ "YMM0","YMM1","YMM2","YMM3","YMM4","YMM5","YMM6","YMM7", 3605 "YMM8","YMM9","YMM10","YMM11","YMM12","YMM13","YMM14","YMM15" ]; 3606 } 3607 3608 /************************************* Tests ***********************************/ 3609 3610 unittest 3611 { 3612 int line16 = __LINE__; 3613 string[20] cases16 = // 16 bit code gen 3614 [ 3615 " 55 push BP", 3616 " 8B EC mov BP,SP", 3617 " 8B 46 04 mov AX,4[BP]", 3618 " 83 C0 05 add AX,5", 3619 " 5D pop BP", 3620 " C3 ret", 3621 " 83 7E 08 00 cmp word ptr 8[BP],0", 3622 " 74 05 je L7", 3623 " D1 66 08 shl word ptr 8[BP],1", 3624 " EB F5 jmp short Lfffffff7", 3625 " C4 5E 04 les BX,4[BP]", 3626 "26 8B 07 mov AX,ES:[BX]", 3627 "26 03 47 10 add AX,ES:010h[BX]", 3628 " 8B 4E 08 mov CX,8[BP]", 3629 " 83 C1 FD add CX,0FFFFFFFDh", 3630 " D1 E1 shl CX,1", 3631 " 03 D9 add BX,CX", 3632 "26 03 07 add AX,ES:[BX]", 3633 " 03 06 00 00 add AX,[00h]", 3634 " 31 C0 xor AX,AX", 3635 ]; 3636 3637 int line32 = __LINE__; 3638 string[16] cases32 = // 32 bit code gen 3639 [ 3640 "8B 44 24 04 mov EAX,4[ESP]", 3641 "83 C0 05 add EAX,5", 3642 "83 7C 24 08 00 cmp dword ptr 8[ESP],0", 3643 "74 06 je L8", 3644 "D1 64 24 08 shl dword ptr 8[ESP],1", 3645 "EB F3 jmp short Lfffffff5", 3646 "8B 00 mov EAX,[EAX]", 3647 "8B 4C 24 04 mov ECX,4[ESP]", 3648 "03 41 20 add EAX,020h[ECX]", 3649 "8B 54 24 08 mov EDX,8[ESP]", 3650 "83 C2 FD add EDX,0FFFFFFFDh", 3651 "03 04 91 add EAX,[EDX*4][ECX]", 3652 "03 05 00 00 00 00 add EAX,[00h]", 3653 "C3 ret", 3654 "31 C0 xor EAX,EAX", 3655 "0F 31 rdtsc", 3656 ]; 3657 3658 int line64 = __LINE__; 3659 string[26] cases64 = // 64 bit code gen 3660 [ 3661 "31 C0 xor EAX,EAX", 3662 "48 89 4C 24 08 mov 8[RSP],RCX", 3663 "48 89 D0 mov RAX,RDX", 3664 "48 03 44 24 08 add RAX,8[RSP]", 3665 "C3 ret", 3666 "0F 30 wrmsr", 3667 "0F 31 rdtsc", 3668 "0F 32 rdmsr", 3669 "0F 33 rdpmc", 3670 "0F 34 sysenter", 3671 "0F 35 sysexit", 3672 "BE 12 00 00 00 mov ESI,012h", 3673 "BF 00 00 00 00 mov EDI,0", 3674 "41 0F C7 09 cmpxchg8b [R9]", 3675 "49 0F C7 09 cmpxchg16b [R9]", 3676 "0F 01 F9 rdtscp", 3677 "66 41 0F 70 C7 66 pshufd XMM0,XMM15,066h", 3678 "F2 41 0F 70 C7 F1 pshuflw XMM0,XMM15,0F1h", 3679 "F3 41 0F 70 C7 C2 pshufhw XMM0,XMM15,0C2h", 3680 "66 41 0F C6 C7 CF shufpd XMM0,XMM15,0CFh", 3681 "66 0F C6 00 CF shufpd XMM0,[RAX],0CFh", 3682 "66 0F C2 00 CF cmppd XMM0,[RAX],0CFh", 3683 "F3 41 0F C2 C7 AF cmpss XMM0,XMM15,0C7h", 3684 "66 0F 73 FF 99 pslldq XMM7,099h", 3685 "F3 0F 1E FB endbr32", 3686 "F3 0F 1E FA endbr64", 3687 ]; 3688 3689 char[BUFMAX] buf; 3690 ubyte[BUFMAX] buf2; 3691 bool errors; 3692 3693 void testcase(int line, string s, uint size) 3694 { 3695 auto codput = Output!ubyte(buf2[]); 3696 size_t j; 3697 auto code = hexToUbytes(codput, j, s); 3698 string expected = s[j .. $]; 3699 3700 addr m; 3701 auto length = calccodsize(code, 0, m, size); 3702 3703 auto output = Output!char(buf[]); 3704 getopstring(&output.put, code, 0, length, 3705 size, 0, 0, null, null, null, null); 3706 auto result = output.peek(); 3707 3708 static bool compareEqual(const(char)[] result, const(char)[] expected) 3709 { 3710 size_t r, e; 3711 while (1) 3712 { 3713 while (r < result.length && (result[r] == ' ' || result[r] == '\t')) 3714 ++r; 3715 while (e < expected.length && (expected[e] == ' ' || expected[e] == '\t')) 3716 ++e; 3717 3718 if ((r == result.length) != (e == expected.length)) 3719 return false; 3720 3721 if (r == result.length) 3722 return true; 3723 3724 if (result[r] != expected[e]) 3725 return false; 3726 3727 ++r; 3728 ++e; 3729 } 3730 } 3731 3732 if (!compareEqual(result, expected)) 3733 { 3734 printf("Fail%d: %d '%.*s' '%.*s'\n", 3735 size, cast(int)(line + 2), 3736 cast(int)expected.length, expected.ptr, cast(int)result.length, result.ptr); 3737 errors = true; 3738 } 3739 } 3740 3741 foreach (i; 0 .. cases16.length) 3742 testcase(line16, cases16[i], 16); 3743 3744 foreach (i; 0 .. cases32.length) 3745 testcase(line32, cases32[i], 32); 3746 3747 foreach (i; 0 .. cases64.length) 3748 testcase(line64, cases64[i], 64); 3749 3750 assert(!errors); 3751 } 3752 3753 version (unittest) 3754 { 3755 3756 /********************** 3757 * Converts hex string prefix in `s` in test cases to ubyte[] 3758 * Params: 3759 * output = where to write the ubyte's 3760 * m = index of start of expected result 3761 * s = ascii source 3762 * Returns: 3763 * converted ubyte[] 3764 */ 3765 ubyte[] hexToUbytes(ref Output!ubyte output, out size_t m, string s) 3766 { 3767 uint n = 0; 3768 ubyte v = 0; 3769 3770 Loop: 3771 foreach (i, cc; s) 3772 { 3773 m = i; 3774 char c = cc; 3775 switch (c) 3776 { 3777 case ' ': 3778 case '\t': 3779 case '\v': 3780 case '\f': 3781 case '\r': 3782 case '\n': 3783 continue; // skip white space 3784 3785 case 0: 3786 case 0x1A: 3787 printf("unterminated string constant at %d\n", cast(int)i); 3788 assert(0); 3789 3790 case '0': .. case '9': 3791 c -= '0'; 3792 break; 3793 3794 case 'A': .. case 'F': 3795 c -= 'A' - 10; 3796 break; 3797 3798 default: 3799 break Loop; 3800 } 3801 if (n & 1) 3802 { 3803 v = cast(ubyte)((v << 4) | c); 3804 output.put(v); 3805 v = 0; 3806 } 3807 else 3808 v = c; 3809 ++n; 3810 } 3811 if (n & 1) 3812 { 3813 printf("unterminated string constant\n"); 3814 assert(0); 3815 } 3816 return output.peek; 3817 } 3818 3819 struct Output(T) 3820 { 3821 nothrow @nogc: 3822 3823 T[] buf; 3824 size_t i; 3825 3826 void put(T c) 3827 { 3828 buf[i] = c; 3829 ++i; 3830 } 3831 3832 void initialize(T[] buf) 3833 { 3834 this.buf = buf; 3835 i = 0; 3836 } 3837 3838 T[] peek() 3839 { 3840 return buf[0 .. i]; 3841 } 3842 } 3843 3844 }