mirror of
https://github.com/ptitSeb/box86.git
synced 2024-11-23 09:54:03 +08:00
[DYNAREC] Remove dynarec linker mecanism and use generic TableJump instead (also all memory that have a dynablock is protected now, should improve compatibility with C# and program taht use SelfModifyCode)
This commit is contained in:
parent
8209cf8398
commit
911b95a505
@ -406,8 +406,7 @@ if(ARM_DYNAREC)
|
||||
|
||||
"${BOX86_ROOT}/src/dynarec/arm_prolog.S"
|
||||
"${BOX86_ROOT}/src/dynarec/arm_epilog.S"
|
||||
"${BOX86_ROOT}/src/dynarec/arm_linker.S"
|
||||
"${BOX86_ROOT}/src/dynarec/arm_table.S"
|
||||
"${BOX86_ROOT}/src/dynarec/arm_next.S"
|
||||
"${BOX86_ROOT}/src/dynarec/arm_lock_helper.S"
|
||||
)
|
||||
|
||||
|
10
USAGE.md
10
USAGE.md
@ -100,16 +100,6 @@ Enables/Disables Box86's Dynarec.
|
||||
* 0 : Disables Dynarec.
|
||||
* 1 : Enable Dynarec. (Default.)
|
||||
|
||||
#### BOX86_DYNAREC_LINKER
|
||||
Enables/Disables Box86's Dynarec linker.
|
||||
* 0 : Disables the Dynarec Linker. (Very useful for debugging when combined with BOX86_DYNAREC__LOG >= 2. This is to have details on which block gets executed.)
|
||||
* 1 : Enables the Dynarec Linker. (Default.)
|
||||
|
||||
#### BOX86_DYNAREC_SAFEMMAP
|
||||
Enables/Disables Box86's Dynarec's SAFEMMAP mecanism.
|
||||
* 0 : Some mmp/mmap64 blocks are considered unsafe (This depends on the program ran). (Default.)
|
||||
* 1 : Consider all mmap/mmap64 blocks safe to use linker (potential speedup, but potential crash for apps using JIT/Dynarec)
|
||||
|
||||
#### BOX86_DYNAREC_TRACE
|
||||
Enables/Disables trace for generated code.
|
||||
* 0 : Disable trace for generated code. (Default.)
|
||||
|
@ -27,71 +27,6 @@
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef DYNAREC
|
||||
// Remove the Write flag from an adress range, so DB can be executed
|
||||
// no log, as it can be executed inside a signal handler
|
||||
void protectDB(uintptr_t addr, uintptr_t size)
|
||||
{
|
||||
uintptr_t idx = (addr>>DYNAMAP_SHIFT);
|
||||
uintptr_t end = ((addr+size-1)>>DYNAMAP_SHIFT);
|
||||
for (uintptr_t i=idx; i<=end; ++i) {
|
||||
uint32_t prot;
|
||||
do {
|
||||
prot=arm_lock_read_d(&my_context->memprot[i]);
|
||||
if(!prot)
|
||||
prot = PROT_READ | PROT_WRITE; // comes from malloc & co, so should not be able to execute
|
||||
} while(arm_lock_write_d(&my_context->memprot[i], prot|PROT_DYNAREC));
|
||||
if(!(prot&PROT_DYNAREC))
|
||||
mprotect((void*)(i<<DYNAMAP_SHIFT), 1<<DYNAMAP_SHIFT, prot&~PROT_WRITE);
|
||||
}
|
||||
}
|
||||
|
||||
// Add the Write flag from an adress range, and mark all block as dirty
|
||||
// no log, as it can be executed inside a signal handler
|
||||
void unprotectDB(uintptr_t addr, uintptr_t size)
|
||||
{
|
||||
uintptr_t idx = (addr>>DYNAMAP_SHIFT);
|
||||
uintptr_t end = ((addr+size-1)>>DYNAMAP_SHIFT);
|
||||
for (uintptr_t i=idx; i<=end; ++i) {
|
||||
uint32_t prot;
|
||||
do {
|
||||
prot=arm_lock_read_d(&my_context->memprot[i]);
|
||||
} while(arm_lock_write_d(&my_context->memprot[i], prot&~PROT_DYNAREC));
|
||||
if(prot&PROT_DYNAREC) {
|
||||
mprotect((void*)(i<<DYNAMAP_SHIFT), 1<<DYNAMAP_SHIFT, prot&~PROT_DYNAREC);
|
||||
cleanDBFromAddressRange((i<<DYNAMAP_SHIFT), 1<<DYNAMAP_SHIFT, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void updateProtection(uintptr_t addr, uintptr_t size, uint32_t prot)
|
||||
{
|
||||
const uintptr_t idx = (addr>>DYNAMAP_SHIFT);
|
||||
const uintptr_t end = ((addr+size-1)>>DYNAMAP_SHIFT);
|
||||
for (uintptr_t i=idx; i<=end; ++i) {
|
||||
#ifdef DYNAREC
|
||||
uint32_t dyn;
|
||||
do {
|
||||
dyn=arm_lock_read_d(&my_context->memprot[i])&PROT_DYNAREC;
|
||||
} while(arm_lock_write_d(&my_context->memprot[i], prot|dyn));
|
||||
if(dyn && (prot&PROT_WRITE)) // need to remove the write protection from this block
|
||||
mprotect((void*)(i<<DYNAMAP_SHIFT), 1<<DYNAMAP_SHIFT, prot&~PROT_WRITE);
|
||||
#else
|
||||
uint32_t dyn=(my_context->memprot[i]&PROT_DYNAREC);
|
||||
if(dyn && (prot&PROT_WRITE)) // need to remove the write protection from this block
|
||||
mprotect((void*)(i<<DYNAMAP_SHIFT), 1<<DYNAMAP_SHIFT, prot&~PROT_WRITE);
|
||||
my_context->memprot[i] = prot|dyn;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t getProtection(uintptr_t addr)
|
||||
{
|
||||
const uintptr_t idx = (addr>>DYNAMAP_SHIFT);
|
||||
return my_context->memprot[idx];
|
||||
}
|
||||
|
||||
EXPORTDYN
|
||||
void initAllHelpers(box86context_t* context)
|
||||
@ -102,10 +37,6 @@ void initAllHelpers(box86context_t* context)
|
||||
my_context = context;
|
||||
init_pthread_helper();
|
||||
init_signal_helper(context);
|
||||
#ifdef DYNAREC
|
||||
if(box86_dynarec)
|
||||
DynablockEmuMarker(context);
|
||||
#endif
|
||||
inited = 1;
|
||||
}
|
||||
|
||||
@ -166,8 +97,6 @@ box86context_t *NewBox86Context(int argc)
|
||||
|
||||
init_custommem_helper(context);
|
||||
|
||||
context->memprot = (uint32_t*)calloc(DYNAMAP_SIZE, sizeof(uint32_t));
|
||||
|
||||
context->maplib = NewLibrarian(context, 1);
|
||||
context->local_maplib = NewLibrarian(context, 1);
|
||||
context->system = NewBridge();
|
||||
@ -310,8 +239,6 @@ void FreeBox86Context(box86context_t** context)
|
||||
#endif
|
||||
pthread_mutex_destroy(&ctx->mutex_tls);
|
||||
pthread_mutex_destroy(&ctx->mutex_thread);
|
||||
free(ctx->memprot);
|
||||
ctx->memprot = NULL;
|
||||
|
||||
free_neededlib(&ctx->neededlibs);
|
||||
|
||||
|
@ -37,6 +37,7 @@ static kh_dynablocks_t *dblist_oversized; // store the list of oversize
|
||||
static uintptr_t **box86_jumptable = NULL;
|
||||
static uintptr_t *box86_jmptbl_default = NULL;
|
||||
#endif
|
||||
static uint32_t* memprot; // protection flags by 4K block
|
||||
|
||||
typedef struct blocklist_s {
|
||||
void* block;
|
||||
@ -443,14 +444,14 @@ dynablocklist_t* getDB(uintptr_t idx)
|
||||
|
||||
// each dynmap is 64k of size
|
||||
|
||||
void addDBFromAddressRange(uintptr_t addr, uintptr_t size, int nolinker)
|
||||
void addDBFromAddressRange(uintptr_t addr, uintptr_t size)
|
||||
{
|
||||
dynarec_log(LOG_DEBUG, "addDBFromAddressRange %p -> %p\n", (void*)addr, (void*)(addr+size-1));
|
||||
uintptr_t idx = (addr>>DYNAMAP_SHIFT);
|
||||
uintptr_t end = ((addr+size-1)>>DYNAMAP_SHIFT);
|
||||
for (uintptr_t i=idx; i<=end; ++i) {
|
||||
if(!dynmap[i]) {
|
||||
dynmap[i] = NewDynablockList(i<<DYNAMAP_SHIFT, 1<<DYNAMAP_SHIFT, nolinker, 0);
|
||||
dynmap[i] = NewDynablockList(i<<DYNAMAP_SHIFT, 1<<DYNAMAP_SHIFT, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -476,13 +477,10 @@ void cleanDBFromAddressRange(uintptr_t addr, uintptr_t size, int destroy)
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef DYNAREC
|
||||
#ifdef ARM
|
||||
void arm_next(void);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
void addJumpTableIfDefault(void* addr, void* jmp)
|
||||
{
|
||||
@ -511,8 +509,89 @@ uintptr_t getJumpTable()
|
||||
return (uintptr_t)box86_jumptable;
|
||||
}
|
||||
|
||||
uintptr_t getJumpTableAddress(uintptr_t addr)
|
||||
{
|
||||
const uintptr_t idx = ((uintptr_t)addr>>DYNAMAP_SHIFT);
|
||||
if(box86_jumptable[idx] == box86_jmptbl_default) {
|
||||
uintptr_t* tbl = (uintptr_t*)malloc((1<<DYNAMAP_SHIFT)*sizeof(uintptr_t));
|
||||
for(int i=0; i<(1<<DYNAMAP_SHIFT); ++i)
|
||||
tbl[i] = (uintptr_t)arm_next;
|
||||
box86_jumptable[idx] = tbl;
|
||||
}
|
||||
const uintptr_t off = (uintptr_t)addr&((1<<DYNAMAP_SHIFT)-1);
|
||||
return (uintptr_t)&box86_jumptable[idx][off];
|
||||
}
|
||||
|
||||
// Remove the Write flag from an adress range, so DB can be executed
|
||||
// no log, as it can be executed inside a signal handler
|
||||
void protectDB(uintptr_t addr, uintptr_t size)
|
||||
{
|
||||
dynarec_log(LOG_DEBUG, "protectDB %p -> %p\n", (void*)addr, (void*)(addr+size-1));
|
||||
uintptr_t idx = (addr>>DYNAMAP_SHIFT);
|
||||
uintptr_t end = ((addr+size-1)>>DYNAMAP_SHIFT);
|
||||
for (uintptr_t i=idx; i<=end; ++i) {
|
||||
uint32_t prot;
|
||||
do {
|
||||
prot=arm_lock_read_d(&memprot[i]);
|
||||
if(!prot)
|
||||
prot = PROT_READ | PROT_WRITE; // comes from malloc & co, so should not be able to execute
|
||||
} while(arm_lock_write_d(&memprot[i], prot|PROT_DYNAREC));
|
||||
if(!(prot&PROT_DYNAREC))
|
||||
mprotect((void*)(i<<DYNAMAP_SHIFT), 1<<DYNAMAP_SHIFT, prot&~PROT_WRITE);
|
||||
}
|
||||
}
|
||||
|
||||
// Add the Write flag from an adress range, and mark all block as dirty
|
||||
// no log, as it can be executed inside a signal handler
|
||||
void unprotectDB(uintptr_t addr, uintptr_t size)
|
||||
{
|
||||
dynarec_log(LOG_DEBUG, "unprotectDB %p -> %p\n", (void*)addr, (void*)(addr+size-1));
|
||||
uintptr_t idx = (addr>>DYNAMAP_SHIFT);
|
||||
uintptr_t end = ((addr+size-1)>>DYNAMAP_SHIFT);
|
||||
for (uintptr_t i=idx; i<=end; ++i) {
|
||||
uint32_t prot;
|
||||
do {
|
||||
prot=arm_lock_read_d(&memprot[i]);
|
||||
} while(arm_lock_write_d(&memprot[i], prot&~PROT_DYNAREC));
|
||||
if(prot&PROT_DYNAREC) {
|
||||
mprotect((void*)(i<<DYNAMAP_SHIFT), 1<<DYNAMAP_SHIFT, prot&~PROT_DYNAREC);
|
||||
cleanDBFromAddressRange((i<<DYNAMAP_SHIFT), 1<<DYNAMAP_SHIFT, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void updateProtection(uintptr_t addr, uintptr_t size, uint32_t prot)
|
||||
{
|
||||
const uintptr_t idx = (addr>>DYNAMAP_SHIFT);
|
||||
const uintptr_t end = ((addr+size-1)>>DYNAMAP_SHIFT);
|
||||
for (uintptr_t i=idx; i<=end; ++i) {
|
||||
#ifdef DYNAREC
|
||||
uint32_t dyn;
|
||||
do {
|
||||
dyn=arm_lock_read_d(&memprot[i])&PROT_DYNAREC;
|
||||
} while(arm_lock_write_d(&memprot[i], prot|dyn));
|
||||
if(dyn && (prot&PROT_WRITE)) // need to remove the write protection from this block
|
||||
mprotect((void*)(i<<DYNAMAP_SHIFT), 1<<DYNAMAP_SHIFT, prot&~PROT_WRITE);
|
||||
#else
|
||||
uint32_t dyn=(memprot[i]&PROT_DYNAREC);
|
||||
if(dyn && (prot&PROT_WRITE)) // need to remove the write protection from this block
|
||||
mprotect((void*)(i<<DYNAMAP_SHIFT), 1<<DYNAMAP_SHIFT, prot&~PROT_WRITE);
|
||||
memprot[i] = prot|dyn;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t getProtection(uintptr_t addr)
|
||||
{
|
||||
const uintptr_t idx = (addr>>DYNAMAP_SHIFT);
|
||||
return memprot[idx];
|
||||
}
|
||||
|
||||
void init_custommem_helper(box86context_t* ctx)
|
||||
{
|
||||
memprot = (uint32_t*)calloc(DYNAMAP_SIZE, sizeof(uint32_t));
|
||||
#ifdef DYNAREC
|
||||
if(dynmap) // already initialized
|
||||
return;
|
||||
@ -567,11 +646,16 @@ void fini_custommem_helper(box86context_t *ctx)
|
||||
free(mmaplist);
|
||||
free(dynmap);
|
||||
dynmap = NULL;
|
||||
for (int i=0; i<DYNAMAP_SIZE; ++i)
|
||||
if(box86_jumptable[i]!=box86_jmptbl_default)
|
||||
free(box86_jumptable[i]);
|
||||
free(box86_jumptable);
|
||||
free(box86_jmptbl_default);
|
||||
box86_jumptable = NULL;
|
||||
box86_jmptbl_default = NULL;
|
||||
#endif
|
||||
free(memprot);
|
||||
memprot = NULL;
|
||||
for(int i=0; i<n_blocks; ++i)
|
||||
free(p_blocks[i].block);
|
||||
free(p_blocks);
|
||||
|
@ -6,24 +6,8 @@
|
||||
.text
|
||||
.align 4
|
||||
|
||||
.extern UpdateLinkTable
|
||||
.extern LinkNext
|
||||
|
||||
.global arm_linker
|
||||
arm_linker:
|
||||
// emu is r0
|
||||
stm r0, {r4-r12,r14} // put back reg value in emu, including EIP (easier debugging, and safer)
|
||||
// table offset is r1
|
||||
// IP address is r14
|
||||
push {r0, r1, r12, r14}
|
||||
mov r2, r14
|
||||
// call the function
|
||||
bl UpdateLinkTable
|
||||
// return offset is jump address
|
||||
mov r3, r0
|
||||
pop {r0, r1, r12, r14}
|
||||
bx r3
|
||||
|
||||
.global arm_next
|
||||
arm_next:
|
||||
// emu is r0
|
@ -1,19 +0,0 @@
|
||||
//arm try to update linker table for dynarec
|
||||
//and address of table to as 1st parameter
|
||||
//jump addres as second and ip as third
|
||||
// don't retry if failed to write...
|
||||
|
||||
.text
|
||||
.align 4
|
||||
|
||||
.global arm_tableupdate
|
||||
arm_tableupdate:
|
||||
// jump address is r0 and IP address is r1
|
||||
// table offset is r2
|
||||
push {r4, r5}
|
||||
ldrexd r4, r5, [r2]
|
||||
strexd r3, r0, r1, [r2]
|
||||
pop {r4, r5}
|
||||
mov r0, r3
|
||||
bx lr
|
||||
|
@ -38,7 +38,7 @@ uint32_t X31_hash_code(void* addr, int len)
|
||||
return (uint32_t)h;
|
||||
}
|
||||
|
||||
dynablocklist_t* NewDynablockList(uintptr_t text, int textsz, int nolinker, int direct)
|
||||
dynablocklist_t* NewDynablockList(uintptr_t text, int textsz, int direct)
|
||||
{
|
||||
if(!textsz) {
|
||||
printf_log(LOG_NONE, "Error, creating a NULL sized Dynablock\n");
|
||||
@ -47,7 +47,6 @@ dynablocklist_t* NewDynablockList(uintptr_t text, int textsz, int nolinker, int
|
||||
dynablocklist_t* ret = (dynablocklist_t*)calloc(1, sizeof(dynablocklist_t));
|
||||
ret->text = text;
|
||||
ret->textsz = textsz;
|
||||
ret->nolinker = nolinker;
|
||||
if(direct && textsz) {
|
||||
ret->direct = (dynablock_t**)calloc(textsz, sizeof(dynablock_t*));
|
||||
if(!ret->direct) {printf_log(LOG_NONE, "Warning, fail to create direct block for dynablock @%p\n", (void*)text);}
|
||||
@ -58,7 +57,7 @@ dynablocklist_t* NewDynablockList(uintptr_t text, int textsz, int nolinker, int
|
||||
void FreeDynablock(dynablock_t* db)
|
||||
{
|
||||
if(db) {
|
||||
dynarec_log(LOG_DEBUG, "FreeDynablock(%p), db->block=%p x86=%p:%p father=%p, tablesz=%d, with %d son(s) already gone=%d\n", db, db->block, db->x86_addr, db->x86_addr+db->x86_size, db->father, db->tablesz, db->sons_size, db->gone);
|
||||
dynarec_log(LOG_DEBUG, "FreeDynablock(%p), db->block=%p x86=%p:%p father=%p, with %d son(s) already gone=%d\n", db, db->block, db->x86_addr, db->x86_addr+db->x86_size, db->father, db->sons_size, db->gone);
|
||||
if(db->gone)
|
||||
return; // already in the process of deletion!
|
||||
db->done = 0;
|
||||
@ -84,7 +83,6 @@ void FreeDynablock(dynablock_t* db)
|
||||
FreeDynarecMap(db, (uintptr_t)db->block, db->size);
|
||||
}
|
||||
free(db->sons);
|
||||
free(db->table);
|
||||
free(db->instsize);
|
||||
free(db);
|
||||
}
|
||||
@ -96,7 +94,7 @@ void FreeDynablockList(dynablocklist_t** dynablocks)
|
||||
return;
|
||||
if(!*dynablocks)
|
||||
return;
|
||||
dynarec_log(LOG_DEBUG, "Free Direct Blocks %p from Dynablocklist nolinker=%d\n", (*dynablocks)->direct, (*dynablocks)->nolinker);
|
||||
dynarec_log(LOG_DEBUG, "Free Direct Blocks %p from Dynablocklist\n", (*dynablocks)->direct);
|
||||
if((*dynablocks)->direct) {
|
||||
for (int i=0; i<(*dynablocks)->textsz; ++i) {
|
||||
if((*dynablocks)->direct[i] && !(*dynablocks)->direct[i]->father)
|
||||
@ -115,12 +113,10 @@ void MarkDynablock(dynablock_t* db)
|
||||
if(db) {
|
||||
if(db->father)
|
||||
db = db->father; // mark only father
|
||||
if(db->nolinker) {
|
||||
db->need_test = 1; // test only blocks that can be marked (and so deleted)
|
||||
setJumpTableDefault(db->x86_addr);
|
||||
for(int i=0; i<db->sons_size; ++i)
|
||||
setJumpTableDefault(db->sons[i]->x86_addr);
|
||||
}
|
||||
db->need_test = 1; // test only blocks that can be marked (and so deleted)
|
||||
setJumpTableDefault(db->x86_addr);
|
||||
for(int i=0; i<db->sons_size; ++i)
|
||||
setJumpTableDefault(db->sons[i]->x86_addr);
|
||||
}
|
||||
}
|
||||
|
||||
@ -139,9 +135,7 @@ void MarkDynablockList(dynablocklist_t** dynablocks)
|
||||
return;
|
||||
if(!*dynablocks)
|
||||
return;
|
||||
if(!(*dynablocks)->nolinker)
|
||||
return;
|
||||
dynarec_log(LOG_DEBUG, "Marked Blocks from Dynablocklist nolinker=%d %p:0x%x\n", (*dynablocks)->nolinker, (void*)(*dynablocks)->text, (*dynablocks)->textsz);
|
||||
dynarec_log(LOG_DEBUG, "Marked Blocks from Dynablocklist %p:0x%x\n", (void*)(*dynablocks)->text, (*dynablocks)->textsz);
|
||||
dynablock_t* db;
|
||||
if((*dynablocks)->direct) {
|
||||
for (int i=0; i<(*dynablocks)->textsz; ++i) {
|
||||
@ -158,7 +152,7 @@ void ProtectDynablockList(dynablocklist_t** dynablocks)
|
||||
return;
|
||||
if(!*dynablocks)
|
||||
return;
|
||||
dynarec_log(LOG_DEBUG, "Protect Blocks from Dynablocklist nolinker=%d %p:0x%x\n", (*dynablocks)->nolinker, (void*)(*dynablocks)->text, (*dynablocks)->textsz);
|
||||
dynarec_log(LOG_DEBUG, "Protect Blocks from Dynablocklist %p:0x%x\n", (void*)(*dynablocks)->text, (*dynablocks)->textsz);
|
||||
dynablock_t* db;
|
||||
if((*dynablocks)->direct) {
|
||||
for (int i=0; i<(*dynablocks)->textsz; ++i) {
|
||||
@ -193,7 +187,7 @@ void MarkDirectDynablock(dynablocklist_t* dynablocks, uintptr_t addr, uintptr_t
|
||||
{
|
||||
if(!dynablocks)
|
||||
return;
|
||||
if(!dynablocks->nolinker || !dynablocks->direct)
|
||||
if(!dynablocks->direct)
|
||||
return;
|
||||
uintptr_t startdb = dynablocks->text;
|
||||
uintptr_t enddb = startdb + dynablocks->textsz -1;
|
||||
@ -272,8 +266,6 @@ void MarkRangeDynablock(dynablocklist_t* dynablocks, uintptr_t addr, uintptr_t s
|
||||
{
|
||||
if(!dynablocks)
|
||||
return;
|
||||
if(!dynablocks->nolinker)
|
||||
return;
|
||||
if(dynablocks->direct) {
|
||||
MarkDirectDynablock(dynablocks, addr, size);
|
||||
// the blocks check before
|
||||
@ -337,6 +329,7 @@ dynablock_t *AddNewDynablock(dynablocklist_t* dynablocks, uintptr_t addr, int* c
|
||||
dynarec_log(LOG_DUMP, "Ask for DynaRec Block creation @%p\n", (void*)addr);
|
||||
|
||||
block = (dynablock_t*)calloc(1, sizeof(dynablock_t));
|
||||
block->parent = dynablocks;
|
||||
dynablock_t* tmp = (dynablock_t*)arm_lock_storeifnull(&dynablocks->direct[addr-dynablocks->text], block);
|
||||
if(tmp != block) {
|
||||
// a block appeard!
|
||||
@ -345,8 +338,6 @@ dynablock_t *AddNewDynablock(dynablocklist_t* dynablocks, uintptr_t addr, int* c
|
||||
return tmp;
|
||||
}
|
||||
|
||||
block->parent = dynablocks;
|
||||
|
||||
*created = 1;
|
||||
return block;
|
||||
}
|
||||
@ -411,8 +402,7 @@ static dynablock_t* internalDBGetBlock(x86emu_t* emu, uintptr_t addr, uintptr_t
|
||||
dblist->maxsz = blocksz;
|
||||
}
|
||||
}
|
||||
if(block->parent->nolinker)
|
||||
protectDB((uintptr_t)block->x86_addr, block->x86_size);
|
||||
protectDB((uintptr_t)block->x86_addr, block->x86_size);
|
||||
// fill-in jumptable
|
||||
addJumpTableIfDefault(block->x86_addr, block->block);
|
||||
for(int i=0; i<block->sons_size; ++i)
|
||||
@ -429,7 +419,7 @@ dynablock_t* DBGetBlock(x86emu_t* emu, uintptr_t addr, int create, dynablock_t**
|
||||
dynablock_t *db = internalDBGetBlock(emu, addr, addr, create, *current);
|
||||
if(db && (db->need_test || (db->father && db->father->need_test))) {
|
||||
dynablock_t *father = db->father?db->father:db;
|
||||
uint32_t hash = father->nolinker?X31_hash_code(father->x86_addr, father->x86_size):0;
|
||||
uint32_t hash = X31_hash_code(father->x86_addr, father->x86_size);
|
||||
if(hash!=father->hash) {
|
||||
dynarec_log(LOG_DEBUG, "Invalidating block %p from %p:%p (hash:%X/%X) with %d son(s) for %p\n", father, father->x86_addr, father->x86_addr+father->x86_size, hash, father->hash, father->sons_size, (void*)addr);
|
||||
// no more current if it gets invalidated too
|
||||
@ -441,8 +431,7 @@ dynablock_t* DBGetBlock(x86emu_t* emu, uintptr_t addr, int create, dynablock_t**
|
||||
db = internalDBGetBlock(emu, addr, addr, create, *current);
|
||||
} else {
|
||||
father->need_test = 0;
|
||||
if(father->nolinker)
|
||||
protectDB((uintptr_t)father->x86_addr, father->x86_size);
|
||||
protectDB((uintptr_t)father->x86_addr, father->x86_size);
|
||||
}
|
||||
}
|
||||
return db;
|
||||
@ -455,7 +444,7 @@ dynablock_t* DBAlternateBlock(x86emu_t* emu, uintptr_t addr, uintptr_t filladdr)
|
||||
dynablock_t *db = internalDBGetBlock(emu, addr, filladdr, create, NULL);
|
||||
if(db && (db->need_test || (db->father && db->father->need_test))) {
|
||||
dynablock_t *father = db->father?db->father:db;
|
||||
uint32_t hash = father->nolinker?X31_hash_code(father->x86_addr, father->x86_size):0;
|
||||
uint32_t hash = X31_hash_code(father->x86_addr, father->x86_size);
|
||||
if(hash!=father->hash) {
|
||||
dynarec_log(LOG_DEBUG, "Invalidating alt block %p from %p:%p (hash:%X/%X) with %d son(s) for %p\n", father, father->x86_addr, father->x86_addr+father->x86_size, hash, father->hash, father->sons_size, (void*)addr);
|
||||
// Free father, it's now invalid!
|
||||
@ -464,8 +453,7 @@ dynablock_t* DBAlternateBlock(x86emu_t* emu, uintptr_t addr, uintptr_t filladdr)
|
||||
db = internalDBGetBlock(emu, addr, filladdr, create, NULL);
|
||||
} else {
|
||||
father->need_test = 0;
|
||||
if(father->nolinker)
|
||||
protectDB((uintptr_t)father->x86_addr, father->x86_size);
|
||||
protectDB((uintptr_t)father->x86_addr, father->x86_size);
|
||||
}
|
||||
}
|
||||
return db;
|
||||
|
@ -15,12 +15,10 @@ typedef struct dynablock_s {
|
||||
void* x86_addr;
|
||||
uintptr_t x86_size;
|
||||
uint32_t hash;
|
||||
uintptr_t* table;
|
||||
int tablesz;
|
||||
uint8_t need_test;
|
||||
uint8_t done;
|
||||
uint8_t gone;
|
||||
uint8_t nolinker;
|
||||
uint8_t dummy;
|
||||
int isize;
|
||||
dynablock_t** sons; // sons (kind-of dummy dynablock...)
|
||||
int sons_size;
|
||||
@ -32,7 +30,6 @@ typedef struct dynablocklist_s {
|
||||
uintptr_t text;
|
||||
int textsz;
|
||||
int maxsz; // maxblock size (for this block or previous block)
|
||||
int nolinker; // in case this dynablock can be deleted
|
||||
dynablock_t** direct; // direct mapping (waste of space, so the array is created at first write)
|
||||
} dynablocklist_t;
|
||||
|
||||
|
@ -25,66 +25,9 @@
|
||||
void arm_prolog(x86emu_t* emu, void* addr) EXPORTDYN;
|
||||
void arm_epilog() EXPORTDYN;
|
||||
void arm_epilog_fast() EXPORTDYN;
|
||||
void arm_linker() EXPORTDYN;
|
||||
int arm_tableupdate(void* jump, uintptr_t addr, void** table) EXPORTDYN;
|
||||
#endif
|
||||
|
||||
void tableupdate(void* jumpto, uintptr_t ref, void** table)
|
||||
{
|
||||
#ifdef ARM
|
||||
if(arm_tableupdate(jumpto, ref, table))
|
||||
#endif
|
||||
{
|
||||
table[0] = jumpto;
|
||||
table[1] = (void*)ref;
|
||||
}
|
||||
}
|
||||
|
||||
void resettable(void** table)
|
||||
{
|
||||
void* p = table[1];
|
||||
#ifdef ARM
|
||||
tableupdate(arm_linker, (uintptr_t)p, table);
|
||||
#endif
|
||||
//table[2] = own_dynablock // unchanged
|
||||
table[3] = NULL; // removed "linked" information
|
||||
}
|
||||
|
||||
#ifdef DYNAREC
|
||||
void* UpdateLinkTable(x86emu_t* emu, void** table, uintptr_t addr)
|
||||
{
|
||||
dynablock_t* current = (dynablock_t*)table[2];
|
||||
if(current->father)
|
||||
current = current->father;
|
||||
void * jblock;
|
||||
dynablock_t* block = DBGetBlock(emu, addr, 1, ¤t);
|
||||
if(!current) { // current has been invalidated, stop running it...
|
||||
//dynarec_log(LOG_DEBUG, "--- Current invalidated while linking.\n");
|
||||
return arm_epilog_fast;
|
||||
}
|
||||
if(!block) {
|
||||
// no block, let link table as is...
|
||||
//tableupdate(arm_epilog, addr, table);
|
||||
return arm_epilog_fast;
|
||||
}
|
||||
if(!block->done) {
|
||||
// not finished yet... leave linker
|
||||
//tableupdate(arm_linker, addr, table);
|
||||
return arm_epilog_fast;
|
||||
}
|
||||
if(!(jblock=block->block)) {
|
||||
// null block, but done: go to epilog, no linker here
|
||||
tableupdate(arm_epilog, addr, table);
|
||||
return arm_epilog_fast;
|
||||
}
|
||||
//dynablock_t *father = block->father?block->father:block;
|
||||
if(!block->parent->nolinker) {
|
||||
//dynarec_log(LOG_DEBUG, "--- Linking %p/%p to %p (table=%p[%p/%p/%p/%p])\n", block, block->block, current, table, table[0], table[1], table[2], table[3]);
|
||||
// only update block if linker is allowed
|
||||
tableupdate(jblock, addr, table);
|
||||
}
|
||||
return jblock;
|
||||
}
|
||||
void* LinkNext(x86emu_t* emu, uintptr_t addr)
|
||||
{
|
||||
dynablock_t* current = NULL;
|
||||
@ -145,14 +88,14 @@ void DynaCall(x86emu_t* emu, uintptr_t addr)
|
||||
dynablock_t* current = NULL;
|
||||
while(!emu->quit) {
|
||||
block = DBGetBlock(emu, R_EIP, 1, ¤t);
|
||||
current = (block && !block->parent->nolinker)?block:NULL;
|
||||
current = block;
|
||||
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, "Calling Interpretor @%p, emu=%p\n", (void*)R_EIP, emu);
|
||||
Run(emu, 1);
|
||||
} else {
|
||||
dynarec_log(LOG_DEBUG, "Calling DynaRec Block @%p (%p) of %d x86 instructions (nolinker=%d, father=%p) emu=%p\n", (void*)R_EIP, block->block, block->isize ,block->parent->nolinker, block->father, emu);
|
||||
dynarec_log(LOG_DEBUG, "Calling DynaRec Block @%p (%p) of %d x86 instructions (father=%p) emu=%p\n", (void*)R_EIP, block->block, block->isize ,block->father, emu);
|
||||
CHECK_FLAGS(emu);
|
||||
// block is here, let's run it!
|
||||
#ifdef ARM
|
||||
@ -220,14 +163,14 @@ int DynaRun(x86emu_t* emu)
|
||||
dynablock_t* current = NULL;
|
||||
while(!emu->quit) {
|
||||
block = DBGetBlock(emu, R_EIP, 1, ¤t);
|
||||
current = (block && !block->parent->nolinker)?block:NULL;
|
||||
current = block;
|
||||
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, "Running Interpretor @%p, emu=%p\n", (void*)R_EIP, emu);
|
||||
Run(emu, 1);
|
||||
} else {
|
||||
dynarec_log(LOG_DEBUG, "Running DynaRec Block @%p (%p) of %d x86 insts (nolinker=%d, father=%p) emu=%p\n", (void*)R_EIP, block->block, block->isize, block->parent->nolinker, block->father, emu);
|
||||
dynarec_log(LOG_DEBUG, "Running DynaRec Block @%p (%p) of %d x86 insts (father=%p) emu=%p\n", (void*)R_EIP, block->block, block->isize, block->father, emu);
|
||||
// block is here, let's run it!
|
||||
#ifdef ARM
|
||||
arm_prolog(emu, block->block);
|
||||
|
@ -313,7 +313,6 @@ void arm_pass3(dynarec_arm_t* dyn, uintptr_t addr);
|
||||
void* FillBlock(dynablock_t* block, uintptr_t addr) {
|
||||
// init the helper
|
||||
dynarec_arm_t helper = {0};
|
||||
helper.nolinker = box86_dynarec_linker?(block->parent->nolinker):1;
|
||||
helper.start = addr;
|
||||
arm_pass0(&helper, addr);
|
||||
if(!helper.size) {
|
||||
@ -366,9 +365,6 @@ void* FillBlock(dynablock_t* block, uintptr_t addr) {
|
||||
}
|
||||
helper.block = p;
|
||||
helper.arm_start = (uintptr_t)p;
|
||||
helper.tablesz = helper.tablei;
|
||||
if(helper.tablesz)
|
||||
helper.table = (uintptr_t*)calloc(helper.tablesz, sizeof(uintptr_t));
|
||||
if(helper.sons_size) {
|
||||
helper.sons_x86 = (uintptr_t*)calloc(helper.sons_size, sizeof(uintptr_t));
|
||||
helper.sons_arm = (void**)calloc(helper.sons_size, sizeof(void*));
|
||||
@ -409,20 +405,15 @@ void* FillBlock(dynablock_t* block, uintptr_t addr) {
|
||||
// ok, free the helper now
|
||||
free(helper.insts);
|
||||
free(helper.next);
|
||||
block->table = helper.table;
|
||||
block->tablesz = helper.tablesz;
|
||||
for (int i=0; i<helper.tablesz/4; ++i)
|
||||
block->table[i*4+2] = (uintptr_t)block;
|
||||
block->size = sz;
|
||||
block->isize = helper.size;
|
||||
block->block = p;
|
||||
block->nolinker = helper.nolinker;
|
||||
block->need_test = 0;
|
||||
//block->x86_addr = (void*)start;
|
||||
block->x86_size = end-start;
|
||||
if(box86_dynarec_largest<block->x86_size)
|
||||
box86_dynarec_largest = block->x86_size;
|
||||
block->hash = (helper.nolinker)?X31_hash_code(block->x86_addr, block->x86_size):0;
|
||||
block->hash = X31_hash_code(block->x86_addr, block->x86_size);
|
||||
// fill sons if any
|
||||
dynablock_t** sons = NULL;
|
||||
int sons_size = 0;
|
||||
|
@ -696,7 +696,7 @@ uintptr_t dynarec00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
/* out of the block */ \
|
||||
i32 = dyn->insts[ninst+1].address-(dyn->arm_size+8); \
|
||||
Bcond(NO, i32); \
|
||||
jump_to_linker(dyn, addr+i8, 0, ninst); \
|
||||
jump_to_next(dyn, addr+i8, 0, ninst); \
|
||||
} else { \
|
||||
/* inside the block */ \
|
||||
i32 = dyn->insts[dyn->insts[ninst].x86.jmp_insts].address-(dyn->arm_size+8); \
|
||||
@ -1982,7 +1982,7 @@ uintptr_t dynarec00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
/* out of the block */ \
|
||||
i32 = dyn->insts[ninst+1].address-(dyn->arm_size+8); \
|
||||
Bcond(NO, i32); \
|
||||
jump_to_linker(dyn, addr+i8, 0, ninst); \
|
||||
jump_to_next(dyn, addr+i8, 0, ninst); \
|
||||
} else { \
|
||||
/* inside the block */ \
|
||||
i32 = dyn->insts[dyn->insts[ninst].x86.jmp_insts].address-(dyn->arm_size+8); \
|
||||
@ -2103,9 +2103,7 @@ uintptr_t dynarec00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
// regular call
|
||||
BARRIER(1);
|
||||
BARRIER_NEXT(1);
|
||||
if(!dyn->nolinker && (!dyn->insts || ninst!=dyn->size-1)) {
|
||||
//cstatck_push put addr in x2, don't need to put it again
|
||||
} else {
|
||||
if(!dyn->insts || ninst==dyn->size-1) {
|
||||
*need_epilog = 0;
|
||||
*ok = 0;
|
||||
}
|
||||
@ -2116,7 +2114,7 @@ uintptr_t dynarec00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
LDR_IMM9(x14, x14, 0);
|
||||
jump_to_next(dyn, 0, x14, ninst);
|
||||
} else
|
||||
jump_to_linker(dyn, addr+i32, 0, ninst);
|
||||
jump_to_next(dyn, addr+i32, 0, ninst);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
@ -2134,7 +2132,7 @@ uintptr_t dynarec00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
if(dyn->insts) {
|
||||
PASS2IF(dyn->insts[ninst].x86.jmp_insts==-1, 1) {
|
||||
// out of the block
|
||||
jump_to_linker(dyn, addr+i32, 0, ninst);
|
||||
jump_to_next(dyn, addr+i32, 0, ninst);
|
||||
} else {
|
||||
// inside the block
|
||||
tmp = dyn->insts[dyn->insts[ninst].x86.jmp_insts].address-(dyn->arm_size+8);
|
||||
@ -2637,8 +2635,7 @@ uintptr_t dynarec00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
GETEDH(xEIP);
|
||||
BARRIER(1);
|
||||
BARRIER_NEXT(1);
|
||||
if(!dyn->nolinker && (!dyn->insts || ninst!=dyn->size-1)) {
|
||||
} else {
|
||||
if(!dyn->insts || ninst==dyn->size-1) {
|
||||
*need_epilog = 0;
|
||||
*ok = 0;
|
||||
}
|
||||
|
@ -1140,7 +1140,7 @@ uintptr_t dynarec0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
/* out of the block */ \
|
||||
i32 = dyn->insts[ninst+1].address-(dyn->arm_size+8); \
|
||||
Bcond(NO, i32); \
|
||||
jump_to_linker(dyn, addr+i32_, 0, ninst); \
|
||||
jump_to_next(dyn, addr+i32_, 0, ninst); \
|
||||
} else { \
|
||||
/* inside the block */ \
|
||||
i32 = dyn->insts[dyn->insts[ninst].x86.jmp_insts].address-(dyn->arm_size+8); \
|
||||
|
@ -291,14 +291,14 @@ uintptr_t dynarecFS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
}
|
||||
BARRIER(1);
|
||||
BARRIER_NEXT(1);
|
||||
if(!dyn->nolinker && (!dyn->insts || ninst!=dyn->size-1)) {
|
||||
if(!dyn->insts || ninst!=dyn->size-1) {
|
||||
} else {
|
||||
*need_epilog = 0;
|
||||
*ok = 0;
|
||||
}
|
||||
MOV32(x2, addr);
|
||||
PUSH1(x2);
|
||||
jump_to_linker(dyn, 0, xEIP, ninst); // smart linker
|
||||
jump_to_next(dyn, 0, xEIP, ninst);
|
||||
break;
|
||||
case 6: // Push Ed
|
||||
INST_NAME("PUSH FS:Ed");
|
||||
|
@ -140,7 +140,7 @@ uintptr_t dynarec67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
/* out of the block */ \
|
||||
i32 = dyn->insts[ninst+1].address-(dyn->arm_size+8); \
|
||||
Bcond(NO, i32); \
|
||||
jump_to_linker(dyn, addr+i8, 0, ninst); \
|
||||
jump_to_next(dyn, addr+i8, 0, ninst); \
|
||||
} else { \
|
||||
/* inside the block */ \
|
||||
i32 = dyn->insts[dyn->insts[ninst].x86.jmp_insts].address-(dyn->arm_size+8); \
|
||||
|
@ -244,86 +244,27 @@ void jump_to_epilog(dynarec_arm_t* dyn, uintptr_t ip, int reg, int ninst)
|
||||
BX(2);
|
||||
}
|
||||
|
||||
void jump_to_linker(dynarec_arm_t* dyn, uintptr_t ip, int reg, int ninst)
|
||||
{
|
||||
MESSAGE(LOG_DUMP, "Jump to linker (#%d) nolinker=%d\n", dyn->tablei, dyn->nolinker);
|
||||
#if 0
|
||||
int j32;
|
||||
MAYUSE(j32);
|
||||
#endif
|
||||
if(dyn->nolinker==2) {
|
||||
jump_to_epilog(dyn, ip, reg, ninst);
|
||||
} else {
|
||||
if(reg) {
|
||||
if(reg!=xEIP) {
|
||||
MOV_REG(xEIP, reg);
|
||||
}
|
||||
} else {
|
||||
MOV32_(xEIP, ip);
|
||||
}
|
||||
uintptr_t* table = 0;
|
||||
if(dyn->tablesz) {
|
||||
table = &dyn->table[dyn->tablei];
|
||||
table[0] = (uintptr_t)arm_linker;
|
||||
table[1] = ip;
|
||||
}
|
||||
dyn->tablei+=4; // smart linker or not, we keep table correctly alligned for LDREXD/STREXD access
|
||||
MOV32_(x1, (uintptr_t)table);
|
||||
// TODO: This is not thread safe.
|
||||
if(!ip) { // no IP, jump address in a reg, so need smart linker
|
||||
#if 0
|
||||
//version thread safe
|
||||
MARK;
|
||||
LDREXD(x2, x1); // load dest address in x2 and planned ip in x3
|
||||
CMPS_REG_LSL_IMM5(xEIP, x3, 0);
|
||||
BXcond(cEQ, x2);
|
||||
MOV32_(x2, (uintptr_t)arm_linker);
|
||||
MOV_REG(x3, x14);
|
||||
STREXD(x14, x2, x1); // nope, putting back linker & IP in place
|
||||
// x14 now contain success / falure for write
|
||||
CMPS_IMM8(x14, 1);
|
||||
MOV_REG(x14, x3); // put back IP in place...
|
||||
B_MARK(cEQ);
|
||||
BX(x2); // go to linker
|
||||
#else
|
||||
// not thread safe, is that still ok?
|
||||
LDRD_IMM8(x2, x1, 0);
|
||||
CMPS_REG_LSL_IMM5(xEIP, x3, 0);
|
||||
BXcond(cEQ, x2);
|
||||
MOV32_(x2, (uintptr_t)arm_linker);
|
||||
MOV_REG(x3, x14);
|
||||
STRD_IMM8(x2, x1, 0);
|
||||
BX(x2);
|
||||
#endif
|
||||
} else {
|
||||
LDR_IMM9(x2, x1, 0);
|
||||
BX(x2); // jump
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void jump_to_next(dynarec_arm_t* dyn, uintptr_t ip, int reg, int ninst)
|
||||
{
|
||||
MESSAGE(LOG_DUMP, "Jump to next nolinker=%d\n", dyn->nolinker);
|
||||
MESSAGE(LOG_DUMP, "Jump to next\n");
|
||||
|
||||
if(dyn->nolinker==2) {
|
||||
jump_to_epilog(dyn, ip, reg, ninst);
|
||||
} else {
|
||||
if(reg) {
|
||||
if(reg!=xEIP) {
|
||||
MOV_REG(xEIP, reg);
|
||||
}
|
||||
} else {
|
||||
MOV32_(xEIP, ip);
|
||||
if(reg) {
|
||||
if(reg!=xEIP) {
|
||||
MOV_REG(xEIP, reg);
|
||||
}
|
||||
MOV32(x2, getJumpTable());
|
||||
MOV_REG_LSR_IMM5(x3, xEIP, DYNAMAP_SHIFT);
|
||||
LDR_REG_LSL_IMM5(x2, x2, x3, 2); // shiftsizeof(uintptr_t)
|
||||
UBFX(x3, xEIP, 0, DYNAMAP_SHIFT);
|
||||
LDR_REG_LSL_IMM5(x2, x2, x3, 2); // shiftsizeof(uintptr_t)
|
||||
MOV_REG(x1, xEIP);
|
||||
BX(x2);
|
||||
} else {
|
||||
uintptr_t p = getJumpTableAddress(ip);
|
||||
MOV32(x2, p);
|
||||
MOV32_(xEIP, ip);
|
||||
LDR_IMM9(x2, x2, 0);
|
||||
}
|
||||
MOV_REG(x1, xEIP);
|
||||
BX(x2);
|
||||
}
|
||||
|
||||
void ret_to_epilog(dynarec_arm_t* dyn, int ninst)
|
||||
|
@ -331,7 +331,6 @@
|
||||
#endif
|
||||
|
||||
void arm_epilog();
|
||||
void* arm_linker(x86emu_t* emu, void** table, uintptr_t addr);
|
||||
void* arm_next(x86emu_t* emu, uintptr_t addr);
|
||||
|
||||
#ifndef STEPNAME
|
||||
@ -364,7 +363,6 @@ void* arm_next(x86emu_t* emu, uintptr_t addr);
|
||||
#define geted STEPNAME(geted_)
|
||||
#define geted16 STEPNAME(geted16_)
|
||||
#define jump_to_epilog STEPNAME(jump_to_epilog_)
|
||||
#define jump_to_linker STEPNAME(jump_to_linker_)
|
||||
#define jump_to_next STEPNAME(jump_to_next_)
|
||||
#define ret_to_epilog STEPNAME(ret_to_epilog_)
|
||||
#define retn_to_epilog STEPNAME(retn_to_epilog_)
|
||||
@ -478,7 +476,6 @@ uintptr_t geted16(dynarec_arm_t* dyn, uintptr_t addr, int ninst, uint8_t nextop,
|
||||
|
||||
// generic x86 helper
|
||||
void jump_to_epilog(dynarec_arm_t* dyn, uintptr_t ip, int reg, int ninst);
|
||||
void jump_to_linker(dynarec_arm_t* dyn, uintptr_t ip, int reg, int ninst);
|
||||
void jump_to_next(dynarec_arm_t* dyn, uintptr_t ip, int reg, int ninst);
|
||||
void ret_to_epilog(dynarec_arm_t* dyn, int ninst);
|
||||
void retn_to_epilog(dynarec_arm_t* dyn, int ninst, int n);
|
||||
|
@ -19,6 +19,7 @@
|
||||
#include "arm_printer.h"
|
||||
#include "dynarec_arm_functions.h"
|
||||
#include "dynarec_arm_helper.h"
|
||||
#include "custommem.h"
|
||||
|
||||
#ifndef STEP
|
||||
#error No STEP defined
|
||||
@ -30,7 +31,6 @@ void arm_pass(dynarec_arm_t* dyn, uintptr_t addr)
|
||||
int ninst = 0;
|
||||
uintptr_t ip = addr;
|
||||
int need_epilog = 1;
|
||||
dyn->tablei = 0;
|
||||
dyn->sons_size = 0;
|
||||
// Clean up (because there are multiple passes)
|
||||
dyn->state_flags = 0;
|
||||
@ -76,18 +76,19 @@ void arm_pass(dynarec_arm_t* dyn, uintptr_t addr)
|
||||
if(!ok && !need_epilog && dyn->insts && (addr < (dyn->start+dyn->isize))) {
|
||||
ok = 1;
|
||||
}
|
||||
if(!ok && !need_epilog && !dyn->insts) { // check if need to continue
|
||||
uintptr_t next = get_closest_next(dyn, addr);
|
||||
if(next && (
|
||||
(((next-addr)<15) && is_nops(dyn, addr, next-addr))
|
||||
||(((next-addr)<30) && is_instructions(dyn, addr, next-addr)) ))
|
||||
{
|
||||
dynarec_log(LOG_DEBUG, "Extend block %p, %p -> %p (ninst=%d)\n", dyn, (void*)addr, (void*)next, ninst);
|
||||
ok = 1;
|
||||
} else if(next && (next-addr)<30) {
|
||||
dynarec_log(LOG_DEBUG, "Cannot extend block %p -> %p (%02X %02X %02X %02X %02X %02X %02X %02x)\n", (void*)addr, (void*)next, PK(0), PK(1), PK(2), PK(3), PK(4), PK(5), PK(6), PK(7));
|
||||
if(!ok && !need_epilog && !dyn->insts && getProtection(addr+3))
|
||||
if(*(uint32_t*)addr!=0) { // check if need to continue (but is next 4 bytes are 0, stop)
|
||||
uintptr_t next = get_closest_next(dyn, addr);
|
||||
if(next && (
|
||||
(((next-addr)<15) && is_nops(dyn, addr, next-addr))
|
||||
||(((next-addr)<30) && is_instructions(dyn, addr, next-addr)) ))
|
||||
{
|
||||
dynarec_log(LOG_DEBUG, "Extend block %p, %p -> %p (ninst=%d)\n", dyn, (void*)addr, (void*)next, ninst);
|
||||
ok = 1;
|
||||
} else if(next && (next-addr)<30) {
|
||||
dynarec_log(LOG_DEBUG, "Cannot extend block %p -> %p (%02X %02X %02X %02X %02X %02X %02X %02x)\n", (void*)addr, (void*)next, PK(0), PK(1), PK(2), PK(3), PK(4), PK(5), PK(6), PK(7));
|
||||
}
|
||||
}
|
||||
}
|
||||
if(ok<0) {ok = 0; need_epilog=1;}
|
||||
++ninst;
|
||||
}
|
||||
|
@ -29,9 +29,6 @@ typedef struct dynarec_arm_s {
|
||||
void* block; // memory pointer where next instruction is emited
|
||||
uintptr_t arm_start; // start of the arm code
|
||||
int arm_size; // size of emitted arm code
|
||||
uintptr_t* table; // jump table
|
||||
int tablesz; // size of the jump table
|
||||
int tablei; // index
|
||||
int state_flags;// actual state for on-demand flags
|
||||
int x87cache[8];// cache status for the 8 x87 register behind the fpu stack
|
||||
int x87reg[8]; // reg used for x87cache entry
|
||||
@ -42,7 +39,6 @@ typedef struct dynarec_arm_s {
|
||||
int fpu_scratch;// scratch counter
|
||||
int fpu_extra_qscratch; // some opcode need an extra quad scratch register
|
||||
int fpu_reg; // x87/sse/mmx reg counter
|
||||
int nolinker; // disable use of (smart) linker in the block
|
||||
int dfnone; // if defered flags is already set to df_none
|
||||
uintptr_t* next; // variable array of "next" jump address
|
||||
int next_sz;
|
||||
|
@ -31,7 +31,5 @@ typedef struct instruction_x86_s {
|
||||
} instruction_x86_t;
|
||||
|
||||
void printf_x86_instruction(zydis_dec_t* dec, instruction_x86_t* inst, const char* name);
|
||||
void tableupdate(void* jumpto, uintptr_t ref, void** table);
|
||||
void resettable(void** table);
|
||||
|
||||
#endif //__DYNAREC_PRIVATE_H_
|
||||
|
@ -271,7 +271,7 @@ int LoadElfMemory(FILE* f, box86context_t* context, elfheader_t* head)
|
||||
#ifdef DYNAREC
|
||||
if(e->p_flags & PF_X) {
|
||||
dynarec_log(LOG_DEBUG, "Add ELF eXecutable Memory %p:%p\n", dest, (void*)e->p_memsz);
|
||||
addDBFromAddressRange((uintptr_t)dest, e->p_memsz, 0);
|
||||
addDBFromAddressRange((uintptr_t)dest, e->p_memsz);
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -1011,7 +1011,7 @@ dynablocklist_t* GetDynablocksFromAddress(box86context_t *context, uintptr_t add
|
||||
return ret;
|
||||
}*/
|
||||
if(box86_dynarec_forced) {
|
||||
addDBFromAddressRange(addr, 1, 1);
|
||||
addDBFromAddressRange(addr, 1);
|
||||
return getDB(addr>>DYNAMAP_SHIFT);
|
||||
}
|
||||
//check if address is in an elf... if yes, grant a block (should I warn)
|
||||
|
@ -15,6 +15,7 @@
|
||||
#include "x86run.h"
|
||||
#include "x86run_private.h"
|
||||
#include "callback.h"
|
||||
#include "bridge.h"
|
||||
#ifdef DYNAREC
|
||||
#include "custommem.h"
|
||||
#endif
|
||||
@ -37,22 +38,15 @@ static uint32_t x86emu_parity_tab[8] =
|
||||
0x69969669,
|
||||
};
|
||||
|
||||
static uint8_t EndEmuMarker[] = {0xcc, 'S', 'C', 0, 0, 0, 0};
|
||||
#ifdef DYNAREC
|
||||
void DynablockEmuMarker(box86context_t* context)
|
||||
{
|
||||
dynarec_log(LOG_DUMP, "Create bridge memory map for PushExit\n");
|
||||
addDBFromAddressRange((uintptr_t)&EndEmuMarker[0], sizeof(EndEmuMarker), 0);
|
||||
}
|
||||
#endif
|
||||
void PushExit(x86emu_t* emu)
|
||||
{
|
||||
Push(emu, (uint32_t)&EndEmuMarker);
|
||||
uintptr_t endMarker = AddCheckBridge(my_context->system, NULL, NULL, 0);
|
||||
Push(emu, endMarker);
|
||||
}
|
||||
|
||||
void* GetExit()
|
||||
{
|
||||
return &EndEmuMarker;
|
||||
return (void*)AddCheckBridge(my_context->system, NULL, NULL, 0);
|
||||
}
|
||||
|
||||
static void internalX86Setup(x86emu_t* emu, box86context_t *context, uintptr_t start, uintptr_t stack, int stacksize, int ownstack)
|
||||
|
@ -61,7 +61,6 @@ typedef struct base_segment_s {
|
||||
} base_segment_t;
|
||||
|
||||
typedef struct box86context_s {
|
||||
uint32_t* memprot; // protection flags by 4K block
|
||||
path_collection_t box86_path; // PATH env. variable
|
||||
path_collection_t box86_ld_lib; // LD_LIBRARY_PATH env. variable
|
||||
|
||||
@ -206,14 +205,6 @@ int AddElfHeader(box86context_t* ctx, elfheader_t* head);
|
||||
// return the tlsbase (negative) for the new TLS partition created (no partition index is stored in the context)
|
||||
int AddTLSPartition(box86context_t* context, int tlssize);
|
||||
|
||||
#define PROT_DYNAREC 0x10000
|
||||
void updateProtection(uintptr_t addr, uintptr_t size, uint32_t prot);
|
||||
uint32_t getProtection(uintptr_t addr);
|
||||
#ifdef DYNAREC
|
||||
void protectDB(uintptr_t addr, uintptr_t size);
|
||||
void unprotectDB(uintptr_t addr, uintptr_t size);
|
||||
#endif
|
||||
|
||||
// defined in fact in threads.c
|
||||
void thread_set_emu(x86emu_t* emu);
|
||||
x86emu_t* thread_get_emu();
|
||||
|
@ -23,15 +23,25 @@ typedef struct dynablocklist_s dynablocklist_t;
|
||||
uintptr_t AllocDynarecMap(dynablock_t* db, int size);
|
||||
void FreeDynarecMap(dynablock_t* db, uintptr_t addr, uint32_t size);
|
||||
|
||||
void addDBFromAddressRange(uintptr_t addr, uintptr_t size, int nolinker);
|
||||
void addDBFromAddressRange(uintptr_t addr, uintptr_t size);
|
||||
void cleanDBFromAddressRange(uintptr_t addr, uintptr_t size, int destroy);
|
||||
|
||||
dynablocklist_t* getDB(uintptr_t idx);
|
||||
void addJumpTableIfDefault(void* addr, void* jmp);
|
||||
void setJumpTableDefault(void* addr);
|
||||
uintptr_t getJumpTable();
|
||||
uintptr_t getJumpTableAddress(uintptr_t addr);
|
||||
#endif
|
||||
|
||||
#define PROT_DYNAREC 0x10000
|
||||
void updateProtection(uintptr_t addr, uintptr_t size, uint32_t prot);
|
||||
uint32_t getProtection(uintptr_t addr);
|
||||
#ifdef DYNAREC
|
||||
void protectDB(uintptr_t addr, uintptr_t size);
|
||||
void unprotectDB(uintptr_t addr, uintptr_t size);
|
||||
#endif
|
||||
|
||||
|
||||
void init_custommem_helper(box86context_t* ctx);
|
||||
void fini_custommem_helper(box86context_t* ctx);
|
||||
|
||||
|
@ -9,12 +9,10 @@ extern int box86_dynarec;
|
||||
extern int box86_pagesize;
|
||||
#ifdef DYNAREC
|
||||
extern int box86_dynarec_dump;
|
||||
extern int box86_dynarec_linker;
|
||||
extern int box86_dynarec_trace;
|
||||
extern int box86_dynarec_forced;
|
||||
extern int box86_dynarec_largest;
|
||||
extern int box86_dynarec_smc;
|
||||
extern int box86_dynarec_safemmap;
|
||||
#ifdef ARM
|
||||
extern int arm_vfp; // vfp version (3 or 4), with 32 registers is mendatory
|
||||
extern int arm_swap;
|
||||
|
@ -7,7 +7,7 @@ typedef struct dynablocklist_s dynablocklist_t;
|
||||
typedef struct kh_dynablocks_s kh_dynablocks_t;
|
||||
|
||||
uint32_t X31_hash_code(void* addr, int len);
|
||||
dynablocklist_t* NewDynablockList(uintptr_t text, int textsz, int nolinker, int direct);
|
||||
dynablocklist_t* NewDynablockList(uintptr_t text, int textsz, int direct);
|
||||
void FreeDynablockList(dynablocklist_t** dynablocks);
|
||||
void FreeDynablock(dynablock_t* db);
|
||||
void MarkDynablock(dynablock_t* db);
|
||||
|
@ -33,9 +33,6 @@ void ResetSegmentsCache(x86emu_t *emu);
|
||||
const char* DumpCPURegs(x86emu_t* emu, uintptr_t ip);
|
||||
|
||||
void StopEmu(x86emu_t* emu, const char* reason);
|
||||
#ifdef DYNAREC
|
||||
void DynablockEmuMarker(box86context_t* context);
|
||||
#endif
|
||||
void PushExit(x86emu_t* emu);
|
||||
void* GetExit();
|
||||
void EmuCall(x86emu_t* emu, uintptr_t addr);
|
||||
|
@ -618,9 +618,6 @@ void my_box86signalhandler(int32_t sig, siginfo_t* info, void * ucntx)
|
||||
dynarec_log(LOG_NONE, "Warning: Access to protected %p from %p, inside same dynablock\n", addr, pc);
|
||||
}
|
||||
}
|
||||
if(db_addr && !db_addr->nolinker) {
|
||||
dynarec_log(LOG_NONE, "Warning: Access to protected %p from %p, inside a dynablock with linker\n", addr, pc);
|
||||
}
|
||||
}
|
||||
dynarec_log(LOG_DEBUG, "Access to protected %p from %p, unprotecting memory (prot=%x)\n", addr, pc, prot);
|
||||
// access error, unprotect the block (and mark them dirty)
|
||||
|
19
src/main.c
19
src/main.c
@ -49,11 +49,9 @@ int box86_pagesize;
|
||||
#ifdef DYNAREC
|
||||
int box86_dynarec = 1;
|
||||
int box86_dynarec_dump = 0;
|
||||
int box86_dynarec_linker = 1;
|
||||
int box86_dynarec_forced = 0;
|
||||
int box86_dynarec_largest = 0;
|
||||
int box86_dynarec_smc = 0;
|
||||
int box86_dynarec_safemmap = 0;
|
||||
#ifdef ARM
|
||||
int arm_vfp = 0; // vfp version (3 or 4), with 32 registers is mendatory
|
||||
int arm_swap = 0;
|
||||
@ -257,14 +255,6 @@ void LoadLogEnv()
|
||||
}
|
||||
printf_log(LOG_INFO, "Dynarec is %s\n", box86_dynarec?"On":"Off");
|
||||
}
|
||||
p = getenv("BOX86_DYNAREC_LINKER");
|
||||
if(p) {
|
||||
if(strlen(p)==1) {
|
||||
if(p[0]>='0' && p[1]<='1')
|
||||
box86_dynarec_linker = p[0]-'0';
|
||||
}
|
||||
printf_log(LOG_INFO, "Dynarec Linker is %s\n", box86_dynarec_linker?"On":"Off");
|
||||
}
|
||||
p = getenv("BOX86_DYNAREC_FORCED");
|
||||
if(p) {
|
||||
if(strlen(p)==1) {
|
||||
@ -283,14 +273,6 @@ void LoadLogEnv()
|
||||
if(box86_dynarec_smc)
|
||||
printf_log(LOG_INFO, "Dynarec is trying to detect SMC in same dynablock\n");
|
||||
}
|
||||
p = getenv("BOX86_DYNAREC_SAFEMMAP");
|
||||
if(p) {
|
||||
if(strlen(p)==1) {
|
||||
if(p[0]>='0' && p[1]<='1')
|
||||
box86_dynarec_safemmap = p[0]-'0';
|
||||
}
|
||||
printf_log(LOG_INFO, "Dynarec Safe mmap is %s\n", box86_dynarec_safemmap?"On":"Off");
|
||||
}
|
||||
#endif
|
||||
#ifdef HAVE_TRACE
|
||||
p = getenv("BOX86_TRACE_XMM");
|
||||
@ -536,7 +518,6 @@ void PrintHelp() {
|
||||
#ifdef DYNAREC
|
||||
printf(" BOX86_DYNAREC_LOG with 0/1/2/3 or NONE/INFO/DEBUG/DUMP to set the printed dynarec info\n");
|
||||
printf(" BOX86_DYNAREC with 0/1 to disable or enable Dynarec (On by default)\n");
|
||||
printf(" BOX86_DYNAREC_LINKER with 0/1 to disable or enable Dynarec Linker (On by default, use 0 only for easier debug)\n");
|
||||
#endif
|
||||
#ifdef HAVE_TRACE
|
||||
printf(" BOX86_TRACE with 1 to enable x86 execution trace\n");
|
||||
|
@ -18,10 +18,11 @@
|
||||
|
||||
KHASH_MAP_INIT_INT(bridgemap, uintptr_t)
|
||||
|
||||
#define NBRICK 64
|
||||
//onebrigde is 16 bytes
|
||||
#define NBRICK 4096/16
|
||||
typedef struct brick_s brick_t;
|
||||
typedef struct brick_s {
|
||||
onebridge_t b[NBRICK];
|
||||
onebridge_t *b;
|
||||
int sz;
|
||||
brick_t *next;
|
||||
} brick_t;
|
||||
@ -32,11 +33,17 @@ typedef struct bridge_s {
|
||||
kh_bridgemap_t *bridgemap;
|
||||
} bridge_t;
|
||||
|
||||
brick_t* NewBrick()
|
||||
{
|
||||
brick_t* ret = (brick_t*)calloc(1, sizeof(brick_t));
|
||||
posix_memalign((void**)&ret->b, box86_pagesize, NBRICK*sizeof(onebridge_t));
|
||||
return ret;
|
||||
}
|
||||
|
||||
bridge_t *NewBridge()
|
||||
{
|
||||
bridge_t *b = (bridge_t*)calloc(1, sizeof(bridge_t));
|
||||
b->head = (brick_t*)calloc(1, sizeof(brick_t));
|
||||
b->head = NewBrick();
|
||||
b->last = b->head;
|
||||
b->bridgemap = kh_init(bridgemap);
|
||||
|
||||
@ -47,6 +54,11 @@ void FreeBridge(bridge_t** bridge)
|
||||
brick_t *b = (*bridge)->head;
|
||||
while(b) {
|
||||
brick_t *n = b->next;
|
||||
#ifdef DYNAREC
|
||||
if(getProtection((uintptr_t)b->b)&PROT_DYNAREC)
|
||||
unprotectDB((uintptr_t)b->b, NBRICK*sizeof(onebridge_t));
|
||||
#endif
|
||||
free(b->b);
|
||||
free(b);
|
||||
b = n;
|
||||
}
|
||||
@ -59,24 +71,33 @@ uintptr_t AddBridge(bridge_t* bridge, wrapper_t w, void* fnc, int N)
|
||||
{
|
||||
brick_t *b = bridge->last;
|
||||
if(b->sz == NBRICK) {
|
||||
b->next = (brick_t*)calloc(1, sizeof(brick_t));
|
||||
b->next = NewBrick();
|
||||
b = b->next;
|
||||
bridge->last = b;
|
||||
}
|
||||
#ifdef DYNAREC
|
||||
int prot = 0;
|
||||
if(box86_dynarec) {
|
||||
prot=(getProtection((uintptr_t)b->b)&PROT_DYNAREC)?1:0;
|
||||
if(prot)
|
||||
unprotectDB((uintptr_t)b->b, NBRICK*sizeof(onebridge_t));
|
||||
addDBFromAddressRange((uintptr_t)&b->b[b->sz].CC, sizeof(onebridge_t));
|
||||
}
|
||||
#endif
|
||||
b->b[b->sz].CC = 0xCC;
|
||||
b->b[b->sz].S = 'S'; b->b[b->sz].C='C';
|
||||
b->b[b->sz].w = w;
|
||||
b->b[b->sz].f = (uintptr_t)fnc;
|
||||
b->b[b->sz].C3 = N?0xC2:0xC3;
|
||||
b->b[b->sz].N = N;
|
||||
#ifdef DYNAREC
|
||||
if(box86_dynarec && prot)
|
||||
protectDB((uintptr_t)b->b, NBRICK*sizeof(onebridge_t));
|
||||
#endif
|
||||
// add bridge to map, for fast recovery
|
||||
int ret;
|
||||
khint_t k = kh_put(bridgemap, bridge->bridgemap, (uintptr_t)fnc, &ret);
|
||||
kh_value(bridge->bridgemap, k) = (uintptr_t)&b->b[b->sz].CC;
|
||||
#ifdef DYNAREC
|
||||
if(box86_dynarec)
|
||||
addDBFromAddressRange((uintptr_t)&b->b[b->sz].CC, sizeof(onebridge_t), 0);
|
||||
#endif
|
||||
|
||||
return (uintptr_t)&b->b[b->sz++].CC;
|
||||
}
|
||||
@ -92,7 +113,7 @@ uintptr_t CheckBridged(bridge_t* bridge, void* fnc)
|
||||
|
||||
uintptr_t AddCheckBridge(bridge_t* bridge, wrapper_t w, void* fnc, int N)
|
||||
{
|
||||
if(!fnc)
|
||||
if(!fnc && w)
|
||||
return 0;
|
||||
uintptr_t ret = CheckBridged(bridge, fnc);
|
||||
if(!ret)
|
||||
|
@ -6,14 +6,16 @@
|
||||
typedef void (*wrapper_t)(x86emu_t* emu, uintptr_t fnc);
|
||||
|
||||
#pragma pack(push, 1)
|
||||
typedef struct onebridge_s {
|
||||
typedef union onebridge_s {
|
||||
struct {
|
||||
uint8_t CC; // CC int 0x3
|
||||
uint8_t S, C; // 'S' 'C', just a signature
|
||||
wrapper_t w; // wrapper
|
||||
uintptr_t f; // the function for the wrapper
|
||||
uint8_t C3; // C2 or C3 ret
|
||||
uint16_t N; // N in case of C2 ret
|
||||
uint8_t dummy[1+2]; // to get 4*32bits size
|
||||
};
|
||||
uint32_t dummy[4];
|
||||
} onebridge_t;
|
||||
#pragma pack(pop)
|
||||
|
||||
|
@ -2302,14 +2302,11 @@ EXPORT void* my_mmap(x86emu_t* emu, void *addr, unsigned long length, int prot,
|
||||
// and responded with a different address, so ignore it
|
||||
} else {
|
||||
if(prot& PROT_EXEC)
|
||||
addDBFromAddressRange((uintptr_t)ret, length, ((flags&MAP_ANONYMOUS) && !box86_dynarec_safemmap)?1:0);
|
||||
addDBFromAddressRange((uintptr_t)ret, length);
|
||||
else
|
||||
cleanDBFromAddressRange((uintptr_t)ret, length, 0);
|
||||
}
|
||||
} else if(box86_dynarec && ret==(void*)-1 && !((flags&MAP_ANONYMOUS) && !box86_dynarec_safemmap) && addr) {
|
||||
// hack, the programs wanted to map a file, but system didn't want. Still, mark the memory as ok with linker
|
||||
addDBFromAddressRange((uintptr_t)addr, length, 0);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if(ret!=(void*)-1)
|
||||
updateProtection((uintptr_t)ret, length, prot);
|
||||
@ -2331,13 +2328,10 @@ EXPORT void* my_mmap64(x86emu_t* emu, void *addr, unsigned long length, int prot
|
||||
// and responded with a different address, so ignore it
|
||||
} else {
|
||||
if(prot& PROT_EXEC)
|
||||
addDBFromAddressRange((uintptr_t)ret, length, ((flags&MAP_ANONYMOUS) && !box86_dynarec_safemmap)?1:0);
|
||||
addDBFromAddressRange((uintptr_t)ret, length);
|
||||
else
|
||||
cleanDBFromAddressRange((uintptr_t)ret, length, 0);
|
||||
}
|
||||
} else if(box86_dynarec && ret==(void*)-1 && !((flags&MAP_ANONYMOUS) && !box86_dynarec_safemmap) && addr) {
|
||||
// hack, the programs wanted to map a file, but system didn't want. Still, mark the memory as ok with linker
|
||||
addDBFromAddressRange((uintptr_t)addr, length, 0);
|
||||
}
|
||||
#endif
|
||||
if(ret!=(void*)-1)
|
||||
@ -2368,7 +2362,7 @@ EXPORT int my_mprotect(x86emu_t* emu, void *addr, unsigned long len, int prot)
|
||||
#ifdef DYNAREC
|
||||
if(box86_dynarec) {
|
||||
if(prot& PROT_EXEC)
|
||||
addDBFromAddressRange((uintptr_t)addr, len, 1);
|
||||
addDBFromAddressRange((uintptr_t)addr, len);
|
||||
else
|
||||
cleanDBFromAddressRange((uintptr_t)addr, len, 0);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user