# HG changeset patch # User Michael Pavone # Date 1672021004 28800 # Node ID 5b308c7b098c2beae2458bfe15c11215daa2c610 # Parent 94cca8b8429e783a961fc04110ab2eab5e34309e Avoid code mem allocation bomb when a div instruction gets rewritten diff -r 94cca8b8429e -r 5b308c7b098c backend_x86.c --- a/backend_x86.c Sat Dec 24 20:23:05 2022 -0800 +++ b/backend_x86.c Sun Dec 25 18:16:44 2022 -0800 @@ -81,11 +81,11 @@ cmp_rr(code, opts->cycles, opts->limit, SZ_D); cc = CC_A; } - check_alloc_code(code, MAX_INST_LEN*2); +ALLOC_CODE_RETRY_POINT code_ptr jmp_off = code->cur+1; jcc(code, cc, jmp_off+1); call(code, opts->handle_cycle_limit); - *jmp_off = code->cur - (jmp_off+1); + CHECK_BRANCH_DEST(jmp_off); } void log_address(cpu_options *opts, uint32_t address, char * format) diff -r 94cca8b8429e -r 5b308c7b098c gen_x86.h --- a/gen_x86.h Sat Dec 24 20:23:05 2022 -0800 +++ b/gen_x86.h Sun Dec 25 18:16:44 2022 -0800 @@ -218,6 +218,7 @@ void btc_irdisp(code_info *code, uint8_t val, uint8_t dst_base, int32_t dst_disp, uint8_t size); void jcc(code_info *code, uint8_t cc, code_ptr dest); void jmp_rind(code_info *code, uint8_t dst); +void jmp_nocheck(code_info *code, code_ptr dest); void call_noalign(code_info *code, code_ptr fun); void call_r(code_info *code, uint8_t dst); void retn(code_info *code); @@ -225,5 +226,18 @@ void loop(code_info *code, code_ptr dst); uint8_t is_mov_ir(code_ptr inst); +#define ALLOC_CODE_RETRY_POINT code_info tmp_alloc_retry = *code; alloc_code_retry: +#define ALLOC_CODE_RETRY_VAR code_info tmp_alloc_retry +#define ALLOC_CODE_RETRY_POINT_NO_VAR tmp_alloc_retry = *code; alloc_code_retry: +#define CHECK_BRANCH_DEST(ptr) if (code->cur - ((ptr) + 1) > 127 || code->cur - ((ptr) + 1) < -128) {\ + code_info next_alloc_retry = *code;\ + *code = tmp_alloc_retry;\ + next_alloc_retry.cur = next_alloc_retry.last - (CODE_ALLOC_SIZE-RESERVE_WORDS);\ + jmp_nocheck(code, next_alloc_retry.cur);\ + *code = next_alloc_retry;\ + goto alloc_code_retry;\ + }\ + *(ptr) = code->cur - ((ptr) + 1); + #endif //GEN_X86_H_ diff -r 94cca8b8429e -r 5b308c7b098c m68k_core_x86.c --- a/m68k_core_x86.c Sat Dec 24 20:23:05 2022 -0800 +++ b/m68k_core_x86.c Sun Dec 25 18:16:44 2022 -0800 @@ -353,7 +353,6 @@ void m68k_check_cycles_int_latch(m68k_options *opts) { code_info *code = &opts->gen.code; - check_alloc_code(code, 3*MAX_INST_LEN); uint8_t cc; if (opts->gen.limit < 0) { cmp_ir(code, 1, opts->gen.cycles, SZ_D); @@ -362,10 +361,11 @@ cmp_rr(code, opts->gen.cycles, opts->gen.limit, SZ_D); cc = CC_A; } +ALLOC_CODE_RETRY_POINT code_ptr jmp_off = code->cur+1; jcc(code, cc, jmp_off+1); call(code, opts->handle_int_latch); - *jmp_off = code->cur - (jmp_off+1); + CHECK_BRANCH_DEST(jmp_off) } uint8_t translate_m68k_op(m68kinst * inst, host_ea * ea, m68k_options * opts, uint8_t dst) @@ -866,7 +866,7 @@ } } else { uint8_t cc = m68k_eval_cond(opts, cond); - check_alloc_code(code, 6*MAX_INST_LEN); +ALLOC_CODE_RETRY_POINT code_ptr true_off = code->cur + 1; jcc(code, cc, code->cur+2); cycles(&opts->gen, BUS); @@ -877,14 +877,14 @@ } code_ptr end_off = code->cur+1; jmp(code, code->cur+2); - *true_off = code->cur - (true_off+1); + CHECK_BRANCH_DEST(true_off); cycles(&opts->gen, inst->dst.addr_mode == MODE_REG ? 6 : 4); if (dst_op.mode == MODE_REG_DIRECT) { mov_ir(code, 0xFF, dst_op.base, SZ_B); } else { mov_irdisp(code, 0xFF, dst_op.base, dst_op.disp, SZ_B); } - *end_off = code->cur - (end_off+1); + CHECK_BRANCH_DEST(end_off); } m68k_save_result(inst, opts); } @@ -897,9 +897,10 @@ code_ptr skip_loc = NULL; //TODO: Check if COND_TRUE technically valid here even though //it's basically a slow NOP + ALLOC_CODE_RETRY_VAR; if (inst->extra.cond != COND_FALSE) { uint8_t cond = m68k_eval_cond(opts, inst->extra.cond); - check_alloc_code(code, 6*MAX_INST_LEN); +ALLOC_CODE_RETRY_POINT_NO_VAR skip_loc = code->cur + 1; jcc(code, cond, code->cur + 2); } @@ -917,7 +918,7 @@ *loop_end_loc = code->cur - (loop_end_loc+1); if (skip_loc) { cycles(&opts->gen, 2); - *skip_loc = code->cur - (skip_loc+1); + CHECK_BRANCH_DEST(skip_loc); cycles(&opts->gen, 2); } else { cycles(&opts->gen, 4); @@ -1031,11 +1032,13 @@ code_ptr end_off = NULL; code_ptr nz_off = NULL; code_ptr z_off = NULL; + ALLOC_CODE_RETRY_VAR; if (inst->src.addr_mode == MODE_UNUSED) { cycles(&opts->gen, BUS); //Memory shift shift_ir(code, 1, dst_op->base, SZ_W); } else { +ALLOC_CODE_RETRY_POINT_NO_VAR if (src_op->mode == MODE_IMMED) { cycles(&opts->gen, (inst->extra.size == OPSIZE_LONG ? 8 : 6) + 2 * src_op->disp); if (src_op->disp != 1 && inst->op == M68K_ASL) { @@ -1046,11 +1049,10 @@ } else { shift_irdisp(code, 1, dst_op->base, dst_op->disp, inst->extra.size); } - check_alloc_code(code, 2*MAX_INST_LEN); code_ptr after_flag_set = code->cur + 1; jcc(code, CC_NO, code->cur + 2); set_flag(opts, 1, FLAG_V); - *after_flag_set = code->cur - (after_flag_set+1); + CHECK_BRANCH_DEST(after_flag_set); } } else { if (dst_op->mode == MODE_REG_DIRECT) { @@ -1071,7 +1073,6 @@ } and_ir(code, 63, RCX, SZ_D); - check_alloc_code(code, 7*MAX_INST_LEN); nz_off = code->cur + 1; jcc(code, CC_NZ, code->cur + 2); //Flag behavior for shift count of 0 is different for x86 than 68K @@ -1089,7 +1090,7 @@ } z_off = code->cur + 1; jmp(code, code->cur + 2); - *nz_off = code->cur - (nz_off + 1); + CHECK_BRANCH_DEST(nz_off); //add 2 cycles for every bit shifted mov_ir(code, 2 * opts->gen.clock_divider, opts->gen.scratch2, SZ_D); imul_rr(code, RCX, opts->gen.scratch2, SZ_D); @@ -1098,7 +1099,6 @@ //ASL has Overflow flag behavior that depends on all of the bits shifted through the MSB //Easiest way to deal with this is to shift one bit at a time set_flag(opts, 0, FLAG_V); - check_alloc_code(code, 5*MAX_INST_LEN); code_ptr loop_start = code->cur; if (dst_op->mode == MODE_REG_DIRECT) { shift_ir(code, 1, dst_op->base, inst->extra.size); @@ -1108,13 +1108,12 @@ code_ptr after_flag_set = code->cur + 1; jcc(code, CC_NO, code->cur + 2); set_flag(opts, 1, FLAG_V); - *after_flag_set = code->cur - (after_flag_set+1); + CHECK_BRANCH_DEST(after_flag_set); loop(code, loop_start); } else { //x86 shifts modulo 32 for operand sizes less than 64-bits //but M68K shifts modulo 64, so we need to check for large shifts here cmp_ir(code, 32, RCX, SZ_B); - check_alloc_code(code, 14*MAX_INST_LEN); code_ptr norm_shift_off = code->cur + 1; jcc(code, CC_L, code->cur + 2); if (special) { @@ -1132,11 +1131,11 @@ set_flag_cond(opts, CC_C, FLAG_C); after_flag_set = code->cur + 1; jmp(code, code->cur + 2); - *neq_32_off = code->cur - (neq_32_off+1); + CHECK_BRANCH_DEST(neq_32_off); } set_flag(opts, 0, FLAG_C); if (after_flag_set) { - *after_flag_set = code->cur - (after_flag_set+1); + CHECK_BRANCH_DEST(after_flag_set); } set_flag(opts, 1, FLAG_Z); set_flag(opts, 0, FLAG_N); @@ -1157,7 +1156,7 @@ } end_off = code->cur + 1; jmp(code, code->cur + 2); - *norm_shift_off = code->cur - (norm_shift_off+1); + CHECK_BRANCH_DEST(norm_shift_off); if (dst_op->mode == MODE_REG_DIRECT) { shift_clr(code, dst_op->base, inst->extra.size); } else { @@ -1168,11 +1167,11 @@ } if (!special && end_off) { - *end_off = code->cur - (end_off + 1); + CHECK_BRANCH_DEST(end_off); } update_flags(opts, C|Z|N); if (special && end_off) { - *end_off = code->cur - (end_off + 1); + CHECK_BRANCH_DEST(end_off); } //set X flag to same as C flag if (opts->flag_regs[FLAG_C] >= 0) { @@ -1181,7 +1180,7 @@ set_flag_cond(opts, CC_C, FLAG_X); } if (z_off) { - *z_off = code->cur - (z_off + 1); + CHECK_BRANCH_DEST(z_off); } if (inst->op != M68K_ASL) { set_flag(opts, 0, FLAG_V); @@ -1352,11 +1351,11 @@ if (inst->dst.addr_mode != MODE_AREG || inst->op == M68K_CMP) { update_flags(opts, flag_mask); if (inst->op == M68K_ADDX || inst->op == M68K_SUBX) { - check_alloc_code(code, 2*MAX_INST_LEN); +ALLOC_CODE_RETRY_POINT code_ptr after_flag_set = code->cur + 1; jcc(code, CC_Z, code->cur + 2); set_flag(opts, 0, FLAG_Z); - *after_flag_set = code->cur - (after_flag_set+1); + CHECK_BRANCH_DEST(after_flag_set); } } if (inst->op != M68K_CMP) { @@ -1726,15 +1725,14 @@ default: isize = 2; } - //make sure we won't start a new chunk in the middle of these branches - check_alloc_code(code, MAX_INST_LEN * 11); +ALLOC_CODE_RETRY_POINT code_ptr passed = code->cur + 1; jcc(code, CC_GE, code->cur + 2); set_flag(opts, 1, FLAG_N); mov_ir(code, VECTOR_CHK, opts->gen.scratch2, SZ_D); mov_ir(code, inst->address+isize, opts->gen.scratch1, SZ_D); jmp(code, opts->trap); - *passed = code->cur - (passed+1); + CHECK_BRANCH_DEST(passed); if (dst_op->mode == MODE_REG_DIRECT) { if (src_op->mode == MODE_REG_DIRECT) { cmp_rr(code, src_op->base, dst_op->base, inst->extra.size); @@ -1756,7 +1754,7 @@ mov_ir(code, VECTOR_CHK, opts->gen.scratch2, SZ_D); mov_ir(code, inst->address+isize, opts->gen.scratch1, SZ_D); jmp(code, opts->trap); - *passed = code->cur - (passed+1); + CHECK_BRANCH_DEST(passed); cycles(&opts->gen, 6); } @@ -1883,7 +1881,6 @@ void translate_m68k_div(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op) { code_info *code = &opts->gen.code; - check_alloc_code(code, MAX_NATIVE_SIZE); set_flag(opts, 0, FLAG_C); if (dst_op->mode == MODE_REG_DIRECT) { mov_rr(code, dst_op->base, opts->gen.scratch2, SZ_D); @@ -1901,6 +1898,7 @@ shl_ir(code, 16, opts->gen.scratch1, SZ_D); } cmp_ir(code, 0, opts->gen.scratch1, SZ_D); +ALLOC_CODE_RETRY_POINT code_ptr not_zero = code->cur+1; jcc(code, CC_NZ, not_zero); @@ -1926,8 +1924,7 @@ mov_ir(code, VECTOR_INT_DIV_ZERO, opts->gen.scratch2, SZ_D); mov_ir(code, inst->address+isize, opts->gen.scratch1, SZ_D); jmp(code, opts->trap); - - *not_zero = code->cur - (not_zero + 1); + CHECK_BRANCH_DEST(not_zero); code_ptr end = NULL; if (inst->op == M68K_DIVU) { //initial overflow check needs to be done in the C code for divs @@ -1942,7 +1939,7 @@ end = code->cur+1; jmp(code, end); - *not_overflow = code->cur - (not_overflow + 1); + CHECK_BRANCH_DEST(not_overflow); } call(code, opts->gen.save_context); push_r(code, opts->gen.context_reg); @@ -1964,7 +1961,7 @@ mov_rrdisp(code, opts->gen.scratch1, dst_op->base, dst_op->disp, SZ_D); } if (end) { - *end = code->cur - (end + 1); + CHECK_BRANCH_DEST(end); } }