diff options
| author | ptitSeb <sebastien.chev@gmail.com> | 2022-07-03 00:06:19 +0200 |
|---|---|---|
| committer | ptitSeb <sebastien.chev@gmail.com> | 2022-07-03 00:06:19 +0200 |
| commit | de30d37ba91b093d459365a93ea9cc4418fc502a (patch) | |
| tree | f61e6ffa33ee86a83b242ab9a250ca3b79dee161 /src | |
| parent | e2b6e32fe9326c3ed9a3a89b039a2544d48bf030 (diff) | |
| download | box64-de30d37ba91b093d459365a93ea9cc4418fc502a.tar.gz box64-de30d37ba91b093d459365a93ea9cc4418fc502a.zip | |
Reworked TLS to limit resizing, as it tends to break Unity3D games
Diffstat (limited to 'src')
| -rwxr-xr-x | src/box64context.c | 2 | ||||
| -rwxr-xr-x | src/elfs/elfloader.c | 12 | ||||
| -rwxr-xr-x | src/emu/x64tls.c | 81 | ||||
| -rwxr-xr-x | src/include/box64context.h | 6 |
4 files changed, 68 insertions, 33 deletions
diff --git a/src/box64context.c b/src/box64context.c index 909184f6..ef5b6c54 100755 --- a/src/box64context.c +++ b/src/box64context.c @@ -63,7 +63,7 @@ void free_tlsdatasize(void* p) if(!p) return; tlsdatasize_t *data = (tlsdatasize_t*)p; - free(data->tlsdata); + free(data->ptr); free(p); } diff --git a/src/elfs/elfloader.c b/src/elfs/elfloader.c index 07328726..44582846 100755 --- a/src/elfs/elfloader.c +++ b/src/elfs/elfloader.c @@ -1152,12 +1152,10 @@ void RefreshElfTLS(elfheader_t* h) memcpy(dest, (void*)(h->tlsaddr+h->delta), h->tlsfilesize); tlsdatasize_t* ptr; if ((ptr = (tlsdatasize_t*)pthread_getspecific(my_context->tlskey)) != NULL) - if(ptr->tlssize==my_context->tlssize) { - // refresh in tlsdata too - dest = (char*)(ptr->tlsdata+ptr->tlssize+h->tlsbase); - printf_dump(LOG_DEBUG, "Refreshing active TLS block @%p from %p:0x%lx\n", dest, (void*)h->tlsaddr, h->tlssize-h->tlsfilesize); - memcpy(dest, (void*)(h->tlsaddr+h->delta), h->tlsfilesize); - } + // refresh in tlsdata too + dest = (char*)(ptr->data+h->tlsbase); + printf_dump(LOG_DEBUG, "Refreshing active TLS block @%p from %p:0x%lx\n", dest, (void*)h->tlsaddr, h->tlssize-h->tlsfilesize); + memcpy(dest, (void*)(h->tlsaddr+h->delta), h->tlsfilesize); } } @@ -1392,7 +1390,7 @@ void* GetTLSPointer(box64context_t* context, elfheader_t* h) } if(ptr->tlssize != context->tlssize) ptr = (tlsdatasize_t*)resizeTLSData(context, ptr); - return ptr->tlsdata+(ptr->tlssize+h->tlsbase); + return ptr->data+h->tlsbase; } void* GetDynamicSection(elfheader_t* h) diff --git a/src/emu/x64tls.c b/src/emu/x64tls.c index 6ed576e2..8a8d26ce 100755 --- a/src/emu/x64tls.c +++ b/src/emu/x64tls.c @@ -182,34 +182,46 @@ int my_arch_prctl(x64emu_t *emu, int code, void* addr) uintptr_t ssp_base 0x78 .... padding .... 0x200? */ +static int sizeDTS(box64context_t* context) +{ + return ((context->elfsize+0xff)&~0xff)*16; +} +static int sizeTLSData(int s) +{ + return (s+0xfff)&~0xfff; +} static tlsdatasize_t* setupTLSData(box64context_t* context) { // Setup the GS segment: - int dtsize = context->elfsize*16; - void *ptr = (char*)malloc(context->tlssize+8+POS_TLS+dtsize); - memcpy(ptr, context->tlsdata, context->tlssize); + int dtssize = sizeDTS(context); + int datasize = sizeTLSData(context->tlssize); + void *ptr_oversized = (char*)malloc(dtssize+POS_TLS+datasize); + void *ptr = (void*)((uintptr_t)ptr_oversized + datasize); + memcpy((void*)((uintptr_t)ptr-context->tlssize), context->tlsdata, context->tlssize); tlsdatasize_t *data = (tlsdatasize_t*)calloc(1, sizeof(tlsdatasize_t)); - data->tlsdata = ptr; + data->data = ptr; data->tlssize = context->tlssize; + data->ptr = ptr_oversized; + data->n_elfs = context->elfsize; pthread_setspecific(context->tlskey, data); // copy canary... - memset((void*)((uintptr_t)ptr+context->tlssize), 0, POS_TLS+dtsize); // set to 0 remining bytes - memcpy((void*)((uintptr_t)ptr+context->tlssize+0x28), context->canary, sizeof(void*)); // put canary in place - uintptr_t tlsptr = (uintptr_t)ptr+context->tlssize; - memcpy((void*)((uintptr_t)ptr+context->tlssize+0x0), &tlsptr, sizeof(void*)); - memcpy((void*)((uintptr_t)ptr+context->tlssize+0x10), &tlsptr, sizeof(void*)); // set tcb and self same address - uintptr_t dtp = (uintptr_t)ptr+context->tlssize+POS_TLS; + memset((void*)((uintptr_t)ptr), 0, POS_TLS+dtssize); // set to 0 remining bytes + memcpy((void*)((uintptr_t)ptr+0x28), context->canary, sizeof(void*)); // put canary in place + uintptr_t tlsptr = (uintptr_t)ptr; + memcpy((void*)((uintptr_t)ptr+0x0), &tlsptr, sizeof(void*)); + memcpy((void*)((uintptr_t)ptr+0x10), &tlsptr, sizeof(void*)); // set tcb and self same address + uintptr_t dtp = (uintptr_t)ptr+POS_TLS; memcpy((void*)(tlsptr+sizeof(void*)), &dtp, sizeof(void*)); - if(dtsize) { + if(dtssize) { for (int i=0; i<context->elfsize; ++i) { // set pointer - dtp = (uintptr_t)ptr + (context->tlssize + GetTLSBase(context->elfs[i])); - *(uint64_t*)((uintptr_t)ptr+context->tlssize+POS_TLS+i*16) = dtp; - *(uint64_t*)((uintptr_t)ptr+context->tlssize+POS_TLS+i*16+8) = i; // index + dtp = (uintptr_t)ptr + GetTLSBase(context->elfs[i]); + *(uint64_t*)((uintptr_t)ptr+POS_TLS+i*16) = dtp; + *(uint64_t*)((uintptr_t)ptr+POS_TLS+i*16+8) = i; // index } } - memcpy((void*)((uintptr_t)ptr+context->tlssize+0x20), &context->vsyscall, sizeof(void*)); // address of vsyscall + memcpy((void*)((uintptr_t)ptr+0x20), &context->vsyscall, sizeof(void*)); // address of vsyscall return data; } @@ -225,13 +237,36 @@ void* resizeTLSData(box64context_t *context, void* oldptr) { pthread_mutex_lock(&context->mutex_tls); tlsdatasize_t* oldata = (tlsdatasize_t*)oldptr; - tlsdatasize_t *data = setupTLSData(context); - // copy the relevent old part, in case something changed - memcpy((void*)((uintptr_t)data->tlsdata+(context->tlssize-oldata->tlssize)), oldata->tlsdata, oldata->tlssize); - // all done, update new size, free old pointer and exit - pthread_mutex_unlock(&context->mutex_tls); - free_tlsdatasize(oldptr); - return data; + if(sizeTLSData(oldata->tlssize)!=sizeTLSData(context->tlssize) || (oldata->n_elfs/0xff)!=(context->elfsize/0xff)) { + tlsdatasize_t *data = setupTLSData(context); + // copy the relevent old part, in case something changed + memcpy((void*)((uintptr_t)data->data-oldata->tlssize), (void*)((uintptr_t)oldata->data-oldata->tlssize), oldata->tlssize); + // all done, update new size, free old pointer and exit + pthread_mutex_unlock(&context->mutex_tls); + free_tlsdatasize(oldptr); + return data; + } else { + // keep the same tlsdata, but fill in the blanks + // adjust tlsdata + void *ptr = oldata->data; + if(context->tlssize!=oldata->tlssize) { + memcpy((void*)((uintptr_t)ptr-context->tlssize), context->tlsdata, context->tlssize-oldata->tlssize); + oldata->tlssize = context->tlssize; + } + // adjust DTS + if(oldata->n_elfs!=context->elfsize) { + uintptr_t dtp = (uintptr_t)ptr+POS_TLS; + for (int i=oldata->n_elfs; i<context->elfsize; ++i) { + // set pointer + dtp = (uintptr_t)ptr + GetTLSBase(context->elfs[i]); + *(uint64_t*)((uintptr_t)ptr+POS_TLS+i*16) = dtp; + *(uint64_t*)((uintptr_t)ptr+POS_TLS+i*16+8) = i; // index + } + oldata->n_elfs = context->elfsize; + } + pthread_mutex_unlock(&context->mutex_tls); + return oldata; + } } static void* GetSeg33Base() @@ -242,7 +277,7 @@ static void* GetSeg33Base() } if(ptr->tlssize != my_context->tlssize) ptr = (tlsdatasize_t*)resizeTLSData(my_context, ptr); - return ptr->tlsdata+ptr->tlssize; + return ptr->data; } void* GetSegmentBase(uint32_t desc) diff --git a/src/include/box64context.h b/src/include/box64context.h index 1a4fd077..1ec9855e 100755 --- a/src/include/box64context.h +++ b/src/include/box64context.h @@ -38,8 +38,10 @@ typedef void* (*vkprocaddess_t)(void* instance, const char* name); #define MAX_SIGNAL 64 typedef struct tlsdatasize_s { - int32_t tlssize; - void* tlsdata; + int tlssize; + int n_elfs; + void* data; + void* ptr; } tlsdatasize_t; void free_tlsdatasize(void* p); |