about summary refs log tree commit diff stats
path: root/src/emu/x64tls.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/emu/x64tls.c')
-rw-r--r--src/emu/x64tls.c81
1 files changed, 58 insertions, 23 deletions
diff --git a/src/emu/x64tls.c b/src/emu/x64tls.c
index 78f83c74..99ae188c 100644
--- a/src/emu/x64tls.c
+++ b/src/emu/x64tls.c
@@ -11,6 +11,9 @@
 #include "x64emu_private.h"
 #include "x64tls.h"
 #include "elfloader.h"
+#ifdef BOX32
+#include "box32.h"
+#endif
 
 typedef struct thread_area_s
 {
@@ -118,12 +121,19 @@ uint32_t my_modify_ldt(x64emu_t* emu, int op, thread_area_t* td, int size)
         return (uint32_t)-1;
     }
 
-    /*
-    my_context->segtls[idx].base = td->base_addr;
-    my_context->segtls[idx].limit = td->limit;
-    pthread_setspecific(my_context->segtls[idx].key, (void*)my_context->segtls[idx].base);
-    */
-    
+    if(box64_is32bits) {
+        emu->segs_serial[_GS] = 0;
+        my_context->segtls[idx].base = td->base_addr;
+        my_context->segtls[idx].limit = td->limit;
+        my_context->segtls[idx].present = 1;
+        if(idx>8 && !my_context->segtls[idx].key_init) {
+            pthread_key_create(&my_context->segtls[idx].key, NULL);
+            my_context->segtls[idx].key_init = 1;
+        }
+        if(my_context->segtls[idx].key_init)
+            pthread_setspecific(my_context->segtls[idx].key, (void*)my_context->segtls[idx].base);
+    }
+
     ResetSegmentsCache(emu);
 
     return 0;
@@ -220,6 +230,7 @@ int my_arch_prctl(x64emu_t *emu, int code, void* addr)
 
 
 #define POS_TLS     0x200
+#define POS_TLS_32  0x50
 /*
  tls record should looks like:
  void*      tcb             0x00
@@ -255,7 +266,7 @@ static tlsdatasize_t* setupTLSData(box64context_t* context)
     // Setup the GS segment:
     int dtssize = sizeDTS(context);
     int datasize = sizeTLSData(context->tlssize);
-    void *ptr_oversized = (char*)box_malloc(dtssize+POS_TLS+datasize);
+    void *ptr_oversized = (char*)box_malloc(dtssize+(box64_is32bits?POS_TLS_32: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*)box_calloc(1, sizeof(tlsdatasize_t));
@@ -264,23 +275,45 @@ static tlsdatasize_t* setupTLSData(box64context_t* context)
     data->ptr = ptr_oversized;
     data->n_elfs = context->elfsize;
     pthread_setspecific(context->tlskey, data);
-    // copy canary...
-    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(dtssize) {
-        for (int i=0; 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
+    #ifdef BOX32
+    if(box64_is32bits) {
+        // copy canary...
+        memset((void*)((uintptr_t)ptr), 0, POS_TLS_32+dtssize);        // set to 0 remining bytes
+        memcpy((void*)((uintptr_t)ptr+0x14), context->canary, 4);      // put canary in place
+        ptr_t tlsptr = to_ptrv(ptr);
+        memcpy((void*)((uintptr_t)ptr+0x0), &tlsptr, 4);
+        ptr_t dtp = to_ptrv(ptr+POS_TLS_32);
+        memcpy(from_ptrv(tlsptr+0x4), &dtp, 4);
+        if(dtssize) {
+            for (int i=0; i<context->elfsize; ++i) {
+                // set pointer
+                dtp = to_ptrv(ptr + GetTLSBase(context->elfs[i]));
+                memcpy((void*)((uintptr_t)ptr+POS_TLS_32+i*8), &dtp, 4);
+                memcpy((void*)((uintptr_t)ptr+POS_TLS_32+i*8+4), &i, 4); // index
+            }
         }
+        memcpy((void*)((uintptr_t)ptr+0x10), &context->vsyscall, 4);  // address of vsyscall
+    } else
+    #endif
+    {
+        // copy canary...
+        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(dtssize) {
+            for (int i=0; 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
+            }
+        }
+        memcpy((void*)((uintptr_t)ptr+0x20), &context->vsyscall, sizeof(void*));  // address of vsyscall
     }
-    memcpy((void*)((uintptr_t)ptr+0x20), &context->vsyscall, sizeof(void*));  // address of vsyscall
     return data;
 }
 
@@ -356,7 +389,9 @@ void* GetSegmentBase(uint32_t desc)
         return NULL;
     }
     int base = desc>>3;
-    if(base==0x8 && !my_context->segtls[base].key_init)
+    if(!box64_is32bits && base==0x8 && !my_context->segtls[base].key_init)
+        return GetSeg43Base();
+    if(box64_is32bits && (base==0x6))
         return GetSeg43Base();
     if(base>15) {
         printf_log(LOG_NONE, "Warning, accessing segment unknown 0x%x or unset\n", desc);