23 changed files with 534 additions and 542 deletions

No files matched your search

+1
View File
@@ -516,6 +516,7 @@ if(ARM_DYNAREC)
"${BOX86_ROOT}/src/dynarec/dynarec_arm.c"
"${BOX86_ROOT}/src/dynarec/dynarec_arm_functions.c"
"${BOX86_ROOT}/src/dynarec/arm_printer.c"
"${BOX86_ROOT}/src/dynarec/arm_jmpnext.c"
"${BOX86_ROOT}/src/dynarec/arm_prolog.S"
"${BOX86_ROOT}/src/dynarec/arm_epilog.S"
+232 -91
View File
@@ -25,6 +25,7 @@
#ifdef DYNAREC
#include "dynablock.h"
#include "dynarec/arm_lock_helper.h"
#include "dynarec/dynarec_next.h"
#include "khash.h"
#define USE_MMAP
@@ -32,7 +33,6 @@
// init inside dynablocks.c
KHASH_MAP_INIT_INT(dynablocks, dynablock_t*)
static dynablocklist_t* dynmap[DYNAMAP_SIZE] = {0}; // 4G of memory mapped by 4K block
static mmaplist_t *mmaplist = NULL;
static int mmapsize = 0;
static int mmapcap = 0;
@@ -45,7 +45,12 @@ static kh_lockaddress_t *lockaddress = NULL;
#endif
#define MEMPROT_SHIFT 12
#define MEMPROT_SIZE (1<<(32-MEMPROT_SHIFT))
static uint8_t memprot[MEMPROT_SIZE] = {0}; // protection flags by 4K block
typedef struct memprot_s
{
uint8_t prot;
uint8_t hot;
} memprot_t;
static memprot_t memprot[MEMPROT_SIZE] = {0}; // protection flags by 4K block
static int inited = 0;
typedef struct mapmem_s {
@@ -59,13 +64,15 @@ typedef struct blocklist_s {
void* block;
int maxfree;
size_t size;
void* first;
} blocklist_t;
#define MMAPSIZE (256*1024) // allocate 256kb sized blocks
static pthread_mutex_t mutex_blocks;
static int n_blocks = 0; // number of blocks for custom malloc
static blocklist_t* p_blocks = NULL; // actual blocks for custom malloc
static int n_blocks = 0; // number of blocks for custom malloc
static int c_blocks = 0; // capacity of blocks for custom malloc
static blocklist_t* p_blocks = NULL; // actual blocks for custom malloc
typedef union mark_s {
struct {
@@ -109,6 +116,23 @@ static void* getFirstBlock(void* block, size_t maxsize, size_t* size, void* star
return NULL;
}
static void* getNextFreeBlock(void* block)
{
blockmark_t *m = (blockmark_t*)block;
while (m->next.fill) {
m = NEXT_BLOCK(m);
};
return m;
}
static void* getPrevFreeBlock(void* block)
{
blockmark_t *m = (blockmark_t*)block;
do {
m = PREV_BLOCK(m);
} while (m->next.fill);
return m;
}
static size_t getMaxFreeBlock(void* block, size_t block_size, void* start)
{
// get start of block
@@ -239,19 +263,37 @@ static size_t sizeBlock(void* sub)
return s->next.size;
}
#define THRESHOLD (128-2*sizeof(blockmark_t))
static size_t roundSize(size_t size)
{
if(!size)
return size;
size = (size+7)&~7LL; // 8 bytes align in size
if(size<THRESHOLD)
size = THRESHOLD;
return size;
}
void* customMalloc(size_t size)
{
size = roundSize(size);
// look for free space
void* sub = NULL;
size_t fullsize = size+2*sizeof(blockmark_t);
pthread_mutex_lock(&mutex_blocks);
for(int i=0; i<n_blocks; ++i) {
if(p_blocks[i].maxfree>=size) {
size_t rsize = 0;
sub = getFirstBlock(p_blocks[i].block, size, &rsize, NULL);
sub = getFirstBlock(p_blocks[i].block, size, &rsize, p_blocks[i].first);
if(sub) {
if(rsize-size<THRESHOLD)
size = rsize;
void* ret = allocBlock(p_blocks[i].block, sub, size, NULL);
if(rsize==p_blocks[i].maxfree)
p_blocks[i].maxfree = getMaxFreeBlock(p_blocks[i].block, p_blocks[i].size, NULL);
p_blocks[i].maxfree = getMaxFreeBlock(p_blocks[i].block, p_blocks[i].size, p_blocks[i].first);
pthread_mutex_unlock(&mutex_blocks);
return ret;
}
@@ -259,10 +301,11 @@ void* customMalloc(size_t size)
}
// add a new block
int i = n_blocks++;
p_blocks = (blocklist_t*)box_realloc(p_blocks, n_blocks*sizeof(blocklist_t));
size_t allocsize = MMAPSIZE;
if(size+2*sizeof(blockmark_t)>allocsize)
allocsize = size+2*sizeof(blockmark_t);
if(n_blocks>c_blocks) {
c_blocks += 4;
p_blocks = (blocklist_t*)box_realloc(p_blocks, c_blocks*sizeof(blocklist_t));
}
size_t allocsize = (fullsize>MMAPSIZE)?fullsize:MMAPSIZE;
#ifdef USE_MMAP_MORE
void* p = mmap(NULL, allocsize, PROT_READ|PROT_WRITE, MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
memset(p, 0, allocsize);
@@ -271,6 +314,7 @@ void* customMalloc(size_t size)
void* p = box_calloc(1, allocsize);
#endif
p_blocks[i].block = p;
p_blocks[i].first = p;
p_blocks[i].size = allocsize;
// setup marks
blockmark_t* m = (blockmark_t*)p;
@@ -289,7 +333,7 @@ void* customMalloc(size_t size)
}
void* customCalloc(size_t n, size_t size)
{
size_t newsize = n*size;
size_t newsize = roundSize(n*size);
void* ret = customMalloc(newsize);
memset(ret, 0, newsize);
return ret;
@@ -298,6 +342,7 @@ void* customRealloc(void* p, size_t size)
{
if(!p)
return customMalloc(size);
size = roundSize(size);
uintptr_t addr = (uintptr_t)p;
pthread_mutex_lock(&mutex_blocks);
for(int i=0; i<n_blocks; ++i) {
@@ -305,7 +350,9 @@ void* customRealloc(void* p, size_t size)
&& (addr<((uintptr_t)p_blocks[i].block+p_blocks[i].size))) {
void* sub = (void*)(addr-sizeof(blockmark_t));
if(expandBlock(p_blocks[i].block, sub, size)) {
p_blocks[i].maxfree = getMaxFreeBlock(p_blocks[i].block, p_blocks[i].size, NULL);
if(sub<p_blocks[i].first && p+size<p_blocks[i].first)
p_blocks[i].first = getNextFreeBlock(sub);
p_blocks[i].maxfree = getMaxFreeBlock(p_blocks[i].block, p_blocks[i].size, p_blocks[i].first);
pthread_mutex_unlock(&mutex_blocks);
return p;
}
@@ -331,7 +378,10 @@ void customFree(void* p)
if ((addr>(uintptr_t)p_blocks[i].block)
&& (addr<((uintptr_t)p_blocks[i].block+p_blocks[i].size))) {
void* sub = (void*)(addr-sizeof(blockmark_t));
void* n = NEXT_BLOCK((blockmark_t*)sub);
size_t newfree = freeBlock(p_blocks[i].block, sub, NULL);
if(sub<=p_blocks[i].first)
p_blocks[i].first = getPrevFreeBlock(n);
if(p_blocks[i].maxfree < newfree) p_blocks[i].maxfree = newfree;
pthread_mutex_unlock(&mutex_blocks);
return;
@@ -358,35 +408,40 @@ uintptr_t FindFreeDynarecMap(dynablock_t* db, int size)
// look for free space
void* sub = NULL;
for(int i=0; i<mmapsize; ++i) {
if(mmaplist[i].maxfree>=size+sizeof(blockmark_t) && !mmaplist[i].locked) {
mmaplist[i].locked = 1;
size_t rsize = 0;
sub = getFirstBlock(mmaplist[i].block, size, &rsize, mmaplist[i].first);
if(sub) {
uintptr_t ret = (uintptr_t)allocBlock(mmaplist[i].block, sub, size, &mmaplist[i].first);
if(rsize==mmaplist[i].maxfree) {
mmaplist[i].maxfree = getMaxFreeBlock(mmaplist[i].block, mmaplist[i].size, mmaplist[i].first);
if(mmaplist[i].maxfree>=size+sizeof(blockmark_t)) {
if(!arm_lock_xchg(&mmaplist[i].locked, 1)) {
size_t rsize = 0;
sub = getFirstBlock(mmaplist[i].block, size, &rsize, mmaplist[i].first);
if(sub) {
uintptr_t ret = (uintptr_t)allocBlock(mmaplist[i].block, sub, size, &mmaplist[i].first);
if(rsize==mmaplist[i].maxfree) {
mmaplist[i].maxfree = getMaxFreeBlock(mmaplist[i].block, mmaplist[i].size, mmaplist[i].first);
}
kh_dynablocks_t *blocks = mmaplist[i].dblist;
if(!blocks) {
blocks = mmaplist[i].dblist = kh_init(dynablocks);
kh_resize(dynablocks, blocks, 64);
}
khint_t k;
int r;
k = kh_put(dynablocks, blocks, (uintptr_t)ret, &r);
kh_value(blocks, k) = db;
int size255=(size<256)?size:255;
for(size_t j=0; j<size255; ++j)
mmaplist[i].helper[(uintptr_t)ret-(uintptr_t)mmaplist[i].block+j] = j;
if(size!=size255)
memset(&mmaplist[i].helper[(uintptr_t)ret-(uintptr_t)mmaplist[i].block+256], -1, size-255);
arm_lock_store(&mmaplist[i].locked, 0);
return ret;
} else {
printf_log(LOG_INFO, "BOX86: Warning, sub not found, corrupted mmaplist[%d] info (requested size=%d)?\n", i, size);
if(box86_log >= LOG_DEBUG)
printBlock(mmaplist[i].block, mmaplist[i].first);
// reset block meta info
mmaplist[i].first = getFirstBlock(mmaplist[i].block, 1, &rsize, NULL);
mmaplist[i].maxfree = getMaxFreeBlock(mmaplist[i].block, mmaplist[i].size, NULL);
arm_lock_store(&mmaplist[i].locked, 0);
}
kh_dynablocks_t *blocks = mmaplist[i].dblist;
if(!blocks) {
blocks = mmaplist[i].dblist = kh_init(dynablocks);
kh_resize(dynablocks, blocks, 64);
}
khint_t k;
int r;
k = kh_put(dynablocks, blocks, (uintptr_t)ret, &r);
kh_value(blocks, k) = db;
int size255=(size<256)?size:255;
for(size_t j=0; j<size255; ++j)
mmaplist[i].helper[(uintptr_t)ret-(uintptr_t)mmaplist[i].block+j] = j;
if(size!=size255)
memset(&mmaplist[i].helper[(uintptr_t)ret-(uintptr_t)mmaplist[i].block+256], -1, size-255);
mmaplist[i].locked = 0;
return ret;
} else {
printf_log(LOG_INFO, "BOX86: Warning, sub not found, corrupted mmaplist[%d] info?\n", i);
if(box86_log >= LOG_DEBUG)
printBlock(mmaplist[i].block, mmaplist[i].first);
}
}
}
@@ -419,7 +474,7 @@ uintptr_t AddNewDynarecMap(dynablock_t* db, int size)
#endif
setProtection((uintptr_t)p, MMAPSIZE, PROT_READ | PROT_WRITE | PROT_EXEC);
mmaplist[i].locked = 1;
arm_lock_store(&mmaplist[i].locked, 1);
mmaplist[i].block = p;
mmaplist[i].size = MMAPSIZE;
mmaplist[i].helper = (uint8_t*)box_calloc(1, MMAPSIZE);
@@ -444,7 +499,7 @@ uintptr_t AddNewDynarecMap(dynablock_t* db, int size)
kh_value(blocks, k) = db;
for(int j=0; j<size; ++j)
mmaplist[i].helper[(uintptr_t)sub-(uintptr_t)mmaplist[i].block + j] = (j<256)?j:255;
mmaplist[i].locked = 0;
arm_lock_store(&mmaplist[i].locked, 0);
return sub;
}
@@ -455,6 +510,12 @@ void ActuallyFreeDynarecMap(dynablock_t* db, uintptr_t addr, int size)
for(int i=0; i<mmapsize; ++i) {
if ((addr>(uintptr_t)mmaplist[i].block)
&& (addr<((uintptr_t)mmaplist[i].block+mmaplist[i].size))) {
// wait the map is free
int cnt = 100;
while(my_context && cnt && arm_lock_store_xchg(&mmaplist[i].locked, (void*)1)) {
--cnt;
sched_yield();
}
void* sub = (void*)(addr-sizeof(blockmark_t));
size_t newfree = freeBlock(mmaplist[i].block, sub, &mmaplist[i].first);
if(mmaplist[i].maxfree < newfree) mmaplist[i].maxfree = newfree;
@@ -465,10 +526,7 @@ void ActuallyFreeDynarecMap(dynablock_t* db, uintptr_t addr, int size)
kh_del(dynablocks, blocks, k);
memset(&mmaplist[i].helper[(uintptr_t)sub-(uintptr_t)mmaplist[i].block], 0, size);
}
if(mmaplist[i].locked) {
printf_log(LOG_INFO, "BOX86: Warning, Free a chunk in a locked mmaplist[%d]\n", i);
++mmaplist[i].locked;
}
arm_lock_store(&mmaplist[i].locked, 0);
return;
}
}
@@ -558,9 +616,23 @@ void FreeDynarecMap(dynablock_t* db, uintptr_t addr, uint32_t size)
ActuallyFreeDynarecMap(db, addr, size);
}
dynablocklist_t* getDB(uintptr_t idx)
dynablock_t* getDB(uintptr_t addr)
{
return dynmap[idx];
if(isJumpTableDefault((void*)addr))
return NULL;
uintptr_t ret = getJumpAddress(addr);
return *(dynablock_t**)(ret-sizeof(void*));
}
uintptr_t getDefaultSize(uintptr_t addr)
{
uintptr_t idx = ((uintptr_t)addr>>JMPTABL_SHIFT);
if(box86_jumptable[idx] == box86_jmptbl_default)
return (addr&~((1<<JMPTABL_SHIFT)-1)|0xffff)-addr + 1;
uintptr_t idx0 = addr&0xffff;
while(box86_jumptable[idx][idx0]==(uintptr_t)arm_next)
++idx0;
return idx0 - (addr&0xffff);
}
// each dynmap is 64k of size
@@ -568,38 +640,30 @@ dynablocklist_t* getDB(uintptr_t idx)
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]) {
dynablocklist_t* p = NewDynablockList(i<<DYNAMAP_SHIFT, 1<<DYNAMAP_SHIFT, 0);
if(arm_lock_storeifnull(&dynmap[i], p)!=p)
FreeDynablockList(&p);
}
}
// do nothing, dynablock are allowed based on memory protection flags
}
void cleanDBFromAddressRange(uintptr_t addr, uintptr_t size, int destroy)
{
dynarec_log(LOG_DEBUG, "cleanDBFromAddressRange %p -> %p %s\n", (void*)addr, (void*)(addr+size-1), destroy?"destroy":"mark");
uintptr_t idx = (addr>>DYNAMAP_SHIFT);
uintptr_t end = ((addr+size-1)>>DYNAMAP_SHIFT);
for (uintptr_t i=idx; i<=end; ++i) {
dynablocklist_t* dblist = dynmap[i];
if(dblist) {
uintptr_t start_addr = my_context?((addr<my_context->max_db_size)?0:(addr-my_context->max_db_size)):addr;
dynarec_log(LOG_DEBUG, "cleanDBFromAddressRange %p/%p -> %p %s\n", (void*)addr, (void*)start_addr, (void*)(addr+size-1), destroy?"destroy":"mark");
for (uintptr_t i=start_addr; i<addr+size; ++i) {
dynablock_t* db = getDB(i);
if(db) {
if(destroy)
FreeRangeDynablock(dblist, addr, size);
FreeRangeDynablock(db, addr, size);
else
MarkRangeDynablock(dblist, addr, size);
MarkRangeDynablock(db, addr, size);
} else {
uintptr_t next = getDefaultSize(i);
if(next)
i+=next-1;
}
}
}
#ifdef ARM
void arm_next(void);
#endif
void addJumpTableIfDefault(void* addr, void* jmp)
int addJumpTableIfDefault(void* addr, void* jmp)
{
const uintptr_t idx = ((uintptr_t)addr>>JMPTABL_SHIFT);
if(box86_jumptable[idx] == box86_jmptbl_default) {
@@ -610,7 +674,7 @@ void addJumpTableIfDefault(void* addr, void* jmp)
box_free(tbl);
}
const uintptr_t off = (uintptr_t)addr&((1<<JMPTABL_SHIFT)-1);
arm_lock_storeifref(&box86_jumptable[idx][off], jmp, arm_next);
return (arm_lock_storeifref(&box86_jumptable[idx][off], jmp, arm_next)==jmp)?1:0;
}
void setJumpTableDefault(void* addr)
{
@@ -621,6 +685,28 @@ void setJumpTableDefault(void* addr)
const uintptr_t off = (uintptr_t)addr&((1<<JMPTABL_SHIFT)-1);
box86_jumptable[idx][off] = (uintptr_t)arm_next;
}
void setJumpTableDefaultRef(void* addr, void* jmp)
{
const uintptr_t idx = ((uintptr_t)addr>>JMPTABL_SHIFT);
if(box86_jumptable[idx] == box86_jmptbl_default) {
return;
}
const uintptr_t off = (uintptr_t)addr&((1<<JMPTABL_SHIFT)-1);
arm_lock_storeifref(&box86_jumptable[idx][off], arm_next, jmp);
}
void setJumpTableIfRef(void* addr, void* jmp, void* ref)
{
const uintptr_t idx = ((uintptr_t)addr>>JMPTABL_SHIFT);
if(box86_jumptable[idx] == box86_jmptbl_default) {
uintptr_t* tbl = (uintptr_t*)box_malloc((1<<JMPTABL_SHIFT)*sizeof(uintptr_t));
for(int i=0; i<(1<<JMPTABL_SHIFT); ++i)
tbl[i] = (uintptr_t)arm_next;
if(arm_lock_storeifref(&box86_jumptable[idx], tbl, box86_jmptbl_default)!=tbl)
box_free(tbl);
}
const uintptr_t off = (uintptr_t)addr&((1<<JMPTABL_SHIFT)-1);
arm_lock_storeifref(&box86_jumptable[idx][off], jmp, ref);
}
int isJumpTableDefault(void* addr)
{
const uintptr_t idx = ((uintptr_t)addr>>JMPTABL_SHIFT);
@@ -649,6 +735,20 @@ uintptr_t getJumpTableAddress(uintptr_t addr)
return (uintptr_t)&box86_jumptable[idx][off];
}
uintptr_t getJumpAddress(uintptr_t addr)
{
const uintptr_t idx = ((uintptr_t)addr>>JMPTABL_SHIFT);
if(box86_jumptable[idx] == box86_jmptbl_default) {
uintptr_t* tbl = (uintptr_t*)box_malloc((1<<JMPTABL_SHIFT)*sizeof(uintptr_t));
for(int i=0; i<(1<<JMPTABL_SHIFT); ++i)
tbl[i] = (uintptr_t)arm_next;
if(arm_lock_storeifref(&box86_jumptable[idx], tbl, box86_jmptbl_default)!=tbl)
box_free(tbl);
}
const uintptr_t off = (uintptr_t)addr&((1<<JMPTABL_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)
@@ -657,16 +757,16 @@ void protectDB(uintptr_t addr, uintptr_t size)
uintptr_t idx = (addr>>MEMPROT_SHIFT);
uintptr_t end = ((addr+size-1)>>MEMPROT_SHIFT);
for (uintptr_t i=idx; i<=end; ++i) {
uint32_t prot = memprot[i];
uint32_t prot = memprot[i].prot;
uint32_t dyn = prot&PROT_CUSTOM;
prot&=~PROT_CUSTOM;
if(!prot)
prot = PROT_READ | PROT_WRITE | PROT_EXEC; // comes from malloc & co, so should not be able to execute
if(prot&PROT_WRITE) {
memprot[i] = prot|PROT_DYNAREC;
memprot[i].prot = prot|PROT_DYNAREC;
if(!dyn) mprotect((void*)(i<<MEMPROT_SHIFT), 1<<MEMPROT_SHIFT, prot&~PROT_WRITE);
} else
memprot[i] = prot|PROT_DYNAREC_R;
memprot[i].prot = prot|PROT_DYNAREC_R;
}
}
@@ -678,17 +778,52 @@ void unprotectDB(uintptr_t addr, uintptr_t size, int mark)
uintptr_t idx = (addr>>MEMPROT_SHIFT);
uintptr_t end = ((addr+size-1)>>MEMPROT_SHIFT);
for (uintptr_t i=idx; i<=end; ++i) {
uint32_t prot = memprot[i];
uint32_t prot = memprot[i].prot;
if(prot&PROT_DYNAREC) {
memprot[i] = prot&~PROT_DYNAREC;
memprot[i].prot = prot&~PROT_DYNAREC;
mprotect((void*)(i<<MEMPROT_SHIFT), 1<<MEMPROT_SHIFT, prot&~PROT_DYNAREC);
if(mark)
cleanDBFromAddressRange((i<<MEMPROT_SHIFT), 1<<MEMPROT_SHIFT, 0);
} else if(prot&PROT_DYNAREC_R)
memprot[i] = prot&~(PROT_CUSTOM);
memprot[i].prot = prot&~(PROT_CUSTOM);
}
}
#define HOTPAGE_STEP 16
int IsInHotPage(uintptr_t addr) {
uintptr_t idx = (addr>>MEMPROT_SHIFT);
if(!memprot[idx].hot)
return 0;
// decrement hot
arm_lock_dec_b(&memprot[idx].hot);
return 1;
}
int AreaInHotPage(uintptr_t start, uintptr_t end_) {
//dynarec_log(LOG_DEBUG, "AreaInHotPage %p -> %p => ", (void*)start, (void*)end_);
uintptr_t idx = (start>>MEMPROT_SHIFT);
uintptr_t end = (end_>>MEMPROT_SHIFT);
if(end<idx) { // memory addresses higher than 48bits are not tracked
//dynarec_log(LOG_DEBUG, "00\n");
return 0;
}
for (uintptr_t i=idx; i<=end; ++i) {
if(memprot[i].hot) {
// decrement hot
arm_lock_dec_b(&memprot[i].hot);
//dynarec_log(LOG_DEBUG, "1\n");
return 1;
}
}
//dynarec_log(LOG_DEBUG, "0\n");
return 0;
}
void AddHotPage(uintptr_t addr) {
int idx = (addr>>MEMPROT_SHIFT);
arm_lock_store_b(&memprot[idx].hot, HOTPAGE_STEP);
}
#endif
void printMapMem()
@@ -788,15 +923,18 @@ void updateProtection(uintptr_t addr, uintptr_t size, uint32_t prot)
const uintptr_t idx = (addr>>MEMPROT_SHIFT);
const uintptr_t end = ((addr+size-1)>>MEMPROT_SHIFT);
for (uintptr_t i=idx; i<=end; ++i) {
uint32_t dyn=(memprot[i]&(PROT_DYNAREC|PROT_DYNAREC_R));
uint32_t dyn=(memprot[i].prot&(PROT_DYNAREC|PROT_DYNAREC_R));
if(dyn && (prot&PROT_WRITE)) { // need to remove the write protection from this block
dyn = PROT_DYNAREC;
mprotect((void*)(i<<MEMPROT_SHIFT), 1<<MEMPROT_SHIFT, prot&~PROT_WRITE);
} else if(dyn && !(prot&PROT_WRITE)) {
dyn = PROT_DYNAREC_R;
}
memprot[i] = prot|dyn;
#ifdef DYNAREC
arm_lock_store_b(&memprot[i].prot, prot|dyn);
#else
memprot[i].prot = prot|dyn;
#endif
}
}
@@ -808,7 +946,11 @@ void forceProtection(uintptr_t addr, uintptr_t size, uint32_t prot)
const uintptr_t end = ((addr+size-1)>>MEMPROT_SHIFT);
for (uintptr_t i=idx; i<=end; ++i) {
mprotect((void*)(i<<MEMPROT_SHIFT), 1<<MEMPROT_SHIFT, prot&~PROT_CUSTOM);
memprot[i] = prot;
#ifdef DYNAREC
arm_lock_store_b(&memprot[i].prot, prot);
#else
memprot[i].prot=prot;
#endif
}
}
@@ -821,7 +963,11 @@ void setProtection(uintptr_t addr, uintptr_t size, uint32_t prot)
const uintptr_t idx = (addr>>MEMPROT_SHIFT);
const uintptr_t end = ((addr+size-1)>>MEMPROT_SHIFT);
for (uintptr_t i=idx; i<=end; ++i) {
memprot[i] = prot;
#ifdef DYNAREC
arm_lock_store_b(&memprot[i].prot, prot);
#else
memprot[i].prot=prot;
#endif
}
}
@@ -831,14 +977,15 @@ void freeProtection(uintptr_t addr, uintptr_t size)
const uintptr_t idx = (addr>>MEMPROT_SHIFT);
const uintptr_t end = ((addr+size-1)>>MEMPROT_SHIFT);
for (uintptr_t i=idx; i<=end; ++i) {
memprot[i] = 0;
memprot[i].prot = 0;
memprot[i].hot = 0;
}
}
uint32_t getProtection(uintptr_t addr)
{
const uintptr_t idx = (addr>>MEMPROT_SHIFT);
uint32_t ret = memprot[idx];
uint32_t ret = memprot[idx].prot;
return ret;
}
@@ -848,8 +995,8 @@ void allocProtection(uintptr_t addr, uintptr_t size, uint32_t prot)
const uintptr_t idx = (addr>>MEMPROT_SHIFT);
const uintptr_t end = ((addr+size-1)>>MEMPROT_SHIFT);
for (uintptr_t i=idx; i<=end; ++i) {
if(!memprot[i])
memprot[i] = prot;
if(!memprot[i].prot)
memprot[i].prot = prot;
}
}
@@ -1013,12 +1160,6 @@ void fini_custommem_helper(box86context_t *ctx)
}
mmapsize = 0;
mmapcap = 0;
dynarec_log(LOG_DEBUG, "Free dynamic Dynarecblocks\n");
uintptr_t idx = 0;
uintptr_t end = ((0xFFFFFFFF)>>DYNAMAP_SHIFT);
for (uintptr_t i=idx; i<=end; ++i)
if(dynmap[i])
FreeDynablockList(&dynmap[i]);
box_free(mmaplist);
for (int i=0; i<DYNAMAP_SIZE; ++i)
if(box86_jumptable[i]!=box86_jmptbl_default)
+2
View File
@@ -391,6 +391,8 @@ Op is 20-27
// ldrd reg, reg+1, [addr, +rm], reg must be even, reg+1 is implicit
#define LDRD_REG(reg, addr, rm) EMIT(c__ | 0b000<<25 | 1<<24 | 1<<23 | 0<<22 | 0<<21 | 0<<20 | ((reg) << 12) | ((addr) << 16) | 0b1101<<4 | (rm) )
#define LDR_litteral(reg, imm12) EMIT(c__ | 0b010<<25 | 0<<24 | ((imm12<0)?0:1)<<23 | 0<<22 | 0<<21 | 1<<20 | 0b1111<<16 | (reg)<<12 | (abs(imm12)))
// str reg, [addr, #+/-imm9]
#define STR_IMM9(reg, addr, imm9) EMIT(0xe5000000 | (((imm9)<0)?0:1)<<23 | ((reg) << 12) | ((addr) << 16) | brIMM(imm9) )
// str with cond reg, [addr, #+/-imm9]
+12
View File
@@ -0,0 +1,12 @@
#include <stdint.h>
#include <stdlib.h>
#include "arm_emitter.h"
#define EMIT(A) *block = (A); ++block
void CreateJmpNextTo(void* addr, void* tonext)
{
uint32_t* block = (uint32_t*)addr;
MOV32(x3, (uintptr_t)tonext);
BX(x3);
}
+48
View File
@@ -16,6 +16,11 @@
.global arm_lock_xchg
.global arm_lock_storeifnull
.global arm_lock_storeifref
.global arm_lock_store_xchg
.global arm_lock_dec
.global arm_lock_dec_b
.global arm_lock_store
.global arm_lock_store_b
arm_lock_read_b:
@@ -113,3 +118,46 @@ arm_lock_storeifref_exit:
mov r0, r3
pop {r4}
bx lr
arm_lock_store_xchg:
// address is r0, value is r1, r1 store to r0 only if [r0] is 0. return new [r0] value (so r1 or old value)
// r0 needs to be aligned
ldrex r2, [r0]
cmp r2, #0
bne arm_lock_store_xchg_exit
mov r2, r1
strex r3, r2, [r0]
cmp r3, #1
beq arm_lock_store_xchg
mov r2, #0
arm_lock_store_xchg_exit:
mov r0, r2
bx lr
arm_lock_dec:
dmb ish
ldrex r1, [r0]
sub r1, r1, #1
strex r2, r1, [r0]
cmp r2, #1
beq arm_lock_dec
bx lr
arm_lock_dec_b:
dmb ish
ldrexb r1, [r0]
sub r1, r1, #1
strexb r2, r1, [r0]
cmp r2, #1
beq arm_lock_dec_b
bx lr
arm_lock_store:
str r1, [r0]
dmb ish
bx lr
arm_lock_store_b:
strb r1, [r0]
dmb ish
bx lr
+15
View File
@@ -31,4 +31,19 @@ extern void* arm_lock_storeifnull(void* p, void* val);
// Atomically store value to [p] only if [p] is ref. Return new [p] value (so val or old)
extern void* arm_lock_storeifref(void* p, void* val, void* ref);
// Atomically store value to [p] only if [p] is NULL. Return old [p] value
extern void* arm_lock_store_xchg(void* p, void* val);
// will decrease *p atomicaly
extern void arm_lock_dec_b(uint8_t* p);
// will decrease *p atomicaly
extern void arm_lock_dec(int* p);
// store value, with data memory barrier
extern void arm_lock_store_b(uint8_t* p, uint8_t val);
// store value, with data memory barrier
extern void arm_lock_store(int* p, int val);
#endif //__ARM_LOCK_HELPER__H__
+96 -280
View File
@@ -4,6 +4,7 @@
#include <errno.h>
#include <sys/mman.h>
#include <setjmp.h>
#include <sys/mman.h>
#include "debug.h"
#include "box86context.h"
@@ -20,6 +21,7 @@
#include "dynablock_private.h"
#include "dynarec_private.h"
#include "elfloader.h"
#include "bridge.h"
#ifdef ARM
#include "dynarec_arm.h"
#include "arm_lock_helper.h"
@@ -40,108 +42,36 @@ uint32_t X31_hash_code(void* addr, int len)
return (uint32_t)h;
}
dynablocklist_t* NewDynablockList(uintptr_t text, int textsz, int direct)
{
if(!textsz) {
printf_log(LOG_NONE, "Error, creating a NULL sized Dynablock\n");
return NULL;
}
dynablocklist_t* ret = (dynablocklist_t*)box_calloc(1, sizeof(dynablocklist_t));
ret->text = text;
ret->textsz = textsz;
if(direct && textsz) {
ret->direct = (dynablock_t**)box_calloc(textsz, sizeof(dynablock_t*));
if(!ret->direct) {printf_log(LOG_NONE, "Warning, fail to create direct block for dynablock @%p\n", (void*)text);}
}
dynarec_log(LOG_DEBUG, "New Dynablocklist %p, from %p->%p\n", ret, (void*)text, (void*)(text+textsz));
return ret;
}
void FreeDynablock(dynablock_t* db, int need_lock)
{
if(db) {
if(db->gone)
return; // already in the process of deletion!
dynarec_log(LOG_DEBUG, "FreeDynablock(%p), db->block=%p 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);
dynarec_log(LOG_DEBUG, "FreeDynablock(%p), db->block=%p x86=%p:%p already gone=%d\n", db, db->block, db->x86_addr, db->x86_addr+db->x86_size, db->gone);
if(need_lock)
pthread_mutex_lock(&my_context->mutex_dyndump);
db->done = 0;
db->gone = 1;
// remove from direct if there
uintptr_t startdb = db->parent->text;
uintptr_t enddb = db->parent->text + db->parent->textsz;
if(db->parent->direct) {
uintptr_t addr = (uintptr_t)db->x86_addr;
if(addr>=startdb && addr<enddb)
db->parent->direct[addr-startdb] = NULL;
}
// remove jumptable
setJumpTableDefault(db->x86_addr);
// remove and free the sons
for (int i=0; i<db->sons_size; ++i) {
dynablock_t *son = (dynablock_t*)arm_lock_xchg(&db->sons[i], 0);
FreeDynablock(son, 0);
}
// only the father free the DynarecMap
if(!db->father) {
dynarec_log(LOG_DEBUG, " -- FreeDyrecMap(%p, %d)\n", db->block, db->size);
FreeDynarecMap(db, (uintptr_t)db->block, db->size);
box_free(db->sons);
box_free(db->instsize);
}
dynarec_log(LOG_DEBUG, " -- FreeDyrecMap(%p, %d)\n", db->actual_block, db->size);
db->done = 0;
db->gone = 1;
FreeDynarecMap(db, (uintptr_t)db->actual_block, db->size);
box_free(db);
if(need_lock)
pthread_mutex_unlock(&my_context->mutex_dyndump);
}
}
void FreeDynablockList(dynablocklist_t** dynablocks)
{
if(!dynablocks)
return;
if(!*dynablocks)
return;
dynarec_log(LOG_DEBUG, "Free Dynablocklist %p, with Direct Blocks %p\n", *dynablocks, (*dynablocks)->direct);
if((*dynablocks)->direct) {
for (int i=0; i<(*dynablocks)->textsz; ++i) {
if((*dynablocks)->direct[i] && !(*dynablocks)->direct[i]->father)
FreeDynablock((*dynablocks)->direct[i], my_context?1:0);
}
box_free((*dynablocks)->direct);
}
(*dynablocks)->direct = NULL;
box_free(*dynablocks);
*dynablocks = NULL;
}
void MarkDynablock(dynablock_t* db)
{
if(db) {
if(db->father)
db = db->father; // mark only father
if(db->need_test)
return; // already done
db->need_test = 1;
setJumpTableDefault(db->x86_addr);
for(int i=0; i<db->sons_size; ++i)
setJumpTableDefault(db->sons[i]->x86_addr);
}
}
uintptr_t StartDynablockList(dynablocklist_t* db)
{
if(db)
return db->text;
return 0;
}
uintptr_t EndDynablockList(dynablocklist_t* db)
{
if(db)
return db->text+db->textsz-1;
return 0;
}
int IntervalIntersects(uintptr_t start1, uintptr_t end1, uintptr_t start2, uintptr_t end2)
{
if(start1 > end2 || start2 > end1)
@@ -149,81 +79,27 @@ int IntervalIntersects(uintptr_t start1, uintptr_t end1, uintptr_t start2, uintp
return 1;
}
void MarkDirectDynablock(dynablocklist_t* dynablocks, uintptr_t addr, uintptr_t size)
void MarkRangeDynablock(dynablock_t* db, uintptr_t addr, uintptr_t size)
{
if(!dynablocks)
if(!db)
return;
if(!dynablocks->direct)
return;
uintptr_t startdb = dynablocks->text;
uintptr_t enddb = startdb + dynablocks->textsz -1;
uintptr_t start = addr;
uintptr_t end = addr+size-1;
if(start<startdb)
start = startdb;
if(end>enddb)
end = enddb;
dynablock_t *db;
if(end>startdb && start<enddb)
for(uintptr_t i = start; i<end; ++i)
if((db=dynablocks->direct[i-startdb]))
if(IntervalIntersects((uintptr_t)db->x86_addr, (uintptr_t)db->x86_addr+db->x86_size-1, addr, addr+size+1))
MarkDynablock(db);
dynarec_log(LOG_DEBUG, "MarkRangeDynablock %p-%p .. startdb=%p, sizedb=%p\n", (void*)addr, (void*)addr+size-1, (void*)db->x86_addr, (void*)db->x86_size);
if(!db->need_test)
if(IntervalIntersects((uintptr_t)db->x86_addr, (uintptr_t)db->x86_addr+db->x86_size-1, addr, addr+size+1))
MarkDynablock(db);
}
void FreeRangeDynablock(dynablocklist_t* dynablocks, uintptr_t addr, uintptr_t size)
int FreeRangeDynablock(dynablock_t* db, uintptr_t addr, uintptr_t size)
{
if(!dynablocks)
return;
if(!db)
return 1;
if(dynablocks->direct) {
int need_lock = my_context?1:0;
dynablock_t* db;
int ret;
khint_t k;
kh_dynablocks_t *blocks = kh_init(dynablocks);
// copy in a temporary list
if(dynablocks->direct) {
uintptr_t startdb = dynablocks->text;
uintptr_t enddb = startdb + dynablocks->textsz;
uintptr_t start = addr;
uintptr_t end = addr+size;
if(start<startdb)
start = startdb;
if(end>enddb)
end = enddb;
if(end>startdb && start<enddb)
for(uintptr_t i = start; i<end; ++i) {
db = (dynablock_t*)arm_lock_xchg(&dynablocks->direct[i-startdb], 0);
if(db) {
if(db->father)
db = db->father;
if(db->parent==dynablocks) {
k = kh_put(dynablocks, blocks, (uintptr_t)db, &ret);
kh_value(blocks, k) = db;
}
}
}
}
// purge the list
kh_foreach_value(blocks, db,
FreeDynablock(db, need_lock);
);
kh_destroy(dynablocks, blocks);
}
}
void MarkRangeDynablock(dynablocklist_t* dynablocks, uintptr_t addr, uintptr_t size)
{
if(!dynablocks)
return;
if(dynablocks->direct) {
uintptr_t new_addr = addr - dynablocks->maxsz;
uintptr_t new_size = size + dynablocks->maxsz;
MarkDirectDynablock(dynablocks, new_addr, new_size);
// the blocks check before
for(int idx=(new_addr)>>DYNAMAP_SHIFT; idx<(addr>>DYNAMAP_SHIFT); ++idx)
MarkDirectDynablock(getDB(idx), new_addr, new_size);
int need_lock = my_context?1:0;
if(IntervalIntersects((uintptr_t)db->x86_addr, (uintptr_t)db->x86_addr+db->x86_size-1, addr, addr+size+1)) {
FreeDynablock(db, need_lock);
return 0;
}
return 1;
}
dynablock_t* FindDynablockDynablocklist(void* addr, kh_dynablocks_t* dynablocks)
@@ -235,66 +111,27 @@ dynablock_t* FindDynablockDynablocklist(void* addr, kh_dynablocks_t* dynablocks)
const uintptr_t s = (uintptr_t)db->block;
const uintptr_t e = (uintptr_t)db->block+db->size;
if((uintptr_t)addr>=s && (uintptr_t)addr<e)
return db->father?db->father:db;
return db;
)
return NULL;
}
static dynablocklist_t* getDBFromAddress(uintptr_t addr)
dynablock_t *AddNewDynablock(uintptr_t addr)
{
const int idx = (addr>>DYNAMAP_SHIFT);
return getDB(idx);
}
dynablock_t *AddNewDynablock(dynablocklist_t* dynablocks, uintptr_t addr, int* created)
{
if(!dynablocks) {
dynarec_log(LOG_INFO, "Warning: Ask to create a dynablock with a NULL dynablocklist (addr=%p)\n", (void*)addr);
*created = 0;
dynablock_t* block;
#if 0
// check if memory as the correct flags
int prot = getProtection(addr);
if(!(prot&(PROT_EXEC|PROT_DYNAREC|PROT_DYNAREC_R))) {
dynarec_log(LOG_VERBOSE, "Block asked on a memory with no execution flags 0x%02X\n", prot);
return NULL;
}
if((addr<dynablocks->text) || (addr>=(dynablocks->text+dynablocks->textsz))) {
// this should be useless
//dynarec_log(LOG_INFO, "Warning: Refused to create a Direct Block that is out-of-bound: dynablocks=%p (%p:%p), addr=%p\n", dynablocks, (void*)(dynablocks->text), (void*)(dynablocks->text+dynablocks->textsz), (void*)addr);
//*created = 0;
//return NULL;
return AddNewDynablock(getDBFromAddress(addr), addr, created);
}
dynablock_t* block = NULL;
// first, check if it exist in direct access mode
if(dynablocks->direct) {
block = dynablocks->direct[addr-dynablocks->text];
if(block) {
dynarec_log(LOG_VERBOSE, "Block already exist in Direct Map\n");
*created = 0;
return block;
}
}
if (!*created)
return block;
#endif
pthread_mutex_lock(&my_context->mutex_dyndump);
if(!dynablocks->direct) {
dynablock_t** p = (dynablock_t**)box_calloc(dynablocks->textsz, sizeof(dynablock_t*));
if(arm_lock_storeifnull(&dynablocks->direct, p)!=p)
box_free(p); // someone already create the direct array, too late...
}
// create and add new block
dynarec_log(LOG_VERBOSE, "Ask for DynaRec Block creation @%p\n", (void*)addr);
block = (dynablock_t*)box_calloc(1, sizeof(dynablock_t));
block->parent = dynablocks;
dynablock_t* tmp = (dynablock_t*)arm_lock_storeifnull(&dynablocks->direct[addr-dynablocks->text], block);
pthread_mutex_unlock(&my_context->mutex_dyndump);
if(tmp != block) {
// a block appeard!
box_free(block);
*created = 0;
return tmp;
}
*created = 1;
return block;
}
@@ -310,39 +147,28 @@ void cancelFillBlock()
return NULL if block is not found / cannot be created.
Don't create if create==0
*/
static dynablock_t* internalDBGetBlock(x86emu_t* emu, uintptr_t addr, uintptr_t filladdr, int create, dynablock_t* current, int need_lock)
static dynablock_t* internalDBGetBlock(x86emu_t* emu, uintptr_t addr, uintptr_t filladdr, int create, int need_lock)
{
// try the quickest way first: get parent of current and check if ok!
dynablocklist_t *dynablocks = NULL;
dynablock_t* block = NULL;
if(current && current->done) {
dynablocks = current->parent;
if(dynablocks && !(addr>=dynablocks->text && addr<(dynablocks->text+dynablocks->textsz)))
dynablocks = NULL;
}
// nope, lets do the long way
if(!dynablocks) {
dynablocks = getDBFromAddress(addr);
if(!dynablocks) {
dynablocks = GetDynablocksFromAddress(emu->context, addr);
if(!dynablocks)
return NULL;
}
}
// check direct first, without lock
if(dynablocks->direct/* && (addr>=dynablocks->text) && (addr<(dynablocks->text+dynablocks->textsz))*/)
if((block = dynablocks->direct[addr-dynablocks->text]))
return block;
if(hasAlternate((void*)addr))
return NULL;
dynablock_t* block = getDB(addr);
if(block || !create)
return block;
int created = create;
block = AddNewDynablock(dynablocks, addr, &created);
if(!created)
return block; // existing block...
if(need_lock)
pthread_mutex_lock(&my_context->mutex_dyndump);
block = getDB(addr); // just in case
if(block) {
if(need_lock)
pthread_mutex_unlock(&my_context->mutex_dyndump);
return block;
}
block = AddNewDynablock(addr);
// fill the block
block->x86_addr = (void*)addr;
if(need_lock)
pthread_mutex_lock(&my_context->mutex_dyndump);
if(sigsetjmp(&dynarec_jmpbuf, 1)) {
printf_log(LOG_INFO, "FillBlock at %p triggered a segfault, cancelling\n", (void*)addr);
if(need_lock)
@@ -354,68 +180,60 @@ static dynablock_t* internalDBGetBlock(x86emu_t* emu, uintptr_t addr, uintptr_t
pthread_mutex_unlock(&my_context->mutex_dyndump);
if(!ret) {
dynarec_log(LOG_DEBUG, "Fillblock of block %p for %p returned an error\n", block, (void*)addr);
void* old = (void*)arm_lock_storeifref(&dynablocks->direct[addr-dynablocks->text], 0, block);
if(old!=block && old) { // put it back in place, strange things are happening here!
dynarec_log(LOG_INFO, "Warning, a wild block appeared at %p: %p\n", (void*)addr, old);
// Doing nothing else, the block has not been written
}
box_free(block);
block = NULL;
}
// check size
if(block && block->x86_size) {
if(block && (block->x86_size || (!block->x86_size && !block->done))) {
int blocksz = block->x86_size;
if(dynablocks->maxsz<blocksz) {
dynablocks->maxsz = blocksz;
for(int idx=(addr>>DYNAMAP_SHIFT)+1; idx<=((addr+blocksz)>>DYNAMAP_SHIFT); ++idx) {
dynablocklist_t* dblist;
if((dblist = getDB(idx)))
if(dblist->maxsz<blocksz)
dblist->maxsz = blocksz;
}
}
//protectDB((uintptr_t)block->x86_addr, block->x86_size); // already protected in FillBlock
// but check if it already need test
if(block->need_test || (block->father && block->father->need_test))
return NULL;
if(blocksz>my_context->max_db_size)
my_context->max_db_size = blocksz;
// fill-in jumptable
addJumpTableIfDefault(block->x86_addr, block->block);
for(int i=0; i<block->sons_size; ++i)
addJumpTableIfDefault(block->sons[i]->x86_addr, block->sons[i]->block);
if(!addJumpTableIfDefault(block->x86_addr, block->block)) {
FreeDynablock(block, 1);
block = getDB(addr);
} else {
if(block->x86_size)
block->done = 1; // don't validate the block if the size is null, but keep the block
}
}
if(need_lock)
pthread_mutex_unlock(&my_context->mutex_dyndump);
dynarec_log(LOG_DEBUG, " --- DynaRec Block %s @%p:%p (%p, 0x%x bytes, with %d son(s))\n", created?"created":"recycled", (void*)addr, (void*)(addr+((block)?block->x86_size:0)), (block)?block->block:0, (block)?block->size:0, (block)?block->sons_size:0);
dynarec_log(LOG_DEBUG, " --- DynaRec Block created @%p:%p (%p, 0x%x bytes)\n", (void*)addr, (void*)(addr+((block)?block->x86_size:0)), (block)?block->block:0, (block)?block->size:0);
return block;
}
dynablock_t* DBGetBlock(x86emu_t* emu, uintptr_t addr, int create, dynablock_t** current)
dynablock_t* DBGetBlock(x86emu_t* emu, uintptr_t addr, int create)
{
dynablock_t *db = internalDBGetBlock(emu, addr, addr, create, *current, 1);
if(db && db->done && db->block && (db->need_test || (db->father && db->father->need_test))) {
if(pthread_mutex_trylock(&my_context->mutex_dyndump))
dynablock_t *db = internalDBGetBlock(emu, addr, addr, create, 1);
if(db && db->done && db->block && db->need_test) {
if(AreaInHotPage((uintptr_t)db->x86_addr, (uintptr_t)db->x86_addr + db->x86_size - 1)) {
dynarec_log(LOG_DEBUG, "Not running block %p from %p:%p with for %p because it's in a hotpage\n", db, db->x86_addr, db->x86_addr+db->x86_size-1, (void*)addr);
return NULL;
dynablock_t *father = db->father?db->father:db;
uint32_t hash = (getProtection((uintptr_t)father->x86_addr)&PROT_READ)?X31_hash_code(father->x86_addr, father->x86_size):0;
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
if(*current && father->x86_addr>=(*current)->x86_addr && (father->x86_addr+father->x86_size)<(*current)->x86_addr)
*current = NULL;
// Free father, it's now invalid!
FreeDynablock(father, 0);
}
uint32_t hash = X31_hash_code(db->x86_addr, db->x86_size);
if(pthread_mutex_trylock(&my_context->mutex_dyndump)) {
dynarec_log(LOG_DEBUG, "mutex_dyndump not available when trying to validate block %p from %p:%p (hash:%X) for %p\n", db, db->x86_addr, db->x86_addr+db->x86_size-1, db->hash, (void*)addr);
return NULL;
}
if(hash!=db->hash) {
db->done = 0; // invalidating the block
dynarec_log(LOG_DEBUG, "Invalidating block %p from %p:%p (hash:%X/%X) for %p\n", db, db->x86_addr, db->x86_addr+db->x86_size-1, hash, db->hash, (void*)addr);
// Free db, it's now invalid!
FreeDynablock(db, 0);
// start again... (will create a new block)
db = internalDBGetBlock(emu, addr, addr, create, *current, 0);
db = internalDBGetBlock(emu, addr, addr, create, 0);
} else {
father->need_test = 0;
protectDB((uintptr_t)father->x86_addr, father->x86_size);
// fill back jumptable
addJumpTableIfDefault(father->x86_addr, father->block);
for(int i=0; i<father->sons_size; ++i)
addJumpTableIfDefault(father->sons[i]->x86_addr, father->sons[i]->block);
db->need_test = 0;
dynarec_log(LOG_DEBUG, "Validating block %p from %p:%p (hash:%X) for %p\n", db, db->x86_addr, db->x86_addr+db->x86_size-1, db->hash, (void*)addr);
protectDB((uintptr_t)db->x86_addr, db->x86_size);
// fill back jumptable
setJumpTableIfRef(db->x86_addr, db->block, db->jmpnext);
}
pthread_mutex_unlock(&my_context->mutex_dyndump);
}
}
return db;
}
@@ -423,27 +241,25 @@ dynablock_t* DBAlternateBlock(x86emu_t* emu, uintptr_t addr, uintptr_t filladdr)
{
dynarec_log(LOG_DEBUG, "Creating AlternateBlock at %p for %p\n", (void*)addr, (void*)filladdr);
int create = 1;
dynablock_t *db = internalDBGetBlock(emu, addr, filladdr, create, NULL, 1);
if(db && db->done && db->block && (db->need_test || (db->father && db->father->need_test))) {
dynablock_t *db = internalDBGetBlock(emu, addr, filladdr, create, 1);
if(db && db->done && db->block && db->need_test) {
if(pthread_mutex_trylock(&my_context->mutex_dyndump))
return NULL;
dynablock_t *father = db->father?db->father:db;
uint32_t hash = (getProtection((uintptr_t)father->x86_addr)&PROT_READ)?X31_hash_code(father->x86_addr, father->x86_size):0;
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!
FreeDynablock(father, 0);
uint32_t hash = X31_hash_code(db->x86_addr, db->x86_size);
if(hash!=db->hash) {
db->done = 0; // invalidating the block
dynarec_log(LOG_DEBUG, "Invalidating alt block %p from %p:%p (hash:%X/%X) for %p\n", db, db->x86_addr, db->x86_addr+db->x86_size, hash, db->hash, (void*)addr);
// Free db, it's now invalid!
FreeDynablock(db, 0);
// start again... (will create a new block)
db = internalDBGetBlock(emu, addr, filladdr, create, NULL, 0);
db = internalDBGetBlock(emu, addr, filladdr, create, 0);
} else {
father->need_test = 0;
protectDB((uintptr_t)father->x86_addr, father->x86_size);
db->need_test = 0;
protectDB((uintptr_t)db->x86_addr, db->x86_size);
// fill back jumptable
addJumpTableIfDefault(father->x86_addr, father->block);
for(int i=0; i<father->sons_size; ++i)
addJumpTableIfDefault(father->sons[i]->x86_addr, father->sons[i]->block);
addJumpTableIfDefault(db->x86_addr, db->block);
}
pthread_mutex_unlock(&my_context->mutex_dyndump);
}
return db;
}
}
+5 -15
View File
@@ -1,16 +1,15 @@
#ifndef __DYNABLOCK_PRIVATE_H_
#define __DYNABLOCK_PRIVATE_H_
typedef struct dynablocklist_s dynablocklist_t;
typedef struct instsize_s {
unsigned int x86:4;
unsigned int nat:4;
unsigned char x86:4;
unsigned char nat:4;
} instsize_t;
typedef struct dynablock_s {
dynablocklist_t* parent;
void* block;
void* block; // block-sizeof(void*) == self
void* actual_block; // the actual start of the block (so block-sizeof(void*))
int size;
void* x86_addr;
uintptr_t x86_size;
@@ -20,17 +19,8 @@ typedef struct dynablock_s {
uint8_t gone;
uint8_t dummy;
int isize;
dynablock_t** sons; // sons (kind-of dummy dynablock...)
int sons_size;
dynablock_t* father; // set only in the case of a son
instsize_t* instsize;
void* jmpnext; // a branch jmpnext code when block is marked
} dynablock_t;
typedef struct dynablocklist_s {
uintptr_t text;
int textsz;
int maxsz; // maxblock size (for this block or previous block)
dynablock_t** direct; // direct mapping (waste of space, so the array is created at first write)
} dynablocklist_t;
#endif //__DYNABLOCK_PRIVATE_H_
+7 -18
View File
@@ -20,12 +20,7 @@
#include "dynablock.h"
#include "dynablock_private.h"
#include "bridge.h"
#endif
#ifdef ARM
void arm_prolog(x86emu_t* emu, void* addr) EXPORTDYN;
void arm_epilog() EXPORTDYN;
void arm_epilog_fast() EXPORTDYN;
#include "dynarec_next.h"
#endif
#ifdef DYNAREC
@@ -44,9 +39,8 @@ void* LinkNext(x86emu_t* emu, uintptr_t addr, void* x2)
printf_log(LOG_NONE, "Warning, jumping to NULL address from %p (db=%p, x86addr=%p/%s)\n", x2, db, x86addr, pcname);
}
#endif
dynablock_t* current = NULL;
void * jblock;
dynablock_t* block = DBGetBlock(emu, addr, 1, &current);
dynablock_t* block = DBGetBlock(emu, addr, 1);
if(!block) {
// no block, let link table as is...
if(hasAlternate((void*)addr)) {
@@ -54,7 +48,7 @@ void* LinkNext(x86emu_t* emu, uintptr_t addr, void* x2)
addr = (uintptr_t)getAlternate((void*)addr);
R_EIP = addr;
printf_log(LOG_INFO, " -> %p\n", (void*)addr);
block = DBGetBlock(emu, addr, 1, &current);
block = DBGetBlock(emu, addr, 1);
}
if(!block) {
#ifdef HAVE_TRACE
@@ -114,18 +108,15 @@ void DynaCall(x86emu_t* emu, uintptr_t addr)
PushExit(emu);
R_EIP = addr;
emu->df = d_none;
dynablock_t* block = NULL;
dynablock_t* current = NULL;
while(!emu->quit) {
block = DBGetBlock(emu, R_EIP, 1, &current);
current = block;
dynablock_t* block = DBGetBlock(emu, R_EIP, 1);
if(!block || !block->block || !block->done) {
// no block, of block doesn't have DynaRec content (yet, temp is not null)
// Use interpreter (should use single instruction step...)
dynarec_log(LOG_DEBUG, "%04d|Calling Interpretor @%p, emu=%p\n", GetTID(), (void*)R_EIP, emu);
Run(emu, 1);
} else {
dynarec_log(LOG_DEBUG, "%04d|Calling DynaRec Block @%p (%p) of %d x86 instructions (father=%p) emu=%p\n", GetTID(), (void*)R_EIP, block->block, block->isize ,block->father, emu);
dynarec_log(LOG_DEBUG, "%04d|Calling DynaRec Block @%p (%p) of %d x86 instructions emu=%p\n", GetTID(), (void*)R_EIP, block->block, block->isize ,emu);
CHECK_FLAGS(emu);
// block is here, let's run it!
#ifdef ARM
@@ -200,17 +191,15 @@ int DynaRun(x86emu_t* emu)
#ifdef DYNAREC
else {
dynablock_t* block = NULL;
dynablock_t* current = NULL;
while(!emu->quit) {
block = DBGetBlock(emu, R_EIP, 1, &current);
current = block;
block = DBGetBlock(emu, R_EIP, 1);
if(!block || !block->block || !block->done) {
// no block, of block doesn't have DynaRec content (yet, temp is not null)
// Use interpreter (should use single instruction step...)
dynarec_log(LOG_DEBUG, "%04d|Running Interpretor @%p, emu=%p\n", GetTID(), (void*)R_EIP, emu);
Run(emu, 1);
} else {
dynarec_log(LOG_DEBUG, "%04d|Running DynaRec Block @%p (%p) of %d x86 insts (father=%p) emu=%p\n", GetTID(), (void*)R_EIP, block->block, block->isize, block->father, emu);
dynarec_log(LOG_DEBUG, "%04d|Running DynaRec Block @%p (%p) of %d x86 insts emu=%p\n", GetTID(), (void*)R_EIP, block->block, block->isize, emu);
// block is here, let's run it!
#ifdef ARM
arm_prolog(emu, block->block);
+73 -92
View File
@@ -23,6 +23,7 @@
#include "dynarec_arm_private.h"
#include "dynarec_arm_functions.h"
#include "elfloader.h"
#include "dynarec_next.h"
void printf_x86_instruction(zydis_dec_t* dec, instruction_x86_t* inst, const char* name) {
uint8_t *ip = (uint8_t*)inst->addr;
@@ -368,17 +369,47 @@ void CancelBlock()
return;
box_free(helper->next);
box_free(helper->insts);
box_free(helper->instsize);
box_free(helper->predecessor);
if(helper->dynablock && helper->dynablock->block)
FreeDynarecMap(helper->dynablock, (uintptr_t)helper->dynablock->block, helper->dynablock->size);
if(helper->dynablock && helper->dynablock->actual_block)
FreeDynarecMap(helper->dynablock, (uintptr_t)helper->dynablock->actual_block, helper->dynablock->size);
else if(helper->dynablock && helper->block)
FreeDynarecMap(helper->dynablock, (uintptr_t)helper->block-sizeof(void*), helper->dynablock->size);
}
void* CreateEmptyBlock(dynablock_t* block, uintptr_t addr) {
block->isize = 0;
block->done = 0;
size_t sz = 4*sizeof(void*);
void* actual_p = (void*)AllocDynarecMap(block, sz);
void* p = actual_p + sizeof(void*);
if(actual_p==NULL) {
dynarec_log(LOG_INFO, "AllocDynarecMap(%p, %zu) failed, cancelling block\n", block, sz);
CancelBlock();
return NULL;
}
block->size = sz;
block->actual_block = actual_p;
block->block = p;
block->jmpnext = p;
*(dynablock_t**)actual_p = block;
CreateJmpNextTo(block->jmpnext, arm_epilog);
block->need_test = 0;
// all done...
__clear_cache(actual_p, actual_p+sz); // need to clear the cache before execution...
return block;
}
void* FillBlock(dynablock_t* block, uintptr_t addr) {
dynarec_log(LOG_DEBUG, "Asked to Fill block %p with %p\n", block, (void*)addr);
if(addr>=box86_nodynarec_start && addr<box86_nodynarec_end) {
dynarec_log(LOG_DEBUG, "Asked to fill a block in fobidden zone\n");
if(IsInHotPage(addr)) {
dynarec_log(LOG_DEBUG, "Cancelling dynarec FillBlock on hotpage for %p\n", (void*)addr);
return NULL;
}
if(addr>=box86_nodynarec_start && addr<box86_nodynarec_end) {
dynarec_log(LOG_INFO, "Create empty block in no-dynarec zone\n");
return CreateEmptyBlock(block, addr);
}
if(!isJumpTableDefault((void*)addr)) {
dynarec_log(LOG_DEBUG, "Asked to fill a block at %p, but JumpTable is not default\n", (void*)addr);
return NULL;
@@ -401,7 +432,7 @@ dynarec_log(LOG_DEBUG, "Asked to Fill block %p with %p\n", block, (void*)addr);
if(!helper.size) {
dynarec_log(LOG_DEBUG, "Warning, null-sized dynarec block (%p)\n", (void*)addr);
CancelBlock();
return (void*)block;
return CreateEmptyBlock(block, addr);
}
// already protect the block and compute hash signature
protectDB(addr, end-addr); //end is 1byte after actual end
@@ -427,44 +458,7 @@ dynarec_log(LOG_DEBUG, "Asked to Fill block %p with %p\n", block, (void*)addr);
}
// fill predecessors with the jump address
fillPredecessors(&helper);
// check for the optionnal barriers now
/*for(int i=helper.size-1; i>=0; --i) {
if(helper.insts[i].barrier_maybe) {
// out-of-block jump
if(helper.insts[i].x86.jmp_insts == -1) {
// nothing for now
} else {
// inside block jump
int k = helper.insts[i].x86.jmp_insts;
if(k>i) {
// jump in the future
if(helper.insts[k].pred_sz>1) {
// with multiple flow, put a barrier
helper.insts[k].x86.barrier|=BARRIER_FLAGS;
}
} else {
// jump back
helper.insts[k].x86.barrier|=BARRIER_FLAGS;
}
}
}
}*/
// check to remove useless barrier, in case of jump when destination doesn't needs flags
/*for(int i=helper.size-1; i>=0; --i) {
int k;
if(helper.insts[i].x86.jmp
&& ((k=helper.insts[i].x86.jmp_insts)>=0)
&& helper.insts[k].x86.barrier&BARRIER_FLAGS) {
//TODO: optimize FPU barrier too
if((!helper.insts[k].x86.need_flags)
||(helper.insts[k].x86.set_flags==X_ALL
&& helper.insts[k].x86.state_flags==SF_SET)
||(helper.insts[k].x86.state_flags==SF_SET_PENDING)) {
//if(box86_dynarec_dump) dynarec_log(LOG_NONE, "Removed barrier for inst %d\n", k);
helper.insts[k].x86.barrier &= ~BARRIER_FLAGS; // remove flag barrier
}
}
}*/
int pos = helper.size;
while (pos>=0)
pos = updateNeed(&helper, pos, 0);
@@ -474,29 +468,44 @@ dynarec_log(LOG_DEBUG, "Asked to Fill block %p with %p\n", block, (void*)addr);
// pass 2, instruction size
arm_pass2(&helper, addr);
// ok, now allocate mapped memory, with executable flag on
int sz = helper.arm_size;
void* p = (void*)AllocDynarecMap(block, sz);
if(p==NULL) {
// keep size of instructions for signal handling
size_t insts_ursize = 0;
{
size_t insts_size = 0;
size_t cap = 1;
for(int i=0; i<helper.size; ++i)
cap += 1 + ((helper.insts[i].x86.size>helper.insts[i].size)?helper.insts[i].x86.size:helper.insts[i].size)/15;
helper.instsize = (instsize_t*)box_calloc(cap, sizeof(instsize_t));
for(int i=0; i<helper.size; ++i)
helper.instsize = addInst(helper.instsize, &insts_size, &cap, helper.insts[i].x86.size, helper.insts[i].size/4);
helper.instsize = addInst(helper.instsize, &insts_size, &cap, 0, 0); // add a "end of block" mark, just in case
insts_ursize = insts_size*sizeof(instsize_t);
}
size_t insts_rsize = (insts_ursize+7)&~7; // round the size...
size_t sz = sizeof(void*) + helper.arm_size + 4*sizeof(void*) + insts_rsize;
// dynablock_t* block (arm insts) jmpnext code instsize
void* actual_p = (void*)AllocDynarecMap(block, sz);
void* p = actual_p + sizeof(void*);
void* next = p + helper.arm_size;
void* instsize = next + 4*sizeof(void*);
if(actual_p==NULL) {
dynarec_log(LOG_DEBUG, "AllocDynarecMap(%p, %d) failed, cancelling block\n", block, sz);
CancelBlock();
return NULL;
}
helper.block = p;
helper.arm_start = (uintptr_t)p;
if(helper.sons_size) {
helper.sons_x86 = (uintptr_t*)alloca(helper.sons_size*sizeof(uintptr_t));
helper.sons_arm = (void**)alloca(helper.sons_size*sizeof(void*));
}
*(dynablock_t**)actual_p = block;
// pass 3, emit (log emit arm opcode)
if(box86_dynarec_dump) {
dynarec_log(LOG_NONE, "%s%04d|Emitting %d bytes for %d x86 bytes", (box86_dynarec_dump>1)?"\e[01;36m":"", GetTID(), helper.arm_size, helper.isize);
printFunctionAddr(helper.start, " => ");
dynarec_log(LOG_NONE, "%s\n", (box86_dynarec_dump>1)?"\e[m":"");
}
size_t oldarmsize = helper.arm_size;
helper.arm_size = 0;
arm_pass3(&helper, addr);
if(sz!=helper.arm_size) {
if(oldarmsize!=helper.arm_size) {
printf_log(LOG_NONE, "BOX86: Warning, size difference in block between pass2 (%d) & pass3 (%d)!\n", sz, helper.arm_size);
uint8_t *dump = (uint8_t*)helper.start;
printf_log(LOG_NONE, "Dump of %d x86 opcodes:\n", helper.size);
@@ -508,32 +517,32 @@ dynarec_log(LOG_DEBUG, "Asked to Fill block %p with %p\n", block, (void*)addr);
}
printf_log(LOG_NONE, " ------------\n");
}
// all done...
__clear_cache(p, p+sz); // need to clear the cache before execution...
// keep size of instructions for signal handling
{
size_t cap = 1;
for(int i=0; i<helper.size; ++i)
cap += 1 + ((helper.insts[i].x86.size>helper.insts[i].size)?helper.insts[i].x86.size:helper.insts[i].size)/15;
size_t size = 0;
block->instsize = (instsize_t*)box_calloc(cap, sizeof(instsize_t));
for(int i=0; i<helper.size; ++i)
block->instsize = addInst(block->instsize, &size, &cap, helper.insts[i].x86.size, helper.insts[i].size/4);
block->instsize = addInst(block->instsize, &size, &cap, 0, 0); // add a "end of block" mark, just in case
}
memcpy(instsize, helper.instsize, insts_ursize);
block->instsize = instsize;
// ok, free the helper now
box_free(helper.insts);
helper.insts = NULL;
box_free(helper.next);
helper.next = NULL;
box_free(helper.instsize);
helper.instsize = NULL;
box_free(helper.predecessor);
helper.predecessor = NULL;
block->size = sz;
block->isize = helper.size;
block->actual_block = actual_p;
block->block = p;
block->jmpnext = next+sizeof(void*);
*(dynablock_t**)next = block;
CreateJmpNextTo(block->jmpnext, arm_next);
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;
// all done...
__clear_cache(actual_p, actual_p+sz); // need to clear the cache before execution...
block->hash = X31_hash_code(block->x86_addr, block->x86_size);
// Check if something changed, to abbort if it as
if(block->hash != hash) {
@@ -541,34 +550,6 @@ dynarec_log(LOG_DEBUG, "Asked to Fill block %p with %p\n", block, (void*)addr);
CancelBlock();
return NULL;
}
// fill sons if any
dynablock_t** sons = NULL;
int sons_size = 0;
if(helper.sons_size) {
sons = (dynablock_t**)box_calloc(helper.sons_size, sizeof(dynablock_t*));
for (int i=0; i<helper.sons_size; ++i) {
int created = 1;
dynablock_t *son = AddNewDynablock(block->parent, helper.sons_x86[i], &created);
if(created) { // avoid breaking a working block!
son->block = helper.sons_arm[i];
son->x86_addr = (void*)helper.sons_x86[i];
son->x86_size = end-helper.sons_x86[i];
if(!son->x86_size) {printf_log(LOG_NONE, "Warning, son with null x86 size! (@%p / ARM=%p)", son->x86_addr, son->block);}
son->father = block;
son->done = 1;
sons[sons_size++] = son;
if(!son->parent)
son->parent = block->parent;
}
}
if(sons_size) {
block->sons = sons;
block->sons_size = sons_size;
} else
box_free(sons);
}
box_free(helper.predecessor);
helper.predecessor = NULL;
current_helper = NULL;
block->done = 1;
return (void*)block;
+1 -2
View File
@@ -35,7 +35,6 @@ uintptr_t arm_pass(dynarec_arm_t* dyn, uintptr_t addr)
uintptr_t init_addr = addr;
MAYUSE(init_addr);
int need_epilog = 1;
dyn->sons_size = 0;
// Clean up (because there are multiple passes)
dyn->f.pending = 0;
dyn->f.dfnone = 0;
@@ -229,6 +228,6 @@ uintptr_t arm_pass(dynarec_arm_t* dyn, uintptr_t addr)
jump_to_epilog(dyn, ip, 0, ninst); // no linker here, it's an unknow instruction
}
FINI;
MESSAGE(LOG_DUMP, "---- END OF BLOCK ---- (%d, %d sons)\n", dyn->size, dyn->sons_size);
MESSAGE(LOG_DUMP, "---- END OF BLOCK ---- (%d)\n", dyn->size);
return addr;
}
-2
View File
@@ -6,8 +6,6 @@
#define NEW_INST \
if(ninst) { \
dyn->insts[ninst].address = (dyn->insts[ninst-1].address+dyn->insts[ninst-1].size); \
if(ninst && isInstClean(dyn, ninst)) \
++dyn->sons_size; \
}
#define INST_EPILOG dyn->insts[ninst].epilog = dyn->arm_size;
#define INST_NAME(name)
-6
View File
@@ -8,12 +8,6 @@
#define MESSAGE(A, ...) if(box86_dynarec_dump) dynarec_log(LOG_NONE, __VA_ARGS__)
#define NEW_INST \
if(ninst && isInstClean(dyn, ninst)) { \
dyn->sons_x86[dyn->sons_size] = (uintptr_t)ip; \
dyn->sons_arm[dyn->sons_size] = dyn->block; \
MESSAGE(LOG_DUMP, "----> potential Son here %p/%p\n", (void*)ip, dyn->block); \
++dyn->sons_size; \
}
#define INST_EPILOG
#define INST_NAME(name) \
+3 -3
View File
@@ -5,6 +5,7 @@
typedef struct x86emu_s x86emu_t;
typedef struct dynablock_s dynablock_t;
typedef struct instsize_s instsize_t;
#define BARRIER_MAYBE 8
@@ -95,16 +96,15 @@ typedef struct dynarec_arm_s {
uintptr_t* next; // variable array of "next" jump address
int next_sz;
int next_cap;
uintptr_t* sons_x86; // the x86 address of potential dynablock sons
void** sons_arm; // the arm address of potential dynablock sons
int sons_size; // number of potential dynablock sons
int* predecessor;// single array of all predecessor
dynablock_t* dynablock;
instsize_t* instsize;
} dynarec_arm_t;
void add_next(dynarec_arm_t *dyn, uintptr_t addr);
uintptr_t get_closest_next(dynarec_arm_t *dyn, uintptr_t addr);
int is_nops(dynarec_arm_t *dyn, uintptr_t addr, int n);
int is_instructions(dynarec_arm_t *dyn, uintptr_t addr, int n);
void CreateJmpNextTo(void* addr, void* tonext);
#endif //__DYNAREC_ARM_PRIVATE_H_
+8
View File
@@ -0,0 +1,8 @@
#ifndef __DYNAREC_NEXT_H__
#define __DYNAREC_NEXT_H__
void arm_next(void) EXPORTDYN;
void arm_prolog(x86emu_t* emu, void* addr) EXPORTDYN;
void arm_epilog() EXPORTDYN;
#endif //__DYNAREC_NEXT_H__
+2 -2
View File
@@ -1558,7 +1558,7 @@ void* ElfSetBrk(void* newbrk)
}
#ifdef DYNAREC
dynablocklist_t* GetDynablocksFromAddress(box86context_t *context, uintptr_t addr)
dynablock_t* GetDynablocksFromAddress(box86context_t *context, uintptr_t addr)
{
// if we are here, the there is not block in standard "space"
/*dynablocklist_t* ret = getDBFromAddress(addr);
@@ -1567,7 +1567,7 @@ dynablocklist_t* GetDynablocksFromAddress(box86context_t *context, uintptr_t add
}*/
if(box86_dynarec_forced) {
addDBFromAddressRange(addr, 1);
return getDB(addr>>DYNAMAP_SHIFT);
return getDB(addr);
}
//check if address is in an elf... if yes, grant a block (should I warn)
Dl_info info;
-4
View File
@@ -1,10 +1,6 @@
#ifndef __ELFLOADER_PRIVATE_H_
#define __ELFLOADER_PRIVATE_H_
#ifdef DYNAREC
typedef struct dynablocklist_s dynablocklist_t;
#endif
typedef struct library_s library_t;
typedef struct needed_libs_s needed_libs_t;
typedef struct kh_mapsymbols_s kh_mapsymbols_t;
+1 -1
View File
@@ -27,7 +27,6 @@ typedef struct atfork_fnc_s {
} atfork_fnc_t;
#ifdef DYNAREC
typedef struct dynablock_s dynablock_t;
typedef struct dynablocklist_s dynablocklist_t;
typedef struct mmaplist_s mmaplist_t;
typedef struct kh_dynablocks_s kh_dynablocks_t;
#endif
@@ -131,6 +130,7 @@ typedef struct box86context_s {
pthread_mutex_t mutex_lock; // dynarec build will use their own mecanism
#else
pthread_mutex_t mutex_dyndump;
uintptr_t max_db_size; // the biggest (in x86_64 instructions bytes) built dynablock
int trace_dynarec;
#endif
pthread_mutex_t mutex_tls;
+8 -3
View File
@@ -18,7 +18,6 @@ void customFree(void* p);
#ifdef DYNAREC
typedef struct dynablock_s dynablock_t;
typedef struct dynablocklist_s dynablocklist_t;
// custom protection flag to mark Page that are Write protected for Dynarec purpose
uintptr_t AllocDynarecMap(dynablock_t* db, int size);
void FreeDynarecMap(dynablock_t* db, uintptr_t addr, uint32_t size);
@@ -26,12 +25,15 @@ void FreeDynarecMap(dynablock_t* db, uintptr_t addr, uint32_t size);
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);
dynablock_t* getDB(uintptr_t addr);
int addJumpTableIfDefault(void* addr, void* jmp); // return 1 if write was succesfull
void setJumpTableIfRef(void* addr, void* jmp, void* ref); // return 1 if write was succesfull
void setJumpTableDefault(void* addr);
void setJumpTableDefaultRef(void* addr, void* jmp);
int isJumpTableDefault(void* addr);
uintptr_t getJumpTable();
uintptr_t getJumpTableAddress(uintptr_t addr);
uintptr_t getJumpAddress(uintptr_t addr);
#endif
#define PROT_DYNAREC 0x80
@@ -47,6 +49,9 @@ void loadProtectionFromMap();
#ifdef DYNAREC
void protectDB(uintptr_t addr, uintptr_t size);
void unprotectDB(uintptr_t addr, uintptr_t size, int mark); // if mark==0, the blocks are not marked as potentially dirty
int IsInHotPage(uintptr_t addr);
int AreaInHotPage(uintptr_t start, uintptr_t end);
void AddHotPage(uintptr_t addr);
#endif
void* find32bitBlock(size_t size);
void* findBlockNearHint(void* hint, size_t size);
+3 -13
View File
@@ -3,31 +3,21 @@
typedef struct x86emu_s x86emu_t;
typedef struct dynablock_s dynablock_t;
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 direct);
void FreeDynablockList(dynablocklist_t** dynablocks);
void FreeDynablock(dynablock_t* db, int need_lock);
void MarkDynablock(dynablock_t* db);
void FreeRangeDynablock(dynablocklist_t* dynablocks, uintptr_t addr, uintptr_t size);
void MarkRangeDynablock(dynablocklist_t* dynablocks, uintptr_t addr, uintptr_t size);
void MarkRangeDynablock(dynablock_t* db, uintptr_t addr, uintptr_t size);
int FreeRangeDynablock(dynablock_t* db, uintptr_t addr, uintptr_t size);
dynablock_t* FindDynablockFromNativeAddress(void* addr); // defined in box86context.h
dynablock_t* FindDynablockDynablocklist(void* addr, kh_dynablocks_t* dynablocks);
uintptr_t StartDynablockList(dynablocklist_t* db);
uintptr_t EndDynablockList(dynablocklist_t* db);
void MarkDirectDynablock(dynablocklist_t* dynablocks, uintptr_t addr, uintptr_t size);
// Handling of Dynarec block (i.e. an exectable chunk of x86 translated code)
dynablock_t* DBGetBlock(x86emu_t* emu, uintptr_t addr, int create, dynablock_t** current); // return NULL if block is not found / cannot be created. Don't create if create==0
dynablock_t* DBGetBlock(x86emu_t* emu, uintptr_t addr, int create); // return NULL if block is not found / cannot be created. Don't create if create==0
dynablock_t* DBAlternateBlock(x86emu_t* emu, uintptr_t addr, uintptr_t filladdr);
// Create and Add an new dynablock in the list, handling direct/map
dynablock_t *AddNewDynablock(dynablocklist_t* dynablocks, uintptr_t addr, int* created);
// for use in signal handler
void cancelFillBlock();
+2 -3
View File
@@ -10,7 +10,7 @@ typedef struct box86context_s box86context_t;
typedef struct x86emu_s x86emu_t;
typedef struct needed_libs_s needed_libs_t;
#ifdef DYNAREC
typedef struct dynablocklist_s dynablocklist_t;
typedef struct dynablock_s dynablock_t;
#endif
elfheader_t* LoadAndCheckElfHeader(FILE* f, const char* name, int exec); // exec : 0 = lib, 1 = exec
@@ -49,8 +49,7 @@ uint32_t GetTLSSize(elfheader_t* h);
void* GetTLSPointer(box86context_t* context, elfheader_t* h);
void* GetDTatOffset(box86context_t* context, int index, int offset);
#ifdef DYNAREC
dynablocklist_t* GetDynablocksFromAddress(box86context_t* context, uintptr_t addr);
dynablocklist_t* GetDynablocksFromElf(elfheader_t* h);
dynablock_t* GetDynablocksFromAddress(box86context_t *context, uintptr_t addr);
#endif
void ResetSpecialCaseMainElf(elfheader_t* h);
void CreateMemorymapFile(box86context_t* context, int fd);
+13 -3
View File
@@ -744,12 +744,22 @@ void my_box86signalhandler(int32_t sig, siginfo_t* info, void * ucntx)
dynablock_t* db = NULL;
int db_searched = 0;
if ((sig==SIGSEGV) && (addr) && (info->si_code == SEGV_ACCERR) && (prot&PROT_CUSTOM)) {
// access error, unprotect the block (and mark them dirty)
unprotectDB((uintptr_t)addr, 1, 1); // unprotect 1 byte... But then, the whole page will be unprotected
// check if SMC inside block
db = FindDynablockFromNativeAddress(pc);
db_searched = 1;
dynarec_log(LOG_INFO/*LOG_DEBUG*/, "SIGSEGV with Access error on %p for %p , db=%p(%p)\n", pc, addr, db, db?((void*)db->x86_addr):NULL);
static uintptr_t repeated_page = 0;
dynarec_log(LOG_DEBUG, "SIGSEGV with Access error on %p for %p , db=%p(%p), prot=0x%x (old page=%p)\n", pc, addr, db, db?((void*)db->x86_addr):NULL, prot, (void*)repeated_page);
static int repeated_count = 0;
if(repeated_page == ((uintptr_t)addr&~0xfff)) {
++repeated_count; // Access eoor multiple time on same page, disable dynarec on this page a few time...
dynarec_log(LOG_DEBUG, "Detecting a Hotpage at %p (%d)\n", (void*)repeated_page, repeated_count);
AddHotPage(repeated_page);
} else {
repeated_page = (uintptr_t)addr&~0xfff;
repeated_count = 0;
}
// access error, unprotect the block (and mark them dirty)
unprotectDB((uintptr_t)addr, 1, 1); // unprotect 1 byte... But then, the whole page will be unprotected
if(db && ((addr>=db->x86_addr && addr<(db->x86_addr+db->x86_size)) || db->need_test)) {
// dynablock got auto-dirty! need to get out of it!!!
emu_jmpbuf_t* ejb = GetJmpBuf();
+2 -4
View File
@@ -322,8 +322,7 @@ EXPORT int my_pthread_create(x86emu_t *emu, void* t, void* attr, void* start_rou
#ifdef DYNAREC
if(box86_dynarec) {
// pre-creation of the JIT code for the entry point of the thread
dynablock_t *current = NULL;
DBGetBlock(emu, (uintptr_t)start_routine, 1, &current);
DBGetBlock(emu, (uintptr_t)start_routine, 1);
}
#endif
// create thread
@@ -346,8 +345,7 @@ void* my_prepare_thread(x86emu_t *emu, void* f, void* arg, int ssize, void** pet
#ifdef DYNAREC
if(box86_dynarec) {
// pre-creation of the JIT code for the entry point of the thread
dynablock_t *current = NULL;
DBGetBlock(emu, (uintptr_t)f, 1, &current);
DBGetBlock(emu, (uintptr_t)f, 1);
}
#endif
*pet = et;