1273 |
} |
} |
1274 |
} |
} |
1275 |
|
|
1276 |
static void gen_pop_update(DisasContext *s) |
static inline void gen_stack_update(DisasContext *s, int addend) |
1277 |
{ |
{ |
1278 |
if (s->ss32) { |
if (s->ss32) { |
1279 |
if (s->dflag) |
if (addend == 2) |
|
gen_op_addl_ESP_4(); |
|
|
else |
|
1280 |
gen_op_addl_ESP_2(); |
gen_op_addl_ESP_2(); |
1281 |
|
else if (addend == 4) |
1282 |
|
gen_op_addl_ESP_4(); |
1283 |
|
else |
1284 |
|
gen_op_addl_ESP_im(addend); |
1285 |
} else { |
} else { |
1286 |
if (s->dflag) |
if (addend == 2) |
1287 |
|
gen_op_addw_ESP_2(); |
1288 |
|
else if (addend == 4) |
1289 |
gen_op_addw_ESP_4(); |
gen_op_addw_ESP_4(); |
1290 |
else |
else |
1291 |
gen_op_addw_ESP_2(); |
gen_op_addw_ESP_im(addend); |
1292 |
} |
} |
1293 |
} |
} |
1294 |
|
|
1295 |
|
static void gen_pop_update(DisasContext *s) |
1296 |
|
{ |
1297 |
|
gen_stack_update(s, 2 << s->dflag); |
1298 |
|
} |
1299 |
|
|
1300 |
|
static void gen_stack_A0(DisasContext *s) |
1301 |
|
{ |
1302 |
|
gen_op_movl_A0_ESP(); |
1303 |
|
if (!s->ss32) |
1304 |
|
gen_op_andl_A0_ffff(); |
1305 |
|
gen_op_movl_T1_A0(); |
1306 |
|
if (s->addseg) |
1307 |
|
gen_op_addl_A0_seg(offsetof(CPUX86State,seg_cache[R_SS].base)); |
1308 |
|
} |
1309 |
|
|
1310 |
/* NOTE: wrap around in 16 bit not fully handled */ |
/* NOTE: wrap around in 16 bit not fully handled */ |
1311 |
static void gen_pusha(DisasContext *s) |
static void gen_pusha(DisasContext *s) |
1312 |
{ |
{ |
1976 |
} |
} |
1977 |
break; |
break; |
1978 |
case 0xc9: /* leave */ |
case 0xc9: /* leave */ |
1979 |
/* XXX: exception not precise (ESP is update before potential exception) */ |
/* XXX: exception not precise (ESP is updated before potential exception) */ |
1980 |
if (s->ss32) { |
if (s->ss32) { |
1981 |
gen_op_mov_TN_reg[OT_LONG][0][R_EBP](); |
gen_op_mov_TN_reg[OT_LONG][0][R_EBP](); |
1982 |
gen_op_mov_reg_T0[OT_LONG][R_ESP](); |
gen_op_mov_reg_T0[OT_LONG][R_ESP](); |
2472 |
break; |
break; |
2473 |
} |
} |
2474 |
break; |
break; |
2475 |
|
case 0x0c: /* fldenv mem */ |
2476 |
|
gen_op_fldenv_A0(s->dflag); |
2477 |
|
break; |
2478 |
case 0x0d: /* fldcw mem */ |
case 0x0d: /* fldcw mem */ |
2479 |
gen_op_fldcw_A0(); |
gen_op_fldcw_A0(); |
2480 |
break; |
break; |
2481 |
|
case 0x0e: /* fnstenv mem */ |
2482 |
|
gen_op_fnstenv_A0(s->dflag); |
2483 |
|
break; |
2484 |
case 0x0f: /* fnstcw mem */ |
case 0x0f: /* fnstcw mem */ |
2485 |
gen_op_fnstcw_A0(); |
gen_op_fnstcw_A0(); |
2486 |
break; |
break; |
2492 |
gen_op_fstt_ST0_A0(); |
gen_op_fstt_ST0_A0(); |
2493 |
gen_op_fpop(); |
gen_op_fpop(); |
2494 |
break; |
break; |
2495 |
|
case 0x2c: /* frstor mem */ |
2496 |
|
gen_op_frstor_A0(s->dflag); |
2497 |
|
break; |
2498 |
|
case 0x2e: /* fnsave mem */ |
2499 |
|
gen_op_fnsave_A0(s->dflag); |
2500 |
|
break; |
2501 |
case 0x2f: /* fnstsw mem */ |
case 0x2f: /* fnstsw mem */ |
2502 |
gen_op_fnstsw_A0(); |
gen_op_fnstsw_A0(); |
2503 |
break; |
break; |
2703 |
goto illegal_op; |
goto illegal_op; |
2704 |
} |
} |
2705 |
break; |
break; |
2706 |
|
case 0x1d: /* fucomi */ |
2707 |
|
if (s->cc_op != CC_OP_DYNAMIC) |
2708 |
|
gen_op_set_cc_op(s->cc_op); |
2709 |
|
gen_op_fmov_FT0_STN(opreg); |
2710 |
|
gen_op_fucomi_ST0_FT0(); |
2711 |
|
s->cc_op = CC_OP_EFLAGS; |
2712 |
|
break; |
2713 |
|
case 0x1e: /* fcomi */ |
2714 |
|
if (s->cc_op != CC_OP_DYNAMIC) |
2715 |
|
gen_op_set_cc_op(s->cc_op); |
2716 |
|
gen_op_fmov_FT0_STN(opreg); |
2717 |
|
gen_op_fcomi_ST0_FT0(); |
2718 |
|
s->cc_op = CC_OP_EFLAGS; |
2719 |
|
break; |
2720 |
case 0x2a: /* fst sti */ |
case 0x2a: /* fst sti */ |
2721 |
gen_op_fmov_STN_ST0(opreg); |
gen_op_fmov_STN_ST0(opreg); |
2722 |
break; |
break; |
2754 |
goto illegal_op; |
goto illegal_op; |
2755 |
} |
} |
2756 |
break; |
break; |
2757 |
|
case 0x3d: /* fucomip */ |
2758 |
|
if (s->cc_op != CC_OP_DYNAMIC) |
2759 |
|
gen_op_set_cc_op(s->cc_op); |
2760 |
|
gen_op_fmov_FT0_STN(opreg); |
2761 |
|
gen_op_fucomi_ST0_FT0(); |
2762 |
|
gen_op_fpop(); |
2763 |
|
s->cc_op = CC_OP_EFLAGS; |
2764 |
|
break; |
2765 |
|
case 0x3e: /* fcomip */ |
2766 |
|
if (s->cc_op != CC_OP_DYNAMIC) |
2767 |
|
gen_op_set_cc_op(s->cc_op); |
2768 |
|
gen_op_fmov_FT0_STN(opreg); |
2769 |
|
gen_op_fcomi_ST0_FT0(); |
2770 |
|
gen_op_fpop(); |
2771 |
|
s->cc_op = CC_OP_EFLAGS; |
2772 |
|
break; |
2773 |
default: |
default: |
2774 |
goto illegal_op; |
goto illegal_op; |
2775 |
} |
} |
2962 |
val = ldsw(s->pc); |
val = ldsw(s->pc); |
2963 |
s->pc += 2; |
s->pc += 2; |
2964 |
gen_pop_T0(s); |
gen_pop_T0(s); |
2965 |
if (s->ss32) |
gen_stack_update(s, val + (2 << s->dflag)); |
|
gen_op_addl_ESP_im(val + (2 << s->dflag)); |
|
|
else |
|
|
gen_op_addw_ESP_im(val + (2 << s->dflag)); |
|
2966 |
if (s->dflag == 0) |
if (s->dflag == 0) |
2967 |
gen_op_andl_T0_ffff(); |
gen_op_andl_T0_ffff(); |
2968 |
gen_op_jmp_T0(); |
gen_op_jmp_T0(); |
2977 |
s->is_jmp = 1; |
s->is_jmp = 1; |
2978 |
break; |
break; |
2979 |
case 0xca: /* lret im */ |
case 0xca: /* lret im */ |
|
/* XXX: not restartable */ |
|
2980 |
val = ldsw(s->pc); |
val = ldsw(s->pc); |
2981 |
s->pc += 2; |
s->pc += 2; |
2982 |
|
do_lret: |
2983 |
|
gen_stack_A0(s); |
2984 |
/* pop offset */ |
/* pop offset */ |
2985 |
gen_pop_T0(s); |
gen_op_ld_T0_A0[1 + s->dflag](); |
2986 |
if (s->dflag == 0) |
if (s->dflag == 0) |
2987 |
gen_op_andl_T0_ffff(); |
gen_op_andl_T0_ffff(); |
2988 |
|
/* NOTE: keeping EIP updated is not a problem in case of |
2989 |
|
exception */ |
2990 |
gen_op_jmp_T0(); |
gen_op_jmp_T0(); |
|
gen_pop_update(s); |
|
2991 |
/* pop selector */ |
/* pop selector */ |
2992 |
gen_pop_T0(s); |
gen_op_addl_A0_im(2 << s->dflag); |
2993 |
|
gen_op_ld_T0_A0[1 + s->dflag](); |
2994 |
gen_movl_seg_T0(s, R_CS, pc_start - s->cs_base); |
gen_movl_seg_T0(s, R_CS, pc_start - s->cs_base); |
|
gen_pop_update(s); |
|
2995 |
/* add stack offset */ |
/* add stack offset */ |
2996 |
if (s->ss32) |
gen_stack_update(s, val + (4 << s->dflag)); |
|
gen_op_addl_ESP_im(val); |
|
|
else |
|
|
gen_op_addw_ESP_im(val); |
|
2997 |
s->is_jmp = 1; |
s->is_jmp = 1; |
2998 |
break; |
break; |
2999 |
case 0xcb: /* lret */ |
case 0xcb: /* lret */ |
3000 |
/* XXX: not restartable */ |
val = 0; |
3001 |
/* pop offset */ |
goto do_lret; |
|
gen_pop_T0(s); |
|
|
if (s->dflag == 0) |
|
|
gen_op_andl_T0_ffff(); |
|
|
gen_op_jmp_T0(); |
|
|
gen_pop_update(s); |
|
|
/* pop selector */ |
|
|
gen_pop_T0(s); |
|
|
gen_movl_seg_T0(s, R_CS, pc_start - s->cs_base); |
|
|
gen_pop_update(s); |
|
|
s->is_jmp = 1; |
|
|
break; |
|
3002 |
case 0xcf: /* iret */ |
case 0xcf: /* iret */ |
3003 |
if (s->vm86 && s->iopl != 3) { |
if (s->vm86 && s->iopl != 3) { |
3004 |
gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); |
gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); |
3005 |
} else { |
} else { |
3006 |
/* XXX: not restartable */ |
/* XXX: not restartable */ |
3007 |
|
gen_stack_A0(s); |
3008 |
/* pop offset */ |
/* pop offset */ |
3009 |
gen_pop_T0(s); |
gen_op_ld_T0_A0[1 + s->dflag](); |
3010 |
if (s->dflag == 0) |
if (s->dflag == 0) |
3011 |
gen_op_andl_T0_ffff(); |
gen_op_andl_T0_ffff(); |
3012 |
gen_op_jmp_T0(); |
/* NOTE: keeping EIP updated is not a problem in case of |
3013 |
gen_pop_update(s); |
exception */ |
3014 |
|
gen_op_jmp_T0(); |
3015 |
/* pop selector */ |
/* pop selector */ |
3016 |
gen_pop_T0(s); |
gen_op_addl_A0_im(2 << s->dflag); |
3017 |
gen_movl_seg_T0(s, R_CS, pc_start - s->cs_base); |
gen_op_ld_T0_A0[1 + s->dflag](); |
|
gen_pop_update(s); |
|
3018 |
/* pop eflags */ |
/* pop eflags */ |
3019 |
gen_pop_T0(s); |
gen_op_addl_A0_im(2 << s->dflag); |
3020 |
|
gen_op_ld_T1_A0[1 + s->dflag](); |
3021 |
|
gen_movl_seg_T0(s, R_CS, pc_start - s->cs_base); |
3022 |
|
gen_op_movl_T0_T1(); |
3023 |
if (s->dflag) { |
if (s->dflag) { |
3024 |
gen_op_movl_eflags_T0(); |
gen_op_movl_eflags_T0(); |
3025 |
} else { |
} else { |
3026 |
gen_op_movw_eflags_T0(); |
gen_op_movw_eflags_T0(); |
3027 |
} |
} |
3028 |
gen_pop_update(s); |
gen_stack_update(s, (6 << s->dflag)); |
3029 |
s->cc_op = CC_OP_EFLAGS; |
s->cc_op = CC_OP_EFLAGS; |
3030 |
} |
} |
3031 |
s->is_jmp = 1; |
s->is_jmp = 1; |
3047 |
case 0x9a: /* lcall im */ |
case 0x9a: /* lcall im */ |
3048 |
{ |
{ |
3049 |
unsigned int selector, offset; |
unsigned int selector, offset; |
3050 |
|
/* XXX: not restartable */ |
3051 |
|
|
3052 |
ot = dflag ? OT_LONG : OT_WORD; |
ot = dflag ? OT_LONG : OT_WORD; |
3053 |
offset = insn_get(s, ot); |
offset = insn_get(s, ot); |
3664 |
[INDEX_op_cmpxchg8b] = CC_Z, |
[INDEX_op_cmpxchg8b] = CC_Z, |
3665 |
[INDEX_op_lar] = CC_Z, |
[INDEX_op_lar] = CC_Z, |
3666 |
[INDEX_op_lsl] = CC_Z, |
[INDEX_op_lsl] = CC_Z, |
3667 |
|
[INDEX_op_fcomi_ST0_FT0] = CC_Z | CC_P | CC_C, |
3668 |
|
[INDEX_op_fucomi_ST0_FT0] = CC_Z | CC_P | CC_C, |
3669 |
}; |
}; |
3670 |
|
|
3671 |
/* simpler form of an operation if no flags need to be generated */ |
/* simpler form of an operation if no flags need to be generated */ |