about summary refs log tree commit diff stats
path: root/src
diff options
context:
space:
mode:
authorptitSeb <sebastien.chev@gmail.com>2022-07-03 00:06:19 +0200
committerptitSeb <sebastien.chev@gmail.com>2022-07-03 00:06:19 +0200
commitde30d37ba91b093d459365a93ea9cc4418fc502a (patch)
treef61e6ffa33ee86a83b242ab9a250ca3b79dee161 /src
parente2b6e32fe9326c3ed9a3a89b039a2544d48bf030 (diff)
downloadbox64-de30d37ba91b093d459365a93ea9cc4418fc502a.tar.gz
box64-de30d37ba91b093d459365a93ea9cc4418fc502a.zip
Reworked TLS to limit resizing, as it tends to break Unity3D games
Diffstat (limited to 'src')
-rwxr-xr-xsrc/box64context.c2
-rwxr-xr-xsrc/elfs/elfloader.c12
-rwxr-xr-xsrc/emu/x64tls.c81
-rwxr-xr-xsrc/include/box64context.h6
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);