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