Revision 6dbad63e translate-i386.c
b/translate-i386.c | ||
---|---|---|
34 | 34 |
#include "dis-asm.h" |
35 | 35 |
#endif |
36 | 36 |
|
37 |
#ifndef offsetof |
|
38 |
#define offsetof(type, field) ((size_t) &((type *)0)->field) |
|
39 |
#endif |
|
40 |
|
|
37 | 41 |
static uint8_t *gen_code_ptr; |
38 | 42 |
int __op_param1, __op_param2, __op_param3; |
39 | 43 |
|
... | ... | |
71 | 75 |
int prefix; |
72 | 76 |
int aflag, dflag; |
73 | 77 |
uint8_t *pc; /* current pc */ |
74 |
int cc_op; /* current CC operation */ |
|
75 |
int f_st; |
|
78 |
int is_jmp; /* 1 = means jump (stop translation), 2 means CPU |
|
79 |
static state change (stop translation) */ |
|
80 |
/* current block context */ |
|
81 |
int code32; /* 32 bit code segment */ |
|
82 |
int cc_op; /* current CC operation */ |
|
83 |
int addseg; /* non zero if either DS/ES/SS have a non zero base */ |
|
84 |
int f_st; /* currently unused */ |
|
76 | 85 |
} DisasContext; |
77 | 86 |
|
78 | 87 |
/* i386 arith/logic operations */ |
... | ... | |
763 | 772 |
static void gen_lea_modrm(DisasContext *s, int modrm, int *reg_ptr, int *offset_ptr) |
764 | 773 |
{ |
765 | 774 |
int havesib; |
766 |
int havebase; |
|
767 | 775 |
int base, disp; |
768 |
int index = 0; |
|
769 |
int scale = 0; |
|
770 |
int reg1, reg2, opreg; |
|
771 |
int mod, rm, code; |
|
776 |
int index; |
|
777 |
int scale; |
|
778 |
int opreg; |
|
779 |
int mod, rm, code, override, must_add_seg; |
|
780 |
|
|
781 |
/* XXX: add a generation time variable to tell if base == 0 in DS/ES/SS */ |
|
782 |
/* XXX: fix lea case */ |
|
783 |
override = -1; |
|
784 |
must_add_seg = s->addseg; |
|
785 |
if (s->prefix & (PREFIX_CS | PREFIX_SS | PREFIX_DS | |
|
786 |
PREFIX_ES | PREFIX_FS | PREFIX_GS)) { |
|
787 |
if (s->prefix & PREFIX_ES) |
|
788 |
override = R_ES; |
|
789 |
else if (s->prefix & PREFIX_CS) |
|
790 |
override = R_CS; |
|
791 |
else if (s->prefix & PREFIX_SS) |
|
792 |
override = R_SS; |
|
793 |
else if (s->prefix & PREFIX_DS) |
|
794 |
override = R_DS; |
|
795 |
else if (s->prefix & PREFIX_FS) |
|
796 |
override = R_FS; |
|
797 |
else |
|
798 |
override = R_GS; |
|
799 |
must_add_seg = 1; |
|
800 |
} |
|
772 | 801 |
|
773 | 802 |
mod = (modrm >> 6) & 3; |
774 | 803 |
rm = modrm & 7; |
... | ... | |
776 | 805 |
if (s->aflag) { |
777 | 806 |
|
778 | 807 |
havesib = 0; |
779 |
havebase = 1; |
|
780 | 808 |
base = rm; |
809 |
index = 0; |
|
810 |
scale = 0; |
|
781 | 811 |
|
782 | 812 |
if (base == 4) { |
783 | 813 |
havesib = 1; |
... | ... | |
790 | 820 |
switch (mod) { |
791 | 821 |
case 0: |
792 | 822 |
if (base == 5) { |
793 |
havebase = 0;
|
|
823 |
base = -1;
|
|
794 | 824 |
disp = ldl(s->pc); |
795 | 825 |
s->pc += 4; |
796 | 826 |
} else { |
... | ... | |
806 | 836 |
s->pc += 4; |
807 | 837 |
break; |
808 | 838 |
} |
809 |
|
|
810 |
reg1 = OR_ZERO; |
|
811 |
reg2 = OR_ZERO; |
|
812 |
|
|
813 |
if (havebase || (havesib && (index != 4 || scale != 0))) { |
|
814 |
if (havebase) |
|
815 |
reg1 = OR_EAX + base; |
|
816 |
if (havesib && index != 4) { |
|
817 |
if (havebase) |
|
818 |
reg2 = index + OR_EAX; |
|
819 |
else |
|
820 |
reg1 = index + OR_EAX; |
|
821 |
} |
|
822 |
} |
|
823 |
/* XXX: disp only ? */ |
|
824 |
if (reg2 == OR_ZERO) { |
|
825 |
/* op: disp + (reg1 << scale) */ |
|
826 |
if (reg1 == OR_ZERO) { |
|
827 |
gen_op_movl_A0_im(disp); |
|
828 |
} else if (scale == 0 && disp == 0) { |
|
829 |
gen_op_movl_A0_reg[reg1](); |
|
830 |
} else { |
|
831 |
gen_op_movl_A0_im(disp); |
|
832 |
gen_op_addl_A0_reg_sN[scale][reg1](); |
|
833 |
} |
|
839 |
|
|
840 |
if (base >= 0) { |
|
841 |
gen_op_movl_A0_reg[base](); |
|
842 |
if (disp != 0) |
|
843 |
gen_op_addl_A0_im(disp); |
|
834 | 844 |
} else { |
835 |
/* op: disp + reg1 + (reg2 << scale) */ |
|
836 |
if (disp != 0) { |
|
837 |
gen_op_movl_A0_im(disp); |
|
838 |
gen_op_addl_A0_reg_sN[0][reg1](); |
|
839 |
} else { |
|
840 |
gen_op_movl_A0_reg[reg1](); |
|
845 |
gen_op_movl_A0_im(disp); |
|
846 |
} |
|
847 |
if (havesib && (index != 4 || scale != 0)) { |
|
848 |
gen_op_addl_A0_reg_sN[scale][index](); |
|
849 |
} |
|
850 |
if (must_add_seg) { |
|
851 |
if (override < 0) { |
|
852 |
if (base == R_EBP || base == R_ESP) |
|
853 |
override = R_SS; |
|
854 |
else |
|
855 |
override = R_DS; |
|
841 | 856 |
} |
842 |
gen_op_addl_A0_reg_sN[scale][reg2]();
|
|
857 |
gen_op_addl_A0_seg(offsetof(CPUX86State,seg_cache[override].base));
|
|
843 | 858 |
} |
844 | 859 |
} else { |
845 | 860 |
switch (mod) { |
... | ... | |
848 | 863 |
disp = lduw(s->pc); |
849 | 864 |
s->pc += 2; |
850 | 865 |
gen_op_movl_A0_im(disp); |
866 |
rm = 0; /* avoid SS override */ |
|
851 | 867 |
goto no_rm; |
852 | 868 |
} else { |
853 | 869 |
disp = 0; |
... | ... | |
896 | 912 |
if (disp != 0) |
897 | 913 |
gen_op_addl_A0_im(disp); |
898 | 914 |
gen_op_andl_A0_ffff(); |
899 |
no_rm: ; |
|
915 |
no_rm: |
|
916 |
if (must_add_seg) { |
|
917 |
if (override < 0) { |
|
918 |
if (rm == 2 || rm == 3 || rm == 6) |
|
919 |
override = R_SS; |
|
920 |
else |
|
921 |
override = R_DS; |
|
922 |
} |
|
923 |
gen_op_addl_A0_seg(offsetof(CPUX86State,seg_cache[override].base)); |
|
924 |
} |
|
900 | 925 |
} |
926 |
|
|
901 | 927 |
opreg = OR_A0; |
902 | 928 |
disp = 0; |
903 | 929 |
*reg_ptr = opreg; |
... | ... | |
1082 | 1108 |
} |
1083 | 1109 |
} |
1084 | 1110 |
|
1111 |
/* move T0 to seg_reg and compute if the CPU state may change */ |
|
1112 |
void gen_movl_seg_T0(DisasContext *s, int seg_reg) |
|
1113 |
{ |
|
1114 |
gen_op_movl_seg_T0(seg_reg); |
|
1115 |
if (!s->addseg && seg_reg < R_FS) |
|
1116 |
s->is_jmp = 2; /* abort translation because the register may |
|
1117 |
have a non zero base */ |
|
1118 |
} |
|
1119 |
|
|
1085 | 1120 |
/* return the next pc address. Return -1 if no insn found. *is_jmp_ptr |
1086 | 1121 |
is set to true if the instruction sets the PC (last instruction of |
1087 | 1122 |
a basic block) */ |
1088 |
long disas_insn(DisasContext *s, uint8_t *pc_start, int *is_jmp_ptr)
|
|
1123 |
long disas_insn(DisasContext *s, uint8_t *pc_start) |
|
1089 | 1124 |
{ |
1090 | 1125 |
int b, prefixes, aflag, dflag; |
1091 | 1126 |
int shift, ot; |
... | ... | |
1093 | 1128 |
|
1094 | 1129 |
s->pc = pc_start; |
1095 | 1130 |
prefixes = 0; |
1096 |
aflag = 1;
|
|
1097 |
dflag = 1;
|
|
1131 |
aflag = s->code32;
|
|
1132 |
dflag = s->code32;
|
|
1098 | 1133 |
// cur_pc = s->pc; /* for insn generation */ |
1099 | 1134 |
next_byte: |
1100 | 1135 |
b = ldub(s->pc); |
... | ... | |
1416 | 1451 |
gen_op_movl_T1_im((long)s->pc); |
1417 | 1452 |
gen_op_pushl_T1(); |
1418 | 1453 |
gen_op_jmp_T0(); |
1419 |
*is_jmp_ptr = 1;
|
|
1454 |
s->is_jmp = 1;
|
|
1420 | 1455 |
break; |
1421 | 1456 |
case 4: /* jmp Ev */ |
1422 | 1457 |
gen_op_jmp_T0(); |
1423 |
*is_jmp_ptr = 1;
|
|
1458 |
s->is_jmp = 1;
|
|
1424 | 1459 |
break; |
1425 | 1460 |
case 6: /* push Ev */ |
1426 | 1461 |
gen_op_pushl_T0(); |
... | ... | |
1555 | 1590 |
gen_op_popl_T0(); |
1556 | 1591 |
gen_op_mov_reg_T0[OT_LONG][R_EBP](); |
1557 | 1592 |
break; |
1593 |
case 0x06: /* push es */ |
|
1594 |
case 0x0e: /* push cs */ |
|
1595 |
case 0x16: /* push ss */ |
|
1596 |
case 0x1e: /* push ds */ |
|
1597 |
gen_op_movl_T0_seg(b >> 3); |
|
1598 |
gen_op_pushl_T0(); |
|
1599 |
break; |
|
1600 |
case 0x1a0: /* push fs */ |
|
1601 |
case 0x1a8: /* push gs */ |
|
1602 |
gen_op_movl_T0_seg(((b >> 3) & 7) + R_FS); |
|
1603 |
gen_op_pushl_T0(); |
|
1604 |
break; |
|
1605 |
case 0x07: /* pop es */ |
|
1606 |
case 0x17: /* pop ss */ |
|
1607 |
case 0x1f: /* pop ds */ |
|
1608 |
gen_op_popl_T0(); |
|
1609 |
gen_movl_seg_T0(s, b >> 3); |
|
1610 |
break; |
|
1611 |
case 0x1a1: /* pop fs */ |
|
1612 |
case 0x1a9: /* pop gs */ |
|
1613 |
gen_op_popl_T0(); |
|
1614 |
gen_movl_seg_T0(s, ((b >> 3) & 7) + R_FS); |
|
1615 |
break; |
|
1616 |
|
|
1558 | 1617 |
/**************************/ |
1559 | 1618 |
/* mov */ |
1560 | 1619 |
case 0x88: |
... | ... | |
1598 | 1657 |
gen_ldst_modrm(s, modrm, ot, OR_TMP0, 0); |
1599 | 1658 |
gen_op_mov_reg_T0[ot][reg](); |
1600 | 1659 |
break; |
1660 |
case 0x8e: /* mov seg, Gv */ |
|
1661 |
ot = dflag ? OT_LONG : OT_WORD; |
|
1662 |
modrm = ldub(s->pc++); |
|
1663 |
reg = (modrm >> 3) & 7; |
|
1664 |
gen_ldst_modrm(s, modrm, ot, OR_TMP0, 0); |
|
1665 |
if (reg >= 6) |
|
1666 |
goto illegal_op; |
|
1667 |
gen_movl_seg_T0(s, reg); |
|
1668 |
break; |
|
1669 |
case 0x8c: /* mov Gv, seg */ |
|
1670 |
ot = dflag ? OT_LONG : OT_WORD; |
|
1671 |
modrm = ldub(s->pc++); |
|
1672 |
reg = (modrm >> 3) & 7; |
|
1673 |
if (reg >= 6) |
|
1674 |
goto illegal_op; |
|
1675 |
gen_op_movl_T0_seg(reg); |
|
1676 |
gen_ldst_modrm(s, modrm, ot, OR_TMP0, 1); |
|
1677 |
break; |
|
1601 | 1678 |
|
1602 | 1679 |
case 0x1b6: /* movzbS Gv, Eb */ |
1603 | 1680 |
case 0x1b7: /* movzwS Gv, Eb */ |
... | ... | |
1648 | 1725 |
ot = dflag ? OT_LONG : OT_WORD; |
1649 | 1726 |
modrm = ldub(s->pc++); |
1650 | 1727 |
reg = (modrm >> 3) & 7; |
1651 |
|
|
1728 |
/* we must ensure that no segment is added */ |
|
1729 |
s->prefix &= ~(PREFIX_CS | PREFIX_SS | PREFIX_DS | |
|
1730 |
PREFIX_ES | PREFIX_FS | PREFIX_GS); |
|
1731 |
val = s->addseg; |
|
1732 |
s->addseg = 0; |
|
1652 | 1733 |
gen_lea_modrm(s, modrm, ®_addr, &offset_addr); |
1734 |
s->addseg = val; |
|
1653 | 1735 |
gen_op_mov_reg_A0[ot - OT_WORD][reg](); |
1654 | 1736 |
break; |
1655 | 1737 |
|
... | ... | |
1711 | 1793 |
gen_op_st_T0_A0[ot](); |
1712 | 1794 |
gen_op_mov_reg_T1[ot][reg](); |
1713 | 1795 |
break; |
1796 |
case 0xc4: /* les Gv */ |
|
1797 |
op = R_ES; |
|
1798 |
goto do_lxx; |
|
1799 |
case 0xc5: /* lds Gv */ |
|
1800 |
op = R_DS; |
|
1801 |
goto do_lxx; |
|
1802 |
case 0x1b2: /* lss Gv */ |
|
1803 |
op = R_SS; |
|
1804 |
goto do_lxx; |
|
1805 |
case 0x1b4: /* lfs Gv */ |
|
1806 |
op = R_FS; |
|
1807 |
goto do_lxx; |
|
1808 |
case 0x1b5: /* lgs Gv */ |
|
1809 |
op = R_GS; |
|
1810 |
do_lxx: |
|
1811 |
ot = dflag ? OT_LONG : OT_WORD; |
|
1812 |
modrm = ldub(s->pc++); |
|
1813 |
reg = (modrm >> 3) & 7; |
|
1814 |
mod = (modrm >> 6) & 3; |
|
1815 |
if (mod == 3) |
|
1816 |
goto illegal_op; |
|
1817 |
gen_op_ld_T1_A0[ot](); |
|
1818 |
op_addl_A0_im(1 << (ot - OT_WORD + 1)); |
|
1819 |
/* load the segment first to handle exceptions properly */ |
|
1820 |
gen_op_lduw_T0_A0(); |
|
1821 |
gen_movl_seg_T0(s, op); |
|
1822 |
/* then put the data */ |
|
1823 |
gen_op_mov_reg_T1[ot][reg](); |
|
1824 |
break; |
|
1714 | 1825 |
|
1715 | 1826 |
/************************/ |
1716 | 1827 |
/* shifts */ |
... | ... | |
2327 | 2438 |
gen_op_popl_T0(); |
2328 | 2439 |
gen_op_addl_ESP_im(val); |
2329 | 2440 |
gen_op_jmp_T0(); |
2330 |
*is_jmp_ptr = 1;
|
|
2441 |
s->is_jmp = 1;
|
|
2331 | 2442 |
break; |
2332 | 2443 |
case 0xc3: /* ret */ |
2333 | 2444 |
gen_op_popl_T0(); |
2334 | 2445 |
gen_op_jmp_T0(); |
2335 |
*is_jmp_ptr = 1;
|
|
2446 |
s->is_jmp = 1;
|
|
2336 | 2447 |
break; |
2337 | 2448 |
case 0xe8: /* call */ |
2338 | 2449 |
val = insn_get(s, OT_LONG); |
... | ... | |
2340 | 2451 |
gen_op_movl_T1_im((long)s->pc); |
2341 | 2452 |
gen_op_pushl_T1(); |
2342 | 2453 |
gen_op_jmp_im(val); |
2343 |
*is_jmp_ptr = 1;
|
|
2454 |
s->is_jmp = 1;
|
|
2344 | 2455 |
break; |
2345 | 2456 |
case 0xe9: /* jmp */ |
2346 | 2457 |
val = insn_get(s, OT_LONG); |
2347 | 2458 |
val += (long)s->pc; |
2348 | 2459 |
gen_op_jmp_im(val); |
2349 |
*is_jmp_ptr = 1;
|
|
2460 |
s->is_jmp = 1;
|
|
2350 | 2461 |
break; |
2351 | 2462 |
case 0xeb: /* jmp Jb */ |
2352 | 2463 |
val = (int8_t)insn_get(s, OT_BYTE); |
2353 | 2464 |
val += (long)s->pc; |
2354 | 2465 |
gen_op_jmp_im(val); |
2355 |
*is_jmp_ptr = 1;
|
|
2466 |
s->is_jmp = 1;
|
|
2356 | 2467 |
break; |
2357 | 2468 |
case 0x70 ... 0x7f: /* jcc Jb */ |
2358 | 2469 |
val = (int8_t)insn_get(s, OT_BYTE); |
... | ... | |
2367 | 2478 |
val += (long)s->pc; /* XXX: fix 16 bit wrap */ |
2368 | 2479 |
do_jcc: |
2369 | 2480 |
gen_jcc(s, b, val); |
2370 |
*is_jmp_ptr = 1;
|
|
2481 |
s->is_jmp = 1;
|
|
2371 | 2482 |
break; |
2372 | 2483 |
|
2373 | 2484 |
case 0x190 ... 0x19f: |
... | ... | |
2548 | 2659 |
break; |
2549 | 2660 |
case 0xcc: /* int3 */ |
2550 | 2661 |
gen_op_int3((long)pc_start); |
2551 |
*is_jmp_ptr = 1;
|
|
2662 |
s->is_jmp = 1;
|
|
2552 | 2663 |
break; |
2553 | 2664 |
case 0xcd: /* int N */ |
2554 | 2665 |
val = ldub(s->pc++); |
2555 | 2666 |
/* XXX: currently we ignore the interrupt number */ |
2556 | 2667 |
gen_op_int_im((long)pc_start); |
2557 |
*is_jmp_ptr = 1;
|
|
2668 |
s->is_jmp = 1;
|
|
2558 | 2669 |
break; |
2559 | 2670 |
case 0xce: /* into */ |
2560 | 2671 |
if (s->cc_op != CC_OP_DYNAMIC) |
2561 | 2672 |
gen_op_set_cc_op(s->cc_op); |
2562 | 2673 |
gen_op_into((long)pc_start, (long)s->pc); |
2563 |
*is_jmp_ptr = 1;
|
|
2674 |
s->is_jmp = 1;
|
|
2564 | 2675 |
break; |
2565 | 2676 |
case 0x1c8 ... 0x1cf: /* bswap reg */ |
2566 | 2677 |
reg = b & 7; |
... | ... | |
2586 | 2697 |
return -1; |
2587 | 2698 |
} |
2588 | 2699 |
return (long)s->pc; |
2700 |
illegal_op: |
|
2701 |
error("illegal opcode pc=0x%08Lx", (long)pc_start); |
|
2702 |
return -1; |
|
2589 | 2703 |
} |
2590 | 2704 |
|
2591 | 2705 |
/* return the next pc */ |
2592 | 2706 |
int cpu_x86_gen_code(uint8_t *gen_code_buf, int max_code_size, |
2593 |
int *gen_code_size_ptr, uint8_t *pc_start) |
|
2707 |
int *gen_code_size_ptr, uint8_t *pc_start, |
|
2708 |
int flags) |
|
2594 | 2709 |
{ |
2595 | 2710 |
DisasContext dc1, *dc = &dc1; |
2596 | 2711 |
uint8_t *gen_code_end, *pc_ptr; |
2597 |
int is_jmp; |
|
2598 | 2712 |
long ret; |
2599 | 2713 |
#ifdef DEBUG_DISAS |
2600 | 2714 |
struct disassemble_info disasm_info; |
2601 | 2715 |
#endif |
2602 |
|
|
2716 |
dc->code32 = (flags >> GEN_FLAG_CODE32_SHIFT) & 1; |
|
2717 |
dc->addseg = (flags >> GEN_FLAG_ADDSEG_SHIFT) & 1; |
|
2718 |
dc->f_st = (flags >> GEN_FLAG_ST_SHIFT) & 7; |
|
2603 | 2719 |
dc->cc_op = CC_OP_DYNAMIC; |
2604 | 2720 |
gen_code_ptr = gen_code_buf; |
2605 | 2721 |
gen_code_end = gen_code_buf + max_code_size - 4096; |
2606 | 2722 |
gen_start(); |
2607 | 2723 |
|
2608 |
is_jmp = 0; |
|
2724 |
dc->is_jmp = 0;
|
|
2609 | 2725 |
pc_ptr = pc_start; |
2610 | 2726 |
do { |
2611 |
ret = disas_insn(dc, pc_ptr, &is_jmp);
|
|
2727 |
ret = disas_insn(dc, pc_ptr); |
|
2612 | 2728 |
if (ret == -1) |
2613 | 2729 |
error("unknown instruction at PC=0x%x B=%02x %02x", |
2614 | 2730 |
pc_ptr, pc_ptr[0], pc_ptr[1]); |
2615 | 2731 |
pc_ptr = (void *)ret; |
2616 |
} while (!is_jmp && gen_code_ptr < gen_code_end); |
|
2732 |
} while (!dc->is_jmp && gen_code_ptr < gen_code_end);
|
|
2617 | 2733 |
/* we must store the eflags state if it is not already done */ |
2618 | 2734 |
if (dc->cc_op != CC_OP_DYNAMIC) |
2619 | 2735 |
gen_op_set_cc_op(dc->cc_op); |
2620 |
if (!is_jmp) {
|
|
2736 |
if (dc->is_jmp != 1) {
|
|
2621 | 2737 |
/* we add an additionnal jmp to update the simulated PC */ |
2622 | 2738 |
gen_op_jmp_im(ret); |
2623 | 2739 |
} |
Also available in: Unified diff