[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:
ptitSeb 2021-01-22 16:16:12 +01:00
parent 8209cf8398
commit 911b95a505
31 changed files with 202 additions and 403 deletions

View File

@ -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"
)

View File

@ -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.)

View File

@ -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);

View File

@ -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);

View File

@ -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

View File

@ -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

View File

@ -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,13 +113,11 @@ 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);
}
}
}
void ProtectDynablock(dynablock_t* db)
@ -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,7 +402,6 @@ 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);
// fill-in jumptable
addJumpTableIfDefault(block->x86_addr, block->block);
@ -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,7 +431,6 @@ 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);
}
}
@ -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,7 +453,6 @@ 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);
}
}

View File

@ -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;

View File

@ -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, &current);
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, &current);
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, &current);
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);

View File

@ -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;

View File

@ -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;
}

View File

@ -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); \

View File

@ -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");

View File

@ -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); \

View File

@ -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);
}
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)
} 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)

View File

@ -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);

View File

@ -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,7 +76,8 @@ 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
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))

View File

@ -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;

View File

@ -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_

View File

@ -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)

View File

@ -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)

View File

@ -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();

View File

@ -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);

View File

@ -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;

View File

@ -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);

View File

@ -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);

View File

@ -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)

View File

@ -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");

View File

@ -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)

View File

@ -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)

View File

@ -2302,13 +2302,10 @@ 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)
@ -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);
}