Revision 4b74fe1f translate-i386.c
b/translate-i386.c | ||
---|---|---|
27 | 27 |
va_list ap; |
28 | 28 |
|
29 | 29 |
va_start(ap, fmt); |
30 |
fprintf(stderr, "\n"); |
|
30 | 31 |
vfprintf(stderr, fmt, ap); |
32 |
fprintf(stderr, "\n"); |
|
31 | 33 |
va_end(ap); |
32 | 34 |
exit(1); |
33 | 35 |
} |
... | ... | |
98 | 100 |
OR_EBP, |
99 | 101 |
OR_ESI, |
100 | 102 |
OR_EDI, |
101 |
|
|
102 |
/* I386 float registers */ |
|
103 |
OR_ST0, |
|
104 |
OR_ST1, |
|
105 |
OR_ST2, |
|
106 |
OR_ST3, |
|
107 |
OR_ST4, |
|
108 |
OR_ST5, |
|
109 |
OR_ST6, |
|
110 |
OR_ST7, |
|
111 | 103 |
OR_TMP0, /* temporary operand register */ |
112 | 104 |
OR_TMP1, |
113 | 105 |
OR_A0, /* temporary register used when doing address evaluation */ |
114 |
OR_EFLAGS, /* cpu flags */ |
|
115 |
OR_ITMP0, /* used for byte/word insertion */ |
|
116 |
OR_ITMP1, /* used for byte/word insertion */ |
|
117 |
OR_ITMP2, /* used for byte/word insertion */ |
|
118 |
OR_FTMP0, /* float temporary */ |
|
119 |
OR_DF, /* D flag, for string ops */ |
|
120 | 106 |
OR_ZERO, /* fixed zero register */ |
121 |
OR_IM, /* dummy immediate value register */ |
|
122 | 107 |
NB_OREGS, |
123 | 108 |
}; |
124 | 109 |
|
125 |
#if 0 |
|
126 |
static const double tab_const[7] = { |
|
127 |
1.0, |
|
128 |
3.32192809488736234789, /* log2(10) */ |
|
129 |
M_LOG2E, |
|
130 |
M_PI, |
|
131 |
0.30102999566398119521, /* log10(2) */ |
|
132 |
M_LN2, |
|
133 |
0.0 |
|
134 |
}; |
|
135 |
#endif |
|
136 |
|
|
137 | 110 |
typedef void (GenOpFunc)(void); |
138 | 111 |
typedef void (GenOpFunc1)(long); |
139 | 112 |
typedef void (GenOpFunc2)(long, long); |
... | ... | |
354 | 327 |
static GenOpFunc *gen_op_arith_T0_T1_cc[8] = { |
355 | 328 |
gen_op_addl_T0_T1_cc, |
356 | 329 |
gen_op_orl_T0_T1_cc, |
357 |
gen_op_adcl_T0_T1_cc,
|
|
358 |
gen_op_sbbl_T0_T1_cc,
|
|
330 |
NULL,
|
|
331 |
NULL,
|
|
359 | 332 |
gen_op_andl_T0_T1_cc, |
360 | 333 |
gen_op_subl_T0_T1_cc, |
361 | 334 |
gen_op_xorl_T0_T1_cc, |
362 | 335 |
gen_op_cmpl_T0_T1_cc, |
363 | 336 |
}; |
364 | 337 |
|
338 |
static GenOpFunc *gen_op_arithc_T0_T1_cc[3][2] = { |
|
339 |
[OT_BYTE] = { |
|
340 |
gen_op_adcb_T0_T1_cc, |
|
341 |
gen_op_sbbb_T0_T1_cc, |
|
342 |
}, |
|
343 |
[OT_WORD] = { |
|
344 |
gen_op_adcw_T0_T1_cc, |
|
345 |
gen_op_sbbw_T0_T1_cc, |
|
346 |
}, |
|
347 |
[OT_LONG] = { |
|
348 |
gen_op_adcl_T0_T1_cc, |
|
349 |
gen_op_sbbl_T0_T1_cc, |
|
350 |
}, |
|
351 |
}; |
|
352 |
|
|
365 | 353 |
static const int cc_op_arithb[8] = { |
366 | 354 |
CC_OP_ADDB, |
367 | 355 |
CC_OP_LOGICB, |
... | ... | |
406 | 394 |
}, |
407 | 395 |
}; |
408 | 396 |
|
397 |
static GenOpFunc *gen_op_btx_T0_T1_cc[2][4] = { |
|
398 |
[0] = { |
|
399 |
gen_op_btw_T0_T1_cc, |
|
400 |
gen_op_btsw_T0_T1_cc, |
|
401 |
gen_op_btrw_T0_T1_cc, |
|
402 |
gen_op_btcw_T0_T1_cc, |
|
403 |
}, |
|
404 |
[1] = { |
|
405 |
gen_op_btl_T0_T1_cc, |
|
406 |
gen_op_btsl_T0_T1_cc, |
|
407 |
gen_op_btrl_T0_T1_cc, |
|
408 |
gen_op_btcl_T0_T1_cc, |
|
409 |
}, |
|
410 |
}; |
|
411 |
|
|
409 | 412 |
static GenOpFunc *gen_op_lds_T0_A0[3] = { |
410 | 413 |
gen_op_ldsb_T0_A0, |
411 | 414 |
gen_op_ldsw_T0_A0, |
... | ... | |
644 | 647 |
gen_op_mov_TN_reg[ot][0][d](); |
645 | 648 |
if (s != OR_TMP1) |
646 | 649 |
gen_op_mov_TN_reg[ot][1][s](); |
647 |
if ((op == OP_ADCL || op == OP_SBBL) && s1->cc_op != CC_OP_DYNAMIC) |
|
648 |
gen_op_set_cc_op(s1->cc_op); |
|
649 |
gen_op_arith_T0_T1_cc[op](); |
|
650 |
if (op == OP_ADCL || op == OP_SBBL) { |
|
651 |
if (s1->cc_op != CC_OP_DYNAMIC) |
|
652 |
gen_op_set_cc_op(s1->cc_op); |
|
653 |
gen_op_arithc_T0_T1_cc[ot][op - OP_ADCL](); |
|
654 |
s1->cc_op = CC_OP_DYNAMIC; |
|
655 |
} else { |
|
656 |
gen_op_arith_T0_T1_cc[op](); |
|
657 |
s1->cc_op = cc_op_arithb[op] + ot; |
|
658 |
} |
|
650 | 659 |
if (d != OR_TMP0 && op != OP_CMPL) |
651 | 660 |
gen_op_mov_reg_T0[ot][d](); |
652 |
s1->cc_op = cc_op_arithb[op] + ot; |
|
653 | 661 |
} |
654 | 662 |
|
655 | 663 |
static void gen_opi(DisasContext *s1, int op, int ot, int d, int c) |
656 | 664 |
{ |
657 | 665 |
gen_op_movl_T1_im(c); |
658 |
gen_op(s1, op, ot, d, OR_TMP0);
|
|
666 |
gen_op(s1, op, ot, d, OR_TMP1);
|
|
659 | 667 |
} |
660 | 668 |
|
661 | 669 |
static void gen_inc(DisasContext *s1, int ot, int d, int c) |
... | ... | |
664 | 672 |
gen_op_mov_TN_reg[ot][0][d](); |
665 | 673 |
if (s1->cc_op != CC_OP_DYNAMIC) |
666 | 674 |
gen_op_set_cc_op(s1->cc_op); |
667 |
if (c > 0) |
|
675 |
if (c > 0) {
|
|
668 | 676 |
gen_op_incl_T0_cc(); |
669 |
else |
|
677 |
s1->cc_op = CC_OP_INCB + ot; |
|
678 |
} else { |
|
670 | 679 |
gen_op_decl_T0_cc(); |
680 |
s1->cc_op = CC_OP_DECB + ot; |
|
681 |
} |
|
671 | 682 |
if (d != OR_TMP0) |
672 | 683 |
gen_op_mov_reg_T0[ot][d](); |
673 | 684 |
} |
... | ... | |
678 | 689 |
gen_op_mov_TN_reg[ot][0][d](); |
679 | 690 |
if (s != OR_TMP1) |
680 | 691 |
gen_op_mov_TN_reg[ot][1][s](); |
681 |
switch(op) { |
|
682 |
case OP_ROL: |
|
683 |
case OP_ROR: |
|
684 |
case OP_RCL: |
|
685 |
case OP_RCR: |
|
686 |
/* only C and O are modified, so we must update flags dynamically */ |
|
687 |
if (s1->cc_op != CC_OP_DYNAMIC) |
|
688 |
gen_op_set_cc_op(s1->cc_op); |
|
689 |
gen_op_shift_T0_T1_cc[ot][op](); |
|
690 |
break; |
|
691 |
default: |
|
692 |
gen_op_shift_T0_T1_cc[ot][op](); |
|
693 |
break; |
|
694 |
} |
|
692 |
/* for zero counts, flags are not updated, so must do it dynamically */ |
|
693 |
if (s1->cc_op != CC_OP_DYNAMIC) |
|
694 |
gen_op_set_cc_op(s1->cc_op); |
|
695 |
|
|
696 |
gen_op_shift_T0_T1_cc[ot][op](); |
|
697 |
|
|
695 | 698 |
if (d != OR_TMP0) |
696 | 699 |
gen_op_mov_reg_T0[ot][d](); |
697 | 700 |
s1->cc_op = CC_OP_DYNAMIC; /* cannot predict flags after */ |
... | ... | |
785 | 788 |
} |
786 | 789 |
gen_op_addl_A0_reg_sN[scale][reg2](); |
787 | 790 |
} |
788 |
opreg = OR_A0; |
|
789 | 791 |
} else { |
790 |
fprintf(stderr, "16 bit addressing not supported\n"); |
|
791 |
disp = 0; |
|
792 |
opreg = 0; |
|
792 |
switch (mod) { |
|
793 |
case 0: |
|
794 |
if (rm == 6) { |
|
795 |
disp = lduw(s->pc); |
|
796 |
s->pc += 2; |
|
797 |
gen_op_movl_A0_im(disp); |
|
798 |
goto no_rm; |
|
799 |
} else { |
|
800 |
disp = 0; |
|
801 |
} |
|
802 |
break; |
|
803 |
case 1: |
|
804 |
disp = (int8_t)ldub(s->pc++); |
|
805 |
break; |
|
806 |
default: |
|
807 |
case 2: |
|
808 |
disp = lduw(s->pc); |
|
809 |
s->pc += 2; |
|
810 |
break; |
|
811 |
} |
|
812 |
switch(rm) { |
|
813 |
case 0: |
|
814 |
gen_op_movl_A0_reg[R_EBX](); |
|
815 |
gen_op_addl_A0_reg_sN[0][R_ESI](); |
|
816 |
break; |
|
817 |
case 1: |
|
818 |
gen_op_movl_A0_reg[R_EBX](); |
|
819 |
gen_op_addl_A0_reg_sN[0][R_EDI](); |
|
820 |
break; |
|
821 |
case 2: |
|
822 |
gen_op_movl_A0_reg[R_EBP](); |
|
823 |
gen_op_addl_A0_reg_sN[0][R_ESI](); |
|
824 |
break; |
|
825 |
case 3: |
|
826 |
gen_op_movl_A0_reg[R_EBP](); |
|
827 |
gen_op_addl_A0_reg_sN[0][R_EDI](); |
|
828 |
break; |
|
829 |
case 4: |
|
830 |
gen_op_movl_A0_reg[R_ESI](); |
|
831 |
break; |
|
832 |
case 5: |
|
833 |
gen_op_movl_A0_reg[R_EDI](); |
|
834 |
break; |
|
835 |
case 6: |
|
836 |
gen_op_movl_A0_reg[R_EBP](); |
|
837 |
break; |
|
838 |
default: |
|
839 |
case 7: |
|
840 |
gen_op_movl_A0_reg[R_EBX](); |
|
841 |
break; |
|
842 |
} |
|
843 |
if (disp != 0) |
|
844 |
gen_op_addl_A0_im(disp); |
|
845 |
gen_op_andl_A0_ffff(); |
|
846 |
no_rm: ; |
|
793 | 847 |
} |
848 |
opreg = OR_A0; |
|
849 |
disp = 0; |
|
794 | 850 |
*reg_ptr = opreg; |
795 | 851 |
*offset_ptr = disp; |
796 | 852 |
} |
... | ... | |
870 | 926 |
case CC_OP_ADDB: |
871 | 927 |
case CC_OP_ADDW: |
872 | 928 |
case CC_OP_ADDL: |
929 |
case CC_OP_ADCB: |
|
930 |
case CC_OP_ADCW: |
|
931 |
case CC_OP_ADCL: |
|
932 |
case CC_OP_SBBB: |
|
933 |
case CC_OP_SBBW: |
|
934 |
case CC_OP_SBBL: |
|
873 | 935 |
case CC_OP_LOGICB: |
874 | 936 |
case CC_OP_LOGICW: |
875 | 937 |
case CC_OP_LOGICL: |
... | ... | |
882 | 944 |
case CC_OP_SHLB: |
883 | 945 |
case CC_OP_SHLW: |
884 | 946 |
case CC_OP_SHLL: |
947 |
case CC_OP_SARB: |
|
948 |
case CC_OP_SARW: |
|
949 |
case CC_OP_SARL: |
|
885 | 950 |
switch(jcc_op) { |
886 | 951 |
case JCC_Z: |
887 | 952 |
func = gen_jcc_sub[(s->cc_op - CC_OP_ADDB) % 3][jcc_op]; |
... | ... | |
1284 | 1349 |
gen_inc(s, ot, OR_TMP0, 1); |
1285 | 1350 |
if (mod != 3) |
1286 | 1351 |
gen_op_st_T0_A0[ot](); |
1352 |
else |
|
1353 |
gen_op_mov_reg_T0[ot][rm](); |
|
1287 | 1354 |
break; |
1288 | 1355 |
case 1: /* dec Ev */ |
1289 | 1356 |
gen_inc(s, ot, OR_TMP0, -1); |
1290 | 1357 |
if (mod != 3) |
1291 | 1358 |
gen_op_st_T0_A0[ot](); |
1359 |
else |
|
1360 |
gen_op_mov_reg_T0[ot][rm](); |
|
1292 | 1361 |
break; |
1293 | 1362 |
case 2: /* call Ev */ |
1294 | 1363 |
gen_op_movl_T1_im((long)s->pc); |
... | ... | |
1359 | 1428 |
ot = dflag ? OT_LONG : OT_WORD; |
1360 | 1429 |
modrm = ldub(s->pc++); |
1361 | 1430 |
reg = ((modrm >> 3) & 7) + OR_EAX; |
1362 |
|
|
1363 | 1431 |
gen_ldst_modrm(s, modrm, ot, OR_TMP0, 0); |
1364 | 1432 |
if (b == 0x69) { |
1365 | 1433 |
val = insn_get(s, ot); |
... | ... | |
1372 | 1440 |
} |
1373 | 1441 |
|
1374 | 1442 |
if (ot == OT_LONG) { |
1375 |
op_imull_T0_T1(); |
|
1443 |
gen_op_imull_T0_T1();
|
|
1376 | 1444 |
} else { |
1377 |
op_imulw_T0_T1(); |
|
1445 |
gen_op_imulw_T0_T1();
|
|
1378 | 1446 |
} |
1379 | 1447 |
gen_op_mov_reg_T0[ot][reg](); |
1380 | 1448 |
s->cc_op = CC_OP_MUL; |
... | ... | |
1522 | 1590 |
offset_addr = insn_get(s, OT_LONG); |
1523 | 1591 |
else |
1524 | 1592 |
offset_addr = insn_get(s, OT_WORD); |
1525 |
|
|
1593 |
gen_op_movl_A0_im(offset_addr); |
|
1526 | 1594 |
if ((b & 2) == 0) { |
1527 | 1595 |
gen_op_ld_T0_A0[ot](); |
1528 | 1596 |
gen_op_mov_reg_T0[ot][R_EAX](); |
... | ... | |
1717 | 1785 |
break; |
1718 | 1786 |
} |
1719 | 1787 |
break; |
1720 |
#if 0 |
|
1788 |
case 0x0d: /* fldcw mem */ |
|
1789 |
gen_op_fldcw_A0(); |
|
1790 |
break; |
|
1791 |
case 0x0f: /* fnstcw mem */ |
|
1792 |
gen_op_fnstcw_A0(); |
|
1793 |
break; |
|
1721 | 1794 |
case 0x2f: /* fnstsw mem */ |
1722 |
gen_insn3(OP_FNSTS, OR_TMP0, OR_ZERO, OR_ZERO); |
|
1723 |
gen_st(OP_STW, OR_TMP0, reg_addr, offset_addr); |
|
1795 |
gen_op_fnstsw_A0(); |
|
1724 | 1796 |
break; |
1725 |
|
|
1726 | 1797 |
case 0x3c: /* fbld */ |
1727 | 1798 |
case 0x3e: /* fbstp */ |
1728 | 1799 |
error("float BCD not hanlded"); |
1729 | 1800 |
return -1; |
1730 |
#endif |
|
1731 | 1801 |
case 0x3d: /* fildll */ |
1732 | 1802 |
gen_op_fpush(); |
1733 | 1803 |
gen_op_fildll_ST0_A0(); |
... | ... | |
1737 | 1807 |
gen_op_fpop(); |
1738 | 1808 |
break; |
1739 | 1809 |
default: |
1740 |
error("unhandled memory FP\n");
|
|
1810 |
error("unhandled memory FP [op=0x%02x]\n", op);
|
|
1741 | 1811 |
return -1; |
1742 | 1812 |
} |
1743 | 1813 |
} else { |
... | ... | |
1987 | 2057 |
else |
1988 | 2058 |
ot = dflag ? OT_LONG : OT_WORD; |
1989 | 2059 |
if (prefixes & PREFIX_REPNZ) { |
2060 |
if (s->cc_op != CC_OP_DYNAMIC) |
|
2061 |
gen_op_set_cc_op(s->cc_op); |
|
1990 | 2062 |
gen_op_scas[6 + ot](); |
2063 |
s->cc_op = CC_OP_DYNAMIC; /* cannot predict flags after */ |
|
1991 | 2064 |
} else if (prefixes & PREFIX_REPZ) { |
2065 |
if (s->cc_op != CC_OP_DYNAMIC) |
|
2066 |
gen_op_set_cc_op(s->cc_op); |
|
1992 | 2067 |
gen_op_scas[3 + ot](); |
2068 |
s->cc_op = CC_OP_DYNAMIC; /* cannot predict flags after */ |
|
1993 | 2069 |
} else { |
1994 | 2070 |
gen_op_scas[ot](); |
2071 |
s->cc_op = CC_OP_SUBB + ot; |
|
1995 | 2072 |
} |
1996 | 2073 |
break; |
1997 | 2074 |
|
... | ... | |
2002 | 2079 |
else |
2003 | 2080 |
ot = dflag ? OT_LONG : OT_WORD; |
2004 | 2081 |
if (prefixes & PREFIX_REPNZ) { |
2082 |
if (s->cc_op != CC_OP_DYNAMIC) |
|
2083 |
gen_op_set_cc_op(s->cc_op); |
|
2005 | 2084 |
gen_op_cmps[6 + ot](); |
2085 |
s->cc_op = CC_OP_DYNAMIC; /* cannot predict flags after */ |
|
2006 | 2086 |
} else if (prefixes & PREFIX_REPZ) { |
2087 |
if (s->cc_op != CC_OP_DYNAMIC) |
|
2088 |
gen_op_set_cc_op(s->cc_op); |
|
2007 | 2089 |
gen_op_cmps[3 + ot](); |
2090 |
s->cc_op = CC_OP_DYNAMIC; /* cannot predict flags after */ |
|
2008 | 2091 |
} else { |
2009 | 2092 |
gen_op_cmps[ot](); |
2093 |
s->cc_op = CC_OP_SUBB + ot; |
|
2010 | 2094 |
} |
2011 | 2095 |
break; |
2012 | 2096 |
|
... | ... | |
2187 | 2271 |
break; |
2188 | 2272 |
|
2189 | 2273 |
/************************/ |
2274 |
/* bit operations */ |
|
2275 |
case 0x1ba: /* bt/bts/btr/btc Gv, im */ |
|
2276 |
ot = dflag ? OT_LONG : OT_WORD; |
|
2277 |
modrm = ldub(s->pc++); |
|
2278 |
op = (modrm >> 3) & 7; |
|
2279 |
mod = (modrm >> 6) & 3; |
|
2280 |
rm = modrm & 7; |
|
2281 |
if (mod != 3) { |
|
2282 |
gen_lea_modrm(s, modrm, ®_addr, &offset_addr); |
|
2283 |
gen_op_ld_T0_A0[ot](); |
|
2284 |
} else { |
|
2285 |
gen_op_mov_TN_reg[ot][0][rm](); |
|
2286 |
} |
|
2287 |
/* load shift */ |
|
2288 |
val = ldub(s->pc++); |
|
2289 |
gen_op_movl_T1_im(val); |
|
2290 |
if (op < 4) |
|
2291 |
return -1; |
|
2292 |
op -= 4; |
|
2293 |
gen_op_btx_T0_T1_cc[ot - OT_WORD][op](); |
|
2294 |
s->cc_op = CC_OP_SHLB + ot; |
|
2295 |
if (op != 0) { |
|
2296 |
if (mod != 3) |
|
2297 |
gen_op_st_T0_A0[ot](); |
|
2298 |
else |
|
2299 |
gen_op_mov_reg_T0[ot][rm](); |
|
2300 |
} |
|
2301 |
break; |
|
2302 |
case 0x1a3: /* bt Gv, Ev */ |
|
2303 |
op = 0; |
|
2304 |
goto do_btx; |
|
2305 |
case 0x1ab: /* bts */ |
|
2306 |
op = 1; |
|
2307 |
goto do_btx; |
|
2308 |
case 0x1b3: /* btr */ |
|
2309 |
op = 2; |
|
2310 |
goto do_btx; |
|
2311 |
case 0x1bb: /* btc */ |
|
2312 |
op = 3; |
|
2313 |
do_btx: |
|
2314 |
ot = dflag ? OT_LONG : OT_WORD; |
|
2315 |
modrm = ldub(s->pc++); |
|
2316 |
reg = (modrm >> 3) & 7; |
|
2317 |
mod = (modrm >> 6) & 3; |
|
2318 |
rm = modrm & 7; |
|
2319 |
gen_op_mov_TN_reg[OT_LONG][1][reg](); |
|
2320 |
if (mod != 3) { |
|
2321 |
gen_lea_modrm(s, modrm, ®_addr, &offset_addr); |
|
2322 |
/* specific case: we need to add a displacement */ |
|
2323 |
if (ot == OT_WORD) |
|
2324 |
gen_op_add_bitw_A0_T1(); |
|
2325 |
else |
|
2326 |
gen_op_add_bitl_A0_T1(); |
|
2327 |
gen_op_ld_T0_A0[ot](); |
|
2328 |
} else { |
|
2329 |
gen_op_mov_TN_reg[ot][0][rm](); |
|
2330 |
} |
|
2331 |
gen_op_btx_T0_T1_cc[ot - OT_WORD][op](); |
|
2332 |
s->cc_op = CC_OP_SHLB + ot; |
|
2333 |
if (op != 0) { |
|
2334 |
if (mod != 3) |
|
2335 |
gen_op_st_T0_A0[ot](); |
|
2336 |
else |
|
2337 |
gen_op_mov_reg_T0[ot][rm](); |
|
2338 |
} |
|
2339 |
break; |
|
2340 |
|
|
2341 |
/************************/ |
|
2190 | 2342 |
/* misc */ |
2191 | 2343 |
case 0x90: /* nop */ |
2192 | 2344 |
break; |
... | ... | |
2206 | 2358 |
gen_op_into((long)pc_start, (long)s->pc); |
2207 | 2359 |
*is_jmp_ptr = 1; |
2208 | 2360 |
break; |
2361 |
case 0x1c8 ... 0x1cf: /* bswap reg */ |
|
2362 |
reg = b & 7; |
|
2363 |
gen_op_mov_TN_reg[OT_LONG][0][reg](); |
|
2364 |
gen_op_bswapl_T0(); |
|
2365 |
gen_op_mov_reg_T0[OT_LONG][reg](); |
|
2366 |
break; |
|
2367 |
|
|
2209 | 2368 |
#if 0 |
2210 | 2369 |
case 0x1a2: /* cpuid */ |
2211 | 2370 |
gen_insn0(OP_ASM); |
Also available in: Unified diff