diff options
| author | ptitSeb <sebastien.chev@gmail.com> | 2022-10-31 12:05:04 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2022-10-31 12:05:04 +0100 |
| commit | 8459ea0d31a851e847318273233c9a8b2b079eae (patch) | |
| tree | 2ab39af3c19d9720d906cd060211107c5dc549a2 /src/dynarec | |
| parent | 494c245b591cef1a34cc4d4dc52163861d4e54af (diff) | |
| download | box64-8459ea0d31a851e847318273233c9a8b2b079eae.tar.gz box64-8459ea0d31a851e847318273233c9a8b2b079eae.zip | |
Remove dynablocklist (#438)
* [DYNAREC] Removed dynablock sons handling * [DYNAREC] Removed dynablocklist, and attached dynablocks to the jumptable * [DYNAREC] Changed handling of HotPage (part of Protection now) * [DYNAREC] Fixed some performance issues (especially with heavily threaded programs)
Diffstat (limited to 'src/dynarec')
| -rwxr-xr-x | src/dynarec/arm64/dynarec_arm64_helper.c | 26 | ||||
| -rw-r--r-- | src/dynarec/arm64/dynarec_arm64_jmpnext.c | 11 | ||||
| -rwxr-xr-x | src/dynarec/arm64/dynarec_arm64_pass2.h | 1 | ||||
| -rwxr-xr-x | src/dynarec/arm64/dynarec_arm64_pass3.h | 4 | ||||
| -rwxr-xr-x | src/dynarec/arm64/dynarec_arm64_private.h | 7 | ||||
| -rwxr-xr-x | src/dynarec/dynablock.c | 499 | ||||
| -rwxr-xr-x | src/dynarec/dynablock_private.h | 22 | ||||
| -rwxr-xr-x | src/dynarec/dynarec.c | 40 | ||||
| -rwxr-xr-x | src/dynarec/dynarec_native.c | 163 | ||||
| -rwxr-xr-x | src/dynarec/dynarec_native_pass.c | 3 | ||||
| -rw-r--r-- | src/dynarec/dynarec_next.h | 22 |
11 files changed, 217 insertions, 581 deletions
diff --git a/src/dynarec/arm64/dynarec_arm64_helper.c b/src/dynarec/arm64/dynarec_arm64_helper.c index 521b0604..d38c8078 100755 --- a/src/dynarec/arm64/dynarec_arm64_helper.c +++ b/src/dynarec/arm64/dynarec_arm64_helper.c @@ -403,30 +403,30 @@ void jump_to_next(dynarec_arm_t* dyn, uintptr_t ip, int reg, int ninst) } uintptr_t tbl = getJumpTable64(); MAYUSE(tbl); - TABLE64(x2, tbl); - UBFXx(x3, xRIP, 48, JMPTABL_SHIFT); - LDRx_REG_LSL3(x2, x2, x3); - UBFXx(x3, xRIP, 32, JMPTABL_SHIFT); - LDRx_REG_LSL3(x2, x2, x3); - UBFXx(x3, xRIP, 16, JMPTABL_SHIFT); - LDRx_REG_LSL3(x2, x2, x3); - UBFXx(x3, xRIP, 0, JMPTABL_SHIFT); - LDRx_REG_LSL3(x3, x2, x3); + TABLE64(x3, tbl); + UBFXx(x2, xRIP, 48, JMPTABL_SHIFT); + LDRx_REG_LSL3(x3, x3, x2); + UBFXx(x2, xRIP, 32, JMPTABL_SHIFT); + LDRx_REG_LSL3(x3, x3, x2); + UBFXx(x2, xRIP, 16, JMPTABL_SHIFT); + LDRx_REG_LSL3(x3, x3, x2); + UBFXx(x2, xRIP, 0, JMPTABL_SHIFT); + LDRx_REG_LSL3(x2, x3, x2); } else { uintptr_t p = getJumpTableAddress64(ip); MAYUSE(p); - TABLE64(x2, p); + TABLE64(x3, p); GETIP_(ip); - LDRx_U12(x3, x2, 0); + LDRx_U12(x2, x3, 0); } if(reg!=x1) { MOVx_REG(x1, xRIP); } CLEARIP(); #ifdef HAVE_TRACE - //MOVx(x2, 15); no access to PC reg + //MOVx(x3, 15); no access to PC reg #endif - BLR(x3); // save LR... + BLR(x2); // save LR... } void ret_to_epilog(dynarec_arm_t* dyn, int ninst) diff --git a/src/dynarec/arm64/dynarec_arm64_jmpnext.c b/src/dynarec/arm64/dynarec_arm64_jmpnext.c new file mode 100644 index 00000000..c40dfb1e --- /dev/null +++ b/src/dynarec/arm64/dynarec_arm64_jmpnext.c @@ -0,0 +1,11 @@ +#include <stdint.h> + +#include "arm64_emitter.h" + +#define EMIT(A) *block = (A); ++block +void CreateJmpNext(void* addr, void* next) +{ + uint32_t* block = (uint32_t*)addr; + LDRx_literal(x2, (intptr_t)next - (intptr_t)addr); + BR(x2); +} \ No newline at end of file diff --git a/src/dynarec/arm64/dynarec_arm64_pass2.h b/src/dynarec/arm64/dynarec_arm64_pass2.h index 4a5122c2..29d5f01a 100755 --- a/src/dynarec/arm64/dynarec_arm64_pass2.h +++ b/src/dynarec/arm64/dynarec_arm64_pass2.h @@ -8,7 +8,6 @@ dyn->insts[ninst].address = (dyn->insts[ninst-1].address+dyn->insts[ninst-1].size); \ if(ninst && isInstClean(dyn, ninst)) { \ if(dyn->last_ip!=ip) dyn->last_ip = 0; \ - ++dyn->sons_size; \ } \ } #define INST_EPILOG dyn->insts[ninst].epilog = dyn->native_size; diff --git a/src/dynarec/arm64/dynarec_arm64_pass3.h b/src/dynarec/arm64/dynarec_arm64_pass3.h index d1d8fbba..2a003711 100755 --- a/src/dynarec/arm64/dynarec_arm64_pass3.h +++ b/src/dynarec/arm64/dynarec_arm64_pass3.h @@ -10,10 +10,6 @@ #define NEW_INST \ if(ninst && isInstClean(dyn, ninst)) { \ if(dyn->last_ip!=ip) dyn->last_ip = 0; \ - dyn->sons_x64[dyn->sons_size] = (uintptr_t)ip; \ - dyn->sons_native[dyn->sons_size] = dyn->block; \ - MESSAGE(LOG_DUMP, "----> potential Son here %p/%p\n", (void*)ip, dyn->block); \ - ++dyn->sons_size; \ } #define INST_EPILOG #define INST_NAME(name) \ diff --git a/src/dynarec/arm64/dynarec_arm64_private.h b/src/dynarec/arm64/dynarec_arm64_private.h index 23fe4af5..1cac7d3e 100755 --- a/src/dynarec/arm64/dynarec_arm64_private.h +++ b/src/dynarec/arm64/dynarec_arm64_private.h @@ -5,6 +5,7 @@ typedef struct x64emu_s x64emu_t; typedef struct dynablock_s dynablock_t; +typedef struct instsize_s instsize_t; #define BARRIER_MAYBE 8 @@ -99,11 +100,9 @@ typedef struct dynarec_arm_s { uintptr_t* next; // variable array of "next" jump address int next_sz; int next_cap; - uintptr_t* sons_x64; // the x64 address of potential dynablock sons - void** sons_native; // the arm address of potential dynablock sons - int sons_size; // number of potential dynablock sons int* predecessor;// single array of all predecessor dynablock_t* dynablock; + instsize_t* instsize; } dynarec_arm_t; void add_next(dynarec_arm_t *dyn, uintptr_t addr); @@ -113,6 +112,8 @@ int is_instructions(dynarec_arm_t *dyn, uintptr_t addr, int n); int Table64(dynarec_arm_t *dyn, uint64_t val); // add a value to etable64 (if needed) and gives back the imm19 to use in LDR_literal +void CreateJmpNext(void* addr, void* next); + #define GO_TRACE() \ GETIP_(ip); \ MOVx_REG(x1, xRIP); \ diff --git a/src/dynarec/dynablock.c b/src/dynarec/dynablock.c index 43222a2e..b795c3c1 100755 --- a/src/dynarec/dynablock.c +++ b/src/dynarec/dynablock.c @@ -3,6 +3,7 @@ #include <pthread.h> #include <errno.h> #include <setjmp.h> +#include <sys/mman.h> #include "debug.h" #include "box64context.h" @@ -37,111 +38,37 @@ uint32_t X31_hash_code(void* addr, int len) return (uint32_t)h; } -dynablocklist_t* NewDynablockList(uintptr_t text, int textsz, int direct) -{ - if(!textsz) { - printf_log(LOG_NONE, "Error, creating a NULL sized Dynablock\n"); - return NULL; - } - dynablocklist_t* ret = (dynablocklist_t*)customCalloc(1, sizeof(dynablocklist_t)); - ret->text = text; - ret->textsz = textsz; - ret->minstart = text; - ret->maxend = text+textsz-1; - if(direct && textsz) { - ret->direct = (dynablock_t**)customCalloc(textsz, sizeof(dynablock_t*)); - if(!ret->direct) {printf_log(LOG_NONE, "Warning, fail to create direct block for dynablock @%p\n", (void*)text);} - } - dynarec_log(LOG_DEBUG, "New Dynablocklist %p, from %p->%p\n", ret, (void*)text, (void*)(text+textsz)); - return ret; -} - void FreeDynablock(dynablock_t* db, int need_lock) { if(db) { if(db->gone) return; // already in the process of deletion! - dynarec_log(LOG_DEBUG, "FreeDynablock(%p), db->block=%p x64=%p:%p parent=%p, father=%p, with %d son(s) already gone=%d\n", db, db->block, db->x64_addr, db->x64_addr+db->x64_size-1, db->parent, db->father, db->sons_size, db->gone); + 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); if(need_lock) pthread_mutex_lock(&my_context->mutex_dyndump); - db->done = 0; - db->gone = 1; - // remove from direct if there - uintptr_t startdb = db->parent->text; - uintptr_t enddb = db->parent->text + db->parent->textsz; - if(db->parent->direct) { - uintptr_t addr = (uintptr_t)db->x64_addr; - if(addr>=startdb && addr<enddb) - native_lock_xchg(&db->parent->direct[addr-startdb], 0); // secured write - } // remove jumptable setJumpTableDefault64(db->x64_addr); - // remove and free the sons - for (int i=0; i<db->sons_size; ++i) { - dynablock_t *son = (dynablock_t*)native_lock_xchg(&db->sons[i], 0); - FreeDynablock(son, 0); - } - // only the father free the DynarecMap - if(!db->father) { - dynarec_log(LOG_DEBUG, " -- FreeDyrecMap(%p, %d)\n", db->block, db->size); - FreeDynarecMap(db, (uintptr_t)db->block, db->size); - customFree(db->sons); - customFree(db->instsize); - } + dynarec_log(LOG_DEBUG, " -- FreeDyrecMap(%p, %d)\n", db->actual_block, db->size); + db->done = 0; + db->gone = 1; + FreeDynarecMap(db, (uintptr_t)db->actual_block, db->size); customFree(db); if(need_lock) pthread_mutex_unlock(&my_context->mutex_dyndump); } } -void FreeDynablockList(dynablocklist_t** dynablocks) -{ - if(!dynablocks) - return; - if(!*dynablocks) - return; - dynarec_log(LOG_DEBUG, "Free Dynablocklist %p, with Direct Blocks %p\n", *dynablocks, (*dynablocks)->direct); - if((*dynablocks)->direct) { - for (int i=0; i<(*dynablocks)->textsz; ++i) { - if((*dynablocks)->direct[i] && !(*dynablocks)->direct[i]->father) - FreeDynablock((*dynablocks)->direct[i], 1); - } - customFree((*dynablocks)->direct); - } - (*dynablocks)->direct = NULL; - - customFree(*dynablocks); - *dynablocks = NULL; -} - void MarkDynablock(dynablock_t* db) { if(db) { - if(db->father) - db = db->father; // mark only father if(db->need_test) return; // already done - dynarec_log(LOG_DEBUG, "MarkDynablock %p with %d son(s) %p-%p\n", db, db->sons_size, db->x64_addr, db->x64_addr+db->x64_size-1); + dynarec_log(LOG_DEBUG, "MarkDynablock %p %p-%p\n", db, db->x64_addr, db->x64_addr+db->x64_size-1); db->need_test = 1; - setJumpTableDefault64(db->x64_addr); - for(int i=0; i<db->sons_size; ++i) - setJumpTableDefault64(db->sons[i]->x64_addr); + setJumpTableIfRef64(db->x64_addr, db->jmpnext, db->block); } } -uintptr_t StartDynablockList(dynablocklist_t* db) -{ - if(db) - return db->text; - return 0; -} -uintptr_t EndDynablockList(dynablocklist_t* db) -{ - if(db) - return db->text+db->textsz-1; - return 0; -} - int IntervalIntersects(uintptr_t start1, uintptr_t end1, uintptr_t start2, uintptr_t end2) { if(start1 > end2 || start2 > end1) @@ -152,90 +79,35 @@ int IntervalIntersects(uintptr_t start1, uintptr_t end1, uintptr_t start2, uintp static int MarkedDynablock(dynablock_t* db) { if(db) { - if(db->father) - db = db->father; // mark only father if(db->need_test) return 1; // already done } return 0; } -void MarkDirectDynablock(dynablocklist_t* dynablocks, uintptr_t addr, uintptr_t size) +void MarkRangeDynablock(dynablock_t* db, uintptr_t addr, uintptr_t size) { // Mark will try to find *any* blocks that intersect the range to mark - if(!dynablocks) - return; - if(!dynablocks->direct) + if(!db) return; - uintptr_t startdb = dynablocks->text; - uintptr_t sizedb = dynablocks->textsz; - dynablock_t *db; - dynarec_log(LOG_DEBUG, "MarkDirectDynablock %p-%p .. startdb=%p, sizedb=%p\n", (void*)addr, (void*)addr+size-1, (void*)startdb, (void*)sizedb); - for(uintptr_t i = 0; i<sizedb; ++i) - if((db=dynablocks->direct[i]) && !MarkedDynablock(db)) - if(IntervalIntersects((uintptr_t)db->x64_addr, (uintptr_t)db->x64_addr+db->x64_size-1, addr, addr+size+1)) - MarkDynablock(db); + dynarec_log(LOG_DEBUG, "MarkRangeDynablock %p-%p .. startdb=%p, sizedb=%p\n", (void*)addr, (void*)addr+size-1, (void*)db->x64_addr, (void*)db->x64_size); + if(!MarkedDynablock(db)) + if(IntervalIntersects((uintptr_t)db->x64_addr, (uintptr_t)db->x64_addr+db->x64_size-1, addr, addr+size+1)) + MarkDynablock(db); } -int FreeRangeDynablock(dynablocklist_t* dynablocks, uintptr_t addr, uintptr_t size) +int FreeRangeDynablock(dynablock_t* db, uintptr_t addr, uintptr_t size) { - if(!dynablocks) + if(!db) return 1; - if(dynablocks->direct) { - int need_lock = my_context?1:0; - dynablock_t* db; - int ret; - khint_t k; - kh_dynablocks_t *blocks = kh_init(dynablocks); - // copy in a temporary list - uintptr_t startdb = dynablocks->text; - uintptr_t enddb = startdb + dynablocks->textsz; - uintptr_t start = addr; - uintptr_t end = addr+size; - if(start<startdb) - start = startdb; - if(end>enddb) - end = enddb; - if(end>startdb && start<enddb) - for(uintptr_t i = start; i<end; ++i) { - db = (dynablock_t*)native_lock_xchg(&dynablocks->direct[i-startdb], 0); - if(db) { - if(db->father) - db = db->father; - if(db->parent==dynablocks) { - k = kh_put(dynablocks, blocks, (uintptr_t)db, &ret); - kh_value(blocks, k) = db; - } - } - } - // purge the list - kh_foreach_value(blocks, db, - FreeDynablock(db, need_lock); - ); - kh_destroy(dynablocks, blocks); - // check emptyness - for(uintptr_t i=0; i<dynablocks->textsz; ++i) - if(dynablocks->direct[i]) - return 0; - return 1; + 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); + return 0; } return 1; } -void MarkRangeDynablock(dynablocklist_t* dynablocks, uintptr_t addr, uintptr_t size) -{ - if(!dynablocks) - return; - dynarec_log(LOG_DEBUG, "MarkRangeDynablock %p-%p\n", (void*)addr, (void*)addr+size-1); - if(dynablocks->direct) { - uintptr_t new_addr = dynablocks->minstart; - uintptr_t new_size = dynablocks->maxend - new_addr + 1; - MarkDirectDynablock(dynablocks, addr, size); - // the blocks check before - for(unsigned idx=(new_addr)>>DYNAMAP_SHIFT; idx<(addr>>DYNAMAP_SHIFT); ++idx) - MarkDirectDynablock(getDB(idx), addr, size); - } -} dynablock_t* FindDynablockDynablocklist(void* addr, kh_dynablocks_t* dynablocks) { @@ -246,63 +118,30 @@ dynablock_t* FindDynablockDynablocklist(void* addr, kh_dynablocks_t* dynablocks) const uintptr_t s = (uintptr_t)db->block; const uintptr_t e = (uintptr_t)db->block+db->size; if((uintptr_t)addr>=s && (uintptr_t)addr<e) - return db->father?db->father:db; + return db; ) return NULL; } -static dynablocklist_t* getDBFromAddress(uintptr_t addr) -{ - const uintptr_t idx = (addr>>DYNAMAP_SHIFT); - return getDB(idx); -} - -dynablock_t *AddNewDynablock(dynablocklist_t* dynablocks, uintptr_t addr, int* created) +dynablock_t *AddNewDynablock(uintptr_t addr) { - if(!dynablocks) { - dynarec_log(LOG_INFO, "Warning: Ask to create a dynablock with a NULL dynablocklist (addr=%p)\n", (void*)addr); - *created = 0; + dynablock_t* block; + #if 0 + // check if memory as the correct flags + int prot = getProtection(addr); + if(!(prot&(PROT_EXEC|PROT_DYNAREC|PROT_DYNAREC_R))) { + dynarec_log(LOG_VERBOSE, "Block asked on a memory with no execution flags 0x%02X\n", prot); return NULL; } - if((addr<dynablocks->text) || (addr>=(dynablocks->text+dynablocks->textsz))) { - return AddNewDynablock(getDBFromAddress(addr), addr, created); - } - dynablock_t* block = NULL; - // first, check if it exist in direct access mode - if(dynablocks->direct) { - block = dynablocks->direct[addr-dynablocks->text]; - if(block) { - dynarec_log(LOG_VERBOSE, "Block already exist in Direct Map\n"); - *created = 0; - return block; - } - } - - if (!*created) - return block; + #endif pthread_mutex_lock(&my_context->mutex_dyndump); - if(!dynablocks->direct) { - dynablock_t** p = (dynablock_t**)customCalloc(dynablocks->textsz, sizeof(dynablock_t*)); - if(native_lock_storeifnull(&dynablocks->direct, p)!=p) - customFree(p); // someone already create the direct array, too late... - } // create and add new block dynarec_log(LOG_VERBOSE, "Ask for DynaRec Block creation @%p\n", (void*)addr); block = (dynablock_t*)customCalloc(1, sizeof(dynablock_t)); - block->parent = dynablocks; - dynablock_t* tmp = (dynablock_t*)native_lock_storeifnull(&dynablocks->direct[addr-dynablocks->text], block); - if(tmp != block) { - // a block appeard! - pthread_mutex_unlock(&my_context->mutex_dyndump); - customFree(block); - *created = 0; - return tmp; - } - *created = 1; pthread_mutex_lock(&my_context->mutex_dyndump); return block; } @@ -319,39 +158,26 @@ void cancelFillBlock() return NULL if block is not found / cannot be created. Don't create if create==0 */ -static dynablock_t* internalDBGetBlock(x64emu_t* emu, uintptr_t addr, uintptr_t filladdr, int create, dynablock_t* current, int need_lock) +static dynablock_t* internalDBGetBlock(x64emu_t* emu, uintptr_t addr, uintptr_t filladdr, int create, int need_lock) { - // try the quickest way first: get parent of current and check if ok! - dynablocklist_t *dynablocks = NULL; - dynablock_t* block = NULL; - if(current && current->done && !current->gone) { - dynablocks = current->parent; - if(dynablocks && !(addr>=dynablocks->text && addr<(dynablocks->text+dynablocks->textsz))) - dynablocks = NULL; - } - // nope, lets do the long way - if(!dynablocks) { - dynablocks = getDBFromAddress(addr); - if(!dynablocks) { - dynablocks = GetDynablocksFromAddress(emu->context, addr); - if(!dynablocks) - return NULL; - } - } - // check direct first, without lock - if(dynablocks->direct/* && (addr>=dynablocks->text) && (addr<(dynablocks->text+dynablocks->textsz))*/) - if((block = dynablocks->direct[addr-dynablocks->text])) - return block; + dynablock_t* block = getDB(addr); + if(block || !create) + return block; - int created = create; - block = AddNewDynablock(dynablocks, addr, &created); - if(!created) - return block; // existing block... + if(need_lock) + pthread_mutex_lock(&my_context->mutex_dyndump); + + block = getDB(addr); // just in case + if(block) { + if(need_lock) + pthread_mutex_unlock(&my_context->mutex_dyndump); + return block; + } + + block = AddNewDynablock(addr); // fill the block block->x64_addr = (void*)addr; - if(need_lock) - pthread_mutex_lock(&my_context->mutex_dyndump); if(sigsetjmp(&dynarec_jmpbuf, 1)) { printf_log(LOG_INFO, "FillBlock at %p triggered a segfault, cancelling\n", (void*)addr); if(need_lock) @@ -359,209 +185,59 @@ static dynablock_t* internalDBGetBlock(x64emu_t* emu, uintptr_t addr, uintptr_t return NULL; } void* ret = FillBlock64(block, filladdr); - if(need_lock) - pthread_mutex_unlock(&my_context->mutex_dyndump); if(!ret) { dynarec_log(LOG_DEBUG, "Fillblock of block %p for %p returned an error\n", block, (void*)addr); - void* old = (void*)native_lock_storeifref(&dynablocks->direct[addr-dynablocks->text], 0, block); - if(old!=block && old) {// put it back in place, strange things are happening here! - dynarec_log(LOG_INFO, "Warning, a wild block appeared at %p: %p\n", (void*)addr, old); - // doing nothing else, the block has not be writen - } customFree(block); block = NULL; } // check size - if(block && block->x64_size) { - if(dynablocks->minstart>addr) - dynablocks->minstart = addr; + if(block && (block->x64_size || (!block->x64_size && !block->done))) { int blocksz = block->x64_size; - if(dynablocks->maxend<addr+blocksz) { - dynablocks->maxend = addr+blocksz; - for(unsigned idx=(addr>>DYNAMAP_SHIFT)+1; idx<=((addr+blocksz-1)>>DYNAMAP_SHIFT); ++idx) { - dynablocklist_t* dblist; - if((dblist = getDB(idx))) - if(dblist->minstart>addr) - dblist->minstart = addr; - } - } + if(blocksz>my_context->max_db_size) + my_context->max_db_size = blocksz; // fill-in jumptable - addJumpTableIfDefault64(block->x64_addr, block->block); - for(int i=0; i<block->sons_size; ++i) { - addJumpTableIfDefault64(block->sons[i]->x64_addr, block->sons[i]->block); - block->sons[i]->done = 1; + if(!addJumpTableIfDefault64(block->x64_addr, block->block)) { + FreeDynablock(block, 1); + block = getDB(addr); + } else { + if(block->x64_size) + block->done = 1; // don't validate the block if the size is null, but keep the block } - block->done = 1; } + if(need_lock) + pthread_mutex_unlock(&my_context->mutex_dyndump); - dynarec_log(LOG_DEBUG, "%04d| --- DynaRec Block %s @%p:%p (%p, 0x%x bytes, with %d son(s))\n", GetTID(), created?"created":"recycled", (void*)addr, (void*)(addr+((block)?block->x64_size:1)-1), (block)?block->block:0, (block)?block->size:0, (block)?block->sons_size:0); + dynarec_log(LOG_DEBUG, "%04d| --- DynaRec Block created @%p:%p (%p, 0x%x bytes)\n", GetTID(), (void*)addr, (void*)(addr+((block)?block->x64_size:1)-1), (block)?block->block:0, (block)?block->size:0); return block; } -#define MAX_HOTPAGE 64 -#define HOTPAGE_STEP 64 -static int volatile hotpage_count[MAX_HOTPAGE] = {0}; -static uintptr_t volatile hotpage[MAX_HOTPAGE] = {0}; -static uintptr_t volatile hotpage_size[MAX_HOTPAGE] = {0}; -static volatile int hotpages = 0; - -int IsInHotPage(uintptr_t addr) { - if(!hotpages) - return 0; - for(int i=0; i<MAX_HOTPAGE; ++i) { - if((hotpage_count[i]>0) && (addr>=hotpage[i]) && (addr<hotpage[i]+0x1000*(hotpage_size[i]+1))) { - --hotpage_count[i]; - if(!hotpage_count[i]) { - --hotpages; - hotpage_size[i] = 0; - dynarec_log(LOG_DEBUG, "End of Hotpage %p\n", (void*)hotpage[i]); - } - __sync_synchronize(); - return 1; - } - } - return 0; -} - -int AreaInHotPage(uintptr_t start, uintptr_t end) { - if(!hotpages) - return 0; - for(int i=0; i<MAX_HOTPAGE; ++i) { - if(hotpage_count[i]>0) - if(IntervalIntersects(start, end, hotpage[i], hotpage[i]+0x1000*(hotpage_size[i]+1)-1)) { - --hotpage_count[i]; - if(!hotpage_count[i]) { - --hotpages; - hotpage_size[i] = 0; - dynarec_log(LOG_DEBUG, "End of Hotpage %p\n", (void*)hotpage[i]); - } - return 1; - } - } - return 0; -} - -void FuseHotPage(int idx) { - uintptr_t start = hotpage[idx]; - uintptr_t end = start+0x1000*(hotpage_size[idx]+1); - for(int i=0; i<MAX_HOTPAGE; ++i) - if(i!=idx && hotpage_count[i]>0) { - if(IntervalIntersects(start, end, hotpage[i], hotpage[i]+0x1000*(hotpage_size[i]+1)-1)) { - if(hotpage_count[i]>hotpage_count[idx]) - hotpage_count[idx] = hotpage_count[i]; - if(hotpage[i]>hotpage[idx]) - hotpage[idx]=hotpage[i]; - if(hotpage[i]+0x1000*(hotpage_size[i]+1)>end) - hotpage_size[idx] = ((hotpage[i]+0x1000*(hotpage_size[i]+1))-hotpage[idx])/0x1000 - 1; - hotpage_count[i] = 0; - return; - } - } -} - -void AddHotPage(uintptr_t addr) { - addr&=~0xfff; - // look for same address - for(int i=0; i<MAX_HOTPAGE; ++i) { - if(addr>=hotpage[i] && addr<hotpage[i]+0x1000*(hotpage_size[i]+1)) { - if(!hotpage_count[i]) - ++hotpages; - hotpage_count[i] = HOTPAGE_STEP; - __sync_synchronize(); - return; - } - if(addr==hotpage[i]+0x1000*(hotpage_size[i]+1)) { - ++hotpage_size[i]; - hotpage_count[i] = HOTPAGE_STEP; - FuseHotPage(i); - __sync_synchronize(); - return; - } - if(addr+0x1000==hotpage[i]) { - ++hotpage_size[i]; - hotpage[i] = addr; - hotpage_count[i] = HOTPAGE_STEP; - __sync_synchronize(); - return; - } - if(addr==hotpage[i]+0x1000*(hotpage_size[i]+2)) { - hotpage_size[i]+=2; - hotpage_count[i] = HOTPAGE_STEP; - FuseHotPage(i); - __sync_synchronize(); - return; - } - if(addr+0x2000==hotpage[i]) { - hotpage_size[i]+=2; - hotpage[i] = addr; - hotpage_count[i] = HOTPAGE_STEP; - FuseHotPage(i); - __sync_synchronize(); - return; - } - } - // look for empty spot / minium - int mincnt = hotpage_count[0]*(hotpage_size[0]+1); - int minidx = 0; - for(int i=1; i<MAX_HOTPAGE; ++i) - if((hotpage_count[i]*(hotpage_size[i]+1))<mincnt) { - mincnt = (hotpage_count[i]*(hotpage_size[i]+1)); - minidx = i; - } - if(hotpage_count[minidx]) { - static int cnt = 0; - if(cnt<50) { - dynarec_log(LOG_NONE, "Warning, not enough Hotpage, replacing %p(%p/%d) with %p\n", (void*)hotpage[minidx], (void*)(0x1000*(hotpage_size[minidx]+1)), hotpage_count[minidx], (void*)addr); - ++cnt; - if(cnt==50) // stop spamming console with message... - dynarec_log(LOG_NONE, " will stop warning about not enough Hotpage now\n"); - } - hotpage_size[minidx] = 0; - } else - ++hotpages; - hotpage[minidx] = addr; - hotpage_count[minidx] = HOTPAGE_STEP; - __sync_synchronize(); -} - -dynablock_t* DBGetBlock(x64emu_t* emu, uintptr_t addr, int create, dynablock_t** current) +dynablock_t* DBGetBlock(x64emu_t* emu, uintptr_t addr, int create) { - dynablock_t *db = internalDBGetBlock(emu, addr, addr, create, *current, 1); - dynablock_t *father = (db && db->father)?db->father:db; - if(father && father->done && db->block && father->need_test) { - if(pthread_mutex_trylock(&my_context->mutex_dyndump)) { - dynarec_log(LOG_DEBUG, "mutex_dyndump not available when trying to validate block %p from %p:%p (hash:%X) with %d son(s) for %p\n", db, db->x64_addr, db->x64_addr+db->x64_size-1, db->hash, db->sons_size, (void*)addr); + dynablock_t *db = internalDBGetBlock(emu, addr, addr, create, 1); + if(db && db->done && db->block && db->need_test) { + if(AreaInHotPage((uintptr_t)db->x64_addr, (uintptr_t)db->x64_addr + db->x64_size - 1)) { + dynarec_log(LOG_DEBUG, "Not running block %p from %p:%p with for %p because it's in a hotpage\n", db, db->x64_addr, db->x64_addr+db->x64_size-1, (void*)addr); return NULL; } - if(AreaInHotPage((uintptr_t)father->x64_addr, (uintptr_t)father->x64_addr + father->x64_size - 1)) { - dynarec_log(LOG_DEBUG, "Not running block %p from %p:%p with %d son(s) for %p because it's in a hotpage\n", father, father->x64_addr, father->x64_addr+father->x64_size-1, father->sons_size, (void*)addr); - pthread_mutex_unlock(&my_context->mutex_dyndump); + uint32_t hash = X31_hash_code(db->x64_addr, db->x64_size); + if(pthread_mutex_trylock(&my_context->mutex_dyndump)) { + dynarec_log(LOG_DEBUG, "mutex_dyndump not available when trying to validate block %p from %p:%p (hash:%X) for %p\n", db, db->x64_addr, db->x64_addr+db->x64_size-1, db->hash, (void*)addr); return NULL; } - uint32_t hash = X31_hash_code(father->x64_addr, father->x64_size); - if(hash!=father->hash) { - father->done = 0; // invalidating the block - dynarec_log(LOG_DEBUG, "Invalidating block %p from %p:%p (hash:%X/%X) with %d son(s) for %p\n", father, father->x64_addr, father->x64_addr+father->x64_size-1, hash, father->hash, father->sons_size, (void*)addr); - // no more current if it gets invalidated too - if(*current && IntervalIntersects( - (uintptr_t)father->x64_addr, - (uintptr_t)father->x64_addr+father->x64_size-1, - (uintptr_t)(*current)->x64_addr, - (uintptr_t)(*current)->x64_addr+(*current)->x64_size-1)) - *current = NULL; - // Free father, it's now invalid! - FreeDynablock(father, 0); + if(hash!=db->hash) { + db->done = 0; // invalidating the block + dynarec_log(LOG_DEBUG, "Invalidating block %p from %p:%p (hash:%X/%X) for %p\n", db, db->x64_addr, db->x64_addr+db->x64_size-1, hash, db->hash, (void*)addr); + // Free db, it's now invalid! + FreeDynablock(db, 0); // start again... (will create a new block) - db = internalDBGetBlock(emu, addr, addr, create, *current, 0); + db = internalDBGetBlock(emu, addr, addr, create, 0); } else { - father->need_test = 0; - dynarec_log(LOG_DEBUG, "Validating block %p from %p:%p (hash:%X) with %d son(s) for %p\n", father, father->x64_addr, father->x64_addr+father->x64_size-1, father->hash, father->sons_size, (void*)addr); - protectDB((uintptr_t)father->x64_addr, father->x64_size); + db->need_test = 0; + dynarec_log(LOG_DEBUG, "Validating block %p from %p:%p (hash:%X) for %p\n", db, db->x64_addr, db->x64_addr+db->x64_size-1, db->hash, (void*)addr); + protectDB((uintptr_t)db->x64_addr, db->x64_size); // fill back jumptable - addJumpTableIfDefault64(father->x64_addr, father->block); - for(int i=0; i<father->sons_size; ++i) - addJumpTableIfDefault64(father->sons[i]->x64_addr, father->sons[i]->block); + setJumpTableIfRef64(db->x64_addr, db->block, db->jmpnext); } pthread_mutex_unlock(&my_context->mutex_dyndump); } @@ -572,26 +248,23 @@ dynablock_t* DBAlternateBlock(x64emu_t* emu, uintptr_t addr, uintptr_t filladdr) { dynarec_log(LOG_DEBUG, "Creating AlternateBlock at %p for %p\n", (void*)addr, (void*)filladdr); int create = 1; - dynablock_t *db = internalDBGetBlock(emu, addr, filladdr, create, NULL, 1); - dynablock_t *father = (db && db->father)?db->father:db; - if(father && father->done && db->block && father->need_test) { + dynablock_t *db = internalDBGetBlock(emu, addr, filladdr, create, 1); + if(db && db->done && db->block && db->need_test) { if(pthread_mutex_trylock(&my_context->mutex_dyndump)) return NULL; - uint32_t hash = X31_hash_code(father->x64_addr, father->x64_size); - if(hash!=father->hash) { - father->done = 0; // invalidating the block - dynarec_log(LOG_DEBUG, "Invalidating alt block %p from %p:%p (hash:%X/%X) with %d son(s) for %p\n", father, father->x64_addr, father->x64_addr+father->x64_size, hash, father->hash, father->sons_size, (void*)addr); - // Free father, it's now invalid! - FreeDynablock(father, 0); + uint32_t 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); + // Free db, it's now invalid! + FreeDynablock(db, 0); // start again... (will create a new block) - db = internalDBGetBlock(emu, addr, filladdr, create, NULL, 0); + db = internalDBGetBlock(emu, addr, filladdr, create, 0); } else { - father->need_test = 0; - protectDB((uintptr_t)father->x64_addr, father->x64_size); + db->need_test = 0; + protectDB((uintptr_t)db->x64_addr, db->x64_size); // fill back jumptable - addJumpTableIfDefault64(father->x64_addr, father->block); - for(int i=0; i<father->sons_size; ++i) - addJumpTableIfDefault64(father->sons[i]->x64_addr, father->sons[i]->block); + addJumpTableIfDefault64(db->x64_addr, db->block); } pthread_mutex_unlock(&my_context->mutex_dyndump); } diff --git a/src/dynarec/dynablock_private.h b/src/dynarec/dynablock_private.h index e73d35ba..dbe8c502 100755 --- a/src/dynarec/dynablock_private.h +++ b/src/dynarec/dynablock_private.h @@ -1,16 +1,14 @@ #ifndef __DYNABLOCK_PRIVATE_H_ #define __DYNABLOCK_PRIVATE_H_ -typedef struct dynablocklist_s dynablocklist_t; - typedef struct instsize_s { - unsigned int x64:4; - unsigned int nat:4; + unsigned char x64:4; + unsigned char nat:4; } instsize_t; typedef struct dynablock_s { - dynablocklist_t* parent; - void* block; + void* block; // block-sizeof(void*) == self + void* actual_block; // the actual start of the block (so block-sizeof(void*)) int size; void* x64_addr; uintptr_t x64_size; @@ -20,18 +18,8 @@ typedef struct dynablock_s { uint8_t gone; uint8_t dummy; int isize; - dynablock_t** sons; // sons (kind-of dummy dynablock...) - int sons_size; - dynablock_t* father; // set only in the case of a son instsize_t* instsize; + void* jmpnext; // a branch jmpnext code when block is marked } dynablock_t; -typedef struct dynablocklist_s { - uintptr_t text; - int textsz; - uintptr_t maxend; // max address end for anyblock on this blocklist - uintptr_t minstart; // min start address for block overlapping this blocklist - dynablock_t** direct; // direct mapping (waste of space, so the array is created at first write) -} dynablocklist_t; - #endif //__DYNABLOCK_PRIVATE_H_ \ No newline at end of file diff --git a/src/dynarec/dynarec.c b/src/dynarec/dynarec.c index 819ef219..920bfaa8 100755 --- a/src/dynarec/dynarec.c +++ b/src/dynarec/dynarec.c @@ -20,22 +20,7 @@ #include "dynablock.h" #include "dynablock_private.h" #include "bridge.h" -#endif - -#ifdef DYNAREC -#ifdef ARM64 -void arm64_prolog(x64emu_t* emu, void* addr) EXPORTDYN; -void arm64_epilog() EXPORTDYN; -#define native_prolog arm64_prolog -#define native_epilog arm64_epilog -#elif defined(LA464) -void la464_prolog(x64emu_t* emu, void* addr) EXPORTDYN; -void la464_epilog() EXPORTDYN; -#define native_prolog la464_prolog -#define native_epilog la464_epilog -#else -#error Unsupported architecture -#endif +#include "dynarec_next.h" #endif #ifdef DYNAREC @@ -49,9 +34,8 @@ void* LinkNext(x64emu_t* emu, uintptr_t addr, void* x2, uintptr_t* x3) printf_log(LOG_NONE, "Warning, jumping to NULL address from %p (db=%p, x64addr=%p/%s)\n", x2-4, db, db?(void*)getX64Address(db, (uintptr_t)x2-4):NULL, db?getAddrFunctionName(getX64Address(db, (uintptr_t)x2-4)):"(nil)"); } #endif - dynablock_t* current = NULL; void * jblock; - dynablock_t* block = DBGetBlock(emu, addr, 1, ¤t); + dynablock_t* block = DBGetBlock(emu, addr, 1); if(!block) { // no block, let link table as is... if(hasAlternate((void*)addr)) { @@ -60,7 +44,7 @@ void* LinkNext(x64emu_t* emu, uintptr_t addr, void* x2, uintptr_t* x3) R_RIP = addr; // but also new RIP! *x3 = addr; // and the RIP in x27 register printf_log(LOG_DEBUG, " -> %p\n", (void*)addr); - block = DBGetBlock(emu, addr, 1, ¤t); + block = DBGetBlock(emu, addr, 1); } if(!block) { #ifdef HAVE_TRACE @@ -121,23 +105,18 @@ void DynaCall(x64emu_t* emu, uintptr_t addr) PushExit(emu); R_RIP = addr; emu->df = d_none; - dynablock_t* current = NULL; - dynablock_t* block = DBGetBlock(emu, R_RIP, 1, ¤t); - current = block; while(!emu->quit) { + dynablock_t* block = DBGetBlock(emu, R_RIP, 1); if(!block || !block->block || !block->done) { // no block, of block doesn't have DynaRec content (yet, temp is not null) // Use interpreter (should use single instruction step...) dynarec_log(LOG_DEBUG, "%04d|Calling Interpretor @%p, emu=%p\n", GetTID(), (void*)R_RIP, emu); Run(emu, 1); - block = DBGetBlock(emu, R_RIP, 1, ¤t); - current = block; } else { - dynarec_log(LOG_DEBUG, "%04d|Calling DynaRec Block @%p (%p) of %d x64 instructions (father=%p) emu=%p\n", GetTID(), (void*)R_RIP, block->block, block->isize ,block->father, emu); + dynarec_log(LOG_DEBUG, "%04d|Calling DynaRec Block @%p (%p) of %d x64 instructions emu=%p\n", GetTID(), (void*)R_RIP, block->block, block->isize ,emu); CHECK_FLAGS(emu); // block is here, let's run it! native_prolog(emu, block->block); - block = NULL; } if(emu->fork) { int forktype = emu->fork; @@ -201,22 +180,17 @@ int DynaRun(x64emu_t* emu) return Run(emu, 0); #ifdef DYNAREC else { - dynablock_t* current = NULL; - dynablock_t* block = DBGetBlock(emu, R_RIP, 1, ¤t);; - current = block; while(!emu->quit) { + dynablock_t* block = DBGetBlock(emu, R_RIP, 1); if(!block || !block->block || !block->done) { // no block, of block doesn't have DynaRec content (yet, temp is not null) // Use interpreter (should use single instruction step...) dynarec_log(LOG_DEBUG, "%04d|Running Interpretor @%p, emu=%p\n", GetTID(), (void*)R_RIP, emu); Run(emu, 1); - block = DBGetBlock(emu, R_RIP, 1, ¤t); - current = block; } else { - dynarec_log(LOG_DEBUG, "%04d|Running DynaRec Block @%p (%p) of %d x64 insts (father=%p) emu=%p\n", GetTID(), (void*)R_RIP, block->block, block->isize, block->father, emu); + dynarec_log(LOG_DEBUG, "%04d|Running DynaRec Block @%p (%p) of %d x64 insts emu=%p\n", GetTID(), (void*)R_RIP, block->block, block->isize, emu); // block is here, let's run it! native_prolog(emu, block->block); - block = NULL; } if(emu->fork) { int forktype = emu->fork; diff --git a/src/dynarec/dynarec_native.c b/src/dynarec/dynarec_native.c index 9da18cf6..890b2397 100755 --- a/src/dynarec/dynarec_native.c +++ b/src/dynarec/dynarec_native.c @@ -23,6 +23,7 @@ #include "dynarec_native.h" #include "dynarec_arch.h" +#include "dynarec_next.h" void printf_x64_instruction(zydis_dec_t* dec, instruction_x64_t* inst, const char* name) { uint8_t *ip = (uint8_t*)inst->addr; @@ -279,7 +280,7 @@ int Table64(dynarec_native_t *dyn, uint64_t val) // not found, add it if(idx==-1) { if(dyn->table64size == dyn->table64cap) { - dyn->table64cap+=4; + dyn->table64cap+=16; dyn->table64 = (uint64_t*)customRealloc(dyn->table64, dyn->table64cap * sizeof(uint64_t)); } idx = dyn->table64size++; @@ -385,9 +386,12 @@ void CancelBlock64() return; customFree(helper->next); customFree(helper->insts); + customFree(helper->instsize); customFree(helper->table64); - if(helper->dynablock && helper->dynablock->block) - FreeDynarecMap(helper->dynablock, (uintptr_t)helper->dynablock->block, helper->dynablock->size); + if(helper->dynablock && helper->dynablock->actual_block) + FreeDynarecMap(helper->dynablock, (uintptr_t)helper->dynablock->actual_block, helper->dynablock->size); + else if(helper->dynablock && helper->block) + FreeDynarecMap(helper->dynablock, (uintptr_t)helper->block-sizeof(void*), helper->dynablock->size); } uintptr_t native_pass0(dynarec_native_t* dyn, uintptr_t addr); @@ -395,15 +399,38 @@ uintptr_t native_pass1(dynarec_native_t* dyn, uintptr_t addr); uintptr_t native_pass2(dynarec_native_t* dyn, uintptr_t addr); uintptr_t native_pass3(dynarec_native_t* dyn, uintptr_t addr); +void* CreateEmptyBlock(dynablock_t* block, uintptr_t addr) { + block->isize = 0; + block->done = 0; + size_t sz = 4*sizeof(void*); + void* actual_p = (void*)AllocDynarecMap(block, sz); + void* p = actual_p + sizeof(void*); + if(actual_p==NULL) { + dynarec_log(LOG_INFO, "AllocDynarecMap(%p, %zu) failed, cancelling block\n", block, sz); + CancelBlock64(); + return NULL; + } + block->size = sz; + block->actual_block = actual_p; + block->block = p; + block->jmpnext = p; + *(dynablock_t**)actual_p = block; + *(void**)(p+2*sizeof(void*)) = native_epilog; + CreateJmpNext(block->jmpnext, p+2*sizeof(void*)); + block->need_test = 0; + // all done... + __clear_cache(actual_p, actual_p+sz); // need to clear the cache before execution... + return block; +} + void* FillBlock64(dynablock_t* block, uintptr_t addr) { if(IsInHotPage(addr)) { dynarec_log(LOG_DEBUG, "Cancelling dynarec FillBlock on hotpage for %p\n", (void*)addr); return NULL; } if(addr>=box64_nodynarec_start && addr<box64_nodynarec_end) { - dynarec_log(LOG_INFO, "Stopping block in no-dynarec zone\n"); - block->done = 1; - return (void*)block; + dynarec_log(LOG_INFO, "Create empty block in no-dynarec zone\n"); + return CreateEmptyBlock(block, addr); } // protect the 1st page protectDB(addr, 1); @@ -425,7 +452,7 @@ void* FillBlock64(dynablock_t* block, uintptr_t addr) { if(!helper.size) { dynarec_log(LOG_INFO, "Warning, null-sized dynarec block (%p)\n", (void*)addr); CancelBlock64(); - return (void*)block; + return CreateEmptyBlock(block, addr);; } if(!isprotectedDB(addr, 1)) { dynarec_log(LOG_INFO, "Warning, write on current page on pass0, aborting dynablock creation (%p)\n", (void*)addr); @@ -458,44 +485,7 @@ void* FillBlock64(dynablock_t* block, uintptr_t addr) { } // fill predecessors with the jump address fillPredecessors(&helper); - // check for the optionnal barriers now - /*for(int i=helper.size-1; i>=0; --i) { - if(helper.insts[i].barrier_maybe) { - // out-of-block jump - if(helper.insts[i].x64.jmp_insts == -1) { - // nothing for now - } else { - // inside block jump - int k = helper.insts[i].x64.jmp_insts; - if(k>i) { - // jump in the future - if(helper.insts[k].pred_sz>1) { - // with multiple flow, put a barrier - helper.insts[k].x64.barrier|=BARRIER_FLAGS; - } - } else { - // jump back - helper.insts[k].x64.barrier|=BARRIER_FLAGS; - } - } - } - }*/ - // check to remove useless barrier, in case of jump when destination doesn't needs flags - /*for(int i=helper.size-1; i>=0; --i) { - int k; - if(helper.insts[i].x64.jmp - && ((k=helper.insts[i].x64.jmp_insts)>=0) - && helper.insts[k].x64.barrier&BARRIER_FLAGS) { - //TODO: optimize FPU barrier too - if((!helper.insts[k].x64.need_flags) - ||(helper.insts[k].x64.set_flags==X_ALL - && helper.insts[k].x64.state_flags==SF_SET) - ||(helper.insts[k].x64.state_flags==SF_SET_PENDING)) { - //if(box64_dynarec_dump) dynarec_log(LOG_NONE, "Removed barrier for inst %d\n", k); - helper.insts[k].x64.barrier &= ~BARRIER_FLAGS; // remove flag barrier - } - } - }*/ + int pos = helper.size; while (pos>=0) pos = updateNeed(&helper, pos, 0); @@ -505,10 +495,28 @@ void* FillBlock64(dynablock_t* block, uintptr_t addr) { // pass 2, instruction size native_pass2(&helper, addr); + // keep size of instructions for signal handling + size_t insts_rsize = 0; + { + size_t insts_size = 0; + size_t cap = 1; + for(int i=0; i<helper.size; ++i) + cap += 1 + ((helper.insts[i].x64.size>helper.insts[i].size)?helper.insts[i].x64.size:helper.insts[i].size)/15; + helper.instsize = (instsize_t*)customCalloc(cap, sizeof(instsize_t)); + for(int i=0; i<helper.size; ++i) + helper.instsize = addInst(helper.instsize, &insts_size, &cap, helper.insts[i].x64.size, helper.insts[i].size/4); + helper.instsize = addInst(helper.instsize, &insts_size, &cap, 0, 0); // add a "end of block" mark, just in case + insts_rsize = insts_size*sizeof(instsize_t); + } + insts_rsize = (insts_rsize+7)&~7; // round the size... // ok, now allocate mapped memory, with executable flag on - size_t sz = helper.native_size + helper.table64size*sizeof(uint64_t); - void* p = (void*)AllocDynarecMap(block, sz); - if(p==NULL) { + size_t sz = sizeof(void*) + helper.native_size + helper.table64size*sizeof(uint64_t) + 4*sizeof(void*) + insts_rsize; + // dynablock_t* block (arm insts) table64 jmpnext code instsize + void* actual_p = (void*)AllocDynarecMap(block, sz); + void* p = actual_p + sizeof(void*); + void* next = p + helper.native_size + helper.table64size*sizeof(uint64_t); + void* instsize = next + 4*sizeof(void*); + if(actual_p==NULL) { dynarec_log(LOG_INFO, "AllocDynarecMap(%p, %zu) failed, cancelling block\n", block, sz); CancelBlock64(); return NULL; @@ -516,11 +524,7 @@ void* FillBlock64(dynablock_t* block, uintptr_t addr) { helper.block = p; helper.native_start = (uintptr_t)p; helper.tablestart = helper.native_start + helper.native_size; - if(helper.sons_size) { - helper.sons_x64 = (uintptr_t*)alloca(helper.sons_size*sizeof(uintptr_t)); - helper.sons_native = (void**)alloca(helper.sons_size*sizeof(void*)); - } - int pass2_sons_size = helper.sons_size; + *(dynablock_t**)actual_p = block; // pass 3, emit (log emit native opcode) if(box64_dynarec_dump) { dynarec_log(LOG_NONE, "%s%04d|Emitting %zu bytes for %u x64 bytes", (box64_dynarec_dump>1)?"\e[01;36m":"", GetTID(), helper.native_size, helper.isize); @@ -550,30 +554,29 @@ void* FillBlock64(dynablock_t* block, uintptr_t addr) { if(helper.table64size) { memcpy((void*)helper.tablestart, helper.table64, helper.table64size*8); } - // all done... - __clear_cache(p, p+sz); // need to clear the cache before execution... // keep size of instructions for signal handling - { - size_t cap = 1; - for(int i=0; i<helper.size; ++i) - cap += 1 + ((helper.insts[i].x64.size>helper.insts[i].size)?helper.insts[i].x64.size:helper.insts[i].size)/15; - size_t size = 0; - block->instsize = (instsize_t*)customCalloc(cap, sizeof(instsize_t)); - for(int i=0; i<helper.size; ++i) - block->instsize = addInst(block->instsize, &size, &cap, helper.insts[i].x64.size, helper.insts[i].size/4); - block->instsize = addInst(block->instsize, &size, &cap, 0, 0); // add a "end of block" mark, just in case - } + memcpy(instsize, helper.instsize, insts_rsize); + block->instsize = instsize; // ok, free the helper now customFree(helper.insts); helper.insts = NULL; customFree(helper.table64); helper.table64 = NULL; + customFree(helper.instsize); + helper.instsize = NULL; block->size = sz; block->isize = helper.size; + block->actual_block = actual_p; block->block = p; + block->jmpnext = next+sizeof(void*); + *(dynablock_t**)next = block; + *(void**)(next+2*sizeof(void*)) = native_next; + CreateJmpNext(block->jmpnext, next+2*sizeof(void*)); block->need_test = 0; //block->x64_addr = (void*)start; block->x64_size = end-start; + // all done... + __clear_cache(actual_p, actual_p+sz); // need to clear the cache before execution... block->hash = X31_hash_code(block->x64_addr, block->x64_size); // Check if something changed, to abbort if it as if((block->hash != hash)) { @@ -587,36 +590,6 @@ void* FillBlock64(dynablock_t* block, uintptr_t addr) { return NULL; //protectDB(addr, end-addr); } - // fill sons if any - dynablock_t** sons = NULL; - int sons_size = 0; - if(pass2_sons_size != helper.sons_size) - dynarec_log(LOG_NONE, "Warning, sons size difference bitween pass2:%d and pass3:%d\n", pass2_sons_size, helper.sons_size); - if(helper.sons_size) { - sons = (dynablock_t**)customCalloc(helper.sons_size, sizeof(dynablock_t*)); - for (int i=0; i<helper.sons_size; ++i) { - int created = 1; - dynablock_t *son = AddNewDynablock(block->parent, helper.sons_x64[i], &created); - if(created) { // avoid breaking a working block! - son->block = helper.sons_native[i]; - son->x64_addr = (void*)helper.sons_x64[i]; - son->x64_size = end-helper.sons_x64[i]; - if(!son->x64_size) {printf_log(LOG_NONE, "Warning, son with null x64 size! (@%p / Native=%p)", son->x64_addr, son->block);} - son->father = block; - son->size = sz + son->block - block->block; // update size count, for debugging - //son->done = 1; - if(!son->parent) - son->parent = block->parent; - sons[sons_size] = son; - ++sons_size; - } - } - if(sons_size) { - block->sons = sons; - block->sons_size = sons_size; - } else - customFree(sons); - } current_helper = NULL; //block->done = 1; return (void*)block; diff --git a/src/dynarec/dynarec_native_pass.c b/src/dynarec/dynarec_native_pass.c index b3357f8d..7ab25a6f 100755 --- a/src/dynarec/dynarec_native_pass.c +++ b/src/dynarec/dynarec_native_pass.c @@ -37,7 +37,6 @@ uintptr_t native_pass(dynarec_native_t* dyn, uintptr_t addr) rex_t rex; int rep; // 0 none, 1=F2 prefix, 2=F3 prefix int need_epilog = 1; - dyn->sons_size = 0; // Clean up (because there are multiple passes) dyn->f.pending = 0; dyn->f.dfnone = 0; @@ -248,6 +247,6 @@ uintptr_t native_pass(dynarec_native_t* dyn, uintptr_t addr) jump_to_epilog(dyn, ip, 0, ninst); // no linker here, it's an unknow instruction } FINI; - MESSAGE(LOG_DUMP, "---- END OF BLOCK ---- (%d, %d sons)\n", dyn->size, dyn->sons_size); + MESSAGE(LOG_DUMP, "---- END OF BLOCK ---- (%d)\n", dyn->size); return addr; } diff --git a/src/dynarec/dynarec_next.h b/src/dynarec/dynarec_next.h new file mode 100644 index 00000000..19d426b8 --- /dev/null +++ b/src/dynarec/dynarec_next.h @@ -0,0 +1,22 @@ +#ifndef __DYNAREC_NEXT_H__ +#define __DYNAREC_NEXT_H__ + +#ifdef ARM64 +void arm64_next(void) EXPORTDYN; +void arm64_prolog(x64emu_t* emu, void* addr) EXPORTDYN; +void arm64_epilog() EXPORTDYN; +#define native_next arm64_next +#define native_prolog arm64_prolog +#define native_epilog arm64_epilog +#elif defined(LA464) +void la464_next(void) EXPORTDYN; +void la464_prolog(x64emu_t* emu, void* addr) EXPORTDYN; +void la464_epilog() EXPORTDYN; +#define native_next la464_next +#define native_prolog la464_prolog +#define native_epilog la464_epilog +#else +#error Unsupported architecture +#endif + +#endif //__DYNAREC_NEXT_H__ \ No newline at end of file |