* Reworked undefined symbol resolution in the runtime loader. Got rid of
the per-root-image breadth-first sorted image array. Instead we have a
per-image hook function to resolve the symbols. The default function
uses the sLoadedImages list directly, which is breadth-first sorted
anyway. There's also a BeOS function for old-style symbol resolution
and one for add-ons, which lacks a proper implementation yet (just
uses old-style ATM).
* Made the dl*() functions POSIX compliant:
- dlopen() does no longer use load_add_on(), but loads the object as a
library. It also properly supports a NULL name, now -- the previous
"_APP_" work-around did only work, if this soname was set on the
program (unlikely for programs using this API).
- Implemented RTLD_{GLOBAL,LOCAL}.
- dlsym() looks up symbols properly now, i.e. not just in the given
image, but breadth-first for an actual image or in load order for
the global scope. It also supports the not-quite POSIX RTLD_DEFAULT
and RTLD_NEXT extensions. Our RTLD_NEXT finds more symbols than in
Linux (also in later dlopen()ed libraries), but that should be fine.
git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@28568 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -14,6 +14,11 @@
|
|||||||
#define RTLD_LOCAL 0 /* symbols are not available for relocating any other object */
|
#define RTLD_LOCAL 0 /* symbols are not available for relocating any other object */
|
||||||
#define RTLD_GLOBAL 2 /* all symbols are available */
|
#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
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
|||||||
@@ -25,8 +25,12 @@ struct rld_export {
|
|||||||
// runtime loader API export
|
// runtime loader API export
|
||||||
image_id (*load_add_on)(char const *path, uint32 flags);
|
image_id (*load_add_on)(char const *path, uint32 flags);
|
||||||
status_t (*unload_add_on)(image_id imageID);
|
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,
|
status_t (*get_image_symbol)(image_id imageID, char const *symbolName,
|
||||||
int32 symbolType, void **_location);
|
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,
|
status_t (*get_nth_image_symbol)(image_id imageID, int32 num, char *symbolName,
|
||||||
int32 *nameLength, int32 *symbolType, void **_location);
|
int32 *nameLength, int32 *symbolType, void **_location);
|
||||||
status_t (*test_executable)(const char *path, char *interpreter);
|
status_t (*test_executable)(const char *path, char *interpreter);
|
||||||
@@ -100,10 +104,9 @@ typedef struct image_t {
|
|||||||
uint32 num_needed;
|
uint32 num_needed;
|
||||||
struct image_t **needed;
|
struct image_t **needed;
|
||||||
|
|
||||||
// For "root" images (the program, add-ons): Symbols are searched in the
|
struct Elf32_Sym* (*find_undefined_symbol)(struct image_t* rootImage,
|
||||||
// images in array order.
|
struct image_t* image, const char* name,
|
||||||
uint32 symbol_resolution_image_count;
|
struct image_t** foundInImage);
|
||||||
struct image_t **symbol_resolution_images;
|
|
||||||
|
|
||||||
// Singly-linked list of symbol patchers for symbols defined respectively
|
// Singly-linked list of symbol patchers for symbols defined respectively
|
||||||
// referenced by this image.
|
// referenced by this image.
|
||||||
@@ -123,7 +126,6 @@ typedef struct image_queue_t {
|
|||||||
// image_t::flags
|
// image_t::flags
|
||||||
#define IMAGE_FLAG_RTLD_MASK 0x03
|
#define IMAGE_FLAG_RTLD_MASK 0x03
|
||||||
// RTLD_{LAZY,NOW} | RTLD_{LOCAL,GLOBAL}
|
// RTLD_{LAZY,NOW} | RTLD_{LOCAL,GLOBAL}
|
||||||
#define IMAGE_FLAG_R5_SYMBOL_RESOLUTION 0x04
|
|
||||||
|
|
||||||
#define STRING(image, offset) ((char *)(&(image)->strtab[(offset)]))
|
#define STRING(image, offset) ((char *)(&(image)->strtab[(offset)]))
|
||||||
#define SYMNAME(image, sym) STRING(image, (sym)->st_name)
|
#define SYMNAME(image, sym) STRING(image, (sym)->st_name)
|
||||||
|
|||||||
@@ -66,6 +66,9 @@ load_image(int32 argCount, const char **args, const char **environ)
|
|||||||
image_id
|
image_id
|
||||||
load_add_on(char const *name)
|
load_add_on(char const *name)
|
||||||
{
|
{
|
||||||
|
if (name == NULL)
|
||||||
|
return B_BAD_VALUE;
|
||||||
|
|
||||||
return __gRuntimeLoader->load_add_on(name, 0);
|
return __gRuntimeLoader->load_add_on(name, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
|
* Copyright 2008, Ingo Weinhold, [email protected].
|
||||||
* Copyright 2003-2008, Axel Dörfler, [email protected].
|
* Copyright 2003-2008, Axel Dörfler, [email protected].
|
||||||
* Distributed under the terms of the MIT License.
|
* Distributed under the terms of the MIT License.
|
||||||
*
|
*
|
||||||
@@ -23,31 +24,27 @@ static status_t sStatus;
|
|||||||
void *
|
void *
|
||||||
dlopen(char const *name, int mode)
|
dlopen(char const *name, int mode)
|
||||||
{
|
{
|
||||||
// TODO: According to the standard multiple dlopen() invocations for the same
|
void* handle;
|
||||||
// file will cause the object to be loaded once only. That is we should load
|
image_id imageID = __gRuntimeLoader->load_library(name, mode, &handle);
|
||||||
// the object as a library, not an add-on.
|
|
||||||
status_t status;
|
|
||||||
|
|
||||||
if (name == NULL)
|
sStatus = imageID >= 0 ? B_OK : imageID;
|
||||||
name = MAGIC_APP_NAME;
|
|
||||||
|
|
||||||
status = __gRuntimeLoader->load_add_on(name, mode);
|
return imageID >= 0 ? handle : NULL;
|
||||||
sStatus = status;
|
|
||||||
|
|
||||||
if (status < B_OK)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
return (void *)status;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void *
|
void *
|
||||||
dlsym(void *handle, char const *name)
|
dlsym(void *handle, char const *name)
|
||||||
{
|
{
|
||||||
|
void* location;
|
||||||
status_t status;
|
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;
|
sStatus = status;
|
||||||
|
|
||||||
if (status < B_OK)
|
if (status < B_OK)
|
||||||
@@ -60,7 +57,7 @@ dlsym(void *handle, char const *name)
|
|||||||
int
|
int
|
||||||
dlclose(void *handle)
|
dlclose(void *handle)
|
||||||
{
|
{
|
||||||
return unload_add_on((image_id)handle);
|
return __gRuntimeLoader->unload_library(handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -77,6 +74,8 @@ dlerror(void)
|
|||||||
int
|
int
|
||||||
dladdr(void *addr, Dl_info *info)
|
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];
|
char curSymName[NAME_MAX];
|
||||||
static char symName[NAME_MAX];
|
static char symName[NAME_MAX];
|
||||||
static char imageName[MAXPATHLEN];
|
static char imageName[MAXPATHLEN];
|
||||||
|
|||||||
+341
-170
@@ -11,6 +11,7 @@
|
|||||||
#include "runtime_loader_private.h"
|
#include "runtime_loader_private.h"
|
||||||
|
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
|
#include <dlfcn.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
@@ -49,9 +50,14 @@
|
|||||||
#define RLD_PROGRAM_BASE 0x00200000
|
#define RLD_PROGRAM_BASE 0x00200000
|
||||||
/* keep in sync with app ldscript */
|
/* keep in sync with app ldscript */
|
||||||
|
|
||||||
|
// a handle returned by load_library() (dlopen())
|
||||||
|
#define RLD_GLOBAL_SCOPE ((void*)-2l)
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
RFLAG_RW = 0x0001,
|
// the lower two bits are reserved for RTLD_NOW and RTLD_GLOBAL
|
||||||
RFLAG_ANON = 0x0002,
|
|
||||||
|
RFLAG_RW = 0x0010,
|
||||||
|
RFLAG_ANON = 0x0020,
|
||||||
|
|
||||||
RFLAG_TERMINATED = 0x0200,
|
RFLAG_TERMINATED = 0x0200,
|
||||||
RFLAG_INITIALIZED = 0x0400,
|
RFLAG_INITIALIZED = 0x0400,
|
||||||
@@ -61,7 +67,8 @@ enum {
|
|||||||
RFLAG_DEPENDENCIES_LOADED = 0x4000,
|
RFLAG_DEPENDENCIES_LOADED = 0x4000,
|
||||||
RFLAG_REMAPPED = 0x8000,
|
RFLAG_REMAPPED = 0x8000,
|
||||||
|
|
||||||
RFLAG_VISITED = 0x10000
|
RFLAG_VISITED = 0x10000,
|
||||||
|
RFLAG_USE_FOR_RESOLVING = 0x20000
|
||||||
// temporarily set in the symbol resolution code
|
// 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);
|
memset(image->needed, 0xa5, sizeof(image->needed[0]) * image->num_needed);
|
||||||
#endif
|
#endif
|
||||||
free(image->needed);
|
free(image->needed);
|
||||||
free(image->symbol_resolution_images);
|
|
||||||
|
|
||||||
while (RuntimeLoaderSymbolPatcher* patcher
|
while (RuntimeLoaderSymbolPatcher* patcher
|
||||||
= image->defined_symbol_patchers) {
|
= 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
|
static status_t
|
||||||
parse_program_headers(image_t *image, char *buff, int phnum, int phentsize)
|
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*
|
static status_t
|
||||||
find_symbol_in_root_image_list(image_t* rootImage, const char* name,
|
find_symbol_breadth_first(image_t* image, const char* name, int32 type,
|
||||||
image_t** foundInImage)
|
image_t** _foundInImage, void** _location)
|
||||||
{
|
{
|
||||||
int32 count = rootImage->symbol_resolution_image_count;
|
image_t* queue[sLoadedImageCount];
|
||||||
image_t** images = rootImage->symbol_resolution_images;
|
uint32 count = 0;
|
||||||
for (int32 i = 0; i < count; i++) {
|
uint32 index = 0;
|
||||||
image_t* image = images[i];
|
queue[count++] = image;
|
||||||
if (image->dynamic_ptr) {
|
image->flags |= RFLAG_VISITED;
|
||||||
Elf32_Sym* symbol = find_symbol(image, name, B_SYMBOL_TYPE_ANY);
|
|
||||||
if (symbol) {
|
bool found = false;
|
||||||
*foundInImage = image;
|
while (index < count) {
|
||||||
return symbol;
|
// 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*
|
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)
|
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
|
// BeOS style symbol resolution: It is sufficient to check the direct
|
||||||
// dependencies. The linker would have complained, if the symbol wasn't
|
// dependencies. The linker would have complained, if the symbol wasn't
|
||||||
// there.
|
// 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.
|
/*! This function is called when we run BeOS images on Haiku.
|
||||||
It allows us to redirect functions to ensure compatibility.
|
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;
|
type = B_SYMBOL_TYPE_DATA;
|
||||||
|
|
||||||
// it's undefined, must be outside this image, try the other images
|
// it's undefined, must be outside this image, try the other images
|
||||||
sharedSym = find_undefined_symbol(rootImage, image, symName,
|
sharedSym = rootImage->find_undefined_symbol(rootImage, image,
|
||||||
&sharedImage);
|
symName, &sharedImage);
|
||||||
void* location = NULL;
|
void* location = NULL;
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
@@ -1447,7 +1553,8 @@ relocate_image(image_t *rootImage, image_t *image)
|
|||||||
|
|
||||||
|
|
||||||
static status_t
|
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;
|
int32 pheaderSize, sheaderSize;
|
||||||
char path[PATH_MAX];
|
char path[PATH_MAX];
|
||||||
@@ -1593,7 +1700,7 @@ load_container(char const *name, image_type type, const char *rpath, image_t **_
|
|||||||
// unavailable)
|
// unavailable)
|
||||||
if (image->gcc_version.major == 0
|
if (image->gcc_version.major == 0
|
||||||
|| image->gcc_version.major == 2 && image->gcc_version.middle < 95) {
|
|| 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);
|
status = map_image(fd, path, image, type == B_APP_IMAGE);
|
||||||
@@ -1659,7 +1766,7 @@ find_dt_rpath(image_t *image)
|
|||||||
|
|
||||||
|
|
||||||
static status_t
|
static status_t
|
||||||
load_dependencies(image_t *image)
|
load_immediate_dependencies(image_t *image)
|
||||||
{
|
{
|
||||||
struct Elf32_Dyn *d = (struct Elf32_Dyn *)image->dynamic_ptr;
|
struct Elf32_Dyn *d = (struct Elf32_Dyn *)image->dynamic_ptr;
|
||||||
bool reportErrors = report_errors();
|
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
|
static uint32
|
||||||
topological_sort(image_t *image, uint32 slot, image_t **initList,
|
topological_sort(image_t *image, uint32 slot, image_t **initList,
|
||||||
uint32 sortFlag)
|
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
|
static ssize_t
|
||||||
get_sorted_image_list(image_t *image, image_t ***_list, uint32 sortFlag)
|
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
|
static status_t
|
||||||
relocate_dependencies(image_t *image)
|
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
|
// get the images that still have to be relocated
|
||||||
image_t **list;
|
image_t **list;
|
||||||
ssize_t count = get_sorted_image_list(image, &list, RFLAG_RELOCATED);
|
ssize_t count = get_sorted_image_list(image, &list, RFLAG_RELOCATED);
|
||||||
if (count < B_OK)
|
if (count < B_OK)
|
||||||
return count;
|
return count;
|
||||||
|
|
||||||
|
// relocate
|
||||||
for (ssize_t i = 0; i < count; i++) {
|
for (ssize_t i = 0; i < count; i++) {
|
||||||
status_t status = relocate_image(image, list[i]);
|
status_t status = relocate_image(image, list[i]);
|
||||||
if (status < B_OK)
|
if (status < B_OK) {
|
||||||
|
free(list);
|
||||||
return status;
|
return status;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
free(list);
|
free(list);
|
||||||
@@ -1959,12 +1988,10 @@ inject_runtime_loader_api(image_t* rootImage)
|
|||||||
// We patch any exported __gRuntimeLoader symbols to point to our private
|
// We patch any exported __gRuntimeLoader symbols to point to our private
|
||||||
// API.
|
// API.
|
||||||
image_t* image;
|
image_t* image;
|
||||||
Elf32_Sym* symbol = find_symbol_in_root_image_list(rootImage,
|
void* _export;
|
||||||
"__gRuntimeLoader", &image);
|
if (find_symbol_breadth_first(rootImage, "__gRuntimeLoader",
|
||||||
|
B_SYMBOL_TYPE_DATA, &image, &_export) == B_OK) {
|
||||||
if (symbol != NULL) {
|
*(void**)_export = &gRuntimeLoader;
|
||||||
void** _export = (void**)(symbol->st_value + image->regions[0].delta);
|
|
||||||
*_export = &gRuntimeLoader;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2003,12 +2030,14 @@ preload_image(char const* path)
|
|||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (image_t* otherImage = sLoadedImages.head; otherImage != NULL;
|
if (image->find_undefined_symbol == NULL)
|
||||||
otherImage = otherImage->next) {
|
image->find_undefined_symbol = find_undefined_symbol_global;
|
||||||
status = load_dependencies(otherImage);
|
|
||||||
if (status < B_OK)
|
status = load_dependencies(image);
|
||||||
goto err;
|
if (status < B_OK)
|
||||||
}
|
goto err;
|
||||||
|
|
||||||
|
set_image_flags_recursively(image, RTLD_GLOBAL);
|
||||||
|
|
||||||
status = relocate_dependencies(image);
|
status = relocate_dependencies(image);
|
||||||
if (status < B_OK)
|
if (status < B_OK)
|
||||||
@@ -2105,11 +2134,17 @@ load_program(char const *path, void **_entry)
|
|||||||
if (status < B_OK)
|
if (status < B_OK)
|
||||||
goto err;
|
goto err;
|
||||||
|
|
||||||
for (image = sLoadedImages.head; image != NULL; image = image->next) {
|
if (sProgramImage->find_undefined_symbol == NULL)
|
||||||
status = load_dependencies(image);
|
sProgramImage->find_undefined_symbol = find_undefined_symbol_global;
|
||||||
if (status < B_OK)
|
|
||||||
goto err;
|
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);
|
status = relocate_dependencies(sProgramImage);
|
||||||
if (status < B_OK)
|
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
|
// Since the images are initialized now, we no longer should use our
|
||||||
// getenv(), but use the one from libroot.so
|
// getenv(), but use the one from libroot.so
|
||||||
{
|
find_symbol_breadth_first(sProgramImage, "getenv", B_SYMBOL_TYPE_TEXT,
|
||||||
struct Elf32_Sym *symbol = find_symbol_in_root_image_list(sProgramImage,
|
&image, (void**)&gGetEnv);
|
||||||
"getenv", &image);
|
|
||||||
|
|
||||||
if (symbol != NULL)
|
|
||||||
gGetEnv = (char* (*)(const char*))
|
|
||||||
(symbol->st_value + image->regions[0].delta);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sProgramImage->entry_point == 0) {
|
if (sProgramImage->entry_point == 0) {
|
||||||
status = B_NOT_AN_EXECUTABLE;
|
status = B_NOT_AN_EXECUTABLE;
|
||||||
@@ -2169,19 +2198,15 @@ err:
|
|||||||
|
|
||||||
|
|
||||||
image_id
|
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 *image = NULL;
|
||||||
image_t *iter;
|
|
||||||
image_type type = (addOn ? B_ADD_ON_IMAGE : B_LIBRARY_IMAGE);
|
image_type type = (addOn ? B_ADD_ON_IMAGE : B_LIBRARY_IMAGE);
|
||||||
status_t status;
|
status_t status;
|
||||||
|
|
||||||
if (path == NULL)
|
if (path == NULL && addOn)
|
||||||
return B_BAD_VALUE;
|
return B_BAD_VALUE;
|
||||||
|
|
||||||
// ToDo: implement flags
|
|
||||||
(void)flags;
|
|
||||||
|
|
||||||
KTRACE("rld: load_library(\"%s\", 0x%lx, %d)", path, flags, addOn);
|
KTRACE("rld: load_library(\"%s\", 0x%lx, %d)", path, flags, addOn);
|
||||||
|
|
||||||
rld_lock();
|
rld_lock();
|
||||||
@@ -2190,12 +2215,23 @@ load_library(char const *path, uint32 flags, bool addOn)
|
|||||||
// have we already loaded this library?
|
// have we already loaded this library?
|
||||||
// Checking it at this stage saves loading its dependencies again
|
// Checking it at this stage saves loading its dependencies again
|
||||||
if (!addOn) {
|
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);
|
image = find_image(path, APP_OR_LIBRARY_TYPE);
|
||||||
|
if (image != NULL && (flags & RTLD_GLOBAL) != 0)
|
||||||
|
set_image_flags_recursively(image, RTLD_GLOBAL);
|
||||||
|
|
||||||
if (image) {
|
if (image) {
|
||||||
atomic_add(&image->ref_count, 1);
|
atomic_add(&image->ref_count, 1);
|
||||||
rld_unlock();
|
rld_unlock();
|
||||||
KTRACE("rld: load_library(\"%s\"): already loaded: %ld", path,
|
KTRACE("rld: load_library(\"%s\"): already loaded: %ld", path,
|
||||||
image->id);
|
image->id);
|
||||||
|
*_handle = image;
|
||||||
return image->id;
|
return image->id;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2208,16 +2244,33 @@ load_library(char const *path, uint32 flags, bool addOn)
|
|||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (iter = sLoadedImages.head; iter; iter = iter->next) {
|
if (image->find_undefined_symbol == NULL) {
|
||||||
status = load_dependencies(iter);
|
if (addOn)
|
||||||
if (status < B_OK)
|
image->find_undefined_symbol = find_undefined_symbol_add_on;
|
||||||
goto err;
|
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);
|
status = relocate_dependencies(image);
|
||||||
if (status < B_OK)
|
if (status < B_OK)
|
||||||
goto err;
|
goto err;
|
||||||
|
|
||||||
|
if ((flags & RTLD_GLOBAL) == 0)
|
||||||
|
clear_image_flags_recursively(image, RFLAG_USE_FOR_RESOLVING);
|
||||||
|
|
||||||
remap_images();
|
remap_images();
|
||||||
init_dependencies(image, true);
|
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);
|
KTRACE("rld: load_library(\"%s\") done: id: %ld", path, image->id);
|
||||||
|
|
||||||
|
*_handle = image;
|
||||||
return image->id;
|
return image->id;
|
||||||
|
|
||||||
err:
|
err:
|
||||||
@@ -2239,15 +2293,18 @@ err:
|
|||||||
|
|
||||||
|
|
||||||
status_t
|
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;
|
status_t status = B_BAD_IMAGE_ID;
|
||||||
image_t *image;
|
image_t *image;
|
||||||
image_type type = addOn ? B_ADD_ON_IMAGE : B_LIBRARY_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;
|
return B_BAD_IMAGE_ID;
|
||||||
|
|
||||||
|
if (handle == RLD_GLOBAL_SCOPE)
|
||||||
|
return B_OK;
|
||||||
|
|
||||||
rld_lock();
|
rld_lock();
|
||||||
// for now, just do stupid simple global locking
|
// 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
|
// we only check images that have been already initialized
|
||||||
|
|
||||||
for (image = sLoadedImages.head; image; image = image->next) {
|
if (handle != NULL) {
|
||||||
if (image->id == imageID) {
|
image = (image_t*)handle;
|
||||||
// unload image
|
put_image(image);
|
||||||
if (type == image->type) {
|
} else {
|
||||||
put_image(image);
|
for (image = sLoadedImages.head; image; image = image->next) {
|
||||||
status = B_OK;
|
if (image->id == imageID) {
|
||||||
} else
|
// unload image
|
||||||
status = B_BAD_VALUE;
|
if (type == image->type) {
|
||||||
break;
|
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
|
status_t
|
||||||
get_next_image_dependency(image_id id, uint32 *cookie, const char **_name)
|
get_next_image_dependency(image_id id, uint32 *cookie, const char **_name)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -16,14 +16,29 @@
|
|||||||
static image_id
|
static image_id
|
||||||
export_load_add_on(char const *name, uint32 flags)
|
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
|
static status_t
|
||||||
export_unload_add_on(image_id id)
|
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
|
// dynamic loading support API
|
||||||
export_load_add_on,
|
export_load_add_on,
|
||||||
export_unload_add_on,
|
export_unload_add_on,
|
||||||
|
export_load_library,
|
||||||
|
export_unload_library,
|
||||||
get_symbol,
|
get_symbol,
|
||||||
|
get_library_symbol,
|
||||||
get_nth_symbol,
|
get_nth_symbol,
|
||||||
test_executable,
|
test_executable,
|
||||||
get_next_image_dependency,
|
get_next_image_dependency,
|
||||||
|
|||||||
@@ -240,8 +240,22 @@ open_executable(char *name, image_type type, const char *rpath,
|
|||||||
memmove(name, paths, strlen(paths) + 1);
|
memmove(name, paths, strlen(paths) + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// first try rpath (DT_RPATH)
|
// let's evaluate the system path variables to find the container
|
||||||
if (rpath) {
|
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
|
// It consists of a colon-separated search path list. Optionally it
|
||||||
// follows a second search path list, separated from the first by a
|
// follows a second search path list, separated from the first by a
|
||||||
// semicolon.
|
// 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) {
|
if (fd >= 0) {
|
||||||
// we found it, copy path!
|
// we found it, copy path!
|
||||||
TRACE(("runtime_loader: open_executable(%s): found at %s\n", name, buffer));
|
TRACE(("runtime_loader: open_executable(%s): found at %s\n", name, buffer));
|
||||||
|
|||||||
@@ -29,12 +29,15 @@ status_t test_executable(const char *path, char *interpreter);
|
|||||||
|
|
||||||
void terminate_program(void);
|
void terminate_program(void);
|
||||||
image_id load_program(char const *path, void **entry);
|
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,
|
status_t get_nth_symbol(image_id imageID, int32 num, char *nameBuffer,
|
||||||
int32 *_nameLength, int32 *_type, void **_location);
|
int32 *_nameLength, int32 *_type, void **_location);
|
||||||
status_t get_symbol(image_id imageID, char const *symbolName, int32 symbolType,
|
status_t get_symbol(image_id imageID, char const *symbolName, int32 symbolType,
|
||||||
void **_location);
|
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,
|
status_t get_next_image_dependency(image_id id, uint32 *cookie,
|
||||||
const char **_name);
|
const char **_name);
|
||||||
int resolve_symbol(image_t *rootImage, image_t *image, struct Elf32_Sym *sym,
|
int resolve_symbol(image_t *rootImage, image_t *image, struct Elf32_Sym *sym,
|
||||||
|
|||||||
Reference in New Issue
Block a user