about summary refs log tree commit diff stats
path: root/src
diff options
context:
space:
mode:
authorptitSeb <sebastien.chev@gmail.com>2021-05-29 18:05:37 +0200
committerptitSeb <sebastien.chev@gmail.com>2021-05-29 18:05:37 +0200
commitf8a969d43ed26e64d21238ead0e9512360fb1fdd (patch)
tree96dd023f4fef48fe62f8a1d9b7c3a1d61b0c2af4 /src
parent55720342adbf22ba318a66b30ed9ea6ec789b032 (diff)
downloadbox64-f8a969d43ed26e64d21238ead0e9512360fb1fdd.tar.gz
box64-f8a969d43ed26e64d21238ead0e9512360fb1fdd.zip
Reworked elfloader, handle versionned symbols now
Diffstat (limited to 'src')
-rwxr-xr-xsrc/box64context.c2
-rwxr-xr-xsrc/elfs/elfload_dump.c17
-rwxr-xr-xsrc/elfs/elfloader.c235
-rwxr-xr-xsrc/elfs/elfloader_private.h5
-rwxr-xr-xsrc/elfs/elfparser.c172
-rwxr-xr-xsrc/include/box64context.h2
-rwxr-xr-xsrc/include/dictionnary.h13
-rwxr-xr-xsrc/include/elfload_dump.h2
-rwxr-xr-xsrc/include/elfloader.h5
-rwxr-xr-xsrc/include/librarian.h26
-rwxr-xr-xsrc/include/library.h7
-rw-r--r--src/include/symbols.h24
-rwxr-xr-xsrc/include/wrappedlibs.h2
-rwxr-xr-xsrc/librarian/dictionnary.c48
-rwxr-xr-xsrc/librarian/librarian.c246
-rwxr-xr-xsrc/librarian/librarian_private.h11
-rwxr-xr-xsrc/librarian/library.c125
-rwxr-xr-xsrc/librarian/library_private.h2
-rw-r--r--src/librarian/symbols.c233
-rwxr-xr-xsrc/main.c20
-rwxr-xr-xsrc/wrapped/wrappedlib_init.h18
-rwxr-xr-xsrc/wrapped/wrappedlibdl.c144
22 files changed, 966 insertions, 393 deletions
diff --git a/src/box64context.c b/src/box64context.c
index 182a079f..2688b124 100755
--- a/src/box64context.c
+++ b/src/box64context.c
@@ -158,6 +158,7 @@ box64context_t *NewBox64Context(int argc)
 
     context->maplib = NewLibrarian(context, 1);
     context->local_maplib = NewLibrarian(context, 1);
+    context->versym = NewDictionnary();
     context->system = NewBridge();
     // create vsyscall
     context->vsyscall = AddBridge(context->system, vFv, x64Syscall, 0, NULL);
@@ -197,6 +198,7 @@ void FreeBox64Context(box64context_t** context)
         FreeLibrarian(&ctx->local_maplib, NULL);
     if(ctx->maplib)
         FreeLibrarian(&ctx->maplib, NULL);
+    FreeDictionnary(&ctx->versym);
 
     for(int i=0; i<ctx->elfsize; ++i) {
         FreeElfHeader(&ctx->elfs[i]);
diff --git a/src/elfs/elfload_dump.c b/src/elfs/elfload_dump.c
index 58415c44..d7d11e47 100755
--- a/src/elfs/elfload_dump.c
+++ b/src/elfs/elfload_dump.c
@@ -225,13 +225,14 @@ const char* DumpRelType(int t)
     return buff;
 }
 
-const char* DumpSym(elfheader_t *h, Elf64_Sym* sym)
+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)));
     memset(buff, 0, sizeof(buff));
-    sprintf(buff, "\"%s\", value=%p, size=%ld, info/other=%d/%d index=%d", 
+    sprintf(buff, "\"%s\", value=%p, size=%ld, info/other=%d/%d index=%d (ver=%d/%s)", 
         h->DynStr+sym->st_name, (void*)sym->st_value, sym->st_size,
-        sym->st_info, sym->st_other, sym->st_shndx);
+        sym->st_info, sym->st_other, sym->st_shndx, version, vername);
     return buff;
 }
 
@@ -298,8 +299,10 @@ void DumpDynSym(elfheader_t *h)
     if(box64_dump && h->DynSym) {
         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)
-            printf_dump(LOG_NEVER, "  %s:DynSym[%zu] = %s\n", name, i, DumpSym(h, h->DynSym+i));
+        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, "ELF Dump DynSym=====\n");
     }
 }
@@ -351,11 +354,11 @@ void DumpRelATable(elfheader_t *h, int cnt, Elf64_Rela *rela, const char* name)
         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%lX: %s, sym=0x%lX/%s) Addend=0x%lx\n", elfname,
+            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)), 
                 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 RelA Table=====\n");
+        printf_dump(LOG_NEVER, "ELF Dump %s Table=====\n", name);
     }
 }
 
diff --git a/src/elfs/elfloader.c b/src/elfs/elfloader.c
index c49a56ea..15619efc 100755
--- a/src/elfs/elfloader.c
+++ b/src/elfs/elfloader.c
@@ -28,6 +28,8 @@
 #include "box64stack.h"
 #include "custommem.h"
 #include "wine_tools.h"
+#include "dictionnary.h"
+#include "symbols.h"
 #ifdef DYNAREC
 #include "dynablock.h"
 #endif
@@ -353,7 +355,7 @@ int ReloadElfMemory(FILE* f, box64context_t* context, elfheader_t* head)
     return 0;
 }
 
