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