about summary refs log tree commit diff stats
path: root/src/elfs
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/elfs
parent55720342adbf22ba318a66b30ed9ea6ec789b032 (diff)
downloadbox64-f8a969d43ed26e64d21238ead0e9512360fb1fdd.tar.gz
box64-f8a969d43ed26e64d21238ead0e9512360fb1fdd.zip
Reworked elfloader, handle versionned symbols now
Diffstat (limited to 'src/elfs')
-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
4 files changed, 296 insertions, 133 deletions
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;
+}