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