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, &reg_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