1 /////////////////////////////////////////////////////////////////////////
2 // $Id: resolve.cc 11863 2013-10-07 19:23:19Z sshwarts $
3 /////////////////////////////////////////////////////////////////////////
4 //
5 //   Copyright (c) 2005-2013 Stanislav Shwartsman
6 //          Written by Stanislav Shwartsman [sshwarts at sourceforge net]
7 //
8 //  This library is free software; you can redistribute it and/or
9 //  modify it under the terms of the GNU Lesser General Public
10 //  License as published by the Free Software Foundation; either
11 //  version 2 of the License, or (at your option) any later version.
12 //
13 //  This library is distributed in the hope that it will be useful,
14 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
15 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16 //  Lesser General Public License for more details.
17 //
18 //  You should have received a copy of the GNU Lesser General Public
19 //  License along with this library; if not, write to the Free Software
20 //  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
21 //
22 /////////////////////////////////////////////////////////////////////////
23 
24 #include <stdio.h>
25 #include <assert.h>
26 #include "disasm.h"
27 
decode_modrm(x86_insn * insn)28 void disassembler::decode_modrm(x86_insn *insn)
29 {
30   insn->modrm = fetch_byte();
31   BX_DECODE_MODRM(insn->modrm, insn->mod, insn->nnn, insn->rm);
32   // MOVs with CRx and DRx always use register ops and ignore the mod field.
33   if ((insn->b1 & ~3) == 0x120) insn->mod = 3;
34   insn->nnn |= insn->rex_r;
35   insn->rm  |= insn->rex_b;
36 
37   if (insn->mod == 3) {
38     return; /* mod, reg, reg */
39   }
40 
41   if (insn->as_64)
42   {
43       if ((insn->rm & 7) != 4) { /* rm != 100b, no s-i-b byte */
44         // one byte modrm
45         switch (insn->mod) {
46           case 0:
47             resolve_modrm = &disassembler::resolve64_mod0;
48             if ((insn->rm & 7) == 5) /* no reg, 32-bit displacement */
49               insn->displacement.displ32 = fetch_dword();
50             break;
51           case 1:
52             /* reg, 8-bit displacement, sign extend */
53             resolve_modrm = &disassembler::resolve64_mod1or2;
54             insn->displacement.displ32 = (Bit8s) fetch_byte();
55             break;
56           case 2:
57             /* reg, 32-bit displacement */
58             resolve_modrm = &disassembler::resolve64_mod1or2;
59             insn->displacement.displ32 = fetch_dword();
60             break;
61         } /* switch (mod) */
62       } /* if (rm != 4) */
63       else { /* rm == 4, s-i-b byte follows */
64         insn->sib = fetch_byte();
65         BX_DECODE_SIB(insn->sib, insn->scale, insn->index, insn->base);
66         insn->base  |= insn->rex_b;
67         insn->index |= insn->rex_x;
68 
69         switch (insn->mod) {
70           case 0:
71             resolve_modrm = &disassembler::resolve64_mod0_rm4;
72             if ((insn->base & 7) == 5)
73               insn->displacement.displ32 = fetch_dword();
74             break;
75           case 1:
76             resolve_modrm = &disassembler::resolve64_mod1or2_rm4;
77             insn->displacement.displ32 = (Bit8s) fetch_byte();
78             break;
79           case 2:
80             resolve_modrm = &disassembler::resolve64_mod1or2_rm4;
81             insn->displacement.displ32 = fetch_dword();
82             break;
83         }
84       } /* s-i-b byte follows */
85   }
86   else
87   {
88     if (insn->as_32)
89     {
90       if ((insn->rm & 7) != 4) { /* rm != 100b, no s-i-b byte */
91         // one byte modrm
92         switch (insn->mod) {
93           case 0:
94             resolve_modrm = &disassembler::resolve32_mod0;
95             if ((insn->rm & 7) == 5) /* no reg, 32-bit displacement */
96               insn->displacement.displ32 = fetch_dword();
97             break;
98           case 1:
99             /* reg, 8-bit displacement, sign extend */
100             resolve_modrm = &disassembler::resolve32_mod1or2;
101             insn->displacement.displ32 = (Bit8s) fetch_byte();
102             break;
103           case 2:
104             /* reg, 32-bit displacement */
105             resolve_modrm = &disassembler::resolve32_mod1or2;
106             insn->displacement.displ32 = fetch_dword();
107             break;
108         } /* switch (mod) */
109       } /* if (rm != 4) */
110       else { /* rm == 4, s-i-b byte follows */
111         insn->sib = fetch_byte();
112         BX_DECODE_SIB(insn->sib, insn->scale, insn->index, insn->base);
113         insn->base  |= insn->rex_b;
114         insn->index |= insn->rex_x;
115 
116         switch (insn->mod) {
117           case 0:
118             resolve_modrm = &disassembler::resolve32_mod0_rm4;
119             if ((insn->base & 7) == 5)
120               insn->displacement.displ32 = fetch_dword();
121             break;
122           case 1:
123             resolve_modrm = &disassembler::resolve32_mod1or2_rm4;
124             insn->displacement.displ32 = (Bit8s) fetch_byte();
125             break;
126           case 2:
127             resolve_modrm = &disassembler::resolve32_mod1or2_rm4;
128             insn->displacement.displ32 = fetch_dword();
129             break;
130         }
131       } /* s-i-b byte follows */
132     }
133     else {
134       assert(insn->rex_b == 0);
135       assert(insn->rex_x == 0);
136       assert(insn->rex_r == 0);
137       /* 16 bit addressing modes. */
138       switch (insn->mod) {
139         case 0:
140           resolve_modrm = &disassembler::resolve16_mod0;
141           if(insn->rm == 6)
142             insn->displacement.displ16 = fetch_word();
143           break;
144         case 1:
145           /* reg, 8-bit displacement, sign extend */
146           resolve_modrm = &disassembler::resolve16_mod1or2;
147           insn->displacement.displ16 = (Bit8s) fetch_byte();
148           break;
149         case 2:
150           resolve_modrm = &disassembler::resolve16_mod1or2;
151           insn->displacement.displ16 = fetch_word();
152           break;
153       } /* switch (mod) ... */
154     }
155   }
156 }
157 
resolve16_mod0(const x86_insn * insn,unsigned datasize)158 void disassembler::resolve16_mod0(const x86_insn *insn, unsigned datasize)
159 {
160   const char *seg;
161 
162   if (insn->is_seg_override())
163     seg = segment_name[insn->seg_override];
164   else
165     seg = sreg_mod00_rm16[insn->rm];
166 
167   if(insn->rm == 6)
168     print_memory_access16(datasize, seg, NULL, insn->displacement.displ16);
169   else
170     print_memory_access16(datasize, seg, index16[insn->rm], 0);
171 }
172 
resolve16_mod1or2(const x86_insn * insn,unsigned datasize)173 void disassembler::resolve16_mod1or2(const x86_insn *insn, unsigned datasize)
174 {
175   const char *seg;
176 
177   if (insn->is_seg_override())
178     seg = segment_name[insn->seg_override];
179   else
180     seg = sreg_mod01or10_rm16[insn->rm];
181 
182   print_memory_access16(datasize, seg, index16[insn->rm], insn->displacement.displ16);
183 }
184 
resolve32_mod0(const x86_insn * insn,unsigned datasize)185 void disassembler::resolve32_mod0(const x86_insn *insn, unsigned datasize)
186 {
187   const char *seg, *eip_regname = NULL;
188 
189   if (insn->is_seg_override())
190     seg = segment_name[insn->seg_override];
191   else
192     seg = segment_name[DS_REG];
193 
194   if (insn->is_64) {
195     if (intel_mode) eip_regname = "eip";
196     else eip_regname = "%eip";
197   }
198 
199   if ((insn->rm & 7) == 5) /* no reg, 32-bit displacement */
200     print_memory_access32(datasize, seg, eip_regname, NULL, 0, insn->displacement.displ32);
201   else
202     print_memory_access32(datasize, seg, general_32bit_regname[insn->rm], NULL, 0, 0);
203 }
204 
resolve32_mod1or2(const x86_insn * insn,unsigned datasize)205 void disassembler::resolve32_mod1or2(const x86_insn *insn, unsigned datasize)
206 {
207   const char *seg;
208 
209   if (insn->is_seg_override())
210     seg = segment_name[insn->seg_override];
211   else
212     seg = sreg_mod01or10_base32[insn->rm];
213 
214   print_memory_access32(datasize, seg,
215       general_32bit_regname[insn->rm], NULL, 0, insn->displacement.displ32);
216 }
217 
resolve32_mod0_rm4(const x86_insn * insn,unsigned datasize)218 void disassembler::resolve32_mod0_rm4(const x86_insn *insn, unsigned datasize)
219 {
220   char vsib_index[8];
221   const char *seg, *base = NULL, *index = NULL;
222   Bit32u disp32 = 0;
223 
224   if (insn->is_seg_override())
225     seg = segment_name[insn->seg_override];
226   else
227     seg = sreg_mod00_base32[insn->base];
228 
229   if ((insn->base & 7) != 5)
230     base = general_32bit_regname[insn->base];
231   else
232     disp32 = insn->displacement.displ32;
233 
234   if (datasize & VSIB_Index) {
235     sprintf(vsib_index, "%s%d", vector_reg_name[insn->vex_l], insn->index);
236     index = vsib_index;
237   }
238   else {
239     if (insn->index != 4)
240       index = general_32bit_regname[insn->index];
241   }
242 
243   print_memory_access32(datasize, seg, base, index, insn->scale, disp32);
244 }
245 
resolve32_mod1or2_rm4(const x86_insn * insn,unsigned datasize)246 void disassembler::resolve32_mod1or2_rm4(const x86_insn *insn, unsigned datasize)
247 {
248   char vsib_index[8];
249   const char *seg, *index = NULL;
250 
251   if (insn->is_seg_override())
252     seg = segment_name[insn->seg_override];
253   else
254     seg = sreg_mod01or10_base32[insn->base];
255 
256   if (datasize & VSIB_Index) {
257     sprintf(vsib_index, "%s%d", vector_reg_name[insn->vex_l], insn->index);
258     index = vsib_index;
259   }
260   else {
261     if (insn->index != 4)
262       index = general_32bit_regname[insn->index];
263   }
264 
265   print_memory_access32(datasize, seg,
266       general_32bit_regname[insn->base], index, insn->scale, insn->displacement.displ32);
267 }
268 
resolve64_mod0(const x86_insn * insn,unsigned datasize)269 void disassembler::resolve64_mod0(const x86_insn *insn, unsigned datasize)
270 {
271   const char *seg, *rip_regname;
272 
273   if (insn->is_seg_override())
274     seg = segment_name[insn->seg_override];
275   else
276     seg = segment_name[DS_REG];
277 
278   if (intel_mode) rip_regname = "rip";
279   else rip_regname = "%rip";
280 
281   if ((insn->rm & 7) == 5) /* no reg, 32-bit displacement */
282     print_memory_access64(datasize, seg, rip_regname, NULL, 0, (Bit32s) insn->displacement.displ32);
283   else
284     print_memory_access64(datasize, seg, general_64bit_regname[insn->rm], NULL, 0, 0);
285 }
286 
resolve64_mod1or2(const x86_insn * insn,unsigned datasize)287 void disassembler::resolve64_mod1or2(const x86_insn *insn, unsigned datasize)
288 {
289   const char *seg;
290 
291   if (insn->is_seg_override())
292     seg = segment_name[insn->seg_override];
293   else
294     seg = sreg_mod01or10_base32[insn->rm];
295 
296   print_memory_access64(datasize, seg,
297       general_64bit_regname[insn->rm], NULL, 0, (Bit32s) insn->displacement.displ32);
298 }
299 
resolve64_mod0_rm4(const x86_insn * insn,unsigned datasize)300 void disassembler::resolve64_mod0_rm4(const x86_insn *insn, unsigned datasize)
301 {
302   char vsib_index[8];
303   const char *seg, *base = NULL, *index = NULL;
304   Bit32s disp32 = 0;
305 
306   if (insn->is_seg_override())
307     seg = segment_name[insn->seg_override];
308   else
309     seg = sreg_mod00_base32[insn->base];
310 
311   if ((insn->base & 7) != 5)
312     base = general_64bit_regname[insn->base];
313   else
314     disp32 = (Bit32s) insn->displacement.displ32;
315 
316   if (datasize & VSIB_Index) {
317     sprintf(vsib_index, "%s%d", vector_reg_name[insn->vex_l], insn->index);
318     index = vsib_index;
319   }
320   else {
321     if (insn->index != 4)
322       index = general_64bit_regname[insn->index];
323   }
324 
325   print_memory_access64(datasize, seg, base, index, insn->scale, disp32);
326 }
327 
resolve64_mod1or2_rm4(const x86_insn * insn,unsigned datasize)328 void disassembler::resolve64_mod1or2_rm4(const x86_insn *insn, unsigned datasize)
329 {
330   char vsib_index[8];
331   const char *seg, *index = NULL;
332 
333   if (insn->is_seg_override())
334     seg = segment_name[insn->seg_override];
335   else
336     seg = sreg_mod01or10_base32[insn->base];
337 
338   if (datasize & VSIB_Index) {
339     sprintf(vsib_index, "%s%d", vector_reg_name[insn->vex_l], insn->index);
340     index = vsib_index;
341   }
342   else {
343     if (insn->index != 4)
344       index = general_64bit_regname[insn->index];
345   }
346 
347   print_memory_access64(datasize, seg,
348       general_64bit_regname[insn->base], index, insn->scale, (Bit32s) insn->displacement.displ32);
349 }
350 
print_datasize(unsigned size)351 void disassembler::print_datasize(unsigned size)
352 {
353   if (!intel_mode || !print_mem_datasize) return;
354 
355   switch(size & 0xf)
356   {
357     case B_SIZE:
358       dis_sprintf("byte ptr ");
359       break;
360     case W_SIZE:
361       dis_sprintf("word ptr ");
362       break;
363     case D_SIZE:
364       dis_sprintf("dword ptr ");
365       break;
366     case Q_SIZE:
367       dis_sprintf("qword ptr ");
368       break;
369     case T_SIZE:
370       dis_sprintf("tbyte ptr ");
371       break;
372     case XMM_SIZE:
373       dis_sprintf("dqword ptr ");
374       break;
375     case YMM_SIZE:
376       dis_sprintf("qqword ptr ");
377       break;
378     case X_SIZE:
379       break;
380   };
381 }
382 
print_memory_access16(int datasize,const char * seg,const char * index,Bit16u disp)383 void disassembler::print_memory_access16(int datasize,
384                 const char *seg, const char *index, Bit16u disp)
385 {
386   print_datasize(datasize);
387 
388   dis_sprintf("%s:", seg);
389 
390   if (intel_mode)
391   {
392     if (index == NULL)
393     {
394       dis_sprintf("0x%04x", (unsigned) disp);
395     }
396     else
397     {
398       if (disp != 0) {
399         if (offset_mode_hex)
400           dis_sprintf("[%s+0x%04x]", index, (unsigned) disp);
401         else
402           dis_sprintf("[%s%+d]", index, (int) (Bit16s) disp);
403       }
404       else
405         dis_sprintf("[%s]", index);
406     }
407   }
408   else
409   {
410     if (index == NULL)
411     {
412       dis_sprintf("0x%04x", (unsigned) disp);
413     }
414     else
415     {
416       if (disp != 0) {
417         if (offset_mode_hex)
418           dis_sprintf("0x%04x(%s,1)", (unsigned) disp, index);
419         else
420           dis_sprintf("%d(%s,1)", (int) (Bit16s) disp, index);
421       }
422       else
423         dis_sprintf("(%s,1)", index);
424     }
425   }
426 }
427 
print_memory_access32(int datasize,const char * seg,const char * base,const char * index,int scale,Bit32s disp)428 void disassembler::print_memory_access32(int datasize,
429         const char *seg, const char *base, const char *index, int scale, Bit32s disp)
430 {
431   print_datasize(datasize);
432 
433   dis_sprintf("%s:", seg);
434 
435   scale = 1 << scale;
436 
437   if (intel_mode)
438   {
439     if (base == NULL)
440     {
441       if (index == NULL)
442       {
443         dis_sprintf("0x%08x", (unsigned) disp);
444       }
445       else
446       {
447         if (scale != 1)
448         {
449           if (disp != 0) {
450             if (offset_mode_hex)
451               dis_sprintf("[%s*%d+0x%08x]", index, scale, (unsigned) disp);
452             else
453               dis_sprintf("[%s*%d%+d]", index, scale, (int) disp);
454           }
455           else
456             dis_sprintf("[%s*%d]", index, scale);
457         }
458         else
459         {
460           if (disp != 0) {
461             if (offset_mode_hex)
462               dis_sprintf("[%s+0x%08x]", index, (unsigned) disp);
463             else
464               dis_sprintf("[%s%+d]", index, (int) disp);
465           }
466           else {
467             dis_sprintf("[%s]", index);
468           }
469         }
470       }
471     }
472     else
473     {
474       if (index == NULL)
475       {
476         if (disp != 0) {
477           if (offset_mode_hex)
478             dis_sprintf("[%s+0x%08x]", base, (unsigned) disp);
479           else
480             dis_sprintf("[%s%+d]", base, (int) disp);
481         }
482         else {
483           dis_sprintf("[%s]", base);
484         }
485       }
486       else
487       {
488         if (scale != 1)
489         {
490           if (disp != 0) {
491             if (offset_mode_hex)
492               dis_sprintf("[%s+%s*%d+0x%08x]", base, index, scale, (unsigned) disp);
493             else
494               dis_sprintf("[%s+%s*%d%+d]", base, index, scale, (int) disp);
495           }
496           else {
497             dis_sprintf("[%s+%s*%d]", base, index, scale);
498           }
499         }
500         else
501         {
502           if (disp != 0) {
503             if (offset_mode_hex)
504               dis_sprintf("[%s+%s+0x%08x]", base, index, (unsigned) disp);
505             else
506               dis_sprintf("[%s+%s%+d]", base, index, (int) disp);
507           }
508           else
509             dis_sprintf("[%s+%s]", base, index);
510         }
511       }
512     }
513   }
514   else
515   {
516     if (base == NULL)
517     {
518       if (index == NULL)
519       {
520         dis_sprintf("0x%08x", (unsigned) disp);
521       }
522       else
523       {
524         if (disp != 0) {
525           if (offset_mode_hex)
526             dis_sprintf("0x%08x(,%s,%d)", (unsigned) disp, index, scale);
527           else
528             dis_sprintf("%d(,%s,%d)", (int) disp, index, scale);
529         }
530         else
531           dis_sprintf("(,%s,%d)", index, scale);
532       }
533     }
534     else
535     {
536       if (index == NULL)
537       {
538         if (disp != 0) {
539           if (offset_mode_hex)
540             dis_sprintf("0x%08x(%s)", (unsigned) disp, base);
541           else
542             dis_sprintf("%d(%s)", (int) disp, base);
543         }
544         else
545           dis_sprintf("(%s)", base);
546       }
547       else
548       {
549         if (disp != 0) {
550           if (offset_mode_hex)
551             dis_sprintf("0x%08x(%s,%s,%d)", (unsigned) disp, base, index, scale);
552           else
553             dis_sprintf("%d(%s,%s,%d)", (int) disp, base, index, scale);
554         }
555         else
556           dis_sprintf("(%s,%s,%d)", base, index, scale);
557       }
558     }
559   }
560 }
561 
print_memory_access64(int datasize,const char * seg,const char * base,const char * index,int scale,Bit32s disp)562 void disassembler::print_memory_access64(int datasize,
563         const char *seg, const char *base, const char *index, int scale, Bit32s disp)
564 {
565   Bit64u disp64 = (Bit64s) disp;
566 
567   print_datasize(datasize);
568 
569   dis_sprintf("%s:", seg);
570 
571   scale = 1 << scale;
572 
573   if (intel_mode)
574   {
575     if (base == NULL)
576     {
577       if (index == NULL)
578       {
579         dis_sprintf("0x%08x%08x", GET32H(disp64), GET32L(disp64));
580       }
581       else
582       {
583         if (scale != 1)
584         {
585           if (disp != 0) {
586             if (offset_mode_hex)
587               dis_sprintf("[%s*%d+0x%08x%08x]", index, scale, GET32H(disp64), GET32L(disp64));
588             else
589               dis_sprintf("[%s*%d%+d]", index, scale, (int) disp);
590           }
591           else
592             dis_sprintf("[%s*%d]", index, scale);
593         }
594         else
595         {
596           if (disp != 0) {
597             if (offset_mode_hex)
598               dis_sprintf("[%s+0x%08x%08x]", index, GET32H(disp64), GET32L(disp64));
599             else
600               dis_sprintf("[%s%+d]", index, (int) disp);
601           }
602           else {
603             dis_sprintf("[%s]", index);
604           }
605         }
606       }
607     }
608     else
609     {
610       if (index == NULL)
611       {
612         if (disp != 0) {
613           if (offset_mode_hex)
614             dis_sprintf("[%s+0x%08x%08x]", base, GET32H(disp64), GET32L(disp64));
615           else
616             dis_sprintf("[%s%+d]", base, (int) disp);
617         }
618         else {
619           dis_sprintf("[%s]", base);
620         }
621       }
622       else
623       {
624         if (scale != 1)
625         {
626           if (disp != 0) {
627             if (offset_mode_hex)
628               dis_sprintf("[%s+%s*%d+0x%08x%08x]", base, index, scale, GET32H(disp64), GET32L(disp64));
629             else
630               dis_sprintf("[%s+%s*%d%+d]", base, index, scale, (int) disp);
631           }
632           else {
633             dis_sprintf("[%s+%s*%d]", base, index, scale);
634           }
635         }
636         else
637         {
638           if (disp != 0) {
639             if (offset_mode_hex)
640               dis_sprintf("[%s+%s+0x%08x%08x]", base, index, GET32H(disp64), GET32L(disp64));
641             else
642               dis_sprintf("[%s+%s%+d]", base, index, (int) disp);
643           }
644           else
645             dis_sprintf("[%s+%s]", base, index);
646         }
647       }
648     }
649   }
650   else
651   {
652     if (base == NULL)
653     {
654       if (index == NULL)
655       {
656         dis_sprintf("0x%08x%08x", GET32H(disp64), GET32L(disp64));
657       }
658       else
659       {
660         if (disp != 0) {
661           if (offset_mode_hex)
662             dis_sprintf("0x%08x%08x(,%s,%d)", GET32H(disp64), GET32L(disp64), index, scale);
663           else
664             dis_sprintf("%d(,%s,%d)", (int) disp, index, scale);
665         }
666         else
667           dis_sprintf("(,%s,%d)", index, scale);
668       }
669     }
670     else
671     {
672       if (index == NULL)
673       {
674         if (disp != 0) {
675           if (offset_mode_hex)
676             dis_sprintf("0x%08x%08x(%s)", GET32H(disp64), GET32L(disp64), base);
677           else
678             dis_sprintf("%d(%s)", (int) disp, base);
679         }
680         else
681           dis_sprintf("(%s)", base);
682       }
683       else
684       {
685         if (disp != 0) {
686           if (offset_mode_hex)
687             dis_sprintf("0x%08x%08x(%s,%s,%d)", GET32H(disp64), GET32L(disp64), base, index, scale);
688           else
689             dis_sprintf("%d(%s,%s,%d)", (int) disp, base, index, scale);
690         }
691         else
692           dis_sprintf("(%s,%s,%d)", base, index, scale);
693       }
694     }
695   }
696 }
697