static uint32_t ropJMP_r8(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) { uint32_t offset = fetchdat & 0xff; if (offset & 0x80) offset |= 0xffffff00; STORE_IMM_ADDR_L((uintptr_t)&cpu_state.pc, op_pc+1+offset); return -1; } static uint32_t ropJMP_r16(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) { uint16_t offset = fetchdat & 0xffff; STORE_IMM_ADDR_L((uintptr_t)&cpu_state.pc, (op_pc+2+offset) & 0xffff); return -1; } static uint32_t ropJMP_r32(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) { uint32_t offset = fastreadl(cs + op_pc); STORE_IMM_ADDR_L((uintptr_t)&cpu_state.pc, op_pc+4+offset); return -1; } static uint32_t ropJCXZ(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) { uint32_t offset = fetchdat & 0xff; if (offset & 0x80) offset |= 0xffffff00; if (op_32 & 0x200) { int host_reg = LOAD_REG_L(REG_ECX); TEST_ZERO_JUMP_L(host_reg, op_pc+1+offset, 0); } else { int host_reg = LOAD_REG_W(REG_CX); TEST_ZERO_JUMP_W(host_reg, op_pc+1+offset, 0); } return op_pc+1; } static uint32_t ropLOOP(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) { uint32_t offset = fetchdat & 0xff; if (offset & 0x80) offset |= 0xffffff00; if (op_32 & 0x200) { int host_reg = LOAD_REG_L(REG_ECX); SUB_HOST_REG_IMM(host_reg, 1); STORE_REG_L_RELEASE(host_reg); TEST_NONZERO_JUMP_L(host_reg, op_pc+1+offset, 0); } else { int host_reg = LOAD_REG_W(REG_CX); SUB_HOST_REG_IMM(host_reg, 1); STORE_REG_W_RELEASE(host_reg); TEST_NONZERO_JUMP_W(host_reg, op_pc+1+offset, 0); } return op_pc+1; } static int BRANCH_COND_B(int pc_offset, uint32_t op_pc, uint32_t offset, int not) { CALL_FUNC(CF_SET); if (not) TEST_ZERO_JUMP_L(0, op_pc+pc_offset+offset, timing_bt); else TEST_NONZERO_JUMP_L(0, op_pc+pc_offset+offset, timing_bt); } static int BRANCH_COND_E(int pc_offset, uint32_t op_pc, uint32_t offset, int not) { int host_reg; switch (codegen_flags_changed ? cpu_state.flags_op : FLAGS_UNKNOWN) { case FLAGS_ZN8: case FLAGS_ZN16: case FLAGS_ZN32: case FLAGS_ADD8: case FLAGS_ADD16: case FLAGS_ADD32: case FLAGS_SUB8: case FLAGS_SUB16: case FLAGS_SUB32: case FLAGS_SHL8: case FLAGS_SHL16: case FLAGS_SHL32: case FLAGS_SHR8: case FLAGS_SHR16: case FLAGS_SHR32: case FLAGS_SAR8: case FLAGS_SAR16: case FLAGS_SAR32: case FLAGS_INC8: case FLAGS_INC16: case FLAGS_INC32: case FLAGS_DEC8: case FLAGS_DEC16: case FLAGS_DEC32: host_reg = LOAD_VAR_L((uintptr_t)&cpu_state.flags_res); if (not) TEST_NONZERO_JUMP_L(host_reg, op_pc+pc_offset+offset, timing_bt); else TEST_ZERO_JUMP_L(host_reg, op_pc+pc_offset+offset, timing_bt); break; case FLAGS_UNKNOWN: CALL_FUNC(ZF_SET); if (not) TEST_ZERO_JUMP_L(0, op_pc+pc_offset+offset, timing_bt); else TEST_NONZERO_JUMP_L(0, op_pc+pc_offset+offset, timing_bt); break; } } static int BRANCH_COND_O(int pc_offset, uint32_t op_pc, uint32_t offset, int not) { CALL_FUNC(VF_SET); if (not) TEST_ZERO_JUMP_L(0, op_pc+pc_offset+offset, timing_bt); else TEST_NONZERO_JUMP_L(0, op_pc+pc_offset+offset, timing_bt); } static int BRANCH_COND_P(int pc_offset, uint32_t op_pc, uint32_t offset, int not) { CALL_FUNC(PF_SET); if (not) TEST_ZERO_JUMP_L(0, op_pc+pc_offset+offset, timing_bt); else TEST_NONZERO_JUMP_L(0, op_pc+pc_offset+offset, timing_bt); } static int BRANCH_COND_S(int pc_offset, uint32_t op_pc, uint32_t offset, int not) { int host_reg; switch (codegen_flags_changed ? cpu_state.flags_op : FLAGS_UNKNOWN) { case FLAGS_ZN8: case FLAGS_ADD8: case FLAGS_SUB8: case FLAGS_SHL8: case FLAGS_SHR8: case FLAGS_SAR8: case FLAGS_INC8: case FLAGS_DEC8: host_reg = LOAD_VAR_L((uintptr_t)&cpu_state.flags_res); AND_HOST_REG_IMM(host_reg, 0x80); if (not) TEST_ZERO_JUMP_L(host_reg, op_pc+pc_offset+offset, timing_bt); else TEST_NONZERO_JUMP_L(host_reg, op_pc+pc_offset+offset, timing_bt); break; case FLAGS_ZN16: case FLAGS_ADD16: case FLAGS_SUB16: case FLAGS_SHL16: case FLAGS_SHR16: case FLAGS_SAR16: case FLAGS_INC16: case FLAGS_DEC16: host_reg = LOAD_VAR_L((uintptr_t)&cpu_state.flags_res); AND_HOST_REG_IMM(host_reg, 0x8000); if (not) TEST_ZERO_JUMP_L(host_reg, op_pc+pc_offset+offset, timing_bt); else TEST_NONZERO_JUMP_L(host_reg, op_pc+pc_offset+offset, timing_bt); break; case FLAGS_ZN32: case FLAGS_ADD32: case FLAGS_SUB32: case FLAGS_SHL32: case FLAGS_SHR32: case FLAGS_SAR32: case FLAGS_INC32: case FLAGS_DEC32: host_reg = LOAD_VAR_L((uintptr_t)&cpu_state.flags_res); AND_HOST_REG_IMM(host_reg, 0x80000000); if (not) TEST_ZERO_JUMP_L(host_reg, op_pc+pc_offset+offset, timing_bt); else TEST_NONZERO_JUMP_L(host_reg, op_pc+pc_offset+offset, timing_bt); break; case FLAGS_UNKNOWN: CALL_FUNC(NF_SET); if (not) TEST_ZERO_JUMP_L(0, op_pc+pc_offset+offset, timing_bt); else TEST_NONZERO_JUMP_L(0, op_pc+pc_offset+offset, timing_bt); break; } } #define ropBRANCH(name, func, not) \ static uint32_t rop ## name(uint8_t opcode, uint32_t fetchdat, \ uint32_t op_32, uint32_t op_pc, \ codeblock_t *block) \ { \ uint32_t offset = fetchdat & 0xff; \ \ if (offset & 0x80) \ offset |= 0xffffff00; \ \ func(1, op_pc, offset, not); \ \ return op_pc+1; \ } \ static uint32_t rop ## name ## _w(uint8_t opcode, \ uint32_t fetchdat, uint32_t op_32, \ uint32_t op_pc, codeblock_t *block) \ { \ uint32_t offset = fetchdat & 0xffff; \ \ if (offset & 0x8000) \ offset |= 0xffff0000; \ \ func(2, op_pc, offset, not); \ \ return op_pc+2; \ } \ static uint32_t rop ## name ## _l(uint8_t opcode, \ uint32_t fetchdat, uint32_t op_32, \ uint32_t op_pc, codeblock_t *block) \ { \ uint32_t offset = fastreadl(cs + op_pc); \ \ func(4, op_pc, offset, not); \ \ return op_pc+4; \ } ropBRANCH(JB, BRANCH_COND_B, 0) ropBRANCH(JNB, BRANCH_COND_B, 1) ropBRANCH(JE, BRANCH_COND_E, 0) ropBRANCH(JNE, BRANCH_COND_E, 1) ropBRANCH(JO, BRANCH_COND_O, 0) ropBRANCH(JNO, BRANCH_COND_O, 1) ropBRANCH(JP, BRANCH_COND_P, 0) ropBRANCH(JNP, BRANCH_COND_P, 1) ropBRANCH(JS, BRANCH_COND_S, 0) ropBRANCH(JNS, BRANCH_COND_S, 1) ropBRANCH(JL, BRANCH_COND_L, 0) ropBRANCH(JNL, BRANCH_COND_L, 1) ropBRANCH(JLE, BRANCH_COND_LE, 0) ropBRANCH(JNLE, BRANCH_COND_LE, 1) ropBRANCH(JBE, BRANCH_COND_BE, 0) ropBRANCH(JNBE, BRANCH_COND_BE, 1)