about summary refs log tree commit diff stats
path: root/src
diff options
context:
space:
mode:
authorptitSeb <sebastien.chev@gmail.com>2024-08-18 16:02:27 +0200
committerGitHub <noreply@github.com>2024-08-18 16:02:27 +0200
commitfda0e9a4cba9b71de60f974fadfa74c7fbff5b15 (patch)
treef18d6631d62761d1556abd18a91d4729bd1f41e1 /src
parentf1da5d433a707a1308732884c455ae50ffbe4fe1 (diff)
parentdead2003fa59cbfa6a2fd8ba285bdf28aac953f3 (diff)
downloadbox64-fda0e9a4cba9b71de60f974fadfa74c7fbff5b15.tar.gz
box64-fda0e9a4cba9b71de60f974fadfa74c7fbff5b15.zip
Merge branch 'box32' into main
Diffstat (limited to 'src')
-rw-r--r--src/core.c8
-rw-r--r--src/custommem.c26
-rw-r--r--src/custommmap.c3
-rw-r--r--src/dynarec/dynarec_native_functions.c2
-rw-r--r--src/elfs/elfhash.c149
-rw-r--r--src/elfs/elfhash32.c190
-rw-r--r--src/elfs/elfload_dump.c136
-rwxr-xr-xsrc/elfs/elfload_dump32.c352
-rw-r--r--src/elfs/elfloader.c384
-rw-r--r--src/elfs/elfloader32.c626
-rw-r--r--src/elfs/elfloader_private.h61
-rw-r--r--src/elfs/elfparser.c87
-rwxr-xr-xsrc/elfs/elfparser32.c466
-rw-r--r--src/emu/x64int3.c6
-rw-r--r--src/include/box32.h112
-rw-r--r--src/include/custommem.h3
-rw-r--r--src/include/debug.h1
-rw-r--r--src/include/elfload_dump.h32
-rw-r--r--src/include/elfloader.h3
-rw-r--r--src/include/x64run.h4
-rw-r--r--src/librarian/librarian.c8
-rw-r--r--src/librarian/library.c4
-rw-r--r--src/mallochook.c48
23 files changed, 2344 insertions, 367 deletions
diff --git a/src/core.c b/src/core.c
index e93a75ea..3283a6c2 100644
--- a/src/core.c
+++ b/src/core.c
@@ -58,6 +58,7 @@ int box64_dynarec_test = 0;
 path_collection_t box64_addlibs = {0};
 int box64_maxcpu = 0;
 int box64_maxcpu_immutable = 0;
+int box64_is32bits = 0;
 #if defined(SD845) || defined(SD888) || defined(SD8G2) || defined(TEGRAX1)
 int box64_mmap32 = 1;
 #else
@@ -2084,6 +2085,13 @@ int initialize(int argc, const char **argv, char** env, x64emu_t** emulator, elf
         FreeCollection(&ld_preload);
         return -1;
     }
+    #ifdef BOX32
+    box64_is32bits = FileIsX86ELF(my_context->fullpath);
+    if(box64_is32bits) {
+        printf_log(LOG_INFO, "BOX64: Using Box32 to load 32bits elf\n");
+        reserveHighMem();
+    }
+    #endif
     elfheader_t *elf_header = LoadAndCheckElfHeader(f, my_context->fullpath, 1);
     if(!elf_header) {
         int x86 = my_context->box86path?FileIsX86ELF(my_context->fullpath):0;
diff --git a/src/custommem.c b/src/custommem.c
index da11885f..06b48328 100644
--- a/src/custommem.c
+++ b/src/custommem.c
@@ -1438,6 +1438,21 @@ void* find47bitBlockElf(size_t size, int mainbin, uintptr_t mask)
     return ret;
 }
 