-int FindR64COPYRel(elfheader_t* h, const char* name, uintptr_t *offs, uint64_t** p)
+int FindR64COPYRel(elfheader_t* h, const char* name, uintptr_t *offs, uint64_t** p, int version, const char* vername)
 {
     if(!h)
         return 0;
@@ -365,7 +367,10 @@ int FindR64COPYRel(elfheader_t* h, const char* name, uintptr_t *offs, uint64_t**
         int t = ELF64_R_TYPE(rel[i].r_info);
         Elf64_Sym *sym = &h->DynSym[ELF64_R_SYM(rel[i].r_info)];
         const char* symname = SymName(h, sym);
-        if(!strcmp(symname, name) && t==R_X86_64_COPY) {
+        int version2 = h->VerSym?((Elf64_Half*)((uintptr_t)h->VerSym+h->delta))[ELF64_R_SYM(rel[i].r_info)]:-1;
+        if(version2!=-1) version2 &= 0x7fff;
+        const char* vername2 = GetSymbolVersion(h, version2);
+        if(SameVersionnedSymbol(name, version, vername, symname, version2, vername2) && t==R_X86_64_COPY) {
             *offs = sym->st_value + h->delta;
             *p = (uint64_t*)(rel[i].r_offset + h->delta + rel[i].r_addend);
             return 1;
@@ -381,27 +386,30 @@ int RelocateElfREL(lib_t *maplib, lib_t *local_maplib, elfheader_t* head, int cn
         Elf64_Sym *sym = &head->DynSym[ELF64_R_SYM(rel[i].r_info)];
         int bind = ELF64_ST_BIND(sym->st_info);
         const char* symname = SymName(head, sym);
-        uint64_t ndx = sym->st_shndx;
+        //uint64_t ndx = sym->st_shndx;
         uint64_t *p = (uint64_t*)(rel[i].r_offset + head->delta);
         uintptr_t offs = 0;
         uintptr_t end = 0;
         //uintptr_t tmp = 0;
+        int version = head->VerSym?((Elf64_Half*)((uintptr_t)head->VerSym+head->delta))[ELF64_R_SYM(rel[i].r_info)]:-1;
+        if(version!=-1) version &=0x7fff;
+        const char* vername = GetSymbolVersion(head, version);
         if(bind==STB_LOCAL) {
             offs = sym->st_value + head->delta;
             end = offs + sym->st_size;
         } else {
             // this is probably very very wrong. A proprer way to get reloc need to be writen, but this hack seems ok for now
             // at least it work for half-life, unreal, ut99, zsnes, Undertale, ColinMcRae Remake, FTL, ShovelKnight...
-            if(bind==STB_GLOBAL && (ndx==10 || ndx==19) && t!=R_X86_64_GLOB_DAT) {
+            /*if(bind==STB_GLOBAL && (ndx==10 || ndx==19) && t!=R_X86_64_GLOB_DAT) {
                 offs = sym->st_value + head->delta;
                 end = offs + sym->st_size;
-            }
+            }*/
             // so weak symbol are the one left
             if(!offs && !end) {
-                if(local_maplib)
-                    GetGlobalSymbolStartEnd(local_maplib, symname, &offs, &end);
-                if(!offs && !end)
-                    GetGlobalSymbolStartEnd(maplib, symname, &offs, &end);
+                GetGlobalSymbolStartEnd(maplib, symname, &offs, &end, head, version, vername);
+                if(!offs && !end && local_maplib) {
+                    GetGlobalSymbolStartEnd(local_maplib, symname, &offs, &end, head, version, vername);
+                }
             }
         }
         uintptr_t globoffs, globend;
@@ -421,21 +429,21 @@ int RelocateElfREL(lib_t *maplib, lib_t *local_maplib, elfheader_t* head, int cn
                     *p += offs;
                 break;
             case R_X86_64_GLOB_DAT:
-                if(head!=my_context->elfs[0] && !IsGlobalNoWeakSymbolInNative(maplib, symname) && FindR64COPYRel(my_context->elfs[0], symname, &globoffs, &globp)) {
+                if(head!=my_context->elfs[0] && !IsGlobalNoWeakSymbolInNative(maplib, symname, version, vername) && FindR64COPYRel(my_context->elfs[0], symname, &globoffs, &globp, version, vername)) {
                     // set global offs / size for the symbol
                     offs = sym->st_value + head->delta;
                     end = offs + sym->st_size;
                     if(sym->st_size) {
                         printf_dump(LOG_NEVER, "Apply %s R_X86_64_GLOB_DAT with R_X86_64_COPY @%p/%p (%p/%p -> %p/%p) size=%ld on sym=%s \n", (bind==STB_LOCAL)?"Local":"Global", p, globp, (void*)(p?(*p):0), (void*)(globp?(*globp):0), (void*)offs, (void*)globoffs, sym->st_size, symname);
                         //memmove((void*)globoffs, (void*)offs, sym->st_size);   // preapply to copy part from lib to main elf
-                        AddWeakSymbol(GetGlobalData(maplib), symname, offs, sym->st_size);
+                        AddWeakSymbol(GetGlobalData(maplib), symname, offs, sym->st_size, version, vername);
                     } else {
                         printf_dump(LOG_NEVER, "Apply %s R_X86_64_GLOB_DAT with R_X86_64_COPY @%p/%p (%p/%p -> %p/%p) null sized on sym=%s \n", (bind==STB_LOCAL)?"Local":"Global", p, globp, (void*)(p?(*p):0), (void*)(globp?(*globp):0), (void*)offs, (void*)globoffs, symname);
                     }
                     *p = globoffs;
                 } else {
                     // Look for same symbol already loaded but not in self (so no need for local_maplib here)
-                    if (GetGlobalNoWeakSymbolStartEnd(maplib, symname, &globoffs, &globend)) {
+                    if (GetGlobalNoWeakSymbolStartEnd(maplib, symname, &globoffs, &globend, version, vername)) {
                         offs = globoffs;
                         end = globend;
                     }
@@ -453,12 +461,11 @@ int RelocateElfREL(lib_t *maplib, lib_t *local_maplib, elfheader_t* head, int cn
                     uintptr_t old_offs = offs;
                     uintptr_t old_end = end;
                     offs = 0;
-                    GetSymbolStartEnd(GetGlobalData(maplib), symname, &offs, &end); // try globaldata symbols first
+                    GetSymbolStartEnd(GetGlobalData(maplib), symname, &offs, &end, version, vername, 1); // try globaldata symbols first
                     if(offs==0) {
-                        if(local_maplib)
-                            GetNoSelfSymbolStartEnd(local_maplib, symname, &offs, &end, head);
-                        if(!offs)
-                            GetNoSelfSymbolStartEnd(maplib, symname, &offs, &end, head);   // get original copy if any
+                        GetNoSelfSymbolStartEnd(maplib, symname, &offs, &end, head, version, vername);   // get original copy if any
+                        if(!offs && local_maplib)
+                            GetNoSelfSymbolStartEnd(local_maplib, symname, &offs, &end, head, version, vername);
                     }
                     if(!offs) {
                         offs = old_offs;
@@ -532,29 +539,31 @@ int RelocateElfRELA(lib_t *maplib, lib_t *local_maplib, elfheader_t* head, int c
         int t = ELF64_R_TYPE(rela[i].r_info);
         Elf64_Sym *sym = &head->DynSym[ELF64_R_SYM(rela[i].r_info)];
         int bind = ELF64_ST_BIND(sym->st_info);
-        uint64_t ndx = sym->st_shndx;
+        //uint64_t ndx = sym->st_shndx;
         const char* symname = SymName(head, sym);
         uint64_t *p = (uint64_t*)(rela[i].r_offset + head->delta);
         uintptr_t offs = 0;
         uintptr_t end = 0;
         elfheader_t* h_tls = head;
+        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);
         if(bind==STB_LOCAL) {
             offs = sym->st_value + head->delta;
             end = offs + sym->st_size;
         } else {
             // this is probably very very wrong. A proprer way to get reloc need to be writen, but this hack seems ok for now
             // at least it work for half-life, unreal, ut99, zsnes, Undertale, ColinMcRae Remake, FTL, ShovelKnight...
-            if(bind==STB_GLOBAL && (ndx==10 || ndx==19) && t!=R_X86_64_GLOB_DAT) {
+            /*if(bind==STB_GLOBAL && (ndx==10 || ndx==19) && t!=R_X86_64_GLOB_DAT) {
                 offs = sym->st_value + head->delta;
                 end = offs + sym->st_size;
-            }
+            }*/
             // so weak symbol are the one left
             if(!offs && !end) {
-                h_tls = NULL;
-                if(local_maplib)
-                    GetGlobalSymbolStartEnd(local_maplib, symname, &offs, &end);
-                if(!offs && !end)
-                    GetGlobalSymbolStartEnd(maplib, symname, &offs, &end);
+                GetGlobalSymbolStartEnd(maplib, symname, &offs, &end, head, version, vername);
+                if(!offs && !end && local_maplib) {
+                    GetGlobalSymbolStartEnd(local_maplib, symname, &offs, &end, head, version, vername);
+                }
             }
         }
         uintptr_t globoffs, globend;
@@ -576,11 +585,11 @@ int RelocateElfRELA(lib_t *maplib, lib_t *local_maplib, elfheader_t* head, int c
                 globoffs = offs;
                 globend = end;
                 offs = end = 0;
-                GetSymbolStartEnd(GetGlobalData(maplib), symname, &offs, &end); // try globaldata symbols first
+                GetSymbolStartEnd(GetGlobalData(maplib), symname, &offs, &end, version, vername, 1); // try globaldata symbols first
                 if(!offs && local_maplib)
-                    GetNoSelfSymbolStartEnd(local_maplib, symname, &offs, &end, head);
+                    GetNoSelfSymbolStartEnd(local_maplib, symname, &offs, &end, head, version, vername);
                 if(!offs)
-                    GetNoSelfSymbolStartEnd(maplib, symname, &offs, &end, head);
+                    GetNoSelfSymbolStartEnd(maplib, symname, &offs, &end, head, version, vername);
                 if(!offs) {offs = globoffs; end = globend;}
                 if(offs) {
                     // add r_addend to p?
@@ -592,7 +601,7 @@ int RelocateElfRELA(lib_t *maplib, lib_t *local_maplib, elfheader_t* head, int c
                 }
                 break;
             case R_X86_64_GLOB_DAT:
-                if(head!=my_context->elfs[0] && !IsGlobalNoWeakSymbolInNative(maplib, symname) && FindR64COPYRel(my_context->elfs[0], symname, &globoffs, &globp)) {
+                if(head!=my_context->elfs[0] && !IsGlobalNoWeakSymbolInNative(maplib, symname, version, vername) && FindR64COPYRel(my_context->elfs[0], symname, &globoffs, &globp, version, vername)) {
                     // set global offs / size for the symbol
                     offs = sym->st_value + head->delta;
                     end = offs + sym->st_size;
@@ -601,16 +610,16 @@ int RelocateElfRELA(lib_t *maplib, lib_t *local_maplib, elfheader_t* head, int c
                             (bind==STB_LOCAL)?"Local":"Global", p, globp, (void*)(p?(*p):0), 
                             (void*)(globp?(*globp):0), (void*)offs, (void*)globoffs, sym->st_size, symname);
                         //memmove((void*)globoffs, (void*)offs, sym->st_size);   // preapply to copy part from lib to main elf
-                        AddWeakSymbol(GetGlobalData(maplib), symname, offs, sym->st_size);
+                        AddWeakSymbol(GetGlobalData(maplib), symname, offs, sym->st_size, version, vername);
                     } else {
-                        printf_dump(LOG_NEVER, "Apply %s R_X86_64_GLOB_DAT with R_X86_64_COPY @%p/%p (%p/%p -> %p/%p) null sized on sym=%s \n", 
+                        printf_dump(LOG_NEVER, "Apply %s R_X86_64_GLOB_DAT with R_X86_64_COPY @%p/%p (%p/%p -> %p/%p) null sized on sym=%s (ver=%d/%s)\n", 
                             (bind==STB_LOCAL)?"Local":"Global", p, globp, (void*)(p?(*p):0), 
-                            (void*)(globp?(*globp):0), (void*)offs, (void*)globoffs, symname);
+                            (void*)(globp?(*globp):0), (void*)offs, (void*)globoffs, symname, version, vername?vername:"(none)");
                     }
                     *p = globoffs;
                 } else {
                     // Look for same symbol already loaded but not in self (so no need for local_maplib here)
-                    if (GetGlobalNoWeakSymbolStartEnd(maplib, symname, &globoffs, &globend)) {
+                    if (GetGlobalNoWeakSymbolStartEnd(maplib, symname, &globoffs, &globend, version, vername)) {
                         offs = globoffs;
                         end = globend;
                     }
@@ -661,8 +670,8 @@ int RelocateElfRELA(lib_t *maplib, lib_t *local_maplib, elfheader_t* head, int c
                     printf_log(LOG_NONE, "Error: Symbol %s not found, cannot apply R_X86_64_64 @%p (%p) in %s\n", symname, p, *(void**)p, head->name);
                     // return -1;
                 } else {
-                    printf_dump(LOG_NEVER, "Apply %s R_X86_64_64 @%p with sym=%s addend=0x%lx (%p -> %p)\n", 
-                        (bind==STB_LOCAL)?"Local":"Global", p, symname, rela[i].r_addend, *(void**)p, (void*)(offs+rela[i].r_addend/*+*(uint64_t*)p*/));
+                    printf_dump(LOG_NEVER, "Apply %s R_X86_64_64 @%p with sym=%s (ver=%d/%s) addend=0x%lx (%p -> %p)\n", 
+                        (bind==STB_LOCAL)?"Local":"Global", p, symname, version, vername?vername:"(none)", rela[i].r_addend, *(void**)p, (void*)(offs+rela[i].r_addend/*+*(uint64_t*)p*/));
                     *p /*+*/= offs+rela[i].r_addend;
                 }
                 break;
@@ -673,9 +682,9 @@ int RelocateElfRELA(lib_t *maplib, lib_t *local_maplib, elfheader_t* head, int c
                         offs = sym->st_value;
                     else {
                         if(local_maplib)
-                            h_tls = GetGlobalSymbolElf(local_maplib, symname);
+                            h_tls = GetGlobalSymbolElf(local_maplib, symname, version, vername);
                         if(!h_tls)
-                            h_tls = GetGlobalSymbolElf(maplib, symname);
+                            h_tls = GetGlobalSymbolElf(maplib, symname, version, vername);
                     }
                     if(h_tls) {
                         delta = *(int64_t*)p;
@@ -693,9 +702,9 @@ int RelocateElfRELA(lib_t *maplib, lib_t *local_maplib, elfheader_t* head, int c
                 else {
                     if(!h_tls) {
                         if(local_maplib)
-                            h_tls = GetGlobalSymbolElf(local_maplib, symname);
+                            h_tls = GetGlobalSymbolElf(local_maplib, symname, version, vername);
                         if(!h_tls)
-                            h_tls = GetGlobalSymbolElf(maplib, symname);
+                            h_tls = GetGlobalSymbolElf(maplib, symname, version, vername);
                     }
                     offs = getElfIndex(my_context, h_tls);
                 }
@@ -856,27 +865,51 @@ uintptr_t GetLastByte(elfheader_t* h)
 
 void AddSymbols(lib_t *maplib, kh_mapsymbols_t* mapsymbols, kh_mapsymbols_t* weaksymbols, kh_mapsymbols_t* localsymbols, elfheader_t* h)
 {
+    if(box64_dump && h->DynSym) DumpDynSym(h);
     printf_dump(LOG_NEVER, "Will look for Symbol to add in SymTable(%zu)\n", h->numSymTab);
     for (size_t i=0; i<h->numSymTab; ++i) {
         const char * symname = h->StrTab+h->SymTab[i].st_name;
         int bind = ELF64_ST_BIND(h->SymTab[i].st_info);
         int type = ELF64_ST_TYPE(h->SymTab[i].st_info);
         int vis = h->SymTab[i].st_other&0x3;
+        uint64_t sz = h->SymTab[i].st_size;
         if((type==STT_OBJECT || type==STT_FUNC || type==STT_COMMON || type==STT_TLS  || type==STT_NOTYPE) 
         && (vis==STV_DEFAULT || vis==STV_PROTECTED) && (h->SymTab[i].st_shndx!=0)) {
-            if((bind==STB_GNU_UNIQUE /*|| (bind==STB_GLOBAL && type==STT_FUNC)*/) && FindGlobalSymbol(maplib, symname))
-                continue;
-            uintptr_t offs = (type==STT_TLS)?h->SymTab[i].st_value:(h->SymTab[i].st_value + h->delta);
-            uint64_t sz = h->SymTab[i].st_size;
-            printf_dump(LOG_NEVER, "Adding Symbol(bind=%s) \"%s\" with offset=%p sz=%zu\n", (bind==STB_LOCAL)?"LOCAL":((bind==STB_WEAK)?"WEAK":"GLOBAL"), symname, (void*)offs, sz);
-            if(bind==STB_LOCAL)
-                AddSymbol(localsymbols, symname, offs, sz);
-            else    // add in local and global map 
-                if(bind==STB_WEAK) {
-                    AddSymbol(weaksymbols, symname, offs, sz);
-                } else {
-                    AddSymbol(mapsymbols, symname, offs, sz);
-                }
+            if(sz && strstr(symname, "@@")) {
+                char symnameversionned[strlen(symname)+1];
+                strcpy(symnameversionned, symname);
+                // extact symname@@vername
+                char* p = strchr(symnameversionned, '@');
+                *p=0;
+                p+=2;
+                symname = AddDictionnary(my_context->versym, symnameversionned);
+                const char* vername = AddDictionnary(my_context->versym, p);
+                if((bind==STB_GNU_UNIQUE /*|| (bind==STB_GLOBAL && type==STT_FUNC)*/) && FindGlobalSymbol(maplib, symname, 2, p))
+                    continue;
+                uintptr_t offs = (type==STT_TLS)?h->SymTab[i].st_value:(h->SymTab[i].st_value + h->delta);
+                printf_dump(LOG_NEVER, "Adding Default Versionned Symbol(bind=%s) \"%s@%s\" with offset=%p sz=%zu\n", (bind==STB_LOCAL)?"LOCAL":((bind==STB_WEAK)?"WEAK":"GLOBAL"), symname, vername, (void*)offs, sz);
+                if(bind==STB_LOCAL)
+                    AddSymbol(localsymbols, symname, offs, sz, 2, vername);
+                else    // add in local and global map 
+                    if(bind==STB_WEAK) {
+                        AddSymbol(weaksymbols, symname, offs, sz, 2, vername);
+                    } else {
+                        AddSymbol(mapsymbols, symname, offs, sz, 2, vername);
+                    }
+            } else {
+                if((bind==STB_GNU_UNIQUE /*|| (bind==STB_GLOBAL && type==STT_FUNC)*/) && FindGlobalSymbol(maplib, symname, -1, NULL))
+                    continue;
+                uintptr_t offs = (type==STT_TLS)?h->SymTab[i].st_value:(h->SymTab[i].st_value + h->delta);
+                printf_dump(LOG_NEVER, "Adding Symbol(bind=%s) \"%s\" with offset=%p sz=%zu\n", (bind==STB_LOCAL)?"LOCAL":((bind==STB_WEAK)?"WEAK":"GLOBAL"), symname, (void*)offs, sz);
+                if(bind==STB_LOCAL)
+                    AddSymbol(localsymbols, symname, offs, sz, 1, NULL);
+                else    // add in local and global map 
+                    if(bind==STB_WEAK) {
+                        AddSymbol(weaksymbols, symname, offs, sz, 1, NULL);
+                    } else {
+                        AddSymbol(mapsymbols, symname, offs, sz, 1, NULL);
+                    }
+            }
         }
     }
     
@@ -886,21 +919,23 @@ void AddSymbols(lib_t *maplib, kh_mapsymbols_t* mapsymbols, kh_mapsymbols_t* wea
         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;
-        //st_shndx==65521 means ABS value
         if((type==STT_OBJECT || type==STT_FUNC || type==STT_COMMON || type==STT_TLS  || type==STT_NOTYPE) 
         && (vis==STV_DEFAULT || vis==STV_PROTECTED) && (h->DynSym[i].st_shndx!=0 && h->DynSym[i].st_shndx<=65521)) {
-            if((bind==STB_GNU_UNIQUE || (bind==STB_GLOBAL && type==STT_FUNC)) && FindGlobalSymbol(maplib, symname))
-                continue;
             uintptr_t offs = (type==STT_TLS)?h->DynSym[i].st_value:(h->DynSym[i].st_value + h->delta);
             uint64_t sz = h->DynSym[i].st_size;
-            printf_dump(LOG_NEVER, "Adding Symbol(bind=%s) \"%s\" with offset=%p sz=%zu\n", (bind==STB_LOCAL)?"LOCAL":((bind==STB_WEAK)?"WEAK":"GLOBAL"), symname, (void*)offs, sz);
+            int version = h->VerSym?((Elf64_Half*)((uintptr_t)h->VerSym+h->delta))[i]:-1;
+            if(version!=-1) version &= 0x7fff;
+            const char* vername = GetSymbolVersion(h, version);
+            if((bind==STB_GNU_UNIQUE /*|| (bind==STB_GLOBAL && type==STT_FUNC)*/) && FindGlobalSymbol(maplib, symname, version, vername))
+                continue;
+            printf_dump(LOG_NEVER, "Adding Versionned Symbol(bind=%s) \"%s\" (ver=%d/%s) with offset=%p sz=%zu\n", (bind==STB_LOCAL)?"LOCAL":((bind==STB_WEAK)?"WEAK":"GLOBAL"), symname, version, vername?vername:"(none)", (void*)offs, sz);
             if(bind==STB_LOCAL)
-                AddSymbol(localsymbols, symname, offs, sz);
+                AddSymbol(localsymbols, symname, offs, sz, version, vername);
             else // add in local and global map 
                 if(bind==STB_WEAK) {
-                    AddSymbol(weaksymbols, symname, offs, sz);
+                    AddSymbol(weaksymbols, symname, offs, sz, version, vername);
                 } else {
-                    AddSymbol(mapsymbols, symname, offs, sz);
+                    AddSymbol(mapsymbols, symname, offs, sz, version, vername);
                 }
         }
     }
@@ -971,16 +1006,22 @@ int LoadNeededLibs(elfheader_t* h, lib_t *maplib, needed_libs_t* neededlibs, lib
         h->neededlibs = neededlibs;
 
     DumpDynamicNeeded(h);
-    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;
-            // TODO: Add LD_LIBRARY_PATH and RPATH handling
-            if(AddNeededLib(maplib, neededlibs, deplib, local, needed, box64, emu)) {
-                printf_log(LOG_INFO, "Error loading needed lib: \"%s\"\n", needed);
-                if(!allow_missing_libs)
-                    return 1;   //error...
-            }
-        }
+    int cnt = 0;
+    for (int i=0; i<h->numDynamic; ++i)
+        if(h->Dynamic[i].d_tag==DT_NEEDED)
+            ++cnt;
+    const char* nlibs[cnt];
+    int j=0;
+    for (int i=0; i<h->numDynamic; ++i)
+        if(h->Dynamic[i].d_tag==DT_NEEDED)
+            nlibs[j++] = h->DynStrTab+h->delta+h->Dynamic[i].d_un.d_val;
+
+    // TODO: Add LD_LIBRARY_PATH and RPATH handling
+    if(AddNeededLib(maplib, neededlibs, deplib, local, nlibs, cnt, box64, emu)) {
+        printf_log(LOG_INFO, "Error loading one of needed lib\n");
+        if(!allow_missing_libs)
+            return 1;   //error...
+    }
     return 0;
 }
 
@@ -1163,6 +1204,43 @@ const char* FindNearestSymbolName(elfheader_t* h, void* p, uintptr_t* start, uin
     return ret;
 }
 
+const char* VersionnedName(const char* name, int ver, const char* vername)
+{
+    if(ver==-1)
+        return name;
+    const char *v=NULL;
+    if(ver==0)
+        v="";
+    if(ver==1)
+        v="*";
+    if(!v && !vername)
+        return name;
+    if(ver>1)
+        v = vername;
+    char buf[strlen(name)+strlen(v)+1+1];
+    strcpy(buf, name);
+    strcat(buf, "@");
+    strcat(buf, v);
+    return AddDictionnary(my_context->versym, buf);
+}
+
+int SameVersionnedSymbol(const char* name1, int ver1, const char* vername1, const char* name2, int ver2, const char* vername2)
+{
+    if(strcmp(name1, name2))    //name are different, no need to go further
+        return 0;
+    if(ver1==-1 || ver2==-1)    // don't check version, so ok
+        return 1;
+    if(ver1==ver2 && ver1<2)    // same ver (local or global), ok
+        return 1;
+    if(ver1==0 || ver2==0)  // one is local, the other is not, no match
+        return 0;
+    if(ver1==1 || ver2==1)  // one if global, ok
+        return 1;
+    if(!strcmp(vername1, vername2))  // same vername
+        return 1;
+    return 0;
+}
+
 void* GetDTatOffset(box64context_t* context, unsigned long int index, unsigned long int offset)
 {
     return (void*)((char*)GetTLSPointer(context, context->elfs[index])+offset);
@@ -1353,34 +1431,37 @@ EXPORT void PltResolver(x64emu_t* emu)
     uintptr_t addr = Pop64(emu);
     int slot = (int)Pop64(emu);
     elfheader_t *h = (elfheader_t*)addr;
-    printf_dump(LOG_DEBUG, "PltResolver: Addr=%p, Slot=%d Return=%p: elf is %s\n", (void*)addr, slot, *(void**)(R_RSP), h->name);
+    printf_dump(LOG_DEBUG, "PltResolver: Addr=%p, Slot=%d Return=%p: elf is %s (VerSym=%p)\n", (void*)addr, slot, *(void**)(R_RSP), h->name, h->VerSym);
 
     Elf64_Rela * rel = (Elf64_Rela *)(h->jmprel + h->delta) + slot;
 
     Elf64_Sym *sym = &h->DynSym[ELF64_R_SYM(rel->r_info)];
     int bind = ELF64_ST_BIND(sym->st_info);
     const char* symname = SymName(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);
     uint64_t *p = (uint64_t*)(rel->r_offset + h->delta);
     uintptr_t offs = 0;
     uintptr_t end = 0;
 
     library_t* lib = h->lib;
     lib_t* local_maplib = GetMaplib(lib);
-    if(local_maplib)
-        GetGlobalSymbolStartEnd(local_maplib, symname, &offs, &end);
-    if(!offs && !end)
-        GetGlobalSymbolStartEnd(my_context->maplib, symname, &offs, &end);
+    GetGlobalSymbolStartEnd(my_context->maplib, symname, &offs, &end, h, version, vername);
+    if(!offs && !end && local_maplib) {
+        GetGlobalSymbolStartEnd(local_maplib, symname, &offs, &end, h, version, vername);
+    }
 
     if (!offs) {
-        printf_log(LOG_NONE, "Error: PltReolver: Symbol %s not found, cannot apply R_X86_64_JUMP_SLOT @%p (%p) in %s\n", symname, p, *(void**)p, h->name);
+        printf_log(LOG_NONE, "Error: PltReolver: Symbol %s(ver %d: %s%s%s) not found, cannot apply R_X86_64_JUMP_SLOT %p (%p) in %s\n", symname, version, symname, vername?"@":"", vername?vername:"", p, *(void**)p, h->name);
         emu->quit = 1;
         return;
     } else {
         if(p) {
-            printf_dump(LOG_DEBUG, "PltReolver: Apply %s R_X86_64_JUMP_SLOT @%p with sym=%s (%p -> %p / %s)\n", (bind==STB_LOCAL)?"Local":"Global", p, symname, *(void**)p, (void*)offs, ElfName(FindElfAddress(my_context, offs)));
+            printf_dump(LOG_DEBUG, "            Apply %s R_X86_64_JUMP_SLOT %p with sym=%s(ver %d: %s%s%s) (%p -> %p / %s)\n", (bind==STB_LOCAL)?"Local":"Global", p, symname, version, symname, vername?"@":"", vername?vername:"",*(void**)p, (void*)offs, ElfName(FindElfAddress(my_context, offs)));
             *p = offs;
         } else {
-            printf_log(LOG_NONE, "PltReolver: Warning, Symbol %s found, but Jump Slot Offset is NULL \n", symname);
+            printf_log(LOG_NONE, "PltReolver: Warning, Symbol %s(ver %d: %s%s%s) found, but Jump Slot Offset is NULL \n", symname, version, symname, vername?"@":"", vername?vername:"");
         }
     }
 
diff --git a/src/elfs/elfloader_private.h b/src/elfs/elfloader_private.h
index fa488845..d3d09daa 100755
--- a/src/elfs/elfloader_private.h
+++ b/src/elfs/elfloader_private.h
@@ -30,6 +30,11 @@ struct elfheader_s {
     size_t      numDynamic;
     char*       DynStrTab;
     size_t      szDynStrTab;
+    Elf64_Half* VerSym;
+    Elf64_Verneed*  VerNeed;
+    int         szVerNeed;
+    Elf64_Verdef*   VerDef;
+    int         szVerDef;
     int         e_type;
 
     intptr_t    delta;  // should be 0
diff --git a/src/elfs/elfparser.c b/src/elfs/elfparser.c
index a5c7f186..453e507e 100755
--- a/src/elfs/elfparser.c
+++ b/src/elfs/elfparser.c
@@ -194,30 +194,87 @@ elfheader_t* ParseElfHeader(FILE* f, const char* name, int exec)
         // also grab the DT_STRTAB string table
         {
             for (size_t i=0; i<h->numDynamic; ++i) {
-                if(h->Dynamic[i].d_tag == DT_REL)
-                    h->rel = h->Dynamic[i].d_un.d_ptr;
-                else if(h->Dynamic[i].d_tag == DT_RELSZ)
-                    h->relsz = h->Dynamic[i].d_un.d_val;
-                else if(h->Dynamic[i].d_tag == DT_RELENT)
-                    h->relent = h->Dynamic[i].d_un.d_val;
-                else if(h->Dynamic[i].d_tag == DT_RELA)
-                    h->rela = h->Dynamic[i].d_un.d_ptr;
-                else if(h->Dynamic[i].d_tag == DT_RELASZ)
-                    h->relasz = h->Dynamic[i].d_un.d_val;
-                else if(h->Dynamic[i].d_tag == DT_RELAENT)
-                    h->relaent = h->Dynamic[i].d_un.d_val;
-                else if(h->Dynamic[i].d_tag == DT_PLTGOT)
-                    h->pltgot = h->Dynamic[i].d_un.d_val;
-                else if(h->Dynamic[i].d_tag == DT_PLTREL)
-                    h->pltrel = h->Dynamic[i].d_un.d_val;
-                else if(h->Dynamic[i].d_tag == DT_PLTRELSZ)
-                    h->pltsz = h->Dynamic[i].d_un.d_val;
-                else if(h->Dynamic[i].d_tag == DT_JMPREL)
-                    h->jmprel = h->Dynamic[i].d_un.d_val;
-                else if(h->Dynamic[i].d_tag == DT_STRTAB)
-                    h->DynStrTab = (char*)(h->Dynamic[i].d_un.d_ptr);
-                else if(h->Dynamic[i].d_tag == DT_STRSZ)
-                    h->szDynStrTab = h->Dynamic[i].d_un.d_val;
+                Elf64_Dyn d = h->Dynamic[i];
+                Elf64_Word val = d.d_un.d_val;
+                Elf64_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_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*)(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", (void*)h->initentry);
+                    break;
+                case DT_INIT_ARRAY:
+                    h->initarray = ptr;
+                    printf_log(LOG_DEBUG, "The DT_INIT_ARRAY is at address %p\n", (void*)h->initarray);
+                    break;
+                case DT_INIT_ARRAYSZ:
+                    h->initarray_sz = val / sizeof(Elf64_Addr);
+                    printf_log(LOG_DEBUG, "The DT_INIT_ARRAYSZ is %zu\n", h->initarray_sz);
+                    break;
+                case DT_FINI: // Exit hook
+                    h->finientry = ptr;
+                    printf_log(LOG_DEBUG, "The DT_FINI is at address %p\n", (void*)h->finientry);
+                    break;
+                case DT_FINI_ARRAY:
+                    h->finiarray = ptr;
+                    printf_log(LOG_DEBUG, "The DT_FINI_ARRAY is at address %p\n", (void*)h->finiarray);
+                    break;
+                case DT_FINI_ARRAYSZ:
+                    h->finiarray_sz = val / sizeof(Elf64_Addr);
+                    printf_log(LOG_DEBUG, "The DT_FINI_ARRAYSZ is %zu\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 = (Elf64_Verneed*)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 = (Elf64_Verdef*)ptr;
+                    printf_log(LOG_DEBUG, "The DT_VERDEF is at address %p\n", h->VerDef);
+                    break;
+                }
             }
             if(h->rel) {
                 if(h->relent != sizeof(Elf64_Rel)) {
@@ -275,31 +332,11 @@ elfheader_t* ParseElfHeader(FILE* f, const char* name, int exec)
             h->plt_end = h->plt + h->SHEntries[ii].sh_size;
             printf_log(LOG_DEBUG, "The PLT Table is at address %p..%p\n", (void*)h->plt, (void*)h->plt_end);
         }
-        // look for .init entry point
-        ii = FindSection(h->SHEntries, h->numSHEntries, h->SHStrTab, ".init");
-        if(ii) {
-            h->initentry = h->SHEntries[ii].sh_addr;
-            printf_log(LOG_DEBUG, "The .init is at address %p\n", (void*)h->initentry);
-        }
-        // and .init_array
-        ii = FindSection(h->SHEntries, h->numSHEntries, h->SHStrTab, ".init_array");
-        if(ii) {
-            h->initarray_sz = h->SHEntries[ii].sh_size / sizeof(Elf64_Addr);
-            h->initarray = (uintptr_t)(h->SHEntries[ii].sh_addr);
-            printf_log(LOG_DEBUG, "The .init_array is at address %p, and have %zu elements\n", (void*)h->initarray, h->initarray_sz);
-        }
-        // look for .fini entry point
-        ii = FindSection(h->SHEntries, h->numSHEntries, h->SHStrTab, ".fini");
+        // grab version of symbols
+        ii = FindSection(h->SHEntries, h->numSHEntries, h->SHStrTab, ".gnu.version");
         if(ii) {
-            h->finientry = h->SHEntries[ii].sh_addr;
-            printf_log(LOG_DEBUG, "The .fini is at address %p\n", (void*)h->finientry);
-        }
-        // and .fini_array
-        ii = FindSection(h->SHEntries, h->numSHEntries, h->SHStrTab, ".fini_array");
-        if(ii) {
-            h->finiarray_sz = h->SHEntries[ii].sh_size / sizeof(Elf64_Addr);
-            h->finiarray = (uintptr_t)(h->SHEntries[ii].sh_addr);
-            printf_log(LOG_DEBUG, "The .fini_array is at address %p, and have %zu elements\n", (void*)h->finiarray, h->finiarray_sz);
+            h->VerSym = (Elf64_Half*)(h->SHEntries[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, h->numSHEntries, h->SHStrTab, ".text");
@@ -311,8 +348,45 @@ elfheader_t* ParseElfHeader(FILE* f, const char* name, int exec)
 
         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);
-        if(box64_dump && h->DynSym) DumpDynSym(h);
     }
     
     return h;
 }
+
+const char* GetSymbolVersion(elfheader_t* h, int version)
+{
+    if(!h->VerNeed || (version<2))
+        return NULL;
+    /*if(version==1)
+        return "*";*/
+    Elf64_Verneed *ver = (Elf64_Verneed*)((uintptr_t)h->VerNeed + h->delta);
+    while(ver) {
+        Elf64_Vernaux *aux = (Elf64_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 = (Elf64_Vernaux*)((uintptr_t)aux + aux->vna_next);
+        }
+        ver = ver->vn_next?((Elf64_Verneed*)((uintptr_t)ver + ver->vn_next)):NULL;
+    }
+    return GetParentSymbolVersion(h, version);  // if symbol is "internal", use Def table instead
+}
+
+const char* GetParentSymbolVersion(elfheader_t* h, int index)
+{
+    if(!h->VerDef || (index<1))
+        return NULL;
+    Elf64_Verdef *def = (Elf64_Verdef*)((uintptr_t)h->VerDef + 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;*/
+            Elf64_Verdaux *aux = (Elf64_Verdaux*)((uintptr_t)def + def->vd_aux);
+            return h->DynStr+aux->vda_name; // return Parent, so 1st aux
+        }
+        def = def->vd_next?((Elf64_Verdef*)((uintptr_t)def + def->vd_next)):NULL;
+    }
+    return NULL;
+}
diff --git a/src/include/box64context.h b/src/include/box64context.h
index d5e8b82d..a83d79ec 100755
--- a/src/include/box64context.h
+++ b/src/include/box64context.h
@@ -3,6 +3,7 @@
 #include <stdint.h>
 #include <pthread.h>
 #include "pathcoll.h"
+#include "dictionnary.h"
 
 typedef struct elfheader_s elfheader_t;
 typedef struct cleanup_s cleanup_t;
@@ -97,6 +98,7 @@ typedef struct box64context_s {
 
     lib_t               *maplib;        // lib and symbols handling
     lib_t               *local_maplib;  // libs and symbols openned has local (only collection of libs, no symbols)
+    dic_t               *versym;        // dictionnary of versionned symbols
 
     kh_threadstack_t    *stacksizes;    // stack sizes attributes for thread (temporary)
     bridge_t            *system;        // other bridges
diff --git a/src/include/dictionnary.h b/src/include/dictionnary.h
new file mode 100755
index 00000000..e2ec1466
--- /dev/null
+++ b/src/include/dictionnary.h
@@ -0,0 +1,13 @@
+#ifndef __DICTIONNARY_H_

+#define __DICTIONNARY_H_

+#include <stdint.h>

+

+typedef void dic_t;

+

+dic_t *NewDictionnary();

+void FreeDictionnary(dic_t **dic);

+

+const char* AddDictionnary(dic_t* dic, const char* s);

+int ExistDictionnary(dic_t* dic, const char* s);

+

+#endif //__DICTIONNARY_H_
\ No newline at end of file
diff --git a/src/include/elfload_dump.h b/src/include/elfload_dump.h
index 251ea3b8..ce0e9c1b 100755
--- a/src/include/elfload_dump.h
+++ b/src/include/elfload_dump.h
@@ -6,7 +6,7 @@ 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);
+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);
diff --git a/src/include/elfloader.h b/src/include/elfloader.h
index aef5ae35..df745aa2 100755
--- a/src/include/elfloader.h
+++ b/src/include/elfloader.h
@@ -55,4 +55,9 @@ void CreateMemorymapFile(box64context_t* context, int fd);
 
 int ElfCheckIfUseTCMallocMinimal(elfheader_t* h);   // return 1 if tcmalloc is used
 
+const char* GetSymbolVersion(elfheader_t* h, int version);
+const char* GetParentSymbolVersion(elfheader_t* h, int index);
+const char* VersionnedName(const char* name, int ver, const char* vername);
+int SameVersionnedSymbol(const char* name1, int ver1, const char* vername1, const char* name2, int ver2, const char* vername2);
+
 #endif //__ELF_LOADER_H_
diff --git a/src/include/librarian.h b/src/include/librarian.h
index 37eda132..522c98b6 100755
--- a/src/include/librarian.h
+++ b/src/include/librarian.h
@@ -24,24 +24,18 @@ kh_mapsymbols_t* GetMapSymbol(lib_t* maplib);
 kh_mapsymbols_t* GetWeakSymbol(lib_t* maplib);
 kh_mapsymbols_t* GetLocalSymbol(lib_t* maplib);
 kh_mapsymbols_t* GetGlobalData(lib_t* maplib);
-int AddNeededLib(lib_t* maplib, needed_libs_t* neededlibs, library_t *deplib, int local, const char* path, box64context_t* box64, x64emu_t* emu); // 0=success, 1=error
+int AddNeededLib(lib_t* maplib, needed_libs_t* neededlibs, library_t *deplib, int local, const char** paths, int npath, box64context_t* box64, x64emu_t* emu); // 0=success, 1=error
 library_t* GetLibMapLib(lib_t* maplib, const char* name);
 library_t* GetLibInternal(const char* name);
-uintptr_t FindGlobalSymbol(lib_t *maplib, const char* name);
-int GetNoSelfSymbolStartEnd(lib_t *maplib, const char* name, uintptr_t* start, uintptr_t* end, elfheader_t* self);
-int GetSelfSymbolStartEnd(lib_t *maplib, const char* name, uintptr_t* start, uintptr_t* end, elfheader_t *self);
-int GetGlobalSymbolStartEnd(lib_t *maplib, const char* name, uintptr_t* start, uintptr_t* end);
-int GetGlobalNoWeakSymbolStartEnd(lib_t *maplib, const char* name, uintptr_t* start, uintptr_t* end);
-int GetLocalSymbolStartEnd(lib_t *maplib, const char* name, uintptr_t* start, uintptr_t* end, elfheader_t *self);
-int GetNoWeakSymbolStartEnd(lib_t *maplib, const char* name, uintptr_t* start, uintptr_t* end, elfheader_t *self);
-elfheader_t* GetGlobalSymbolElf(lib_t *maplib, const char* name);
-int IsGlobalNoWeakSymbolInNative(lib_t *maplib, const char* name);
-
-void AddSymbol(kh_mapsymbols_t *mapsymbols, const char* name, uintptr_t addr, uint64_t sz); // replace if already there
-uintptr_t FindSymbol(kh_mapsymbols_t *mapsymbols, const char* name);
-void AddWeakSymbol(kh_mapsymbols_t *mapsymbols, const char* name, uintptr_t addr, uint64_t sz); // don't add if already there
-int GetSymbolStartEnd(kh_mapsymbols_t* mapsymbols, const char* name, uintptr_t* start, uintptr_t* end);
-const char* GetSymbolName(kh_mapsymbols_t* mapsymbols, void* p, uintptr_t* offs, uint64_t* sz);
+uintptr_t FindGlobalSymbol(lib_t *maplib, const char* name, int version, const char* vername);
+int GetNoSelfSymbolStartEnd(lib_t *maplib, const char* name, uintptr_t* start, uintptr_t* end, elfheader_t* self, int version, const char* vername);
+int GetSelfSymbolStartEnd(lib_t *maplib, const char* name, uintptr_t* start, uintptr_t* end, elfheader_t *self, int version, const char* vername);
+int GetGlobalSymbolStartEnd(lib_t *maplib, const char* name, uintptr_t* start, uintptr_t* end, elfheader_t *self, int version, const char* vername);
+int GetGlobalNoWeakSymbolStartEnd(lib_t *maplib, const char* name, uintptr_t* start, uintptr_t* end, int version, const char* vername);
+int GetLocalSymbolStartEnd(lib_t *maplib, const char* name, uintptr_t* start, uintptr_t* end, elfheader_t *self, int version, const char* vername);
+int GetNoWeakSymbolStartEnd(lib_t *maplib, const char* name, uintptr_t* start, uintptr_t* end, elfheader_t *self, int version, const char* vername);
+elfheader_t* GetGlobalSymbolElf(lib_t *maplib, const char* name, int version, const char* vername);
+int IsGlobalNoWeakSymbolInNative(lib_t *maplib, const char* name, int version, const char* vername);
 
 const char* FindSymbolName(lib_t *maplib, void* p, void** start, uint64_t* sz, const char** libname, void** base);
 
diff --git a/src/include/library.h b/src/include/library.h
index 26f395dc..64f376ec 100755
--- a/src/include/library.h
+++ b/src/include/library.h
@@ -1,6 +1,7 @@
 #ifndef __LIBRARY_H_
 #define __LIBRARY_H_
 #include <stdint.h>
+#include "symbols.h"
 
 typedef struct library_s       library_t;
 typedef struct lib_s           lib_t;
@@ -18,9 +19,9 @@ void Free1Library(library_t **lib, x64emu_t* emu);
 
 char* GetNameLib(library_t *lib);
 int IsSameLib(library_t* lib, const char* path);    // check if lib is same (path -> name)
-int GetLibSymbolStartEnd(library_t* lib, const char* name, uintptr_t* start, uintptr_t* end);
-int GetLibNoWeakSymbolStartEnd(library_t* lib, const char* name, uintptr_t* start, uintptr_t* end);
-int GetLibLocalSymbolStartEnd(library_t* lib, const char* name, uintptr_t* start, uintptr_t* end);
+int GetLibSymbolStartEnd(library_t* lib, const char* name, uintptr_t* start, uintptr_t* end, int version, const char* vername, int local);
+int GetLibNoWeakSymbolStartEnd(library_t* lib, const char* name, uintptr_t* start, uintptr_t* end, int version, const char* vername, int local);
+int GetLibLocalSymbolStartEnd(library_t* lib, const char* name, uintptr_t* start, uintptr_t* end, int version, const char* vername, int local);
 void fillGLProcWrapper(box64context_t* context);
 void freeGLProcWrapper(box64context_t* context);
 void fillALProcWrapper(box64context_t* context);
diff --git a/src/include/symbols.h b/src/include/symbols.h
new file mode 100644
index 00000000..49cd40f0
--- /dev/null
+++ b/src/include/symbols.h
@@ -0,0 +1,24 @@
+#ifndef __SYMBOLS_PRIVATE_H_
+#define __SYMBOLS_PRIVATE_H_
+#include <stdint.h>
+
+#include "custommem.h"
+#include "khash.h"
+
+typedef struct versymbols_s versymbols_t;
+
+KHASH_MAP_DECLARE_STR(mapsymbols, versymbols_t)
+
+kh_mapsymbols_t* NewMapSymbols();
+void FreeMapSymbols(kh_mapsymbols_t** map);
+
+// replace if already there
+void AddSymbol(kh_mapsymbols_t *mapsymbols, const char* name, uintptr_t addr, uint32_t sz, int ver, const char* vername);
+uintptr_t FindSymbol(kh_mapsymbols_t *mapsymbols, const char* name, int ver, const char* vername, int local);
+// don't add if already there
+
+void AddWeakSymbol(kh_mapsymbols_t *mapsymbols, const char* name, uintptr_t addr, uint32_t sz, int ver, const char* vername);
+int GetSymbolStartEnd(kh_mapsymbols_t* mapsymbols, const char* name, uintptr_t* start, uintptr_t* end, int ver, const char* vername, int local);
+const char* GetSymbolName(kh_mapsymbols_t* mapsymbols, void* p, uintptr_t* offs, uint32_t* sz, const char** vername);
+
+#endif //__SYMBOLS_PRIVATE_H_
\ No newline at end of file
diff --git a/src/include/wrappedlibs.h b/src/include/wrappedlibs.h
index 41e27765..f78dcfb2 100755
--- a/src/include/wrappedlibs.h
+++ b/src/include/wrappedlibs.h
@@ -7,7 +7,7 @@ typedef struct box64context_s  box64context_t;
 
 typedef int (*wrappedlib_init_t)(library_t * lib, box64context_t* box64);  // 0 = success
 typedef void (*wrappedlib_fini_t)(library_t * lib);
-typedef int (*wrappedlib_get_t)(library_t* lib, const char* name, uintptr_t *offs, uintptr_t *sz);
+typedef int (*wrappedlib_get_t)(library_t* lib, const char* name, uintptr_t *offs, uintptr_t *sz, int version, const char* vername, int local);
 
 typedef struct wrappedlib_s {
     const char*         name;
diff --git a/src/librarian/dictionnary.c b/src/librarian/dictionnary.c
new file mode 100755
index 00000000..9d343e93
--- /dev/null
+++ b/src/librarian/dictionnary.c
@@ -0,0 +1,48 @@
+#include <stdio.h>

+#include <stdlib.h>

+

+#include "debug.h"

+#include "dictionnary.h"

+#include "custommem.h"

+#include "khash.h"

+

+KHASH_SET_INIT_STR(dic);

+

+dic_t *NewDictionnary()

+{

+    dic_t *dic = kh_init(dic);

+    return dic;

+}

+

+void FreeDictionnary(dic_t **d)

+{

+    if(!d || !*d)

+        return;

+    kh_dic_t* dic = (kh_dic_t*)*d;

+    const char* k;

+    kh_foreach_key(dic, k, free((void*)k));

+    kh_destroy(dic, dic);

+    *d = NULL;

+}

+

+const char* AddDictionnary(dic_t* d, const char* s)

+{

+    kh_dic_t* dic = (kh_dic_t*)d;

+    khint_t k = kh_get(dic, dic, s);

+    if(k!=kh_end(dic))

+        return kh_key(dic, k);

+    char* n = strdup(s);

+    int ret;

+    k = kh_put(dic, dic, n, &ret);

+    return n;

+}

+

+int ExistDictionnary(dic_t* d, const char* s)

+{

+    kh_dic_t* dic = (kh_dic_t*)d;

+    khint_t k = kh_get(dic, dic, s);

+    if(k!=kh_end(dic))

+        return 1;

+    return 0;

+

+}
\ No newline at end of file
diff --git a/src/librarian/librarian.c b/src/librarian/librarian.c
index 9eb191fd..2cec106b 100755
--- a/src/librarian/librarian.c
+++ b/src/librarian/librarian.c
@@ -14,18 +14,17 @@
 
 #include "bridge.h"
 
-KHASH_MAP_IMPL_STR(mapsymbols, onesymbol_t);
 KHASH_MAP_IMPL_INT(mapoffsets, cstr_t);
 
 lib_t *NewLibrarian(box64context_t* context, int ownlibs)
 {
     lib_t *maplib = (lib_t*)calloc(1, sizeof(lib_t));
     
-    maplib->mapsymbols = kh_init(mapsymbols);
-    maplib->weaksymbols = kh_init(mapsymbols);
-    maplib->localsymbols = kh_init(mapsymbols);
+    maplib->mapsymbols = NewMapSymbols();
+    maplib->weaksymbols = NewMapSymbols();
+    maplib->localsymbols = NewMapSymbols();
     maplib->mapoffsets = kh_init(mapoffsets);
-    maplib->globaldata = kh_init(mapsymbols);
+    maplib->globaldata = NewMapSymbols();
     maplib->bridge = NewBridge();
 
     maplib->context = context;
@@ -82,30 +81,21 @@ void FreeLibrarian(lib_t **maplib, x64emu_t *emu)
             for (int i=(*maplib)->libsz-1; i>=0; --i) {
                 freeLibraryRecurse(*maplib, emu, i, freed);
             }
-            for (int i=0; i<(*maplib)->libsz; ++i) {
-                (*maplib)->libraries[i] = NULL;
-            }
+            memset((*maplib)->libraries, 0, (*maplib)->libsz*sizeof(library_t*)); // NULL = 0 anyway
+            (*maplib)->libsz = 0;
             free(freed);
         }
     }
     free((*maplib)->libraries);
     (*maplib)->libraries = NULL;
 
-    if((*maplib)->mapsymbols) {
-        kh_destroy(mapsymbols, (*maplib)->mapsymbols);
-    }
-    if((*maplib)->weaksymbols) {
-        kh_destroy(mapsymbols, (*maplib)->weaksymbols);
-    }
-    if((*maplib)->localsymbols) {
-        kh_destroy(mapsymbols, (*maplib)->localsymbols);
-    }
+    FreeMapSymbols(&(*maplib)->mapsymbols);
+    FreeMapSymbols(&(*maplib)->weaksymbols);
+    FreeMapSymbols(&(*maplib)->localsymbols);
     if((*maplib)->mapoffsets) {
         kh_destroy(mapoffsets, (*maplib)->mapoffsets);
     }
-    if((*maplib)->globaldata) {
-        kh_destroy(mapsymbols, (*maplib)->globaldata);
-    }
+    FreeMapSymbols(&(*maplib)->globaldata);
     (*maplib)->libsz = (*maplib)->libcap = 0;
 
     if((*maplib)->bridge)
@@ -164,6 +154,8 @@ static int libraryInMapLib(lib_t* maplib, library_t* lib)
 
 void MapLibAddLib(lib_t* maplib, library_t* lib)
 {
+    if(libraryInMapLib(maplib, lib))
+        return;
     if (maplib->libsz == maplib->libcap) {
         maplib->libcap += 8;
         maplib->libraries = (library_t**)realloc(maplib->libraries, maplib->libcap*sizeof(library_t*));
@@ -202,8 +194,7 @@ void MapLibRemoveLib(lib_t* maplib, library_t* lib)
         memmove(&maplib->libraries[idx], &maplib->libraries[idx+1], sizeof(library_t*)*(maplib->libsz-idx));
 }
 
-EXPORTDYN
-int AddNeededLib(lib_t* maplib, needed_libs_t* neededlibs, library_t* deplib, int local, const char* path, box64context_t* box64, x64emu_t* emu)
+int AddNeededLib_add(lib_t* maplib, needed_libs_t* neededlibs, library_t* deplib, int local, const char* path, box64context_t* box64, x64emu_t* emu)
 {
     printf_log(LOG_DEBUG, "Trying to add \"%s\" to maplib%s\n", path, local?" (local)":"");
     // first check if lib is already loaded
@@ -267,33 +258,38 @@ int AddNeededLib(lib_t* maplib, needed_libs_t* neededlibs, library_t* deplib, in
     if(!maplib)
         maplib = (local)?lib->maplib:my_context->maplib;
 
+
+    if(AddSymbolsLibrary(maplib, lib, emu)) {   // also add needed libs
+        printf_log(LOG_DEBUG, "Failure to Add lib => fail\n");
+        return 1;
+    }
+    return 0;
+}
+
+int AddNeededLib_init(lib_t* maplib, needed_libs_t* neededlibs, library_t* deplib, int local, library_t* lib, box64context_t* box64, x64emu_t* emu)
+{
+    if(!maplib)
+        maplib = (local)?lib->maplib:my_context->maplib;
+
     int mainelf = GetElfIndex(lib);
 
     if(mainelf==-1) {
-        // It's a native libs, just add wrapped symbols to global map
-        if(AddSymbolsLibrary(maplib, lib, emu)) {   // also add needed libs
-            printf_log(LOG_DEBUG, "Failure to Add lib => fail\n");
-            return 1;
-        }
+        // It's a native libs, nothing else to do
     } else {
         // it's an emulated lib, 
-        // lets load dependancies before adding symbols and launch init sequence
+        // load dependancies and launch init sequence
         if(LoadNeededLibs(box64->elfs[mainelf], maplib, &lib->needed, lib, 0, box64, emu)) {
             printf_log(LOG_DEBUG, "Failure to Add dependant lib => fail\n");
             return 1;
         }
         // some special case, where dependancies may not be correct
         if(!strcmp(GetNameLib(lib), "libCgGL.so")) {
-            AddNeededLib(maplib, &lib->needed, lib, 0, "libGL.so.1", box64, emu);
+            const char* libs[] = {"libGL.so.1"};
+            AddNeededLib(maplib, &lib->needed, lib, 0, libs, 1, box64, emu);
         }
         if(!strcmp(GetNameLib(lib), "libmss.so.6")) {
-            AddNeededLib(maplib, &lib->needed, lib, 0, "libSDL-1.2.so.0", box64, emu);
-            AddNeededLib(maplib, &lib->needed, lib, 0, "libdl.so.2", box64, emu);
-        }
-        // add symbols
-        if(AddSymbolsLibrary(maplib, lib, emu)) {   // also add needed libs
-            printf_log(LOG_DEBUG, "Failure to Add lib => fail\n");
-            return 1;
+            const char* libs[] = {"libSDL-1.2.so.0", "libdl.so.2"};
+            AddNeededLib(maplib, &lib->needed, lib, 0, libs, 2, box64, emu);
         }
 
         // finalize the lib
@@ -308,6 +304,26 @@ int AddNeededLib(lib_t* maplib, needed_libs_t* neededlibs, library_t* deplib, in
     return 0;
 }
 
+EXPORTDYN
+int AddNeededLib(lib_t* maplib, needed_libs_t* neededlibs, library_t* deplib, int local, const char** paths, int npath, box64context_t* box64, x64emu_t* emu)
+{
+    if(!neededlibs) {
+        neededlibs = alloca(sizeof(needed_libs_t));
+        memset(neededlibs, 0, sizeof(needed_libs_t));
+    }
+    int idx = neededlibs->size;
+    // Add libs and symbol
+    for(int i=0; i<npath; ++i) {
+        if(AddNeededLib_add(maplib, neededlibs, deplib, local, paths[i], box64, emu))
+            return 1;
+    }
+    // add dependant libs and init them
+    for (int i=idx; i<neededlibs->size; ++i)
+        if(AddNeededLib_init(maplib, neededlibs, deplib, local, neededlibs->libs[i], box64, emu))
+            if(!allow_missing_libs) return 1;
+    return 0;
+}
+
 library_t* GetLibMapLib(lib_t* maplib, const char* name)
 {
     printf_log(LOG_DEBUG, "Trying to Get \"%s\" to maplib\n", name);
@@ -323,44 +339,53 @@ library_t* GetLibInternal(const char* name)
 }
 
 EXPORTDYN
-uintptr_t FindGlobalSymbol(lib_t *maplib, const char* name)
+uintptr_t FindGlobalSymbol(lib_t *maplib, const char* name, int version, const char* vername)
 {
     uintptr_t start = 0, end = 0;
-    if(GetGlobalSymbolStartEnd(maplib, name, &start, &end))
+    if(GetGlobalSymbolStartEnd(maplib, name, &start, &end, (void*)1, version, vername))
         return start;
     return 0;
 }
 
-int GetNoSelfSymbolStartEnd(lib_t *maplib, const char* name, uintptr_t* start, uintptr_t* end, elfheader_t* self)
+static int isLocal(elfheader_t* self, library_t* l)
+{
+    if(GetElfIndex(l)==-1)
+        return 1;
+    if(my_context->elfs[GetElfIndex(l)]==self)
+        return 1;
+    return 0;
+}
+
+int GetNoSelfSymbolStartEnd(lib_t *maplib, const char* name, uintptr_t* start, uintptr_t* end, elfheader_t* self, int version, const char* vername)
 {
     //excude self if defined
     if(maplib->context->elfs[0]!=self) {
-        if(GetSymbolStartEnd(maplib->mapsymbols, name, start, end))
+        if(GetSymbolStartEnd(maplib->mapsymbols, name, start, end, version, vername, 0))
             if(*start)
                 return 1;
-        if(GetSymbolStartEnd(maplib->weaksymbols, name, start, end))
+        if(GetSymbolStartEnd(maplib->weaksymbols, name, start, end, version, vername, 0))
             if(*start)
                 return 1;
     }
     for(int i=0; i<maplib->libsz; ++i) {
         if(GetElfIndex(maplib->libraries[i])==-1 || (maplib->context->elfs[GetElfIndex(maplib->libraries[i])]!=self))
-            if(GetLibSymbolStartEnd(maplib->libraries[i], name, start, end))
+            if(GetLibSymbolStartEnd(maplib->libraries[i], name, start, end, version, vername, 0))
                 if(*start)
                     return 1;
     }
     // if self defined, give it another chance with self...
     if(self) {
         if(maplib->context->elfs[0]==self) {
-            if(GetSymbolStartEnd(maplib->mapsymbols, name, start, end))
+            if(GetSymbolStartEnd(maplib->mapsymbols, name, start, end, version, vername, 1))
                 if(*start)
                     return 1;
-            if(GetSymbolStartEnd(maplib->weaksymbols, name, start, end))
+            if(GetSymbolStartEnd(maplib->weaksymbols, name, start, end, version, vername, 1))
                 if(*start)
                     return 1;
         }
         for(int i=0; i<maplib->libsz; ++i) {
             if(GetElfIndex(maplib->libraries[i])!=-1 && (maplib->context->elfs[GetElfIndex(maplib->libraries[i])]==self))
-                if(GetLibSymbolStartEnd(maplib->libraries[i], name, start, end))
+                if(GetLibSymbolStartEnd(maplib->libraries[i], name, start, end, version, vername, 1))
                     if(*start)
                         return 1;
         }
@@ -368,32 +393,32 @@ int GetNoSelfSymbolStartEnd(lib_t *maplib, const char* name, uintptr_t* start, u
     // nope, not found
     return 0;
 }
-static int GetGlobalSymbolStartEnd_internal(lib_t *maplib, const char* name, uintptr_t* start, uintptr_t* end)
+static int GetGlobalSymbolStartEnd_internal(lib_t *maplib, const char* name, uintptr_t* start, uintptr_t* end, elfheader_t* self, int version, const char* vername)
 {
     // search non-weak symbol, from older to newer (first GLOBAL object wins)
-    if(GetSymbolStartEnd(maplib->mapsymbols, name, start, end))
+    if(GetSymbolStartEnd(maplib->mapsymbols, name, start, end, version, vername, (maplib->context->elfs[0]==self || !self)?1:0))
         if(*start)
             return 1;
     // TODO: create a temporary map to search lib only 1 time, and in order of needed...
     // search in needed libs from neededlibs first, in order
     for(int i=0; i<my_context->neededlibs.size; ++i)
-        if(GetLibNoWeakSymbolStartEnd(my_context->neededlibs.libs[i], name, start, end))
+        if(GetLibNoWeakSymbolStartEnd(my_context->neededlibs.libs[i], name, start, end, version, vername, isLocal(self, my_context->neededlibs.libs[i])))
             if(*start)
                 return 1;
     // search in global symbols
     for(int i=0; i<maplib->libsz; ++i) {
-        if(GetLibNoWeakSymbolStartEnd(maplib->libraries[i], name, start, end))
+        if(GetLibNoWeakSymbolStartEnd(maplib->libraries[i], name, start, end, version, vername, isLocal(self, maplib->libraries[i])))
             if(*start)
                 return 1;
     }
 
     // library from newer to older, weak only now
     for(int i=maplib->libsz-1; i>=0; --i) {
-        if(GetLibSymbolStartEnd(maplib->libraries[i], name, start, end))    // only weak symbol haven't been found yet
+        if(GetLibSymbolStartEnd(maplib->libraries[i], name, start, end, version, vername, isLocal(self, maplib->libraries[i])))    // only weak symbol haven't been found yet
             if(*start)
                 return 1;
     }
-    if(GetSymbolStartEnd(maplib->weaksymbols, name, start, end))
+    if(GetSymbolStartEnd(maplib->weaksymbols, name, start, end, version, vername, (maplib->context->elfs[0]==self || !self)?1:0))
         if(*start)
             return 1;
     // nope, not found
@@ -401,15 +426,15 @@ static int GetGlobalSymbolStartEnd_internal(lib_t *maplib, const char* name, uin
 }
 //void** my_GetGTKDisplay();
 //void** my_GetGthreadsGotInitialized();
-int GetGlobalSymbolStartEnd(lib_t *maplib, const char* name, uintptr_t* start, uintptr_t* end)
+int GetGlobalSymbolStartEnd(lib_t *maplib, const char* name, uintptr_t* start, uintptr_t* end, elfheader_t* self, int version, const char* vername)
 {
-    if(GetGlobalSymbolStartEnd_internal(maplib, name, start, end)) {
+    if(GetGlobalSymbolStartEnd_internal(maplib, name, start, end, self, version, vername)) {
         if(start && end && *end==*start) {  // object is of 0 sized, try to see an "_END" object of null size
             uintptr_t start2, end2;
             char* buff = (char*)malloc(strlen(name) + strlen("_END") + 1);
             strcpy(buff, name);
             strcat(buff, "_END");
-            if(GetGlobalSymbolStartEnd_internal(maplib, buff, &start2, &end2)) {
+            if(GetGlobalSymbolStartEnd_internal(maplib, buff, &start2, &end2, self, version, vername)) {
                 if(end2>*end && start2==end2)
                     *end = end2;
             }
@@ -418,32 +443,32 @@ int GetGlobalSymbolStartEnd(lib_t *maplib, const char* name, uintptr_t* start, u
         return 1;
     }
     // some special case symbol, defined inside box64 itself
-//    if(!strcmp(name, "gdk_display")) {
-//        *start = (uintptr_t)my_GetGTKDisplay();
-//        *end = *start+sizeof(void*);
-//        printf_log(LOG_INFO, "Using global gdk_display for gdk-x11 (%p:%p)\n", start, *(void**)start);
-//        return 1;
-//    }
-//    if(!strcmp(name, "g_threads_got_initialized")) {
-//        *start = (uintptr_t)my_GetGthreadsGotInitialized();
-//        *end = *start+sizeof(int);
-//        printf_log(LOG_INFO, "Using global g_threads_got_initialized for gthread2 (%p:%p)\n", start, *(void**)start);
-//        return 1;
-//    }
+    //if(!strcmp(name, "gdk_display")) {
+    //    *start = (uintptr_t)my_GetGTKDisplay();
+    //    *end = *start+sizeof(void*);
+    //    printf_log(LOG_INFO, "Using global gdk_display for gdk-x11 (%p:%p)\n", start, *(void**)start);
+    //    return 1;
+    //}
+    //if(!strcmp(name, "g_threads_got_initialized")) {
+    //    *start = (uintptr_t)my_GetGthreadsGotInitialized();
+    //    *end = *start+sizeof(int);
+    //    printf_log(LOG_INFO, "Using global g_threads_got_initialized for gthread2 (%p:%p)\n", start, *(void**)start);
+    //    return 1;
+    //}
     // not found...
     return 0;
 }
 
-elfheader_t* GetGlobalSymbolElf(lib_t *maplib, const char* name)
+elfheader_t* GetGlobalSymbolElf(lib_t *maplib, const char* name, int version, const char* vername)
 {
     uintptr_t start = 0;
     uintptr_t end = 0;
-    if(GetSymbolStartEnd(maplib->mapsymbols, name, &start, &end))
+    if(GetSymbolStartEnd(maplib->mapsymbols, name, &start, &end, version, vername, 1))
         return maplib->context->elfs[0];
-    if(GetSymbolStartEnd(maplib->weaksymbols, name, &start, &end))
+    if(GetSymbolStartEnd(maplib->weaksymbols, name, &start, &end, version, vername, 1))
         return maplib->context->elfs[0];
     for(int i=0; i<maplib->libsz; ++i) {
-        if(GetLibSymbolStartEnd(maplib->libraries[i], name, &start, &end)) {
+        if(GetLibSymbolStartEnd(maplib->libraries[i], name, &start, &end, version, vername, 1)) {
             int idx = GetElfIndex(maplib->libraries[i]);
             if(idx==-1) {
                 printf_log(LOG_NONE, "Warning, getting Elf info for a native symbol \"%s\" from lib \"%s\"\n", name, GetNameLib(maplib->libraries[i]));
@@ -456,26 +481,25 @@ elfheader_t* GetGlobalSymbolElf(lib_t *maplib, const char* name)
     return NULL;
 }
 
-int GetGlobalNoWeakSymbolStartEnd(lib_t *maplib, const char* name, uintptr_t* start, uintptr_t* end)
+int GetGlobalNoWeakSymbolStartEnd(lib_t *maplib, const char* name, uintptr_t* start, uintptr_t* end, int version, const char* vername)
 {
-    if(GetSymbolStartEnd(maplib->mapsymbols, name, start, end))
+    if(GetSymbolStartEnd(maplib->mapsymbols, name, start, end, version, vername, 1))
         if(*start || *end)
             return 1;
     for(int i=0; i<maplib->libsz; ++i)
-        if(GetLibNoWeakSymbolStartEnd(maplib->libraries[i], name, start, end))
+        if(GetLibNoWeakSymbolStartEnd(maplib->libraries[i], name, start, end, version, vername, 1))
             if(*start || *end)
                 return 1;
     // nope, not found
     return 0;
 }
 
-int IsGlobalNoWeakSymbolInNative(lib_t *maplib, const char* name)
+int IsGlobalNoWeakSymbolInNative(lib_t *maplib, const char* name, int version, const char* vername)
 {
-    uintptr_t start=0;
-    uintptr_t end=0;
+    uintptr_t start, end;
     for(int i=0; i<maplib->libsz; ++i)
         if(GetElfIndex(maplib->libraries[i])==-1)
-            if(GetLibNoWeakSymbolStartEnd(maplib->libraries[i], name, &start, &end))
+            if(GetLibNoWeakSymbolStartEnd(maplib->libraries[i], name, &start, &end, version, vername, 1))
                 if(start || end)
                     return 1;
     // nope, not found
@@ -483,10 +507,10 @@ int IsGlobalNoWeakSymbolInNative(lib_t *maplib, const char* name)
 
 }
 
-int GetLocalSymbolStartEnd(lib_t *maplib, const char* name, uintptr_t* start, uintptr_t* end, elfheader_t *self)
+int GetLocalSymbolStartEnd(lib_t *maplib, const char* name, uintptr_t* start, uintptr_t* end, elfheader_t *self, int version, const char* vername)
 {
     if(maplib->context->elfs[0]==self || !self) {
-        if(GetSymbolStartEnd(maplib->localsymbols, name, start, end))
+        if(GetSymbolStartEnd(maplib->localsymbols, name, start, end, version, vername, 1))
             if(*start || *end)
                 return 1;
         if(self)
@@ -494,7 +518,7 @@ int GetLocalSymbolStartEnd(lib_t *maplib, const char* name, uintptr_t* start, ui
     }
     for(int i=0; i<maplib->libsz; ++i) {
         if(GetElfIndex(maplib->libraries[i])!=-1 && (!self || maplib->context->elfs[GetElfIndex(maplib->libraries[i])]==self)) {
-            if(GetLibLocalSymbolStartEnd(maplib->libraries[i], name, start, end))
+            if(GetLibLocalSymbolStartEnd(maplib->libraries[i], name, start, end, version, vername, 1))
                 if(*start)
                     return 1;
             if(self)
@@ -504,16 +528,16 @@ int GetLocalSymbolStartEnd(lib_t *maplib, const char* name, uintptr_t* start, ui
     return 0;
 }
 
-int GetSelfSymbolStartEnd(lib_t *maplib, const char* name, uintptr_t* start, uintptr_t* end, elfheader_t *self)
+int GetSelfSymbolStartEnd(lib_t *maplib, const char* name, uintptr_t* start, uintptr_t* end, elfheader_t *self, int version, const char* vername)
 {
     if(maplib->context->elfs[0]==self) {
-        if(GetSymbolStartEnd(maplib->localsymbols, name, start, end))
+        if(GetSymbolStartEnd(maplib->localsymbols, name, start, end, version, vername, 1))
             if(*start || *end)
                 return 1;
     } else {
         for(int i=0; i<maplib->libsz; ++i) {
             if(GetElfIndex(maplib->libraries[i])!=-1 && (maplib->context->elfs[GetElfIndex(maplib->libraries[i])]==self))
-                if(GetLibSymbolStartEnd(maplib->libraries[i], name, start, end))
+                if(GetLibSymbolStartEnd(maplib->libraries[i], name, start, end, version, vername, 1))
                     if(*start || *end)
                         return 1;
         }
@@ -521,72 +545,22 @@ int GetSelfSymbolStartEnd(lib_t *maplib, const char* name, uintptr_t* start, uin
     return 0;
 }
 
-int GetNoWeakSymbolStartEnd(lib_t *maplib, const char* name, uintptr_t* start, uintptr_t* end, elfheader_t *self)
+int GetNoWeakSymbolStartEnd(lib_t *maplib, const char* name, uintptr_t* start, uintptr_t* end, elfheader_t *self, int version, const char* vername)
 {
     if(maplib->context->elfs[0]==self) {
-        if(GetSymbolStartEnd(maplib->mapsymbols, name, start, end))
+        if(GetSymbolStartEnd(maplib->mapsymbols, name, start, end, version, vername, 1))
             if(*start || *end)
                 return 1;
     } else {
         for(int i=0; i<maplib->libsz; ++i) {
             if(GetElfIndex(maplib->libraries[i])!=-1 && (maplib->context->elfs[GetElfIndex(maplib->libraries[i])]==self))
-                if(GetLibNoWeakSymbolStartEnd(maplib->libraries[i], name, start, end))
+                if(GetLibNoWeakSymbolStartEnd(maplib->libraries[i], name, start, end, version, vername, 1))
                     if(*start || *end)
                         return 1;
         }
     }
     return 0;
 }
-
-
-void AddSymbol(kh_mapsymbols_t *mapsymbols, const char* name, uintptr_t addr, uint64_t sz)
-{
-    int ret;
-    khint_t k = kh_put(mapsymbols, mapsymbols, name, &ret);
-    kh_value(mapsymbols, k).offs = addr;
-    kh_value(mapsymbols, k).sz = sz;
-}
-uintptr_t FindSymbol(kh_mapsymbols_t *mapsymbols, const char* name)
-{
-    khint_t k = kh_get(mapsymbols, mapsymbols, name);
-    if(k==kh_end(mapsymbols))
-        return 0;
-    return kh_val(mapsymbols, k).offs;
-}
-void AddWeakSymbol(kh_mapsymbols_t *mapsymbols, const char* name, uintptr_t addr, uint64_t sz)
-{
-    int ret;
-    khint_t k = kh_put(mapsymbols, mapsymbols, name, &ret);
-    if(ret==0)
-        return; // Symbol already there, don't touch it
-    kh_value(mapsymbols, k).offs = addr;
-    kh_value(mapsymbols, k).sz = sz;
-}
-
-int GetSymbolStartEnd(kh_mapsymbols_t* mapsymbols, const char* name, uintptr_t* start, uintptr_t* end)
-{
-    khint_t k = kh_get(mapsymbols, mapsymbols, name);
-    if(k==kh_end(mapsymbols))
-        return 0;
-    *start = kh_val(mapsymbols, k).offs;
-    *end = *start + kh_val(mapsymbols, k).sz;
-    return 1;
-}
-
-const char* GetSymbolName(kh_mapsymbols_t* mapsymbols, void* p, uintptr_t* start, uint64_t* sz)
-{
-    uintptr_t addr = (uintptr_t)p;
-    onesymbol_t *one;
-    kh_foreach_value_ref(mapsymbols, one, 
-        if((one->offs >= addr) && (one->offs+one->sz<addr)) {
-            *start  = one->offs;
-            *sz = one->sz;
-            return kh_key(mapsymbols, __i);
-        }
-    );
-    return NULL;
-}
-
 const char* FindSymbolName(lib_t *maplib, void* p, void** start, uint64_t* sz, const char** libname, void** base)
 {
     // first, search in self...
diff --git a/src/librarian/librarian_private.h b/src/librarian/librarian_private.h
index d76157c7..da2b1f0f 100755
--- a/src/librarian/librarian_private.h
+++ b/src/librarian/librarian_private.h
@@ -6,18 +6,10 @@
 #include "khash.h"
 
 typedef struct box64context_s box64context_t;
-
-typedef struct onesymbol_s {
-    uintptr_t   offs;
-    uint64_t    sz;
-    // need to track type of symbol?
-    // need to track origin?
-} onesymbol_t;
+typedef struct kh_mapsymbols_s kh_mapsymbols_t;
 
 typedef char* cstr_t;
 
-KHASH_MAP_DECLARE_STR(mapsymbols, onesymbol_t)
-
 KHASH_MAP_DECLARE_INT(mapoffsets, cstr_t);
 
 typedef struct lib_s {
@@ -30,6 +22,7 @@ typedef struct lib_s {
     int                   libsz;
     int                   libcap;
     int                   ownlibs;
+    library_t             *owner;       // in case that maplib is owned by a lib
 
     box64context_t*       context;
     
diff --git a/src/librarian/library.c b/src/librarian/library.c
index 6876045d..68ccf919 100755
--- a/src/librarian/library.c
+++ b/src/librarian/library.c
@@ -27,8 +27,8 @@
 // create the native lib list
 #define GO(P, N) int wrapped##N##_init(library_t* lib, box64context_t *box64); \
                  void wrapped##N##_fini(library_t* lib);\
-                 int wrapped##N##_get(library_t* lib, const char* name, uintptr_t *offs, uintptr_t *sz); \
-                 int wrapped##N##_getnoweak(library_t* lib, const char* name, uintptr_t *offs, uintptr_t *sz);
+                 int wrapped##N##_get(library_t* lib, const char* name, uintptr_t *offs, uintptr_t *sz, int version, const char* vername, int local); \
+                 int wrapped##N##_getnoweak(library_t* lib, const char* name, uintptr_t *offs, uintptr_t *sz, int version, const char* vername, int local);
 #include "library_list.h"
 #undef GO
 
@@ -85,51 +85,51 @@ void EmuLib_Fini(library_t* lib)
     kh_destroy(mapsymbols, lib->priv.n.localsymbols);
 }
 
-int EmuLib_Get(library_t* lib, const char* name, uintptr_t *offs, uintptr_t *sz)
+int EmuLib_Get(library_t* lib, const char* name, uintptr_t *offs, uintptr_t *sz, int version, const char* vername, int local)
 {
-    khint_t k;
     // symbols...
-    k = kh_get(mapsymbols, lib->priv.n.mapsymbols, name);
-    if(k!=kh_end(lib->priv.n.mapsymbols)) {
-        *offs = kh_value(lib->priv.n.mapsymbols, k).offs;
-        *sz = kh_value(lib->priv.n.mapsymbols, k).sz;
+    uintptr_t start, end;
+    if(GetSymbolStartEnd(lib->priv.n.mapsymbols, name, &start, &end, version, vername, local))
+    {
+        *offs = start;
+        *sz = end-start;
         return 1;
     }
     // weak symbols...
-    k = kh_get(mapsymbols, lib->priv.n.weaksymbols, name);
-    if(k!=kh_end(lib->priv.n.weaksymbols)) {
-        *offs = kh_value(lib->priv.n.weaksymbols, k).offs;
-        *sz = kh_value(lib->priv.n.weaksymbols, k).sz;
+    if(GetSymbolStartEnd(lib->priv.n.weaksymbols, name, &start, &end, version, vername, local))
+    {
+        *offs = start;
+        *sz = end-start;
         return 1;
     }
     return 0;
 }
-int EmuLib_GetNoWeak(library_t* lib, const char* name, uintptr_t *offs, uintptr_t *sz)
+int EmuLib_GetNoWeak(library_t* lib, const char* name, uintptr_t *offs, uintptr_t *sz, int version, const char* vername, int local)
 {
-    khint_t k;
-    k = kh_get(mapsymbols, lib->priv.n.mapsymbols, name);
-    if(k!=kh_end(lib->priv.n.mapsymbols)) {
-        *offs = kh_value(lib->priv.n.mapsymbols, k).offs;
-        *sz = kh_value(lib->priv.n.mapsymbols, k).sz;
+    uintptr_t start, end;
+    if(GetSymbolStartEnd(lib->priv.n.mapsymbols, name, &start, &end, version, vername, local))
+    {
+        *offs = start;
+        *sz = end-start;
         return 1;
     }
     return 0;
 }
-int EmuLib_GetLocal(library_t* lib, const char* name, uintptr_t *offs, uintptr_t *sz)
+int EmuLib_GetLocal(library_t* lib, const char* name, uintptr_t *offs, uintptr_t *sz, int version, const char* vername, int local)
 {
-    khint_t k;
-    k = kh_get(mapsymbols, lib->priv.n.localsymbols, name);
-    if(k!=kh_end(lib->priv.n.localsymbols)) {
-        *offs = kh_value(lib->priv.n.localsymbols, k).offs;
-        *sz = kh_value(lib->priv.n.localsymbols, k).sz;
+    uintptr_t start, end;
+    if(GetSymbolStartEnd(lib->priv.n.localsymbols, name, &start, &end, version, vername, local))
+    {
+        *offs = start;
+        *sz = end-start;
         return 1;
     }
     return 0;
 }
 
-int NativeLib_GetLocal(library_t* lib, const char* name, uintptr_t *offs, uintptr_t *sz)
+int NativeLib_GetLocal(library_t* lib, const char* name, uintptr_t *offs, uintptr_t *sz, int version, const char* vername, int local)
 {
-    (void)lib; (void)name; (void)offs; (void)sz;
+    (void)lib; (void)name; (void)offs; (void)sz; (void)version; (void)vername; (void)local;
     return 0;
 }
 
@@ -151,11 +151,9 @@ static void initNativeLib(library_t *lib, box64context_t* context) {
             lib->getlocal = NativeLib_GetLocal;
             lib->type = 0;
             // Call librarian to load all dependant elf
-            for(int j=0; j<lib->priv.w.needed; ++j) {
-                if(AddNeededLib(context->maplib, &lib->needed, lib, 0, lib->priv.w.neededlibs[j], context, thread_get_emu())) {
-                    printf_log(LOG_NONE, "Error: loading needed libs in elf %s\n", lib->priv.w.neededlibs[j]);
-                    return;
-                }
+            if(AddNeededLib(context->maplib, &lib->needed, lib, 0, (const char**)lib->priv.w.neededlibs, lib->priv.w.needed, context, NULL)) {  // probably all native, not emulated, so that's fine
+                printf_log(LOG_NONE, "Error: loading a needed libs in elf %s\n", lib->name);
+                return;
             }
             break;
         }
@@ -308,12 +306,12 @@ int FinalizeLibrary(library_t* lib, lib_t* local_maplib, x64emu_t* emu)
         RelocateElfPlt(my_context->maplib, local_maplib, elf_header);
 #ifdef HAVE_TRACE
         if(trace_func) {
-            if (GetGlobalSymbolStartEnd(my_context->maplib, trace_func, &trace_start, &trace_end)) {
+            if (GetGlobalSymbolStartEnd(my_context->maplib, trace_func, &trace_start, &trace_end, elf_header, -1, NULL)) {
                 SetTraceEmu(trace_start, trace_end);
                 printf_log(LOG_INFO, "TRACE on %s only (%p-%p)\n", trace_func, (void*)trace_start, (void*)trace_end);
                 free(trace_func);
                 trace_func = NULL;
-            } else if(GetLibLocalSymbolStartEnd(lib, trace_func, &trace_start, &trace_end)) {
+            } else if(GetLibLocalSymbolStartEnd(lib, trace_func, &trace_start, &trace_end, -1, NULL, 0)) {
                 SetTraceEmu(trace_start, trace_end);
                 printf_log(LOG_INFO, "TRACE on %s only (%p-%p)\n", trace_func, (void*)trace_start, (void*)trace_end);
                 free(trace_func);
@@ -323,11 +321,6 @@ int FinalizeLibrary(library_t* lib, lib_t* local_maplib, x64emu_t* emu)
 #endif
         RunElfInit(elf_header, emu);
     }
-    if(box64_dynarec && strcmp(lib->name, "libfmod.so")==0) {
-        if (GetGlobalSymbolStartEnd(lib->maplib?lib->maplib:my_context->maplib, "FSOUND_Mixer_FPU_Ramp", &fmod_smc_start, &fmod_smc_end)) {
-            printf_log(LOG_INFO, "Detected libfmod with potential SMC part, applying workaround in Dynarec\n");
-        }
-    }
     return 0;
 }
 
@@ -451,22 +444,22 @@ int IsSameLib(library_t* lib, const char* path)
     free(name);
     return ret;
 }
-int GetLibSymbolStartEnd(library_t* lib, const char* name, uintptr_t* start, uintptr_t* end)
+int GetLibSymbolStartEnd(library_t* lib, const char* name, uintptr_t* start, uintptr_t* end, int version, const char* vername, int local)
 {
     if(!name[0] || !lib->active)
         return 0;
     khint_t k;
     // check first if already in the map
-    k = kh_get(bridgemap, lib->bridgemap, name);
+    k = kh_get(bridgemap, lib->bridgemap, VersionnedName(name, version, vername));
     if(k!=kh_end(lib->bridgemap)) {
         *start = kh_value(lib->bridgemap, k).start;
         *end = kh_value(lib->bridgemap, k).end;
         return 1;
     }
     // get a new symbol
-    if(lib->get(lib, name, start, end)) {
+    if(lib->get(lib, name, start, end, version, vername, local)) {
         *end += *start;     // lib->get(...) gives size, not end
-        char* symbol = strdup(name);
+        char* symbol = strdup(VersionnedName(name, version, vername));
         int ret;
         k = kh_put(bridgemap, lib->bridgemap, symbol, &ret);
         kh_value(lib->bridgemap, k).name = symbol;
@@ -477,22 +470,22 @@ int GetLibSymbolStartEnd(library_t* lib, const char* name, uintptr_t* start, uin
     // nope
     return 0;
 }
-int GetLibNoWeakSymbolStartEnd(library_t* lib, const char* name, uintptr_t* start, uintptr_t* end)
+int GetLibNoWeakSymbolStartEnd(library_t* lib, const char* name, uintptr_t* start, uintptr_t* end, int version, const char* vername, int local)
 {
     if(!name[0] || !lib->active)
         return 0;
     khint_t k;
     // get a new symbol
-    if(lib->getnoweak(lib, name, start, end)) {
+    if(lib->getnoweak(lib, name, start, end, version, vername, local)) {
         *end += *start;     // lib->get(...) gives size, not end
         // check if already in the map
-        k = kh_get(bridgemap, lib->bridgemap, name);
+        k = kh_get(bridgemap, lib->bridgemap, VersionnedName(name, version, vername));
         if(k!=kh_end(lib->bridgemap)) {
             *start = kh_value(lib->bridgemap, k).start;
             *end = kh_value(lib->bridgemap, k).end;
             return 1;
         }
-        char* symbol = strdup(name);
+        char* symbol = strdup(VersionnedName(name, version, vername));
         int ret;
         k = kh_put(bridgemap, lib->bridgemap, symbol, &ret);
         kh_value(lib->bridgemap, k).name = symbol;
@@ -503,22 +496,22 @@ int GetLibNoWeakSymbolStartEnd(library_t* lib, const char* name, uintptr_t* star
     // nope
     return 0;
 }
-int GetLibLocalSymbolStartEnd(library_t* lib, const char* name, uintptr_t* start, uintptr_t* end)
+int GetLibLocalSymbolStartEnd(library_t* lib, const char* name, uintptr_t* start, uintptr_t* end, int version, const char* vername, int local)
 {
     if(!name[0] || !lib->active)
         return 0;
     khint_t k;
     // check first if already in the map
-    k = kh_get(bridgemap, lib->bridgemap, name);
+    k = kh_get(bridgemap, lib->bridgemap, VersionnedName(name, version, vername));
     if(k!=kh_end(lib->bridgemap)) {
         *start = kh_value(lib->bridgemap, k).start;
         *end = kh_value(lib->bridgemap, k).end;
         return 1;
     }
     // get a new symbol
-    if(lib->getlocal(lib, name, start, end)) {
+    if(lib->getlocal(lib, name, start, end, version, vername, local)) {
         *end += *start;     // lib->get(...) gives size, not end
-        char* symbol = strdup(name);
+        char* symbol = strdup(VersionnedName(name, version, vername));
         int ret;
         k = kh_put(bridgemap, lib->bridgemap, symbol, &ret);
         kh_value(lib->bridgemap, k).name = symbol;
@@ -536,14 +529,10 @@ int GetElfIndex(library_t* lib)
     return lib->priv.n.elf_index;
 }
 
-int getSymbolInMaps(library_t *lib, const char* name, int noweak, uintptr_t *addr, uintptr_t *size)
+static int getSymbolInDataMaps(library_t*lib, const char* name, int noweak, uintptr_t *addr, uintptr_t *size)
 {
-    if(!lib->active)
-        return 0;
-    khint_t k;
     void* symbol;
-    // check in datamap
-    k = kh_get(datamap, lib->datamap, name);
+    khint_t k = kh_get(datamap, lib->datamap, name);
     if (k!=kh_end(lib->datamap)) {
         symbol = dlsym(lib->priv.w.lib, kh_key(lib->datamap, k));
         if(symbol) {
@@ -584,8 +573,13 @@ int getSymbolInMaps(library_t *lib, const char* name, int noweak, uintptr_t *add
             return 1;
         }
     }
+    return 0;
+}
+static int getSymbolInSymbolMaps(library_t*lib, const char* name, int noweak, uintptr_t *addr, uintptr_t *size)
+{
+    void* symbol;
     // check in mysymbolmap
-    k = kh_get(symbolmap, lib->mysymbolmap, name);
+    khint_t k = kh_get(symbolmap, lib->mysymbolmap, name);
     if (k!=kh_end(lib->mysymbolmap)) {
         char buff[200];
         if(lib->altmy)
@@ -680,6 +674,23 @@ int getSymbolInMaps(library_t *lib, const char* name, int noweak, uintptr_t *add
     return 0;
 }
 
+int getSymbolInMaps(library_t *lib, const char* name, int noweak, uintptr_t *addr, uintptr_t *size, int version, const char* vername, int local)
+{
+    if(!lib->active)
+        return 0;
+    // check in datamaps (but no version, it's not handled there)
+    if(getSymbolInDataMaps(lib, name, noweak, addr, size))
+        return 1;
+
+    if(getSymbolInSymbolMaps(lib, VersionnedName(name, version, vername), noweak, addr, size))
+        return 1;
+
+    if(getSymbolInSymbolMaps(lib, name, noweak, addr, size))
+        return 1;
+
+    return 0;
+}
+
 int GetNeededLibN(library_t* lib) {
     return lib->needed.size;
 }
diff --git a/src/librarian/library_private.h b/src/librarian/library_private.h
index 7e8aa4d4..606e47f8 100755
--- a/src/librarian/library_private.h
+++ b/src/librarian/library_private.h
@@ -97,6 +97,6 @@ typedef struct map_onedata_s {
     int         weak;
 } map_onedata_t;
 
-int getSymbolInMaps(library_t *lib, const char* name, int noweak, uintptr_t *addr, uintptr_t *size);  // Add bridges to functions
+int getSymbolInMaps(library_t *lib, const char* name, int noweak, uintptr_t *addr, uintptr_t *size, int version, const char* vername, int local);  // Add bridges to functions
 
 #endif //__LIBRARY_PRIVATE_H_
diff --git a/src/librarian/symbols.c b/src/librarian/symbols.c
new file mode 100644
index 00000000..adf6020a
--- /dev/null
+++ b/src/librarian/symbols.c
@@ -0,0 +1,233 @@
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <pthread.h>
+
+#include "debug.h"
+#include "x64emu.h"
+#include "box64context.h"
+#include "symbols.h"
+#include "dictionnary.h"
+
+typedef struct onesymbol_s {
+    uintptr_t   offs;
+    uint32_t    sz;
+    // need to track type of symbol?
+    // need to track origin?
+} onesymbol_t;
+
+typedef struct versymbol_s {
+    int         version;    // -1 = no-version, 0=local, 1=global, X=versionned
+    const char* vername;    // NULL or version name if version=X
+    onesymbol_t sym;
+} versymbol_t;
+
+typedef struct versymbols_s {
+    int sz;
+    int cap;
+    versymbol_t *syms;
+} versymbols_t;
+
+KHASH_MAP_IMPL_STR(mapsymbols, versymbols_t);
+
+kh_mapsymbols_t* NewMapSymbols()
+{
+    kh_mapsymbols_t* map = kh_init(mapsymbols);
+    return map;
+}
+
+void FreeMapSymbols(kh_mapsymbols_t** map)
+{
+    if(!map || !(*map))
+        return;
+    versymbols_t *v;
+    kh_foreach_value_ref(*map, v, free(v->syms););
+
+    kh_destroy(mapsymbols, *map);
+    *map = NULL;
+}
+
+// Exact same version (ver<2 or vername if ver>=2)
+static int SameVersion(versymbol_t* s, int ver, const char* vername)
+{
+    if(ver<2)
+        return (s->version == ver)?1:0;
+    if(s->vername && !strcmp(s->vername, vername))
+        return 1;
+    return 0;
+    
+}
+
+static versymbol_t* FindVersionLocal(versymbols_t* s)
+{
+    if(!s || !s->sz)
+        return NULL;
+    for (int i=0; i<s->sz; ++i)
+        if(s->syms[i].version==0)
+            return &s->syms[i];
+    return NULL;
+}
+static versymbol_t* FindNoVersion(versymbols_t* s)
+{
+    if(!s || !s->sz)
+        return NULL;
+    for (int i=0; i<s->sz; ++i)
+        if(s->syms[i].version==-1)
+            return &s->syms[i];
+    return NULL;
+}
+static versymbol_t* FindVersionGlobal(versymbols_t* s)
+{
+    if(!s || !s->sz)
+        return NULL;
+    for (int i=0; i<s->sz; ++i)
+        if(s->syms[i].version==1)
+            return &s->syms[i];
+    return NULL;
+}
+static versymbol_t* FindVersion(versymbols_t* s, const char* vername)
+{
+    if(!s || !s->sz)
+        return NULL;
+    for (int i=0; i<s->sz; ++i)
+        if(s->syms[i].vername && !strcmp(s->syms[i].vername, vername))
+            return &s->syms[i];
+    return NULL;
+}
+static versymbol_t* FindFirstVersion(versymbols_t* s)
+{
+    if(!s || !s->sz)
+        return NULL;
+    for (int i=0; i<s->sz; ++i)
+        if(s->syms[i].version>1)
+            return &s->syms[i];
+    return NULL;
+}
+
+// Match version (so ver=0:0, ver=1:-1/1/X, ver=-1:any, ver=X:1/"name")
+static versymbol_t* MatchVersion(versymbols_t* s, int ver, const char* vername, int local)
+{
+    if(!s || !s->sz)
+        return NULL;
+    versymbol_t* ret = NULL;
+    if(ver==0) {
+        if(local) ret = FindVersionLocal(s);
+        if(!ret) ret = FindNoVersion(s);
+        if(!ret) ret = FindVersionGlobal(s);
+        return ret;
+    }
+    if(ver==-1) {
+        if(local) ret = FindVersionLocal(s);
+        if(!ret) ret = FindNoVersion(s);
+        if(!ret) ret = FindVersionGlobal(s);
+        if(!ret) ret = FindFirstVersion(s);
+        return ret;
+    }
+    if(ver==1) {
+        if(local) ret = FindVersionLocal(s);
+        if(!ret) ret = FindVersionGlobal(s);
+        if(!ret) ret = FindNoVersion(s);
+        if(!ret) ret = FindFirstVersion(s);
+        return ret;
+    }
+    ret = FindVersion(s, vername);
+    if(local && !ret) FindVersionLocal(s);
+    if(!ret) return FindVersionGlobal(s);
+    return ret;
+}
+
+void AddSymbol(kh_mapsymbols_t *mapsymbols, const char* name, uintptr_t addr, uint32_t sz, int ver, const char* vername)
+{
+    int ret;
+    khint_t k = kh_put(mapsymbols, mapsymbols, name, &ret);
+    versymbols_t * v = &kh_val(mapsymbols, k);
+    if(ret) {v->sz = v->cap = 0; v->syms = NULL;}
+    // now check if that version already exist, and update record and exit if yes
+    for(int i=0; i<v->sz; ++i)
+        if(SameVersion(&v->syms[i], ver, vername)) {
+            v->syms[i].sym.offs = addr;
+            v->syms[i].sym.sz = sz;
+            return;
+        }
+    // add a new record
+    if(v->sz == v->cap) {
+        v->cap+=4;
+        v->syms = (versymbol_t*)realloc(v->syms, v->cap*sizeof(versymbol_t));
+    }
+    int idx = v->sz++;
+    v->syms[idx].version = ver;
+    v->syms[idx].vername = vername;
+    v->syms[idx].sym.offs = addr;
+    v->syms[idx].sym.sz = sz;
+}
+
+uintptr_t FindSymbol(kh_mapsymbols_t *mapsymbols, const char* name, int ver, const char* vername, int local)
+{
+    if(!mapsymbols)
+        return 0;
+    khint_t k = kh_get(mapsymbols, mapsymbols, name);
+    if(k==kh_end(mapsymbols))
+        return 0;
+    versymbols_t * v = &kh_val(mapsymbols, k);
+    versymbol_t * s = MatchVersion(v, ver, vername, local);
+    if(s)
+        return s->sym.offs;
+    return 0;
+}
+
+void AddWeakSymbol(kh_mapsymbols_t *mapsymbols, const char* name, uintptr_t addr, uint32_t sz, int ver, const char* vername)
+{
+    int ret;
+    khint_t k = kh_put(mapsymbols, mapsymbols, name, &ret);
+    versymbols_t * v = &kh_val(mapsymbols, k);
+    if(ret) {v->sz = v->cap = 0; v->syms = NULL;}
+    // now check if that version already exist, and exit if yes
+    for(int i=0; i<v->sz; ++i)
+        if(SameVersion(&v->syms[i], ver, vername)) {
+            return;
+        }
+    // add a new record
+    if(v->sz == v->cap) {
+        v->cap+=4;
+        v->syms = (versymbol_t*)realloc(v->syms, v->cap*sizeof(versymbol_t));
+    }
+    int idx = v->sz++;
+    v->syms[idx].version = ver;
+    v->syms[idx].vername = vername;
+    v->syms[idx].sym.offs = addr;
+    v->syms[idx].sym.sz = sz;
+}
+
+int GetSymbolStartEnd(kh_mapsymbols_t* mapsymbols, const char* name, uintptr_t* start, uintptr_t* end, int ver, const char* vername, int local)
+{
+    if(!mapsymbols)
+        return 0;
+    khint_t k = kh_get(mapsymbols, mapsymbols, name);
+    if(k==kh_end(mapsymbols))
+        return 0;
+    versymbols_t * v = &kh_val(mapsymbols, k);
+    versymbol_t* s = MatchVersion(v, ver, vername, local);
+    if(s) {
+        *start = s->sym.offs;
+        *end = *start + s->sym.sz;
+        return 1;
+    }
+    return 0;
+}
+
+const char* GetSymbolName(kh_mapsymbols_t* mapsymbols, void* p, uintptr_t* start, uint32_t* sz, const char** vername)
+{
+    uintptr_t addr = (uintptr_t)p;
+    versymbols_t *s;
+    kh_foreach_value_ref(mapsymbols, s, 
+        for(int i=0; i<s->sz; ++i)
+            if((s->syms[i].sym.offs >= addr) && (s->syms[i].sym.offs+s->syms[i].sym.sz<addr)) {
+                *start  = s->syms[i].sym.offs;
+                *sz = s->syms[i].sym.sz;
+                if(vername)
+                    *vername = s->syms[i].vername;
+                return kh_key(mapsymbols, __i);
+            }
+    );
+    return NULL;
+}
diff --git a/src/main.c b/src/main.c
index 623b9ba1..2ef08494 100755
--- a/src/main.c
+++ b/src/main.c
@@ -23,6 +23,7 @@
 #include "x64trace.h"
 #include "librarian.h"
 #include "x64run.h"
+#include "symbols.h"
 
 box64context_t *my_context = NULL;
 int box64_log = LOG_INFO; //LOG_NONE;
@@ -553,7 +554,7 @@ void setupTraceInit()
             if(s_trace_start || s_trace_end)
                 SetTraceEmu(s_trace_start, s_trace_end);
         } else {
-            if (GetSymbolStartEnd(GetMapSymbol(my_context->maplib), p, &s_trace_start, &s_trace_end)) {
+            if (GetSymbolStartEnd(GetMapSymbol(my_context->maplib), p, &s_trace_start, &s_trace_end, -1, NULL, -1)) {
                 SetTraceEmu(s_trace_start, s_trace_end);
                 printf_log(LOG_INFO, "TRACE on %s only (%p-%p)\n", p, (void*)s_trace_start, (void*)s_trace_end);
             } else {
@@ -594,10 +595,10 @@ void setupTrace()
                 }
             }
         } else {
-            if (GetGlobalSymbolStartEnd(my_context->maplib, p, &s_trace_start, &s_trace_end)) {
+            if (GetGlobalSymbolStartEnd(my_context->maplib, p, &s_trace_start, &s_trace_end, NULL, -1, NULL)) {
                 SetTraceEmu(s_trace_start, s_trace_end);
                 printf_log(LOG_INFO, "TRACE on %s only (%p-%p)\n", p, (void*)s_trace_start, (void*)s_trace_end);
-            } else if(GetLocalSymbolStartEnd(my_context->maplib, p, &s_trace_start, &s_trace_end, NULL)) {
+            } else if(GetLocalSymbolStartEnd(my_context->maplib, p, &s_trace_start, &s_trace_end, NULL, -1, NULL)) {
                 SetTraceEmu(s_trace_start, s_trace_end);
                 printf_log(LOG_INFO, "TRACE on %s only (%p-%p)\n", p, (void*)s_trace_start, (void*)s_trace_end);
             } else {
@@ -987,9 +988,9 @@ int main(int argc, const char **argv, const char **env) {
     // export symbols
     AddSymbols(my_context->maplib, GetMapSymbol(my_context->maplib), GetWeakSymbol(my_context->maplib), GetLocalSymbol(my_context->maplib), elf_header);
     if(wine_preloaded) {
-        uintptr_t wineinfo = FindSymbol(GetMapSymbol(my_context->maplib), "wine_main_preload_info");
-        if(!wineinfo) wineinfo = FindSymbol(GetWeakSymbol(my_context->maplib), "wine_main_preload_info");
-        if(!wineinfo) wineinfo = FindSymbol(GetLocalSymbol(my_context->maplib), "wine_main_preload_info");
+        uintptr_t wineinfo = FindSymbol(GetMapSymbol(my_context->maplib), "wine_main_preload_info", -1, NULL, 1);
+        if(!wineinfo) wineinfo = FindSymbol(GetWeakSymbol(my_context->maplib), "wine_main_preload_info", -1, NULL, 1);
+        if(!wineinfo) wineinfo = FindSymbol(GetLocalSymbol(my_context->maplib), "wine_main_preload_info", -1, NULL, 1);
         if(!wineinfo) {printf_log(LOG_NONE, "Warning, Symbol wine_main_preload_info not found\n");}
         else {
             *(void**)wineinfo = get_wine_prereserve();
@@ -1001,11 +1002,8 @@ int main(int argc, const char **argv, const char **env) {
     }
     // pre-load lib if needed
     if(ld_preload.size) {
-        for (int i=0; i<ld_preload.size; ++i) {
-            if(AddNeededLib(NULL, NULL, NULL, 0, ld_preload.paths[i], my_context, emu)) {
-                if(!strstr(ld_preload.paths[i], "vgpreload_"))
-                    printf_log(LOG_INFO, "Warning, cannot pre-load lib: \"%s\"\n", ld_preload.paths[i]);
-            }            
+        if(AddNeededLib(NULL, NULL, NULL, 0, (const char**)ld_preload.paths, ld_preload.size, my_context, emu)) {
+            printf_log(LOG_INFO, "Warning, cannot pre-load a lib\n");
         }
     }
     FreeCollection(&ld_preload);
diff --git a/src/wrapped/wrappedlib_init.h b/src/wrapped/wrappedlib_init.h
index a3a2049c..d991f8a2 100755
--- a/src/wrapped/wrappedlib_init.h
+++ b/src/wrapped/wrappedlib_init.h
@@ -130,21 +130,29 @@ int FUNC(_init)(library_t* lib, box64context_t* box64)
     for (int i=0; i<cnt; ++i) {
         k = kh_put(symbolmap, lib->symbolmap, MAPNAME(symbolmap)[i].name, &ret);
         kh_value(lib->symbolmap, k) = MAPNAME(symbolmap)[i].w;
+        if(strchr(MAPNAME(symbolmap)[i].name, '@'))
+            AddDictionnary(box64->versym, MAPNAME(symbolmap)[i].name);
     }
     cnt = sizeof(MAPNAME(wsymbolmap))/sizeof(map_onesymbol_t);
     for (int i=0; i<cnt; ++i) {
         k = kh_put(symbolmap, lib->wsymbolmap, MAPNAME(wsymbolmap)[i].name, &ret);
         kh_value(lib->wsymbolmap, k) = MAPNAME(wsymbolmap)[i].w;
+        if(strchr(MAPNAME(wsymbolmap)[i].name, '@'))
+            AddDictionnary(box64->versym, MAPNAME(wsymbolmap)[i].name);
     }
     cnt = sizeof(MAPNAME(mysymbolmap))/sizeof(map_onesymbol_t);
     for (int i=0; i<cnt; ++i) {
         k = kh_put(symbolmap, lib->mysymbolmap, MAPNAME(mysymbolmap)[i].name, &ret);
         kh_value(lib->mysymbolmap, k) = MAPNAME(mysymbolmap)[i].w;
+        if(strchr(MAPNAME(mysymbolmap)[i].name, '@'))
+            AddDictionnary(box64->versym, MAPNAME(mysymbolmap)[i].name);
     }
     cnt = sizeof(MAPNAME(stsymbolmap))/sizeof(map_onesymbol_t);
     for (int i=0; i<cnt; ++i) {
         k = kh_put(symbolmap, lib->stsymbolmap, MAPNAME(stsymbolmap)[i].name, &ret);
         kh_value(lib->stsymbolmap, k) = MAPNAME(stsymbolmap)[i].w;
+        if(strchr(MAPNAME(stsymbolmap)[i].name, '@'))
+            AddDictionnary(box64->versym, MAPNAME(stsymbolmap)[i].name);
     }
     cnt = sizeof(MAPNAME(symbol2map))/sizeof(map_onesymbol2_t);
     for (int i=0; i<cnt; ++i) {
@@ -152,6 +160,8 @@ int FUNC(_init)(library_t* lib, box64context_t* box64)
         kh_value(lib->symbol2map, k).name = MAPNAME(symbol2map)[i].name2;
         kh_value(lib->symbol2map, k).w = MAPNAME(symbol2map)[i].w;
         kh_value(lib->symbol2map, k).weak = MAPNAME(symbol2map)[i].weak;
+        if(strchr(MAPNAME(symbol2map)[i].name, '@'))
+            AddDictionnary(box64->versym, MAPNAME(symbol2map)[i].name);
     }
     cnt = sizeof(MAPNAME(datamap))/sizeof(map_onedata_t);
     for (int i=0; i<cnt; ++i) {
@@ -194,7 +204,7 @@ int FUNC(_fini)(library_t* lib)
     return 1;
 }
 
-int FUNC(_get)(library_t* lib, const char* name, uintptr_t *offs, uintptr_t *sz)
+int FUNC(_get)(library_t* lib, const char* name, uintptr_t *offs, uintptr_t *sz, int version, const char* vername, int local)
 {
     uintptr_t addr = 0;
     uintptr_t size = 0;
@@ -202,7 +212,7 @@ int FUNC(_get)(library_t* lib, const char* name, uintptr_t *offs, uintptr_t *sz)
     void* symbol = NULL;
 #endif
 //PRE
-    if (!getSymbolInMaps(lib, name, 0, &addr, &size)) {
+    if (!getSymbolInMaps(lib, name, 0, &addr, &size, version, vername, local)) {
 #ifdef CUSTOM_FAIL
     CUSTOM_FAIL
 #else
@@ -217,7 +227,7 @@ int FUNC(_get)(library_t* lib, const char* name, uintptr_t *offs, uintptr_t *sz)
     return 1;
 }
 
-int FUNC(_getnoweak)(library_t* lib, const char* name, uintptr_t *offs, uintptr_t *sz)
+int FUNC(_getnoweak)(library_t* lib, const char* name, uintptr_t *offs, uintptr_t *sz, int version, const char* vername, int local)
 {
     uintptr_t addr = 0;
     uintptr_t size = 0;
@@ -225,7 +235,7 @@ int FUNC(_getnoweak)(library_t* lib, const char* name, uintptr_t *offs, uintptr_
     void* symbol = NULL;
 #endif
 //PRE
-    if (!getSymbolInMaps(lib, name, 1, &addr, &size)) {
+    if (!getSymbolInMaps(lib, name, 1, &addr, &size, version, vername, local)) {
 #ifdef CUSTOM_FAIL
     CUSTOM_FAIL
 #else
diff --git a/src/wrapped/wrappedlibdl.c b/src/wrapped/wrappedlibdl.c
index 0d9aa8cb..5655616c 100755
--- a/src/wrapped/wrappedlibdl.c
+++ b/src/wrapped/wrappedlibdl.c
@@ -42,7 +42,7 @@ char* my_dlerror(x64emu_t* emu) EXPORT;
 void* my_dlsym(x64emu_t* emu, void *handle, void *symbol) EXPORT;
 int my_dlclose(x64emu_t* emu, void *handle) EXPORT;
 int my_dladdr(x64emu_t* emu, void *addr, void *info) EXPORT;
-void* my_dlvsym(x64emu_t* emu, void *handle, void *symbol, void *version) EXPORT;
+void* my_dlvsym(x64emu_t* emu, void *handle, void *symbol, const char *vername) EXPORT;
 int my_dlinfo(x64emu_t* emu, void* handle, int request, void* info) EXPORT;
 
 #define LIBNAME libdl
@@ -97,7 +97,8 @@ void* my_dlopen(x64emu_t* emu, void *filename, int flag)
         }
         dlopened = (GetLibInternal(rfilename)==NULL);
         // Then open the lib
-        if(AddNeededLib(NULL, NULL, NULL, is_local, rfilename, emu->context, emu)) {
+        const char* libs[] = {rfilename};
+        if(AddNeededLib(NULL, NULL, NULL, is_local, libs, 1, emu->context, emu)) {
             printf_log(LOG_INFO, "Warning: Cannot dlopen(\"%s\"/%p, %X)\n", rfilename, filename, flag);
             if(!dl->last_error)
                 dl->last_error = malloc(129);
@@ -152,7 +153,7 @@ char* my_dlerror(x64emu_t* emu)
 
 KHASH_SET_INIT_INT(libs);
 
-int recursive_dlsym_lib(kh_libs_t* collection, library_t* lib, const char* rsymbol, uintptr_t *start, uintptr_t *end)
+int recursive_dlsym_lib(kh_libs_t* collection, library_t* lib, const char* rsymbol, uintptr_t *start, uintptr_t *end, int version, const char* vername)
 {
     if(!lib)
         return 0;
@@ -162,23 +163,23 @@ int recursive_dlsym_lib(kh_libs_t* collection, library_t* lib, const char* rsymb
     int ret;
     kh_put(libs, collection, (uintptr_t)lib, &ret);
     // look in the library itself
-    if(lib->get(lib, rsymbol, start, end))
+    if(lib->get(lib, rsymbol, start, end, version, vername, 1))
         return 1;
     // look in other libs
     int n = GetNeededLibN(lib);
     for (int i=0; i<n; ++i) {
         library_t *l = GetNeededLib(lib, i);
-        if(recursive_dlsym_lib(collection, l, rsymbol, start, end))
+        if(recursive_dlsym_lib(collection, l, rsymbol, start, end, version, vername))
             return 1;
     }
         
     return 0;
 }
 
-int my_dlsym_lib(library_t* lib, const char* rsymbol, uintptr_t *start, uintptr_t *end)
+int my_dlsym_lib(library_t* lib, const char* rsymbol, uintptr_t *start, uintptr_t *end, int version, const char* vername)
 {
     kh_libs_t *collection = kh_init(libs);
-    int ret = recursive_dlsym_lib(collection, lib, rsymbol, start, end);
+    int ret = recursive_dlsym_lib(collection, lib, rsymbol, start, end, version, vername);
     kh_destroy(libs, collection);
 
     return ret;
@@ -196,7 +197,7 @@ void* my_dlsym(x64emu_t* emu, void *handle, void *symbol)
     printf_log(LOG_DEBUG, "Call to dlsym(%p, \"%s\")\n", handle, rsymbol);
     if(handle==NULL) {
         // special case, look globably
-        if(GetGlobalSymbolStartEnd(emu->context->maplib, rsymbol, &start, &end)) {
+        if(GetGlobalSymbolStartEnd(emu->context->maplib, rsymbol, &start, &end, NULL, -1, NULL)) {
             if(dlsym_error && box64_log<LOG_DEBUG) {
                 printf_log(LOG_NONE, "%p\n", (void*)start);
             }
@@ -212,8 +213,8 @@ void* my_dlsym(x64emu_t* emu, void *handle, void *symbol)
     }
     if(handle==(void*)0xFFFFFFFF) {
         // special case, look globably but no self (RTLD_NEXT)
-        elfheader_t *elf = FindElfAddress(emu->context, *(uint32_t*)R_RSP); // use return address to guess "self"
-        if(GetNoSelfSymbolStartEnd(emu->context->maplib, rsymbol, &start, &end, elf)) {
+        elfheader_t *elf = FindElfAddress(emu->context, *(uintptr_t*)R_RSP); // use return address to guess "self"
+        if(GetNoSelfSymbolStartEnd(emu->context->maplib, rsymbol, &start, &end, elf, -1, NULL)) {
             if(dlsym_error && box64_log<LOG_DEBUG) {
                 printf_log(LOG_NONE, "%p\n", (void*)start);
             }
@@ -249,7 +250,7 @@ void* my_dlsym(x64emu_t* emu, void *handle, void *symbol)
         return NULL;
     }
     if(dl->libs[nlib]) {
-        if(my_dlsym_lib(dl->libs[nlib], rsymbol, &start, &end)==0) {
+        if(my_dlsym_lib(dl->libs[nlib], rsymbol, &start, &end, -1, NULL)==0) {
             // not found
             if(dlsym_error && box64_log<LOG_DEBUG) {
                 printf_log(LOG_NONE, "%p\nCall to dlsym(%s, \"%s\") Symbol not found\n", NULL, GetNameLib(dl->libs[nlib]), rsymbol);
@@ -262,19 +263,19 @@ void* my_dlsym(x64emu_t* emu, void *handle, void *symbol)
         }
     } else {
         // still usefull?
-        if(GetSymbolStartEnd(GetLocalSymbol(emu->context->maplib), rsymbol, &start, &end)) {
+        if(GetSymbolStartEnd(GetLocalSymbol(emu->context->maplib), rsymbol, &start, &end, -1, NULL, 0)) {
             if(dlsym_error && box64_log<LOG_DEBUG) {
                 printf_log(LOG_NONE, "%p\n", (void*)start);
             }
             return (void*)start;
         }
-        if(GetSymbolStartEnd(GetWeakSymbol(emu->context->maplib), rsymbol, &start, &end)) {
+        if(GetSymbolStartEnd(GetWeakSymbol(emu->context->maplib), rsymbol, &start, &end, -1, NULL, 0)) {
             if(dlsym_error && box64_log<LOG_DEBUG) {
                 printf_log(LOG_NONE, "%p\n", (void*)start);
             }
             return (void*)start;
         }
-        if(GetSymbolStartEnd(GetMapSymbol(emu->context->maplib), rsymbol, &start, &end)) {
+        if(GetSymbolStartEnd(GetMapSymbol(emu->context->maplib), rsymbol, &start, &end, -1, NULL, 0)) {
             if(dlsym_error && box64_log<LOG_DEBUG) {
                 printf_log(LOG_NONE, "%p\n", (void*)start);
             }
@@ -352,16 +353,117 @@ int my_dladdr(x64emu_t* emu, void *addr, void *i)
     printf_log(LOG_DEBUG, "     dladdr return saddr=%p, fname=\"%s\", sname=\"%s\"\n", info->dli_saddr, info->dli_sname?info->dli_sname:"", info->dli_fname?info->dli_fname:"");
     return (info->dli_sname)?1:0;   // success is non-null here...
 }
-void* my_dlvsym(x64emu_t* emu, void *handle, void *symbol, void *version)
+void* my_dlvsym(x64emu_t* emu, void *handle, void *symbol, const char *vername)
 {
     dlprivate_t *dl = emu->context->dlprivate;
-    CLEARERR
-    //void *dlvsym(void *handle, char *symbol, char *version);
+    int version = (vername)?2:-1;
+    uintptr_t start, end;
     char* rsymbol = (char*)symbol;
-    char* rversion = (char*)version;
-    printf_log(LOG_INFO, "Warning: unimplement call to dlvsym(%p, %s, %s), fallback to dlsym\n", handle, rsymbol, rversion);
-
-    return my_dlsym(emu, handle, symbol);
+    CLEARERR
+    if(dlsym_error && box64_log<LOG_DEBUG) {
+        printf_log(LOG_NONE, "Call to dlvsym(%p, %s, %s) :", handle, rsymbol, vername?vername:"(nil)");
+    }
+    printf_log(LOG_DEBUG, "Call to dlvsym(%p, \"%s\", %s)\n", handle, rsymbol, vername?vername:"(nil)");
+    if(handle==NULL) {
+        // special case, look globably
+        if(GetGlobalSymbolStartEnd(emu->context->maplib, rsymbol, &start, &end, NULL, version, vername)) {
+            if(dlsym_error && box64_log<LOG_DEBUG) {
+                printf_log(LOG_NONE, "%p\n", (void*)start);
+            }
+            return (void*)start;
+        }
+        if(!dl->last_error)
+            dl->last_error = malloc(129);
+        snprintf(dl->last_error, 129, "Symbol \"%s\" version %s not found in %p)\n", rsymbol, vername?vername:"(nil)", handle);
+        if(dlsym_error && box64_log<LOG_DEBUG) {
+            printf_log(LOG_NONE, "%p\n", NULL);
+        }
+        return NULL;
+    }
+    if(handle==(void*)0xFFFFFFFF) {
+        // special case, look globably but no self (RTLD_NEXT)
+        elfheader_t *elf = FindElfAddress(emu->context, *(uintptr_t*)R_RSP); // use return address to guess "self"
+        if(GetNoSelfSymbolStartEnd(emu->context->maplib, rsymbol, &start, &end, elf, version, vername)) {
+            if(dlsym_error && box64_log<LOG_DEBUG) {
+                printf_log(LOG_NONE, "%p\n", (void*)start);
+            }
+            return (void*)start;
+        }
+        if(!dl->last_error)
+            dl->last_error = malloc(129);
+        snprintf(dl->last_error, 129, "Symbol \"%s\" version %s not found in %p)\n", rsymbol, vername?vername:"(nil)", handle);
+        if(dlsym_error && box64_log<LOG_DEBUG) {
+            printf_log(LOG_NONE, "%p\n", NULL);
+        }
+        return NULL;
+    }
+    size_t nlib = (size_t)handle;
+    --nlib;
+    // size_t is unsigned
+    if(nlib>=dl->lib_sz) {
+        if(!dl->last_error)
+            dl->last_error = malloc(129);
+        snprintf(dl->last_error, 129, "Bad handle %p)\n", handle);
+        if(dlsym_error && box64_log<LOG_DEBUG) {
+            printf_log(LOG_NONE, "%p\n", NULL);
+        }
+        return NULL;
+    }
+    if(dl->count[nlib]==0) {
+        if(!dl->last_error)
+            dl->last_error = malloc(129);
+        snprintf(dl->last_error, 129, "Bad handle %p (already closed))\n", handle);
+        if(dlsym_error && box64_log<LOG_DEBUG) {
+            printf_log(LOG_NONE, "%p\n", (void*)NULL);
+        }
+        return NULL;
+    }
+    if(dl->libs[nlib]) {
+        if(my_dlsym_lib(dl->libs[nlib], rsymbol, &start, &end, version, vername)==0) {
+            // not found
+            if(dlsym_error && box64_log<LOG_DEBUG) {
+                printf_log(LOG_NONE, "%p\nCall to dlvsym(%s, \"%s\", %s) Symbol not found\n", NULL, GetNameLib(dl->libs[nlib]), rsymbol, vername?vername:"(nil)");
+            }
+            printf_log(LOG_DEBUG, " Symbol not found\n");
+            if(!dl->last_error)
+                dl->last_error = malloc(129);
+            snprintf(dl->last_error, 129, "Symbol \"%s\" not found in %p(%s)", rsymbol, handle, GetNameLib(dl->libs[nlib]));
+            return NULL;
+        }
+    } else {
+        // still usefull?
+        if(GetSymbolStartEnd(GetLocalSymbol(emu->context->maplib), rsymbol, &start, &end, version, vername, 1)) {
+            if(dlsym_error && box64_log<LOG_DEBUG) {
+                printf_log(LOG_NONE, "%p\n", (void*)start);
+            }
+            return (void*)start;
+        }
+        if(GetSymbolStartEnd(GetWeakSymbol(emu->context->maplib), rsymbol, &start, &end, version, vername, 1)) {
+            if(dlsym_error && box64_log<LOG_DEBUG) {
+                printf_log(LOG_NONE, "%p\n", (void*)start);
+            }
+            return (void*)start;
+        }
+        if(GetSymbolStartEnd(GetMapSymbol(emu->context->maplib), rsymbol, &start, &end, version, vername, 1)) {
+            if(dlsym_error && box64_log<LOG_DEBUG) {
+                printf_log(LOG_NONE, "%p\n", (void*)start);
+            }
+            return (void*)start;
+        }
+        // not found
+        if(dlsym_error && box64_log<LOG_DEBUG) {
+            printf_log(LOG_NONE, "%p\nCall to dlvsym(%s, \"%s\", %s) Symbol not found\n", NULL, "Self", rsymbol, vername?vername:"(nil)");
+        }
+        printf_log(LOG_DEBUG, " Symbol not found\n");
+        if(!dl->last_error)
+            dl->last_error = malloc(129);
+        snprintf(dl->last_error, 129, "Symbol \"%s\" version %s not found in %p)\n", rsymbol, vername?vername:"(nil)", handle);
+        return NULL;
+    }
+    if(dlsym_error && box64_log<LOG_DEBUG) {
+        printf_log(LOG_NONE, "%p\n", (void*)start);
+    }
+    return (void*)start;
 }
 
 typedef struct link_map_s {