diff --git a/src/elfs/elfloader.c b/src/elfs/elfloader.c index 6e042a9da..70906e5a2 100644 --- a/src/elfs/elfloader.c +++ b/src/elfs/elfloader.c @@ -1138,6 +1138,81 @@ $PLATFORM – Expands to the processor type of the current machine (see the uname(1) man page description of the -i option). For more details of this token expansion, see “System Specific Shared Objects” */ +char* ExpandNeededLibs(elfheader_t* h, char* rpath) +{ + if(!rpath || !h) return rpath; + char* rpathref = rpath; + while(strstr(rpath, "$$ORIGIN")) { + char* origin = box_strdup(h->path); + char* p = strrchr(origin, '/'); + if(p) *p = '\0'; // remove file name to have only full path, without last '/' + char* tmp = (char*)box_calloc(1, strlen(rpath)-strlen("$$ORIGIN")+strlen(origin)+1); + p = strstr(rpath, "$$ORIGIN"); + memcpy(tmp, rpath, p-rpath); + strcat(tmp, origin); + strcat(tmp, p+strlen("$$ORIGIN")); + if(rpath!=rpathref) + box_free(rpath); + rpath = tmp; + box_free(origin); + } + while(strstr(rpath, "$ORIGIN")) { + char* origin = box_strdup(h->path); + char* p = strrchr(origin, '/'); + if(p) *p = '\0'; // remove file name to have only full path, without last '/' + char* tmp = (char*)box_calloc(1, strlen(rpath)-strlen("$ORIGIN")+strlen(origin)+1); + p = strstr(rpath, "$ORIGIN"); + memcpy(tmp, rpath, p-rpath); + strcat(tmp, origin); + strcat(tmp, p+strlen("$ORIGIN")); + if(rpath!=rpathref) + box_free(rpath); + rpath = tmp; + box_free(origin); + } + while(strstr(rpath, "${ORIGIN}")) { + char* origin = box_strdup(h->path); + char* p = strrchr(origin, '/'); + if(p) *p = '\0'; // remove file name to have only full path, without last '/' + char* tmp = (char*)box_calloc(1, strlen(rpath)-strlen("${ORIGIN}")+strlen(origin)+1); + p = strstr(rpath, "${ORIGIN}"); + memcpy(tmp, rpath, p-rpath); + strcat(tmp, origin); + strcat(tmp, p+strlen("${ORIGIN}")); + if(rpath!=rpathref) + box_free(rpath); + rpath = tmp; + box_free(origin); + if(!FileExist(rpath, 0) && strstr(rpath, "/../../")) { + tmp = (char*)box_calloc(1, strlen(rpath)+1); + strcpy(tmp, rpath); + // check if one "/.." could be removed for the folder to exist + char* p = strstr(tmp, "/../../"); + memmove(p, p+3, strlen(p+3)+1); + if(FileExist(tmp, 0)) { + if(rpath!=rpathref) + box_free(rpath); + rpath = tmp; + } else + box_free(tmp); + } + } + while(strstr(rpath, "${PLATFORM}")) { + char* platform = box_strdup("x86_64"); + char* p = strrchr(platform, '/'); + if(p) *p = '\0'; // remove file name to have only full path, without last '/' + char* tmp = (char*)box_calloc(1, strlen(rpath)-strlen("${PLATFORM}")+strlen(platform)+1); + p = strstr(rpath, "${PLATFORM}"); + memcpy(tmp, rpath, p-rpath); + strcat(tmp, platform); + strcat(tmp, p+strlen("${PLATFORM}")); + if(rpath!=rpathref) + box_free(rpath); + rpath = tmp; + box_free(platform); + } + return rpath; +} int LoadNeededLibs(elfheader_t* h, lib_t *maplib, int local, int bindnow, int deepbind, box64context_t *box64, x64emu_t* emu) { if(h->needed) // already done @@ -1150,75 +1225,7 @@ int LoadNeededLibs(elfheader_t* h, lib_t *maplib, int local, int bindnow, int de if(tag==DT_RPATH || tag==DT_RUNPATH) { char *rpathref = h->DynStrTab+h->delta+(box64_is32bits?h->Dynamic._32[i].d_un.d_val:h->Dynamic._64[i].d_un.d_val); char* rpath = rpathref; - while(strstr(rpath, "$$ORIGIN")) { - char* origin = box_strdup(h->path); - char* p = strrchr(origin, '/'); - if(p) *p = '\0'; // remove file name to have only full path, without last '/' - char* tmp = (char*)box_calloc(1, strlen(rpath)-strlen("$$ORIGIN")+strlen(origin)+1); - p = strstr(rpath, "$$ORIGIN"); - memcpy(tmp, rpath, p-rpath); - strcat(tmp, origin); - strcat(tmp, p+strlen("$$ORIGIN")); - if(rpath!=rpathref) - box_free(rpath); - rpath = tmp; - box_free(origin); - } - while(strstr(rpath, "$ORIGIN")) { - char* origin = box_strdup(h->path); - char* p = strrchr(origin, '/'); - if(p) *p = '\0'; // remove file name to have only full path, without last '/' - char* tmp = (char*)box_calloc(1, strlen(rpath)-strlen("$ORIGIN")+strlen(origin)+1); - p = strstr(rpath, "$ORIGIN"); - memcpy(tmp, rpath, p-rpath); - strcat(tmp, origin); - strcat(tmp, p+strlen("$ORIGIN")); - if(rpath!=rpathref) - box_free(rpath); - rpath = tmp; - box_free(origin); - } - while(strstr(rpath, "${ORIGIN}")) { - char* origin = box_strdup(h->path); - char* p = strrchr(origin, '/'); - if(p) *p = '\0'; // remove file name to have only full path, without last '/' - char* tmp = (char*)box_calloc(1, strlen(rpath)-strlen("${ORIGIN}")+strlen(origin)+1); - p = strstr(rpath, "${ORIGIN}"); - memcpy(tmp, rpath, p-rpath); - strcat(tmp, origin); - strcat(tmp, p+strlen("${ORIGIN}")); - if(rpath!=rpathref) - box_free(rpath); - rpath = tmp; - box_free(origin); - if(!FileExist(rpath, 0) && strstr(rpath, "/../../")) { - tmp = (char*)box_calloc(1, strlen(rpath)+1); - strcpy(tmp, rpath); - // check if one "/.." could be removed for the folder to exist - char* p = strstr(tmp, "/../../"); - memmove(p, p+3, strlen(p+3)+1); - if(FileExist(tmp, 0)) { - if(rpath!=rpathref) - box_free(rpath); - rpath = tmp; - } else - box_free(tmp); - } - } - while(strstr(rpath, "${PLATFORM}")) { - char* platform = box_strdup("x86_64"); - char* p = strrchr(platform, '/'); - if(p) *p = '\0'; // remove file name to have only full path, without last '/' - char* tmp = (char*)box_calloc(1, strlen(rpath)-strlen("${PLATFORM}")+strlen(platform)+1); - p = strstr(rpath, "${PLATFORM}"); - memcpy(tmp, rpath, p-rpath); - strcat(tmp, platform); - strcat(tmp, p+strlen("${PLATFORM}")); - if(rpath!=rpathref) - box_free(rpath); - rpath = tmp; - box_free(platform); - } + rpath = ExpandNeededLibs(h, rpath); if(strchr(rpath, '$')) { printf_log(LOG_INFO, "Warning, RPATH with $ variable not supported yet (%s)\n", rpath); } else { @@ -1255,8 +1262,13 @@ int LoadNeededLibs(elfheader_t* h, lib_t *maplib, int local, int bindnow, int de my_context->neededlibs = h->needed; int j=0; for (size_t i=0; inumDynamic; ++i) - if((box64_is32bits?h->Dynamic._32[i].d_tag:h->Dynamic._64[i].d_tag)==DT_NEEDED) - h->needed->names[j++] = h->DynStrTab+h->delta+(box64_is32bits?h->Dynamic._32[i].d_un.d_val:h->Dynamic._64[i].d_un.d_val); + if((box64_is32bits?h->Dynamic._32[i].d_tag:h->Dynamic._64[i].d_tag)==DT_NEEDED) { + char* path = h->DynStrTab+h->delta+(box64_is32bits?h->Dynamic._32[i].d_un.d_val:h->Dynamic._64[i].d_un.d_val); + char* newpath = ExpandNeededLibs(h, path); + if(path!=newpath) + path = add1nsname(h->needed, newpath); + h->needed->names[j++] = path; + } #ifndef ANDROID if(box64_is32bits && strstr(h->name, "lsteamclient.dll.so")) h->needed->names[j++] = "libgcc_s.so.1"; diff --git a/src/include/box64context.h b/src/include/box64context.h index 6de8ae6e9..49c065904 100644 --- a/src/include/box64context.h +++ b/src/include/box64context.h @@ -79,6 +79,8 @@ typedef struct needed_libs_s { library_t** libs; path_collection_t* rpath; int nb_done; + char** nonstaticnames; + int ns_size; } needed_libs_t; void free_neededlib(needed_libs_t* needed); @@ -88,6 +90,7 @@ void add1_neededlib(needed_libs_t* needed); void add1lib_neededlib(needed_libs_t* needed, library_t* lib, const char* name); void add1lib_neededlib_name(needed_libs_t* needed, library_t* lib, const char* name); void add1libref_neededlib(needed_libs_t* needed, library_t* lib); +char* add1nsname(needed_libs_t* needed, char* nsname); typedef struct base_segment_s { uintptr_t base; diff --git a/src/include/elfloader.h b/src/include/elfloader.h index 7dee4434e..ef564b722 100644 --- a/src/include/elfloader.h +++ b/src/include/elfloader.h @@ -54,6 +54,7 @@ uintptr_t GetEntryPoint(lib_t* maplib, elfheader_t* h); uintptr_t GetLastByte(elfheader_t* h); void AddSymbols(lib_t *maplib, elfheader_t* h); int NeededLibs(elfheader_t* h); +char* ExpandNeededLibs(elfheader_t* h, char* rpath); int LoadNeededLibs(elfheader_t* h, lib_t *maplib, int local, int bindnow, int deepbind, box64context_t *box64, x64emu_t* emu); needed_libs_t* GetELfNeededLibs(elfheader_t* h); uintptr_t GetElfInit(elfheader_t* h); diff --git a/src/librarian/library.c b/src/librarian/library.c index 1c5b04459..45a8f907b 100644 --- a/src/librarian/library.c +++ b/src/librarian/library.c @@ -1323,6 +1323,13 @@ void free_neededlib(needed_libs_t* needed) FreeCollection(needed->rpath); box_free(needed->rpath); } + if(needed->nonstaticnames) { + for(int i=0; ins_size; ++i) + box_free(needed->nonstaticnames[i]); + box_free(needed->nonstaticnames); + needed->ns_size = 0; + needed->nonstaticnames = NULL; + } box_free(needed); } void add1_neededlib(needed_libs_t* needed) @@ -1406,8 +1413,30 @@ needed_libs_t* copy_neededlib(needed_libs_t* needed) ret->names = (char**)box_calloc(ret->cap, sizeof(char*)); memcpy(ret->libs, needed->libs, ret->size*sizeof(library_t*)); memcpy(ret->names, needed->names, ret->size*sizeof(char*)); + if(needed->nonstaticnames) { + ret->ns_size = needed->ns_size; + ret->nonstaticnames = (char**)box_malloc(ret->ns_size*sizeof(char*)); + for(int i=0; ins_size; ++i) + ret->nonstaticnames[i] = box_strdup(needed->nonstaticnames[i]); + } return ret; } +char* add1nsname(needed_libs_t* needed, char* nsname) +{ + if(!needed->ns_size) { + needed->ns_size = 1; + needed->nonstaticnames = (char**)box_malloc(needed->ns_size*sizeof(char*)); + needed->nonstaticnames[0] = nsname; + return needed->nonstaticnames[0]; + } + for(int i=0; ins_size; ++i) + if(!strcmp(needed->nonstaticnames[i], nsname)) + return needed->nonstaticnames[i]; + int i = needed->ns_size++; + needed->nonstaticnames = (char**)box_realloc(needed->nonstaticnames, (i+1)*sizeof(char*)); + needed->nonstaticnames[i] = nsname; + return needed->nonstaticnames[i]; +} void setNeededLibs(library_t* lib, int n, ...) {