about summary refs log tree commit diff stats
path: root/src
diff options
context:
space:
mode:
authorptitSeb <sebastien.chev@gmail.com>2022-01-05 11:21:33 +0100
committerptitSeb <sebastien.chev@gmail.com>2022-01-05 11:21:33 +0100
commit42b18c57ce5a10b45dc644c75ff7580c88f7fc56 (patch)
tree367c781c07955d10cc6d9ba276e9b5d2c1f9a8c3 /src
parentdd0f7c1d5c5a7cf084e7ecc6aa54c758e7a79995 (diff)
downloadbox64-42b18c57ce5a10b45dc644c75ff7580c88f7fc56.tar.gz
box64-42b18c57ce5a10b45dc644c75ff7580c88f7fc56.zip
Added a Workaround when dlsym a native (versionned) symbol without default version fails
Diffstat (limited to 'src')
-rwxr-xr-xsrc/elfs/elfloader.c65
-rwxr-xr-xsrc/include/elfloader.h2
-rwxr-xr-xsrc/librarian/library.c18
3 files changed, 85 insertions, 0 deletions
diff --git a/src/elfs/elfloader.c b/src/elfs/elfloader.c
index d688d0a8..0927ab3c 100755
--- a/src/elfs/elfloader.c
+++ b/src/elfs/elfloader.c
@@ -1539,6 +1539,71 @@ void ElfAttachLib(elfheader_t* head, library_t* lib)
     head->lib = lib;
 }
 
+typedef struct search_symbol_s{
+    const char* name;
+    void*       addr;
+    void*       lib;
+} search_symbol_t;
+int dl_iterate_phdr_findsymbol(struct dl_phdr_info* info, size_t size, void* data)
+{
+    search_symbol_t* s = (search_symbol_t*)data;
+
+    for(int j = 0; j<info->dlpi_phnum; ++j) {
+        if (info->dlpi_phdr[j].p_type == PT_DYNAMIC) {
+            ElfW(Sym)* sym = NULL;
+            ElfW(Word) sym_cnt = 0;
+            ElfW(Verdef)* verdef = NULL;
+            ElfW(Word) verdef_cnt = 0;
+            char *strtab = NULL;
+            ElfW(Dyn)* dyn = (ElfW(Dyn)*)(info->dlpi_addr +  info->dlpi_phdr[j].p_vaddr); //Dynamic Section
+            // grab the needed info
+            while(dyn->d_tag != DT_NULL) {
+                switch(dyn->d_tag) {
+                    case DT_STRTAB:
+                        strtab = (char *)(dyn->d_un.d_ptr);
+                        break;
+                    case DT_VERDEF:
+                        verdef = (ElfW(Verdef)*)(info->dlpi_addr +  dyn->d_un.d_ptr);
+                        break;
+                    case DT_VERDEFNUM:
+                        verdef_cnt = dyn->d_un.d_val;
+                        break;
+                }
+                ++dyn;
+            }
+            if(strtab && verdef && verdef_cnt) {
+                // Look fr all defined versions now
+                ElfW(Verdef)* v = verdef;
+                for(int k=0; k<verdef_cnt; ++k) {
+                    ElfW(Verdaux)* vda = (ElfW(Verdaux)*)(((uintptr_t)v) + v->vd_aux);
+                    for(int i=0; i<v->vd_cnt; ++i) {
+                        const char* vername = &strtab[vda->vda_name];
+                        if((s->addr = dlvsym(s->lib, s->name, vername))) {
+                            printf_log(LOG_DEBUG, "Found symbol with version %s, value = %p\n", vername, s->addr);
+                            return 1;   // stop searching
+                        }
+                        vda = (ElfW(Verdaux)*)(((uintptr_t)vda) + vda->vda_next);
+                    }
+                    v = (ElfW(Verdef)*)((uintptr_t)v + v->vd_next);
+                }
+            }
+        }
+    }
+    return 0;
+}
+
+void* GetNativeSymbolUnversionned(void* lib, const char* name)
+{
+    // try to find "name" in loaded elf, whithout checking for the symbol version (like dlsym, but no version check)
+    search_symbol_t s;
+    s.name = name;
+    s.addr = NULL;
+    s.lib = lib;
+    printf_log(LOG_INFO, "Look for %s in loaded elfs\n", name);
+    dl_iterate_phdr(dl_iterate_phdr_findsymbol, &s);
+    return s.addr;
+}
+
 uintptr_t pltResolver = ~0LL;
 EXPORT void PltResolver(x64emu_t* emu)
 {
diff --git a/src/include/elfloader.h b/src/include/elfloader.h
index afef7981..c1b4ce89 100755
--- a/src/include/elfloader.h
+++ b/src/include/elfloader.h
@@ -60,4 +60,6 @@ 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);
 
+void* GetNativeSymbolUnversionned(void* lib, const char* name);
+
 #endif //__ELF_LOADER_H_
diff --git a/src/librarian/library.c b/src/librarian/library.c
index 86638591..647d014c 100755
--- a/src/librarian/library.c
+++ b/src/librarian/library.c
@@ -704,6 +704,14 @@ static int getSymbolInSymbolMaps(library_t*lib, const char* name, int noweak, ui
             strcat(newname, name);
             symbol = dlsym(lib->priv.w.lib, newname);
         }
+        if(!symbol)
+            symbol = GetNativeSymbolUnversionned(lib->priv.w.lib, name);
+        if(!symbol && lib->priv.w.altprefix) {
+            char newname[200];
+            strcpy(newname, lib->priv.w.altprefix);
+            strcat(newname, name);
+            symbol = GetNativeSymbolUnversionned(lib->priv.w.lib, newname);
+        }
         if(!symbol) {
             printf_log(LOG_INFO, "Warning, function %s not found in lib %s\n", name, lib->name);
             return 0;
@@ -741,6 +749,14 @@ static int getSymbolInSymbolMaps(library_t*lib, const char* name, int noweak, ui
                 strcat(newname, name);
                 symbol = dlsym(lib->priv.w.lib, newname);
             }
+            if(!symbol)
+                symbol = GetNativeSymbolUnversionned(lib->priv.w.lib, name);
+            if(!symbol && lib->priv.w.altprefix) {
+                char newname[200];
+                strcpy(newname, lib->priv.w.altprefix);
+                strcat(newname, name);
+                symbol = GetNativeSymbolUnversionned(lib->priv.w.lib, newname);
+            }
             if(!symbol) {
                 printf_log(LOG_INFO, "Warning, function %s not found in lib %s\n", name, lib->name);
                 return 0;
@@ -759,6 +775,8 @@ static int getSymbolInSymbolMaps(library_t*lib, const char* name, int noweak, ui
             symbol = dlsym(lib->priv.w.lib, kh_value(lib->symbol2map, k).name);
             if(!symbol)
                 symbol = dlsym(RTLD_DEFAULT, kh_value(lib->symbol2map, k).name);    // search globaly maybe
+            if(!symbol)
+                symbol = GetNativeSymbolUnversionned(lib->priv.w.lib, kh_value(lib->symbol2map, k).name);
             if(!symbol) {
                 printf_log(LOG_INFO, "Warning, function %s not found in lib %s\n", kh_value(lib->symbol2map, k).name, lib->name);
                 return 0;