about summary refs log tree commit diff stats
path: root/src/emu
diff options
context:
space:
mode:
Diffstat (limited to 'src/emu')
-rw-r--r--src/emu/x64emu.c57
-rw-r--r--src/emu/x64emu_private.h6
-rw-r--r--src/emu/x64int3.c14
-rw-r--r--src/emu/x64run.c10
-rw-r--r--src/emu/x64run64.c10
-rw-r--r--src/emu/x64run_private.c53
-rw-r--r--src/emu/x64run_private.h21
-rw-r--r--src/emu/x64tls.c81
-rwxr-xr-xsrc/emu/x86int3.c347
-rwxr-xr-xsrc/emu/x86syscall.c2
-rw-r--r--src/emu/x86syscall_32.c447
-rw-r--r--src/emu/x87emu_private.c18
12 files changed, 1011 insertions, 55 deletions
diff --git a/src/emu/x64emu.c b/src/emu/x64emu.c
index f0865299..ddfa0fc6 100644
--- a/src/emu/x64emu.c
+++ b/src/emu/x64emu.c
@@ -64,11 +64,29 @@ static void internalX64Setup(x64emu_t* emu, box64context_t *context, uintptr_t s
     // set default value
     R_RIP = start;
     R_RSP = (stack + stacksize) & ~7;   // align stack start, always
+    #ifdef BOX32
+    if(box64_is32bits) {
+        if(stack>=0x100000000LL) {
+            printf_log(LOG_NONE, "BOX32: Stack pointer too high (%p), aborting\n", (void*)stack);
+            abort();
+        }
+        if(R_RSP>=0x100000000LL) {    // special case, stack is just a bit too high
+            R_RSP = 0x100000000LL - 16;
+        }
+    }
+    #endif
     // fake init of segments...
-    emu->segs[_CS] = 0x33;
-    emu->segs[_DS] = emu->segs[_ES] = emu->segs[_SS] = 0x2b;
-    emu->segs[_FS] = 0x43;
-    emu->segs[_GS] = default_gs;
+    if(box64_is32bits) {
+        emu->segs[_CS] = 0x23;
+        emu->segs[_DS] = emu->segs[_ES] = emu->segs[_SS] = 0x2b;
+        emu->segs[_FS] = default_fs;
+        emu->segs[_GS] = 0x33;
+    } else {
+        emu->segs[_CS] = 0x33;
+        emu->segs[_DS] = emu->segs[_ES] = emu->segs[_SS] = 0x2b;
+        emu->segs[_FS] = 0x43;
+        emu->segs[_GS] = default_gs;
+    }
     // setup fpu regs
     reset_fpu(emu);
     emu->mxcsr.x32 = 0x1f80;
@@ -77,7 +95,7 @@ static void internalX64Setup(x64emu_t* emu, box64context_t *context, uintptr_t s
 EXPORTDYN
 x64emu_t *NewX64Emu(box64context_t *context, uintptr_t start, uintptr_t stack, int stacksize, int ownstack)
 {
-    printf_log(LOG_DEBUG, "Allocate a new X86_64 Emu, with EIP=%p and Stack=%p/0x%X\n", (void*)start, (void*)stack, stacksize);
+    printf_log(LOG_DEBUG, "Allocate a new X86_64 Emu, with %cIP=%p and Stack=%p/0x%X\n", box64_is32bits?'E':'R', (void*)start, (void*)stack, stacksize);
 
     x64emu_t *emu = (x64emu_t*)box_calloc(1, sizeof(x64emu_t));
 
@@ -161,7 +179,7 @@ void CallCleanup(x64emu_t *emu, elfheader_t* h)
     if(!h)
         return;
     for(int i=h->clean_sz-1; i>=0; --i) {
-        printf_log(LOG_DEBUG, "Call cleanup #%d\n", i);
+        printf_log(LOG_DEBUG, "Call cleanup #%d (args:%d, arg:%p)\n", i, h->cleanups[i].arg, h->cleanups[i].a);
         RunFunctionWithEmu(emu, 0, (uintptr_t)(h->cleanups[i].f), h->cleanups[i].arg, h->cleanups[i].a );
         // now remove the cleanup
         if(i!=h->clean_sz-1)
@@ -325,10 +343,14 @@ void SetEBP(x64emu_t *emu, uint32_t v)
 {
     R_EBP = v;
 }
-//void SetESP(x64emu_t *emu, uint32_t v)
-//{
-//    R_ESP = v;
-//}
+void SetESP(x64emu_t *emu, uint32_t v)
+{
+    R_ESP = v;
+}
+void SetEIP(x64emu_t *emu, uint32_t v)
+{
+    R_EIP = v;
+}
 void SetRAX(x64emu_t *emu, uint64_t v)
 {
     R_RAX = v;
@@ -373,7 +395,7 @@ uint64_t GetRBP(x64emu_t *emu)
 {
     return R_RBP;
 }
-/*void SetFS(x64emu_t *emu, uint16_t v)
+void SetFS(x64emu_t *emu, uint16_t v)
 {
     emu->segs[_FS] = v;
     emu->segs_serial[_FS] = 0;
@@ -381,7 +403,7 @@ uint64_t GetRBP(x64emu_t *emu)
 uint16_t GetFS(x64emu_t *emu)
 {
     return emu->segs[_FS];
-}*/
+}
 
 
 void ResetFlags(x64emu_t *emu)
@@ -572,9 +594,14 @@ void EmuCall(x64emu_t* emu, uintptr_t addr)
     uint64_t old_rip = R_RIP;
     //Push64(emu, GetRBP(emu));   // set frame pointer
     //SetRBP(emu, GetRSP(emu));   // save RSP
-    R_RSP -= 200;
-    R_RSP &= ~63LL;
-    PushExit(emu);
+    //R_RSP -= 200;
+    //R_RSP &= ~63LL;
+    #ifdef BOX32
+    if(box64_is32bits)
+        PushExit_32(emu);
+    else
+    #endif
+        PushExit(emu);
     R_RIP = addr;
     emu->df = d_none;
     Run(emu, 0);
diff --git a/src/emu/x64emu_private.h b/src/emu/x64emu_private.h
index bef4a9a4..35bfd97e 100644
--- a/src/emu/x64emu_private.h
+++ b/src/emu/x64emu_private.h
@@ -5,6 +5,9 @@
 
 typedef struct box64context_s box64context_t;
 typedef struct x64_ucontext_s x64_ucontext_t;
+#ifdef BOX32
+typedef struct i386_ucontext_s i386_ucontext_t;
+#endif
 
 #define ERR_UNIMPL  1
 #define ERR_DIVBY0  2
@@ -116,6 +119,7 @@ typedef struct x64emu_s {
     uintptr_t   prev2_ip;
     #endif
     // scratch stack, used for alignment of double and 64bits ints on arm. 200 elements should be enough
+    __int128_t  dummy_align;    // here to have scratch 128bits aligned
     uint64_t    scratch[200];
     // local stack, do be deleted when emu is freed
     void*       stack2free; // this is the stack to free (can be NULL)
@@ -126,7 +130,7 @@ typedef struct x64emu_s {
     uintptr_t   old_savedsp;
     #endif
 
-    x64_ucontext_t *uc_link; // to handle setcontext
+    void*       uc_link; // to handle setcontext (can be x64_ucontext_t or a i386_ucontext_t)
 
     int         type;       // EMUTYPE_xxx define
 } x64emu_t;
diff --git a/src/emu/x64int3.c b/src/emu/x64int3.c
index dd1b439c..b0f452a2 100644
--- a/src/emu/x64int3.c
+++ b/src/emu/x64int3.c
@@ -88,6 +88,10 @@ static uint8_t Peek8(uintptr_t addr, uintptr_t offset)
 
 void x64Int3(x64emu_t* emu, uintptr_t* addr)
 {
+    if(box64_is32bits) {
+        x86Int3(emu,addr);
+        return;
+    }
     onebridge_t* bridge = (onebridge_t*)(*addr-1);
     if(Peek8(*addr, 0)=='S' && Peek8(*addr, 1)=='C') // Signature for "Out of x86 door"
     {
@@ -393,4 +397,12 @@ void print_cycle_log(int loglevel) {
             }
         }
     }
-}
\ No newline at end of file
+}
+
+#ifndef BOX32
+void x86Int3(x64emu_t* emu, uintptr_t* addr)
+{
+    printf_log(LOG_NONE, "Error: Calling 32bits wrapped function without box32 support built in\n");
+    abort();
+}
+#endif
\ No newline at end of file
diff --git a/src/emu/x64run.c b/src/emu/x64run.c
index 614bf91c..fbb92d1a 100644
--- a/src/emu/x64run.c
+++ b/src/emu/x64run.c
@@ -27,6 +27,9 @@
 #include "modrm.h"
 
 int my_setcontext(x64emu_t* emu, void* ucp);
+#ifdef BOX32
+int my32_setcontext(x64emu_t* emu, void* ucp);
+#endif
 
 #ifdef TEST_INTERPRETER
 int RunTest(x64test_t *test)
@@ -2232,7 +2235,12 @@ if(emu->segs[_CS]!=0x33 && emu->segs[_CS]!=0x23) printf_log(LOG_NONE, "Warning,
     // setcontext handling
     else if(emu->quit && emu->uc_link) {
         emu->quit = 0;
-        my_setcontext(emu, emu->uc_link);
+        #ifdef BOX32
+        if(box64_is32bits)
+            my32_setcontext(emu, emu->uc_link);
+        else
+        #endif
+            my_setcontext(emu, emu->uc_link);
         addr = R_RIP;
         goto x64emurun;
     }
diff --git a/src/emu/x64run64.c b/src/emu/x64run64.c
index fe8da3e5..7ceef8ab 100644
--- a/src/emu/x64run64.c
+++ b/src/emu/x64run64.c
@@ -639,7 +639,15 @@ uintptr_t Run64(x64emu_t *emu, rex_t rex, int seg, uintptr_t addr)
                     R_RAX = *(uint32_t*)(tlsdata+tmp64u);

             }

             break;

-

+        case 0xA2:                      /* MOV Ob,AL */

+            if(rex.is32bits) {

+                tmp32s = F32S;

+                *(uint8_t*)(uintptr_t)(tlsdata+tmp32s) = R_AL;

+            } else {

+                tmp64u = F64;

+                *(uint8_t*)(tlsdata+tmp64u) = R_AL;

+            }

+            break;

         case 0xA3:                      /* MOV FS:Od,EAX */

             if(rex.is32bits) {

                 tmp32s = F32S;

diff --git a/src/emu/x64run_private.c b/src/emu/x64run_private.c
index f94025ee..6055101a 100644
--- a/src/emu/x64run_private.c
+++ b/src/emu/x64run_private.c
@@ -24,6 +24,9 @@
 #endif
 #include "x64tls.h"
 #include "bridge.h"
+#ifdef BOX32
+#include "box32.h"
+#endif
 
 #define PARITY(x)   (((emu->x64emu_parity_tab[(x) / 32] >> ((x) % 32)) & 1) == 0)
 #define XOR2(x)     (((x) ^ ((x)>>1)) & 0x1)
@@ -53,7 +56,7 @@ void EXPORT my___libc_init(x64emu_t* emu, void* raw_args , void (*onexit)(void)
     emu->quit = 1; // finished!
 }
 #else
-int32_t EXPORT my___libc_start_main(x64emu_t* emu, int (*main) (int, char * *, char * *), int argc, char * * ubp_av, void (*init) (void), void (*fini) (void), void (*rtld_fini) (void), void (* stack_end))
+EXPORT int32_t my___libc_start_main(x64emu_t* emu, int (*main) (int, char * *, char * *), int argc, char * * ubp_av, void (*init) (void), void (*fini) (void), void (*rtld_fini) (void), void (* stack_end))
 {
     (void)argc; (void)ubp_av; (void)fini; (void)rtld_fini; (void)stack_end;
 
@@ -106,6 +109,54 @@ int32_t EXPORT my___libc_start_main(x64emu_t* emu, int (*main) (int, char * *, c
     }
     return (int)GetEAX(emu);
 }
+#ifdef BOX32
+#ifdef ANDROID
+void EXPORT my32___libc_init(x64emu_t* emu, void* raw_args , void (*onexit)(void) , int (*main)(int, char**, char**), void const * const structors )
+{
+    //TODO: register fini
+    // let's cheat and set all args...
+    Push_32(emu, (uint32_t)my_context->envv32);
+    Push_32(emu, (uint32_t)my_context->argv32);
+    Push_32(emu, (uint32_t)my_context->argc);
+
+    printf_log(LOG_DEBUG, "Transfert to main(%d, %p, %p)=>%p from __libc_init\n", my_context->argc, my_context->argv, my_context->envv, main);
+    // should call structors->preinit_array and structors->init_array!
+    // call main and finish
+    PushExit_32(emu);
+    R_EIP=to_ptrv(main);
+
+    DynaRun(emu);
+
+    emu->quit = 1; // finished!
+}
+#else
+int32_t EXPORT my32___libc_start_main(x64emu_t* emu, int *(main) (int, char * *, char * *), int argc, char * * ubp_av, void (*init) (void), void (*fini) (void), void (*rtld_fini) (void), void (* stack_end))
+{
+    // let's cheat and set all args...
+    Push_32(emu, my_context->envv32);
+    Push_32(emu, my_context->argv32);
+    Push_32(emu, my_context->argc);
+    if(init) {
+        PushExit_32(emu);
+        R_EIP=to_ptrv(*init);
+        printf_log(LOG_DEBUG, "Calling init(%p) from __libc_start_main\n", *init);
+        DynaRun(emu);
+        if(emu->error)  // any error, don't bother with more
+            return 0;
+        emu->quit = 0;
+    }
+    printf_log(LOG_DEBUG, "Transfert to main(%d, %p, %p)=>%p from __libc_start_main\n", my_context->argc, my_context->argv, my_context->envv, main);
+    // call main and finish
+    PushExit_32(emu);
+    R_EIP=to_ptrv(main);
+
+    DynaRun(emu);
+
+    emu->quit = 1; // finished!
+    return 0;
+}
+#endif
+#endif
 #endif
 
 const char* GetNativeName(void* p)
diff --git a/src/emu/x64run_private.h b/src/emu/x64run_private.h
index 45a68659..925e14d5 100644
--- a/src/emu/x64run_private.h
+++ b/src/emu/x64run_private.h
@@ -50,6 +50,12 @@ static inline void Push16(x64emu_t *emu, uint16_t v)
     *((uint16_t*)R_RSP) = v;
 }
 
+static inline void Push_32(x64emu_t *emu, uint32_t v)
+{
+    R_ESP -= 4;
+    *((uint32_t*)(uintptr_t)R_ESP) = v;
+}
+
 static inline void Push32(x64emu_t *emu, uint32_t v)
 {
     R_RSP -= 4;
@@ -70,6 +76,13 @@ static inline uint16_t Pop16(x64emu_t *emu)
     return *st;
 }
 
+static inline uint32_t Pop_32(x64emu_t *emu)
+{
+    uint32_t* st = (uint32_t*)(uintptr_t)R_RSP;
+    R_ESP += 4;
+    return *st;
+}
+
 static inline uint32_t Pop32(x64emu_t *emu)
 {
     uint32_t* st = (uint32_t*)R_RSP;
@@ -90,6 +103,13 @@ static inline void PushExit(x64emu_t* emu)
     *((uint64_t*)R_RSP) = my_context->exit_bridge;
 }
 
+#ifdef BOX32
+static inline void PushExit_32(x64emu_t* emu)
+{
+    R_ESP -= 4;
+    *((ptr_t*)(uintptr_t)R_ESP) = my_context->exit_bridge;
+}
+#endif
 // the op code definition can be found here: http://ref.x86asm.net/geek32.html
 
 reg64_t* GetECommon(x64emu_t* emu, uintptr_t* addr, rex_t rex, uint8_t m, uint8_t delta);
@@ -232,6 +252,7 @@ void x64Syscall(x64emu_t *emu);
 void x64Int3(x64emu_t* emu, uintptr_t* addr);
 x64emu_t* x64emu_fork(x64emu_t* e, int forktype);
 void x86Syscall(x64emu_t *emu); //32bits syscall
+void x86Int3(x64emu_t* emu, uintptr_t* addr);
 
 uintptr_t GetSegmentBaseEmu(x64emu_t* emu, int seg);
 #define GetGSBaseEmu(emu)    GetSegmentBaseEmu(emu, _GS)
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);
diff --git a/src/emu/x86int3.c b/src/emu/x86int3.c
new file mode 100755
index 00000000..73f5b3ae
--- /dev/null
+++ b/src/emu/x86int3.c
@@ -0,0 +1,347 @@
+#define _GNU_SOURCE         /* See feature_test_macros(7) */
+#include <dlfcn.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <pthread.h>
+#include <signal.h>
+
+#include "debug.h"
+#include "box64stack.h"
+#include "x64emu.h"
+#include "x64run.h"
+#include "x64emu_private.h"
+#include "x64run_private.h"
+#include "x87emu_private.h"
+#include "x64primop.h"
+#include "x64trace.h"
+#include "wrapper32.h"
+#include "box32context.h"
+#include "librarian.h"
+#include "signals.h"
+#include "tools/bridge_private.h"
+
+#include <elf.h>
+#include "elfloader.h"
+#include "elfload_dump.h"
+#include "elfs/elfloader_private.h"
+
+typedef int32_t (*iFpppp_t)(void*, void*, void*, void*);
+
+static uint64_t F64(uintptr_t* addr) {
+    uint64_t ret = *(uint64_t*)*addr;
+    *addr+=8;
+    return ret;
+}
+static uint8_t Peek8(uintptr_t addr, uintptr_t offset)
+{
+    return *(uint8_t*)(addr+offset);
+}
+
+extern int errno;
+void x86Int3(x64emu_t* emu, uintptr_t* addr)
+{
+    onebridge_t* bridge = (onebridge_t*)(*addr-1);
+    if(Peek8(*addr, 0)=='S' && Peek8(*addr, 1)=='C') // Signature for "Out of x86 door"
+    {
+        *addr += 2;
+        uintptr_t a = F64(addr);
+        if(a==0) {
+            R_RIP = *addr;
+            //printf_log(LOG_INFO, "%p:Exit x86 emu (emu=%p)\n", *(void**)(R_ESP), emu);
+            emu->quit=1; // normal quit
+        } else {
+            RESET_FLAGS(emu);
+            wrapper_t w = bridge->w;
+            a = F64(addr);
+            R_RIP = *addr;
+            /* This party can be used to trace only 1 specific lib (but it is quite slow)
+            elfheader_t *h = FindElfAddress(my_context, *(uintptr_t*)(R_ESP));
+            int have_trace = 0;
+            if(h && strstr(ElfName(h), "libMiles")) have_trace = 1;*/
+            if(box64_log>=LOG_DEBUG || cycle_log) {
+                int tid = GetTID();
+                char t_buff[256] = "\0";
+                char buff2[64] = "\0";
+                char buff3[64] = "\0";
+                int cycle_line = my_context->current_line;
+                if(cycle_log) {
+                    my_context->current_line = (my_context->current_line+1)%cycle_log;
+                }
+                char* buff = cycle_log?my_context->log_call[cycle_line]:t_buff;
+                char* buffret = cycle_log?my_context->log_ret[cycle_line]:NULL;
+                if(buffret) buffret[0] = '\0';
+                char *tmp;
+                int post = 0;
+                int perr = 0;
+                uint64_t *pu64 = NULL;
+                uint32_t *pu32 = NULL;
+                uint8_t *pu8 = NULL;
+                const char *s = bridge->name;
+                if(!s)
+                    s = GetNativeName((void*)a);
+                if(a==(uintptr_t)PltResolver32) {
+                    if(cycle_log) {
+                        ptr_t addr = *((uint32_t*)from_ptrv(R_ESP));
+                        int slot = *((uint32_t*)from_ptrv(R_ESP+4));
+                        elfheader_t *h = (elfheader_t*)from_ptrv(addr);
+                        Elf32_Rel * rel = (Elf32_Rel *)from_ptrv(h->jmprel + h->delta + slot);
+                        Elf32_Sym *sym = &h->DynSym._32[ELF32_R_SYM(rel->r_info)];
+                        const char* symname = SymName32(h, sym);
+                        snprintf(buff, 256, "%04d|PltResolver \"%s\"", tid, symname?symname:"???");
+                    } else {
+                        snprintf(buff, 256, "%s", " ... ");
+                    }
+                } else
+                if(strstr(s, "SDL_RWFromFile")==s || strstr(s, "SDL_RWFromFile")==s) {
+                    snprintf(buff, 255, "%04d|%p: Calling %s(%s, %s)", tid, *(void**)from_ptr(R_ESP), s, from_ptrv(*(ptr_t*)from_ptr(R_ESP+4)), from_ptrv(*(ptr_t*)from_ptr(R_ESP+8)));
+                } else  if(strstr(s, "glColor4f")==s) {
+                    snprintf(buff, 255, "%04d|%p: Calling %s(%f, %f, %f, %f)", tid, *(void**)from_ptr(R_ESP), s, *(float*)from_ptr(R_ESP+4), *(float*)from_ptr(R_ESP+8), *(float*)from_ptr(R_ESP+12), *(float*)from_ptr(R_ESP+16));
+                } else  if(strstr(s, "glTexCoord2f")==s) {
+                    snprintf(buff, 255, "%04d|%p: Calling %s(%f, %f)", tid, *(void**)from_ptr(R_ESP), s, *(float*)from_ptr(R_ESP+4), *(float*)from_ptr(R_ESP+8));
+                } else  if(strstr(s, "glVertex2f")==s) {
+                    snprintf(buff, 255, "%04d|%p: Calling %s(%f, %f)", tid, *(void**)from_ptr(R_ESP), s, *(float*)from_ptr(R_ESP+4), *(float*)from_ptr(R_ESP+8));
+                } else  if(strstr(s, "glVertex3f")==s) {
+                    snprintf(buff, 255, "%04d|%p: Calling %s(%f, %f, %f)", tid, *(void**)from_ptr(R_ESP), s, *(float*)from_ptr(R_ESP+4), *(float*)from_ptr(R_ESP+8), *(float*)from_ptr(R_ESP+12));
+                } else  if(strstr(s, "__open64")==s || strcmp(s, "open64")==0) {
+                    snprintf(buff, 255, "%04d|%p: Calling %s(\"%s\", %d, %d)", tid, *(void**)from_ptr(R_ESP), s, from_ptrv(*(ptr_t*)from_ptr(R_ESP+4)), *(int*)from_ptr(R_ESP+8), *(int*)from_ptr(R_ESP+12));
+                    perr = 1;
+                } else  if(!strcmp(s, "opendir")) {
+                    snprintf(buff, 255, "%04d|%p: Calling %s(\"%s\")", tid, *(void**)from_ptr(R_ESP), s, from_ptrv(*(ptr_t*)from_ptr(R_ESP+4)));
+                    perr = 1;
+                } else  if(strstr(s, "__open")==s || !strcmp(s, "open") || !strcmp(s, "my_open64")) {
+                    tmp = from_ptrv(*(ptr_t*)from_ptr(R_ESP+4));
+                    snprintf(buff, 255, "%04d|%p: Calling %s(\"%s\", %d (,%d))", tid, *(void**)from_ptr(R_ESP), s, (tmp)?tmp:"(nil)", *(int*)from_ptr(R_ESP+8), *(int*)from_ptr(R_ESP+12));
+                    perr = 1;
+                } else  if(!strcmp(s, "shm_open")) {
+                    tmp = from_ptrv(*(ptr_t*)from_ptr(R_ESP+4));
+                    snprintf(buff, 255, "%04d|%p: Calling %s(\"%s\", %d, %d)", tid, *(void**)from_ptr(R_ESP), s, (tmp)?tmp:"(nil)", *(int*)from_ptr(R_ESP+8), *(int*)from_ptr(R_ESP+12));
+                    perr = 1;
+                } else  if(strcmp(s, "mkdir")==0) {
+                    tmp = from_ptrv(*(ptr_t*)from_ptr(R_ESP+4));
+                    snprintf(buff, 255, "%04d|%p: Calling %s(\"%s\", %d)", tid, *(void**)from_ptr(R_ESP), s, (tmp)?tmp:"(nil)", *(int*)from_ptr(R_ESP+8));
+                    perr = 1;
+                } else  if(!strcmp(s, "fopen")) {
+                    snprintf(buff, 255, "%04d|%p: Calling %s(\"%s\", \"%s\")", tid, *(void**)from_ptr(R_ESP), s, from_ptrv(*(ptr_t*)from_ptr(R_ESP+4)), from_ptrv(*(ptr_t*)from_ptr(R_ESP+8)));
+                    perr = 2;
+                } else  if(!strcmp(s, "freopen")) {
+                    snprintf(buff, 255, "%04d|%p: Calling %s(\"%s\", \"%s\", %p)", tid, *(void**)from_ptr(R_ESP), s, from_ptrv(*(ptr_t*)from_ptr(R_ESP+4)), from_ptrv(*(ptr_t*)from_ptr(R_ESP+8)), *(void**)from_ptr(R_ESP+12));
+                    perr = 2;
+                } else  if(!strcmp(s, "fopen64")) {
+                    snprintf(buff, 255, "%04d|%p: Calling %s(\"%s\", \"%s\")", tid, *(void**)from_ptr(R_ESP), s, from_ptrv(*(ptr_t*)from_ptr(R_ESP+4)), from_ptrv(*(ptr_t*)from_ptr(R_ESP+8)));
+                    perr = 2;
+                } else  if(!strcmp(s, "chdir")) {
+                    pu32=*(uint32_t**)from_ptr(R_ESP+4);
+                    snprintf(buff, 255, "%04d|%p: Calling %s(\"%s\")", tid, *(void**)from_ptr(R_ESP), s, pu32?((pu32==(uint32_t*)1)?"/1/":(char*)pu32):"/0/");
+                } else  if(strstr(s, "getenv")==s) {
+                    snprintf(buff, 255, "%04d|%p: Calling %s(\"%s\")", tid, *(void**)from_ptr(R_ESP), s, from_ptrv(*(ptr_t*)from_ptr(R_ESP+4)));
+                    post = 2;
+                } else  if(strstr(s, "putenv")==s) {
+                    snprintf(buff, 255, "%04d|%p: Calling %s(\"%s\")", tid, *(void**)from_ptr(R_ESP), s, from_ptrv(*(ptr_t*)from_ptr(R_ESP+4)));
+                } else  if(strstr(s, "pread")==s) {
+                    snprintf(buff, 255, "%04d|%p: Calling %s(%d, %p, %u, %d)", tid, *(void**)from_ptr(R_ESP), s, *(int32_t*)from_ptr(R_ESP+4), *(void**)from_ptr(R_ESP+8), *(uint32_t*)from_ptr(R_ESP+12), *(int32_t*)from_ptr(R_ESP+16));
+                    perr = 1;
+                } else  if(!strcmp(s, "read")) {
+                    snprintf(buff, 255, "%04d|%p: Calling %s(%d, %p, %u)", tid, *(void**)from_ptr(R_ESP), s, *(int32_t*)from_ptr(R_ESP+4), *(void**)from_ptr(R_ESP+8), *(uint32_t*)from_ptr(R_ESP+12));
+                    perr = 1;
+                } else  if(strstr(s, "ioctl")==s) {
+                    snprintf(buff, 255, "%04d|%p: Calling %s(%d, 0x%x, %p)", tid, *(void**)from_ptr(R_ESP), s, *(int32_t*)from_ptr(R_ESP+4), *(int32_t*)from_ptr(R_ESP+8), *(void**)from_ptr(R_ESP+12));
+                    perr = 1;
+                } else  if(strstr(s, "statvfs64")==s) {
+                    snprintf(buff, 255, "%04d|%p: Calling %s(%p(\"%s\"), %p)", tid, *(void**)from_ptr(R_ESP), s, *(void**)from_ptr(R_ESP+4), from_ptrv(*(ptr_t*)from_ptr(R_ESP+4)), *(void**)from_ptr(R_ESP+8));
+                } else  if(strstr(s, "index")==s) {
+                    snprintf(buff, 255, "%04d|%p: Calling %s(%p(\"%s\"), %i(%c))", tid, *(void**)from_ptr(R_ESP), s, from_ptrv(*(ptr_t*)from_ptr(R_ESP+4)), from_ptrv(*(ptr_t*)from_ptr(R_ESP+4)), *(int32_t*)from_ptr(R_ESP+8), *(int32_t*)from_ptr(R_ESP+8));
+                } else  if(strstr(s, "rindex")==s) {
+                    snprintf(buff, 255, "%04d|%p: Calling %s(%p(\"%s\"), %i(%c))", tid, *(void**)from_ptr(R_ESP), s, from_ptrv(*(ptr_t*)from_ptr(R_ESP+4)), from_ptrv(*(ptr_t*)from_ptr(R_ESP+4)), *(int32_t*)from_ptr(R_ESP+8), *(int32_t*)from_ptr(R_ESP+8));
+                } else  if(strstr(s, "__xstat64")==s) {
+                    snprintf(buff, 255, "%04d|%p: Calling %s(%d, %p(\"%s\"), %p)", tid, *(void**)from_ptr(R_ESP), s, *(int32_t*)from_ptr(R_ESP+4), from_ptrv(*(ptr_t*)from_ptr(R_ESP+8)), from_ptrv(*(ptr_t*)from_ptr(R_ESP+8)), *(void**)from_ptr(R_ESP+12));
+                    perr = 1;
+                } else  if(strcmp(s, "__xstat")==0) {
+                    snprintf(buff, 255, "%04d|%p: Calling %s(%d, %p(\"%s\"), %p)", tid, *(void**)from_ptr(R_ESP), s, *(int32_t*)from_ptr(R_ESP+4), from_ptrv(*(ptr_t*)from_ptr(R_ESP+8)), from_ptrv(*(ptr_t*)from_ptr(R_ESP+8)), *(void**)from_ptr(R_ESP+12));
+                    perr = 1;
+                } else  if(strstr(s, "__lxstat64")==s) {
+                    snprintf(buff, 255, "%04d|%p: Calling %s(%d, %p(\"%s\"), %p)", tid, *(void**)from_ptr(R_ESP), s, *(int32_t*)from_ptr(R_ESP+4), from_ptrv(*(ptr_t*)from_ptr(R_ESP+8)), from_ptrv(*(ptr_t*)from_ptr(R_ESP+8)), *(void**)from_ptr(R_ESP+12));
+                    perr = 1;
+                } else  if(strstr(s, "sem_timedwait")==s) {
+                    pu32 = (uint32_t*)from_ptr(*(ptr_t*)from_ptr(R_ESP+8));
+                    snprintf(buff, 255, "%04d|%p: Calling %s(%p, %p[%d sec %d ns])", tid, *(void**)from_ptr(R_ESP), s, *(void**)from_ptr(R_ESP+4), *(void**)from_ptr(R_ESP+8), pu32?pu32[0]:-1, pu32?pu32[1]:-1);
+                    perr = 1;
+                } else  if(strstr(s, "waitpid")==s) {
+                    snprintf(buff, 255, "%04d|%p: Calling %s(%d, %p, 0x%x)", tid, *(void**)from_ptr(R_ESP), s, *(int32_t*)from_ptr(R_ESP+4), *(void**)from_ptr(R_ESP+8), *(uint32_t*)from_ptr(R_ESP+12));
+                    perr = 1;
+                } else  if(strstr(s, "clock_gettime")==s || strstr(s, "__clock_gettime")==s) {
+                    snprintf(buff, 255, "%04d|%p: Calling %s(%d, %p)", tid, *(void**)from_ptr(R_ESP), s, *(uint32_t*)from_ptr(R_ESP+4), *(void**)from_ptr(R_ESP+8));
+                    post = 1;
+                    pu32 = (uint32_t*)from_ptr(*(ptr_t*)from_ptr(R_ESP+8));
+                } else  if(strstr(s, "semop")==s) {
+                    int16_t* p16 = *(int16_t**)from_ptr(R_ESP+8);
+                    snprintf(buff, 255, "%04d|%p: Calling %s(%d, %p[%u/%d/0x%x], %d)", tid, *(void**)from_ptr(R_ESP), s, *(int*)from_ptr(R_ESP+4), p16, p16[0], p16[1], p16[2], *(int*)from_ptr(R_ESP+12));
+                    perr = 1;
+                } else  if(!strcmp(s, "mmap64")) {
+                    snprintf(buff, 255, "%04d|%p: Calling %s(%p, 0x%x, %d, 0x%x, %d, %ld)", tid, *(void**)from_ptr(R_ESP), s, *(void**)from_ptr(R_ESP+4), *(ulong_t*)from_ptr(R_ESP+8), *(int*)from_ptr(R_ESP+12), *(int*)from_ptr(R_ESP+16), *(int*)from_ptr(R_ESP+20), *(int64_t*)from_ptr(R_ESP+24));
+                    perr = 3;
+                } else  if(!strcmp(s, "mmap")) {
+                    snprintf(buff, 255, "%04d|%p: Calling %s(%p, 0x%x, %d, 0x%x, %d, %d)", tid, *(void**)from_ptr(R_ESP), s, *(void**)from_ptr(R_ESP+4), *(ulong_t*)from_ptr(R_ESP+8), *(int*)from_ptr(R_ESP+12), *(int*)from_ptr(R_ESP+16), *(int*)from_ptr(R_ESP+20), *(int*)from_ptr(R_ESP+24));
+                    perr = 3;
+                } else  if(strstr(s, "strcasecmp")==s || strstr(s, "__strcasecmp")==s) {
+                    snprintf(buff, 255, "%04d|%p: Calling %s(\"%s\", \"%s\")", tid, *(void**)from_ptr(R_ESP), s, from_ptrv(*(ptr_t*)from_ptr(R_ESP+4)), from_ptrv(*(ptr_t*)from_ptr(R_ESP+8)));
+                } else  if(strstr(s, "gtk_signal_connect_full")) {
+                    snprintf(buff, 255, "%04d|%p: Calling %s(%p, \"%s\", %p, %p, %p, %p, %d, %d)", tid, *(void**)from_ptr(R_ESP), "gtk_signal_connect_full", *(void**)from_ptr(R_ESP+4), from_ptrv(*(ptr_t*)from_ptr(R_ESP+8)), *(void**)from_ptr(R_ESP+12), *(void**)from_ptr(R_ESP+16), *(void**)from_ptr(R_ESP+20), *(void**)from_ptr(R_ESP+24), *(int32_t*)from_ptr(R_ESP+28), *(int32_t*)from_ptr(R_ESP+32));
+                } else  if(strstr(s, "strcmp")==s || strstr(s, "__strcmp")==s) {
+                    snprintf(buff, 255, "%04d|%p: Calling %s(\"%s\", \"%s\")", tid, *(void**)from_ptr(R_ESP), s, from_ptrv(*(ptr_t*)from_ptr(R_ESP+4)), from_ptrv(*(ptr_t*)from_ptr(R_ESP+8)));
+                } else  if(strstr(s, "strstr")==s) {
+                    snprintf(buff, 255, "%04d|%p: Calling %s(\"%.127s\", \"%.127s\")", tid, *(void**)from_ptr(R_ESP), s, from_ptrv(*(ptr_t*)from_ptr(R_ESP+4)), from_ptrv(*(ptr_t*)from_ptr(R_ESP+8)));
+                } else  if(strstr(s, "strlen")==s) {
+                    snprintf(buff, 255, "%04d|%p: Calling %s(%p(\"%s\"))", tid, *(void**)from_ptr(R_ESP), s, from_ptrv(*(ptr_t*)from_ptr(R_ESP+4)), ((R_ESP+4))?((char*)from_ptrv(*(ptr_t*)from_ptr(R_ESP+4))):"nil");
+                } else  if(strstr(s, "vsnprintf")==s) {
+                    snprintf(buff, 255, "%04d|%p: Calling %s(%08X, %u, %08X...)", tid, *(void**)from_ptr(R_ESP), s, *(uint32_t*)from_ptr(R_ESP+4), *(uint32_t*)from_ptr(R_ESP+8), *(uint32_t*)from_ptr(R_ESP+12));
+                    pu32 = (uint32_t*)from_ptr(*(ptr_t*)from_ptr(R_ESP+4));
+                    post = 3;
+                } else  if(strstr(s, "vsprintf")==s) {
+                    snprintf(buff, 255, "%04d|%p: Calling %s(%p, \"%s\", %p)", tid, *(void**)from_ptr(R_ESP), s, *(void**)from_ptr(R_ESP+4), from_ptrv(*(ptr_t*)from_ptr(R_ESP+8)), *(void**)from_ptr(R_ESP+12));
+                    pu32 = (uint32_t*)from_ptr(*(ptr_t*)from_ptr(R_ESP+4));
+                    post = 3;
+                } else  if(strstr(s, "__vsprintf_chk")==s) {
+                    snprintf(buff, 255, "%04d|%p: Calling %s(%p, %d, %zu, \"%s\", %p)", tid, *(void**)from_ptr(R_ESP), s, *(void**)from_ptr(R_ESP+4), *(int*)from_ptr(R_ESP+8), *(size_t*)from_ptr(R_ESP+12), from_ptrv(*(ptr_t*)from_ptr(R_ESP+16)), *(void**)from_ptr(R_ESP+20));
+                    pu32 = (uint32_t*)from_ptr(*(ptr_t*)from_ptr(R_ESP+4));
+                    post = 3;
+                } else  if(strstr(s, "__snprintf_chk")==s) {
+                    snprintf(buff, 255, "%04d|%p: Calling %s(%p, %zu, %d, %d, \"%s\", %p)", tid, *(void**)from_ptr(R_ESP), s, *(void**)from_ptr(R_ESP+4), *(size_t*)from_ptr(R_ESP+8), *(int*)from_ptr(R_ESP+12), *(int*)from_ptr(R_ESP+16), from_ptrv(*(ptr_t*)from_ptr(R_ESP+20)), *(void**)from_ptr(R_ESP+24));
+                    pu32 = (uint32_t*)from_ptr(*(ptr_t*)from_ptr(R_ESP+4));
+                    post = 3;
+                } else  if(strstr(s, "snprintf")==s) {
+                    snprintf(buff, 255, "%04d|%p: Calling %s(%p, %zu, \"%s\", ...)", tid, *(void**)from_ptr(R_ESP), s, *(void**)from_ptr(R_ESP+4), *(size_t*)from_ptr(R_ESP+8), from_ptrv(*(ptr_t*)from_ptr(R_ESP+12)));
+                    pu32 = (uint32_t*)from_ptr(*(ptr_t*)from_ptr(R_ESP+4));
+                    post = 3;
+                } else  if(strstr(s, "sprintf")==s) {
+                    snprintf(buff, 255, "%04d|%p: Calling %s(%08X, %08X...)", tid, *(void**)from_ptr(R_ESP), s, *(uint32_t*)from_ptr(R_ESP+4), *(uint32_t*)from_ptr(R_ESP+8));
+                    pu32 = (uint32_t*)from_ptr(*(ptr_t*)from_ptr(R_ESP+4));
+                    post = 3;
+                } else  if(strstr(s, "printf")==s) {
+                    pu32 = (uint32_t*)from_ptr(*(ptr_t*)from_ptr(R_ESP+4));
+                    if(((uintptr_t)pu32)<0x5) // probably a _chk function
+                        pu32 = (uint32_t*)from_ptr(*(ptr_t*)from_ptr(R_ESP+8));
+                    snprintf(buff, 255, "%04d|%p: Calling %s(\"%s\"...)", tid, *(void**)from_ptr(R_ESP), s, pu32?((char*)(pu32)):"nil");
+                } else  if(strstr(s, "__printf_chk")==s) {
+                    pu32 = (uint32_t*)from_ptr(*(ptr_t*)from_ptr(R_ESP+8));
+                    snprintf(buff, 255, "%04d|%p: Calling %s(%d, \"%s\", ...)", tid, *(void**)from_ptr(R_ESP), s, from_ptri(int, R_ESP+4), pu32?((char*)(pu32)):"nil");
+                } else  if(strstr(s, "wprintf")==s) {
+                    pu32 = (uint32_t*)from_ptr(*(ptr_t*)from_ptr(R_ESP+4));
+                    if(((uintptr_t)pu32)<0x5) // probably a _chk function
+                        pu32 = (uint32_t*)from_ptr(*(ptr_t*)from_ptr(R_ESP+8));
+                    snprintf(buff, 255, "%04d|%p: Calling %s(\"%S\"...)", tid, *(void**)from_ptr(R_ESP), s, pu32?((wchar_t*)(pu32)):L"nil");
+                } else  if(strstr(s, "__vswprintf")==s) {
+                    if(*(size_t*)from_ptr(R_ESP+12)<2) {
+                        snprintf(buff, 255, "%04d|%p: Calling %s(%p, %u, %p, %p, %p)", tid, *(void**)from_ptr(R_ESP), s, *(void**)from_ptr(R_ESP+4), *(ulong_t*)from_ptr(R_ESP+8), *(void**)from_ptr(R_ESP+12), *(void**)from_ptr(R_ESP+16), *(void**)from_ptr(R_ESP+20));
+                    } else {
+                        snprintf(buff, 255, "%04d|%p: Calling %s(%p, %u, \"%S\", %p)", tid, *(void**)from_ptr(R_ESP), s, *(void**)from_ptr(R_ESP+4), *(ulong_t*)from_ptr(R_ESP+8), *(wchar_t**)from_ptr(R_ESP+12), *(void**)from_ptr(R_ESP+16));
+                        pu32 = (uint32_t*)from_ptr(*(ptr_t*)from_ptr(R_ESP+4));
+                        post = 6;
+                    }
+                } else  if(strstr(s, "puts")==s) {
+                    snprintf(buff, 255, "%04d|%p: Calling %s(\"%s\"...)", tid, *(void**)from_ptr(R_ESP), s, from_ptrv(*(ptr_t*)from_ptr(R_ESP+4)));
+                } else  if(strstr(s, "fputs")==s) {
+                    snprintf(buff, 255, "%04d|%p: Calling %s(\"%s\", %p...)", tid, *(void**)from_ptr(R_ESP), s, from_ptrv(*(ptr_t*)from_ptr(R_ESP+4)), *(void**)from_ptr(R_ESP+8));
+                } else  if(strstr(s, "fprintf")==s) {
+                    pu32 = (uint32_t*)from_ptr(*(ptr_t*)from_ptr(R_ESP+8));
+                    if(((uintptr_t)pu32)<0x5) // probably a __fprint_chk
+                        pu32 = (uint32_t*)from_ptr(*(ptr_t*)from_ptr(R_ESP+12));
+                    snprintf(buff, 255, "%04d|%p: Calling %s(%08X, \"%s\", ...)", tid, *(void**)from_ptr(R_ESP), s, *(uint32_t*)from_ptr(R_ESP+4), pu32?((char*)(pu32)):"nil");
+                } else  if(strstr(s, "vfprintf")==s) {
+                    pu32 = (uint32_t*)from_ptr(*(ptr_t*)from_ptr(R_ESP+8));
+                    if(((uintptr_t)pu32)<0x5) // probably a _chk function
+                        pu32 = (uint32_t*)from_ptr(*(ptr_t*)from_ptr(R_ESP+12));
+                    snprintf(buff, 255, "%04d|%p: Calling %s(%08X, \"%s\", ...)", tid, *(void**)from_ptr(R_ESP), s, *(uint32_t*)from_ptr(R_ESP+4), pu32?((char*)(pu32)):"nil");
+                } else  if(strstr(s, "vkGetInstanceProcAddr")==s) {
+                    snprintf(buff, 255, "%04d|%p: Calling %s(%p, \"%s\")", tid, *(void**)from_ptr(R_ESP), s, *(void**)from_ptr(R_ESP+4), from_ptrv(*(ptr_t*)from_ptr(R_ESP+8)));
+                } else  if(strstr(s, "vkGetDeviceProcAddr")==s) {
+                    snprintf(buff, 255, "%04d|%p: Calling %s(%p, \"%s\")", tid, *(void**)from_ptr(R_ESP), s, *(void**)from_ptr(R_ESP+4), from_ptrv(*(ptr_t*)from_ptr(R_ESP+8)));
+                } else  if(strstr(s, "glXGetProcAddress")==s) {
+                    snprintf(buff, 255, "%04d|%p: Calling %s(\"%s\")", tid, *(void**)from_ptr(R_ESP), s, from_ptrv(*(ptr_t*)from_ptr(R_ESP+4)));
+                } else  if(strstr(s, "sscanf")==s) {
+                    snprintf(buff, 255, "%04d|%p: Calling %s(\"%s\", \"%s\", ...)", tid, *(void**)from_ptr(R_ESP), s, from_ptrv(*(ptr_t*)from_ptr(R_ESP+4)), from_ptrv(*(ptr_t*)from_ptr(R_ESP+8)));
+                } else  if(!strcmp(s, "vsscanf")) {
+                    snprintf(buff, 255, "%04d|%p: Calling %s(\"%s\", \"%s\", ...)", tid, *(void**)from_ptr(R_ESP), s, from_ptrv(*(ptr_t*)from_ptr(R_ESP+4)), from_ptrv(*(ptr_t*)from_ptr(R_ESP+8)));
+                } else if(strstr(s, "XCreateWindow")==s) {
+                    snprintf(buff, 255, "%04d|%p: Calling %s(%p, %p, %d, %d, %u, %u, %u, %d, %u, %p, %u, %p)", tid, *(void**)from_ptr(R_ESP), s, *(void**)from_ptr(R_ESP+4), *(void**)from_ptr(R_ESP+8), *(int*)from_ptr(R_ESP+12), *(int*)from_ptr(R_ESP+16), *(uint32_t*)from_ptr(R_ESP+20), *(uint32_t*)from_ptr(R_ESP+24), *(uint32_t*)from_ptr(R_ESP+28), *(int32_t*)from_ptr(R_ESP+32), *(uint32_t*)from_ptr(R_ESP+36), *(void**)from_ptr(R_ESP+40), *(uint32_t*)from_ptr(R_ESP+44), *(void**)from_ptr(R_ESP+48));
+                } else if(strstr(s, "XLoadQueryFont")==s) {
+                    snprintf(buff, 255, "%04d|%p: Calling %s(%p, \"%s\")", tid, *(void**)from_ptr(R_ESP), s, *(void**)from_ptr(R_ESP+4), from_ptrv(*(ptr_t*)from_ptr(R_ESP+8)));
+                } else if(strstr(s, "pthread_mutex_lock")==s) {
+                    snprintf(buff, 255, "%04d|%p: Calling %s(%p)", tid, *(void**)from_ptr(R_ESP), s, *(void**)from_ptr(R_ESP+4));
+                } else if(!strcmp(s, "fmodf")) {
+                    post = 4;
+                    snprintf(buff, 255, "%04d|%p: Calling %s(%f, %f)", tid, *(void**)from_ptr(R_ESP), s, *(float*)from_ptr(R_ESP+4), *(float*)from_ptr(R_ESP+8));
+                } else if(!strcmp(s, "fmod")) {
+                    post = 4;
+                    snprintf(buff, 255, "%04d|%p: Calling %s(%f, %f)", tid, *(void**)from_ptr(R_ESP), s, *(double*)from_ptr(R_ESP+4), *(double*)from_ptr(R_ESP+12));
+                } else if(strstr(s, "SDL_GetWindowSurface")==s) {
+                    post = 5;
+                    snprintf(buff, 255, "%04d|%p: Calling %s(%p)", tid, *(void**)from_ptr(R_ESP), s, *(void**)from_ptr(R_ESP+4));
+                } else if(strstr(s, "udev_monitor_new_from_netlink")==s) {
+                    post = 5;
+                    snprintf(buff, 255, "%04d|%p: Calling %s(%p, \"%s\")", tid, *(void**)from_ptr(R_ESP), s, *(void**)from_ptr(R_ESP+4), from_ptrv(*(ptr_t*)from_ptr(R_ESP+8)));
+                } else  if(!strcmp(s, "syscall")) {
+                    snprintf(buff, 255, "%04d|%p: Calling %s(%d, %p, %p, %p...)", tid, *(void**)from_ptr(R_ESP), s, *(int32_t*)from_ptr(R_ESP+4), *(void**)from_ptr(R_ESP+8), *(void**)from_ptr(R_ESP+12), *(void**)from_ptr(R_ESP+16));
+                    perr = 1;
+                } else {
+                    snprintf(buff, 255, "%04d|%p: Calling %s (%08X, %08X, %08X...)", tid, *(void**)from_ptr(R_ESP), s, *(uint32_t*)from_ptr(R_ESP+4), *(uint32_t*)from_ptr(R_ESP+8), *(uint32_t*)from_ptr(R_ESP+12));
+                }
+                if(!cycle_log) {
+                    mutex_lock(&emu->context->mutex_trace);
+                    printf_log(LOG_NONE, "%s =>", buff);
+                    mutex_unlock(&emu->context->mutex_trace);
+                }
+                w(emu, a);   // some function never come back, so unlock the mutex first!
+                if(post)
+                    switch(post) {
+                    case 1: snprintf(buff2, 63, " [%d sec %d nsec]", pu32?pu32[0]:-1, pu32?pu32[1]:-1);
+                            break;
+                    case 2: snprintf(buff2, 63, "(%s)", R_EAX?((char*)from_ptr(R_EAX)):"nil");
+                            break;
+                    case 3: snprintf(buff2, 63, "(%s)", pu32?((char*)pu32):"nil");
+                            break;
+                    case 4: snprintf(buff2, 63, " (%f)", ST0.d);
+                            break;
+                    case 5: {
+                            uint32_t* p = (uint32_t*)from_ptrv(R_EAX);
+                            if(p)
+                                snprintf(buff2, 63, " size=%dx%d, pitch=%d, pixels=%p", p[2], p[3], p[4], p+5);
+                            else
+                                snprintf(buff2, 63, "NULL Surface");
+                            }
+                            break;
+                    case 6: snprintf(buff2, 63, "(%S)", pu32?((wchar_t*)pu32):L"nil");
+                            break;
+                }
+                if(perr==1 && ((int)R_EAX)<0)
+                    snprintf(buff3, 63, " (errno=%d:\"%s\")", errno, strerror(errno));
+                else if(perr==2 && R_EAX==0)
+                    snprintf(buff3, 63, " (errno=%d:\"%s\")", errno, strerror(errno));
+                else if(perr==3 && ((int)R_EAX)==-1)
+                    snprintf(buff3, 63, " (errno=%d:\"%s\")", errno, strerror(errno));
+                if(cycle_log)
+                    snprintf(buffret, 128, "0x%lX%s%s", R_RAX, buff2, buff3);
+                else {
+                    mutex_lock(&emu->context->mutex_trace);
+                    printf_log(LOG_NONE, " return 0x%lX%s%s\n", R_RAX, buff2, buff3);
+                    mutex_unlock(&emu->context->mutex_trace);
+                }
+            } else
+                w(emu, a);
+        }
+        return;
+    }
+    if(!box64_ignoreint3 && my_context->signals[SIGTRAP]) {
+        R_RIP = *addr;  // update RIP
+        emit_signal(emu, SIGTRAP, NULL, 3);
+    } else {
+        printf_log(LOG_DEBUG, "%04d|Warning, ignoring unsupported Int 3 call @%p\n", GetTID(), (void*)R_RIP);
+        R_RIP = *addr;
+    }
+    //emu->quit = 1;
+}
diff --git a/src/emu/x86syscall.c b/src/emu/x86syscall.c
index 1d28a989..5a76a505 100755
--- a/src/emu/x86syscall.c
+++ b/src/emu/x86syscall.c
@@ -266,7 +266,7 @@ void EXPORT x86Syscall(x64emu_t *emu)
             R_EAX = R_EBX; // faking the syscall here, we don't want to really terminate the thread now
             break;
         /*case 123:   // SYS_modify_ldt
-            R_EAX = my_modify_ldt(emu, R_EBX, (thread_area_t*)(uintptr_t)R_ECX, R_EDX);
+            R_EAX = my32_modify_ldt(emu, R_EBX, (thread_area_t*)(uintptr_t)R_ECX, R_EDX);
             if(R_EAX==0xffffffff && errno>0)
                 R_EAX = (uint32_t)-errno;
             break;*/
diff --git a/src/emu/x86syscall_32.c b/src/emu/x86syscall_32.c
new file mode 100644
index 00000000..cae7b40b
--- /dev/null
+++ b/src/emu/x86syscall_32.c
@@ -0,0 +1,447 @@
+#define _GNU_SOURCE         /* See feature_test_macros(7) */
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <sys/syscall.h>   /* For SYS_xxx definitions */
+#include <unistd.h>
+#include <time.h>
+#include <sys/mman.h>
+#include <sys/select.h>
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <asm/stat.h>
+#include <errno.h>
+#include <sched.h>
+#include <sys/wait.h>
+#include <sys/utsname.h>
+#ifndef __NR_socketcall
+#include <linux/net.h>
+#include <sys/socket.h>
+#endif
+#include <sys/resource.h>
+#include <poll.h>
+
+#include "debug.h"
+#include "box64stack.h"
+#include "x64emu.h"
+#include "x64run.h"
+#include "x64emu_private.h"
+#include "x64trace.h"
+#include "myalign32.h"
+#include "box64context.h"
+#include "callback.h"
+#include "signals.h"
+#include "x64tls.h"
+#include "box32.h"
+
+
+// Syscall table for x86_64 can be found 
+typedef struct scwrap_s {
+    uint32_t x86s;
+    int nats;
+    int nbpars;
+} scwrap_t;
+
+static const scwrap_t syscallwrap[] = {
+    //{ 2, __NR_fork, 1 },  
+    //{ 3, __NR_read, 3 },  // wrapped so SA_RESTART can be handled by libc
+    //{ 4, __NR_write, 3 }, // same
+    //{ 5, __NR_open, 3 },  // flags need transformation
+    //{ 6, __NR_close, 1 },   // wrapped so SA_RESTART can be handled by libc
+    //{ 7, __NR_waitpid, 3 },
+    //{ 10, __NR_unlink, 1 },
+    //{ 12, __NR_chdir, 1 },
+    //{ 13, __NR_time, 1 },
+    //{ 15, __NR_chmod, 2 },
+    //{ 19, __NR_lseek, 3 },
+    //{ 20, __NR_getpid, 0 },
+    //{ 24, __NR_getuid, 0 },
+    //{ 33, __NR_access, 2 },
+    //{ 37, __NR_kill, 2 },
+    //{ 38, __NR_rename, 2 },
+    //{ 39, __NR_mkdir, 2 },
+    //{ 40, __NR_rmdir, 1 },
+    //{ 41, __NR_dup, 1 },
+    //{ 42, __NR_pipe, 1 },
+    //{ 45, __NR_brk, 1 },
+    //{ 47, __NR_getgid, 0 },
+    //{ 49, __NR_geteuid, 0 },
+    //{ 50, __NR_getegid, 0 },
+    //{ 54, __NR_ioctl, 3 },    // should be wrapped to allow SA_RESTART handling by libc, but syscall is only 3 arguments, ioctl can be 5
+    //{ 55, __NR_fcntl, 3 },    // wrapped to allow filter of F_SETFD
+    //{ 60, __NR_umask, 1 },
+    //{ 63, __NR_dup2, 2 },
+    //{ 64, __NR_getppid, 0 },
+    //{ 66, __NR_setsid, 0 },
+    //{ 75, __NR_setrlimit, 2 },
+    //{ 76, __NR_getrlimit, 2 },
+    //{ 77, __NR_getrusage, 2 },
+    //{ 78, __NR_gettimeofday, 2 },
+    //{ 83, __NR_symlink, 2 },
+    //{ 82, __NR_select, 5 },
+    //{ 85, __NR_readlink, 3 },
+    //{ 91, __NR_munmap, 2 },
+    //{ 94, __NR_fchmod, 2 },
+    //{ 99, __NR_statfs, 2 },
+    //{ 102, __NR_socketcall, 2 },
+    //{ 104, __NR_setitimer, 3 },
+    //{ 105, __NR_getitimer, 2 },
+    //{ 106, __NR_newstat, 2 },
+    //{ 106, __NR_stat, 2 },
+    //{ 107, __NR_newlstat, 2 },
+    //{ 107, __NR_lstat, 2 },
+    //{ 108, __NR_newfstat, 2 },
+    //{ 108, __NR_fstat, 2 },
+    //{ 109, __NR_olduname, 1 },
+    //{ 110, __NR_iopl, 1 },
+    //{ 114, __NR_wait4, 4 }, //TODO: check struct rusage alignment
+    //{ 117, __NR_ipc, 6 },
+    //{ 119, __NR_sigreturn, 0},
+    //{ 120, __NR_clone, 5 },    // need works
+    //{ 122, __NR_uname, 1 },
+    //{ 123, __NR_modify_ldt },
+    //{ 125, __NR_mprotect, 3 },
+    //{ 136, __NR_personality, 1 },
+    //{ 140, __NR__llseek, 5 },
+    //{ 141, __NR_getdents, 3 },
+    //{ 142, __NR__newselect, 5 },
+    //{ 143, __NR_flock,  2 },
+    //{ 144, __NR_msync, 3 },
+    //{ 145, __NR_readv, 3 },
+    //{ 146, __NR_writev, 3 },
+    //{ 148, __NR_fdatasync, 1 },
+    //{ 149, __NR__sysctl, 1 },    // need wrapping?
+    //{ 156, __NR_sched_setscheduler, 3 },
+    //{ 157, __NR_sched_getscheduler, 1 },
+    //{ 158, __NR_sched_yield, 0 },
+    //{ 162, __NR_nanosleep, 2 },
+    //{ 164, __NR_setresuid, 3 },
+    //{ 168, __NR_poll, 3 },    // wrapped to allow SA_RESTART wrapping by libc
+    //{ 172, __NR_prctl, 5 },
+    //{ 173, __NR_rt_sigreturn, 0 },
+    //{ 175, __NR_rt_sigprocmask, 4 },
+    //{ 179, __NR_rt_sigsuspend, 2 },
+    //{ 183, __NR_getcwd, 2 },
+    //{ 184, __NR_capget, 2},
+    //{ 185, __NR_capset, 2},
+    //{ 186, __NR_sigaltstack, 2 },    // neeed wrap or something?
+    //{ 191, __NR_ugetrlimit, 2 },
+//    { 192, __NR_mmap2, 6},
+    //{ 195, __NR_stat64, 2 },  // need proprer wrap because of structure size change
+    //{ 196, __NR_lstat64, 2 }, // need proprer wrap because of structure size change
+    //{ 197, __NR_fstat64, 2 },  // need proprer wrap because of structure size change
+    //{ 199, __NR_getuid32, 0 },
+    //{ 200, __NR_getgid32, 0 },
+    //{ 201, __NR_geteuid32, 0 },
+    //{ 202, __NR_getegid32, 0 },
+    //{ 208, __NR_setresuid32, 3 },
+    //{ 209, __NR_getresuid32, 3 },
+    //{ 210, __NR_setresgid32, 3 },
+    //{ 211, __NR_getresgid32, 3 },
+    //{ 220, __NR_getdents64, 3 },
+    //{ 221, __NR_fcntl64, 3 },
+    { 224, __NR_gettid, 0 },
+    //{ 240, __NR_futex, 6 },
+    //{ 241, __NR_sched_setaffinity, 3 },
+    //{ 242, __NR_sched_getaffinity, 3 },
+    //{ 252, __NR_exit_group, 1 },
+    //{ 254, __NR_epoll_create, 1 },
+    //{ 255, __NR_epoll_ctl, 4 },
+    //{ 256, __NR_epoll_wait, 4 },
+    //{ 265, __NR_clock_gettime, 2 },
+    //{ 266, __NR_clock_getres, 2 },
+    //{ 270, __NR_tgkill, 3 },
+    //{ 271, __NR_utimes, 2 },
+    //{ 291, __NR_inotify_init, 0},
+    //{ 292, __NR_inotify_add_watch, 3},
+    //{ 293, __NR_inotify_rm_watch, 2},
+    //{ 311, __NR_set_robust_list, 2 },
+    //{ 312, __NR_get_robust_list, 4 },
+    //{ 318, __NR_getcpu, 3},
+    //{ 328, __NR_eventfd2, 2},
+    //{ 329, __NR_epoll_create1, 1 },
+    //{ 331, __NR_pipe2, 2},
+    //{ 332, __NR_inotify_init1, 1},
+    //{ 355, __NR_getrandom, 3 },
+    //{ 356, __NR_memfd_create, 2},
+    //{ 449, __NR_futex_waitv, 5},
+};
+
+struct mmap_arg_struct {
+    unsigned long addr;
+    unsigned long len;
+    unsigned long prot;
+    unsigned long flags;
+    unsigned long fd;
+    unsigned long offset;
+};
+
+#undef st_atime
+#undef st_ctime
+#undef st_mtime
+
+struct x64_pt_regs {
+    long ebx;
+    long ecx;
+    long edx;
+    long esi;
+    long edi;
+    long ebp;
+    long eax;
+    int  xds;
+    int  xes;
+    int  xfs;
+    int  xgs;
+    long orig_eax;
+    long eip;
+    int  xcs;
+    long eflags;
+    long esp;
+    int  xss;
+};
+
+#ifndef __NR_olduname
+struct oldold_utsname {
+        char sysname[9];
+        char nodename[9];
+        char release[9];
+        char version[9];
+        char machine[9];
+};
+#endif
+struct old_utsname {
+        char sysname[65];
+        char nodename[65];
+        char release[65];
+        char version[65];
+        char machine[65];
+};
+
+struct i386_user_desc {
+    unsigned int  entry_number;
+    unsigned long base_addr;
+    unsigned int  limit;
+    unsigned int  seg_32bit:1;
+    unsigned int  contents:2;
+    unsigned int  read_exec_only:1;
+    unsigned int  limit_in_pages:1;
+    unsigned int  seg_not_present:1;
+    unsigned int  useable:1;
+};
+
+int32_t my32_open(x64emu_t* emu, void* pathname, int32_t flags, uint32_t mode);
+int32_t my32_execve(x64emu_t* emu, const char* path, char* const argv[], char* const envp[]);
+int my32_munmap(x64emu_t* emu, void* addr, unsigned long length);
+
+void EXPORT x86Syscall(x64emu_t *emu)
+{
+    uint32_t s = R_EAX;
+    printf_log(LOG_DEBUG, "%p: Calling 32bits syscall 0x%02X (%d) %p %p %p %p %p", (void*)R_RIP, s, s, (void*)(uintptr_t)R_EBX, (void*)(uintptr_t)R_ECX, (void*)(uintptr_t)R_EDX, (void*)(uintptr_t)R_ESI, (void*)(uintptr_t)R_EDI); 
+    // check wrapper first
+    int cnt = sizeof(syscallwrap) / sizeof(scwrap_t);
+    for (int i=0; i<cnt; i++) {
+        if(syscallwrap[i].x86s == s) {
+            int sc = syscallwrap[i].nats;
+            switch(syscallwrap[i].nbpars) {
+                case 0: *(int32_t*)&R_EAX = syscall(sc); break;
+                case 1: *(int32_t*)&R_EAX = syscall(sc, R_EBX); break;
+                case 2: *(int32_t*)&R_EAX = syscall(sc, R_EBX, R_ECX); break;
+                case 3: *(int32_t*)&R_EAX = syscall(sc, R_EBX, R_ECX, R_EDX); break;
+                case 4: *(int32_t*)&R_EAX = syscall(sc, R_EBX, R_ECX, R_EDX, R_ESI); break;
+                case 5: *(int32_t*)&R_EAX = syscall(sc, R_EBX, R_ECX, R_EDX, R_ESI, R_EDI); break;
+                case 6: *(int32_t*)&R_EAX = syscall(sc, R_EBX, R_ECX, R_EDX, R_ESI, R_EDI, R_EBP); break;
+                default:
+                   printf_log(LOG_NONE, "ERROR, Unimplemented syscall wrapper (%d, %d)\n", s, syscallwrap[i].nbpars); 
+                   emu->quit = 1;
+                   return;
+            }
+            if(R_EAX==0xffffffff && errno>0)
+                R_EAX = (uint32_t)-errno;
+            printf_log(LOG_DEBUG, " => 0x%x\n", R_EAX);
+            return;
+        }
+    }
+    switch (s) {
+        case 1: // sys_exit
+            emu->quit = 1;
+            emu->exit = 1;
+            //R_EAX = syscall(__NR_exit, R_EBX);  // the syscall should exit only current thread
+            R_EAX = R_EBX; // faking the syscall here, we don't want to really terminate the thread now
+            break;
+        case 3:  // sys_read
+            S_EAX = read((int)R_EBX, from_ptrv(R_ECX), from_ulong(R_EDX));
+            break;
+        case 4:  // sys_write
+            S_EAX = write((int)R_EBX, from_ptrv(R_ECX), from_ulong(R_EDX));
+            break;
+        case 5: // sys_open
+            if(s==5) {printf_log(LOG_DEBUG, " => sys_open(\"%s\", %d, %d)", (char*)from_ptrv(R_EBX), of_convert32(R_ECX), R_EDX);}; 
+            //S_EAX = open((void*)R_EBX, of_convert32(R_ECX), R_EDX);
+            S_EAX = my32_open(emu, from_ptrv(R_EBX), of_convert32(R_ECX), R_EDX);
+            break;
+        case 6:  // sys_close
+            S_EAX = close((int)R_EBX);
+            break;
+        /*case 123:   // SYS_modify_ldt
+            R_EAX = my32_modify_ldt(emu, R_EBX, (thread_area_t*)(uintptr_t)R_ECX, R_EDX);
+            if(R_EAX==0xffffffff && errno>0)
+                R_EAX = (uint32_t)-errno;
+            break;*/
+        case 243: // set_thread_area
+            R_EAX = my_set_thread_area_32(emu, (thread_area_32_t*)(uintptr_t)R_EBX);
+            if(R_EAX==0xffffffff && errno>0)
+                R_EAX = (uint32_t)-errno;
+            break;
+        default:
+            printf_log(LOG_INFO, "Warning: Unsupported Syscall 0x%02Xh (%d)\n", s, s);
+            R_EAX = (uint32_t)-ENOSYS;
+            return;
+    }
+    printf_log(LOG_DEBUG, " => 0x%x\n", R_EAX);
+}
+
+#ifdef BOX32
+#define stack(n) (b[(n)/4])
+#define i32(n)  (int32_t)stack(n)
+#define u32(n)  (uint32_t)stack(n)
+#define p(n)    from_ptrv(stack(n))
+
+uint32_t EXPORT my32_syscall(x64emu_t *emu, ptr_t* b)
+{
+    static uint32_t warned = 0;
+    uint32_t s = u32(0);
+    printf_log(LOG_DEBUG, "%p: Calling libc syscall 0x%02X (%d) %p %p %p %p %p\n", from_ptrv(R_EIP), s, s, from_ptrv(u32(4)), from_ptrv(u32(8)), from_ptrv(u32(12)), from_ptrv(u32(16)), from_ptrv(u32(20))); 
+    // check wrapper first
+    int cnt = sizeof(syscallwrap) / sizeof(scwrap_t);
+    for (int i=0; i<cnt; i++) {
+        if(syscallwrap[i].x86s == s) {
+            int sc = syscallwrap[i].nats;
+            switch(syscallwrap[i].nbpars) {
+                case 0: return syscall(sc);
+                case 1: return syscall(sc, u32(4));
+                case 2: return syscall(sc, u32(4), u32(8));
+                case 3: return syscall(sc, u32(4), u32(8), u32(12));
+                case 4: return syscall(sc, u32(4), u32(8), u32(12), u32(16));
+                case 5: return syscall(sc, u32(4), u32(8), u32(12), u32(16), u32(20));
+                case 6: return syscall(sc, u32(4), u32(8), u32(12), u32(16), u32(20), u32(24));
+                default:
+                   printf_log(LOG_NONE, "ERROR, Unimplemented syscall wrapper (%d, %d)\n", s, syscallwrap[i].nbpars); 
+                   emu->quit = 1;
+                   return 0;
+            }
+        }
+    }
+    switch (s) {
+        case 1: // __NR_exit
+            emu->quit = 1;
+            return u32(4); // faking the syscall here, we don't want to really terminate the program now
+        case 3:  // sys_read
+            return (uint32_t)read(i32(4), p(8), u32(12));
+        case 4:  // sys_write
+            return (uint32_t)write(i32(4), p(8), u32(12));
+        case 5: // sys_open
+            return my32_open(emu, p(4), of_convert32(u32(8)), u32(12));
+        case 6:  // sys_close
+            return (uint32_t)close(i32(4));
+        case 11: // execve
+            return (uint32_t)my32_execve(emu, p(4), p(8), p(12));
+        case 91:   // munmap
+            return (uint32_t)my32_munmap(emu, p(4), u32(8));
+#if 0
+        case 120:   // clone
+            // x86 raw syscall is long clone(unsigned long flags, void *stack, int *parent_tid, unsigned long tls, int *child_tid);
+            // so flags=u(4), stack=p(8), parent_tid=p(12), tls=p(16), child_tid=p(20)
+            if(p(8))
+            {
+                void* stack_base = p(8);
+                int stack_size = 0;
+                if(!stack_base) {
+                    // allocate a new stack...
+                    int currstack = 0;
+                    if((R_ESP>=(uintptr_t)emu->init_stack) && (R_ESP<=((uintptr_t)emu->init_stack+emu->size_stack)))
+                        currstack = 1;
+                    stack_size = (currstack)?emu->size_stack:(1024*1024);
+                    stack_base = mmap(NULL, stack_size, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS|MAP_GROWSDOWN, -1, 0);
+                    // copy value from old stack to new stack
+                    if(currstack)
+                        memcpy(stack_base, emu->init_stack, stack_size);
+                    else {
+                        int size_to_copy = (uintptr_t)emu->init_stack + emu->size_stack - (R_ESP);
+                        memcpy(stack_base+stack_size-size_to_copy, (void*)R_ESP, size_to_copy);
+                    }
+                }
+                x64emu_t * newemu = NewX86Emu(emu->context, R_EIP, (uintptr_t)stack_base, stack_size, (p(8))?0:1);
+                SetupX86Emu(newemu);
+                CloneEmu(newemu, emu);
+                Push32(newemu, 0);
+                PushExit(newemu);
+                void* mystack = NULL;
+                if(my32_context->stack_clone_used) {
+                    mystack = malloc(1024*1024);  // stack for own process... memory leak, but no practical way to remove it
+                } else {
+                    if(!my32_context->stack_clone)
+                        my32_context->stack_clone = malloc(1024*1024);
+                    mystack = my32_context->stack_clone;
+                    my32_context->stack_clone_used = 1;
+                }
+                // x86_64 raw clone is long clone(unsigned long flags, void *stack, int *parent_tid, int *child_tid, unsigned long tls);
+                long ret = clone(clone_fn, (void*)((uintptr_t)mystack+1024*1024), u32(4), newemu, p(12), p(16), p(20));
+                return (uint32_t)ret;
+            }
+            else
+                return (uint32_t)syscall(__NR_clone, u32(4), p(8), p(12), p(16), p(20));
+            break;
+        case 123:   // SYS_modify_ldt
+            return my32_modify_ldt(emu, i32(4), (thread_area_t*)p(8), i32(12));
+        case 125:   // mprotect
+            return (uint32_t)my32_mprotect(emu, p(4), u32(8), i32(12));
+        case 174:   // sys_rt_sigaction
+            return (uint32_t)my32_sigaction(emu, i32(4), (x86_sigaction_t*)p(8), (x86_sigaction_t*)p(12));
+        case 192:   // mmap2
+            return (uint32_t)my32_mmap64(emu, p(4), u32(8), i32(12), i32(16), i32(20), u32(24));
+        case 243: // set_thread_area
+            return my32_set_thread_area((thread_area_t*)p(4));
+#ifndef NOALIGN
+        case 254: // epoll_create
+            return my32_epoll_create(emu, i32(4));
+        case 255: // epoll_ctl
+            return my32_epoll_ctl(emu, i32(4), i32(8), i32(12), p(16));
+        case 256: // epoll_wait
+            return my32_epoll_wait(emu, i32(4), p(8), i32(12), i32(16));
+#endif
+        case 270: //_NR_tgkill
+            /*if(!u32(12))*/ {
+                //printf("tgkill(%u, %u, %u) => ", u32(4), u32(8), u32(12));
+                uint32_t ret = (uint32_t)syscall(__NR_tgkill, u32(4), u32(8), u32(12));
+                //printf("%u (errno=%d)\n", ret, (ret==(uint32_t)-1)?errno:0);
+                return ret;
+            }/* else {
+                printf_log(LOG_INFO, "Warning: ignoring libc Syscall tgkill (%u, %u, %u)\n", u32(4), u32(8), u32(12));
+            }*/
+            return 0;
+#ifndef NOALIGN
+        case 329:   // epoll_create1
+            return my32_epoll_create1(emu, of_convert32(i32(4)));
+#endif
+#ifndef __NR_getrandom
+        case 355:  // getrandom
+            return (uint32_t)my32_getrandom(emu, p(4), u32(8), u32(12));
+#endif
+#ifndef __NR_memfd_create
+        case 356:  // memfd_create
+            return (uint32_t)my32_memfd_create(emu, (void*)R_EBX, R_ECX);
+#endif
+#endif
+        default:
+            if(!(warned&(1<<s))) {
+                printf_log(LOG_INFO, "Warning: Unsupported libc Syscall 0x%02X (%d)\n", s, s);
+                warned|=(1<<s);
+            }
+            errno = ENOSYS;
+            return -1;
+    }
+    return 0;
+}
+#endif //BOX32
\ No newline at end of file
diff --git a/src/emu/x87emu_private.c b/src/emu/x87emu_private.c
index 92c14268..c64f49cb 100644
--- a/src/emu/x87emu_private.c
+++ b/src/emu/x87emu_private.c
@@ -295,7 +295,6 @@ void fpu_savenv(x64emu_t* emu, char* p, int b16)
     // other stuff are not pushed....
 }
 
-// this is the 64bits version (slightly different than the 32bits!)
 typedef struct xsave32_s {
     uint16_t ControlWord;        /* 000 */
     uint16_t StatusWord;         /* 002 */
@@ -311,9 +310,10 @@ typedef struct xsave32_s {
     uint32_t MxCsr;              /* 018 */
     uint32_t MxCsr_Mask;         /* 01c */
     sse_regs_t FloatRegisters[8];/* 020 */  // fpu/mmx are store in 128bits here
-    sse_regs_t XmmRegisters[16]; /* 0a0 */
-    uint8_t  Reserved4[96];      /* 1a0 */
+    sse_regs_t XmmRegisters[8];  /* 0a0 */
+    uint8_t  Reserved4[56*4];    /* 1a0 */
 } xsave32_t;
+// this is the 64bits version (slightly different than the 32bits!)
 typedef struct xsave64_s {
     uint16_t ControlWord;        /* 000 */
     uint16_t StatusWord;         /* 002 */
@@ -354,8 +354,7 @@ void fpu_fxsave32(x64emu_t* emu, void* ed)
     for(int i=0; i<8; ++i)
         memcpy(&p->FloatRegisters[i].q[0], (i<stack)?&ST(i):&emu->mmx[i], sizeof(mmx87_regs_t));
     // copy SSE regs
-    for(int i=0; i<16; ++i)
-        memcpy(&p->XmmRegisters[i], &emu->xmm[i], 16);
+    memcpy(p->XmmRegisters, emu->xmm, 8*16);
 }
 
 void fpu_fxsave64(x64emu_t* emu, void* ed)
@@ -381,8 +380,7 @@ void fpu_fxsave64(x64emu_t* emu, void* ed)
     for(int i=0; i<8; ++i)
         memcpy(&p->FloatRegisters[i].q[0], (i<stack)?&ST(i):&emu->mmx[i], sizeof(mmx87_regs_t));
     // copy SSE regs
-    for(int i=0; i<16; ++i)
-        memcpy(&p->XmmRegisters[i], &emu->xmm[i], 16);
+    memcpy(p->XmmRegisters, emu->xmm, 16*16);
 }
 
 void fpu_fxrstor32(x64emu_t* emu, void* ed)
@@ -406,8 +404,7 @@ void fpu_fxrstor32(x64emu_t* emu, void* ed)
     for(int i=0; i<8; ++i)
         memcpy((i<stack)?&ST(i):&emu->mmx[i], &p->FloatRegisters[i].q[0], sizeof(mmx87_regs_t));
     // copy SSE regs
-    for(int i=0; i<16; ++i)
-        memcpy(&emu->xmm[i], &p->XmmRegisters[i], 16);
+    memcpy(emu->xmm, p->XmmRegisters, 8*16);
 }
 
 void fpu_fxrstor64(x64emu_t* emu, void* ed)
@@ -431,8 +428,7 @@ void fpu_fxrstor64(x64emu_t* emu, void* ed)
     for(int i=0; i<8; ++i)
         memcpy((i<stack)?&ST(i):&emu->mmx[i], &p->FloatRegisters[i].q[0], sizeof(mmx87_regs_t));
     // copy SSE regs
-    for(int i=0; i<16; ++i)
-        memcpy(&emu->xmm[i], &p->XmmRegisters[i], 16);
+    memcpy(emu->xmm, p->XmmRegisters, 16*16);
 }
 
 typedef struct xsaveheader_s {