From 61b37794a4fa1d5766fc704db52b82e628e0149a Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Sat, 17 May 2008 23:25:17 +0000 Subject: [PATCH] Added explicit support for loading executables compiled with the respectively other gcc version on a Haiku compiled with gcc 2 or gcc 4. The libraries for such an executable are first searched in "gcc4" respectively "gcc2" subdirectories of the standard search path directories. If not found there, we try again with the standard paths. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@25532 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- src/system/runtime_loader/elf.cpp | 20 +++++++-- src/system/runtime_loader/runtime_loader.c | 41 ++++++++++++++----- .../runtime_loader/runtime_loader_private.h | 2 +- 3 files changed, 48 insertions(+), 15 deletions(-) diff --git a/src/system/runtime_loader/elf.cpp b/src/system/runtime_loader/elf.cpp index 5ba8881941..85ef13d93e 100644 --- a/src/system/runtime_loader/elf.cpp +++ b/src/system/runtime_loader/elf.cpp @@ -81,6 +81,7 @@ static uint32 sLoadedImageCount = 0; static image_t *sProgramImage; static KMessage sErrorMessage; static bool sProgramLoaded = false; +static const char *sSearchPathSubDir = NULL; // a recursive lock static sem_id rld_sem; @@ -1192,8 +1193,9 @@ load_container(char const *name, image_type type, const char *rpath, image_t **_ strlcpy(path, name, sizeof(path)); - // Try to load explicit image path first - fd = open_executable(path, type, rpath, get_program_path()); + // find and open the file + fd = open_executable(path, type, rpath, get_program_path(), + sSearchPathSubDir); if (fd < 0) { FATAL("cannot open file %s\n", path); KTRACE("rld: load_container(\"%s\"): failed to open file", name); @@ -1270,8 +1272,20 @@ load_container(char const *name, image_type type, const char *rpath, image_t **_ goto err2; } - if (!analyze_object_gcc_version(fd, image, eheader, sheaderSize, ph_buff, + if (analyze_object_gcc_version(fd, image, eheader, sheaderSize, ph_buff, sizeof(ph_buff))) { + // If this is the executable image, we init the search path + // subdir, if the compiler version doesn't match ours. + if (type == B_APP_IMAGE) { + #if __GNUC__ == 2 + if (image->gcc_version.major > 2) + sSearchPathSubDir = "gcc4"; + #elif __GNUC__ == 4 + if (image->gcc_version.major == 2) + sSearchPathSubDir = "gcc2"; + #endif + } + } else { FATAL("Failed to get gcc version for %s\n", path); // not really fatal, actually } diff --git a/src/system/runtime_loader/runtime_loader.c b/src/system/runtime_loader/runtime_loader.c index ebd0af7ed8..e34f300869 100644 --- a/src/system/runtime_loader/runtime_loader.c +++ b/src/system/runtime_loader/runtime_loader.c @@ -90,7 +90,8 @@ search_path_for_type(image_type type) static int try_open_executable(const char *dir, int dirLength, const char *name, - const char *programPath, char *path, size_t pathLength) + const char *programPath, const char *compatibilitySubDir, char *path, + size_t pathLength) { size_t nameLength = strlen(name); struct stat stat; @@ -99,6 +100,7 @@ try_open_executable(const char *dir, int dirLength, const char *name, // construct the path if (dirLength > 0) { char *buffer = path; + size_t subDirLen = 0; if (programPath == NULL) programPath = gProgramArgs->program_path; @@ -121,14 +123,23 @@ try_open_executable(const char *dir, int dirLength, const char *name, pathLength -= bytesCopied; dir += 2; dirLength -= 2; + } else if (compatibilitySubDir != NULL) { + // We're looking for a library or an add-on and the executable has + // not been compiled with a compiler compatible with the one the + // OS has been built with. Thus we only look in specific subdirs. + subDirLen = strlen(compatibilitySubDir) + 1; } - if (dirLength + 1 + nameLength >= pathLength) + if (dirLength + 1 + subDirLen + nameLength >= pathLength) return B_NAME_TOO_LONG; memcpy(buffer, dir, dirLength); buffer[dirLength] = '/'; - strcpy(buffer + dirLength + 1, name); + if (subDirLen > 0) { + memcpy(buffer + dirLength + 1, compatibilitySubDir, subDirLen - 1); + buffer[dirLength + subDirLen] = '/'; + } + strcpy(buffer + dirLength + 1 + subDirLen, name); } else { if (nameLength >= pathLength) return B_NAME_TOO_LONG; @@ -169,8 +180,8 @@ try_open_executable(const char *dir, int dirLength, const char *name, static int search_executable_in_path_list(const char *name, const char *pathList, - int pathListLen, const char *programPath, char *pathBuffer, - size_t pathBufferLength) + int pathListLen, const char *programPath, const char *compatibilitySubDir, + char *pathBuffer, size_t pathBufferLength) { const char *pathListEnd = pathList + pathListLen; status_t status = B_ENTRY_NOT_FOUND; @@ -187,7 +198,7 @@ search_executable_in_path_list(const char *name, const char *pathList, pathEnd++; fd = try_open_executable(pathList, pathEnd - pathList, name, - programPath, pathBuffer, pathBufferLength); + programPath, compatibilitySubDir, pathBuffer, pathBufferLength); if (fd >= 0) { // see if it's a dir struct stat stat; @@ -210,7 +221,7 @@ search_executable_in_path_list(const char *name, const char *pathList, int open_executable(char *name, image_type type, const char *rpath, - const char *programPath) + const char *programPath, const char *compatibilitySubDir) { const char *paths; char buffer[PATH_MAX]; @@ -240,11 +251,12 @@ open_executable(char *name, image_type type, const char *rpath, // If there is no ';', we set only secondList to simplify things. if (firstList) { fd = search_executable_in_path_list(name, firstList, - semicolon - firstList, programPath, buffer, sizeof(buffer)); + semicolon - firstList, programPath, NULL, buffer, + sizeof(buffer)); } if (fd < 0) { fd = search_executable_in_path_list(name, secondList, - strlen(secondList), programPath, buffer, sizeof(buffer)); + strlen(secondList), programPath, NULL, buffer, sizeof(buffer)); } } @@ -253,7 +265,14 @@ open_executable(char *name, image_type type, const char *rpath, paths = search_path_for_type(type); if (paths) { fd = search_executable_in_path_list(name, paths, strlen(paths), - programPath, buffer, sizeof(buffer)); + programPath, compatibilitySubDir, buffer, sizeof(buffer)); + + // If not found and a compatibility sub directory has been + // specified, look again in the standard search paths. + if (fd == B_ENTRY_NOT_FOUND && compatibilitySubDir != NULL) { + fd = search_executable_in_path_list(name, paths, strlen(paths), + programPath, NULL, buffer, sizeof(buffer)); + } } } @@ -288,7 +307,7 @@ test_executable(const char *name, char *invoker) strlcpy(path, name, sizeof(path)); - fd = open_executable(path, B_APP_IMAGE, NULL, NULL); + fd = open_executable(path, B_APP_IMAGE, NULL, NULL, NULL); if (fd < B_OK) return fd; diff --git a/src/system/runtime_loader/runtime_loader_private.h b/src/system/runtime_loader/runtime_loader_private.h index 84f3e5c569..0de639bee3 100644 --- a/src/system/runtime_loader/runtime_loader_private.h +++ b/src/system/runtime_loader/runtime_loader_private.h @@ -24,7 +24,7 @@ extern "C" { int runtime_loader(void *arg); int open_executable(char *name, image_type type, const char *rpath, - const char *programPath); + const char *programPath, const char *compatibilitySubDir); status_t test_executable(const char *path, char *interpreter); void terminate_program(void);