LDS/LES/LFS/LGS/LSS: Fix segment wraparounds in 16-bit address mode.

This commit is contained in:
OBattler
2025-04-07 06:03:19 +02:00
parent 018ff46253
commit 3b5966eb46
15 changed files with 105 additions and 31 deletions

View File

@@ -931,6 +931,8 @@ codegen_MEM_LOAD_REG(codeblock_t *block, uop_t *uop)
host_arm64_ADD_REG(block, REG_X0, seg_reg, addr_reg, 0);
if (uop->imm_data)
host_arm64_ADD_IMM(block, REG_X0, REG_X0, uop->imm_data);
if (uop->is_a16)
host_arm64_AND_IMM(block, REG_X0, REG_X0, 0xffff);
if (REG_IS_B(dest_size) || REG_IS_BH(dest_size)) {
host_arm64_call(block, codegen_mem_load_byte);
} else if (REG_IS_W(dest_size)) {

View File

@@ -995,6 +995,8 @@ codegen_MEM_LOAD_REG(codeblock_t *block, uop_t *uop)
host_arm_ADD_REG(block, REG_R0, seg_reg, addr_reg);
if (uop->imm_data)
host_arm_ADD_IMM(block, REG_R0, REG_R0, uop->imm_data);
if (uop->is_a16)
host_arm_AND_IMM(block, REG_R0, REG_R0, 0xffff);
if (REG_IS_B(dest_size) || REG_IS_BH(dest_size)) {
host_arm_BL(block, (uintptr_t) codegen_mem_load_byte);
} else if (REG_IS_W(dest_size)) {

View File

@@ -997,8 +997,13 @@ codegen_MEM_LOAD_REG(codeblock_t *block, uop_t *uop)
int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real);
host_x86_LEA_REG_REG(block, REG_ESI, seg_reg, addr_reg);
if (uop->imm_data)
host_x86_ADD32_REG_IMM(block, REG_ESI, uop->imm_data);
if (uop->imm_data) {
if (uop->is_a16) {
host_x86_ADD16_REG_IMM(block, REG_SI, uop->imm_data);
} else {
host_x86_ADD32_REG_IMM(block, REG_ESI, uop->imm_data);
}
}
if (REG_IS_B(dest_size)) {
host_x86_CALL(block, codegen_mem_load_byte);
} else if (REG_IS_W(dest_size)) {

View File

@@ -981,8 +981,13 @@ codegen_MEM_LOAD_REG(codeblock_t *block, uop_t *uop)
int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real);
host_x86_LEA_REG_REG(block, REG_ESI, seg_reg, addr_reg);
if (uop->imm_data)
host_x86_ADD32_REG_IMM(block, REG_ESI, uop->imm_data);
if (uop->imm_data) {
if (uop->is_a16) {
host_x86_ADD16_REG_IMM(block, REG_SI, uop->imm_data);
} else {
host_x86_ADD32_REG_IMM(block, REG_ESI, uop->imm_data);
}
}
if (REG_IS_B(dest_size)) {
host_x86_CALL(block, codegen_mem_load_byte);
} else if (REG_IS_W(dest_size)) {

View File

@@ -340,6 +340,7 @@ typedef struct uop_t {
void *p;
ir_host_reg_t dest_reg_a_real;
ir_host_reg_t src_reg_a_real, src_reg_b_real, src_reg_c_real;
int is_a16;
int jump_dest_uop;
int jump_list_next;
void *jump_dest;
@@ -364,6 +365,8 @@ uop_alloc(ir_data_t *ir, uint32_t uop_type)
uop = &ir->uops[ir->wr_pos++];
uop->is_a16 = 0;
uop->dest_reg_a = invalid_ir_reg;
uop->src_reg_a = invalid_ir_reg;
uop->src_reg_b = invalid_ir_reg;
@@ -489,7 +492,12 @@ uop_gen_reg_dst_src2_imm(uint32_t uop_type, ir_data_t *ir, int dest_reg, int src
uop->type = uop_type;
uop->src_reg_a = codegen_reg_read(src_reg_a);
uop->src_reg_b = codegen_reg_read(src_reg_b);
uop->is_a16 = 0;
if (src_reg_b == IREG_eaa16) {
uop->src_reg_b = codegen_reg_read(IREG_eaaddr);
uop->is_a16 = 1;
} else
uop->src_reg_b = codegen_reg_read(src_reg_b);
uop->dest_reg_a = codegen_reg_write(dest_reg, ir->wr_pos - 1);
uop->imm_data = imm;
}

View File

@@ -533,8 +533,8 @@ ropCWDE(UNUSED(codeblock_t *block), ir_data_t *ir, UNUSED(uint8_t opcode), UNUSE
uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); \
target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); \
codegen_check_seg_read(block, ir, target_seg); \
uop_MEM_LOAD_REG(ir, IREG_temp0_W, ireg_seg_base(target_seg), IREG_eaaddr); \
uop_MEM_LOAD_REG_OFFSET(ir, IREG_temp1_W, ireg_seg_base(target_seg), IREG_eaaddr, 2); \
uop_MEM_LOAD_REG(ir, IREG_temp0_W, ireg_seg_base(target_seg), (op_32 & 0x200) ? IREG_eaaddr : IREG_eaa16); \
uop_MEM_LOAD_REG_OFFSET(ir, IREG_temp1_W, ireg_seg_base(target_seg), (op_32 & 0x200) ? IREG_eaaddr : IREG_eaa16, 2); \
uop_LOAD_SEG(ir, seg, IREG_temp1_W); \
uop_MOV(ir, IREG_16(dest_reg), IREG_temp0_W); \
\
@@ -556,8 +556,8 @@ ropCWDE(UNUSED(codeblock_t *block), ir_data_t *ir, UNUSED(uint8_t opcode), UNUSE
uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); \
target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); \
codegen_check_seg_read(block, ir, target_seg); \
uop_MEM_LOAD_REG(ir, IREG_temp0, ireg_seg_base(target_seg), IREG_eaaddr); \
uop_MEM_LOAD_REG_OFFSET(ir, IREG_temp1_W, ireg_seg_base(target_seg), IREG_eaaddr, 4); \
uop_MEM_LOAD_REG(ir, IREG_temp0, ireg_seg_base(target_seg), (op_32 & 0x200) ? IREG_eaaddr : IREG_eaa16); \
uop_MEM_LOAD_REG_OFFSET(ir, IREG_temp1_W, ireg_seg_base(target_seg), (op_32 & 0x200) ? IREG_eaaddr : IREG_eaa16, 4); \
uop_LOAD_SEG(ir, seg, IREG_temp1_W); \
uop_MOV(ir, IREG_32(dest_reg), IREG_temp0); \
\

View File

@@ -169,6 +169,8 @@ struct
[IREG_GS_limit_high] = { REG_DWORD, &cpu_state.seg_gs.limit_high, REG_INTEGER, REG_PERMANENT},
[IREG_SS_limit_high] = { REG_DWORD, &cpu_state.seg_ss.limit_high, REG_INTEGER, REG_PERMANENT},
[IREG_eaa16] = { REG_WORD, &cpu_state.eaaddr, REG_INTEGER, REG_PERMANENT},
/*Temporary registers are stored on the stack, and are not guaranteed to
be preserved across uOPs. They will not be written back if they will
not be read again.*/

View File

@@ -132,7 +132,9 @@ enum {
IREG_GS_limit_high = 86,
IREG_SS_limit_high = 87,
IREG_COUNT = 88,
IREG_eaa16 = 88,
IREG_COUNT = 89,
IREG_INVALID = 255,