runtime_loader: Implement DT_RUNPATH

DT_RUNPATH is generated by the linker instead of DT_RPATH when using --enable-new-dtags
It seems to be the default when using ld.lld
Normally one difference is LD_LIBRARY_PATH is checked before DT_RUNPATH (and not with DT_RPATH),
but we don't check LD_LIBRARY_PATH at the moment. Checking LIBRARY_PATH isn't an option, because
runtime_loader dosesn't use default paths, test suites would define LIBRARY_PATH empty.
Tested with tcpdump build_matrix.sh script, with clang 17, local libpcap, which requires
--disable-new-dtags on r1beta4.

Change-Id: Iacccde8d20e25ad14c5c548dd8832ea32b67e228
Reviewed-on: https://review.haiku-os.org/c/haiku/+/7539
Reviewed-by: waddlesplash <waddlesplash@gmail.com>
Tested-by: Commit checker robot <no-reply+buildbot@haiku-os.org>
This commit is contained in:
Jérôme Duval 2024-03-21 16:49:39 +01:00 committed by waddlesplash
parent 76142a9377
commit 43d1a0dc3c
5 changed files with 47 additions and 27 deletions

View File

@ -54,13 +54,13 @@ static recursive_lock sLock = RECURSIVE_LOCK_INITIALIZER(kLockName);
static const char *
find_dt_rpath(image_t *image)
find_dt_string(image_t *image, int32 d_tag)
{
int i;
elf_dyn *d = (elf_dyn *)image->dynamic_ptr;
for (i = 0; d[i].d_tag != DT_NULL; i++) {
if (d[i].d_tag == DT_RPATH)
if (d[i].d_tag == d_tag)
return STRING(image, d[i].d_un.d_val);
}
@ -68,6 +68,20 @@ find_dt_rpath(image_t *image)
}
static const char *
find_dt_rpath(image_t *image)
{
return find_dt_string(image, DT_RPATH);
}
static const char *
find_dt_runpath(image_t *image)
{
return find_dt_string(image, DT_RUNPATH);
}
image_id
preload_image(char const* path, image_t **image)
{
@ -76,7 +90,7 @@ preload_image(char const* path, image_t **image)
KTRACE("rld: preload_image(\"%s\")", path);
status_t status = load_image(path, B_LIBRARY_IMAGE, NULL, NULL, image);
status_t status = load_image(path, B_LIBRARY_IMAGE, NULL, NULL, NULL, image);
if (status < B_OK) {
KTRACE("rld: preload_image(\"%s\") failed to load container: %s", path,
strerror(status));
@ -148,8 +162,7 @@ load_immediate_dependencies(image_t *image, bool preload)
bool reportErrors = report_errors();
status_t status = B_OK;
uint32 i, j;
const char *rpath;
const char *rpath = NULL, *runpath;
if (!d || (image->flags & RFLAG_DEPENDENCIES_LOADED))
return B_OK;
@ -177,7 +190,9 @@ load_immediate_dependencies(image_t *image, bool preload)
memset(image->needed, 0, image->num_needed * sizeof(image_t *));
if (preload)
preload_images(image->needed);
rpath = find_dt_rpath(image);
runpath = find_dt_runpath(image);
if (runpath == NULL)
rpath = find_dt_rpath(image);
for (i = 0, j = preloadedCount; d[i].d_tag != DT_NULL; i++) {
switch (d[i].d_tag) {
@ -187,7 +202,7 @@ load_immediate_dependencies(image_t *image, bool preload)
const char *name = STRING(image, neededOffset);
status_t loadStatus = load_image(name, B_LIBRARY_IMAGE,
rpath, image->path, &image->needed[j]);
rpath, runpath, image->path, &image->needed[j]);
if (loadStatus < B_OK) {
status = loadStatus;
// correct error code in case the file could not been found
@ -433,7 +448,7 @@ preload_addon(char const* path)
KTRACE("rld: preload_addon(\"%s\")", path);
image_t *image = NULL;
status_t status = load_image(path, B_LIBRARY_IMAGE, NULL, NULL, &image);
status_t status = load_image(path, B_LIBRARY_IMAGE, NULL, NULL, NULL, &image);
if (status < B_OK) {
KTRACE("rld: preload_addon(\"%s\") failed to load container: %s", path,
strerror(status));
@ -535,7 +550,7 @@ load_program(char const *path, void **_entry)
TRACE(("rld: load %s\n", path));
status = load_image(path, B_APP_IMAGE, NULL, NULL, &gProgramImage);
status = load_image(path, B_APP_IMAGE, NULL, NULL, NULL, &gProgramImage);
if (status < B_OK)
goto err;
@ -606,7 +621,7 @@ load_library(char const *path, uint32 flags, bool addOn, void* caller,
image_t *image = NULL;
image_type type = (addOn ? B_ADD_ON_IMAGE : B_LIBRARY_IMAGE);
status_t status;
const char* rpath = NULL;
const char* rpath = NULL, *runpath = NULL;
const char* requestingObjectPath = NULL;
if (path == NULL && addOn)
@ -649,12 +664,14 @@ load_library(char const *path, uint32 flags, bool addOn, void* caller,
}
}
if (callerImage != NULL) {
rpath = find_dt_rpath(callerImage);
runpath = find_dt_runpath(callerImage);
if (runpath == NULL)
rpath = find_dt_rpath(callerImage);
requestingObjectPath = callerImage->path;
}
}
status = load_image(path, type, rpath, requestingObjectPath, &image);
status = load_image(path, type, rpath, runpath, requestingObjectPath, &image);
if (status < B_OK) {
KTRACE("rld: load_library(\"%s\") failed to load container: %s", path,
strerror(status));

View File

@ -389,7 +389,6 @@ parse_dynamic_segment(image_t* image)
// DT_SYMENT: The size of a symbol table entry.
// DT_PLTREL: The type of the PLT relocation entries (DT_JMPREL).
// DT_BIND_NOW/DF_BIND_NOW: No lazy binding allowed.
// DT_RUNPATH: Library search path (supersedes DT_RPATH).
// DT_TEXTREL/DF_TEXTREL: Indicates whether text relocations are
// required (for optimization purposes only).
}
@ -491,7 +490,7 @@ parse_elf64_header(Elf64_Ehdr* eheader, int32* _pheaderSize,
status_t
load_image(char const* name, image_type type, const char* rpath,
load_image(char const* name, image_type type, const char* rpath, const char* runpath,
const char* requestingObjectPath, image_t** _image)
{
int32 pheaderSize, sheaderSize;
@ -523,19 +522,20 @@ load_image(char const* name, image_type type, const char* rpath,
if (found) {
atomic_add(&found->ref_count, 1);
*_image = found;
KTRACE("rld: load_container(\"%s\", type: %d, rpath: \"%s\") "
"already loaded", name, type, rpath);
KTRACE("rld: load_container(\"%s\", type: %d, %s: \"%s\") "
"already loaded", name, type,
runpath != NULL ? "runpath" : "rpath", runpath != NULL ? runpath : rpath);
return B_OK;
}
}
KTRACE("rld: load_container(\"%s\", type: %d, rpath: \"%s\")", name, type,
rpath);
KTRACE("rld: load_container(\"%s\", type: %d, %s: \"%s\")", name, type,
runpath != NULL ? "runpath" : "rpath", runpath != NULL ? runpath : rpath);
strlcpy(path, name, sizeof(path));
// find and open the file
fd = open_executable(path, type, rpath, get_program_path(),
fd = open_executable(path, type, rpath, runpath, get_program_path(),
requestingObjectPath, sSearchPathSubDir);
if (fd < 0) {
FATAL("Cannot open file %s (needed by %s): %s\n", name, requestingObjectPath, strerror(fd));

View File

@ -20,7 +20,7 @@ status_t parse_elf64_header(Elf64_Ehdr* eheader, int32* _pheaderSize,
#endif
#endif
status_t load_image(char const* name, image_type type, const char* rpath,
const char* requestingObjectPath, image_t** _image);
const char* runpath, const char* requestingObjectPath, image_t** _image);
#endif // ELF_LOAD_IMAGE_H

View File

@ -299,7 +299,7 @@ search_executable_in_path_list(const char *name, const char *pathList,
int
open_executable(char *name, image_type type, const char *rpath,
open_executable(char *name, image_type type, const char *rpath, const char* runpath,
const char *programPath, const char *requestingObjectPath,
const char *abiSpecificSubDir)
{
@ -328,14 +328,17 @@ open_executable(char *name, image_type type, const char *rpath,
}
}
// try rpath (DT_RPATH)
if (rpath != NULL) {
// try runpath or rpath (DT_RUNPATH or DT_RPATH)
const char* pathString = runpath;
if (pathString == NULL)
pathString = rpath;
if (pathString != NULL) {
// It consists of a colon-separated search path list. Optionally a
// second search path list follows, separated from the first by a
// semicolon.
const char *semicolon = strchr(rpath, ';');
const char *firstList = (semicolon ? rpath : NULL);
const char *secondList = (semicolon ? semicolon + 1 : rpath);
const char *firstList = (semicolon ? pathString : NULL);
const char *secondList = (semicolon ? semicolon + 1 : pathString);
// If there is no ';', we set only secondList to simplify things.
if (firstList) {
fd = search_executable_in_path_list(name, firstList,
@ -404,7 +407,7 @@ test_executable(const char *name, char *invoker)
strlcpy(path, name, sizeof(path));
fd = open_executable(path, B_APP_IMAGE, NULL, NULL, NULL, NULL);
fd = open_executable(path, B_APP_IMAGE, NULL, NULL, NULL, NULL, NULL);
if (fd < B_OK)
return fd;

View File

@ -63,7 +63,7 @@ extern "C" {
int runtime_loader(void* arg, void* commpage);
int open_executable(char* name, image_type type, const char* rpath,
const char* programPath, const char* requestingObjectPath,
const char* runpath, const char* programPath, const char* requestingObjectPath,
const char* abiSpecificSubDir);
status_t test_executable(const char* path, char* interpreter);
status_t get_executable_architecture(const char* path,