[DYNAREC] Re-introduce a simple HotPage handling, to speedup heavily obfuscated program loading (backported from box64)

This commit is contained in:
ptitSeb 2024-05-19 18:39:03 +02:00
parent dd5bba2aac
commit 148722dac4
5 changed files with 47 additions and 5 deletions

View File

@ -881,6 +881,26 @@ int isprotectedDB(uintptr_t addr, size_t size)
return 1;
}
uintptr_t hotpage = 0;
int hotpage_cnt = 0;
#define HOTPAGE_MARK 64
void SetHotPage(uintptr_t addr)
{
hotpage = addr&~(box86_pagesize-1);
hotpage_cnt = HOTPAGE_MARK;
}
int isInHotPage(uintptr_t addr)
{
if(!hotpage_cnt)
return 0;
--hotpage_cnt;
return (addr>=hotpage) && (addr<hotpage+box86_pagesize);
}
int checkInHotPage(uintptr_t addr)
{
return hotpage_cnt && (addr>=hotpage) && (addr<hotpage+box86_pagesize);
}
#endif
void updateProtection(uintptr_t addr, uintptr_t size, uint32_t prot)

View File

@ -262,6 +262,8 @@ static dynablock_t* internalDBGetBlock(x86emu_t* emu, uintptr_t addr, uintptr_t
dynablock_t* DBGetBlock(x86emu_t* emu, uintptr_t addr, int create)
{
if(isInHotPage(addr))
return NULL;
dynablock_t *db = internalDBGetBlock(emu, addr, addr, create, 1);
if(db && db->done && db->block && getNeedTest(addr)) {
if(db->always_test)

View File

@ -20,6 +20,7 @@
#include "dynablock.h"
#include "dynablock_private.h"
#include "bridge.h"
#include "custommem.h"
void x86test_check(x86emu_t* ref, uintptr_t ip);
#endif
@ -59,9 +60,13 @@ void* LinkNext(x86emu_t* emu, uintptr_t addr, void* x2)
// no block, let link table as is...
#ifdef HAVE_TRACE
if(LOG_INFO<=box86_dynarec_log) {
dynablock_t* db = FindDynablockFromNativeAddress(x2);
elfheader_t* h = FindElfAddress(my_context, (uintptr_t)x2);
dynarec_log(LOG_INFO, "Warning, jumping to a no-block address %p from %p (db=%p, x64addr=%p(elf=%s))\n", (void*)addr, x2, db, db?(void*)getX86Address(db, (uintptr_t)x2-4):NULL, h?ElfName(h):"(none)");
if(checkInHotPage(addr)) {
dynarec_log(LOG_INFO, "Not trying to run a block from a Hotpage at %p\n", (void*)addr);
} else {
dynablock_t* db = FindDynablockFromNativeAddress(x2-4);
elfheader_t* h = FindElfAddress(my_context, (uintptr_t)x2-4);
dynarec_log(LOG_INFO, "Warning, jumping to a no-block address %p from %p (db=%p, x86addr=%p(elf=%s))\n", (void*)addr, x2-4, db, db?(void*)getX86Address(db, (uintptr_t)x2-4):NULL, h?ElfName(h):"(none)");
}
}
#endif
//tableupdate(arm_epilog, addr, table);

View File

@ -76,6 +76,10 @@ void fini_custommem_helper(box86context_t* ctx);
// ---- StrongMemoryModel
void addLockAddress(uintptr_t addr); // add an address to the list of "LOCK"able
int isLockAddress(uintptr_t addr); // return 1 is the address is used as a LOCK, 0 else
void SetHotPage(uintptr_t addr);
int isInHotPage(uintptr_t addr);
int checkInHotPage(uintptr_t addr);
#endif
#endif //__CUSTOM_MEM__H_

View File

@ -850,11 +850,22 @@ void my_box86signalhandler(int32_t sig, siginfo_t* info, void * ucntx)
int db_searched = 0;
if ((sig==SIGSEGV) && (addr) && (info->si_code == SEGV_ACCERR) && (prot&PROT_CUSTOM)) {
lock_signal();
// access error, unprotect the block (and mark them dirty)
unprotectDB((uintptr_t)addr, 1, 1); // unprotect 1 byte... But then, the whole page will be unprotected
// check if SMC inside block
db = FindDynablockFromNativeAddress(pc);
db_searched = 1;
static uintptr_t repeated_page = 0;
dynarec_log(LOG_DEBUG, "SIGSEGV with Access error on %p for %p , db=%p(%p), prot=0x%hhx (old page=%p)\n", pc, addr, db, db?((void*)db->x86_addr):NULL, prot, (void*)repeated_page);
static int repeated_count = 0;
if(repeated_page == ((uintptr_t)addr&~(box86_pagesize-1))) {
++repeated_count; // Access eoor multiple time on same page, disable dynarec on this page a few time...
dynarec_log(LOG_DEBUG, "Detecting a Hotpage at %p (%d)\n", (void*)repeated_page, repeated_count);
SetHotPage(repeated_page);
} else {
repeated_page = (uintptr_t)addr&~(box86_pagesize-1);
repeated_count = 0;
}
// access error, unprotect the block (and mark them dirty)
unprotectDB((uintptr_t)addr, 1, 1); // unprotect 1 byte... But then, the whole page will be unprotected
int db_need_test = (db && !box86_dynarec_fastpage)?getNeedTest((uintptr_t)db->x86_addr):0;
dynarec_log(LOG_INFO/*LOG_DEBUG*/, "SIGSEGV with Access error on %p for %p , db=%p(%p)\n", pc, addr, db, db?((void*)db->x86_addr):NULL);
if(db && ((addr>=db->x86_addr && addr<(db->x86_addr+db->x86_size)) || db_need_test)) {