+void* find31bitBlockElf(size_t size, int mainbin, uintptr_t mask)
+{
+    static void* startingpoint = NULL;
+    if(!startingpoint) {
+        startingpoint = (void*)WINE_LOWEST;
+    }
+    void* mainaddr = (void*)0x1000000;
+    void* ret = find31bitBlockNearHint(MEDIUM, size, mask);
+    if(!ret)
+        ret = find31bitBlockNearHint(LOWEST, size, mask);
+    if(!mainbin)
+        startingpoint = (void*)(((uintptr_t)startingpoint+size+0x1000000)&~0xffffff);
+    return ret;
+}
+
 int isBlockFree(void* hint, size_t size)
 {
     uint32_t prot;
@@ -1510,10 +1525,10 @@ static void atfork_child_custommem(void)
 void my_reserveHighMem()
 {
     static int reserved = 0;
-    if(reserved || !have48bits)
+    if(reserved || (!have48bits && !box64_is32bits))
         return;
     reserved = 1;
-    uintptr_t cur = 1ULL<<47;
+    uintptr_t cur = box64_is32bits?(1ULL<<32):(1ULL<<47);
     uintptr_t bend = 0;
     uint32_t prot;
     while (bend!=0xffffffffffffffffLL) {
@@ -1533,12 +1548,13 @@ void my_reserveHighMem()
 void reserveHighMem()
 {
     char* p = getenv("BOX64_RESERVE_HIGH");
+    if(!box64_is32bits)
     #if 0//def ADLINK
-    if(p && p[0]=='0')
+        if(p && p[0]=='0')
     #else
-    if(!p || p[0]=='0')
+        if(!p || p[0]=='0')
     #endif
-        return; // don't reserve by default
+            return; // don't reserve by default
     my_reserveHighMem();
 }
 
diff --git a/src/custommmap.c b/src/custommmap.c
index 93173098..7ad26b7d 100644
--- a/src/custommmap.c
+++ b/src/custommmap.c
@@ -15,6 +15,7 @@
 
 typedef void x64emu_t;
 extern void* mapallmem;
+extern int box64_is32bits;
 void setProtection(uintptr_t addr, size_t size, uint32_t prot);
 void freeProtection(uintptr_t addr, size_t size);
 void* internal_mmap(void *addr, unsigned long length, int prot, int flags, int fd, ssize_t offset);
@@ -28,7 +29,7 @@ extern int box64_mmap32;
 EXPORT void* mmap64(void *addr, unsigned long length, int prot, int flags, int fd, ssize_t offset)
 {
     void* ret;
-    if(!addr && ((running32bits && box64_mmap32) || (flags&0x40)))
+    if(!addr && ((running32bits && box64_mmap32) || (flags&0x40) || box64_is32bits))
         ret = my_mmap64(NULL, addr, length, prot, flags | 0x40, fd, offset);
     else
         ret = internal_mmap(addr, length, prot, flags, fd, offset);
diff --git a/src/dynarec/dynarec_native_functions.c b/src/dynarec/dynarec_native_functions.c
index 376541d1..c29e5083 100644
--- a/src/dynarec/dynarec_native_functions.c
+++ b/src/dynarec/dynarec_native_functions.c
@@ -608,7 +608,7 @@ int isNativeCall(dynarec_native_t* dyn, uintptr_t addr, uintptr_t* calladdress,
     if(!addr || !getProtection(addr))
         return 0;
     onebridge_t *b = (onebridge_t*)(addr);
-    if(b->CC==0xCC && b->S=='S' && b->C=='C' && b->w!=(wrapper_t)0 && b->f!=(uintptr_t)PltResolver) {
+    if(b->CC==0xCC && b->S=='S' && b->C=='C' && b->w!=(wrapper_t)0 && b->f!=(uintptr_t)PltResolver64) {
         // found !
         if(retn) *retn = (b->C3==0xC2)?b->N:0;
         if(calladdress) *calladdress = addr+1;
diff --git a/src/elfs/elfhash.c b/src/elfs/elfhash.c
index fefb0e7f..966a18b7 100644
--- a/src/elfs/elfhash.c
+++ b/src/elfs/elfhash.c
@@ -18,14 +18,20 @@
 #include "elfload_dump.h"
 #include "elfloader_private.h"
 
-const char* GetSymbolVersion(elfheader_t* h, int version)
+const char* GetSymbolVersion32(elfheader_t* h, int version)
+#ifndef BOX32
+{ return NULL; }
+#else
+ ;
+#endif
+const char* GetSymbolVersion64(elfheader_t* h, int version)
 {
     if(version<2)
         return NULL;
     /*if(version==1)
         return "*";*/
-    if(h->VerNeed) {
-        Elf64_Verneed *ver = (Elf64_Verneed*)((uintptr_t)h->VerNeed + h->delta);
+    if(h->VerNeed._64) {
+        Elf64_Verneed *ver = (Elf64_Verneed*)((uintptr_t)h->VerNeed._64 + h->delta);
         while(ver) {
             Elf64_Vernaux *aux = (Elf64_Vernaux*)((uintptr_t)ver + ver->vn_aux);
             for(int j=0; j<ver->vn_cnt; ++j) {
@@ -38,12 +44,22 @@ const char* GetSymbolVersion(elfheader_t* h, int version)
     }
     return GetParentSymbolVersion(h, version);  // if symbol is "internal", use Def table instead
 }
+const char* GetSymbolVersion(elfheader_t* h, int version)
+{
+    return box64_is32bits?GetSymbolVersion32(h, version):GetSymbolVersion64(h, version);
+}
 
-const char* GetParentSymbolVersion(elfheader_t* h, int index)
+const char* GetParentSymbolVersion32(elfheader_t* h, int index)
+#ifndef BOX32
+{ return NULL; }
+#else
+ ;
+#endif
+const char* GetParentSymbolVersion64(elfheader_t* h, int index)
 {
-    if(!h->VerDef || (index<1))
+    if(!h->VerDef._64 || (index<1))
         return NULL;
-    Elf64_Verdef *def = (Elf64_Verdef*)((uintptr_t)h->VerDef + h->delta);
+    Elf64_Verdef *def = (Elf64_Verdef*)((uintptr_t)h->VerDef._64 + h->delta);
     while(def) {
         if(def->vd_ndx==index) {
             if(def->vd_cnt<1)
@@ -57,26 +73,37 @@ const char* GetParentSymbolVersion(elfheader_t* h, int index)
     }
     return NULL;
 }
+const char* GetParentSymbolVersion(elfheader_t* h, int version)
+{
+    return box64_is32bits?GetParentSymbolVersion32(h, version):GetParentSymbolVersion64(h, version);
+}
 
-Elf64_Half GetParentSymbolVersionFlag(elfheader_t* h, int index)
+uint16_t GetParentSymbolVersionFlag32(elfheader_t* h, int index) { /* TODO */ return (uint16_t)-1; }
+uint16_t GetParentSymbolVersionFlag64(elfheader_t* h, int index)
 {
-    if(!h->VerDef || (index<1))
-        return (Elf64_Half)-1;
-    Elf64_Verdef *def = (Elf64_Verdef*)((uintptr_t)h->VerDef + h->delta);
+    if(!h->VerDef._64 || (index<1))
+        return (uint16_t)-1;
+    Elf64_Verdef *def = (Elf64_Verdef*)((uintptr_t)h->VerDef._64 + h->delta);
     while(def) {
         if(def->vd_ndx==index) {
             return def->vd_flags;
         }
         def = def->vd_next?((Elf64_Verdef*)((uintptr_t)def + def->vd_next)):NULL;
     }
-    return (Elf64_Half)-1;
+    return (uint16_t)-1;
 }
-Elf64_Half GetSymbolVersionFlag(elfheader_t* h, int version)
+uint16_t GetParentSymbolVersionFlag(elfheader_t* h, int index)
+{
+    return box64_is32bits?GetParentSymbolVersionFlag32(h, index):GetParentSymbolVersionFlag64(h, index);
+}
+
+uint16_t GetSymbolVersionFlag32(elfheader_t* h, int version) { /* TODO */ return (uint16_t)-1; }
+uint16_t GetSymbolVersionFlag64(elfheader_t* h, int version)
 {
     if(version<2)
-        return (Elf64_Half)-1;
-    if(h->VerNeed) {
-        Elf64_Verneed *ver = (Elf64_Verneed*)((uintptr_t)h->VerNeed + h->delta);
+        return (uint16_t)-1;
+    if(h->VerNeed._64) {
+        Elf64_Verneed *ver = (Elf64_Verneed*)((uintptr_t)h->VerNeed._64 + h->delta);
         while(ver) {
             Elf64_Vernaux *aux = (Elf64_Vernaux*)((uintptr_t)ver + ver->vn_aux);
             for(int j=0; j<ver->vn_cnt; ++j) {
@@ -89,14 +116,23 @@ Elf64_Half GetSymbolVersionFlag(elfheader_t* h, int version)
     }
     return GetParentSymbolVersionFlag(h, version);  // if symbol is "internal", use Def table instead
 }
+uint16_t GetSymbolVersionFlag(elfheader_t* h, int index) {
+    return box64_is32bits?GetSymbolVersionFlag32(h, index):GetSymbolVersionFlag64(h, index);
+}
 
 
-int GetVersionIndice(elfheader_t* h, const char* vername)
+int GetVersionIndice32(elfheader_t* h, const char* vername)
+#ifndef BOX32
+{ return 0; }
+#else
+ ;
+#endif
+int GetVersionIndice64(elfheader_t* h, const char* vername)
 {
     if(!vername)
         return 0;
-    if(h->VerDef) {
-        Elf64_Verdef *def = (Elf64_Verdef*)((uintptr_t)h->VerDef + h->delta);
+    if(h->VerDef._64) {
+        Elf64_Verdef *def = (Elf64_Verdef*)((uintptr_t)h->VerDef._64 + h->delta);
         while(def) {
             Elf64_Verdaux *aux = (Elf64_Verdaux*)((uintptr_t)def + def->vd_aux);
             if(!strcmp(h->DynStr+aux->vda_name, vername))
@@ -106,13 +142,23 @@ int GetVersionIndice(elfheader_t* h, const char* vername)
     }
     return 0;
 }
+int GetVersionIndice(elfheader_t* h, const char* vername)
+{
+    return box64_is32bits?GetVersionIndice32(h, vername):GetVersionIndice64(h, vername);
+}
 
-int GetNeededVersionCnt(elfheader_t* h, const char* libname)
+int GetNeededVersionCnt32(elfheader_t* h, const char* libname)
+#ifndef BOX32
+{ return 0; }
+#else
+ ;
+#endif
+int GetNeededVersionCnt64(elfheader_t* h, const char* libname)
 {
     if(!libname)
         return 0;
-    if(h->VerNeed) {
-        Elf64_Verneed *ver = (Elf64_Verneed*)((uintptr_t)h->VerNeed + h->delta);
+    if(h->VerNeed._64) {
+        Elf64_Verneed *ver = (Elf64_Verneed*)((uintptr_t)h->VerNeed._64 + h->delta);
         while(ver) {
             char *filename = h->DynStr + ver->vn_file;
             if(!strcmp(filename, libname))
@@ -122,13 +168,23 @@ int GetNeededVersionCnt(elfheader_t* h, const char* libname)
     }
     return 0;
 }
+int GetNeededVersionCnt(elfheader_t* h, const char* libname)
+{
+    return box64_is32bits?GetNeededVersionCnt32(h, libname):GetNeededVersionCnt64(h, libname);
+}
 
-const char* GetNeededVersionString(elfheader_t* h, const char* libname, int idx)
+const char* GetNeededVersionString32(elfheader_t* h, const char* libname, int idx)
+#ifndef BOX32
+{ return NULL; }
+#else
+ ;
+#endif
+const char* GetNeededVersionString64(elfheader_t* h, const char* libname, int idx)
 {
     if(!libname)
-        return 0;
-    if(h->VerNeed) {
-        Elf64_Verneed *ver = (Elf64_Verneed*)((uintptr_t)h->VerNeed + h->delta);
+        return NULL;
+    if(h->VerNeed._64) {
+        Elf64_Verneed *ver = (Elf64_Verneed*)((uintptr_t)h->VerNeed._64 + h->delta);
         while(ver) {
             char *filename = h->DynStr + ver->vn_file;
             Elf64_Vernaux *aux = (Elf64_Vernaux*)((uintptr_t)ver + ver->vn_aux);
@@ -145,6 +201,10 @@ const char* GetNeededVersionString(elfheader_t* h, const char* libname, int idx)
     }
     return NULL;
 }
+const char* GetNeededVersionString(elfheader_t* h, const char* libname, int idx)
+{
+    return box64_is32bits?GetNeededVersionString32(h, libname, idx):GetNeededVersionString64(h, libname, idx);
+}
 
 int GetNeededVersionForLib(elfheader_t* h, const char* libname, const char* ver)
 {
@@ -197,7 +257,7 @@ uint32_t old_elf_hash(const char* name)
     return h;
 }
 
-Elf64_Sym* old_elf_lookup(elfheader_t* h, const char* symname, int ver, const char* vername, int local, int veropt)
+static Elf64_Sym* old_elf_lookup(elfheader_t* h, const char* symname, int ver, const char* vername, int local, int veropt)
 {
     // Prepare hash table
     const uint32_t *hashtab = (uint32_t*)(h->hash + h->delta);
@@ -209,16 +269,16 @@ Elf64_Sym* old_elf_lookup(elfheader_t* h, const char* symname, int ver, const ch
     const uint32_t hash = old_elf_hash(symname);
     // Search for it
     for (uint32_t i = buckets[hash % nbuckets]; i; i = chains[i]) {
-        const char* name = h->DynStr + h->DynSym[i].st_name;
+        const char* name = h->DynStr + h->DynSym._64[i].st_name;
         if (!strcmp(symname, name) && SymbolMatch(h, i, ver, vername, local, veropt)) {
-            return &h->DynSym[i];
+            return &h->DynSym._64[i];
         }
     }
     return NULL;
 }
 
 
-void old_elf_hash_dump(elfheader_t* h)
+static void old_elf_hash_dump(elfheader_t* h)
 {
     // Prepare hash table
     const uint32_t *hashtab = (uint32_t*)(h->hash + h->delta);
@@ -229,7 +289,7 @@ void old_elf_hash_dump(elfheader_t* h)
     printf_log(LOG_NONE, "------------ Dump HASH from %s\n", h->name);
     printf_log(LOG_NONE, "Buckets[%d] = \n", nbuckets);
     for(uint32_t i=0; i<nbuckets; ++i) {
-        const char* name = h->DynStr + h->DynSym[buckets[i]].st_name;
+        const char* name = h->DynStr + h->DynSym._64[buckets[i]].st_name;
         printf_log(LOG_NONE, "%d: %s\n", buckets[i], name);
     }
     printf_log(LOG_NONE,"Chains[%d] = ", nchains);
@@ -246,7 +306,7 @@ uint32_t new_elf_hash(const char *name)
     return h;
 }
 
-Elf64_Sym* new_elf_lookup(elfheader_t* h, const char* symname, int ver, const char* vername, int local, int veropt)
+static Elf64_Sym* new_elf_lookup(elfheader_t* h, const char* symname, int ver, const char* vername, int local, int veropt)
 {
     // Prepare hash table
     const uint32_t *hashtab = (uint32_t*)(h->gnu_hash + h->delta);
@@ -272,10 +332,10 @@ Elf64_Sym* new_elf_lookup(elfheader_t* h, const char* symname, int ver, const ch
     if (symidx < symoffset)
         return NULL;
     while(1) {
-        const char* name = h->DynStr + h->DynSym[symidx].st_name;
+        const char* name = h->DynStr + h->DynSym._64[symidx].st_name;
         const uint32_t symhash = chains[symidx-symoffset];
         if ((hash|1) == (symhash|1) && !strcmp(name, symname) && SymbolMatch(h, symidx, ver, vername, local, veropt)) {
-            return &h->DynSym[symidx];
+            return &h->DynSym._64[symidx];
         }
         if(symhash&1)
             return NULL;
@@ -283,7 +343,7 @@ Elf64_Sym* new_elf_lookup(elfheader_t* h, const char* symname, int ver, const ch
     }
 }
 
-void new_elf_hash_dump(elfheader_t* h)
+static void new_elf_hash_dump(elfheader_t* h)
 {
     // Prepare hash table
     const uint32_t *hashtab = (uint32_t*)(h->gnu_hash + h->delta);
@@ -301,7 +361,7 @@ void new_elf_hash_dump(elfheader_t* h)
         uint32_t symidx = buckets[i];
         printf_log(LOG_NONE, "%d:", symidx);
         while(symidx>=symoffset) {
-            const char* name = h->DynStr + h->DynSym[symidx].st_name;
+            const char* name = h->DynStr + h->DynSym._64[symidx].st_name;
             const uint32_t hash = chains[symidx-symoffset];
             if(hash&1)
                 symidx=0;
@@ -314,19 +374,24 @@ void new_elf_hash_dump(elfheader_t* h)
     printf_log(LOG_NONE, "\n===============\n");
 }
 
-Elf64_Sym* ElfLookup(elfheader_t* h, const char* symname, int ver, const char* vername, int local, int veropt)
+#ifndef BOX32
+Elf32_Sym* ElfLookup32(elfheader_t* h, const char* symname, int ver, const char* vername, int local, int veropt) { return NULL; }
+Elf32_Sym* ElfSymTabLookup32(elfheader_t* h, const char* symname) { return NULL; }
+Elf32_Sym* ElfDynSymLookup32(elfheader_t* h, const char* symname) { return NULL; }
+#endif
+Elf64_Sym* ElfLookup64(elfheader_t* h, const char* symname, int ver, const char* vername, int local, int veropt)
 {
     if(h->gnu_hash)
         return new_elf_lookup(h, symname, ver, vername, local, veropt);
     return old_elf_lookup(h, symname, ver, vername, local, veropt);
 }
 
-Elf64_Sym* ElfSymTabLookup(elfheader_t* h, const char* symname)
+Elf64_Sym* ElfSymTabLookup64(elfheader_t* h, const char* symname)
 {
-    if(!h->SymTab)
+    if(!h->SymTab._64)
         return 0;
     for(size_t i=0; i<h->numSymTab; ++i) {
-        Elf64_Sym* sym = &h->SymTab[i];
+        Elf64_Sym* sym = &h->SymTab._64[i];
         int type = ELF64_ST_TYPE(sym->st_info);
         if(type==STT_FUNC || type==STT_TLS || type==STT_OBJECT) {
             const char * name = h->StrTab+sym->st_name;
@@ -337,12 +402,12 @@ Elf64_Sym* ElfSymTabLookup(elfheader_t* h, const char* symname)
     return NULL;
 }
 
-Elf64_Sym* ElfDynSymLookup(elfheader_t* h, const char* symname)
+Elf64_Sym* ElfDynSymLookup64(elfheader_t* h, const char* symname)
 {
-    if(!h->DynSym)
+    if(!h->DynSym._64)
         return 0;
     for(size_t i=0; i<h->numDynSym; ++i) {
-        Elf64_Sym* sym = &h->DynSym[i];
+        Elf64_Sym* sym = &h->DynSym._64[i];
         int type = ELF64_ST_TYPE(sym->st_info);
         if(type==STT_FUNC || type==STT_TLS || type==STT_OBJECT) {
             const char * name = h->DynStr+sym->st_name;
diff --git a/src/elfs/elfhash32.c b/src/elfs/elfhash32.c
new file mode 100644
index 00000000..00423b0a
--- /dev/null
+++ b/src/elfs/elfhash32.c
@@ -0,0 +1,190 @@
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <elf.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/sysmacros.h>
+#include <sys/types.h>
+#include <link.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include "custommem.h"
+#include "box64version.h"
+#include "elfloader.h"
+#include "debug.h"
+#include "elfload_dump.h"
+#include "elfloader_private.h"
+
+static int SymbolMatch(elfheader_t* h, uint32_t i, int ver, const char* vername, int local, int veropt)
+{
+    int version = h->VerSym?((Elf32_Half*)((uintptr_t)h->VerSym+h->delta))[i]:-1;
+    if(version!=-1) version &=0x7fff;
+    const char* symvername = GetSymbolVersion(h, version);
+    Elf32_Half flags = GetSymbolVersionFlag(h, version);
+    if(ver==-1 || version==-1)
+        return 1;
+    if(version==0 && !local)
+        return 0;
+    if(version<2 && ver>1 && veropt)
+        return 1;
+    if(ver==0 && version<2)
+        return 1;
+    if(ver==1 && version<2)
+        return 1;
+    if(ver<2 && version>1 && flags==0)  // flag is not WEAK, so global works
+        return 1;
+    if(ver<2 || !symvername)
+        return 0;
+    return strcmp(vername, symvername)?0:1;
+}
+
+static Elf32_Sym* old_elf_lookup(elfheader_t* h, const char* symname, int ver, const char* vername, int local, int veropt)
+{
+    // Prepare hash table
+    const uint32_t *hashtab = (uint32_t*)(h->hash + h->delta);
+    const uint32_t nbuckets = hashtab[0];
+    const uint32_t nchains = hashtab[1];
+    const uint32_t *buckets = &hashtab[2];
+    const uint32_t *chains = &buckets[nbuckets];
+    // get hash from symname to lookup
+    const uint32_t hash = old_elf_hash(symname);
+    // Search for it
+    for (uint32_t i = buckets[hash % nbuckets]; i; i = chains[i]) {
+        const char* name = h->DynStr + h->DynSym._32[i].st_name;
+        if (!strcmp(symname, name) && SymbolMatch(h, i, ver, vername, local, veropt)) {
+            return &h->DynSym._32[i];
+        }
+    }
+    return NULL;
+}
+
+
+static void old_elf_hash_dump(elfheader_t* h)
+{
+    // Prepare hash table
+    const uint32_t *hashtab = (uint32_t*)(h->hash + h->delta);
+    const uint32_t nbuckets = hashtab[0];
+    const uint32_t nchains = hashtab[1];
+    const uint32_t *buckets = &hashtab[2];
+    const uint32_t *chains = &buckets[nbuckets];
+    printf_log(LOG_NONE, "------------ Dump HASH from %s\n", h->name);
+    printf_log(LOG_NONE, "Buckets[%d] = \n", nbuckets);
+    for(uint32_t i=0; i<nbuckets; ++i) {
+        const char* name = h->DynStr + h->DynSym._32[buckets[i]].st_name;
+        printf_log(LOG_NONE, "%d: %s\n", buckets[i], name);
+    }
+    printf_log(LOG_NONE,"Chains[%d] = ", nchains);
+    for (uint32_t i = 0; i<nchains; ++i)
+        printf_log(LOG_NONE, "%d ", chains[i]);
+    printf_log(LOG_NONE, "\n------------\n");
+}
+
+static Elf32_Sym* new_elf_lookup(elfheader_t* h, const char* symname, int ver, const char* vername, int local, int veropt)
+{
+    // Prepare hash table
+    const uint32_t *hashtab = (uint32_t*)(h->gnu_hash + h->delta);
+    const uint32_t nbuckets = hashtab[0];
+    const uint32_t symoffset = hashtab[1];
+    const uint32_t bloom_size = hashtab[2];
+    const uint32_t bloom_shift = hashtab[3];
+    const uint64_t *blooms = (uint64_t*)&hashtab[4];
+    const uint32_t *buckets = (uint32_t*)&blooms[bloom_size];
+    const uint32_t *chains = &buckets[nbuckets];
+    // get hash from symname to lookup
+    const uint32_t hash = new_elf_hash(symname);
+    // early check with bloom: if at least one bit is not set, a symbol is surely missing.
+    uint64_t word = blooms[(hash/64)%bloom_size];
+    uint64_t mask = 0
+        | 1LL << (hash%64)
+        | 1LL << ((hash>>bloom_shift)%64);
+    if ((word & mask) != mask) {
+        return NULL;
+    }
+    // now look at the bucket chain for the symbol
+    uint32_t symidx = buckets[hash%nbuckets];
+    if (symidx < symoffset)
+        return NULL;
+    while(1) {
+        const char* name = h->DynStr + h->DynSym._32[symidx].st_name;
+        const uint32_t symhash = chains[symidx-symoffset];
+        if ((hash|1) == (symhash|1) && !strcmp(name, symname) && SymbolMatch(h, symidx, ver, vername, local, veropt)) {
+            return &h->DynSym._32[symidx];
+        }
+        if(symhash&1)
+            return NULL;
+        symidx++;
+    }
+}
+
+static void new_elf_hash_dump(elfheader_t* h)
+{
+    // Prepare hash table
+    const uint32_t *hashtab = (uint32_t*)(h->gnu_hash + h->delta);
+    const uint32_t nbuckets = hashtab[0];
+    const uint32_t symoffset = hashtab[1];
+    const uint32_t bloom_size = hashtab[2];
+    const uint32_t bloom_shift = hashtab[3];
+    const uint64_t *blooms = (uint64_t*)&hashtab[4];
+    const uint32_t *buckets = (uint32_t*)&blooms[bloom_size];
+    const uint32_t *chains = &buckets[nbuckets];
+    printf_log(LOG_NONE, "===============Dump GNU_HASH from %s\n", h->name);
+    printf_log(LOG_NONE, "Bloom: size=%d, shift=%d\n", bloom_size, bloom_shift);
+    printf_log(LOG_NONE, "Buckets[%d] offset=%d = \n", nbuckets, symoffset);
+    for(uint32_t i=0; i<nbuckets; ++i) {
+        uint32_t symidx = buckets[i];
+        printf_log(LOG_NONE, "%d:", symidx);
+        while(symidx>=symoffset) {
+            const char* name = h->DynStr + h->DynSym._32[symidx].st_name;
+            const uint32_t hash = chains[symidx-symoffset];
+            if(hash&1)
+                symidx=0;
+            else
+                symidx++;
+            printf_log(LOG_NONE, " %s (%x) -> %d", name, hash, symidx);
+        }
+        printf_log(LOG_NONE, "\n");
+    }
+    printf_log(LOG_NONE, "\n===============\n");
+}
+
+Elf32_Sym* ElfLookup32(elfheader_t* h, const char* symname, int ver, const char* vername, int local, int veropt)
+{
+    if(h->gnu_hash)
+        return new_elf_lookup(h, symname, ver, vername, local, veropt);
+    return old_elf_lookup(h, symname, ver, vername, local, veropt);
+}
+
+Elf32_Sym* ElfSymTabLookup32(elfheader_t* h, const char* symname)
+{
+    if(!h->SymTab._32)
+        return 0;
+    for(size_t i=0; i<h->numSymTab; ++i) {
+        Elf32_Sym* sym = &h->SymTab._32[i];
+        int type = ELF32_ST_TYPE(sym->st_info);
+        if(type==STT_FUNC || type==STT_TLS || type==STT_OBJECT) {
+            const char * name = h->StrTab+sym->st_name;
+            if(name && !strcmp(symname, name))
+                return sym;
+        }
+    }
+    return NULL;
+}
+
+Elf32_Sym* ElfDynSymLookup32(elfheader_t* h, const char* symname)
+{
+    if(!h->DynSym._32)
+        return 0;
+    for(size_t i=0; i<h->numDynSym; ++i) {
+        Elf32_Sym* sym = &h->DynSym._32[i];
+        int type = ELF32_ST_TYPE(sym->st_info);
+        if(type==STT_FUNC || type==STT_TLS || type==STT_OBJECT) {
+            const char * name = h->DynStr+sym->st_name;
+            if(name && !strcmp(symname, name))
+                return sym;
+        }
+    }
+    return NULL;
+}
diff --git a/src/elfs/elfload_dump.c b/src/elfs/elfload_dump.c
index 62cedcf6..18d4dbc6 100644
--- a/src/elfs/elfload_dump.c
+++ b/src/elfs/elfload_dump.c
@@ -13,7 +13,7 @@
 #define SHT_CHECKSUM 0x6ffffff8
 #endif
 
-const char* DumpSection(Elf64_Shdr *s, char* SST) {
+static const char* DumpSection(Elf64_Shdr *s, char* SST) {
     static char buff[400];
     switch (s->sh_type) {
         case SHT_NULL:
@@ -64,7 +64,7 @@ const char* DumpSection(Elf64_Shdr *s, char* SST) {
     return buff;
 }
 
-const char* DumpDynamic(Elf64_Dyn *s) {
+static const char* DumpDynamic(Elf64_Dyn *s) {
     static char buff[200];
     switch (s->d_tag) {
         case DT_NULL:
@@ -148,7 +148,7 @@ const char* DumpDynamic(Elf64_Dyn *s) {
     return buff;
 }
 
-const char* DumpPHEntry(Elf64_Phdr *e)
+static const char* DumpPHEntry(Elf64_Phdr *e)
 {
     static char buff[500];
     memset(buff, 0, sizeof(buff));
@@ -174,8 +174,10 @@ const char* DumpPHEntry(Elf64_Phdr *e)
     }
     return buff;
 }
-
-const char* DumpRelType(int t)
+#ifndef BOX32
+const char* DumpRelType32(int t) { return NULL; }
+#endif
+const char* DumpRelType64(int t)
 {
     static char buff[50];
     memset(buff, 0, sizeof(buff));
@@ -229,7 +231,7 @@ const char* DumpRelType(int t)
     return buff;
 }
 
-const char* DumpSym(elfheader_t *h, Elf64_Sym* sym, int version)
+static const char* DumpSym(elfheader_t *h, Elf64_Sym* sym, int version)
 {
     static char buff[4096];
     const char* vername = (version==-1)?"(none)":((version==0)?"*local*":((version==1)?"*global*":GetSymbolVersion(h, version)));
@@ -241,16 +243,22 @@ const char* DumpSym(elfheader_t *h, Elf64_Sym* sym, int version)
     return buff;
 }
 
-const char* SymName(elfheader_t *h, Elf64_Sym* sym)
+#ifndef BOX32
+const char* SymName32(elfheader_t *h, Elf32_Sym* sym) { return NULL; }
+#endif
+const char* SymName64(elfheader_t *h, Elf64_Sym* sym)
 {
     return h->DynStr+sym->st_name;
 }
-const char* IdxSymName(elfheader_t *h, int sym)
+static const char* IdxSymName(elfheader_t *h, int sym)
 {
-    return h->DynStr+h->DynSym[sym].st_name;
+    return h->DynStr+h->DynSym._64[sym].st_name;
 }
 
-void DumpMainHeader(Elf64_Ehdr *header, elfheader_t *h)
+#ifndef BOX32
+void DumpMainHeader32(Elf32_Ehdr *header, elfheader_t *h) { }
+#endif
+void DumpMainHeader64(Elf64_Ehdr *header, elfheader_t *h)
 {
     if(box64_dump) {
         printf_dump(LOG_NEVER, "ELF Dump main header\n");
@@ -266,108 +274,142 @@ void DumpMainHeader(Elf64_Ehdr *header, elfheader_t *h)
 
         printf_dump(LOG_NEVER, "ELF Dump PEntries (%zu)\n", h->numPHEntries);
         for (size_t i=0; i<h->numPHEntries; ++i)
-            printf_dump(LOG_NEVER, "  PHEntry %04zu : %s\n", i, DumpPHEntry(h->PHEntries+i));
+            printf_dump(LOG_NEVER, "  PHEntry %04zu : %s\n", i, DumpPHEntry(h->PHEntries._64+i));
         printf_dump(LOG_NEVER, "ELF Dump PEntries ====\n");
 
         printf_dump(LOG_NEVER, "ELF Dump Sections (%zu)\n", h->numSHEntries);
         for (size_t i=0; i<h->numSHEntries; ++i)
-            printf_dump(LOG_NEVER, "  Section %04zu : %s\n", i, DumpSection(h->SHEntries+i, h->SHStrTab));
+            printf_dump(LOG_NEVER, "  Section %04zu : %s\n", i, DumpSection(h->SHEntries._64+i, h->SHStrTab));
         printf_dump(LOG_NEVER, "ELF Dump Sections ====\n");
     }
 }
-
-void DumpSymTab(elfheader_t *h)
+#ifndef BOX32
+void DumpSymTab32(elfheader_t *h) { }
+#endif
+void DumpSymTab64(elfheader_t *h)
 {
-    if(box64_dump && h->SymTab) {
+    if(box64_dump && h->SymTab._64) {
         const char* name = ElfName(h);
         printf_dump(LOG_NEVER, "ELF Dump SymTab(%zu)=\n", h->numSymTab);
         for (size_t i=0; i<h->numSymTab; ++i)
             printf_dump(LOG_NEVER, "  %s:SymTab[%zu] = \"%s\", value=%p, size=%ld, info/other=%d/%d index=%d\n", name, 
-                i, h->StrTab+h->SymTab[i].st_name, (void*)h->SymTab[i].st_value, h->SymTab[i].st_size,
-                h->SymTab[i].st_info, h->SymTab[i].st_other, h->SymTab[i].st_shndx);
+                i, h->StrTab+h->SymTab._64[i].st_name, (void*)h->SymTab._64[i].st_value, h->SymTab._64[i].st_size,
+                h->SymTab._64[i].st_info, h->SymTab._64[i].st_other, h->SymTab._64[i].st_shndx);
         printf_dump(LOG_NEVER, "ELF Dump SymTab=====\n");
     }
 }
 
-void DumpDynamicSections(elfheader_t *h)
+#ifndef BOX32
+void DumpDynamicSections32(elfheader_t *h) { }
+#endif
+void DumpDynamicSections64(elfheader_t *h)
 {
-    if(box64_dump && h->Dynamic) {
+    if(box64_dump && h->Dynamic._64) {
         printf_dump(LOG_NEVER, "ELF Dump Dynamic(%zu)=\n", h->numDynamic);
         for (size_t i=0; i<h->numDynamic; ++i)
-            printf_dump(LOG_NEVER, "  Dynamic %04zu : %s\n", i, DumpDynamic(h->Dynamic+i));
+            printf_dump(LOG_NEVER, "  Dynamic %04zu : %s\n", i, DumpDynamic(h->Dynamic._64+i));
         printf_dump(LOG_NEVER, "ELF Dump Dynamic=====\n");
     }
 }
 
-void DumpDynSym(elfheader_t *h)
+#ifndef BOX32
+void DumpDynSym32(elfheader_t *h) { }
+#endif
+void DumpDynSym64(elfheader_t *h)
 {
-    if(box64_dump && h->DynSym) {
+    if(box64_dump && h->DynSym._64) {
         const char* name = ElfName(h);
         printf_dump(LOG_NEVER, "ELF Dump DynSym(%zu)=\n", h->numDynSym);
         for (size_t i=0; i<h->numDynSym; ++i) {
             int version = h->VerSym?((Elf64_Half*)((uintptr_t)h->VerSym+h->delta))[i]:-1;
-            printf_dump(LOG_NEVER, "  %s:DynSym[%zu] = %s\n", name, i, DumpSym(h, h->DynSym+i, version));
+            printf_dump(LOG_NEVER, "  %s:DynSym[%zu] = %s\n", name, i, DumpSym(h, h->DynSym._64+i, version));
         }
         printf_dump(LOG_NEVER, "ELF Dump DynSym=====\n");
     }
 }
 
+void DumpDynamicNeeded32(elfheader_t *h)
+#ifndef BOX32
+ {  }
+#else
+ ;
+#endif
 void DumpDynamicNeeded(elfheader_t *h)
 {
-    if(box64_dump && h->DynStrTab) {
-        printf_dump(LOG_NEVER, "ELF Dump DT_NEEDED=====\n");
-        for (size_t i=0; i<h->numDynamic; ++i)
-            if(h->Dynamic[i].d_tag==DT_NEEDED) {
-                printf_dump(LOG_NEVER, "  Needed : %s\n", h->DynStrTab+h->Dynamic[i].d_un.d_val + h->delta);
-            }
-        printf_dump(LOG_NEVER, "ELF Dump DT_NEEDED=====\n");
-    }
+    if(box64_is32bits)
+        DumpDynamicNeeded32(h);
+    else
+        if(box64_dump && h->DynStrTab) {
+            printf_dump(LOG_NEVER, "ELF Dump DT_NEEDED=====\n");
+            for (size_t i=0; i<h->numDynamic; ++i)
+                if(h->Dynamic._64[i].d_tag==DT_NEEDED) {
+                    printf_dump(LOG_NEVER, "  Needed : %s\n", h->DynStrTab+h->Dynamic._64[i].d_un.d_val + h->delta);
+                }
+            printf_dump(LOG_NEVER, "ELF Dump DT_NEEDED=====\n");
+        }
 }
 
+void DumpDynamicRPath32(elfheader_t *h) 
+#ifndef BOX32
+{  }
+#else
+ ;
+#endif
 void DumpDynamicRPath(elfheader_t *h)
 {
-    if(box64_dump && h->DynStrTab) {
-        printf_dump(LOG_NEVER, "ELF Dump DT_RPATH/DT_RUNPATH=====\n");
-        for (size_t i=0; i<h->numDynamic; ++i) {
-            if(h->Dynamic[i].d_tag==DT_RPATH) {
-                printf_dump(LOG_NEVER, "   RPATH : %s\n", h->DynStrTab+h->Dynamic[i].d_un.d_val + h->delta);
-            }
-            if(h->Dynamic[i].d_tag==DT_RUNPATH) {
-                printf_dump(LOG_NEVER, " RUNPATH : %s\n", h->DynStrTab+h->Dynamic[i].d_un.d_val + h->delta);
+    if(box64_is32bits)
+        DumpDynamicRPath32(h);
+    else
+        if(box64_dump && h->DynStrTab) {
+            printf_dump(LOG_NEVER, "ELF Dump DT_RPATH/DT_RUNPATH=====\n");
+            for (size_t i=0; i<h->numDynamic; ++i) {
+                if(h->Dynamic._64[i].d_tag==DT_RPATH) {
+                    printf_dump(LOG_NEVER, "   RPATH : %s\n", h->DynStrTab+h->Dynamic._64[i].d_un.d_val + h->delta);
+                }
+                if(h->Dynamic._64[i].d_tag==DT_RUNPATH) {
+                    printf_dump(LOG_NEVER, " RUNPATH : %s\n", h->DynStrTab+h->Dynamic._64[i].d_un.d_val + h->delta);
+                }
             }
+            printf_dump(LOG_NEVER, "=====ELF Dump DT_RPATH/DT_RUNPATH\n");
         }
-        printf_dump(LOG_NEVER, "=====ELF Dump DT_RPATH/DT_RUNPATH\n");
-    }
 }
 
-void DumpRelTable(elfheader_t *h, int cnt, Elf64_Rel *rel, const char* name)
+#ifndef BOX32
+void DumpRelTable32(elfheader_t *h, int cnt, Elf32_Rel *rel, const char* name) { }
+#endif
+void DumpRelTable64(elfheader_t *h, int cnt, Elf64_Rel *rel, const char* name)
 {
     if(box64_dump) {
         const char* elfname = ElfName(h);
         printf_dump(LOG_NEVER, "ELF Dump %s Table(%d) @%p\n", name, cnt, rel);
         for (int i = 0; i<cnt; ++i)
             printf_dump(LOG_NEVER, "  %s:Rel[%d] = %p (0x%lX: %s, sym=0x%0lX/%s)\n", elfname,
-                i, (void*)rel[i].r_offset, rel[i].r_info, DumpRelType(ELF64_R_TYPE(rel[i].r_info)), 
+                i, (void*)rel[i].r_offset, rel[i].r_info, DumpRelType64(ELF64_R_TYPE(rel[i].r_info)), 
                 ELF64_R_SYM(rel[i].r_info), IdxSymName(h, ELF64_R_SYM(rel[i].r_info)));
         printf_dump(LOG_NEVER, "ELF Dump Rel Table=====\n");
     }
 }
-
-void DumpRelATable(elfheader_t *h, int cnt, Elf64_Rela *rela, const char* name)
+#ifndef BOX32
+void DumpRelATable32(elfheader_t *h, int cnt, Elf32_Rela *rela, const char* name) { }
+#endif
+void DumpRelATable64(elfheader_t *h, int cnt, Elf64_Rela *rela, const char* name)
 {
     if(box64_dump && h->rela) {
         const char* elfname = ElfName(h);
         printf_dump(LOG_NEVER, "ELF Dump %s Table(%d) @%p\n", name, cnt, rela);
         for (int i = 0; i<cnt; ++i)
             printf_dump(LOG_NEVER, "  %s:%s[%d] = %p (0x%lX: %s, sym=0x%lX/%s) Addend=0x%lx\n", elfname, name,
-                i, (void*)rela[i].r_offset, rela[i].r_info, DumpRelType(ELF64_R_TYPE(rela[i].r_info)), 
+                i, (void*)rela[i].r_offset, rela[i].r_info, DumpRelType64(ELF64_R_TYPE(rela[i].r_info)), 
                 ELF64_R_SYM(rela[i].r_info), IdxSymName(h, ELF64_R_SYM(rela[i].r_info)), 
                 rela[i].r_addend);
         printf_dump(LOG_NEVER, "ELF Dump %s Table=====\n", name);
     }
 }
 
-void DumpRelRTable(elfheader_t *h, int cnt, Elf64_Relr *relr, const char *name)
+#ifndef BOX32
+void DumpRelRTable32(elfheader_t *h, int cnt, Elf32_Relr *relr, const char *name) { }
+#endif
+void DumpRelRTable64(elfheader_t *h, int cnt, Elf64_Relr *relr, const char *name)
 {
     if(box64_dump && h->relr) {
         const char* elfname = ElfName(h);
diff --git a/src/elfs/elfload_dump32.c b/src/elfs/elfload_dump32.c
new file mode 100755
index 00000000..b6d8df41
--- /dev/null
+++ b/src/elfs/elfload_dump32.c
@@ -0,0 +1,352 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <elf.h>
+
+#include "box64version.h"
+#include "elfloader.h"
+#include "debug.h"
+#include "elfload_dump.h"
+#include "elfloader_private.h"
+#include "box32.h"
+
+static const char* DumpSection(Elf32_Shdr *s, char* SST) {
+    static char buff[400];
+    switch (s->sh_type) {
+        case SHT_NULL:
+            return "SHT_NULL";
+        #define GO(A) \
+        case A:     \
+            sprintf(buff, #A " Name=\"%s\"(%d) off=0x%X, size=%d, attr=0x%04X, addr=%p(%02X), link/info=%d/%d", \
+                SST+s->sh_name, s->sh_name, s->sh_offset, s->sh_size, s->sh_flags, from_ptrv(s->sh_addr), s->sh_addralign, s->sh_link, s->sh_info); \
+            break
+        GO(SHT_PROGBITS);
+        GO(SHT_SYMTAB);
+        GO(SHT_STRTAB);
+        GO(SHT_RELA);
+        GO(SHT_HASH);
+        GO(SHT_DYNAMIC);
+        GO(SHT_NOTE);
+        GO(SHT_NOBITS);
+        GO(SHT_REL);
+        GO(SHT_SHLIB);
+        GO(SHT_DYNSYM);
+        GO(SHT_INIT_ARRAY);
+        GO(SHT_FINI_ARRAY);
+        GO(SHT_PREINIT_ARRAY);
+        GO(SHT_GROUP);
+        GO(SHT_SYMTAB_SHNDX);
+        GO(SHT_NUM);
+        GO(SHT_LOPROC);
+        GO(SHT_HIPROC);
+        GO(SHT_LOUSER);
+        GO(SHT_HIUSER);
+        #if defined(SHT_GNU_versym) && defined(SHT_GNU_ATTRIBUTES)
+        GO(SHT_GNU_versym);
+        GO(SHT_GNU_ATTRIBUTES);
+        GO(SHT_GNU_HASH);
+        GO(SHT_GNU_LIBLIST);
+        GO(SHT_CHECKSUM);
+        GO(SHT_LOSUNW);
+        //GO(SHT_SUNW_move);
+        GO(SHT_SUNW_COMDAT);
+        GO(SHT_SUNW_syminfo);
+        GO(SHT_GNU_verdef);
+        GO(SHT_GNU_verneed);
+        #endif
+        #undef GO
+        default:
+            sprintf(buff, "0x%X unknown type", s->sh_type);
+    }
+    return buff;
+}
+
+static const char* DumpDynamic(Elf32_Dyn *s) {
+    static char buff[200];
+    switch (s->d_tag) {
+        case DT_NULL:
+            return "DT_NULL: End Dynamic Section";
+        #define GO(A, Add) \
+        case A:     \
+            sprintf(buff, #A " %s=0x%X", (Add)?"Addr":"Val", (Add)?s->d_un.d_ptr:s->d_un.d_val); \
+            break
+            GO(DT_NEEDED, 0);
+            GO(DT_PLTRELSZ, 0);
+            GO(DT_PLTGOT, 1);
+            GO(DT_HASH, 1);
+            GO(DT_STRTAB, 1);
+            GO(DT_SYMTAB, 1);
+            GO(DT_RELA, 1);
+            GO(DT_RELASZ, 0);
+            GO(DT_RELAENT, 0);
+            GO(DT_STRSZ, 0);
+            GO(DT_SYMENT, 0);
+            GO(DT_INIT, 1);
+            GO(DT_FINI, 1);
+            GO(DT_SONAME, 0);
+            GO(DT_RPATH, 0);
+            GO(DT_SYMBOLIC, 0);
+            GO(DT_REL, 1);
+            GO(DT_RELSZ, 0);
+            GO(DT_RELENT, 0);
+            GO(DT_PLTREL, 0);
+            GO(DT_DEBUG, 0);
+            GO(DT_TEXTREL, 0);
+            GO(DT_JMPREL, 1);
+            GO(DT_BIND_NOW, 1);
+            GO(DT_INIT_ARRAY, 1);
+            GO(DT_FINI_ARRAY, 1);
+            GO(DT_INIT_ARRAYSZ, 0);
+            GO(DT_FINI_ARRAYSZ, 0);
+            GO(DT_RUNPATH, 0);
+            GO(DT_FLAGS, 0);
+            GO(DT_ENCODING, 0);
+            #if defined(DT_NUM) && defined(DT_TLSDESC_PLT)
+            GO(DT_NUM, 0);
+            GO(DT_VALRNGLO, 0);
+            GO(DT_GNU_PRELINKED, 0);
+            GO(DT_GNU_CONFLICTSZ, 0);
+            GO(DT_GNU_LIBLISTSZ, 0);
+            GO(DT_CHECKSUM, 0);
+            GO(DT_PLTPADSZ, 0);
+            GO(DT_MOVEENT, 0);
+            GO(DT_MOVESZ, 0);
+            GO(DT_FEATURE_1, 0);
+            GO(DT_POSFLAG_1, 0);
+            GO(DT_SYMINSZ, 0);
+            GO(DT_SYMINENT, 0);
+            GO(DT_ADDRRNGLO, 0);
+            GO(DT_GNU_HASH, 0);
+            GO(DT_TLSDESC_PLT, 0);
+            GO(DT_TLSDESC_GOT, 0);
+            GO(DT_GNU_CONFLICT, 0);
+            GO(DT_GNU_LIBLIST, 0);
+            GO(DT_CONFIG, 0);
+            GO(DT_DEPAUDIT, 0);
+            GO(DT_AUDIT, 0);
+            GO(DT_PLTPAD, 0);
+            GO(DT_MOVETAB, 0);
+            GO(DT_SYMINFO, 0);
+            GO(DT_VERSYM, 0);
+            GO(DT_RELACOUNT, 0);
+            GO(DT_RELCOUNT, 0);
+            GO(DT_FLAGS_1, 0);
+            GO(DT_VERDEF, 0);
+            GO(DT_VERDEFNUM, 0);
+            GO(DT_VERNEED, 0);
+            GO(DT_VERNEEDNUM, 0);
+            GO(DT_AUXILIARY, 0);
+            GO(DT_FILTER, 0);
+            #endif
+        #undef GO
+        default:
+            sprintf(buff, "0x%X unknown type", s->d_tag);
+    }
+    return buff;
+}
+
+static const char* DumpPHEntry(Elf32_Phdr *e)
+{
+    static char buff[500];
+    memset(buff, 0, sizeof(buff));
+    switch(e->p_type) {
+        case PT_NULL: sprintf(buff, "type: %s", "PT_NULL"); break;
+        #define GO(T) case T: sprintf(buff, "type: %s, Off=%x vaddr=%p paddr=%p filesz=%u memsz=%u flags=%x align=%u", #T, e->p_offset, from_ptrv(e->p_vaddr), from_ptrv(e->p_paddr), e->p_filesz, e->p_memsz, e->p_flags, e->p_align); break
+        GO(PT_LOAD);
+        GO(PT_DYNAMIC);
+        GO(PT_INTERP);
+        GO(PT_NOTE);
+        GO(PT_SHLIB);
+        GO(PT_PHDR);
+        GO(PT_TLS);
+        #ifdef PT_NUM
+        GO(PT_NUM);
+        GO(PT_LOOS);
+        GO(PT_GNU_EH_FRAME);
+        GO(PT_GNU_STACK);
+        GO(PT_GNU_RELRO);
+        #endif
+        #undef GO
+        default: sprintf(buff, "type: %x, Off=%x vaddr=%p paddr=%p filesz=%u memsz=%u flags=%x align=%u", e->p_type, e->p_offset, from_ptrv(e->p_vaddr), from_ptrv(e->p_paddr), e->p_filesz, e->p_memsz, e->p_flags, e->p_align); break;
+    }
+    return buff;
+}
+
+const char* DumpRelType32(int t)
+{
+    static char buff[50];
+    memset(buff, 0, sizeof(buff));
+    switch(t) {
+        #define GO(T) case T: sprintf(buff, "type: %s", #T); break
+        GO(R_386_NONE);
+        GO(R_386_32);
+        GO(R_386_PC32);
+        GO(R_386_GOT32);
+        GO(R_386_PLT32);
+        GO(R_386_COPY);
+        GO(R_386_GLOB_DAT);
+        GO(R_386_JMP_SLOT);
+        GO(R_386_RELATIVE);
+        GO(R_386_GOTOFF);
+        GO(R_386_GOTPC);
+        GO(R_386_PC8);
+        GO(R_386_TLS_TPOFF);
+        GO(R_386_TLS_GD_32);
+        GO(R_386_TLS_DTPMOD32);
+        GO(R_386_TLS_DTPOFF32);
+        GO(R_386_TLS_TPOFF32);
+        #undef GO
+        default: sprintf(buff, "type: 0x%x (unknown)", t); break;
+    }
+    return buff;
+}
+
+static const char* DumpSym(elfheader_t *h, Elf32_Sym* sym, int version)
+{
+    static char buff[4096];
+    const char* vername = (version==-1)?"(none)":((version==0)?"*local*":((version==1)?"*global*":GetSymbolVersion(h, version)));
+    memset(buff, 0, sizeof(buff));
+    sprintf(buff, "\"%s\", value=%p, size=%d, info/other=%d/%d index=%d (ver=%d/%s)", 
+        h->DynStr+sym->st_name, from_ptrv(sym->st_value), sym->st_size,
+        sym->st_info, sym->st_other, sym->st_shndx, version, vername);
+    return buff;
+}
+
+const char* SymName32(elfheader_t *h, Elf32_Sym* sym)
+{
+    return h->DynStr+sym->st_name;
+}
+static const char* IdxSymName(elfheader_t *h, int sym)
+{
+    return h->DynStr+h->DynSym._32[sym].st_name;
+}
+
+void DumpMainHeader32(Elf32_Ehdr *header, elfheader_t *h)
+{
+    if(box64_dump) {
+        printf_dump(LOG_NEVER, "ELF Dump main header\n");
+        printf_dump(LOG_NEVER, "  Entry point = %p\n", from_ptrv(header->e_entry));
+        printf_dump(LOG_NEVER, "  Program Header table offset = %p\n", from_ptrv(header->e_phoff));
+        printf_dump(LOG_NEVER, "  Section Header table offset = %p\n", from_ptrv(header->e_shoff));
+        printf_dump(LOG_NEVER, "  Flags = 0x%X\n", header->e_flags);
+        printf_dump(LOG_NEVER, "  ELF Header size = %d\n", header->e_ehsize);
+        printf_dump(LOG_NEVER, "  Program Header Entry num/size = %d(%d)/%d\n", h->numPHEntries, header->e_phnum, header->e_phentsize);
+        printf_dump(LOG_NEVER, "  Section Header Entry num/size = %d(%d)/%d\n", h->numSHEntries, header->e_shnum, header->e_shentsize);
+        printf_dump(LOG_NEVER, "  Section Header index num = %d(%d)\n", h->SHIdx, header->e_shstrndx);
+        printf_dump(LOG_NEVER, "ELF Dump ==========\n");
+
+        printf_dump(LOG_NEVER, "ELF Dump PEntries (%d)\n", h->numSHEntries);
+        for (int i=0; i<h->numPHEntries; ++i)
+            printf_dump(LOG_NEVER, "  PHEntry %04d : %s\n", i, DumpPHEntry(h->PHEntries._32+i));
+        printf_dump(LOG_NEVER, "ELF Dump PEntries ====\n");
+
+        printf_dump(LOG_NEVER, "ELF Dump Sections (%d)\n", h->numSHEntries);
+        for (int i=0; i<h->numSHEntries; ++i)
+            printf_dump(LOG_NEVER, "  Section %04d : %s\n", i, DumpSection(h->SHEntries._32+i, h->SHStrTab));
+        printf_dump(LOG_NEVER, "ELF Dump Sections ====\n");
+    }
+}
+
+void DumpSymTab32(elfheader_t *h)
+{
+    if(box64_dump && h->SymTab._32) {
+        const char* name = ElfName(h);
+        printf_dump(LOG_NEVER, "ELF Dump SymTab(%d)=\n", h->numSymTab);
+        for (int i=0; i<h->numSymTab; ++i)
+            printf_dump(LOG_NEVER, "  %s:SymTab[%d] = \"%s\", value=%p, size=%d, info/other=%d/%d index=%d\n", name, 
+                i, h->StrTab+h->SymTab._32[i].st_name, from_ptrv(h->SymTab._32[i].st_value), h->SymTab._32[i].st_size,
+                h->SymTab._32[i].st_info, h->SymTab._32[i].st_other, h->SymTab._32[i].st_shndx);
+        printf_dump(LOG_NEVER, "ELF Dump SymTab=====\n");
+    }
+}
+
+void DumpDynamicSections32(elfheader_t *h)
+{
+    if(box64_dump && h->Dynamic._32) {
+        printf_dump(LOG_NEVER, "ELF Dump Dynamic(%d)=\n", h->numDynamic);
+        for (int i=0; i<h->numDynamic; ++i)
+            printf_dump(LOG_NEVER, "  Dynamic %04d : %s\n", i, DumpDynamic(h->Dynamic._32+i));
+        printf_dump(LOG_NEVER, "ELF Dump Dynamic=====\n");
+    }
+}
+
+void DumpDynSym32(elfheader_t *h)
+{
+    if(box64_dump && h->DynSym._32) {
+        const char* name = ElfName(h);
+        printf_dump(LOG_NEVER, "ELF Dump DynSym(%d)=\n", h->numDynSym);
+        for (int i=0; i<h->numDynSym; ++i) {
+            int version = h->VerSym?((Elf32_Half*)((uintptr_t)h->VerSym+h->delta))[i]:-1;
+            printf_dump(LOG_NEVER, "  %s:DynSym[%d] = %s\n", name, i, DumpSym(h, h->DynSym._32+i, version));
+        }
+        printf_dump(LOG_NEVER, "ELF Dump DynSym=====\n");
+    }
+}
+
+void DumpDynamicNeeded32(elfheader_t *h)
+{
+    if(box64_dump && h->DynStrTab) {
+        printf_dump(LOG_NEVER, "ELF Dump DT_NEEDED=====\n");
+        for (int i=0; i<h->numDynamic; ++i)
+            if(h->Dynamic._32[i].d_tag==DT_NEEDED) {
+                printf_dump(LOG_NEVER, "  Needed : %s\n", h->DynStrTab+h->Dynamic._32[i].d_un.d_val + h->delta);
+            }
+        printf_dump(LOG_NEVER, "ELF Dump DT_NEEDED=====\n");
+    }
+}
+
+void DumpDynamicRPath32(elfheader_t *h)
+{
+    if(box64_dump && h->DynStrTab) {
+        printf_dump(LOG_NEVER, "ELF Dump DT_RPATH/DT_RUNPATH=====\n");
+        for (int i=0; i<h->numDynamic; ++i) {
+            if(h->Dynamic._32[i].d_tag==DT_RPATH) {
+                printf_dump(LOG_NEVER, "   RPATH : %s\n", h->DynStrTab+h->Dynamic._32[i].d_un.d_val + h->delta);
+            }
+            if(h->Dynamic._32[i].d_tag==DT_RUNPATH) {
+                printf_dump(LOG_NEVER, " RUNPATH : %s\n", h->DynStrTab+h->Dynamic._32[i].d_un.d_val + h->delta);
+            }
+        }
+        printf_dump(LOG_NEVER, "=====ELF Dump DT_RPATH/DT_RUNPATH\n");
+    }
+}
+
+void DumpRelTable32(elfheader_t *h, int cnt, Elf32_Rel *rel, const char* name)
+{
+    if(box64_dump) {
+        const char* elfname = ElfName(h);
+        printf_dump(LOG_NEVER, "ELF Dump %s Table(%d) @%p\n", name, cnt, rel);
+        for (int i = 0; i<cnt; ++i)
+            printf_dump(LOG_NEVER, "  %s:Rel[%d] = %p (0x%X: %s, sym=0x%0X/%s)\n", elfname,
+                i, from_ptrv(rel[i].r_offset), rel[i].r_info, DumpRelType32(ELF32_R_TYPE(rel[i].r_info)), 
+                ELF32_R_SYM(rel[i].r_info), IdxSymName(h, ELF32_R_SYM(rel[i].r_info)));
+        printf_dump(LOG_NEVER, "ELF Dump %s Table=====\n", name);
+    }
+}
+
+void DumpRelATable32(elfheader_t *h, int cnt, Elf32_Rela *rela, const char* name)
+{
+    if(box64_dump && h->rela) {
+        const char* elfname = ElfName(h);
+        printf_dump(LOG_NEVER, "ELF Dump %s Table(%d) @%p\n", name, cnt, rela);
+        for (int i = 0; i<cnt; ++i)
+            printf_dump(LOG_NEVER, "  %s:RelA[%d] = %p (0x%X: %s, sym=0x%X/%s) Addend=%d\n", elfname,
+                i, from_ptrv(rela[i].r_offset), rela[i].r_info, DumpRelType32(ELF32_R_TYPE(rela[i].r_info)), 
+                ELF32_R_SYM(rela[i].r_info), IdxSymName(h, ELF32_R_SYM(rela[i].r_info)), 
+                rela[i].r_addend);
+        printf_dump(LOG_NEVER, "ELF Dump %s Table=====\n", name);
+    }
+}
+
+void DumpRelRTable32(elfheader_t *h, int cnt, Elf32_Relr *relr, const char* name)
+{
+    if(box64_dump && h->relr) {
+        const char* elfname = ElfName(h);
+        printf_dump(LOG_NEVER, "ELF Dump %s Table(%d) @%p\n", name, cnt, relr);
+        for (int i = 0; i<cnt; ++i)
+            printf_dump(LOG_NEVER, "  %s:%s[%d] = %p\n", elfname, name,
+                i, from_ptrv(relr[i]));
+        printf_dump(LOG_NEVER, "ELF Dump %s Table=====\n", name);
+    }
+}
+
diff --git a/src/elfs/elfloader.c b/src/elfs/elfloader.c
index 016ae50b..248c4282 100644
--- a/src/elfs/elfloader.c
+++ b/src/elfs/elfloader.c
@@ -46,7 +46,7 @@ void* my__IO_2_1_stdin_  = NULL;
 void* my__IO_2_1_stdout_ = NULL;
 
 // return the index of header (-1 if it doesn't exist)
-int getElfIndex(box64context_t* ctx, elfheader_t* head) {
+static int getElfIndex(box64context_t* ctx, elfheader_t* head) {
     for (int i=0; i<ctx->elfsize; ++i)
         if(ctx->elfs[i]==head)
             return i;
@@ -55,7 +55,7 @@ int getElfIndex(box64context_t* ctx, elfheader_t* head) {
 
 elfheader_t* LoadAndCheckElfHeader(FILE* f, const char* name, int exec)
 {
-    elfheader_t *h = ParseElfHeader(f, name, exec);
+    elfheader_t *h = box64_is32bits?ParseElfHeader32(f, name, exec):ParseElfHeader64(f, name, exec);
     if(!h)
         return NULL;
 
@@ -80,14 +80,14 @@ void FreeElfHeader(elfheader_t** head)
     if(my_context)
         RemoveElfHeader(my_context, h);
 
-    box_free(h->PHEntries);
-    box_free(h->SHEntries);
+    box_free(h->PHEntries._64); //_64 or _32 doesn't mater for free, it's the same address
+    box_free(h->SHEntries._64);
     box_free(h->SHStrTab);
     box_free(h->StrTab);
-    box_free(h->Dynamic);
+    box_free(h->Dynamic._64);
     box_free(h->DynStr);
-    box_free(h->SymTab);
-    box_free(h->DynSym);
+    box_free(h->SymTab._64);
+    box_free(h->DynSym._64);
 
     FreeElfMemory(h);
 
@@ -105,13 +105,23 @@ int CalcLoadAddr(elfheader_t* head)
     head->memsz = 0;
     head->paddr = head->vaddr = ~(uintptr_t)0;
     head->align = box64_pagesize;
-    for (size_t i=0; i<head->numPHEntries; ++i)
-        if(head->PHEntries[i].p_type == PT_LOAD) {
-            if(head->paddr > (uintptr_t)head->PHEntries[i].p_paddr)
-                head->paddr = (uintptr_t)head->PHEntries[i].p_paddr;
-            if(head->vaddr > (uintptr_t)head->PHEntries[i].p_vaddr)
-                head->vaddr = (uintptr_t)head->PHEntries[i].p_vaddr;
-        }
+    if(box64_is32bits) {
+        for (size_t i=0; i<head->numPHEntries; ++i)
+            if(head->PHEntries._32[i].p_type == PT_LOAD) {
+                if(head->paddr > (uintptr_t)head->PHEntries._32[i].p_paddr)
+                    head->paddr = (uintptr_t)head->PHEntries._32[i].p_paddr;
+                if(head->vaddr > (uintptr_t)head->PHEntries._32[i].p_vaddr)
+                    head->vaddr = (uintptr_t)head->PHEntries._32[i].p_vaddr;
+            }
+    } else {
+        for (size_t i=0; i<head->numPHEntries; ++i)
+            if(head->PHEntries._64[i].p_type == PT_LOAD) {
+                if(head->paddr > (uintptr_t)head->PHEntries._64[i].p_paddr)
+                    head->paddr = (uintptr_t)head->PHEntries._64[i].p_paddr;
+                if(head->vaddr > (uintptr_t)head->PHEntries._64[i].p_vaddr)
+                    head->vaddr = (uintptr_t)head->PHEntries._64[i].p_vaddr;
+            }
+    }
     
     if(head->vaddr==~(uintptr_t)0 || head->paddr==~(uintptr_t)0) {
         printf_log(LOG_NONE, "Error: v/p Addr for Elf Load not set\n");
@@ -120,31 +130,58 @@ int CalcLoadAddr(elfheader_t* head)
 
     head->stacksz = 1024*1024;          //1M stack size default?
     head->stackalign = 16;   // default align for stack
-    for (size_t i=0; i<head->numPHEntries; ++i) {
-        if(head->PHEntries[i].p_type == PT_LOAD) {
-            uintptr_t phend = head->PHEntries[i].p_vaddr - head->vaddr + head->PHEntries[i].p_memsz;
-            if(phend > head->memsz)
-                head->memsz = phend;
-            if(head->PHEntries[i].p_align > head->align)
-                head->align = head->PHEntries[i].p_align;
-        }
-        if(head->PHEntries[i].p_type == PT_GNU_STACK) {
-            if(head->stacksz < head->PHEntries[i].p_memsz)
-                head->stacksz = head->PHEntries[i].p_memsz;
-            if(head->stackalign < head->PHEntries[i].p_align)
-                head->stackalign = head->PHEntries[i].p_align;
+    if(box64_is32bits)
+        for (size_t i=0; i<head->numPHEntries; ++i) {
+            if(head->PHEntries._32[i].p_type == PT_LOAD) {
+                uintptr_t phend = head->PHEntries._32[i].p_vaddr - head->vaddr + head->PHEntries._32[i].p_memsz;
+                if(phend > head->memsz)
+                    head->memsz = phend;
+                if(head->PHEntries._32[i].p_align > head->align)
+                    head->align = head->PHEntries._32[i].p_align;
+            }
+            if(head->PHEntries._32[i].p_type == PT_GNU_STACK) {
+                if(head->stacksz < head->PHEntries._32[i].p_memsz)
+                    head->stacksz = head->PHEntries._32[i].p_memsz;
+                if(head->stackalign < head->PHEntries._32[i].p_align)
+                    head->stackalign = head->PHEntries._32[i].p_align;
+            }
+            if(head->PHEntries._32[i].p_type == PT_TLS) {
+                head->tlsaddr = head->PHEntries._32[i].p_vaddr;
+                head->tlssize = head->PHEntries._32[i].p_memsz;
+                head->tlsfilesize = head->PHEntries._32[i].p_filesz;
+                head->tlsalign = head->PHEntries._32[i].p_align;
+                // force alignement...
+                if(head->tlsalign>1)
+                    while(head->tlssize&(head->tlsalign-1))
+                        head->tlssize++;
+            }
         }
-        if(head->PHEntries[i].p_type == PT_TLS) {
-            head->tlsaddr = head->PHEntries[i].p_vaddr;
-            head->tlssize = head->PHEntries[i].p_memsz;
-            head->tlsfilesize = head->PHEntries[i].p_filesz;
-            head->tlsalign = head->PHEntries[i].p_align;
-            // force alignement...
-            if(head->tlsalign>1)
-                while(head->tlssize&(head->tlsalign-1))
-                    head->tlssize++;
+    else
+        for (size_t i=0; i<head->numPHEntries; ++i) {
+            if(head->PHEntries._64[i].p_type == PT_LOAD) {
+                uintptr_t phend = head->PHEntries._64[i].p_vaddr - head->vaddr + head->PHEntries._64[i].p_memsz;
+                if(phend > head->memsz)
+                    head->memsz = phend;
+                if(head->PHEntries._64[i].p_align > head->align)
+                    head->align = head->PHEntries._64[i].p_align;
+            }
+            if(head->PHEntries._64[i].p_type == PT_GNU_STACK) {
+                if(head->stacksz < head->PHEntries._64[i].p_memsz)
+                    head->stacksz = head->PHEntries._64[i].p_memsz;
+                if(head->stackalign < head->PHEntries._64[i].p_align)
+                    head->stackalign = head->PHEntries._64[i].p_align;
+            }
+            if(head->PHEntries._64[i].p_type == PT_TLS) {
+                head->tlsaddr = head->PHEntries._64[i].p_vaddr;
+                head->tlssize = head->PHEntries._64[i].p_memsz;
+                head->tlsfilesize = head->PHEntries._64[i].p_filesz;
+                head->tlsalign = head->PHEntries._64[i].p_align;
+                // force alignement...
+                if(head->tlsalign>1)
+                    while(head->tlssize&(head->tlsalign-1))
+                        head->tlssize++;
+            }
         }
-    }
     printf_log(LOG_DEBUG, "Elf Addr(v/p)=%p/%p Memsize=0x%zx (align=0x%zx)\n", (void*)head->vaddr, (void*)head->paddr, head->memsz, head->align);
     printf_log(LOG_DEBUG, "Elf Stack Memsize=%zu (align=%zu)\n", head->stacksz, head->stackalign);
     printf_log(LOG_DEBUG, "Elf TLS Memsize=%zu (align=%zu)\n", head->tlssize, head->tlsalign);
@@ -165,8 +202,16 @@ const char* ElfPath(elfheader_t* head)
     return head->path;
 }
 
+int AllocLoadElfMemory32(box64context_t* context, elfheader_t* head, int mainbin)
+#ifndef BOX32
+{ return 1; }
+#else
+ ;
+#endif
 int AllocLoadElfMemory(box64context_t* context, elfheader_t* head, int mainbin)
 {
+    if(box64_is32bits)
+        return AllocLoadElfMemory32(context, head, mainbin);
     uintptr_t offs = 0;
     loadProtectionFromMap();
     int log_level = box64_load_addr?LOG_INFO:LOG_DEBUG;
@@ -174,7 +219,7 @@ int AllocLoadElfMemory(box64context_t* context, elfheader_t* head, int mainbin)
     head->multiblock_n = 0; // count PHEntrie with LOAD
     uintptr_t max_align = head->align-1;
     for (size_t i=0; i<head->numPHEntries; ++i) 
-        if(head->PHEntries[i].p_type == PT_LOAD && head->PHEntries[i].p_flags) {
+        if(head->PHEntries._64[i].p_type == PT_LOAD && head->PHEntries._64[i].p_flags) {
             ++head->multiblock_n;
         }
 
@@ -230,8 +275,8 @@ int AllocLoadElfMemory(box64context_t* context, elfheader_t* head, int mainbin)
     head->memory = (char*)0xffffffffffffffff;
     int n = 0;
     for (size_t i=0; i<head->numPHEntries; ++i) {
-        if(head->PHEntries[i].p_type == PT_LOAD && head->PHEntries[i].p_flags) {
-            Elf64_Phdr * e = &head->PHEntries[i];
+        if(head->PHEntries._64[i].p_type == PT_LOAD && head->PHEntries._64[i].p_flags) {
+            Elf64_Phdr * e = &head->PHEntries._64[i];
 
             head->multiblocks[n].flags = e->p_flags;
             head->multiblocks[n].offs = e->p_offset;
@@ -350,8 +395,8 @@ int AllocLoadElfMemory(box64context_t* context, elfheader_t* head, int mainbin)
                 head->memory = (char*)head->multiblocks[n].p;
             ++n;
         }
-        if(head->PHEntries[i].p_type == PT_TLS) {
-            Elf64_Phdr * e = &head->PHEntries[i];
+        if(head->PHEntries._64[i].p_type == PT_TLS) {
+            Elf64_Phdr * e = &head->PHEntries._64[i];
             char* dest = (char*)(context->tlsdata+context->tlssize+head->tlsbase);
             printf_log(LOG_DEBUG, "Loading TLS block #%zu @%p (0x%zx/0x%zx)\n", i, dest, e->p_filesz, e->p_memsz);
             if(e->p_filesz) {
@@ -400,7 +445,7 @@ int isElfHasNeededVer(elfheader_t* head, const char* libname, elfheader_t* verne
 {
     if(!verneeded || !head)
         return 1;
-    if(!head->VerDef || !verneeded->VerNeed)
+    if(!head->VerDef._64 || !verneeded->VerNeed._64)
         return 1;
     int cnt = GetNeededVersionCnt(verneeded, libname);
     for (int i=0; i<cnt; ++i) {
@@ -418,9 +463,9 @@ static int IsSymInElfSpace(const elfheader_t* h, Elf64_Sym* sym)
     if(!h || !sym)
         return 0;
     uintptr_t addr = (uintptr_t)sym;
-    if(h->SymTab && addr>=(uintptr_t)h->SymTab && addr<(uintptr_t)&h->SymTab[h->numSymTab])
+    if(h->SymTab._64 && addr>=(uintptr_t)h->SymTab._64 && addr<(uintptr_t)&h->SymTab._64[h->numSymTab])
         return 1;
-    if(h->DynSym && addr>=(uintptr_t)h->DynSym && addr<(uintptr_t)&h->DynSym[h->numDynSym])
+    if(h->DynSym._64 && addr>=(uintptr_t)h->DynSym._64 && addr<(uintptr_t)&h->DynSym._64[h->numDynSym])
         return 1;
     return 0;
 }
@@ -435,7 +480,7 @@ static elfheader_t* FindElfSymbol(box64context_t *context, Elf64_Sym* sym)
     return NULL;
 }
 
-int FindR64COPYRel(elfheader_t* h, const char* name, uintptr_t *offs, uint64_t** p, size_t size, int version, const char* vername, int veropt)
+static int FindR64COPYRel(elfheader_t* h, const char* name, uintptr_t *offs, uint64_t** p, size_t size, int version, const char* vername, int veropt)
 {
     if(!h)
         return 0;
@@ -445,8 +490,8 @@ int FindR64COPYRel(elfheader_t* h, const char* name, uintptr_t *offs, uint64_t**
     int cnt = h->relasz / h->relaent;
     for (int i=0; i<cnt; ++i) {
         int t = ELF64_R_TYPE(rela[i].r_info);
-        Elf64_Sym *sym = &h->DynSym[ELF64_R_SYM(rela[i].r_info)];
-        const char* symname = SymName(h, sym);
+        Elf64_Sym *sym = &h->DynSym._64[ELF64_R_SYM(rela[i].r_info)];
+        const char* symname = SymName64(h, sym);
         if((t==R_X86_64_COPY) && symname && !strcmp(symname, name) && (sym->st_size==size)) {
             int version2 = h->VerSym?((Elf64_Half*)((uintptr_t)h->VerSym+h->delta))[ELF64_R_SYM(rela[i].r_info)]:-1;
             if(version2!=-1) version2 &= 0x7fff;
@@ -464,7 +509,7 @@ int FindR64COPYRel(elfheader_t* h, const char* name, uintptr_t *offs, uint64_t**
     return 0;
 }
 
-int RelocateElfREL(lib_t *maplib, lib_t *local_maplib, int bindnow, int deepbind, elfheader_t* head, int cnt, Elf64_Rel *rel)
+static int RelocateElfREL(lib_t *maplib, lib_t *local_maplib, int bindnow, int deepbind, elfheader_t* head, int cnt, Elf64_Rel *rel)
 {
     printf_log(LOG_NONE, "Error: REL type of Relocation unsupported (only RELA)\n");
     return 1;
@@ -483,7 +528,7 @@ EXPORT uintptr_t my__dl_tlsdesc_undefweak(x64emu_t* emu)
     return td->arg;
 }
 
-void GrabX64CopyMainElfReloc(elfheader_t* head)
+static void GrabX64CopyMainElfReloc(elfheader_t* head)
 {
     if(head->rela) {
         int cnt = head->relasz / head->relaent;
@@ -492,8 +537,8 @@ void GrabX64CopyMainElfReloc(elfheader_t* head)
         for (int i=0; i<cnt; ++i) {
             int t = ELF64_R_TYPE(rela[i].r_info);
             if(t == R_X86_64_COPY) {
-                Elf64_Sym *sym = &head->DynSym[ELF64_R_SYM(rela[i].r_info)];
-                const char* symname = SymName(head, sym);
+                Elf64_Sym *sym = &head->DynSym._64[ELF64_R_SYM(rela[i].r_info)];
+                const char* symname = SymName64(head, sym);
                 int version = head->VerSym?((Elf64_Half*)((uintptr_t)head->VerSym+head->delta))[ELF64_R_SYM(rela[i].r_info)]:-1;
                 if(version!=-1) version &=0x7fff;
                 const char* vername = GetSymbolVersion(head, version);
@@ -505,21 +550,6 @@ void GrabX64CopyMainElfReloc(elfheader_t* head)
         }
     }
 }
-void CheckGNUUniqueBindings(elfheader_t* head)
-{
-    if(head->rela) {
-        int cnt = head->relasz / head->relaent;
-        Elf64_Rela* rela = (Elf64_Rela *)(head->rela + head->delta);
-        printf_dump(LOG_DEBUG, "Checking for symbol with STB_GNU_UNIQUE bindingsfor %s\n", head->name);
-        for (int i=0; i<cnt; ++i) {
-            int bind = ELF64_ST_BIND(rela[i].r_info);
-            if(bind == STB_GNU_UNIQUE) {
-                head->gnuunique = 1;
-                return; // can stop searching
-            }
-        }
-    }
-}
 
 static elfheader_t* checkElfLib(elfheader_t* h, library_t* lib)
 {
@@ -531,15 +561,15 @@ static elfheader_t* checkElfLib(elfheader_t* h, library_t* lib)
     return h;
 }
 
-int RelocateElfRELA(lib_t *maplib, lib_t *local_maplib, int bindnow, int deepbind, elfheader_t* head, int cnt, Elf64_Rela *rela, int* need_resolv)
+static int RelocateElfRELA(lib_t *maplib, lib_t *local_maplib, int bindnow, int deepbind, elfheader_t* head, int cnt, Elf64_Rela *rela, int* need_resolv)
 {
     int ret_ok = 0;
     for (int i=0; i<cnt; ++i) {
         int t = ELF64_R_TYPE(rela[i].r_info);
-        Elf64_Sym *sym = &head->DynSym[ELF64_R_SYM(rela[i].r_info)];
+        Elf64_Sym *sym = &head->DynSym._64[ELF64_R_SYM(rela[i].r_info)];
         int bind = ELF64_ST_BIND(sym->st_info);
         //uint64_t ndx = sym->st_shndx;
-        const char* symname = SymName(head, sym);
+        const char* symname = SymName64(head, sym);
         uint64_t *p = (uint64_t*)(rela[i].r_offset + head->delta);
         uintptr_t offs = 0;
         uintptr_t end = 0;
@@ -554,7 +584,7 @@ int RelocateElfRELA(lib_t *maplib, lib_t *local_maplib, int bindnow, int deepbin
         Elf64_Sym* elfsym = NULL;
         int vis = ELF64_ST_VISIBILITY(sym->st_other);
         if(vis==STV_PROTECTED) {
-            elfsym = ElfDynSymLookup(head, symname);
+            elfsym = ElfDynSymLookup64(head, symname);
             printf_log(LOG_DEBUG, "Symbol %s from %s is PROTECTED\n", symname, head->name);
         } else {
             if(bind==STB_GNU_UNIQUE) {
@@ -566,7 +596,7 @@ int RelocateElfRELA(lib_t *maplib, lib_t *local_maplib, int bindnow, int deepbin
                     offs = sym->st_value + head->delta;
                     end = offs + sym->st_size;
                 } else {
-                    elfsym = ElfDynSymLookup(head, symname);
+                    elfsym = ElfDynSymLookup64(head, symname);
                     if(elfsym && elfsym->st_shndx) {
                         offs = elfsym->st_value + head->delta;
                         end = offs + elfsym->st_size;
@@ -695,7 +725,7 @@ int RelocateElfRELA(lib_t *maplib, lib_t *local_maplib, int bindnow, int deepbin
                     if(offs!=globoffs) {
                         offs = globoffs;
                         sym_elf = my_context->elfs[0];
-                        elfsym = ElfDynSymLookup(sym_elf, symname);
+                        elfsym = ElfDynSymLookup64(sym_elf, symname);
                     }
                 }
                 if (!offs && !elfsym) {
@@ -718,11 +748,11 @@ int RelocateElfRELA(lib_t *maplib, lib_t *local_maplib, int bindnow, int deepbin
                     }
                     if(sym_elf) {
                         delta = *(int64_t*)p;
-                        printf_dump(LOG_NEVER, "Applying %s %s on %s @%p (%ld -> %ld+%ld+%ld, size=%ld)\n", BindSym(bind), DumpRelType(t), symname, p, delta, sym_elf->tlsbase, (int64_t)offs, rela[i].r_addend, end-offs);
+                        printf_dump(LOG_NEVER, "Applying %s %s on %s @%p (%ld -> %ld+%ld+%ld, size=%ld)\n", BindSym(bind), DumpRelType64(t), symname, p, delta, sym_elf->tlsbase, (int64_t)offs, rela[i].r_addend, end-offs);
                         *p = (uintptr_t)((int64_t)offs + rela[i].r_addend + sym_elf->tlsbase);
                         if(sym_elf && sym_elf!=last_elf && sym_elf!=head) last_elf = checkElfLib(head, sym_elf->lib);
                     } else {
-                        printf_log(LOG_INFO, "Warning, cannot apply %s %s on %s @%p (%ld), no elf_header found\n", BindSym(bind), DumpRelType(t), symname, p, (int64_t)offs);
+                        printf_log(LOG_INFO, "Warning, cannot apply %s %s on %s @%p (%ld), no elf_header found\n", BindSym(bind), DumpRelType64(t), symname, p, (int64_t)offs);
                     }
                 }
                 break;
@@ -779,13 +809,13 @@ int RelocateElfRELA(lib_t *maplib, lib_t *local_maplib, int bindnow, int deepbin
                 }
                 break;
             default:
-                printf_log(LOG_INFO, "Warning, don't know of to handle rela #%d %s on %s\n", i, DumpRelType(ELF64_R_TYPE(rela[i].r_info)), symname);
+                printf_log(LOG_INFO, "Warning, don't know of to handle rela #%d %s on %s\n", i, DumpRelType64(ELF64_R_TYPE(rela[i].r_info)), symname);
         }
     }
     return bindnow?ret_ok:0;
 }
 
-int RelocateElfRELR(elfheader_t *head, int cnt, Elf64_Relr *relr) {
+static int RelocateElfRELR(elfheader_t *head, int cnt, Elf64_Relr *relr) {
     Elf64_Addr *where = NULL;
     for (int i = 0; i < cnt; i++) {
         Elf64_Relr p = relr[i];
@@ -805,7 +835,13 @@ int RelocateElfRELR(elfheader_t *head, int cnt, Elf64_Relr *relr) {
     return 0;
 }
 
-int RelocateElf(lib_t *maplib, lib_t *local_maplib, int bindnow, int deepbind, elfheader_t* head)
+int RelocateElf32(lib_t *maplib, lib_t *local_maplib, int bindnow, int deepbind, elfheader_t* head)
+#ifndef BOX32
+{ return -1; }
+#else
+ ;
+#endif
+int RelocateElf64(lib_t *maplib, lib_t *local_maplib, int bindnow, int deepbind, elfheader_t* head)
 {
     if((head->flags&DF_BIND_NOW) && !bindnow) {
         bindnow = 1;
@@ -813,29 +849,34 @@ int RelocateElf(lib_t *maplib, lib_t *local_maplib, int bindnow, int deepbind, e
     }
     if(head->relr) {
         int cnt = head->relrsz / head->relrent;
-        DumpRelRTable(head, cnt, (Elf64_Relr *)(head->relr + head->delta), "RelR");
+        DumpRelRTable64(head, cnt, (Elf64_Relr *)(head->relr + head->delta), "RelR");
         printf_dump(LOG_DEBUG, "Applying %d Relocation(s) without Addend for %s bindnow=%d, deepbind=%d\n", cnt, head->name, bindnow, deepbind);
         if(RelocateElfRELR(head, cnt, (Elf64_Relr *)(head->relr + head->delta)))
             return -1;
     }
     if(head->rel) {
         int cnt = head->relsz / head->relent;
-        DumpRelTable(head, cnt, (Elf64_Rel *)(head->rel + head->delta), "Rel");
+        DumpRelTable64(head, cnt, (Elf64_Rel *)(head->rel + head->delta), "Rel");
         printf_dump(LOG_DEBUG, "Applying %d Relocation(s) for %s bindnow=%d, deepbind=%d\n", cnt, head->name, bindnow, deepbind);
         if(RelocateElfREL(maplib, local_maplib, bindnow, deepbind, head, cnt, (Elf64_Rel *)(head->rel + head->delta)))
             return -1;
     }
     if(head->rela) {
         int cnt = head->relasz / head->relaent;
-        DumpRelATable(head, cnt, (Elf64_Rela *)(head->rela + head->delta), "RelA");
+        DumpRelATable64(head, cnt, (Elf64_Rela *)(head->rela + head->delta), "RelA");
         printf_dump(LOG_DEBUG, "Applying %d Relocation(s) with Addend for %s bindnow=%d, deepbind=%d\n", cnt, head->name, bindnow, deepbind);
         if(RelocateElfRELA(maplib, local_maplib, bindnow, deepbind, head, cnt, (Elf64_Rela *)(head->rela + head->delta), NULL))
             return -1;
     }
     return 0;
 }
+int RelocateElf(lib_t *maplib, lib_t *local_maplib, int bindnow, int deepbind, elfheader_t* head)
+{
+    return box64_is32bits?RelocateElf32(maplib, local_maplib, bindnow, deepbind, head):RelocateElf64(maplib, local_maplib, bindnow, deepbind, head);
+}
 
-int RelocateElfPlt(lib_t *maplib, lib_t *local_maplib, int bindnow, int deepbind, elfheader_t* head)
+int RelocateElfPlt32(lib_t *maplib, lib_t *local_maplib, int bindnow, int deepbind, elfheader_t* head) { /* TODO */ return -1; }
+int RelocateElfPlt64(lib_t *maplib, lib_t *local_maplib, int bindnow, int deepbind, elfheader_t* head)
 {
     int need_resolver = 0;
     if((head->flags&DF_BIND_NOW) && !bindnow) {
@@ -845,26 +886,26 @@ int RelocateElfPlt(lib_t *maplib, lib_t *local_maplib, int bindnow, int deepbind
     if(head->pltrel) {
         int cnt = head->pltsz / head->pltent;
         if(head->pltrel==DT_REL) {
-            DumpRelTable(head, cnt, (Elf64_Rel *)(head->jmprel + head->delta), "PLT");
+            DumpRelTable64(head, cnt, (Elf64_Rel *)(head->jmprel + head->delta), "PLT");
             printf_dump(LOG_DEBUG, "Applying %d PLT Relocation(s) for %s bindnow=%d, deepbind=%d\n", cnt, head->name, bindnow, deepbind);
             if(RelocateElfREL(maplib, local_maplib, bindnow, deepbind, head, cnt, (Elf64_Rel *)(head->jmprel + head->delta)))
                 return -1;
         } else if(head->pltrel==DT_RELA) {
-            DumpRelATable(head, cnt, (Elf64_Rela *)(head->jmprel + head->delta), "PLT");
+            DumpRelATable64(head, cnt, (Elf64_Rela *)(head->jmprel + head->delta), "PLT");
             printf_dump(LOG_DEBUG, "Applying %d PLT Relocation(s) with Addend for %s bindnow=%d, deepbind=%d\n", cnt, head->name, bindnow, deepbind);
             if(RelocateElfRELA(maplib, local_maplib, bindnow, deepbind, head, cnt, (Elf64_Rela *)(head->jmprel + head->delta), &need_resolver))
                 return -1;
         }
         if(need_resolver) {
-            if(pltResolver==(uintptr_t)-1) {
-                pltResolver = AddBridge(my_context->system, vFE, PltResolver, 0, "PltResolver");
+            if(pltResolver64==(uintptr_t)-1) {
+                pltResolver64 = AddBridge(my_context->system, vFE, PltResolver64, 0, "PltResolver");
             }
             if(head->pltgot) {
-                *(uintptr_t*)(head->pltgot+head->delta+16) = pltResolver;
+                *(uintptr_t*)(head->pltgot+head->delta+16) = pltResolver64;
                 *(uintptr_t*)(head->pltgot+head->delta+8) = (uintptr_t)head;
                 printf_dump(LOG_DEBUG, "PLT Resolver injected in plt.got at %p\n", (void*)(head->pltgot+head->delta+16));
             } else if(head->got) {
-                *(uintptr_t*)(head->got+head->delta+16) = pltResolver;
+                *(uintptr_t*)(head->got+head->delta+16) = pltResolver64;
                 *(uintptr_t*)(head->got+head->delta+8) = (uintptr_t)head;
                 printf_dump(LOG_DEBUG, "PLT Resolver injected in got at %p\n", (void*)(head->got+head->delta+16));
             }
@@ -873,6 +914,10 @@ int RelocateElfPlt(lib_t *maplib, lib_t *local_maplib, int bindnow, int deepbind
    
     return 0;
 }
+int RelocateElfPlt(lib_t *maplib, lib_t *local_maplib, int bindnow, int deepbind, elfheader_t* head)
+{
+    return box64_is32bits?RelocateElfPlt32(maplib, local_maplib, bindnow, deepbind, head):RelocateElfPlt64(maplib, local_maplib, bindnow, deepbind, head);
+}
 
 void CalcStack(elfheader_t* elf, uint64_t* stacksz, size_t* stackalign)
 {
@@ -882,43 +927,6 @@ void CalcStack(elfheader_t* elf, uint64_t* stacksz, size_t* stackalign)
         *stackalign = elf->stackalign;
 }
 
-Elf64_Sym* GetFunction(elfheader_t* h, const char* name)
-{
-    // TODO: create a hash on named to avoid this loop
-    for (size_t i=0; i<h->numSymTab; ++i) {
-        int type = ELF64_ST_TYPE(h->SymTab[i].st_info);
-        if(type==STT_FUNC) {
-            const char * symname = h->StrTab+h->SymTab[i].st_name;
-            if(strcmp(symname, name)==0) {
-                return h->SymTab+i;
-            }
-        }
-    }
-    return NULL;
-}
-
-Elf64_Sym* GetElfObject(elfheader_t* h, const char* name)
-{
-    for (size_t i=0; i<h->numSymTab; ++i) {
-        int type = ELF64_ST_TYPE(h->SymTab[i].st_info);
-        if(type==STT_OBJECT) {
-            const char * symname = h->StrTab+h->SymTab[i].st_name;
-            if(strcmp(symname, name)==0) {
-                return h->SymTab+i;
-            }
-        }
-    }
-    return NULL;
-}
-
-
-uintptr_t GetFunctionAddress(elfheader_t* h, const char* name)
-{
-    Elf64_Sym* sym = GetFunction(h, name);
-    if(sym) return sym->st_value;
-    return 0;
-}
-
 uintptr_t GetEntryPoint(lib_t* maplib, elfheader_t* h)
 {
     (void)maplib;
@@ -945,13 +953,18 @@ uintptr_t GetLastByte(elfheader_t* h)
 #endif
 
 void checkHookedSymbols(elfheader_t* h); // in mallochook.c
+void AddSymbols32(lib_t *maplib, elfheader_t* h) { /* TODO */ }
 void AddSymbols(lib_t *maplib, elfheader_t* h)
 {
-    //if(box64_dump && h->hash)   old_elf_hash_dump(h);
-    //if(box64_dump && h->gnu_hash)   new_elf_hash_dump(h);
-    if(box64_dump && h->DynSym) DumpDynSym(h);
-    if(h==my_context->elfs[0]) 
-        GrabX64CopyMainElfReloc(h);
+    if(box64_is32bits) {
+        AddSymbols32(maplib, h);
+    } else {
+        //if(box64_dump && h->hash)   old_elf_hash_dump(h);
+        //if(box64_dump && h->gnu_hash)   new_elf_hash_dump(h);
+        if(box64_dump && h->DynSym._64) DumpDynSym64(h);
+        if(h==my_context->elfs[0]) 
+            GrabX64CopyMainElfReloc(h);
+    }
     #ifndef STATICBUILD
     checkHookedSymbols(h);
     #endif
@@ -977,9 +990,10 @@ int LoadNeededLibs(elfheader_t* h, lib_t *maplib, int local, int bindnow, int de
         return 0;
     DumpDynamicRPath(h);
     // update RPATH first
-    for (size_t i=0; i<h->numDynamic; ++i)
-        if(h->Dynamic[i].d_tag==DT_RPATH || h->Dynamic[i].d_tag==DT_RUNPATH) {
-            char *rpathref = h->DynStrTab+h->delta+h->Dynamic[i].d_un.d_val;
+    for (size_t i=0; i<h->numDynamic; ++i) {
+        int tag = box64_is32bits?h->Dynamic._32[i].d_tag:h->Dynamic._64[i].d_tag;
+        if(tag==DT_RPATH || tag==DT_RUNPATH) {
+            char *rpathref = h->DynStrTab+h->delta+(box64_is32bits?h->Dynamic._32[i].d_un.d_val:h->Dynamic._64[i].d_un.d_val);
             char* rpath = rpathref;
             while(strstr(rpath, "$ORIGIN")) {
                 char* origin = box_strdup(h->path);
@@ -1032,23 +1046,24 @@ int LoadNeededLibs(elfheader_t* h, lib_t *maplib, int local, int bindnow, int de
             if(rpath!=rpathref)
                 box_free(rpath);
         }
-
+    }
     DumpDynamicNeeded(h);
     int cnt = 0;
     // count the number of needed libs, and also grab soname
     for (size_t i=0; i<h->numDynamic; ++i) {
-        if(h->Dynamic[i].d_tag==DT_NEEDED)
+        int tag = box64_is32bits?h->Dynamic._32[i].d_tag:h->Dynamic._64[i].d_tag;
+        if(tag==DT_NEEDED)
             ++cnt;
-        if(h->Dynamic[i].d_tag==DT_SONAME)
-            h->soname = h->DynStrTab+h->delta+h->Dynamic[i].d_un.d_val;
+        if(tag==DT_SONAME)
+            h->soname = h->DynStrTab+h->delta+(box64_is32bits?h->Dynamic._32[i].d_un.d_val:h->Dynamic._64[i].d_un.d_val);
     }
     h->needed = new_neededlib(cnt);
     if(h == my_context->elfs[0])
         my_context->neededlibs = h->needed;
     int j=0;
     for (size_t i=0; i<h->numDynamic; ++i)
-        if(h->Dynamic[i].d_tag==DT_NEEDED)
-            h->needed->names[j++] = h->DynStrTab+h->delta+h->Dynamic[i].d_un.d_val;
+        if((box64_is32bits?h->Dynamic._32[i].d_tag:h->Dynamic._64[i].d_tag)==DT_NEEDED)
+            h->needed->names[j++] = h->DynStrTab+h->delta+(box64_is32bits?h->Dynamic._32[i].d_un.d_val:h->Dynamic._64[i].d_un.d_val);
     if(h==my_context->elfs[0] && box64_addlibs.size) {
         for(int i=0; i<box64_addlibs.size; ++i) {
             printf_log(LOG_INFO, "BOX64, Adding %s to needed libs of %s\n", box64_addlibs.paths[i], h->name);
@@ -1069,8 +1084,8 @@ int ElfCheckIfUseTCMallocMinimal(elfheader_t* h)
     if(!h)
         return 0;
     for (size_t i=0; i<h->numDynamic; ++i)
-        if(h->Dynamic[i].d_tag==DT_NEEDED) {
-            char *needed = h->DynStrTab+h->delta+h->Dynamic[i].d_un.d_val;
+        if((box64_is32bits?h->Dynamic._32[i].d_tag:h->Dynamic._64[i].d_tag)==DT_NEEDED) {
+            char *needed = h->DynStrTab+h->delta+(box64_is32bits?h->Dynamic._32[i].d_un.d_val:h->Dynamic._64[i].d_un.d_val);
             if(!strcmp(needed, "libtcmalloc_minimal.so.4")) // tcmalloc needs to be the 1st lib loaded
                 return 1;
             else if(!strcmp(needed, "libtcmalloc_minimal.so.0")) // tcmalloc needs to be the 1st lib loaded
@@ -1106,10 +1121,15 @@ void startMallocHook();
 #else
 void startMallocHook() {}
 #endif
+void RunElfInit32(elfheader_t* h, x64emu_t *emu) { /* TODO*/ }
 void RunElfInit(elfheader_t* h, x64emu_t *emu)
 {
     if(!h || h->init_done)
         return;
+    if(box64_is32bits) {
+        RunElfInit32(h, emu);
+        return;
+    }
     // reset Segs Cache
     memset(emu->segs_serial, 0, sizeof(emu->segs_serial));
     uintptr_t p = h->initentry + h->delta;
@@ -1171,10 +1191,15 @@ void RunDeferredElfInit(x64emu_t *emu)
     box_free(List);
 }
 
+void RunElfFini32(elfheader_t* h, x64emu_t *emu) { /* TODO */ }
 void RunElfFini(elfheader_t* h, x64emu_t *emu)
 {
     if(!h || h->fini_done || !h->init_done)
         return;
+    if(box64_is32bits) {
+        RunElfFini32(h, emu);
+        return;
+    }
     h->fini_done = 1;
     // Call the registered cxa_atexit functions
     CallCleanup(emu, h);
@@ -1274,28 +1299,28 @@ const char* FindNearestSymbolName(elfheader_t* h, void* p, uintptr_t* start, uin
         return ret;
 
     for (size_t i=0; i<h->numSymTab && distance!=0; ++i) {
-        const char * symname = h->StrTab+h->SymTab[i].st_name;
-        uintptr_t offs = h->SymTab[i].st_value + h->delta;
+        const char * symname = box64_is32bits?(h->StrTab+h->SymTab._32[i].st_name):(h->StrTab+h->SymTab._64[i].st_name);
+        uintptr_t offs = (box64_is32bits?h->SymTab._32[i].st_value:h->SymTab._64[i].st_value) + h->delta;
 
         if(offs<=addr) {
             if(distance>addr-offs) {
                 distance = addr-offs;
                 ret = symname;
                 s = offs;
-                size = h->SymTab[i].st_size;
+                size = box64_is32bits?h->SymTab._32[i].st_size:h->SymTab._64[i].st_size;
             }
         }
     }
     for (size_t i=0; i<h->numDynSym && distance!=0; ++i) {
-        const char * symname = h->DynStr+h->DynSym[i].st_name;
-        uintptr_t offs = h->DynSym[i].st_value + h->delta;
+        const char * symname = h->DynStr+(box64_is32bits?h->DynSym._32[i].st_name:h->DynSym._64[i].st_name);
+        uintptr_t offs = (box64_is32bits?h->DynSym._32[i].st_value:h->DynSym._64[i].st_value) + h->delta;
 
         if(offs<=addr) {
             if(distance>addr-offs) {
                 distance = addr-offs;
                 ret = symname;
                 s = offs;
-                size = h->DynSym[i].st_size;
+                size = box64_is32bits?h->DynSym._32[i].st_size:h->DynSym._64[i].st_size;
             }
         }
     }
@@ -1376,7 +1401,7 @@ void* GetDynamicSection(elfheader_t* h)
 {
     if(!h)
         return NULL;
-    return h->Dynamic;
+    return box64_is32bits?((void*)h->Dynamic._32):((void*)h->Dynamic._64);
 }
 
 #ifdef DYNAREC
@@ -1452,6 +1477,7 @@ static void* find_dl_iterate_phdr_Fct(void* fct)
 #undef SUPER
 
 EXPORT int my_dl_iterate_phdr(x64emu_t *emu, void* F, void *data) {
+    if(box64_is32bits) {printf_log(LOG_NONE, "Error, calling unsuppoeted dl_iterate_phdr in 32bits\n"); return 0; }
     printf_log(LOG_DEBUG, "Call to partially implemented dl_iterate_phdr(%p, %p)\n", F, data);
     box64context_t *context = GetEmuContext(emu);
     const char* empty = "";
@@ -1461,7 +1487,7 @@ EXPORT int my_dl_iterate_phdr(x64emu_t *emu, void* F, void *data) {
             my_dl_phdr_info_t info;
             info.dlpi_addr = GetElfDelta(context->elfs[idx]);
             info.dlpi_name = idx?context->elfs[idx]->name:empty;    //1st elf is program, and this one doesn't get a name
-            info.dlpi_phdr = context->elfs[idx]->PHEntries;
+            info.dlpi_phdr = context->elfs[idx]->PHEntries._64;
             info.dlpi_phnum = context->elfs[idx]->numPHEntries;
             if((ret = dl_iterate_phdr_callback(emu, F, &info, sizeof(info), data))) {
                 return ret;
@@ -1473,12 +1499,17 @@ EXPORT int my_dl_iterate_phdr(x64emu_t *emu, void* F, void *data) {
     return ret;
 }
 
+void ResetSpecialCaseMainElf32(elfheader_t* h) { /* TODO */ }
 void ResetSpecialCaseMainElf(elfheader_t* h)
 {
+    if(box64_is32bits) {
+        ResetSpecialCaseMainElf32(h);
+        return;
+    }
     Elf64_Sym *sym = NULL;
     for (size_t i=0; i<h->numDynSym; ++i) {
-        if(h->DynSym[i].st_info == 17) {
-            sym = h->DynSym+i;
+        if(h->DynSym._64[i].st_info == 17) {
+            sym = h->DynSym._64+i;
             const char * symname = h->DynStr+sym->st_name;
             if(strcmp(symname, "_IO_2_1_stderr_")==0 && ((void*)sym->st_value+h->delta)) {
                 memcpy((void*)sym->st_value+h->delta, stderr, sym->st_size);
@@ -1564,12 +1595,12 @@ void ElfAttachLib(elfheader_t* head, library_t* lib)
     head->lib = lib;
 }
 
-Elf64_Sym* ElfLocateSymbol(elfheader_t* head, uintptr_t *offs, uintptr_t *end, const char* symname, int* ver, const char** vername, int local, int* veropt)
+static Elf64_Sym* ElfLocateSymbol(elfheader_t* head, uintptr_t *offs, uintptr_t *end, const char* symname, int* ver, const char** vername, int local, int* veropt)
 {
-    Elf64_Sym* sym = ElfLookup(head, symname, *ver, *vername, local, *veropt);
+    Elf64_Sym* sym = ElfLookup64(head, symname, *ver, *vername, local, *veropt);
     if(!sym) return NULL;
     if(head->VerSym && !*veropt) {
-        int idx = ((uintptr_t)sym - (uintptr_t)head->DynSym)/sizeof(Elf64_Sym);
+        int idx = ((uintptr_t)sym - (uintptr_t)head->DynSym._64)/sizeof(Elf64_Sym);
         int version = ((Elf64_Half*)((uintptr_t)head->VerSym+head->delta))[idx];
         if(version!=-1) version &=0x7fff;
         const char* symvername = GetSymbolVersion(head, version);
@@ -1589,7 +1620,8 @@ Elf64_Sym* ElfLocateSymbol(elfheader_t* head, uintptr_t *offs, uintptr_t *end, c
     return sym;
 }
 
-void* ElfGetLocalSymbolStartEnd(elfheader_t* head, uintptr_t *offs, uintptr_t *end, const char* symname, int* ver, const char** vername, int local, int* veropt)
+void* ElfGetLocalSymbolStartEnd32(elfheader_t* head, uintptr_t *offs, uintptr_t *end, const char* symname, int* ver, const char** vername, int local, int* veropt) { /* TOODO */ return NULL; }
+void* ElfGetLocalSymbolStartEnd64(elfheader_t* head, uintptr_t *offs, uintptr_t *end, const char* symname, int* ver, const char** vername, int local, int* veropt)
 {
     Elf64_Sym* sym = ElfLocateSymbol(head, offs, end, symname, ver, vername, local, veropt);
     if(!sym) return NULL;
@@ -1599,7 +1631,13 @@ void* ElfGetLocalSymbolStartEnd(elfheader_t* head, uintptr_t *offs, uintptr_t *e
     if(end) *end = sym->st_value + head->delta + sym->st_size;
     return sym;
 }
-void* ElfGetGlobalSymbolStartEnd(elfheader_t* head, uintptr_t *offs, uintptr_t *end, const char* symname, int* ver, const char** vername, int local, int* veropt)
+void* ElfGetLocalSymbolStartEnd(elfheader_t* head, uintptr_t *offs, uintptr_t *end, const char* symname, int* ver, const char** vername, int local, int* veropt)
+{
+    return box64_is32bits?ElfGetLocalSymbolStartEnd32(head, offs, end, symname, ver, vername, local, veropt):ElfGetLocalSymbolStartEnd64(head, offs, end, symname, ver, vername, local, veropt);
+}
+
+void* ElfGetGlobalSymbolStartEnd32(elfheader_t* head, uintptr_t *offs, uintptr_t *end, const char* symname, int* ver, const char** vername, int local, int* veropt) { /*T ODO */ return NULL; }
+void* ElfGetGlobalSymbolStartEnd64(elfheader_t* head, uintptr_t *offs, uintptr_t *end, const char* symname, int* ver, const char** vername, int local, int* veropt)
 {
     Elf64_Sym* sym = ElfLocateSymbol(head, offs, end, symname, ver, vername, local, veropt);
     if(!sym) return NULL;
@@ -1609,7 +1647,13 @@ void* ElfGetGlobalSymbolStartEnd(elfheader_t* head, uintptr_t *offs, uintptr_t *
     if(end) *end = sym->st_value + head->delta + sym->st_size;
     return sym;
 }
-void* ElfGetWeakSymbolStartEnd(elfheader_t* head, uintptr_t *offs, uintptr_t *end, const char* symname, int* ver, const char** vername, int local, int* veropt)
+void* ElfGetGlobalSymbolStartEnd(elfheader_t* head, uintptr_t *offs, uintptr_t *end, const char* symname, int* ver, const char** vername, int local, int* veropt)
+{
+    return box64_is32bits?ElfGetGlobalSymbolStartEnd32(head, offs, end, symname, ver, vername, local, veropt):ElfGetGlobalSymbolStartEnd64(head, offs, end, symname, ver, vername, local, veropt);
+}
+
+void* ElfGetWeakSymbolStartEnd32(elfheader_t* head, uintptr_t *offs, uintptr_t *end, const char* symname, int* ver, const char** vername, int local, int* veropt) { /* TODO */ return NULL; }
+void* ElfGetWeakSymbolStartEnd64(elfheader_t* head, uintptr_t *offs, uintptr_t *end, const char* symname, int* ver, const char** vername, int local, int* veropt)
 {
     Elf64_Sym* sym = ElfLocateSymbol(head, offs, end, symname, ver, vername, local, veropt);
     if(!sym) return NULL;
@@ -1619,9 +1663,15 @@ void* ElfGetWeakSymbolStartEnd(elfheader_t* head, uintptr_t *offs, uintptr_t *en
     if(end) *end = sym->st_value + head->delta + sym->st_size;
     return sym;
 }
-int ElfGetSymTabStartEnd(elfheader_t* head, uintptr_t *offs, uintptr_t *end, const char* symname)
+void* ElfGetWeakSymbolStartEnd(elfheader_t* head, uintptr_t *offs, uintptr_t *end, const char* symname, int* ver, const char** vername, int local, int* veropt)
+{
+    return box64_is32bits?ElfGetWeakSymbolStartEnd32(head, offs, end, symname, ver, vername, local, veropt):ElfGetWeakSymbolStartEnd64(head, offs, end, symname, ver, vername, local, veropt);
+}
+
+int ElfGetSymTabStartEnd32(elfheader_t* head, uintptr_t *offs, uintptr_t *end, const char* symname) { /* TODO */ return 0; }
+int ElfGetSymTabStartEnd64(elfheader_t* head, uintptr_t *offs, uintptr_t *end, const char* symname)
 {
-    Elf64_Sym* sym = ElfSymTabLookup(head, symname);
+    Elf64_Sym* sym = ElfSymTabLookup64(head, symname);
     if(!sym) return 0;
     if(!sym->st_shndx) return 0;
     if(!sym->st_size) return 0; //needed?
@@ -1629,6 +1679,10 @@ int ElfGetSymTabStartEnd(elfheader_t* head, uintptr_t *offs, uintptr_t *end, con
     if(end) *end = sym->st_value + head->delta + sym->st_size;
     return 1;
 }
+int ElfGetSymTabStartEnd(elfheader_t* head, uintptr_t *offs, uintptr_t *end, const char* symname)
+{
+    return box64_is32bits?ElfGetSymTabStartEnd32(head, offs, end, symname):ElfGetSymTabStartEnd64(head, offs, end, symname);
+}
 
 typedef struct search_symbol_s{
     const char* name;
@@ -1701,8 +1755,8 @@ void* GetNativeSymbolUnversioned(void* lib, const char* name)
     return s.addr;
 }
 
-uintptr_t pltResolver = ~0LL;
-EXPORT void PltResolver(x64emu_t* emu)
+uintptr_t pltResolver64 = ~0LL;
+EXPORT void PltResolver64(x64emu_t* emu)
 {
     uintptr_t addr = Pop64(emu);
     int slot = (int)Pop64(emu);
@@ -1710,13 +1764,13 @@ EXPORT void PltResolver(x64emu_t* emu)
     library_t* lib = h->lib;
     lib_t* local_maplib = GetMaplib(lib);
     int deepbind = GetDeepBind(lib);
-    printf_dump(LOG_DEBUG, "PltResolver: Addr=%p, Slot=%d Return=%p(%s): elf is %s (VerSym=%p, deepbind=%d, local_maplib=%p) func param: %p, %p...\n", (void*)addr, slot, *(void**)(R_RSP), getAddrFunctionName(*(uintptr_t*)R_RSP),h->name, h->VerSym, deepbind, local_maplib, (void*)R_RDI, (void*)R_RSI);
+    printf_dump(LOG_DEBUG, "PltResolver64: Addr=%p, Slot=%d Return=%p(%s): elf is %s (VerSym=%p, deepbind=%d, local_maplib=%p) func param: %p, %p...\n", (void*)addr, slot, *(void**)(R_RSP), getAddrFunctionName(*(uintptr_t*)R_RSP),h->name, h->VerSym, deepbind, local_maplib, (void*)R_RDI, (void*)R_RSI);
 
     Elf64_Rela * rel = (Elf64_Rela *)(h->jmprel + h->delta) + slot;
 
-    Elf64_Sym *sym = &h->DynSym[ELF64_R_SYM(rel->r_info)];
+    Elf64_Sym *sym = &h->DynSym._64[ELF64_R_SYM(rel->r_info)];
     int bind = ELF64_ST_BIND(sym->st_info);
-    const char* symname = SymName(h, sym);
+    const char* symname = SymName64(h, sym);
     int version = h->VerSym?((Elf64_Half*)((uintptr_t)h->VerSym+h->delta))[ELF64_R_SYM(rel->r_info)]:-1;
     if(version!=-1) version &= 0x7fff;
     const char* vername = GetSymbolVersion(h, version);
@@ -1728,7 +1782,7 @@ EXPORT void PltResolver(x64emu_t* emu)
 
     Elf64_Sym *elfsym = NULL;
     if(bind==STB_LOCAL) {
-        elfsym = ElfDynSymLookup(h, symname);
+        elfsym = ElfDynSymLookup64(h, symname);
         if(elfsym && elfsym->st_shndx) {
             offs = elfsym->st_value + h->delta;
             end = offs + elfsym->st_size;
diff --git a/src/elfs/elfloader32.c b/src/elfs/elfloader32.c
new file mode 100644
index 00000000..3b30bc07
--- /dev/null
+++ b/src/elfs/elfloader32.c
@@ -0,0 +1,626 @@
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <elf.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/sysmacros.h>
+#include <sys/types.h>
+#include <link.h>
+#include <unistd.h>
+#include <errno.h>
+#ifndef _DLFCN_H
+#include <dlfcn.h>
+#endif
+
+#include "custommem.h"
+#include "box64version.h"
+#include "elfloader.h"
+#include "debug.h"
+#include "elfload_dump.h"
+#include "elfloader_private.h"
+#include "librarian.h"
+#include "x64run.h"
+#include "bridge.h"
+#include "wrapper.h"
+#include "box64context.h"
+#include "library.h"
+#include "x64emu.h"
+#include "box64stack.h"
+#include "callback.h"
+#include "box64stack.h"
+#include "wine_tools.h"
+#include "dictionnary.h"
+#include "symbols.h"
+#ifdef DYNAREC
+#include "dynablock.h"
+#endif
+#include "../emu/x64emu_private.h"
+#include "../emu/x64run_private.h"
+#include "../tools/bridge_private.h"
+#include "x64tls.h"
+#include "box32.h"
+
+// return the index of header (-1 if it doesn't exist)
+static int getElfIndex(box64context_t* ctx, elfheader_t* head) {
+    for (int i=0; i<ctx->elfsize; ++i)
+        if(ctx->elfs[i]==head)
+            return i;
+    return -1;
+}
+
+static elfheader_t* checkElfLib(elfheader_t* h, library_t* lib)
+{
+    if(h && lib) {
+        if(!h->needed)
+            h->needed = new_neededlib(1);
+        add1libref_neededlib(h->needed, lib);
+    }
+    return h;
+}
+
+int AllocLoadElfMemory32(box64context_t* context, elfheader_t* head, int mainbin)
+{
+    ptr_t offs = 0;
+    loadProtectionFromMap();
+    int log_level = box64_load_addr?LOG_INFO:LOG_DEBUG;
+
+    head->multiblock_n = 0; // count PHEntrie with LOAD
+    uintptr_t max_align = (box64_pagesize-1);
+    for (size_t i=0; i<head->numPHEntries; ++i) 
+        if(head->PHEntries._32[i].p_type == PT_LOAD && head->PHEntries._32[i].p_flags) {
+            ++head->multiblock_n;
+        }
+
+    if(!head->vaddr && box64_load_addr) {
+        offs = to_ptrv(find31bitBlockNearHint((void*)box64_load_addr, head->memsz, max_align));
+        box64_load_addr = offs + head->memsz;
+        box64_load_addr = (box64_load_addr+0x10ffffff)&~0xffffff;
+    }
+    if(!offs && !head->vaddr)
+        offs = (uintptr_t)find31bitBlockElf(head->memsz, mainbin, max_align);
+    // prereserve the whole elf image, without populating
+    size_t sz = head->memsz;
+    void* raw = NULL;
+    void* image = NULL;
+    if(!head->vaddr) {
+        sz += head->align;
+        raw = mmap64(from_ptrv(offs), sz, 0, MAP_ANONYMOUS|MAP_PRIVATE|MAP_NORESERVE, -1, 0);
+        image = (void*)(((uintptr_t)raw+max_align)&~max_align);
+    } else {
+        image = raw = mmap64(from_ptrv(head->vaddr), sz, 0, MAP_ANONYMOUS|MAP_PRIVATE|MAP_NORESERVE, -1, 0);
+    }
+    if(image!=MAP_FAILED && !head->vaddr && image!=from_ptrv(offs)) {
+        printf_log(LOG_INFO, "%s: Mmap64 for (@%p 0x%zx) for elf \"%s\" returned %p(%p/0x%zx) instead\n", (((uintptr_t)image)&max_align)?"Error":"Warning", from_ptrv(head->vaddr?head->vaddr:offs), head->memsz, head->name, image, raw, head->align);
+        offs = to_ptrv(image);
+        if(((uintptr_t)image)&max_align) {
+            munmap(raw, sz);
+            return 1;   // that's an error, alocated memory is not aligned properly
+        }
+    }
+    if(image==MAP_FAILED || image!=from_ptrv(head->vaddr?head->vaddr:offs)) {
+        printf_log(LOG_NONE, "%s cannot create memory map (@%p 0x%zx) for elf \"%s\"", (image==MAP_FAILED)?"Error:":"Warning:", from_ptrv(head->vaddr?head->vaddr:offs), head->memsz, head->name);
+        if(image==MAP_FAILED) {
+            printf_log(LOG_NONE, " error=%d/%s\n", errno, strerror(errno));
+        } else {
+            printf_log(LOG_NONE, " got %p\n", image);
+        }
+        if(image==MAP_FAILED)
+            return 1;
+        offs = to_ptrv(image)-head->vaddr;
+    }
+    printf_dump(log_level, "Pre-allocated 0x%zx byte at %p for %s\n", head->memsz, image, head->name);
+    head->delta = offs;
+    printf_dump(log_level, "Delta of %p (vaddr=%p) for Elf \"%s\"\n", from_ptrv(offs), from_ptrv(head->vaddr), head->name);
+
+    head->image = image;
+    head->raw = raw;
+    head->raw_size = sz;
+    setProtection_elf((uintptr_t)raw, sz, 0);
+
+    head->multiblocks = (multiblock_t*)box_calloc(head->multiblock_n, sizeof(multiblock_t));
+    head->tlsbase = AddTLSPartition(context, head->tlssize);
+    // and now, create all individual blocks
+    head->memory = (char*)0xffffffff;
+    int n = 0;
+    for (size_t i=0; i<head->numPHEntries; ++i) {
+        if(head->PHEntries._32[i].p_type == PT_LOAD && head->PHEntries._32[i].p_flags) {
+            Elf32_Phdr * e = &head->PHEntries._32[i];
+
+            head->multiblocks[n].flags = e->p_flags;
+            head->multiblocks[n].offs = e->p_offset;
+            head->multiblocks[n].paddr = e->p_paddr + offs;
+            head->multiblocks[n].size = e->p_filesz;
+            head->multiblocks[n].align = e->p_align;
+            uint8_t prot = PROT_READ|PROT_WRITE|((e->p_flags & PF_X)?PROT_EXEC:0);
+            // check if alignment is correct
+            uintptr_t balign = head->multiblocks[n].align-1;
+            if(balign<4095) balign = 4095;
+            head->multiblocks[n].asize = (e->p_memsz+(e->p_paddr&balign)+4095)&~4095;
+            int try_mmap = 1;
+            if(e->p_paddr&balign)
+                try_mmap = 0;
+            if(e->p_offset&(box64_pagesize-1))
+                try_mmap = 0;
+            if(ALIGN(e->p_memsz)!=ALIGN(e->p_filesz))
+                try_mmap = 0;
+            if(!e->p_filesz)
+                try_mmap = 0;
+            if(e->p_align<box64_pagesize)
+                try_mmap = 0;
+            if(try_mmap) {
+                printf_dump(log_level, "Mmaping 0x%lx(0x%lx) bytes @%p for Elf \"%s\"\n", head->multiblocks[n].size, head->multiblocks[n].asize, (void*)head->multiblocks[n].paddr, head->name);
+                void* p = mmap64(
+                    (void*)head->multiblocks[n].paddr, 
+                    head->multiblocks[n].size, 
+                    prot,
+                    MAP_PRIVATE|MAP_FIXED, //((prot&PROT_WRITE)?MAP_SHARED:MAP_PRIVATE)|MAP_FIXED,
+                    head->fileno,
+                    e->p_offset
+                );
+                if(p==MAP_FAILED || p!=(void*)head->multiblocks[n].paddr) {
+                    try_mmap = 0;
+                    printf_dump(log_level, "Mapping failed, using regular mmap+read");
+                } else {
+                    if(e->p_memsz>e->p_filesz && (prot&PROT_WRITE))
+                        memset((void*)((uintptr_t)p + e->p_filesz), 0, e->p_memsz-e->p_filesz);
+                    setProtection_elf((uintptr_t)p, head->multiblocks[n].asize, prot);
+                    head->multiblocks[n].p = p;
+
+                }
+            }
+            if(!try_mmap) {
+                uintptr_t paddr = head->multiblocks[n].paddr&~balign;
+                size_t asize = head->multiblocks[n].asize;
+                void* p = MAP_FAILED;
+                if(paddr==(paddr&~(box64_pagesize-1)) && (asize==ALIGN(asize))) {
+                    printf_dump(log_level, "Allocating 0x%zx (0x%zx) bytes @%p, will read 0x%zx @%p for Elf \"%s\"\n", asize, e->p_memsz, (void*)paddr, e->p_filesz, (void*)head->multiblocks[n].paddr, head->name);
+                    p = mmap64(
+                        (void*)paddr,
+                        asize,
+                        prot|PROT_WRITE,
+                        MAP_PRIVATE|MAP_ANONYMOUS|MAP_FIXED,
+                        -1,
+                        0
+                    );
+                } else {
+                    // difference in pagesize, so need to mmap only what needed to be...
+                    //check startint point
+                    uintptr_t new_addr = paddr;
+                    ssize_t new_size = asize;
+                    while(getProtection(new_addr) && (new_size>0)) {
+                        new_size -= ALIGN(new_addr) - new_addr;
+                        new_addr = ALIGN(new_addr);
+                    }
+                    if(new_size>0) {
+                        printf_dump(log_level, "Allocating 0x%zx (0x%zx) bytes @%p, will read 0x%zx @%p for Elf \"%s\"\n", ALIGN(new_size), e->p_memsz, (void*)new_addr, e->p_filesz, (void*)head->multiblocks[n].paddr, head->name);
+                        p = mmap64(
+                            (void*)new_addr,
+                            ALIGN(new_size),
+                            prot|PROT_WRITE,
+                            MAP_PRIVATE|MAP_ANONYMOUS|MAP_FIXED,
+                            -1,
+                            0
+                        );
+                        if(p==(void*)new_addr)
+                            p = (void*)paddr;
+                    } else {
+                        p = (void*)paddr;
+                        printf_dump(log_level, "Will read 0x%zx @%p for Elf \"%s\"\n", e->p_filesz, (void*)head->multiblocks[n].paddr, head->name);    
+                    }
+                }
+                if(p==MAP_FAILED || p!=(void*)paddr) {
+                    printf_log(LOG_NONE, "Cannot create memory map (@%p 0x%zx/0x%zx) for elf \"%s\"", (void*)paddr, asize, balign, head->name);
+                    if(p==MAP_FAILED) {
+                        printf_log(LOG_NONE, " error=%d/%s\n", errno, strerror(errno));
+                    } else {
+                        printf_log(LOG_NONE, " got %p\n", p);
+                    }
+                    return 1;
+                }
+                setProtection_elf((uintptr_t)p, asize, prot);
+                head->multiblocks[n].p = p;
+                if(e->p_filesz) {
+                    fseeko64(head->file, head->multiblocks[n].offs, SEEK_SET);
+                    if(fread((void*)head->multiblocks[n].paddr, head->multiblocks[n].size, 1, head->file)!=1) {
+                        printf_log(LOG_NONE, "Cannot read elf block (@%p 0x%zx/0x%zx) for elf \"%s\"\n", (void*)head->multiblocks[n].offs, head->multiblocks[n].asize, balign, head->name);
+                        return 1;
+                    }
+                }
+                if(!(prot&PROT_WRITE) && (paddr==(paddr&(box64_pagesize-1)) && (asize==ALIGN(asize))))
+                    mprotect((void*)paddr, asize, prot);
+            }
+#ifdef DYNAREC
+            if(box64_dynarec && (e->p_flags & PF_X)) {
+                dynarec_log(LOG_DEBUG, "Add ELF eXecutable Memory %p:%p\n", head->multiblocks[n].p, (void*)head->multiblocks[n].asize);
+                addDBFromAddressRange((uintptr_t)head->multiblocks[n].p, head->multiblocks[n].asize);
+            }
+#endif
+            if((uintptr_t)head->memory>(uintptr_t)head->multiblocks[n].p)
+                head->memory = (char*)head->multiblocks[n].p;
+            ++n;
+        }
+        if(head->PHEntries._32[i].p_type == PT_TLS) {
+            Elf32_Phdr * e = &head->PHEntries._32[i];
+            char* dest = (char*)(context->tlsdata+context->tlssize+head->tlsbase);
+            printf_log(LOG_DEBUG, "Loading TLS block #%zu @%p (0x%zx/0x%zx)\n", i, dest, e->p_filesz, e->p_memsz);
+            if(e->p_filesz) {
+                fseeko64(head->file, e->p_offset, SEEK_SET);
+                if(fread(dest, e->p_filesz, 1, head->file)!=1) {
+                    printf_log(LOG_NONE, "Fail to read PT_TLS part #%zu (size=%zd)\n", i, e->p_filesz);
+                    return 1;
+                }
+            }
+            // zero'd difference between filesz and memsz
+            if(e->p_filesz != e->p_memsz)
+                memset(dest+e->p_filesz, 0, e->p_memsz - e->p_filesz);
+        }
+    }
+
+    // can close the elf file now!
+    fclose(head->file);
+    head->file = NULL;
+    head->fileno = -1;
+
+    return 0;
+}
+
+static int IsSymInElfSpace(const elfheader_t* h, Elf32_Sym* sym)
+{
+    if(!h || !sym)
+        return 0;
+    uintptr_t addr = (uintptr_t)sym;
+    if(h->SymTab._32 && addr>=(uintptr_t)h->SymTab._32 && addr<(uintptr_t)&h->SymTab._32[h->numSymTab])
+        return 1;
+    if(h->DynSym._32 && addr>=(uintptr_t)h->DynSym._32 && addr<(uintptr_t)&h->DynSym._32[h->numDynSym])
+        return 1;
+    return 0;
+}
+static elfheader_t* FindElfSymbol(box64context_t *context, Elf32_Sym* sym)
+{
+    if(!sym)
+        return NULL;
+    for (int i=0; i<context->elfsize; ++i)
+        if(IsSymInElfSpace(context->elfs[i], sym))
+            return context->elfs[i];
+    
+    return NULL;
+}
+
+void GrabR386CopyMainElfReloc(elfheader_t* head)
+{
+    if(head->rela) {
+        int cnt = head->relasz / head->relaent;
+        Elf32_Rel* rel = (Elf32_Rel *)(head->rela + head->delta);
+        printf_dump(LOG_DEBUG, "Grabbing R_386_COPY Relocation(s) in advance for %s\n", head->name);
+        for (int i=0; i<cnt; ++i) {
+            int t = ELF32_R_TYPE(rel[i].r_info);
+            if(t == R_386_COPY) {
+                Elf32_Sym *sym = &head->DynSym._32[ELF32_R_SYM(rel[i].r_info)];
+                const char* symname = SymName32(head, sym);
+                int version = head->VerSym?((Elf32_Half*)((uintptr_t)head->VerSym+head->delta))[ELF32_R_SYM(rel[i].r_info)]:-1;
+                if(version!=-1) version &=0x7fff;
+                const char* vername = GetSymbolVersion(head, version);
+                Elf32_Half flags = GetSymbolVersionFlag(head, version);
+                int veropt = flags?0:1;
+                uintptr_t offs = sym->st_value + head->delta;
+                AddUniqueSymbol(my_context->globdata, symname, offs, sym->st_size, version, vername, veropt);
+            }
+        }
+    }
+}
+
+
+static int FindR386COPYRel(elfheader_t* h, const char* name, ptr_t *offs, uint32_t** p, size_t size, int version, const char* vername, int veropt)
+{
+    if(!h)
+        return 0;
+    if(!h->rel)
+        return 0;
+    if(h->relent) {
+        Elf32_Rel * rel = (Elf32_Rel *)(h->rel + h->delta);
+        int cnt = h->relsz / h->relent;
+        for (int i=0; i<cnt; ++i) {
+            int t = ELF32_R_TYPE(rel[i].r_info);
+            Elf32_Sym *sym = &h->DynSym._32[ELF32_R_SYM(rel[i].r_info)];
+            const char* symname = SymName32(h, sym);
+            if((t==R_386_COPY) && symname && !strcmp(symname, name) && (sym->st_size==size)) {
+                int version2 = h->VerSym?((Elf32_Half*)((uintptr_t)h->VerSym+h->delta))[ELF32_R_SYM(rel[i].r_info)]:-1;
+                if(version2!=-1) version2 &= 0x7fff;
+                if(version && !version2) version2=-1;   // match a versionned symbol against a global "local" symbol
+                const char* vername2 = GetSymbolVersion(h, version2);
+                Elf32_Half flags = GetSymbolVersionFlag(h, version2);
+                int veropt2 = flags?0:1;
+                if(SameVersionedSymbol(name, version, vername, veropt, symname, version2, vername2, veropt2)) {
+                    if(offs) *offs = sym->st_value + h->delta;
+                    if(p) *p = (uint32_t*)(rel[i].r_offset + h->delta);
+                    return 1;
+                }
+            }
+        }
+    }
+    return 0;
+}
+
+static int RelocateElfREL(lib_t *maplib, lib_t *local_maplib, int bindnow, int deepbind, elfheader_t* head, int cnt, Elf32_Rel *rel, int* need_resolv)
+{
+    int ret_ok = 0;
+    for (int i=0; i<cnt; ++i) {
+        int t = ELF32_R_TYPE(rel[i].r_info);
+        Elf32_Sym *sym = &head->DynSym._32[ELF32_R_SYM(rel[i].r_info)];
+        int bind = ELF32_ST_BIND(sym->st_info);
+        //uint32_t ndx = sym->st_shndx;
+        const char* symname = SymName32(head, sym);
+        uint32_t *p = (uint32_t*)(rel[i].r_offset + head->delta);
+        uintptr_t offs = 0;
+        uintptr_t end = 0;
+        size_t size = sym->st_size;
+        elfheader_t* sym_elf = NULL;
+        elfheader_t* last_elf = NULL;
+        int version = head->VerSym?((Elf32_Half*)((uintptr_t)head->VerSym+head->delta))[ELF32_R_SYM(rel[i].r_info)]:-1;
+        if(version!=-1) version &=0x7fff;
+        const char* vername = GetSymbolVersion(head, version);
+        Elf32_Half flags = GetSymbolVersionFlag(head, version);
+        int veropt = flags?0:1;
+        Elf32_Sym* elfsym = NULL;
+        int vis = ELF64_ST_VISIBILITY(sym->st_other);
+        if(vis==STV_PROTECTED) {
+            elfsym = ElfDynSymLookup32(head, symname);
+            printf_log(LOG_DEBUG, "Symbol %s from %s is PROTECTED\n", symname, head->name);
+        } else {
+            if(bind==STB_GNU_UNIQUE) {
+                GetGlobalSymbolStartEnd(maplib, symname, &offs, &end, head, version, vername, veropt, (void**)&elfsym);
+                if(!offs && !end && local_maplib)
+                    GetGlobalSymbolStartEnd(local_maplib, symname, &offs, &end, head, version, vername, veropt, (void**)&elfsym);
+            } else if(bind==STB_LOCAL) {
+                if(!symname || !symname[0]) {
+                    offs = sym->st_value + head->delta;
+                    end = offs + sym->st_size;
+                } else {
+                    elfsym = ElfDynSymLookup32(head, symname);
+                    if(elfsym && elfsym->st_shndx) {
+                        offs = elfsym->st_value + head->delta;
+                        end = offs + elfsym->st_size;
+                    }
+                    if(!offs && !end && local_maplib && deepbind)
+                        GetLocalSymbolStartEnd(local_maplib, symname, &offs, &end, head, version, vername, veropt, (void**)&elfsym);
+                    if(!offs && !end)
+                        GetLocalSymbolStartEnd(maplib, symname, &offs, &end, head, version, vername, veropt, (void**)&elfsym);
+                    if(!offs && !end && local_maplib && !deepbind)
+                        GetLocalSymbolStartEnd(local_maplib, symname, &offs, &end, head, version, vername, veropt, (void**)&elfsym);
+                }
+            } else {
+                if(!offs && !end && local_maplib && deepbind)
+                    GetGlobalSymbolStartEnd(local_maplib, symname, &offs, &end, head, version, vername, veropt, (void**)&elfsym);
+                if(!offs && !end)
+                    GetGlobalSymbolStartEnd(maplib, symname, &offs, &end, head, version, vername, veropt, (void**)&elfsym);
+                if(!offs && !end && local_maplib && !deepbind)
+                    GetGlobalSymbolStartEnd(local_maplib, symname, &offs, &end, head, version, vername, veropt, (void**)&elfsym);
+            }
+        }
+        sym_elf = FindElfSymbol(my_context, elfsym);
+        if(elfsym && (ELF32_ST_TYPE(elfsym->st_info)==STT_TLS))
+            offs = elfsym->st_value;
+        uintptr_t globoffs, globend;
+        uint32_t* globp;
+        uintptr_t tmp = 0;
+        intptr_t delta;
+        switch(t) {
+            case R_386_NONE:
+                // can be ignored
+                printf_dump(LOG_NEVER, "Ignoring [%d] %s %p (%p)\n", i, DumpRelType32(t), p, from_ptrv(p?(*p):0));
+                break;
+            case R_386_PC32:
+                    if (!offs) {
+                        printf_log(LOG_NONE, "Error: Global Symbol %s not found, cannot apply R_386_PC32 %p (%p) in %s\n", symname, p, from_ptrv(*p), head->name);
+                        ret_ok = 1;
+                    }
+                    if(offs)
+                        printf_dump(LOG_NEVER, "Apply [%d] %s R_386_PC32 %p with sym=%s (ver=%d/%s), (%p -> %p/%p)\n", i, (bind==STB_LOCAL)?"Local":((bind==STB_WEAK)?"Weak":"Global"), p, symname, version, vername?vername:"(none)", from_ptrv(*(ptr_t*)p), from_ptrv(*(ptr_t*)p+(offs-to_ptrv(p))), from_ptrv(offs));
+                    offs = (offs - to_ptrv(p));
+                    *p += offs;
+                break;
+            case R_386_RELATIVE:
+                printf_dump(LOG_NEVER, "Apply [%d] %s R_386_RELATIVE %p (%p -> %p)\n", i, (bind==STB_LOCAL)?"Local":((bind==STB_WEAK)?"Weak":"Global"), p, from_ptrv(*p), (void*)((*p)+head->delta));
+                *p += head->delta;
+                break;
+            case R_386_COPY:
+                globoffs = offs;
+                globend = end;
+                offs = end = 0;
+                if(!offs && local_maplib && deepbind)
+                    GetNoSelfSymbolStartEnd(local_maplib, symname, &offs, &end, head, size, version, vername, veropt, NULL);
+                if(!offs)
+                    GetNoSelfSymbolStartEnd(maplib, symname, &offs, &end, head, size, version, vername, veropt, NULL);
+                if(!offs && local_maplib && !deepbind)
+                    GetNoSelfSymbolStartEnd(local_maplib, symname, &offs, &end, head, size, version, vername, veropt, NULL);
+                if(!offs) {offs = globoffs; end = globend;}
+                if(offs) {
+                    // add r_addend to p?
+                    printf_dump(LOG_NEVER, "Apply R_386_COPY @%p with sym=%s (%sver=%d/%s), @%p size=%ld\n", p, symname, veropt?"opt":"", version, vername?vername:"(none)", from_ptrv(offs), sym->st_size);
+                    if(p!=from_ptrv(offs))
+                        memmove(p, from_ptrv(offs), sym->st_size);
+                    sym_elf = FindElfAddress(my_context, offs);
+                    if(sym_elf && sym_elf!=last_elf && sym_elf!=head) last_elf = checkElfLib(head, sym_elf->lib);
+                } else {
+                    printf_log(LOG_NONE, "Error: Symbol %s not found, cannot apply REL R_386_COPY @%p (%p) in %s\n", symname, p, from_ptrv(*p), head->name);
+                }
+                break;
+            case R_386_GLOB_DAT:
+                if(GetSymbolStartEnd(my_context->globdata, symname, &globoffs, &globend, version, vername, 1, veropt)) {
+                    globp = (uint32_t*)globoffs;
+                    printf_dump(LOG_NEVER, "Apply %s R_X86_64_GLOB_DAT with R_X86_64_COPY @%p/%p (%p/%p -> %p/%p) size=%zd on sym=%s (%sver=%d/%s) \n", 
+                        BindSym(bind), p, globp, from_ptrv(p?(*p):0), 
+                        from_ptrv(globp?(*globp):0), (void*)offs, (void*)globoffs, sym->st_size, symname, veropt?"opt":"", version, vername?vername:"(none)");
+                    sym_elf = my_context->elfs[0];
+                    *p = globoffs;
+                } else {
+                    if (!offs) {
+                        if(strcmp(symname, "__gmon_start__") && strcmp(symname, "data_start") && strcmp(symname, "__data_start") && strcmp(symname, "collector_func_load"))
+                            printf_log((bind==STB_WEAK)?LOG_DEBUG:LOG_NONE, "%s: Global Symbol %s not found, cannot apply R_X86_64_GLOB_DAT @%p (%p) in %s\n", (bind==STB_WEAK)?"Warning":"Error", symname, p, *(void**)p, head->name);
+                    } else {
+                        printf_dump(LOG_NEVER, "Apply %s R_X86_64_GLOB_DAT @%p (%p -> %p) on sym=%s (%sver=%d/%s, elf=%s)\n", BindSym(bind), p, from_ptrv(p?(*p):0), from_ptrv(offs), symname, veropt?"opt":"", version, vername?vername:"(none)", sym_elf?sym_elf->name:"(native)");
+                        *p = offs;
+                        if(sym_elf && sym_elf!=last_elf && sym_elf!=head) last_elf = checkElfLib(head, sym_elf->lib);
+                    }
+                }
+                break;
+            case R_386_JMP_SLOT:
+                // apply immediatly for gobject closure marshal or for LOCAL binding. Also, apply immediatly if it doesn't jump in the got
+                tmp = (uintptr_t)(*p);
+                if (bind==STB_LOCAL 
+                  || ((symname && strstr(symname, "g_cclosure_marshal_")==symname)) 
+                  || ((symname && strstr(symname, "__pthread_unwind_next")==symname)) 
+                  || !tmp
+                  || !((tmp>=head->plt && tmp<head->plt_end) || (tmp>=head->gotplt && tmp<head->gotplt_end))
+                  || !need_resolv
+                  || bindnow
+                  ) {
+                    if (!offs) {
+                        if(bind==STB_WEAK) {
+                            printf_log(LOG_INFO, "Warning: Weak Symbol %s not found, cannot apply R_386_JMP_SLOT %p (%p)\n", symname, p, from_ptrv(*p));
+                        } else {
+                            printf_log(LOG_NONE, "Error: Symbol %s not found, cannot apply R_386_JMP_SLOT %p (%p) in %s\n", symname, p, from_ptrv(*p), head->name);
+                            ret_ok = 1;
+                        }
+                    } else {
+                        if(p) {
+                            printf_dump(LOG_NEVER, "Apply %s R_386_JMP_SLOT %p with sym=%s(%s%s%s) (%p -> %p)\n", (bind==STB_LOCAL)?"Local":((bind==STB_WEAK)?"Weak":"Global"), p, symname, symname, vername?"@":"", vername?vername:"", from_ptrv(*p), from_ptrv(offs));
+                            *p = offs;
+                        } else {
+                            printf_log(LOG_NONE, "Warning, Symbol %s found, but Jump Slot Offset is NULL \n", symname);
+                        }
+                    }
+                } else {
+                    printf_dump(LOG_NEVER, "Preparing (if needed) %s R_386_JMP_SLOT %p (0x%x->0x%0x) with sym=%s(%s%s%s/version %d) to be apply later\n", (bind==STB_LOCAL)?"Local":((bind==STB_WEAK)?"Weak":"Global"), p, *p, *p+head->delta, symname, symname, vername?"@":"", vername?vername:"", version);
+                    *p += head->delta;
+                    *need_resolv = 1;
+                }
+                break;
+            case R_386_32:
+                if (!offs) {
+                        if(strcmp(symname, "__gmon_start__") && strcmp(symname, "data_start") && strcmp(symname, "__data_start")) {
+                            printf_log(LOG_NONE, "Error: Symbol sym=%s(%s%s%s/version %d) not found, cannot apply R_386_32 %p (%p) in %s\n", symname, symname, vername?"@":"", vername?vername:"", version, p, from_ptrv(*p), head->name);
+                            ret_ok = 1;
+                        }
+                } else {
+                    printf_dump(LOG_NEVER, "Apply %s R_386_32 %p with sym=%s (ver=%d/%s) (%p -> %p)\n", (bind==STB_LOCAL)?"Local":((bind==STB_WEAK)?"Weak":"Global"), p, symname, version, vername?vername:"(none)", from_ptrv(*p), from_ptrv(offs+*p));
+                    *p += offs;
+                }
+                break;
+            case R_386_TLS_TPOFF:
+                // Negated offset in static TLS block
+                {
+                    if(!symname || !symname[0]) {
+                        sym_elf = head;
+                        offs = sym->st_value;
+                    }
+                    if(sym_elf) {
+                        delta = *(int32_t*)p;
+                        printf_dump(LOG_NEVER, "Applying %s %s on %s @%p (%d -> %d+%d, size=%d)\n", (bind==STB_LOCAL)?"Local":((bind==STB_WEAK)?"Weak":"Global"), DumpRelType32(t), symname, p, delta, sym_elf->tlsbase, (int32_t)offs, end-offs);
+                        *p = (uintptr_t)((int32_t)offs + sym_elf->tlsbase);
+                    } else {
+                        printf_log(LOG_INFO, "Warning, cannot apply %s %s on %s @%p (%d), no elf_header found\n", (bind==STB_LOCAL)?"Local":((bind==STB_WEAK)?"Weak":"Global"), DumpRelType32(t), symname, p, (int32_t)offs);
+                    }
+                }
+                break;
+            case R_386_TLS_TPOFF32:
+                // Non-negated offset in static TLS block???
+                {
+                    if(!symname || !symname[0]) {
+                        sym_elf = head;
+                        offs = sym->st_value;
+                    }
+                    if(sym_elf) {
+                        delta = *(int32_t*)p;
+                        printf_dump(LOG_NEVER, "Applying %s %s on %s @%p (%d -> %d+%d, size=%d)\n", (bind==STB_LOCAL)?"Local":((bind==STB_WEAK)?"Weak":"Global"), DumpRelType32(t), symname, p, delta, -sym_elf->tlsbase, (int32_t)offs, end-offs);
+                        *p = (uintptr_t)((int32_t)offs - sym_elf->tlsbase);
+                    } else {
+                        printf_log(LOG_INFO, "Warning, cannot apply %s %s on %s @%p (%d), no elf_header found\n", (bind==STB_LOCAL)?"Local":((bind==STB_WEAK)?"Weak":"Global"), DumpRelType32(t), symname, p, (int32_t)offs);
+                    }
+                }
+                break;
+            case R_386_TLS_DTPMOD32:
+                // ID of module containing symbol
+                if(!symname || symname[0]=='\0' || bind==STB_LOCAL) {
+                    offs = getElfIndex(my_context, head);
+                    sym_elf = head;
+                } else {
+                    offs = getElfIndex(my_context, sym_elf);
+                }
+                if(p) {
+                    printf_dump(LOG_NEVER, "Apply %s %s %p with sym=%s (%p -> %p)\n", "R_386_TLS_DTPMOD32", (bind==STB_LOCAL)?"Local":((bind==STB_WEAK)?"Weak":"Global"), p, symname, from_ptrv(*p), from_ptrv(offs));
+                    *p = offs;
+                } else {
+                    printf_log(LOG_NONE, "Warning, Symbol %s or Elf not found, but R_386_TLS_DTPMOD32 Slot Offset is NULL \n", symname);
+                }
+                break;
+            case R_386_TLS_DTPOFF32:
+                // Offset in TLS block
+                if (!offs && !end) {
+                    if(bind==STB_WEAK) {
+                        printf_log(LOG_INFO, "Warning: Weak Symbol %s not found, cannot apply R_386_TLS_DTPOFF32 %p (%p)\n", symname, p, from_ptrv(*p));
+                    } else {
+                        printf_log(LOG_NONE, "Error: Symbol %s not found, cannot apply R_386_TLS_DTPOFF32 %p (%p) in %s\n", symname, p, from_ptrv(*p), head->name);
+                    }
+                } else {
+                    if(!symname || !symname[0]) {
+                        offs = (uintptr_t)((intptr_t)(head->tlsaddr + head->delta) - (intptr_t)offs);    // negative offset
+                    }
+                    if(p) {
+                        printf_dump(LOG_NEVER, "Apply %s R_386_TLS_DTPOFF32 %p with sym=%s (ver=%d/%s) (%zd -> %zd)\n", (bind==STB_LOCAL)?"Local":((bind==STB_WEAK)?"Weak":"Global"), p, symname, version, vername?vername:"(none)", (intptr_t)*p, (intptr_t)offs);
+                        *p = offs;
+                    } else {
+                        printf_log(LOG_NONE, "Warning, Symbol %s found, but R_386_TLS_DTPOFF32 Slot Offset is NULL \n", symname);
+                    }
+                }
+                break;
+            default:
+                printf_log(LOG_INFO, "Warning, don't know of to handle rel #%d %s (%p) for %s\n", i, DumpRelType32(ELF32_R_TYPE(rel[i].r_info)), p, symname?symname:"(nil)");
+        }
+    }
+    return bindnow?ret_ok:0;
+}
+
+static int RelocateElfRELA(lib_t *maplib, lib_t *local_maplib, int bindnow, int deepbind, elfheader_t* head, int cnt, Elf32_Rela *rela, int* need_resolv)
+{
+    printf_log(LOG_NONE, "Error: RELA type of Relocation unsupported (only REL)\n");
+    return 1;
+}
+
+static int RelocateElfRELR(elfheader_t *head, int cnt, Elf32_Relr *relr)
+{
+    printf_log(LOG_NONE, "Error: RELR type of Relocation unsupported (only REL)\n");
+    return 1;
+}
+
+int RelocateElf32(lib_t *maplib, lib_t *local_maplib, int bindnow, int deepbind, elfheader_t* head)
+{
+    if(0 && (head->flags&DF_BIND_NOW) && !bindnow) { // disable for now, needs more symbol in a fow libs like gtk and nss3
+        bindnow = 1;
+        printf_log(LOG_DEBUG, "Forcing %s to Bind Now\n", head->name);
+    }
+    if(head->relr) {
+        int cnt = head->relrsz / head->relrent;
+        DumpRelRTable32(head, cnt, (Elf32_Relr *)(head->relr + head->delta), "RelR");
+        printf_log(LOG_DEBUG, "Applying %d Relocation(s) with Addend for %s\n", cnt, head->name);
+        if(RelocateElfRELR(head, cnt, (Elf32_Relr *)(head->relr + head->delta)))
+            return -1;
+    }
+    if(head->rel) {
+        int cnt = head->relsz / head->relent;
+        DumpRelTable32(head, cnt, (Elf32_Rel *)(head->rel + head->delta), "Rel");
+        printf_log(LOG_DEBUG, "Applying %d Relocation(s) for %s\n", cnt, head->name);
+        if(RelocateElfREL(maplib, local_maplib, bindnow, deepbind, head, cnt, (Elf32_Rel *)(head->rel + head->delta), NULL))
+            return -1;
+    }
+    if(head->rela) {
+        int cnt = head->relasz / head->relaent;
+        DumpRelATable32(head, cnt, (Elf32_Rela *)(head->rela + head->delta), "RelA");
+        printf_log(LOG_DEBUG, "Applying %d Relocation(s) with Addend for %s\n", cnt, head->name);
+        if(RelocateElfRELA(maplib, local_maplib, bindnow, deepbind, head, cnt, (Elf32_Rela *)(head->rela + head->delta), NULL))
+            return -1;
+    }
+    return 0;
+}
diff --git a/src/elfs/elfloader_private.h b/src/elfs/elfloader_private.h
index d813488c..6bcf6d82 100644
--- a/src/elfs/elfloader_private.h
+++ b/src/elfs/elfloader_private.h
@@ -7,6 +7,7 @@ typedef struct cleanup_s cleanup_t;
 
 #include <elf.h>
 #include "elfloader.h"
+#include "box32.h"
 
 typedef struct multiblock_s {
     void*       p;
@@ -22,27 +23,48 @@ typedef struct elfheader_s {
     char*       name;
     char*       path;   // Resolved path to file
     char*       soname; // soname of the elf
-    size_t      numPHEntries;
-    Elf64_Phdr  *PHEntries;
-    size_t      numSHEntries;
-    Elf64_Shdr  *SHEntries;
+    uint16_t    numPHEntries;
+    union {
+        Elf64_Phdr* _64;
+        Elf32_Phdr* _32;
+    }           PHEntries;
+    uint16_t    numSHEntries;
+    union {
+        Elf64_Shdr* _64;
+        Elf32_Shdr* _32;
+    }           SHEntries;
     size_t      SHIdx;
     size_t      numSST;
     char*       SHStrTab;
     char*       StrTab;
-    Elf64_Sym*  SymTab;
+    union {
+        Elf64_Sym*  _64;
+        Elf32_Sym*  _32;
+    }           SymTab;
     size_t      numSymTab;
     char*       DynStr;
-    Elf64_Sym*  DynSym;
+    union {
+        Elf64_Sym*  _64;
+        Elf32_Sym*  _32;
+    }           DynSym;
     size_t      numDynSym;
-    Elf64_Dyn*  Dynamic;
+    union {
+        Elf64_Dyn*  _64;
+        Elf32_Dyn*  _32;
+    }           Dynamic;
     size_t      numDynamic;
     char*       DynStrTab;
     size_t      szDynStrTab;
-    Elf64_Half* VerSym;
-    Elf64_Verneed*  VerNeed;
+    uint16_t*   VerSym;
+    union {
+        Elf64_Verneed*  _64;
+        Elf32_Verneed*  _32;
+    }           VerNeed;
     int         szVerNeed;
-    Elf64_Verdef*   VerDef;
+    union {
+        Elf64_Verdef*   _64;
+        Elf32_Verdef*   _32;
+    }           VerDef;
     int         szVerDef;
     int         e_type;
     uint32_t    flags;
@@ -176,21 +198,22 @@ typedef struct elfheader_s {
 #define ELF64_ST_VISIBILITY(o)   ((o) & 0x03)
 #endif
 
-elfheader_t* ParseElfHeader(FILE* f, const char* name, int exec);
+elfheader_t* ParseElfHeader32(FILE* f, const char* name, int exec);
+elfheader_t* ParseElfHeader64(FILE* f, const char* name, int exec);
 
 const char* BindSym(int bind);
 
-Elf64_Half GetSymbolVersionFlag(elfheader_t* h, int index);
+uint16_t GetSymbolVersionFlag(elfheader_t* h, int index);
 
 uint32_t old_elf_hash(const char* name);
-Elf64_Sym* old_elf_lookup(elfheader_t* h, const char* symname, int ver, const char* vername, int local, int veropt);
-void old_elf_hash_dump(elfheader_t* h);
 uint32_t new_elf_hash(const char *name);
-Elf64_Sym* new_elf_lookup(elfheader_t* h, const char* symname, int ver, const char* vername, int local, int veropt);
-void new_elf_hash_dump(elfheader_t* h);
 
-Elf64_Sym* ElfLookup(elfheader_t* h, const char* symname, int ver, const char* vername, int local, int veropt);
-Elf64_Sym* ElfSymTabLookup(elfheader_t* h, const char* symname);
-Elf64_Sym* ElfDynSymLookup(elfheader_t* h, const char* symname);
+Elf32_Sym* ElfLookup32(elfheader_t* h, const char* symname, int ver, const char* vername, int local, int veropt);
+Elf32_Sym* ElfSymTabLookup32(elfheader_t* h, const char* symname);
+Elf32_Sym* ElfDynSymLookup32(elfheader_t* h, const char* symname);
+
+Elf64_Sym* ElfLookup64(elfheader_t* h, const char* symname, int ver, const char* vername, int local, int veropt);
+Elf64_Sym* ElfSymTabLookup64(elfheader_t* h, const char* symname);
+Elf64_Sym* ElfDynSymLookup64(elfheader_t* h, const char* symname);
 
 #endif //__ELFLOADER_PRIVATE_H_
diff --git a/src/elfs/elfparser.c b/src/elfs/elfparser.c
index 49fea7aa..c9919123 100644
--- a/src/elfs/elfparser.c
+++ b/src/elfs/elfparser.c
@@ -17,7 +17,7 @@
 #define DT_GNU_HASH 0x6ffffef5
 #endif
 
-int LoadSH(FILE *f, Elf64_Shdr *s, void** SH, const char* name, uint32_t type)
+static int LoadSH(FILE *f, Elf64_Shdr *s, void** SH, const char* name, uint32_t type)
 {
     if(type && (s->sh_type != type)) {
         printf_log(LOG_INFO, "Section Header \"%s\" (off=%ld, size=%ld) has incorect type (%d != %d)\n", name, s->sh_offset, s->sh_size, s->sh_type, type);
@@ -36,7 +36,7 @@ int LoadSH(FILE *f, Elf64_Shdr *s, void** SH, const char* name, uint32_t type)
     return 0;
 }
 
-int FindSection(Elf64_Shdr *s, int n, char* SHStrTab, const char* name)
+static int FindSection(Elf64_Shdr *s, int n, char* SHStrTab, const char* name)
 {
     for (int i=0; i<n; ++i) {
         if(s[i].sh_type!=SHT_NULL)
@@ -46,7 +46,7 @@ int FindSection(Elf64_Shdr *s, int n, char* SHStrTab, const char* name)
     return 0;
 }
 
-void LoadNamedSection(FILE *f, Elf64_Shdr *s, int size, char* SHStrTab, const char* name, const char* clearname, uint32_t type, void** what, size_t* num)
+static void LoadNamedSection(FILE *f, Elf64_Shdr *s, int size, char* SHStrTab, const char* name, const char* clearname, uint32_t type, void** what, size_t* num)
 {
     int n = FindSection(s, size, SHStrTab, name);
     printf_dump(LOG_DEBUG, "Loading %s (idx = %d)\n", clearname, n);
@@ -61,7 +61,10 @@ void LoadNamedSection(FILE *f, Elf64_Shdr *s, int size, char* SHStrTab, const ch
     }
 }
 
-elfheader_t* ParseElfHeader(FILE* f, const char* name, int exec)
+#ifndef BOX32
+elfheader_t* ParseElfHeader32(FILE* f, const char* name, int exec) { return NULL; }
+#endif
+elfheader_t* ParseElfHeader64(FILE* f, const char* name, int exec)
 {
     Elf64_Ehdr header;
     int level = (exec)?LOG_INFO:LOG_DEBUG;
@@ -145,9 +148,9 @@ elfheader_t* ParseElfHeader(FILE* f, const char* name, int exec)
     if(header.e_shentsize && h->numSHEntries) {
         // now read all section headers
         printf_dump(LOG_DEBUG, "Read %zu Section header\n", h->numSHEntries);
-        h->SHEntries = (Elf64_Shdr*)box_calloc(h->numSHEntries, sizeof(Elf64_Shdr));
+        h->SHEntries._64 = (Elf64_Shdr*)box_calloc(h->numSHEntries, sizeof(Elf64_Shdr));
         fseeko64(f, header.e_shoff ,SEEK_SET);
-        if(fread(h->SHEntries, sizeof(Elf64_Shdr), h->numSHEntries, f)!=h->numSHEntries) {
+        if(fread(h->SHEntries._64, sizeof(Elf64_Shdr), h->numSHEntries, f)!=h->numSHEntries) {
                 FreeElfHeader(&h);
                 printf_log(LOG_INFO, "Cannot read all Section Header\n");
                 return NULL;
@@ -156,14 +159,14 @@ elfheader_t* ParseElfHeader(FILE* f, const char* name, int exec)
         if(h->numPHEntries == PN_XNUM) {
             printf_dump(LOG_DEBUG, "Read number of Program Header in 1st Section\n");
             // read 1st section header and grab actual number from here
-            h->numPHEntries = h->SHEntries[0].sh_info;
+            h->numPHEntries = h->SHEntries._64[0].sh_info;
         }
     }
 
     printf_dump(LOG_DEBUG, "Read %zu Program header\n", h->numPHEntries);
-    h->PHEntries = (Elf64_Phdr*)box_calloc(h->numPHEntries, sizeof(Elf64_Phdr));
+    h->PHEntries._64 = (Elf64_Phdr*)box_calloc(h->numPHEntries, sizeof(Elf64_Phdr));
     fseeko64(f, header.e_phoff ,SEEK_SET);
-    if(fread(h->PHEntries, sizeof(Elf64_Phdr), h->numPHEntries, f)!=h->numPHEntries) {
+    if(fread(h->PHEntries._64, sizeof(Elf64_Phdr), h->numPHEntries, f)!=h->numPHEntries) {
             FreeElfHeader(&h);
             printf_log(LOG_INFO, "Cannot read all Program Header\n");
             return NULL;
@@ -172,7 +175,7 @@ elfheader_t* ParseElfHeader(FILE* f, const char* name, int exec)
     if(header.e_shentsize && header.e_shnum) {
         if(h->SHIdx == SHN_XINDEX) {
             printf_dump(LOG_DEBUG, "Read number of String Table in 1st Section\n");
-            h->SHIdx = h->SHEntries[0].sh_link;
+            h->SHIdx = h->SHEntries._64[0].sh_link;
         }
         if(h->SHIdx > h->numSHEntries) {
             printf_log(LOG_INFO, "Incoherent Section String Table Index : %zu / %zu\n", h->SHIdx, h->numSHEntries);
@@ -181,23 +184,23 @@ elfheader_t* ParseElfHeader(FILE* f, const char* name, int exec)
         }
         // load Section table
         printf_dump(LOG_DEBUG, "Loading Sections Table String (idx = %zu)\n", h->SHIdx);
-        if(LoadSH(f, h->SHEntries+h->SHIdx, (void*)&h->SHStrTab, ".shstrtab", SHT_STRTAB)) {
+        if(LoadSH(f, h->SHEntries._64+h->SHIdx, (void*)&h->SHStrTab, ".shstrtab", SHT_STRTAB)) {
             FreeElfHeader(&h);
             return NULL;
         }
-        if(box64_dump) DumpMainHeader(&header, h);
+        if(box64_dump) DumpMainHeader64(&header, h);
 
-        LoadNamedSection(f, h->SHEntries, h->numSHEntries, h->SHStrTab, ".strtab", "SymTab Strings", SHT_STRTAB, (void**)&h->StrTab, NULL);
-        LoadNamedSection(f, h->SHEntries, h->numSHEntries, h->SHStrTab, ".symtab", "SymTab", SHT_SYMTAB, (void**)&h->SymTab, &h->numSymTab);
-        if(box64_dump && h->SymTab) DumpSymTab(h);
+        LoadNamedSection(f, h->SHEntries._64, h->numSHEntries, h->SHStrTab, ".strtab", "SymTab Strings", SHT_STRTAB, (void**)&h->StrTab, NULL);
+        LoadNamedSection(f, h->SHEntries._64, h->numSHEntries, h->SHStrTab, ".symtab", "SymTab", SHT_SYMTAB, (void**)&h->SymTab._64, &h->numSymTab);
+        if(box64_dump && h->SymTab._64) DumpSymTab64(h);
 
-        LoadNamedSection(f, h->SHEntries, h->numSHEntries, h->SHStrTab, ".dynamic", "Dynamic", SHT_DYNAMIC, (void**)&h->Dynamic, &h->numDynamic);
-        if(box64_dump && h->Dynamic) DumpDynamicSections(h);
+        LoadNamedSection(f, h->SHEntries._64, h->numSHEntries, h->SHStrTab, ".dynamic", "Dynamic", SHT_DYNAMIC, (void**)&h->Dynamic._64, &h->numDynamic);
+        if(box64_dump && h->Dynamic._64) DumpDynamicSections64(h);
         // grab DT_REL & DT_RELA stuffs
         // also grab the DT_STRTAB string table
         {
             for (size_t i=0; i<h->numDynamic; ++i) {
-                Elf64_Dyn d = h->Dynamic[i];
+                Elf64_Dyn d = h->Dynamic._64[i];
                 Elf64_Word val = d.d_un.d_val;
                 Elf64_Addr ptr = d.d_un.d_ptr;
                 switch (d.d_tag) {
@@ -281,7 +284,7 @@ elfheader_t* ParseElfHeader(FILE* f, const char* name, int exec)
                     printf_dump(LOG_DEBUG, "The DT_VERNEEDNUM is %d\n", h->szVerNeed);
                     break;
                 case DT_VERNEED:
-                    h->VerNeed = (Elf64_Verneed*)ptr;
+                    h->VerNeed._64 = (Elf64_Verneed*)ptr;
                     printf_dump(LOG_DEBUG, "The DT_VERNEED is at address %p\n", h->VerNeed);
                     break;
                 case DT_VERDEFNUM:
@@ -289,7 +292,7 @@ elfheader_t* ParseElfHeader(FILE* f, const char* name, int exec)
                     printf_dump(LOG_DEBUG, "The DT_VERDEFNUM is %d\n", h->szVerDef);
                     break;
                 case DT_VERDEF:
-                    h->VerDef = (Elf64_Verdef*)ptr;
+                    h->VerDef._64 = (Elf64_Verdef*)ptr;
                     printf_dump(LOG_DEBUG, "The DT_VERDEF is at address %p\n", h->VerDef);
                     break;
                 case DT_FLAGS:
@@ -340,55 +343,55 @@ elfheader_t* ParseElfHeader(FILE* f, const char* name, int exec)
                 printf_dump(LOG_DEBUG, "PLT Table @%p (type=%ld 0x%zx/0x%0x)\n", (void*)h->jmprel, h->pltrel, h->pltsz, h->pltent);
             }
             if(h->DynStrTab && h->szDynStrTab) {
-                //DumpDynamicNeeded(h); cannot dump now, it's not loaded yet
+                //DumpDynamicNeeded64(h); cannot dump now, it's not loaded yet
             }
         }
         // look for PLT Offset
-        int ii = FindSection(h->SHEntries, h->numSHEntries, h->SHStrTab, ".got.plt");
+        int ii = FindSection(h->SHEntries._64, h->numSHEntries, h->SHStrTab, ".got.plt");
         if(ii) {
-            h->gotplt = h->SHEntries[ii].sh_addr;
-            h->gotplt_end = h->gotplt + h->SHEntries[ii].sh_size;
+            h->gotplt = h->SHEntries._64[ii].sh_addr;
+            h->gotplt_end = h->gotplt + h->SHEntries._64[ii].sh_size;
             printf_dump(LOG_DEBUG, "The GOT.PLT Table is at address %p\n", (void*)h->gotplt);
         }
-        ii = FindSection(h->SHEntries, h->numSHEntries, h->SHStrTab, ".got");
+        ii = FindSection(h->SHEntries._64, h->numSHEntries, h->SHStrTab, ".got");
         if(ii) {
-            h->got = h->SHEntries[ii].sh_addr;
-            h->got_end = h->got + h->SHEntries[ii].sh_size;
+            h->got = h->SHEntries._64[ii].sh_addr;
+            h->got_end = h->got + h->SHEntries._64[ii].sh_size;
             printf_dump(LOG_DEBUG, "The GOT Table is at address %p..%p\n", (void*)h->got, (void*)h->got_end);
         }
-        ii = FindSection(h->SHEntries, h->numSHEntries, h->SHStrTab, ".plt");
+        ii = FindSection(h->SHEntries._64, h->numSHEntries, h->SHStrTab, ".plt");
         if(ii) {
-            h->plt = h->SHEntries[ii].sh_addr;
-            h->plt_end = h->plt + h->SHEntries[ii].sh_size;
+            h->plt = h->SHEntries._64[ii].sh_addr;
+            h->plt_end = h->plt + h->SHEntries._64[ii].sh_size;
             printf_dump(LOG_DEBUG, "The PLT Table is at address %p..%p\n", (void*)h->plt, (void*)h->plt_end);
         }
         // grab version of symbols
-        ii = FindSection(h->SHEntries, h->numSHEntries, h->SHStrTab, ".gnu.version");
+        ii = FindSection(h->SHEntries._64, h->numSHEntries, h->SHStrTab, ".gnu.version");
         if(ii) {
-            h->VerSym = (Elf64_Half*)(h->SHEntries[ii].sh_addr);
+            h->VerSym = (Elf64_Half*)(h->SHEntries._64[ii].sh_addr);
             printf_dump(LOG_DEBUG, "The .gnu.version is at address %p\n", h->VerSym);
         }
         // grab .text for main code
-        ii = FindSection(h->SHEntries, h->numSHEntries, h->SHStrTab, ".text");
+        ii = FindSection(h->SHEntries._64, h->numSHEntries, h->SHStrTab, ".text");
         if(ii) {
-            h->text = (uintptr_t)(h->SHEntries[ii].sh_addr);
-            h->textsz = h->SHEntries[ii].sh_size;
+            h->text = (uintptr_t)(h->SHEntries._64[ii].sh_addr);
+            h->textsz = h->SHEntries._64[ii].sh_size;
             printf_dump(LOG_DEBUG, "The .text is at address %p, and is %zu big\n", (void*)h->text, h->textsz);
         }
-        ii = FindSection(h->SHEntries, h->numSHEntries, h->SHStrTab, ".eh_frame");
+        ii = FindSection(h->SHEntries._64, h->numSHEntries, h->SHStrTab, ".eh_frame");
         if(ii) {
-            h->ehframe = (uintptr_t)(h->SHEntries[ii].sh_addr);
-            h->ehframe_end = h->ehframe + h->SHEntries[ii].sh_size;
+            h->ehframe = (uintptr_t)(h->SHEntries._64[ii].sh_addr);
+            h->ehframe_end = h->ehframe + h->SHEntries._64[ii].sh_size;
             printf_dump(LOG_DEBUG, "The .eh_frame section is at address %p..%p\n", (void*)h->ehframe, (void*)h->ehframe_end);
         }
-        ii = FindSection(h->SHEntries, h->numSHEntries, h->SHStrTab, ".eh_frame_hdr");
+        ii = FindSection(h->SHEntries._64, h->numSHEntries, h->SHStrTab, ".eh_frame_hdr");
         if(ii) {
-            h->ehframehdr = (uintptr_t)(h->SHEntries[ii].sh_addr);
+            h->ehframehdr = (uintptr_t)(h->SHEntries._64[ii].sh_addr);
             printf_dump(LOG_DEBUG, "The .eh_frame_hdr section is at address %p\n", (void*)h->ehframehdr);
         }
 
-        LoadNamedSection(f, h->SHEntries, h->numSHEntries, h->SHStrTab, ".dynstr", "DynSym Strings", SHT_STRTAB, (void**)&h->DynStr, NULL);
-        LoadNamedSection(f, h->SHEntries, h->numSHEntries, h->SHStrTab, ".dynsym", "DynSym", SHT_DYNSYM, (void**)&h->DynSym, &h->numDynSym);
+        LoadNamedSection(f, h->SHEntries._64, h->numSHEntries, h->SHStrTab, ".dynstr", "DynSym Strings", SHT_STRTAB, (void**)&h->DynStr, NULL);
+        LoadNamedSection(f, h->SHEntries._64, h->numSHEntries, h->SHStrTab, ".dynsym", "DynSym", SHT_DYNSYM, (void**)&h->DynSym, &h->numDynSym);
     }
     
     return h;
diff --git a/src/elfs/elfparser32.c b/src/elfs/elfparser32.c
new file mode 100755
index 00000000..b4bb78e4
--- /dev/null
+++ b/src/elfs/elfparser32.c
@@ -0,0 +1,466 @@
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <elf.h>
+
+#include "box64version.h"
+#include "elfloader.h"
+#include "debug.h"
+#include "elfload_dump.h"
+#include "elfloader_private.h"
+#include "box32.h"
+
+#ifndef PN_XNUM 
+#define PN_XNUM (0xffff)
+#endif
+
+static int LoadSH(FILE *f, Elf32_Shdr *s, void** SH, const char* name, uint32_t type)
+{
+    if(type && (s->sh_type != type)) {
+        printf_log(LOG_INFO, "Section Header \"%s\" (off=%d, size=%d) has incorect type (%d != %d)\n", name, s->sh_offset, s->sh_size, s->sh_type, type);
+        return -1;
+    }
+    if (type==SHT_SYMTAB && s->sh_size%sizeof(Elf32_Sym)) {
+        printf_log(LOG_INFO, "Section Header \"%s\" (off=%d, size=%d) has size (not multiple of %ld)\n", name, s->sh_offset, s->sh_size, sizeof(Elf32_Sym));
+    }
+    *SH = box_calloc(1, s->sh_size);
+    fseeko64(f, s->sh_offset ,SEEK_SET);
+    if(fread(*SH, s->sh_size, 1, f)!=1) {
+            printf_log(LOG_INFO, "Cannot read Section Header \"%s\" (off=%d, size=%d)\n", name, s->sh_offset, s->sh_size);
+            return -1;
+    }
+
+    return 0;
+}
+
+static int FindSection(Elf32_Shdr *s, int n, char* SHStrTab, const char* name)
+{
+    for (int i=0; i<n; ++i) {
+        if(s[i].sh_type!=SHT_NULL)
+            if(!strcmp(SHStrTab+s[i].sh_name, name))
+                return i;
+    }
+    return 0;
+}
+
+static void LoadNamedSection(FILE *f, Elf32_Shdr *s, int size, char* SHStrTab, const char* name, const char* clearname, uint32_t type, void** what, size_t* num)
+{
+    int n = FindSection(s, size, SHStrTab, name);
+    printf_log(LOG_DEBUG, "Loading %s (idx = %d)\n", clearname, n);
+    if(n)
+        LoadSH(f, s+n, what, name, type);
+    if(type==SHT_SYMTAB || type==SHT_DYNSYM) {
+        if(*what && num)
+            *num = s[n].sh_size / sizeof(Elf32_Sym);
+    } else if(type==SHT_DYNAMIC) {
+        if(*what && num)
+            *num = s[n].sh_size / sizeof(Elf32_Dyn);
+    }
+}
+
+elfheader_t* ParseElfHeader32(FILE* f, const char* name, int exec)
+{
+    Elf32_Ehdr header;
+    int level = (exec)?LOG_INFO:LOG_DEBUG;
+    if(fread(&header, sizeof(Elf32_Ehdr), 1, f)!=1) {
+        printf_log(level, "Cannot read ELF Header\n");
+        return NULL;
+    }
+    if(memcmp(header.e_ident, ELFMAG, SELFMAG)!=0) {
+        printf_log(LOG_INFO, "Not an ELF file (sign=%c%c%c%c)\n", header.e_ident[0], header.e_ident[1], header.e_ident[2], header.e_ident[3]);
+        return NULL;
+    }
+    if(header.e_ident[EI_CLASS]!=ELFCLASS32) {
+        if(header.e_ident[EI_CLASS]==ELFCLASS64) {
+            printf_log(LOG_INFO, "This is a 64bits ELF! box32 can only run 32bits ELF!\n");
+        } else {
+            printf_log(LOG_INFO, "Not a 32bits ELF (%d)\n", header.e_ident[EI_CLASS]);
+        }
+        return NULL;
+    }
+    if(header.e_ident[EI_DATA]!=ELFDATA2LSB) {
+        printf_log(LOG_INFO, "Not a LittleEndian ELF (%d)\n", header.e_ident[EI_DATA]);
+        return NULL;
+    }
+    if(header.e_ident[EI_VERSION]!=EV_CURRENT) {
+        printf_log(LOG_INFO, "Incorrect ELF version (%d)\n", header.e_ident[EI_VERSION]);
+        return NULL;
+    }
+    if(header.e_ident[EI_OSABI]!=ELFOSABI_LINUX && header.e_ident[EI_OSABI]!=ELFOSABI_NONE && header.e_ident[EI_OSABI]!=ELFOSABI_SYSV) {
+        printf_log(LOG_INFO, "Not a Linux ELF (%d)\n",header.e_ident[EI_OSABI]);
+        return NULL;
+    }
+
+    if(header.e_type != ET_EXEC && header.e_type != ET_DYN) {
+        printf_log(LOG_INFO, "Not an Executable (%d)\n", header.e_type);
+        return NULL;
+    }
+
+    if(header.e_machine != EM_386) {
+        printf_log(level, "Not an i386 ELF (%d)\n", header.e_machine);
+        return NULL;
+    }
+
+    if(header.e_entry == 0 && exec) {
+        printf_log(LOG_INFO, "No entry point in ELF\n");
+        return NULL;
+    }
+    if(header.e_phentsize != sizeof(Elf32_Phdr)) {
+        printf_log(LOG_INFO, "Program Header Entry size incorrect (%d != %ld)\n", header.e_phentsize, sizeof(Elf32_Phdr));
+        return NULL;
+    }
+    if(header.e_shentsize != sizeof(Elf32_Shdr) && header.e_shentsize != 0) {
+        printf_log(LOG_INFO, "Section Header Entry size incorrect (%d != %ld)\n", header.e_shentsize, sizeof(Elf32_Shdr));
+        return NULL;
+    }
+
+    elfheader_t *h = box_calloc(1, sizeof(elfheader_t));
+    h->name = box_strdup(name);
+    h->entrypoint = header.e_entry;
+    h->numPHEntries = header.e_phnum;
+    h->numSHEntries = header.e_shnum;
+    h->SHIdx = header.e_shstrndx;
+    h->e_type = header.e_type;
+    if(header.e_shentsize && header.e_shnum) {
+        // special cases for nums
+        if(h->numSHEntries == 0) {
+            printf_log(LOG_DEBUG, "Read number of Sections in 1st Section\n");
+            // read 1st section header and grab actual number from here
+            fseeko64(f, header.e_shoff, SEEK_SET);
+            Elf32_Shdr section;
+            if(fread(&section, sizeof(Elf32_Shdr), 1, f)!=1) {
+                box_free(h);
+                printf_log(LOG_INFO, "Cannot read Initial Section Header\n");
+                return NULL;
+            }
+            h->numSHEntries = section.sh_size;
+        }
+        // now read all section headers
+        printf_log(LOG_DEBUG, "Read %d Section header\n", h->numSHEntries);
+        h->SHEntries._32 = (Elf32_Shdr*)box_calloc(h->numSHEntries, sizeof(Elf32_Shdr));
+        fseeko64(f, header.e_shoff ,SEEK_SET);
+        if(fread(h->SHEntries._32, sizeof(Elf32_Shdr), h->numSHEntries, f)!=h->numSHEntries) {
+                FreeElfHeader(&h);
+                printf_log(LOG_INFO, "Cannot read all Section Header\n");
+                return NULL;
+        }
+
+        if(h->numPHEntries == PN_XNUM) {
+            printf_log(LOG_DEBUG, "Read number of Program Header in 1st Section\n");
+            // read 1st section header and grab actual number from here
+            h->numPHEntries = h->SHEntries._32[0].sh_info;
+        }
+    }
+
+    printf_log(LOG_DEBUG, "Read %d Program header\n", h->numPHEntries);
+    h->PHEntries._32 = (Elf32_Phdr*)box_calloc(h->numPHEntries, sizeof(Elf32_Phdr));
+    fseeko64(f, header.e_phoff ,SEEK_SET);
+    if(fread(h->PHEntries._32, sizeof(Elf32_Phdr), h->numPHEntries, f)!=h->numPHEntries) {
+            FreeElfHeader(&h);
+            printf_log(LOG_INFO, "Cannot read all Program Header\n");
+            return NULL;
+    }
+
+    if(header.e_shentsize && header.e_shnum) {
+        if(h->SHIdx == SHN_XINDEX) {
+            printf_log(LOG_DEBUG, "Read number of String Table in 1st Section\n");
+            h->SHIdx = h->SHEntries._32[0].sh_link;
+        }
+        if(h->SHIdx > h->numSHEntries) {
+            printf_log(LOG_INFO, "Incoherent Section String Table Index : %d / %d\n", h->SHIdx, h->numSHEntries);
+            FreeElfHeader(&h);
+            return NULL;
+        }
+        // load Section table
+        printf_log(LOG_DEBUG, "Loading Sections Table String (idx = %d)\n", h->SHIdx);
+        if(LoadSH(f, h->SHEntries._32+h->SHIdx, (void*)&h->SHStrTab, ".shstrtab", SHT_STRTAB)) {
+            FreeElfHeader(&h);
+            return NULL;
+        }
+        if(box64_dump) DumpMainHeader32(&header, h);
+
+        LoadNamedSection(f, h->SHEntries._32, h->numSHEntries, h->SHStrTab, ".strtab", "SymTab Strings", SHT_STRTAB, (void**)&h->StrTab, NULL);
+        LoadNamedSection(f, h->SHEntries._32, h->numSHEntries, h->SHStrTab, ".symtab", "SymTab", SHT_SYMTAB, (void**)&h->SymTab._32, &h->numSymTab);
+        if(box64_dump && h->SymTab._32) DumpSymTab32(h);
+
+        LoadNamedSection(f, h->SHEntries._32, h->numSHEntries, h->SHStrTab, ".dynamic", "Dynamic", SHT_DYNAMIC, (void**)&h->Dynamic._32, &h->numDynamic);
+        if(box64_dump && h->Dynamic._32) DumpDynamicSections32(h);
+        // grab DT_REL & DT_RELA stuffs
+        // also grab the DT_STRTAB string table
+        {
+            for (int i=0; i<h->numDynamic; ++i) {
+                Elf32_Dyn d = h->Dynamic._32[i];
+                Elf32_Word val = d.d_un.d_val;
+                Elf32_Addr ptr = d.d_un.d_ptr;
+                switch (d.d_tag) {
+                case DT_REL:
+                    h->rel = ptr;
+                    break;
+                case DT_RELSZ:
+                    h->relsz = val;
+                    break;
+                case DT_RELENT:
+                    h->relent = val;
+                    break;
+                case DT_RELA:
+                    h->rela = ptr;
+                    break;
+                case DT_RELASZ:
+                    h->relasz = val;
+                    break;
+                case DT_RELAENT:
+                    h->relaent = val;
+                    break;
+                case DT_RELR:
+                    h->relr = ptr;
+                    break;
+                case DT_RELRSZ:
+                    h->relrsz = val;
+                    break;
+                case DT_RELRENT:
+                    h->relrent = val;
+                    break;
+                case DT_PLTGOT:
+                    h->pltgot = ptr;
+                    break;
+                case DT_PLTREL:
+                    h->pltrel = val;
+                    break;
+                case DT_PLTRELSZ:
+                    h->pltsz = val;
+                    break;
+                case DT_JMPREL:
+                    h->jmprel = ptr;
+                    break;
+                case DT_STRTAB:
+                    h->DynStrTab = (char *)from_ptr(ptr);
+                    break;
+                case DT_STRSZ:
+                    h->szDynStrTab = val;
+                    break;
+                case DT_INIT: // Entry point
+                    h->initentry = ptr;
+                    printf_log(LOG_DEBUG, "The DT_INIT is at address %p\n", from_ptrv(h->initentry));
+                    break;
+                case DT_INIT_ARRAY:
+                    h->initarray = ptr;
+                    printf_log(LOG_DEBUG, "The DT_INIT_ARRAY is at address %p\n", from_ptrv(h->initarray));
+                    break;
+                case DT_INIT_ARRAYSZ:
+                    h->initarray_sz = val / sizeof(Elf32_Addr);
+                    printf_log(LOG_DEBUG, "The DT_INIT_ARRAYSZ is %d\n", h->initarray_sz);
+                    break;
+                case DT_PREINIT_ARRAYSZ:
+                    if(val)
+                        printf_log(LOG_NONE, "Warning, PreInit Array (size=%d) present and ignored!\n", val);
+                    break;
+                case DT_FINI: // Exit hook
+                    h->finientry = ptr;
+                    printf_log(LOG_DEBUG, "The DT_FINI is at address %p\n", from_ptrv(h->finientry));
+                    break;
+                case DT_FINI_ARRAY:
+                    h->finiarray = ptr;
+                    printf_log(LOG_DEBUG, "The DT_FINI_ARRAY is at address %p\n", from_ptrv(h->finiarray));
+                    break;
+                case DT_FINI_ARRAYSZ:
+                    h->finiarray_sz = val / sizeof(Elf32_Addr);
+                    printf_log(LOG_DEBUG, "The DT_FINI_ARRAYSZ is %d\n", h->finiarray_sz);
+                    break;
+                case DT_VERNEEDNUM:
+                    h->szVerNeed = val;
+                    printf_log(LOG_DEBUG, "The DT_VERNEEDNUM is %d\n", h->szVerNeed);
+                    break;
+                case DT_VERNEED:
+                    h->VerNeed._32 = (Elf32_Verneed*)from_ptr(ptr);
+                    printf_log(LOG_DEBUG, "The DT_VERNEED is at address %p\n", h->VerNeed);
+                    break;
+                case DT_VERDEFNUM:
+                    h->szVerDef = val;
+                    printf_log(LOG_DEBUG, "The DT_VERDEFNUM is %d\n", h->szVerDef);
+                    break;
+                case DT_VERDEF:
+                    h->VerDef._32 = (Elf32_Verdef*)from_ptr(ptr);
+                    printf_log(LOG_DEBUG, "The DT_VERDEF is at address %p\n", h->VerDef);
+                    break;
+                case DT_HASH:
+                    h->hash = ptr;
+                    printf_dump(LOG_DEBUG, "The DT_HASH is at address %p\n", (void*)h->hash);
+                    break;
+                case DT_GNU_HASH:
+                    h->gnu_hash = ptr;
+                    printf_dump(LOG_DEBUG, "The DT_GNU_HASH is at address %p\n", (void*)h->gnu_hash);
+                    break;
+                }
+            }
+            if(h->rel) {
+                if(h->relent != sizeof(Elf32_Rel)) {
+                    printf_log(LOG_NONE, "Rel Table Entry size invalid (0x%x should be 0x%lx)\n", h->relent, sizeof(Elf32_Rel));
+                    FreeElfHeader(&h);
+                    return NULL;
+                }
+                printf_log(LOG_DEBUG, "Rel Table @%p (0x%x/0x%x)\n", from_ptrv(h->rel), h->relsz, h->relent);
+            }
+            if(h->rela) {
+                if(h->relaent != sizeof(Elf32_Rela)) {
+                    printf_log(LOG_NONE, "RelA Table Entry size invalid (0x%x should be 0x%lx)\n", h->relaent, sizeof(Elf32_Rela));
+                    FreeElfHeader(&h);
+                    return NULL;
+                }
+                printf_log(LOG_DEBUG, "RelA Table @%p (0x%x/0x%x)\n", from_ptrv(h->rela), h->relasz, h->relaent);
+            }
+            if(h->jmprel) {
+                if(h->pltrel == DT_REL) {
+                    h->pltent = sizeof(Elf32_Rel);
+                } else if(h->pltrel == DT_RELA) {
+                    h->pltent = sizeof(Elf32_Rela);
+                } else {
+                    printf_log(LOG_NONE, "PLT Table type is unknown (size = 0x%x, type=%d)\n", h->pltsz, h->pltrel);
+                    FreeElfHeader(&h);
+                    return NULL;
+                }
+                if((h->pltsz / h->pltent)*h->pltent != h->pltsz) {
+                    printf_log(LOG_NONE, "PLT Table Entry size invalid (0x%x, ent=0x%x, type=%d)\n", h->pltsz, h->pltent, h->pltrel);
+                    FreeElfHeader(&h);
+                    return NULL;
+                }
+                printf_log(LOG_DEBUG, "PLT Table @%p (type=%d 0x%x/0x%0x)\n", from_ptrv(h->jmprel), h->pltrel, h->pltsz, h->pltent);
+            }
+            if(h->DynStrTab && h->szDynStrTab) {
+                //DumpDynamicNeeded32(h); cannot dump now, it's not loaded yet
+            }
+        }
+        // look for PLT Offset
+        int ii = FindSection(h->SHEntries._32, h->numSHEntries, h->SHStrTab, ".got.plt");
+        if(ii) {
+            h->gotplt = h->SHEntries._32[ii].sh_addr;
+            h->gotplt_end = h->gotplt + h->SHEntries._32[ii].sh_size;
+            printf_log(LOG_DEBUG, "The GOT.PLT Table is at address %p\n", from_ptrv(h->gotplt));
+        }
+        ii = FindSection(h->SHEntries._32, h->numSHEntries, h->SHStrTab, ".got");
+        if(ii) {
+            h->got = h->SHEntries._32[ii].sh_addr;
+            h->got_end = h->got + h->SHEntries._32[ii].sh_size;
+            printf_log(LOG_DEBUG, "The GOT Table is at address %p..%p\n", from_ptrv(h->got), from_ptrv(h->got_end));
+        }
+        ii = FindSection(h->SHEntries._32, h->numSHEntries, h->SHStrTab, ".plt");
+        if(ii) {
+            h->plt = h->SHEntries._32[ii].sh_addr;
+            h->plt_end = h->plt + h->SHEntries._32[ii].sh_size;
+            printf_log(LOG_DEBUG, "The PLT Table is at address %p..%p\n", from_ptrv(h->plt), from_ptrv(h->plt_end));
+        }
+        // grab version of symbols
+        ii = FindSection(h->SHEntries._32, h->numSHEntries, h->SHStrTab, ".gnu.version");
+        if(ii) {
+            h->VerSym = (Elf32_Half*)from_ptrv(h->SHEntries._32[ii].sh_addr);
+            printf_log(LOG_DEBUG, "The .gnu.version is at address %p\n", h->VerSym);
+        }
+        // grab .text for main code
+        ii = FindSection(h->SHEntries._32, h->numSHEntries, h->SHStrTab, ".text");
+        if(ii) {
+            h->text = (uintptr_t)(h->SHEntries._32[ii].sh_addr);
+            h->textsz = h->SHEntries._32[ii].sh_size;
+            printf_log(LOG_DEBUG, "The .text is at address %p, and is %d big\n", from_ptrv(h->text), h->textsz);
+        }
+
+        LoadNamedSection(f, h->SHEntries._32, h->numSHEntries, h->SHStrTab, ".dynstr", "DynSym Strings", SHT_STRTAB, (void**)&h->DynStr, NULL);
+        LoadNamedSection(f, h->SHEntries._32, h->numSHEntries, h->SHStrTab, ".dynsym", "DynSym", SHT_DYNSYM, (void**)&h->DynSym, &h->numDynSym);
+    }
+    
+    return h;
+}
+
+const char* GetParentSymbolVersion32(elfheader_t* h, int index)
+{
+    if(!h->VerDef._32 || (index<1))
+        return NULL;
+    Elf32_Verdef *def = (Elf32_Verdef*)((uintptr_t)h->VerDef._32 + h->delta);
+    while(def) {
+        if(def->vd_ndx==index) {
+            if(def->vd_cnt<1)
+                return NULL;
+            /*if(def->vd_flags&VER_FLG_BASE)
+                return NULL;*/
+            Elf32_Verdaux *aux = (Elf32_Verdaux*)((uintptr_t)def + def->vd_aux);
+            return h->DynStr+aux->vda_name; // return Parent, so 1st aux
+        }
+        def = def->vd_next?((Elf32_Verdef*)((uintptr_t)def + def->vd_next)):NULL;
+    }
+    return NULL;
+}
+
+const char* GetSymbolVersion32(elfheader_t* h, int version)
+{
+    version&=0x7fff;    // remove bit15 that switch between hidden/public
+    if(!h->VerNeed._32 || (version<2))
+        return NULL;
+    /*if(version==1)
+        return "*";*/
+    Elf32_Verneed *ver = (Elf32_Verneed*)((uintptr_t)h->VerNeed._32 + h->delta);
+    while(ver) {
+        Elf32_Vernaux *aux = (Elf32_Vernaux*)((uintptr_t)ver + ver->vn_aux);
+        for(int j=0; j<ver->vn_cnt; ++j) {
+            if(aux->vna_other==version)
+                return h->DynStr+aux->vna_name;
+            aux = (Elf32_Vernaux*)((uintptr_t)aux + aux->vna_next);
+        }
+        ver = ver->vn_next?((Elf32_Verneed*)((uintptr_t)ver + ver->vn_next)):NULL;
+    }
+    return GetParentSymbolVersion32(h, version);  // if symbol is "internal", use Def table instead
+}
+
+int GetVersionIndice32(elfheader_t* h, const char* vername)
+{
+    if(!vername)
+        return 0;
+    if(h->VerDef._32) {
+        Elf32_Verdef *def = (Elf32_Verdef*)((uintptr_t)h->VerDef._32 + h->delta);
+        while(def) {
+            Elf32_Verdaux *aux = (Elf32_Verdaux*)((uintptr_t)def + def->vd_aux);
+            if(!strcmp(h->DynStr+aux->vda_name, vername))
+                return def->vd_ndx;
+            def = def->vd_next?((Elf32_Verdef*)((uintptr_t)def + def->vd_next)):NULL;
+        }
+    }
+    return 0;
+}
+
+int GetNeededVersionCnt32(elfheader_t* h, const char* libname)
+{
+    if(!libname)
+        return 0;
+    if(h->VerNeed._32) {
+        Elf32_Verneed *ver = (Elf32_Verneed*)((uintptr_t)h->VerNeed._32 + h->delta);
+        while(ver) {
+            char *filename = h->DynStr + ver->vn_file;
+            Elf32_Vernaux *aux = (Elf32_Vernaux*)((uintptr_t)ver + ver->vn_aux);
+            if(!strcmp(filename, libname))
+                return ver->vn_cnt;
+            ver = ver->vn_next?((Elf32_Verneed*)((uintptr_t)ver + ver->vn_next)):NULL;
+        }
+    }
+    return 0;
+}
+
+const char* GetNeededVersionString32(elfheader_t* h, const char* libname, int idx)
+{
+    if(!libname)
+        return 0;
+    if(h->VerNeed._32) {
+        Elf32_Verneed *ver = (Elf32_Verneed*)((uintptr_t)h->VerNeed._32 + h->delta);
+        while(ver) {
+            char *filename = h->DynStr + ver->vn_file;
+            Elf32_Vernaux *aux = (Elf32_Vernaux*)((uintptr_t)ver + ver->vn_aux);
+            if(!strcmp(filename, libname)) {
+                for(int j=0; j<ver->vn_cnt; ++j) {
+                    if(j==idx) 
+                        return h->DynStr+aux->vna_name;
+                    aux = (Elf32_Vernaux*)((uintptr_t)aux + aux->vna_next);
+                }
+                return NULL;    // idx out of bound, return NULL...
+           }
+            ver = ver->vn_next?((Elf32_Verneed*)((uintptr_t)ver + ver->vn_next)):NULL;
+        }
+    }
+    return NULL;
+}
diff --git a/src/emu/x64int3.c b/src/emu/x64int3.c
index 2b907c35..dd1b439c 100644
--- a/src/emu/x64int3.c
+++ b/src/emu/x64int3.c
@@ -127,14 +127,14 @@ void x64Int3(x64emu_t* emu, uintptr_t* addr)
                 const char *s = bridge->name;
                 if(!s)
                     s = GetNativeName((void*)a);
-                if(a==(uintptr_t)PltResolver) {
+                if(a==(uintptr_t)PltResolver64) {
                     if(cycle_log) {
                         uintptr_t addr = *((uint64_t*)(R_RSP));
                         int slot = *((uint64_t*)(R_RSP+8));
                         elfheader_t *h = (elfheader_t*)addr;
                         Elf64_Rela * rel = (Elf64_Rela *)(h->jmprel + h->delta) + slot;
-                        Elf64_Sym *sym = &h->DynSym[ELF64_R_SYM(rel->r_info)];
-                        const char* symname = SymName(h, sym);
+                        Elf64_Sym *sym = &h->DynSym._64[ELF64_R_SYM(rel->r_info)];
+                        const char* symname = SymName64(h, sym);
                         snprintf(buff, 256, "%04d|PltResolver \"%s\"", tid, symname?symname:"???");
                     } else {
                         snprintf(buff, 256, "%s", " ... ");
diff --git a/src/include/box32.h b/src/include/box32.h
new file mode 100644
index 00000000..ab8fa184
--- /dev/null
+++ b/src/include/box32.h
@@ -0,0 +1,112 @@
+#ifndef __BOX32_64__H_
+#define __BOX32_64__H_
+
+#include <stdint.h>
+#include <stdlib.h>
+
+#ifndef BOX32_DEF
+#define BOX32_DEF
+typedef uint32_t ptr_t;
+typedef int32_t long_t;
+typedef uint32_t ulong_t;
+#endif
+
+#define TEST32
+#define TEST_ABORT
+
+static inline uintptr_t from_ptr(ptr_t p) {
+    return (uintptr_t)p;
+}
+static inline void* from_ptrv(ptr_t p) {
+    return (void*)(uintptr_t)p;
+}
+static inline long from_long(long_t l) {
+    return (long)l;
+}
+static inline unsigned long from_ulong(ulong_t l) {
+    return (unsigned long)l;
+}
+uintptr_t from_hash(ulong_t l);
+uintptr_t from_hash_d(ulong_t l);
+#ifdef TEST32
+#include "debug.h"
+
+static inline ptr_t to_ptr(uintptr_t p) {
+    if(p!=0xffffffffffffffffLL && (p>>32)) {
+        printf_log(LOG_NONE, "Warning, pointer %p is not a 32bits value\n", (void*)p);
+        #ifdef TEST_ABORT
+        abort();
+        #endif
+    }
+    return (ptr_t)p;
+}
+static inline ptr_t to_ptrv(void* p2) {
+    uintptr_t p = (uintptr_t)p2;
+    if(p!=0xffffffffffffffffLL && (p>>32)) {
+        printf_log(LOG_NONE, "Warning, pointer %p is not a 32bits value\n", (void*)p);
+        #ifdef TEST_ABORT
+        abort();
+        #endif
+    }
+    return (ptr_t)p;
+}
+static inline long_t to_long(long l) {
+    long_t ret = (long_t)l;
+    if(l!=ret)
+        printf_log(LOG_NONE, "Warning, long %ld is not a 32bits value\n", l);
+    return ret;
+}
+static inline ulong_t to_ulong(unsigned long l) {
+    if(l!=0xffffffffffffffffLL && (l>>32))
+        printf_log(LOG_NONE, "Warning, long 0x%p is not a 32bits value\n", (void*)l);
+    return (ulong_t)l;
+}
+#else //TEST32
+static inline ptr_t to_ptr(uintptr_t p) {
+    return (ptr_t)p;
+}
+static inline ptr_t to_ptrv(void* p) {
+    return (ptr_t)(uintptr_t)p;
+}
+static inline long_t to_long(long l) {
+    return (long_t)l;
+}
+static inline ulong_t to_ulong(unsigned long l) {
+    return (ulong_t)l;
+}
+#endif //TEST32
+
+static inline ptr_t to_ptr_silent(uintptr_t p) {
+    return (ptr_t)p;
+}
+static inline ptr_t to_ptrv_silent(void* p) {
+    return (ptr_t)(uintptr_t)p;
+}
+// indirect l -> T
+#define from_ptri(T, l) *(T*)from_ptr(l)
+// indirect l -> void*
+static inline void* from_ptriv(ptr_t l) {
+    return from_ptrv(from_ptri(ptr_t, l));
+}
+
+ulong_t to_hash(uintptr_t p);
+ulong_t to_hash_d(uintptr_t p);
+static inline ulong_t to_hashv(void* p) {return to_hash((uintptr_t)p);}
+static inline ulong_t to_hashv_d(uintptr_t p) {return to_hash_d((uintptr_t)p);}
+
+void* from_locale(ptr_t l);
+void* from_locale_d(ptr_t l);
+ptr_t to_locale(void* p);
+ptr_t to_locale_d(void* p);
+
+void init_hash_helper();
+void fini_hash_helper();
+
+typedef struct x86emu_s x86emu_t;
+
+void* my_mmap(x86emu_t* emu, void* addr, unsigned long length, int prot, int flags, int fd, int offset);
+void* my_mmap64(x86emu_t* emu, void *addr, unsigned long length, int prot, int flags, int fd, int64_t offset);
+int my_munmap(x86emu_t* emu, void* addr, unsigned long length);
+int my_mprotect(x86emu_t* emu, void *addr, unsigned long len, int prot);
+
+#endif //__BOX32_64__H_
diff --git a/src/include/custommem.h b/src/include/custommem.h
index dda21053..ba5441d1 100644
--- a/src/include/custommem.h
+++ b/src/include/custommem.h
@@ -102,6 +102,7 @@ void* find31bitBlockNearHint(void* hint, size_t size, uintptr_t mask);
 void* find47bitBlock(size_t size);
 void* find47bitBlockNearHint(void* hint, size_t size, uintptr_t mask); // mask can be 0 for default one (0xffff)
 void* find47bitBlockElf(size_t size, int mainbin, uintptr_t mask);
+void* find31bitBlockElf(size_t size, int mainbin, uintptr_t mask);
 int isBlockFree(void* hint, size_t size);
 
 // unlock mutex that are locked by current thread (for signal handling). Return a mask of unlock mutex
@@ -125,4 +126,6 @@ int checkInHotPage(uintptr_t addr);
 void* internal_mmap(void *addr, unsigned long length, int prot, int flags, int fd, ssize_t offset);
 int internal_munmap(void* addr, unsigned long length);
 
+void reserveHighMem();
+
 #endif //__CUSTOM_MEM__H_
diff --git a/src/include/debug.h b/src/include/debug.h
index 1e31b437..e0f81c95 100644
--- a/src/include/debug.h
+++ b/src/include/debug.h
@@ -16,6 +16,7 @@ extern int box64_ignoreint3;
 extern int box64_rdtsc;
 extern int box64_rdtsc_1ghz;
 extern uint8_t box64_rdtsc_shift;
+extern int box64_is32bits;
 #ifdef DYNAREC
 extern int box64_dynarec_dump;
 extern int box64_dynarec_trace;
diff --git a/src/include/elfload_dump.h b/src/include/elfload_dump.h
index ad2ecd71..3fa0a910 100644
--- a/src/include/elfload_dump.h
+++ b/src/include/elfload_dump.h
@@ -3,22 +3,26 @@
 
 typedef struct elfheader_s elfheader_t;
 
-const char* DumpSection(Elf64_Shdr *s, char* SST);
-const char* DumpDynamic(Elf64_Dyn *s);
-const char* DumpPHEntry(Elf64_Phdr *e);
-const char* DumpSym(elfheader_t *h, Elf64_Sym* sym, int version);
-const char* DumpRelType(int t);
-const char* SymName(elfheader_t *h, Elf64_Sym* sym);
-const char* IdxSymName(elfheader_t *h, int sym);
-void DumpMainHeader(Elf64_Ehdr *header, elfheader_t *h);
-void DumpSymTab(elfheader_t *h);
-void DumpDynamicSections(elfheader_t *h);
+const char* SymName32(elfheader_t *h, Elf32_Sym* sym);
+const char* SymName64(elfheader_t *h, Elf64_Sym* sym);
+const char* DumpRelType32(int t);
+const char* DumpRelType64(int t);
+void DumpMainHeader32(Elf32_Ehdr *header, elfheader_t *h);
+void DumpMainHeader64(Elf64_Ehdr *header, elfheader_t *h);
+void DumpSymTab32(elfheader_t *h);
+void DumpSymTab64(elfheader_t *h);
+void DumpDynamicSections32(elfheader_t *h);
+void DumpDynamicSections64(elfheader_t *h);
 void DumpDynamicNeeded(elfheader_t *h);
 void DumpDynamicRPath(elfheader_t *h);
-void DumpDynSym(elfheader_t *h);
-void DumpRelTable(elfheader_t *h, int cnt, Elf64_Rel *rel, const char* name);
-void DumpRelATable(elfheader_t *h, int cnt, Elf64_Rela *rela, const char* name);
-void DumpRelRTable(elfheader_t *h, int cnt, Elf64_Relr *relr, const char *name);
+void DumpDynSym32(elfheader_t *h);
+void DumpDynSym64(elfheader_t *h);
+void DumpRelTable32(elfheader_t *h, int cnt, Elf32_Rel *rel, const char* name);
+void DumpRelTable64(elfheader_t *h, int cnt, Elf64_Rel *rel, const char* name);
+void DumpRelATable32(elfheader_t *h, int cnt, Elf32_Rela *rela, const char* name);
+void DumpRelATable64(elfheader_t *h, int cnt, Elf64_Rela *rela, const char* name);
+void DumpRelRTable32(elfheader_t *h, int cnt, Elf32_Relr *relr, const char *name);
+void DumpRelRTable64(elfheader_t *h, int cnt, Elf64_Relr *relr, const char *name);
 
 void DumpBinary(char* p, int sz);
 
diff --git a/src/include/elfloader.h b/src/include/elfloader.h
index 770709c8..edaf9771 100644
--- a/src/include/elfloader.h
+++ b/src/include/elfloader.h
@@ -45,7 +45,6 @@ int CalcLoadAddr(elfheader_t* head);
 int AllocLoadElfMemory(box64context_t* context, elfheader_t* head, int mainbin);
 void FreeElfMemory(elfheader_t* head);
 int isElfHasNeededVer(elfheader_t* head, const char* libname, elfheader_t* verneeded);
-void GrabX64CopyMainElfReloc(elfheader_t* head);
 int RelocateElf(lib_t *maplib, lib_t* local_maplib, int bindnow, int deepbind, elfheader_t* head);
 int RelocateElfPlt(lib_t *maplib, lib_t* local_maplib, int bindnow, int deepbind, elfheader_t* head);
 void CalcStack(elfheader_t* h, uint64_t* stacksz, size_t* stackalign);
@@ -91,7 +90,7 @@ int GetNeededVersionForLib(elfheader_t* h, const char* libname, const char* ver)
 void* ElfGetLocalSymbolStartEnd(elfheader_t* head, uintptr_t *offs, uintptr_t *sz, const char* symname, int* ver, const char** vername, int local, int* veropt);
 void* ElfGetGlobalSymbolStartEnd(elfheader_t* head, uintptr_t *offs, uintptr_t *sz, const char* symname, int* ver, const char** vername, int local, int* veropt);
 void* ElfGetWeakSymbolStartEnd(elfheader_t* head, uintptr_t *offs, uintptr_t *sz, const char* symname, int* ver, const char** vername, int local, int* veropt);
-int ElfGetSymTabStartEnd(elfheader_t* head, uintptr_t *offs, uintptr_t *end, const char* symname);
+int ElfGetSymTabStartEnd64(elfheader_t* head, uintptr_t *offs, uintptr_t *end, const char* symname);
 
 void* GetNativeSymbolUnversioned(void* lib, const char* name);
 
diff --git a/src/include/x64run.h b/src/include/x64run.h
index b6c9e960..a5d4528e 100644
--- a/src/include/x64run.h
+++ b/src/include/x64run.h
@@ -9,8 +9,8 @@ int RunTest(x64test_t *test);
 void DynaRun(x64emu_t *emu);
 
 uint32_t LibSyscall(x64emu_t *emu);
-void PltResolver(x64emu_t* emu);
-extern uintptr_t pltResolver;
+void PltResolver64(x64emu_t* emu);
+extern uintptr_t pltResolver64;
 int GetTID(void);
 
 #endif //__X64RUN_H_
\ No newline at end of file
diff --git a/src/librarian/librarian.c b/src/librarian/librarian.c
index 56a0fffa..b836e4ca 100644
--- a/src/librarian/librarian.c
+++ b/src/librarian/librarian.c
@@ -709,8 +709,12 @@ int GetSymTabStartEnd(lib_t* maplib, const char* name, uintptr_t* start, uintptr
         return 0;
     for(int i=0; i<maplib->libsz; ++i) {
         elfheader_t* h = GetElf(maplib->libraries[i]);
-        if(h && ElfGetSymTabStartEnd(h, start, end, name))
-            return 1;
+        if(box64_is32bits) {
+            /* TODO */
+        } else {
+            if(h && ElfGetSymTabStartEnd64(h, start, end, name))
+                return 1;
+        }
     }
     return 0;
 }
diff --git a/src/librarian/library.c b/src/librarian/library.c
index 350a68a9..69f27d5f 100644
--- a/src/librarian/library.c
+++ b/src/librarian/library.c
@@ -232,6 +232,10 @@ int DummyLib_GetLocal(library_t* lib, const char* name, uintptr_t *offs, uintptr
 }
 
 static void initWrappedLib(library_t *lib, box64context_t* context) {
+    if(box64_is32bits) {
+        // TODO
+        return; // nothing wrapped yet
+    }
     int nb = sizeof(wrappedlibs) / sizeof(wrappedlib_t);
     for (int i=0; i<nb; ++i) {
         if(strcmp(lib->name, wrappedlibs[i].name)==0) {
diff --git a/src/mallochook.c b/src/mallochook.c
index f63a85bd..abdadc8d 100644
--- a/src/mallochook.c
+++ b/src/mallochook.c
@@ -776,11 +776,15 @@ void checkHookedSymbols(elfheader_t* h)
     int hooked_symtab = 0;
     if(box64_malloc_hack==1)
         return;
+    if(box64_is32bits) {
+        /* TODO? */
+        return;
+    }
     for (size_t i=0; i<h->numSymTab; ++i) {
-        int type = ELF64_ST_TYPE(h->SymTab[i].st_info);
-        int sz = ELF64_ST_TYPE(h->SymTab[i].st_size);
-        if((type==STT_FUNC) && sz && (h->SymTab[i].st_shndx!=0 && h->SymTab[i].st_shndx<=65521)) {
-            const char * symname = h->StrTab+h->SymTab[i].st_name;
+        int type = ELF64_ST_TYPE(h->SymTab._64[i].st_info);
+        int sz = ELF64_ST_TYPE(h->SymTab._64[i].st_size);
+        if((type==STT_FUNC) && sz && (h->SymTab._64[i].st_shndx!=0 && h->SymTab._64[i].st_shndx<=65521)) {
+            const char * symname = h->StrTab+h->SymTab._64[i].st_name;
             #define GO(A, B) if(!strcmp(symname, #A)) ++hooked; else if(!strcmp(symname, "__libc_" #A)) ++hooked;
             #define GO2(A, B)
             SUPER()
@@ -790,14 +794,14 @@ void checkHookedSymbols(elfheader_t* h)
     }
     if(hooked<2) {
         for (size_t i=0; i<h->numDynSym && hooked<2; ++i) {
-            const char * symname = h->DynStr+h->DynSym[i].st_name;
-            int bind = ELF64_ST_BIND(h->DynSym[i].st_info);
-            int type = ELF64_ST_TYPE(h->DynSym[i].st_info);
-            int vis = h->DynSym[i].st_other&0x3;
+            const char * symname = h->DynStr+h->DynSym._64[i].st_name;
+            int bind = ELF64_ST_BIND(h->DynSym._64[i].st_info);
+            int type = ELF64_ST_TYPE(h->DynSym._64[i].st_info);
+            int vis = h->DynSym._64[i].st_other&0x3;
             if((type==STT_FUNC) 
-            && (vis==STV_DEFAULT || vis==STV_PROTECTED) && (h->DynSym[i].st_shndx!=0 && h->DynSym[i].st_shndx<=65521)) {
-                uintptr_t offs = h->DynSym[i].st_value + h->delta;
-                size_t sz = h->DynSym[i].st_size;
+            && (vis==STV_DEFAULT || vis==STV_PROTECTED) && (h->DynSym._64[i].st_shndx!=0 && h->DynSym._64[i].st_shndx<=65521)) {
+                uintptr_t offs = h->DynSym._64[i].st_value + h->delta;
+                size_t sz = h->DynSym._64[i].st_size;
                 if(bind!=STB_LOCAL && bind!=STB_WEAK && sz>=sizeof(reloc_jmp_t)) {
                     #define GO(A, B) if(!strcmp(symname, #A)) ++hooked; else if(!strcmp(symname, "__libc_" #A)) ++hooked;
                     #define GO2(A, B)
@@ -814,11 +818,11 @@ void checkHookedSymbols(elfheader_t* h)
     printf_log(LOG_INFO, "Redirecting overridden malloc%s from %s function for %s\n", malloc_hack_2?" with hack":"", hooked_symtab?"symtab":"dynsym", ElfName(h));
     if(hooked_symtab) {
         for (size_t i=0; i<h->numSymTab; ++i) {
-            int type = ELF64_ST_TYPE(h->SymTab[i].st_info);
+            int type = ELF64_ST_TYPE(h->SymTab._64[i].st_info);
             if(type==STT_FUNC) {
-                const char * symname = h->StrTab+h->SymTab[i].st_name;
-                uintptr_t offs = h->SymTab[i].st_value + h->delta;
-                size_t sz = h->SymTab[i].st_size;
+                const char * symname = h->StrTab+h->SymTab._64[i].st_name;
+                uintptr_t offs = h->SymTab._64[i].st_value + h->delta;
+                size_t sz = h->SymTab._64[i].st_size;
                 #define GO(A, B) if(!strcmp(symname, "__libc_" #A)) {uintptr_t alt = AddCheckBridge(my_context->system, B, A, 0, #A); printf_log(LOG_DEBUG, "Redirecting %s function from %p (%s)\n", symname, (void*)offs, ElfName(h)); addRelocJmp((void*)offs, (void*)alt, sz, "__libc_" #A, h, NULL);}
                 #define GO2(A, B)
                 SUPER()
@@ -833,14 +837,14 @@ void checkHookedSymbols(elfheader_t* h)
         }
     } else {
         for (size_t i=0; i<h->numDynSym; ++i) {
-            const char * symname = h->DynStr+h->DynSym[i].st_name;
-            int bind = ELF64_ST_BIND(h->DynSym[i].st_info);
-            int type = ELF64_ST_TYPE(h->DynSym[i].st_info);
-            int vis = h->DynSym[i].st_other&0x3;
+            const char * symname = h->DynStr+h->DynSym._64[i].st_name;
+            int bind = ELF64_ST_BIND(h->DynSym._64[i].st_info);
+            int type = ELF64_ST_TYPE(h->DynSym._64[i].st_info);
+            int vis = h->DynSym._64[i].st_other&0x3;
             if((type==STT_FUNC) 
-            && (vis==STV_DEFAULT || vis==STV_PROTECTED) && (h->DynSym[i].st_shndx!=0 && h->DynSym[i].st_shndx<=65521)) {
-                uintptr_t offs = h->DynSym[i].st_value + h->delta;
-                size_t sz = h->DynSym[i].st_size;
+            && (vis==STV_DEFAULT || vis==STV_PROTECTED) && (h->DynSym._64[i].st_shndx!=0 && h->DynSym._64[i].st_shndx<=65521)) {
+                uintptr_t offs = h->DynSym._64[i].st_value + h->delta;
+                size_t sz = h->DynSym._64[i].st_size;
                 if(bind!=STB_LOCAL && bind!=STB_WEAK) {
                     #define GO(A, B) if(!strcmp(symname, "__libc_" #A)) {uintptr_t alt = AddCheckBridge(my_context->system, B, A, 0, #A); printf_log(LOG_DEBUG, "Redirecting %s function from %p (%s)\n", symname, (void*)offs, ElfName(h)); addRelocJmp((void*)offs, (void*)alt, sz, "__libc_" #A, h, NULL);}
                     #define GO2(A, B)