diff --git a/headers/posix/dlfcn.h b/headers/posix/dlfcn.h index ff673e2a76..0e229d3ebc 100644 --- a/headers/posix/dlfcn.h +++ b/headers/posix/dlfcn.h @@ -14,6 +14,11 @@ #define RTLD_LOCAL 0 /* symbols are not available for relocating any other object */ #define RTLD_GLOBAL 2 /* all symbols are available */ +/* not-yet-POSIX extensions (dlsym() handles) */ +#define RTLD_DEFAULT ((void*)0) + /* find the symbol in the global scope */ +#define RTLD_NEXT ((void*)-1L) + /* find the next definition of the symbol */ #ifdef __cplusplus extern "C" { diff --git a/headers/private/runtime_loader/runtime_loader.h b/headers/private/runtime_loader/runtime_loader.h index 2b5697fe14..da3005cd0b 100644 --- a/headers/private/runtime_loader/runtime_loader.h +++ b/headers/private/runtime_loader/runtime_loader.h @@ -25,8 +25,12 @@ struct rld_export { // runtime loader API export image_id (*load_add_on)(char const *path, uint32 flags); status_t (*unload_add_on)(image_id imageID); + image_id (*load_library)(char const *path, uint32 flags, void **_handle); + status_t (*unload_library)(void* handle); status_t (*get_image_symbol)(image_id imageID, char const *symbolName, int32 symbolType, void **_location); + status_t (*get_library_symbol)(void* handle, void* caller, + const char* symbolName, void **_location); status_t (*get_nth_image_symbol)(image_id imageID, int32 num, char *symbolName, int32 *nameLength, int32 *symbolType, void **_location); status_t (*test_executable)(const char *path, char *interpreter); @@ -100,10 +104,9 @@ typedef struct image_t { uint32 num_needed; struct image_t **needed; - // For "root" images (the program, add-ons): Symbols are searched in the - // images in array order. - uint32 symbol_resolution_image_count; - struct image_t **symbol_resolution_images; + struct Elf32_Sym* (*find_undefined_symbol)(struct image_t* rootImage, + struct image_t* image, const char* name, + struct image_t** foundInImage); // Singly-linked list of symbol patchers for symbols defined respectively // referenced by this image. @@ -123,7 +126,6 @@ typedef struct image_queue_t { // image_t::flags #define IMAGE_FLAG_RTLD_MASK 0x03 // RTLD_{LAZY,NOW} | RTLD_{LOCAL,GLOBAL} -#define IMAGE_FLAG_R5_SYMBOL_RESOLUTION 0x04 #define STRING(image, offset) ((char *)(&(image)->strtab[(offset)])) #define SYMNAME(image, sym) STRING(image, (sym)->st_name) diff --git a/src/system/libroot/os/image.cpp b/src/system/libroot/os/image.cpp index e7837a5b72..d330382b4d 100644 --- a/src/system/libroot/os/image.cpp +++ b/src/system/libroot/os/image.cpp @@ -66,6 +66,9 @@ load_image(int32 argCount, const char **args, const char **environ) image_id load_add_on(char const *name) { + if (name == NULL) + return B_BAD_VALUE; + return __gRuntimeLoader->load_add_on(name, 0); } diff --git a/src/system/libroot/posix/dlfcn.c b/src/system/libroot/posix/dlfcn.c index d0cb53f3d6..fee50e8dfd 100644 --- a/src/system/libroot/posix/dlfcn.c +++ b/src/system/libroot/posix/dlfcn.c @@ -1,4 +1,5 @@ /* + * Copyright 2008, Ingo Weinhold, ingo_weinhold@gmx.de. * Copyright 2003-2008, Axel Dörfler, axeld@pinc-software.de. * Distributed under the terms of the MIT License. * @@ -23,31 +24,27 @@ static status_t sStatus; void * dlopen(char const *name, int mode) { -// TODO: According to the standard multiple dlopen() invocations for the same -// file will cause the object to be loaded once only. That is we should load -// the object as a library, not an add-on. - status_t status; + void* handle; + image_id imageID = __gRuntimeLoader->load_library(name, mode, &handle); - if (name == NULL) - name = MAGIC_APP_NAME; + sStatus = imageID >= 0 ? B_OK : imageID; - status = __gRuntimeLoader->load_add_on(name, mode); - sStatus = status; - - if (status < B_OK) - return NULL; - - return (void *)status; + return imageID >= 0 ? handle : NULL; } void * dlsym(void *handle, char const *name) { + void* location; status_t status; - void *location; + void* caller = NULL; - status = get_image_symbol((image_id)handle, name, B_SYMBOL_TYPE_ANY, &location); + if (handle == RTLD_NEXT) + caller = __arch_get_caller(); + + status = __gRuntimeLoader->get_library_symbol(handle, caller, name, + &location); sStatus = status; if (status < B_OK) @@ -60,7 +57,7 @@ dlsym(void *handle, char const *name) int dlclose(void *handle) { - return unload_add_on((image_id)handle); + return __gRuntimeLoader->unload_library(handle); } @@ -77,6 +74,8 @@ dlerror(void) int dladdr(void *addr, Dl_info *info) { +// TODO: This can be implemented more efficiently in the runtime loader. +// get_library_symbol() already has the code doing that. char curSymName[NAME_MAX]; static char symName[NAME_MAX]; static char imageName[MAXPATHLEN]; diff --git a/src/system/runtime_loader/elf.cpp b/src/system/runtime_loader/elf.cpp index 070833dfe4..5bac30b152 100644 --- a/src/system/runtime_loader/elf.cpp +++ b/src/system/runtime_loader/elf.cpp @@ -11,6 +11,7 @@ #include "runtime_loader_private.h" #include +#include #include #include #include @@ -49,9 +50,14 @@ #define RLD_PROGRAM_BASE 0x00200000 /* keep in sync with app ldscript */ +// a handle returned by load_library() (dlopen()) +#define RLD_GLOBAL_SCOPE ((void*)-2l) + enum { - RFLAG_RW = 0x0001, - RFLAG_ANON = 0x0002, + // the lower two bits are reserved for RTLD_NOW and RTLD_GLOBAL + + RFLAG_RW = 0x0010, + RFLAG_ANON = 0x0020, RFLAG_TERMINATED = 0x0200, RFLAG_INITIALIZED = 0x0400, @@ -61,7 +67,8 @@ enum { RFLAG_DEPENDENCIES_LOADED = 0x4000, RFLAG_REMAPPED = 0x8000, - RFLAG_VISITED = 0x10000 + RFLAG_VISITED = 0x10000, + RFLAG_USE_FOR_RESOLVING = 0x20000 // temporarily set in the symbol resolution code }; @@ -501,7 +508,6 @@ delete_image_struct(image_t *image) memset(image->needed, 0xa5, sizeof(image->needed[0]) * image->num_needed); #endif free(image->needed); - free(image->symbol_resolution_images); while (RuntimeLoaderSymbolPatcher* patcher = image->defined_symbol_patchers) { @@ -535,6 +541,52 @@ delete_image(image_t *image) } +static void +update_image_flags_recursively(image_t* image, uint32 flagsToSet, + uint32 flagsToClear) +{ + image_t* queue[sLoadedImageCount]; + uint32 count = 0; + uint32 index = 0; + queue[count++] = image; + image->flags |= RFLAG_VISITED; + + while (index < count) { + // pop next image + image = queue[index++]; + + // push dependencies + for (uint32 i = 0; i < image->num_needed; i++) { + image_t* needed = image->needed[i]; + if ((needed->flags & RFLAG_VISITED) == 0) { + queue[count++] = needed; + needed->flags |= RFLAG_VISITED; + } + } + } + + // update flags + for (uint32 i = 0; i < count; i++) { + queue[i]->flags = (queue[i]->flags | flagsToSet) + & ~(flagsToClear | RFLAG_VISITED); + } +} + + +static void +set_image_flags_recursively(image_t* image, uint32 flags) +{ + update_image_flags_recursively(image, flags, 0); +} + + +static void +clear_image_flags_recursively(image_t* image, uint32 flags) +{ + update_image_flags_recursively(image, 0, flags); +} + + static status_t parse_program_headers(image_t *image, char *buff, int phnum, int phentsize) { @@ -1183,36 +1235,48 @@ find_symbol(image_t* image, char const* symbolName, int32 symbolType, } -static struct Elf32_Sym* -find_symbol_in_root_image_list(image_t* rootImage, const char* name, - image_t** foundInImage) +static status_t +find_symbol_breadth_first(image_t* image, const char* name, int32 type, + image_t** _foundInImage, void** _location) { - int32 count = rootImage->symbol_resolution_image_count; - image_t** images = rootImage->symbol_resolution_images; - for (int32 i = 0; i < count; i++) { - image_t* image = images[i]; - if (image->dynamic_ptr) { - Elf32_Sym* symbol = find_symbol(image, name, B_SYMBOL_TYPE_ANY); - if (symbol) { - *foundInImage = image; - return symbol; + image_t* queue[sLoadedImageCount]; + uint32 count = 0; + uint32 index = 0; + queue[count++] = image; + image->flags |= RFLAG_VISITED; + + bool found = false; + while (index < count) { + // pop next image + image = queue[index++]; + + if (find_symbol(image, name, type, _location) == B_OK) { + found = true; + break; + } + + // push needed images + for (uint32 i = 0; i < image->num_needed; i++) { + image_t* needed = image->needed[i]; + if ((needed->flags & RFLAG_VISITED) == 0) { + queue[count++] = needed; + needed->flags |= RFLAG_VISITED; } } } - return NULL; + // clear visited flags + for (uint32 i = 0; i < count; i++) + queue[i]->flags &= ~RFLAG_VISITED; + + return found ? B_OK : B_ENTRY_NOT_FOUND; } static struct Elf32_Sym* -find_undefined_symbol(image_t* rootImage, image_t* image, const char* name, +find_undefined_symbol_beos(image_t* rootImage, image_t* image, const char* name, image_t** foundInImage) { - // If not simulating BeOS style symbol resolution, undefined symbols are - // searched recursively starting from the root image. - if ((rootImage->flags & IMAGE_FLAG_R5_SYMBOL_RESOLUTION) == 0) - return find_symbol_in_root_image_list(rootImage, name, foundInImage); - // BeOS style symbol resolution: It is sufficient to check the direct // dependencies. The linker would have complained, if the symbol wasn't // there. @@ -1231,6 +1295,48 @@ find_undefined_symbol(image_t* rootImage, image_t* image, const char* name, } +static struct Elf32_Sym* +find_undefined_symbol_global(image_t* rootImage, image_t* image, + const char* name, image_t** foundInImage) +{ + // Global load order symbol resolution: All loaded images are searched for + // the symbol in the order they have been loaded. We skip add-on images and + // RTLD_LOCAL images though. + image_t* otherImage = sLoadedImages.head; + while (otherImage != NULL) { + if (otherImage == rootImage + || otherImage->type != B_ADD_ON_IMAGE + && (otherImage->flags + & (RTLD_GLOBAL | RFLAG_USE_FOR_RESOLVING)) != 0) { + struct Elf32_Sym *symbol = find_symbol(otherImage, name, + B_SYMBOL_TYPE_ANY); + if (symbol) { + *foundInImage = otherImage; + return symbol; + } + } + otherImage = otherImage->next; + } + + return NULL; +} + + +static struct Elf32_Sym* +find_undefined_symbol_add_on(image_t* rootImage, image_t* image, + const char* name, image_t** foundInImage) +{ +// TODO: How do we want to implement this one? Using global scope resolution +// might be undesired as it is now, since libraries could refer to symbols in +// the add-on, which would result in add-on symbols implicitely becoming used +// outside of the add-on. So the options would be to use the global scope but +// skip the add-on, or to do breadth-first resolution in the add-on dependency +// scope, also skipping the add-on itself. BeOS style resolution is safe, too, +// but we miss out features like undefined symbols and preloading. + return find_undefined_symbol_beos(rootImage, image, name, foundInImage); +} + + /*! This function is called when we run BeOS images on Haiku. It allows us to redirect functions to ensure compatibility. */ @@ -1289,8 +1395,8 @@ resolve_symbol(image_t *rootImage, image_t *image, struct Elf32_Sym *sym, type = B_SYMBOL_TYPE_DATA; // it's undefined, must be outside this image, try the other images - sharedSym = find_undefined_symbol(rootImage, image, symName, - &sharedImage); + sharedSym = rootImage->find_undefined_symbol(rootImage, image, + symName, &sharedImage); void* location = NULL; enum { @@ -1447,7 +1553,8 @@ relocate_image(image_t *rootImage, image_t *image) static status_t -load_container(char const *name, image_type type, const char *rpath, image_t **_image) +load_container(char const *name, image_type type, const char *rpath, + image_t **_image) { int32 pheaderSize, sheaderSize; char path[PATH_MAX]; @@ -1593,7 +1700,7 @@ load_container(char const *name, image_type type, const char *rpath, image_t **_ // unavailable) if (image->gcc_version.major == 0 || image->gcc_version.major == 2 && image->gcc_version.middle < 95) { - image->flags |= IMAGE_FLAG_R5_SYMBOL_RESOLUTION; + image->find_undefined_symbol = find_undefined_symbol_beos; } status = map_image(fd, path, image, type == B_APP_IMAGE); @@ -1659,7 +1766,7 @@ find_dt_rpath(image_t *image) static status_t -load_dependencies(image_t *image) +load_immediate_dependencies(image_t *image) { struct Elf32_Dyn *d = (struct Elf32_Dyn *)image->dynamic_ptr; bool reportErrors = report_errors(); @@ -1748,6 +1855,20 @@ load_dependencies(image_t *image) } +static status_t +load_dependencies(image_t* image) +{ + for (image_t* otherImage = image; otherImage != NULL; + otherImage = otherImage->next) { + status_t status = load_immediate_dependencies(otherImage); + if (status != B_OK) + return status; + } + + return B_OK; +} + + static uint32 topological_sort(image_t *image, uint32 slot, image_t **initList, uint32 sortFlag) @@ -1766,36 +1887,6 @@ topological_sort(image_t *image, uint32 slot, image_t **initList, } -static uint32 -topological_sort_breadth_first(image_t* image, image_t** list, uint32 sortFlag) -{ - if ((image->flags & sortFlag) != 0) - return 0; - - // We directly use the result list as queue for the breadth first search. - list[0] = image; - image->flags |= sortFlag; - - int32 index = 0; - int32 count = 1; - - while (index < count) { - image = list[index++]; - - for (uint32 i = 0; i < image->num_needed; i++) { - image_t* neededImage = image->needed[i]; - if ((neededImage->flags & sortFlag) == 0) { - // dependency not yet visited -- add to queue - list[count++] = neededImage; - neededImage->flags |= sortFlag; - } - } - } - - return count; -} - - static ssize_t get_sorted_image_list(image_t *image, image_t ***_list, uint32 sortFlag) { @@ -1815,84 +1906,22 @@ get_sorted_image_list(image_t *image, image_t ***_list, uint32 sortFlag) } -static ssize_t -get_sorted_image_list_breadth_first(image_t* image, image_t*** _list, - uint32 sortFlag) -{ - image_t** list = (image_t**)malloc(sLoadedImageCount * sizeof(image_t*)); - if (list == NULL) { - FATAL("memory shortage in get_sorted_image_list()"); - *_list = NULL; - return B_NO_MEMORY; - } - - memset(list, 0, sLoadedImageCount * sizeof(image_t *)); - - *_list = list; - - return topological_sort_breadth_first(image, list, sortFlag); -} - - static status_t relocate_dependencies(image_t *image) { - // build an array of images in the order we want to lookup symbols - image_t** lookupList; - ssize_t lookupCount = get_sorted_image_list_breadth_first(image, - &lookupList, RFLAG_VISITED); - if (lookupCount < 0) - return lookupCount; - - // If the image is not the program image, add it and its dependencies, too. - if (sProgramImage != NULL && image != sProgramImage) { - lookupCount += topological_sort_breadth_first(sProgramImage, - lookupList + lookupCount, RFLAG_VISITED); - } - - // If we have pre-loaded images, prepend them. - if (sPreloadedImageCount > 0) { - // Count the ones that have to be added -- normally all, but one never - // knows. - uint32 preloadedCount = 0; - for (uint32 i = 0; i < sPreloadedImageCount; i++) { - image_t* preloadedImage = sPreloadedImages[i]; - if ((preloadedImage->flags & RFLAG_VISITED) == 0) - preloadedCount++; - } - - // add them - if (preloadedCount > 0) { - memmove(lookupList + preloadedCount, lookupList, - lookupCount * sizeof(image_t*)); - lookupCount += preloadedCount; - - preloadedCount = 0; - for (uint32 i = 0; i < sPreloadedImageCount; i++) { - image_t* preloadedImage = sPreloadedImages[i]; - if ((preloadedImage->flags & RFLAG_VISITED) == 0) - lookupList[preloadedCount++] = preloadedImage; - } - } - } - - // clear the "visited" flag - for (int32 i = 0; i < lookupCount; i++) - lookupList[i]->flags &= ~RFLAG_VISITED; - - image->symbol_resolution_images = lookupList; - image->symbol_resolution_image_count = lookupCount; - // get the images that still have to be relocated image_t **list; ssize_t count = get_sorted_image_list(image, &list, RFLAG_RELOCATED); if (count < B_OK) return count; + // relocate for (ssize_t i = 0; i < count; i++) { status_t status = relocate_image(image, list[i]); - if (status < B_OK) + if (status < B_OK) { + free(list); return status; + } } free(list); @@ -1959,12 +1988,10 @@ inject_runtime_loader_api(image_t* rootImage) // We patch any exported __gRuntimeLoader symbols to point to our private // API. image_t* image; - Elf32_Sym* symbol = find_symbol_in_root_image_list(rootImage, - "__gRuntimeLoader", &image); - - if (symbol != NULL) { - void** _export = (void**)(symbol->st_value + image->regions[0].delta); - *_export = &gRuntimeLoader; + void* _export; + if (find_symbol_breadth_first(rootImage, "__gRuntimeLoader", + B_SYMBOL_TYPE_DATA, &image, &_export) == B_OK) { + *(void**)_export = &gRuntimeLoader; } } @@ -2003,12 +2030,14 @@ preload_image(char const* path) return status; } - for (image_t* otherImage = sLoadedImages.head; otherImage != NULL; - otherImage = otherImage->next) { - status = load_dependencies(otherImage); - if (status < B_OK) - goto err; - } + if (image->find_undefined_symbol == NULL) + image->find_undefined_symbol = find_undefined_symbol_global; + + status = load_dependencies(image); + if (status < B_OK) + goto err; + + set_image_flags_recursively(image, RTLD_GLOBAL); status = relocate_dependencies(image); if (status < B_OK) @@ -2105,11 +2134,17 @@ load_program(char const *path, void **_entry) if (status < B_OK) goto err; - for (image = sLoadedImages.head; image != NULL; image = image->next) { - status = load_dependencies(image); - if (status < B_OK) - goto err; - } + if (sProgramImage->find_undefined_symbol == NULL) + sProgramImage->find_undefined_symbol = find_undefined_symbol_global; + + status = load_dependencies(sProgramImage); + if (status < B_OK) + goto err; + + // Set RTLD_GLOBAL on all libraries, but clear it on the program image. + // This results in the desired symbol resolution for dlopen()ed libraries. + set_image_flags_recursively(sProgramImage, RTLD_GLOBAL); + sProgramImage->flags &= ~RTLD_GLOBAL; status = relocate_dependencies(sProgramImage); if (status < B_OK) @@ -2122,14 +2157,8 @@ load_program(char const *path, void **_entry) // Since the images are initialized now, we no longer should use our // getenv(), but use the one from libroot.so - { - struct Elf32_Sym *symbol = find_symbol_in_root_image_list(sProgramImage, - "getenv", &image); - - if (symbol != NULL) - gGetEnv = (char* (*)(const char*)) - (symbol->st_value + image->regions[0].delta); - } + find_symbol_breadth_first(sProgramImage, "getenv", B_SYMBOL_TYPE_TEXT, + &image, (void**)&gGetEnv); if (sProgramImage->entry_point == 0) { status = B_NOT_AN_EXECUTABLE; @@ -2169,19 +2198,15 @@ err: image_id -load_library(char const *path, uint32 flags, bool addOn) +load_library(char const *path, uint32 flags, bool addOn, void** _handle) { image_t *image = NULL; - image_t *iter; image_type type = (addOn ? B_ADD_ON_IMAGE : B_LIBRARY_IMAGE); status_t status; - if (path == NULL) + if (path == NULL && addOn) return B_BAD_VALUE; - // ToDo: implement flags - (void)flags; - KTRACE("rld: load_library(\"%s\", 0x%lx, %d)", path, flags, addOn); rld_lock(); @@ -2190,12 +2215,23 @@ load_library(char const *path, uint32 flags, bool addOn) // have we already loaded this library? // Checking it at this stage saves loading its dependencies again if (!addOn) { + // a NULL path is fine -- it means the global scope shall be opened + if (path == NULL) { + *_handle = RLD_GLOBAL_SCOPE; + rld_unlock(); + return 0; + } + image = find_image(path, APP_OR_LIBRARY_TYPE); + if (image != NULL && (flags & RTLD_GLOBAL) != 0) + set_image_flags_recursively(image, RTLD_GLOBAL); + if (image) { atomic_add(&image->ref_count, 1); rld_unlock(); KTRACE("rld: load_library(\"%s\"): already loaded: %ld", path, image->id); + *_handle = image; return image->id; } } @@ -2208,16 +2244,33 @@ load_library(char const *path, uint32 flags, bool addOn) return status; } - for (iter = sLoadedImages.head; iter; iter = iter->next) { - status = load_dependencies(iter); - if (status < B_OK) - goto err; + if (image->find_undefined_symbol == NULL) { + if (addOn) + image->find_undefined_symbol = find_undefined_symbol_add_on; + else + image->find_undefined_symbol = find_undefined_symbol_global; } + status = load_dependencies(image); + if (status < B_OK) + goto err; + + // If specified, set the RTLD_GLOBAL flag recursively on this image and all + // dependencies. If not specified, we temporarily set + // RFLAG_USE_FOR_RESOLVING so that the dependencies will correctly be used + // for undefined symbol resolution. + if ((flags & RTLD_GLOBAL) != 0) + set_image_flags_recursively(image, RTLD_GLOBAL); + else + set_image_flags_recursively(image, RFLAG_USE_FOR_RESOLVING); + status = relocate_dependencies(image); if (status < B_OK) goto err; + if ((flags & RTLD_GLOBAL) == 0) + clear_image_flags_recursively(image, RFLAG_USE_FOR_RESOLVING); + remap_images(); init_dependencies(image, true); @@ -2225,6 +2278,7 @@ load_library(char const *path, uint32 flags, bool addOn) KTRACE("rld: load_library(\"%s\") done: id: %ld", path, image->id); + *_handle = image; return image->id; err: @@ -2239,15 +2293,18 @@ err: status_t -unload_library(image_id imageID, bool addOn) +unload_library(void* handle, image_id imageID, bool addOn) { status_t status = B_BAD_IMAGE_ID; image_t *image; image_type type = addOn ? B_ADD_ON_IMAGE : B_LIBRARY_IMAGE; - if (imageID < B_OK) + if (handle == NULL && imageID < 0) return B_BAD_IMAGE_ID; + if (handle == RLD_GLOBAL_SCOPE) + return B_OK; + rld_lock(); // for now, just do stupid simple global locking @@ -2258,15 +2315,20 @@ unload_library(image_id imageID, bool addOn) // we only check images that have been already initialized - for (image = sLoadedImages.head; image; image = image->next) { - if (image->id == imageID) { - // unload image - if (type == image->type) { - put_image(image); - status = B_OK; - } else - status = B_BAD_VALUE; - break; + if (handle != NULL) { + image = (image_t*)handle; + put_image(image); + } else { + for (image = sLoadedImages.head; image; image = image->next) { + if (image->id == imageID) { + // unload image + if (type == image->type) { + put_image(image); + status = B_OK; + } else + status = B_BAD_VALUE; + break; + } } } @@ -2383,6 +2445,115 @@ get_symbol(image_id imageID, char const *symbolName, int32 symbolType, } +status_t +get_library_symbol(void* handle, void* caller, const char* symbolName, + void **_location) +{ + status_t status = B_ENTRY_NOT_FOUND; + + if (symbolName == NULL) + return B_BAD_VALUE; + + rld_lock(); + // for now, just do stupid simple global locking + + if (handle == RTLD_DEFAULT || handle == RLD_GLOBAL_SCOPE) { + // look in the default scope + image_t* image; + Elf32_Sym* symbol = find_undefined_symbol_global(sProgramImage, + sProgramImage, symbolName, &image); + if (symbol != NULL) { + *_location = (void*)(symbol->st_value + image->regions[0].delta); + int32 symbolType = ELF32_ST_TYPE(symbol->st_info) == STT_FUNC + ? B_SYMBOL_TYPE_TEXT : B_SYMBOL_TYPE_DATA; + patch_defined_symbol(image, symbolName, _location, &symbolType); + status = B_OK; + } + } else if (handle == RTLD_NEXT) { + // Look in the default scope, but also in the dependencies of the + // calling image. Return the next after the caller symbol. + + // First of all, find the caller symbol and its image. + Elf32_Sym* callerSymbol = NULL; + image_t* callerImage = sLoadedImages.head; + for (; callerImage != NULL; callerImage = callerImage->next) { + elf_region_t& text = callerImage->regions[0]; + if ((addr_t)caller < text.vmstart + || (addr_t)caller >= text.vmstart + text.vmsize) { + continue; + } + + // found the image -- now find the symbol + for (uint32 i = 0; i < callerImage->symhash[1]; i++) { + Elf32_Sym& symbol = callerImage->syms[i]; + if ((ELF32_ST_TYPE(symbol.st_info) != STT_FUNC) + || symbol.st_value == 0) { + continue; + } + + addr_t address = symbol.st_value + + callerImage->regions[0].delta; + if ((addr_t)caller >= address + && (addr_t)caller < address + symbol.st_size) { + callerSymbol = &symbol; + break; + } + } + + break; + } + + if (callerSymbol != NULL) { + // found the caller -- now search the global scope until we find + // the next symbol + set_image_flags_recursively(callerImage, RFLAG_USE_FOR_RESOLVING); + + image_t* image = sLoadedImages.head; + for (; image != NULL; image = image->next) { + if (image != callerImage + && (image->type == B_ADD_ON_IMAGE + || (image->flags + & (RTLD_GLOBAL | RFLAG_USE_FOR_RESOLVING)) == 0)) { + continue; + } + + struct Elf32_Sym *symbol = find_symbol(image, symbolName, + B_SYMBOL_TYPE_TEXT); + if (symbol == NULL) + continue; + + if (callerSymbol == NULL) { + // already skipped the caller symbol -- so this is + // the one we're looking for + *_location = (void*)(symbol->st_value + + image->regions[0].delta); + int32 symbolType = B_SYMBOL_TYPE_TEXT; + patch_defined_symbol(image, symbolName, _location, + &symbolType); + status = B_OK; + break; + } + if (symbol == callerSymbol) { + // found the caller symbol + callerSymbol = NULL; + } + } + + clear_image_flags_recursively(callerImage, RFLAG_USE_FOR_RESOLVING); + } + + } else { + // breadth-first search in the given image and its dependencies + image_t* inImage; + status = find_symbol_breadth_first((image_t*)handle, symbolName, + B_SYMBOL_TYPE_ANY, &inImage, _location); + } + + rld_unlock(); + return status; +} + + status_t get_next_image_dependency(image_id id, uint32 *cookie, const char **_name) { diff --git a/src/system/runtime_loader/export.c b/src/system/runtime_loader/export.c index 03c3d73f8c..03b72152f1 100644 --- a/src/system/runtime_loader/export.c +++ b/src/system/runtime_loader/export.c @@ -16,14 +16,29 @@ static image_id export_load_add_on(char const *name, uint32 flags) { - return load_library(name, flags, true); + void* handle; + return load_library(name, flags, true, &handle); } static status_t export_unload_add_on(image_id id) { - return unload_library(id, true); + return unload_library(NULL, id, true); +} + + +static image_id +export_load_library(char const *name, uint32 flags, void **_handle) +{ + return load_library(name, flags, false, _handle); +} + + +static status_t +export_unload_library(void* handle) +{ + return unload_library(handle, -1, false); } @@ -31,7 +46,10 @@ struct rld_export gRuntimeLoader = { // dynamic loading support API export_load_add_on, export_unload_add_on, + export_load_library, + export_unload_library, get_symbol, + get_library_symbol, get_nth_symbol, test_executable, get_next_image_dependency, diff --git a/src/system/runtime_loader/runtime_loader.c b/src/system/runtime_loader/runtime_loader.c index 7393200fbf..38ec10efa0 100644 --- a/src/system/runtime_loader/runtime_loader.c +++ b/src/system/runtime_loader/runtime_loader.c @@ -240,8 +240,22 @@ open_executable(char *name, image_type type, const char *rpath, memmove(name, paths, strlen(paths) + 1); } - // first try rpath (DT_RPATH) - if (rpath) { + // let's evaluate the system path variables to find the container + paths = search_path_for_type(type); + if (paths) { + fd = search_executable_in_path_list(name, paths, strlen(paths), + 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)); + } + } + + // try rpath (DT_RPATH), if not found yet + if (fd < 0 && rpath != NULL) { // It consists of a colon-separated search path list. Optionally it // follows a second search path list, separated from the first by a // semicolon. @@ -260,22 +274,6 @@ open_executable(char *name, image_type type, const char *rpath, } } - // let's evaluate the system path variables to find the container - if (fd < 0) { - paths = search_path_for_type(type); - if (paths) { - fd = search_executable_in_path_list(name, paths, strlen(paths), - 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)); - } - } - } - if (fd >= 0) { // we found it, copy path! TRACE(("runtime_loader: open_executable(%s): found at %s\n", name, buffer)); diff --git a/src/system/runtime_loader/runtime_loader_private.h b/src/system/runtime_loader/runtime_loader_private.h index b71802d503..163b46e135 100644 --- a/src/system/runtime_loader/runtime_loader_private.h +++ b/src/system/runtime_loader/runtime_loader_private.h @@ -29,12 +29,15 @@ status_t test_executable(const char *path, char *interpreter); void terminate_program(void); image_id load_program(char const *path, void **entry); -status_t unload_library(image_id imageID, bool addOn); -image_id load_library(char const *path, uint32 flags, bool addOn); +image_id load_library(char const *path, uint32 flags, bool addOn, + void** _handle); +status_t unload_library(void* handle, image_id imageID, bool addOn); status_t get_nth_symbol(image_id imageID, int32 num, char *nameBuffer, int32 *_nameLength, int32 *_type, void **_location); status_t get_symbol(image_id imageID, char const *symbolName, int32 symbolType, void **_location); +status_t get_library_symbol(void* handle, void* caller, const char* symbolName, + void **_location); status_t get_next_image_dependency(image_id id, uint32 *cookie, const char **_name); int resolve_symbol(image_t *rootImage, image_t *image, struct Elf32_Sym *sym,