diff options
Diffstat (limited to 'src/dynarec')
| -rw-r--r-- | src/dynarec/arm64/dynarec_arm64_00.c | 30 | ||||
| -rw-r--r-- | src/dynarec/arm64/dynarec_arm64_64.c | 2 | ||||
| -rw-r--r-- | src/dynarec/arm64/dynarec_arm64_67.c | 2 | ||||
| -rw-r--r-- | src/dynarec/arm64/dynarec_arm64_avx_f2_0f.c | 4 | ||||
| -rw-r--r-- | src/dynarec/arm64/dynarec_arm64_consts.c | 7 | ||||
| -rw-r--r-- | src/dynarec/arm64/dynarec_arm64_consts.h | 1 | ||||
| -rw-r--r-- | src/dynarec/arm64/dynarec_arm64_f20f.c | 4 | ||||
| -rw-r--r-- | src/dynarec/arm64/dynarec_arm64_helper.c | 23 | ||||
| -rw-r--r-- | src/dynarec/arm64/dynarec_arm64_helper.h | 57 | ||||
| -rw-r--r-- | src/dynarec/arm64/dynarec_arm64_pass2.h | 18 | ||||
| -rw-r--r-- | src/dynarec/arm64/dynarec_arm64_pass3.h | 16 | ||||
| -rw-r--r-- | src/dynarec/dynablock.c | 17 | ||||
| -rw-r--r-- | src/dynarec/dynablock_private.h | 4 | ||||
| -rw-r--r-- | src/dynarec/dynacache_reloc.c | 84 | ||||
| -rw-r--r-- | src/dynarec/dynacache_reloc.h | 4 | ||||
| -rw-r--r-- | src/dynarec/dynarec_native.c | 67 | ||||
| -rw-r--r-- | src/dynarec/la64/dynarec_la64_00.c | 8 |
17 files changed, 251 insertions, 97 deletions
diff --git a/src/dynarec/arm64/dynarec_arm64_00.c b/src/dynarec/arm64/dynarec_arm64_00.c index 75d963af..219fa44c 100644 --- a/src/dynarec/arm64/dynarec_arm64_00.c +++ b/src/dynarec/arm64/dynarec_arm64_00.c @@ -3365,7 +3365,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin #endif } #if STEP < 2 - if (!rex.is32bits && IsNativeCall(addr + i32, rex.is32bits, &dyn->insts[ninst].natcall, &dyn->insts[ninst].retn)) + if (!rex.is32bits && !dyn->need_reloc && IsNativeCall(addr + i32, rex.is32bits, &dyn->insts[ninst].natcall, &dyn->insts[ninst].retn)) tmp = dyn->insts[ninst].pass2choice = 3; else tmp = dyn->insts[ninst].pass2choice = i32?0:1; @@ -3377,8 +3377,14 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin SETFLAGS(X_ALL, SF_SET_NODF); // Hack to set flags to "dont'care" state if(dyn->last_ip && (addr-dyn->last_ip<0x1000)) { ADDx_U12(x2, xRIP, addr-dyn->last_ip); + } else if(dyn->last_ip && (dyn->last_ip-addr<0x1000)) { + SUBx_U12(x2, xRIP, dyn->last_ip-addr); } else { - MOV64x(x2, addr); + if(dyn->need_reloc) { + TABLE64(x2, addr); + } else { + MOV64x(x2, addr); + } } PUSH1(x2); MESSAGE(LOG_DUMP, "Native Call to %s (retn=%d)\n", GetBridgeName((void*)(dyn->insts[ninst].natcall - 1)) ?: GetNativeName(GetNativeFnc(dyn->insts[ninst].natcall - 1)), dyn->insts[ninst].retn); @@ -3406,6 +3412,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin CALL_S(const_int3, -1); SMWRITE2(); LOAD_XEMU_CALL(xRIP); + // in case of dyn->need_reloc, the previous GETIP_ will end up in a TABLE64 that will generate a RELOC_CANCELBLOCK as natcall will be out of the mmap space anyway MOV64x(x3, dyn->insts[ninst].natcall); ADDx_U12(x3, x3, 2+8+8); CMPSx_REG(xRIP, x3); @@ -3424,7 +3431,11 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin break; case 1: // this is call to next step, so just push the return address to the stack - MOV64x(x2, addr); + if(dyn->need_reloc) { + TABLE64(x2, addr); + } else { + MOV64x(x2, addr); + } PUSH1z(x2); break; default: @@ -3434,7 +3445,11 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin SETFLAGS(X_ALL, SF_SET_NODF); // Hack to set flags to "dont'care" state } // regular call - MOV64x(x2, addr); + if(dyn->need_reloc) { + TABLE64(x2, addr); + } else { + MOV64x(x2, addr); + } fpu_purgecache(dyn, ninst, 1, x1, x3, x4); PUSH1z(x2); if (BOX64DRENV(dynarec_callret)) { @@ -3471,7 +3486,12 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin // jumps out of current dynablock... MARK; j64 = getJumpTableAddress64(addr); - MOV64x(x4, j64); + if(dyn->need_reloc) { + AddRelocTable64JmpTbl(dyn, ninst, addr, STEP); + TABLE64_(x4, j64); + } else { + MOV64x(x4, j64); + } LDRx_U12(x4, x4, 0); BR(x4); } diff --git a/src/dynarec/arm64/dynarec_arm64_64.c b/src/dynarec/arm64/dynarec_arm64_64.c index de10a343..63f0b6af 100644 --- a/src/dynarec/arm64/dynarec_arm64_64.c +++ b/src/dynarec/arm64/dynarec_arm64_64.c @@ -1648,7 +1648,7 @@ uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin MARK; j64 = getJumpTableAddress64(addr); if(dyn->need_reloc) AddRelocTable64RetEndBlock(dyn, ninst, addr, STEP); - TABLE64(x4, j64); + TABLE64_(x4, j64); LDRx_U12(x4, x4, 0); BR(x4); } diff --git a/src/dynarec/arm64/dynarec_arm64_67.c b/src/dynarec/arm64/dynarec_arm64_67.c index f44cb687..e6755147 100644 --- a/src/dynarec/arm64/dynarec_arm64_67.c +++ b/src/dynarec/arm64/dynarec_arm64_67.c @@ -1749,7 +1749,7 @@ uintptr_t dynarec64_67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin MARK; j64 = getJumpTableAddress64(addr); if(dyn->need_reloc) AddRelocTable64RetEndBlock(dyn, ninst, addr, STEP); - TABLE64(x4, j64); + TABLE64_(x4, j64); LDRx_U12(x4, x4, 0); BR(x4); } diff --git a/src/dynarec/arm64/dynarec_arm64_avx_f2_0f.c b/src/dynarec/arm64/dynarec_arm64_avx_f2_0f.c index d1953a79..ab644ee8 100644 --- a/src/dynarec/arm64/dynarec_arm64_avx_f2_0f.c +++ b/src/dynarec/arm64/dynarec_arm64_avx_f2_0f.c @@ -509,9 +509,7 @@ uintptr_t dynarec64_AVX_F2_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, INST_NAME("VADDSUBPS Gx, Vx, Ex"); nextop = F8; q0 = fpu_get_scratch(dyn, ninst); - static float addsubps[4] = {-1.f, 1.f, -1.f, 1.f}; - MAYUSE(addsubps); - MOV64x(x2, (uintptr_t)&addsubps); + TABLE64C(x2, const_4f_m1_1_m1_1); VLDR128_U12(q0, x2, 0); for(int l=0; l<1+vex.l; ++l) { if(!l) { GETGX_empty_VXEX(v0, v2, v1, 0); } else { GETGY_empty_VYEY(v0, v2, v1); } diff --git a/src/dynarec/arm64/dynarec_arm64_consts.c b/src/dynarec/arm64/dynarec_arm64_consts.c index ce59c954..d30c0bd2 100644 --- a/src/dynarec/arm64/dynarec_arm64_consts.c +++ b/src/dynarec/arm64/dynarec_arm64_consts.c @@ -21,6 +21,7 @@ #include "emu/x87emu_private.h" #include "emu/x64compstrings.h" #include "x64test.h" +#include "dynarec/dynarec_next.h" static const int8_t mask_shift8[] = { -7, -6, -5, -4, -3, -2, -1, 0 }; static const int8_t mask_string8[] = { 7, 6, 5, 4, 3, 2, 1, 0 }; @@ -30,9 +31,6 @@ static const double addsubpd[2] = {-1., 1.}; static const float subaddps[4] = {1.f, -1.f, 1.f, -1.f}; static const double subaddpd[2] = {1., -1.}; -void arm64_epilog(void); -void* arm64_next(x64emu_t* emu, uintptr_t addr); - #ifndef HAVE_TRACE void PrintTrace() {} #endif @@ -84,6 +82,7 @@ uintptr_t getConst(arm64_consts_t which) case const_native_fld: return (uintptr_t)native_fld; case const_native_fstp: return (uintptr_t)native_fstp; case const_native_frstor: return (uintptr_t)native_frstor; + case const_native_next: return (uintptr_t)native_next; case const_int3: return (uintptr_t)EmuInt3; case const_x86syscall: return (uintptr_t)EmuX86Syscall; case const_x64syscall: return (uintptr_t)EmuX64Syscall; @@ -122,7 +121,7 @@ uintptr_t getConst(arm64_consts_t which) case const_sse42_compare_string_implicit_len: return (uintptr_t)sse42_compare_string_implicit_len; case const_x64test_step: return (uintptr_t)x64test_step; case const_printtrace: return (uintptr_t)PrintTrace; - case const_epilog: return (uintptr_t)arm64_epilog; + case const_epilog: return (uintptr_t)native_epilog; case const_jmptbl32: return getJumpTable32(); case const_jmptbl48: return getJumpTable48(); case const_jmptbl64: return getJumpTable64(); diff --git a/src/dynarec/arm64/dynarec_arm64_consts.h b/src/dynarec/arm64/dynarec_arm64_consts.h index 71e2bdce..9ba65aca 100644 --- a/src/dynarec/arm64/dynarec_arm64_consts.h +++ b/src/dynarec/arm64/dynarec_arm64_consts.h @@ -46,6 +46,7 @@ typedef enum arm64_consts_s { const_native_fld, const_native_fstp, const_native_frstor, + const_native_next, const_int3, const_x86syscall, const_x64syscall, diff --git a/src/dynarec/arm64/dynarec_arm64_f20f.c b/src/dynarec/arm64/dynarec_arm64_f20f.c index 6e13def9..e6289479 100644 --- a/src/dynarec/arm64/dynarec_arm64_f20f.c +++ b/src/dynarec/arm64/dynarec_arm64_f20f.c @@ -523,9 +523,7 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n GETGX(v0, 1); GETEX(v1, 0, 0); q0 = fpu_get_scratch(dyn, ninst); - static float addsubps[4] = {-1.f, 1.f, -1.f, 1.f}; - MAYUSE(addsubps); - MOV64x(x2, (uintptr_t)&addsubps); // no need to use table64, as box64 is loaded in low memory + TABLE64C(x2, const_4f_m1_1_m1_1); VLDR128_U12(q0, x2, 0); VFMLAQS(v0, v1, q0); break; diff --git a/src/dynarec/arm64/dynarec_arm64_helper.c b/src/dynarec/arm64/dynarec_arm64_helper.c index d4817803..e6ee1b70 100644 --- a/src/dynarec/arm64/dynarec_arm64_helper.c +++ b/src/dynarec/arm64/dynarec_arm64_helper.c @@ -101,7 +101,7 @@ uintptr_t geted(dynarec_arm_t* dyn, uintptr_t addr, int ninst, uint8_t nextop, u } else if(tmp<0 && tmp>-0x1000) { GETIP(addr+delta); SUBx_U12(ret, xRIP, -tmp); - } else if(tmp+addr+delta<0x1000000000000LL) { // 3 opcodes to load immediate is cheap enough + } else if((tmp+addr+delta<0x1000000000000LL) && !dyn->need_reloc) { // 3 opcodes to load immediate is cheap enough MOV64x(ret, tmp+addr+delta); } else { MOV64x(ret, tmp); @@ -575,7 +575,11 @@ static int indirect_lookup(dynarec_arm_t* dyn, int ninst, int is32bits, int s1, LSRx_IMM(s1, xRIP, 48); CBNZw(s1, (intptr_t)dyn->jmp_next - (intptr_t)dyn->block); // load table - MOV64x(s2, getConst(const_jmptbl48)); // this is a static value, so will be a low address + if(dyn->need_reloc) { + TABLE64C(s2, const_jmptbl48); + } else { + MOV64x(s2, getConst(const_jmptbl48)); // this is a static value, so will be a low address + } #ifdef JMPTABL_SHIFT4 UBFXx(s1, xRIP, JMPTABL_START3, JMPTABL_SHIFT3); LDRx_REG_LSL3(s2, s2, s1); @@ -751,7 +755,11 @@ void iret_to_epilog(dynarec_arm_t* dyn, uintptr_t ip, int ninst, int is32bits, i MOVx_REG(xRSP, x3); MARKSEG; // Ret.... - MOV64x(x2, getConst(const_epilog)); // epilog on purpose, CS might have changed! + // epilog on purpose, CS might have changed! + if(dyn->need_reloc) + TABLE64C(x2, const_epilog); + else + MOV64x(x2, getConst(const_epilog)); BR(x2); CLEARIP(); } @@ -880,8 +888,13 @@ void call_n(dynarec_arm_t* dyn, int ninst, void* fnc, int w) MOVx_REG(x4, xR8); MOVx_REG(x5, xR9); // native call - // fnc is indirect, to help with relocation (but PltResolver might be an issue here) - TABLE64(16, *(uintptr_t*)fnc); // using x16 as scratch regs for call address + if(dyn->need_reloc) { + // fnc is indirect, to help with relocation (but PltResolver might be an issue here) + TABLE64(16, (uintptr_t)fnc); + LDRx_U12(16, 16, 0); + } else { + TABLE64_(16, *(uintptr_t*)fnc); // using x16 as scratch regs for call address + } BLR(16); // put return value in x64 regs if(w>0) { diff --git a/src/dynarec/arm64/dynarec_arm64_helper.h b/src/dynarec/arm64/dynarec_arm64_helper.h index 8806777c..63418126 100644 --- a/src/dynarec/arm64/dynarec_arm64_helper.h +++ b/src/dynarec/arm64/dynarec_arm64_helper.h @@ -1229,31 +1229,40 @@ #define GETIP_(A) MOV64x(xRIP, A) #else // put value in the Table64 even if not using it for now to avoid difference between Step2 and Step3. Needs to be optimized later... -#define GETIP(A) \ - if(dyn->last_ip && ((A)-dyn->last_ip)<0x1000) { \ - uint64_t _delta_ip = (A)-dyn->last_ip; \ - dyn->last_ip += _delta_ip; \ - if(_delta_ip) { \ - ADDx_U12(xRIP, xRIP, _delta_ip); \ - } \ - } else { \ - dyn->last_ip = (A); \ - if(dyn->need_reloc) { \ - TABLE64(xRIP, dyn->last_ip); \ - } else { \ - MOV64x(xRIP, dyn->last_ip); \ - } \ +#define GETIP(A) \ + if(dyn->last_ip && ((A)-dyn->last_ip)<0x1000) { \ + uint64_t _delta_ip = (A)-dyn->last_ip; \ + dyn->last_ip += _delta_ip; \ + if(_delta_ip) { \ + ADDx_U12(xRIP, xRIP, _delta_ip); \ + } \ + } else if(dyn->last_ip && (dyn->last_ip-(A))<0x1000) { \ + uint64_t _delta_ip = dyn->last_ip-(A); \ + dyn->last_ip -= _delta_ip; \ + if(_delta_ip) { \ + SUBx_U12(xRIP, xRIP, _delta_ip); \ + } \ + } else { \ + dyn->last_ip = (A); \ + if(dyn->need_reloc) { \ + TABLE64(xRIP, dyn->last_ip); \ + } else { \ + MOV64x(xRIP, dyn->last_ip); \ + } \ } -#define GETIP_(A) \ - if(dyn->last_ip && ((A)-dyn->last_ip)<0x1000) { \ - uint64_t _delta_ip = (A)-dyn->last_ip; \ - if(_delta_ip) {ADDx_U12(xRIP, xRIP, _delta_ip);}\ - } else { \ - if(dyn->need_reloc) { \ - TABLE64(xRIP, (A)); \ - } else { \ - MOV64x(xRIP, (A)); \ - } \ +#define GETIP_(A) \ + if(dyn->last_ip && ((A)-dyn->last_ip)<0x1000) { \ + uint64_t _delta_ip = (A)-dyn->last_ip; \ + if(_delta_ip) {ADDx_U12(xRIP, xRIP, _delta_ip);} \ + } else if(dyn->last_ip && (dyn->last_ip-(A))<0x1000) { \ + uint64_t _delta_ip = dyn->last_ip-(A); \ + if(_delta_ip) {SUBx_U12(xRIP, xRIP, _delta_ip);} \ + } else { \ + if(dyn->need_reloc) { \ + TABLE64(xRIP, (A)); \ + } else { \ + MOV64x(xRIP, (A)); \ + } \ } #endif #define CLEARIP() dyn->last_ip=0 diff --git a/src/dynarec/arm64/dynarec_arm64_pass2.h b/src/dynarec/arm64/dynarec_arm64_pass2.h index 6bedf76a..90abb349 100644 --- a/src/dynarec/arm64/dynarec_arm64_pass2.h +++ b/src/dynarec/arm64/dynarec_arm64_pass2.h @@ -15,19 +15,19 @@ } #define INST_EPILOG dyn->insts[ninst].epilog = dyn->native_size; #define INST_NAME(name) -#define TABLE64(A, V) { \ - if(dyn->need_reloc && !isTable64(dyn, (V))) \ +#define TABLE64(A, V) do { \ + if(dyn->need_reloc) \ AddRelocTable64Addr(dyn, ninst, (V), 2); \ Table64(dyn, (V), 2); EMIT(0); \ - } -#define TABLE64_(A, V) { \ + } while(0) +#define TABLE64_(A, V) do { \ Table64(dyn, (V), 2); EMIT(0); \ - } -#define TABLE64C(A, V) { \ - if(dyn->need_reloc && !isTable64(dyn, getConst(V))) \ + } while(0) +#define TABLE64C(A, V) do { \ + if(dyn->need_reloc) \ AddRelocTable64Const(dyn, ninst, (V), 2); \ Table64(dyn, getConst(V), 2); EMIT(0); \ - } -#define FTABLE64(A, V) {mmx87_regs_t v = {.d = V}; Table64(dyn, v.q, 2); EMIT(0);} + } while(0) +#define FTABLE64(A, V) do {mmx87_regs_t v = {.d = V}; Table64(dyn, v.q, 2); EMIT(0);} while(0) #define CALLRET_RET() do {dyn->callrets[dyn->callret_size].type = 0; dyn->callrets[dyn->callret_size++].offs = dyn->native_size; EMIT(ARCH_NOP); } while(0) #define CALLRET_LOOP() do {dyn->callrets[dyn->callret_size].type = 1; dyn->callrets[dyn->callret_size++].offs = dyn->native_size; EMIT(ARCH_NOP); } while(0) \ No newline at end of file diff --git a/src/dynarec/arm64/dynarec_arm64_pass3.h b/src/dynarec/arm64/dynarec_arm64_pass3.h index 5930c410..c59d2aee 100644 --- a/src/dynarec/arm64/dynarec_arm64_pass3.h +++ b/src/dynarec/arm64/dynarec_arm64_pass3.h @@ -24,22 +24,22 @@ } #define INST_EPILOG #define INST_NAME(name) inst_name_pass3(dyn, ninst, name, rex) -#define TABLE64(A, V) { \ - if(dyn->need_reloc && !isTable64(dyn, (V))) \ +#define TABLE64(A, V) do { \ + if(dyn->need_reloc) \ AddRelocTable64Addr(dyn, ninst, (V), 3); \ int val64offset = Table64(dyn, (V), 3); \ MESSAGE(LOG_DUMP, " Table64: 0x%lx\n", (V)); LDRx_literal(A, val64offset); \ - } + } while(0) #define TABLE64_(A, V) { \ int val64offset = Table64(dyn, (V), 3); \ MESSAGE(LOG_DUMP, " Table64: 0x%lx\n", (V)); LDRx_literal(A, val64offset); \ } -#define TABLE64C(A, V) { \ - if(dyn->need_reloc && !isTable64(dyn, getConst(V))) \ +#define TABLE64C(A, V) do { \ + if(dyn->need_reloc) \ AddRelocTable64Const(dyn, ninst, (V), 3); \ int val64offset = Table64(dyn, getConst(V), 3); \ - MESSAGE(LOG_DUMP, " Table64: 0x%lx\n", (V)); LDRx_literal(A, val64offset); \ - } -#define FTABLE64(A, V) {mmx87_regs_t v = {.d = V}; int val64offset = Table64(dyn, v.q, 3); MESSAGE(LOG_DUMP, " FTable64: %g\n", v.d); VLDR64_literal(A, val64offset);} + MESSAGE(LOG_DUMP, " Table64C: 0x%lx\n", (V)); LDRx_literal(A, val64offset);\ + } while(0) +#define FTABLE64(A, V) do {mmx87_regs_t v = {.d = V}; int val64offset = Table64(dyn, v.q, 3); MESSAGE(LOG_DUMP, " FTable64: %g\n", v.d); VLDR64_literal(A, val64offset);} while(0) #define CALLRET_RET() do {dyn->callrets[dyn->callret_size].type = 0; dyn->callrets[dyn->callret_size++].offs = dyn->native_size; EMIT(ARCH_NOP); } while(0) #define CALLRET_LOOP() do {dyn->callrets[dyn->callret_size].type = 1; dyn->callrets[dyn->callret_size++].offs = dyn->native_size; EMIT(ARCH_NOP); } while(0) diff --git a/src/dynarec/dynablock.c b/src/dynarec/dynablock.c index b5a81020..b804eff2 100644 --- a/src/dynarec/dynablock.c +++ b/src/dynarec/dynablock.c @@ -85,14 +85,15 @@ void FreeInvalidDynablock(dynablock_t* db, int need_lock) } } -void FreeDynablock(dynablock_t* db, int need_lock) +void FreeDynablock(dynablock_t* db, int need_lock, int need_remove) { if(db) { if(db->gone) return; // already in the process of deletion! dynarec_log(LOG_DEBUG, "FreeDynablock(%p), db->block=%p x64=%p:%p already gone=%d\n", db, db->block, db->x64_addr, db->x64_addr+db->x64_size-1, db->gone); // remove jumptable without waiting - setJumpTableDefault64(db->x64_addr); + if(need_remove) + setJumpTableDefault64(db->x64_addr); if(need_lock) mutex_lock(&my_context->mutex_dyndump); dynarec_log(LOG_DEBUG, " -- FreeDyrecMap(%p, %d)\n", db->actual_block, db->size); @@ -168,7 +169,7 @@ int FreeRangeDynablock(dynablock_t* db, uintptr_t addr, uintptr_t size) int need_lock = my_context?1:0; if(IntervalIntersects((uintptr_t)db->x64_addr, (uintptr_t)db->x64_addr+db->x64_size-1, addr, addr+size+1)) { - FreeDynablock(db, need_lock); + FreeDynablock(db, need_lock, 1); return 0; } return 1; @@ -233,7 +234,7 @@ static dynablock_t* internalDBGetBlock(x64emu_t* emu, uintptr_t addr, uintptr_t if(block) { // fill-in jumptable if(!addJumpTableIfDefault64(block->x64_addr, block->dirty?block->jmpnext:block->block)) { - FreeDynablock(block, 0); + FreeDynablock(block, 0, 0); block = getDB(addr); MarkDynablock(block); // just in case... } else { @@ -261,9 +262,9 @@ dynablock_t* DBGetBlock(x64emu_t* emu, uintptr_t addr, int create, int is32bits) if(is_inhotpage && !BOX64ENV(dynarec_dirty)) return NULL; dynablock_t *db = internalDBGetBlock(emu, addr, addr, create, 1, is32bits, 1); - if(db && db->done && db->block && getNeedTest(addr)) { + if(db && db->done && db->block && (db->dirty || getNeedTest(addr))) { if (db->always_test) SchedYield(); // just calm down... - uint32_t hash = X31_hash_code(db->x64_addr, db->x64_size); + uint32_t hash = db->dirty?(~db->hash):X31_hash_code(db->x64_addr, db->x64_size); if(is_inhotpage && hash!=db->hash) return NULL; // will be handle when hotpage is over int need_lock = mutex_trylock(&my_context->mutex_dyndump); @@ -313,10 +314,10 @@ dynablock_t* DBAlternateBlock(x64emu_t* emu, uintptr_t addr, uintptr_t filladdr, dynarec_log(LOG_DEBUG, "Creating AlternateBlock at %p for %p%s\n", (void*)addr, (void*)filladdr, is32bits?" 32bits":""); int create = 1; dynablock_t *db = internalDBGetBlock(emu, addr, filladdr, create, 1, is32bits, 1); - if(db && db->done && db->block && getNeedTest(filladdr)) { + if(db && db->done && db->block && (db->dirty || getNeedTest(filladdr))) { if (db->always_test) SchedYield(); // just calm down... int need_lock = mutex_trylock(&my_context->mutex_dyndump); - uint32_t hash = X31_hash_code(db->x64_addr, db->x64_size); + uint32_t hash = db->dirty?(~db->hash):X31_hash_code(db->x64_addr, db->x64_size); if(hash!=db->hash) { db->done = 0; // invalidating the block dynarec_log(LOG_DEBUG, "Invalidating alt block %p from %p:%p (hash:%X/%X) for %p\n", db, db->x64_addr, db->x64_addr+db->x64_size, hash, db->hash, (void*)addr); diff --git a/src/dynarec/dynablock_private.h b/src/dynarec/dynablock_private.h index f78d457c..db142c25 100644 --- a/src/dynarec/dynablock_private.h +++ b/src/dynarec/dynablock_private.h @@ -17,6 +17,7 @@ typedef struct dynablock_s { struct dynablock_s* previous; // a previous block that might need to be freed void* x64_addr; uintptr_t x64_size; + size_t native_size; int size; uint32_t hash; uint8_t done; @@ -31,6 +32,9 @@ typedef struct dynablock_s { void* arch; // arch dependant per inst info (can be NULL) callret_t* callrets; // array of callret return, with NOP / UDF depending if the block is clean or dirty void* jmpnext; // a branch jmpnext code when block is marked + size_t table64size;// to check table64 + void* table64; // to relocate the table64 + size_t relocsize; // number of relocations (should be an int only) void* relocs; // relocations, when block is loaded #ifdef GDBJIT void* gdbjit_block; diff --git a/src/dynarec/dynacache_reloc.c b/src/dynarec/dynacache_reloc.c index 7692e007..b145629e 100644 --- a/src/dynarec/dynacache_reloc.c +++ b/src/dynarec/dynacache_reloc.c @@ -4,6 +4,7 @@ #include "os.h" #include "dynarec_private.h" #include "emu/x64run_private.h" +#include "dynablock_private.h" #include "dynarec_arch.h" #include "custommem.h" #include "debug.h" @@ -13,7 +14,7 @@ #define RELOC_TBL64RETENDBL 3 #define RELOC_CANCELBLOCK 4 #define RELOC_TBL64TBLJMPH 5 -#define RELOC_TBL64TBLJMPL 5 +#define RELOC_TBL64TBLJMPL 6 typedef union reloc_s { uint8_t type; @@ -48,6 +49,8 @@ void AddRelocTable64Const(dynarec_native_t* dyn, int ninst, native_consts_t C, i { if(!dyn->need_reloc) return; + if(isTable64(dyn, getConst(C))) + return; if(pass<3) { dyn->reloc_size++; return; @@ -117,12 +120,13 @@ void AddRelocTable64Addr(dynarec_native_t* dyn, int ninst, uintptr_t addr, int p } if(!ok) return AddRelocCancelBlock(dyn, ninst, pass); if(pass<3) { - dyn->reloc_size+=2; + dyn->reloc_size++; return; } reloc_t reloc = {0}; reloc.type = RELOC_TBL64ADDR; reloc.table64addr.idx = dyn->table64size; + dyn->relocs[dyn->reloc_size++] = reloc.x; } @@ -159,4 +163,80 @@ void AddRelocTable64JmpTbl(dynarec_native_t* dyn, int ninst, uintptr_t addr, int reloc.type = RELOC_TBL64TBLJMPL; reloc.table64jmptbll.deltal = delta&0xffffff; dyn->relocs[dyn->reloc_size++] = reloc.x; +} + +int ApplyRelocs(dynablock_t* block, intptr_t delta_block, intptr_t delta_map, uintptr_t mapping_start) +{ + if(!block || !block->relocs || !block->relocsize) + return 0; + size_t reloc_size = block->relocsize / sizeof(uint32_t); + reloc_t *relocs = block->relocs; + uint64_t *table64 = block->table64; + int idx; + + int i = 0; + uintptr_t addr; + dynarec_log(LOG_DEBUG, "Will apply %zd reloc to dynablock starting at %p - %p\n", reloc_size, block->x64_addr, block->x64_addr + block->x64_size); + while(i<reloc_size) { + idx = -1; + switch(relocs[i].type) { + case RELOC_TBL64C: + idx = relocs[i].table64c.idx; + table64[idx] = getConst(relocs[i].table64c.C); + dynarec_log(LOG_DEBUG, "\tApply Relocs[%d]: TABLE64[%d]=Const:%d\n", i, idx, relocs[i].table64c.C); + break; + case RELOC_TBL64ADDR: + idx = relocs[i].table64addr.idx; + table64[idx] += delta_map; + dynarec_log(LOG_DEBUG, "\tApply Relocs[%d]: TABLE64[%d]=Addr in Map, delta=%zd\n", i, idx, delta_map); + break; + case RELOC_TBL64RETENDBL: + idx = relocs[i].table64retendbl.idx; + addr = (uintptr_t)block->x64_addr + block->x64_size + relocs[i].table64retendbl.delta; + table64[idx] = getJumpTableAddress64(addr); + dynarec_log(LOG_DEBUG, "\tApply Relocs[%d]: TABLE64[%d]=JmpTable64(%p)\n", i, idx, (void*)addr); + break; + case RELOC_CANCELBLOCK: + dynarec_log(LOG_DEBUG, "\tApply Relocs[%d]: Cancel Block\n", i); + block->dirty = 1; + block->hash = 0; + return 0; + case RELOC_TBL64TBLJMPH: + if(relocs[i+1].type!=RELOC_TBL64TBLJMPL) + return -2; // bad sequence + idx = relocs[i].table64jmptblh.idx; + addr = relocs[i].table64jmptblh.deltah; + addr = mapping_start + relocs[i+1].table64jmptbll.deltal + (addr<<24); + table64[idx] = getJumpTableAddress64(addr); + dynarec_log(LOG_DEBUG, "\tApply Relocs[%d,%d]: TABLE64[%d]=JmpTable64(%p)=%p\n", i, i+1, idx, (void*)addr, getJumpTableAddress64(addr)); + break; + case RELOC_TBL64TBLJMPL: + break; + default: + dynarec_log(LOG_DEBUG, "\tUnknown Relocs[%d]: %d\n", i, relocs[i].type); + return -1; + } + if(idx!=-1) { + if(idx>=block->table64size) { + dynarec_log(LOG_NONE, "Warning: Reloc Table64 idx out of range (%d vs %d)\n", idx, block->table64size); + } + } + ++i; + } + return 0; +} + +int RelocsHaveCancel(dynablock_t* block) +{ + if(!block->relocs || !block->relocsize) + return 0; + size_t reloc_size = block->relocsize/sizeof(uint32_t); + for(size_t i=0; i<reloc_size; ++i) + if(((reloc_t*)block->relocs)[i].type == RELOC_CANCELBLOCK) + return 1; + return 0; +} + +uintptr_t RelocGetNext() { + return getConst(const_native_next); } \ No newline at end of file diff --git a/src/dynarec/dynacache_reloc.h b/src/dynarec/dynacache_reloc.h index fed00562..dc0f63a4 100644 --- a/src/dynarec/dynacache_reloc.h +++ b/src/dynarec/dynacache_reloc.h @@ -17,4 +17,8 @@ void AddRelocTable64RetEndBlock(dynarec_native_t* dyn, int ninst, uintptr_t addr void AddRelocTable64JmpTbl(dynarec_native_t* dyn, int ninst, uintptr_t addr, int pass); void AddRelocCancelBlock(dynarec_native_t* dyn, int ninst, int pass); +int ApplyRelocs(dynablock_t* block, intptr_t delta_block, intptr_t delta_map, uintptr_t mapping_start); +int RelocsHaveCancel(dynablock_t* block); +uintptr_t RelocGetNext(); + #endif \ No newline at end of file diff --git a/src/dynarec/dynarec_native.c b/src/dynarec/dynarec_native.c index bba18978..8e142b57 100644 --- a/src/dynarec/dynarec_native.c +++ b/src/dynarec/dynarec_native.c @@ -23,6 +23,9 @@ #include "dynarec_arch.h" #include "dynarec_next.h" #include "gdbjit.h" +#include "khash.h" + +KHASH_MAP_INIT_INT64(table64, uint32_t) void printf_x64_instruction(dynarec_native_t* dyn, zydis_dec_t* dec, instruction_x64_t* inst, const char* name) { uint8_t *ip = (uint8_t*)inst->addr; @@ -293,36 +296,51 @@ void addInst(instsize_t* insts, size_t* size, int x64_size, int native_size) } } +static kh_table64_t* khtable64 = NULL; + int isTable64(dynarec_native_t *dyn, uint64_t val) { - // find the value if already present - int idx = -1; - for(int i=0; i<dyn->table64size && (idx==-1); ++i) - if(dyn->table64[i] == val) - idx = i; - return (idx!=-1); + if(!khtable64) + return 0; + if(kh_get(table64, khtable64, val)==kh_end(khtable64)) + return 0; + return 1; } // add a value to table64 (if needed) and gives back the imm19 to use in LDR_literal int Table64(dynarec_native_t *dyn, uint64_t val, int pass) { + if(!khtable64) + khtable64 = kh_init(table64); // find the value if already present - int idx = -1; - for(int i=0; i<dyn->table64size && (idx==-1); ++i) - if(dyn->table64[i] == val) - idx = i; - // not found, add it - if(idx==-1) { + khint_t k = kh_get(table64, khtable64, val); + uint32_t idx = 0; + if(k!=kh_end(khtable64)) { + idx = kh_value(khtable64, k); + } else { idx = dyn->table64size++; - if(idx < dyn->table64cap) - dyn->table64[idx] = val; - else if(pass==3) - printf_log(LOG_NONE, "Warning, table64 bigger than expected %d vs %d\n", idx, dyn->table64cap); + if(pass==3) { + if(idx < dyn->table64cap) + dyn->table64[idx] = val; + else + printf_log(LOG_NONE, "Warning, table64 bigger than expected %d vs %d\n", idx, dyn->table64cap); + } + int ret; + k = kh_put(table64, khtable64, val, &ret); + kh_value(khtable64, k) = idx; } // calculate offset int delta = dyn->tablestart + idx*sizeof(uint64_t) - (uintptr_t)dyn->block; return delta; } +void ResetTable64(dynarec_native_t* dyn) +{ + dyn->table64size = 0; + if(khtable64) { + kh_clear(table64, khtable64); + } +} + static void recurse_mark_alive(dynarec_native_t* dyn, int i) { if(dyn->insts[i].x64.alive) @@ -510,7 +528,6 @@ static void updateYmm0s(dynarec_native_t* dyn, int ninst, int max_ninst_reached) void* current_helper = NULL; static int static_jmps[MAX_INSTS+2]; static uintptr_t static_next[MAX_INSTS+2]; -static uint64_t static_table64[(MAX_INSTS+3)/4]; static instruction_native_t static_insts[MAX_INSTS+2] = {0}; static callret_t static_callrets[MAX_INSTS+2] = {0}; // TODO: ninst could be a uint16_t instead of an int, that could same some temp. memory @@ -640,8 +657,9 @@ dynablock_t* FillBlock64(uintptr_t addr, int alternate, int is32bits, int inst_m helper.jmp_cap = MAX_INSTS; helper.next = static_next; helper.next_cap = MAX_INSTS; - helper.table64 = static_table64; - helper.table64cap = sizeof(static_table64)/sizeof(uint64_t); + helper.table64 = NULL; + ResetTable64(&helper); + helper.table64cap = 0; helper.end = addr + SizeFileMapped(addr); if(helper.end == helper.start) // that means there is no mmap with a file associated to the memory helper.end = (uintptr_t)~0LL; @@ -780,7 +798,7 @@ dynablock_t* FillBlock64(uintptr_t addr, int alternate, int is32bits, int inst_m // no need for next anymore helper.next_sz = helper.next_cap = 0; helper.next = NULL; - helper.table64size = 0; + ResetTable64(&helper); helper.reloc_size = 0; // pass 1, float optimizations, first pass for flags native_pass1(&helper, addr, alternate, is32bits, inst_max); @@ -794,7 +812,7 @@ dynablock_t* FillBlock64(uintptr_t addr, int alternate, int is32bits, int inst_m helper.need_x87check = 0; } POSTUPDATE_SPECIFICS(&helper); - helper.table64size = 0; + ResetTable64(&helper); helper.reloc_size = 0; // pass 2, instruction size helper.callrets = static_callrets; @@ -850,6 +868,7 @@ dynablock_t* FillBlock64(uintptr_t addr, int alternate, int is32bits, int inst_m block->actual_block = actual_p; helper.relocs = relocs; block->relocs = relocs; + block->table64size = helper.table64size; helper.native_start = (uintptr_t)p; helper.tablestart = (uintptr_t)tablestart; helper.jmp_next = (uintptr_t)next+sizeof(void*); @@ -858,6 +877,7 @@ dynablock_t* FillBlock64(uintptr_t addr, int alternate, int is32bits, int inst_m helper.table64cap = helper.table64size; helper.table64 = (uint64_t*)helper.tablestart; helper.callrets = (callret_t*)callrets; + block->table64 = helper.table64; if(callret_size) memcpy(helper.callrets, static_callrets, helper.callret_size*sizeof(callret_t)); helper.callret_size = 0; @@ -875,7 +895,7 @@ dynablock_t* FillBlock64(uintptr_t addr, int alternate, int is32bits, int inst_m size_t oldinstsize = helper.insts_size; int oldsize= helper.size; helper.native_size = 0; - helper.table64size = 0; // reset table64 (but not the cap) + ResetTable64(&helper); // reset table64 (but not the cap) helper.insts_size = 0; // reset helper.reloc_size = 0; native_pass3(&helper, addr, alternate, is32bits, inst_max); @@ -899,6 +919,7 @@ dynablock_t* FillBlock64(uintptr_t addr, int alternate, int is32bits, int inst_m block->always_test = helper.always_test; block->dirty = block->always_test; block->is32bits = is32bits; + block->relocsize = helper.reloc_size*sizeof(uint32_t); if(arch_size) { block->arch_size = arch_size; block->arch = ARCH_FILL(&helper, arch, arch_size); @@ -909,6 +930,7 @@ dynablock_t* FillBlock64(uintptr_t addr, int alternate, int is32bits, int inst_m } block->callret_size = helper.callret_size; block->callrets = helper.callrets; + block->native_size = native_size; *(dynablock_t**)next = block; *(void**)(next+3*sizeof(void*)) = native_next; CreateJmpNext(block->jmpnext, next+3*sizeof(void*)); @@ -950,6 +972,7 @@ dynablock_t* FillBlock64(uintptr_t addr, int alternate, int is32bits, int inst_m return NULL; } // ok, free the helper now + ResetTable64(&helper); //dynaFree(helper.insts); helper.insts = NULL; if(insts_rsize/sizeof(instsize_t)<helper.insts_size) { diff --git a/src/dynarec/la64/dynarec_la64_00.c b/src/dynarec/la64/dynarec_la64_00.c index 20b7a597..43c4f1f5 100644 --- a/src/dynarec/la64/dynarec_la64_00.c +++ b/src/dynarec/la64/dynarec_la64_00.c @@ -2446,7 +2446,9 @@ uintptr_t dynarec64_00(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni // jumps out of current dynablock... MARK; j64 = getJumpTableAddress64(addr); - TABLE64(x4, j64); + if(dyn->need_reloc) + AddRelocTable64JmpTbl(dyn, ninst, addr, STEP); + TABLE64_(x4, j64); LD_D(x4, x4, 0); BR(x4); } @@ -2842,7 +2844,9 @@ uintptr_t dynarec64_00(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni // jumps out of current dynablock... MARK; j64 = getJumpTableAddress64(addr); - TABLE64(x4, j64); + if(dyn->need_reloc) + AddRelocTable64JmpTbl(dyn, ninst, addr, STEP); + TABLE64_(x4, j64); LD_D(x4, x4, 0); BR(x4); } |