diff options
Diffstat (limited to 'src/dynarec/dynarec_native.c')
| -rw-r--r-- | src/dynarec/dynarec_native.c | 41 |
1 files changed, 35 insertions, 6 deletions
diff --git a/src/dynarec/dynarec_native.c b/src/dynarec/dynarec_native.c index 58aa4493..df6ab348 100644 --- a/src/dynarec/dynarec_native.c +++ b/src/dynarec/dynarec_native.c @@ -504,6 +504,7 @@ 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 void ClearCache(void* start, size_t len) @@ -653,7 +654,12 @@ void* FillBlock64(dynablock_t* block, uintptr_t addr, int alternate, int is32bit int i = helper.jmps[ii]; uintptr_t j = helper.insts[i].x64.jmp; helper.insts[i].x64.jmp_insts = -1; - if(j<start || j>=end || j==helper.insts[i].x64.addr) { + #ifndef ARCH_NOP + if(j<start || j>=end || j==helper.insts[i].x64.addr) + #else + if(j<start || j>=end) + #endif + { helper.insts[i].x64.need_after |= X_PEND; } else { // find jump address instruction @@ -691,8 +697,12 @@ void* FillBlock64(dynablock_t* block, uintptr_t addr, int alternate, int is32bit helper.insts[k].x64.barrier |= BARRIER_FULL; // special case, loop on itself with some nop in between if(k<i && !helper.insts[i].x64.has_next && is_nops(&helper, helper.insts[k].x64.addr, helper.insts[i].x64.addr-helper.insts[k].x64.addr)) { + #ifndef ARCH_NOP helper.always_test = 1; k = -1; + #else + helper.insts[k].x64.self_loop = 1; + #endif } helper.insts[i].x64.jmp_insts = k; } @@ -737,7 +747,11 @@ void* FillBlock64(dynablock_t* block, uintptr_t addr, int alternate, int is32bit for(int ii=0; ii<helper.jmp_sz && !helper.always_test; ++ii) { int i = helper.jmps[ii]; if(helper.insts[i].x64.alive && (helper.insts[i].x64.jmp==helper.insts[i].x64.addr)) { + #ifndef ARCH_NOP helper.always_test = 1; + #else + helper.insts[i].x64.self_loop = 1; + #endif } } // no need for next anymore @@ -753,6 +767,7 @@ void* FillBlock64(dynablock_t* block, uintptr_t addr, int alternate, int is32bit } // pass 2, instruction size + helper.callrets = static_callrets; native_pass2(&helper, addr, alternate, is32bits, inst_max); if(helper.abort) { if(BOX64DRENV(dynarec_dump) || BOX64ENV(dynarec_log))dynarec_log(LOG_NONE, "Abort dynablock on pass2\n"); @@ -778,15 +793,17 @@ void* FillBlock64(dynablock_t* block, uintptr_t addr, int alternate, int is32bit size_t insts_rsize = (helper.insts_size+2)*sizeof(instsize_t); insts_rsize = (insts_rsize+7)&~7; // round the size... size_t arch_size = ARCH_SIZE(&helper); + size_t callret_size = helper.callret_size*4; // ok, now allocate mapped memory, with executable flag on - size_t sz = sizeof(void*) + native_size + helper.table64size*sizeof(uint64_t) + 4*sizeof(void*) + insts_rsize + arch_size; - // dynablock_t* block (arm insts) table64 jmpnext code instsize arch + size_t sz = sizeof(void*) + native_size + helper.table64size*sizeof(uint64_t) + 4*sizeof(void*) + insts_rsize + arch_size + callret_size; + // dynablock_t* block (arm insts) table64 jmpnext code instsize arch callrets void* actual_p = (void*)AllocDynarecMap(sz); void* p = (void*)(((uintptr_t)actual_p) + sizeof(void*)); void* tablestart = p + native_size; void* next = tablestart + helper.table64size*sizeof(uint64_t); void* instsize = next + 4*sizeof(void*); void* arch = instsize + insts_rsize; + void* callrets = arch + arch_size; if(actual_p==NULL) { dynarec_log(LOG_INFO, "AllocDynarecMap(%p, %zu) failed, canceling block\n", block, sz); CancelBlock64(0); @@ -801,9 +818,13 @@ void* FillBlock64(dynablock_t* block, uintptr_t addr, int alternate, int is32bit *(dynablock_t**)actual_p = block; helper.table64cap = helper.table64size; helper.table64 = (uint64_t*)helper.tablestart; + helper.callrets = (callret_t*)callrets; + if(callret_size) + memcpy(helper.callrets, static_callrets, helper.callret_size*sizeof(callret_t)); + helper.callret_size = 0; // pass 3, emit (log emit native opcode) if(BOX64DRENV(dynarec_dump)) { - dynarec_log(LOG_NONE, "%s%04d|Emitting %zu bytes for %u %s bytes (native=%zu, table64=%zu, instsize=%zu, arch=%zu)", (BOX64DRENV(dynarec_dump)>1)?"\e[01;36m":"", GetTID(), helper.native_size, helper.isize, is32bits?"x86":"x64", native_size, helper.table64size*sizeof(uint64_t), insts_rsize, arch_size); + dynarec_log(LOG_NONE, "%s%04d|Emitting %zu bytes for %u %s bytes (native=%zu, table64=%zu, instsize=%zu, arch=%zu, callrets=%zu)", (BOX64DRENV(dynarec_dump)>1)?"\e[01;36m":"", GetTID(), helper.native_size, helper.isize, is32bits?"x86":"x64", native_size, helper.table64size*sizeof(uint64_t), insts_rsize, arch_size, callret_size); printFunctionAddr(helper.start, " => "); dynarec_log(LOG_NONE, "%s\n", (BOX64DRENV(dynarec_dump)>1)?"\e[m":""); } @@ -846,6 +867,8 @@ void* FillBlock64(dynablock_t* block, uintptr_t addr, int alternate, int is32bit block->arch = NULL; block->arch_size = arch_size; } + block->callret_size = helper.callret_size; + block->callrets = helper.callrets; *(dynablock_t**)next = block; *(void**)(next+3*sizeof(void*)) = native_next; CreateJmpNext(block->jmpnext, next+3*sizeof(void*)); @@ -889,7 +912,7 @@ void* FillBlock64(dynablock_t* block, uintptr_t addr, int alternate, int is32bit printf_log(LOG_NONE, "Warning, insts_size difference in block between pass2 (%zu) and pass3 (%zu), allocated: %zu\n", oldinstsize, helper.insts_size, insts_rsize/sizeof(instsize_t)); } if(!isprotectedDB(addr, end-addr)) { - dynarec_log(LOG_DEBUG, "Warning, block unprotected while being processed %p:%ld, marking as need_test\n", block->x64_addr, block->x64_size); + dynarec_log(LOG_INFO, "Warning, block unprotected while being processed %p:%ld, marking as need_test\n", block->x64_addr, block->x64_size); block->dirty = 1; //protectDB(addr, end-addr); } @@ -898,7 +921,13 @@ void* FillBlock64(dynablock_t* block, uintptr_t addr, int alternate, int is32bit block->always_test = 1; } if(block->always_test) { - dynarec_log(LOG_DEBUG, "Note: block marked as always dirty %p:%ld\n", block->x64_addr, block->x64_size); + dynarec_log(LOG_INFO, "Note: block marked as always dirty %p:%ld\n", block->x64_addr, block->x64_size); + #ifdef ARCH_NOP + // mark callrets to trigger SIGILL to check clean state + if(block->callret_size) + for(int i=0; i<block->callret_size; ++i) + *(uint32_t*)(block->block+block->callrets[i].offs) = ARCH_UDF; + #endif } current_helper = NULL; //block->done = 1; |