runtime_loader: Add support for RTLD_NOLOAD

Add support for using `RTLD_NOLOAD` with `dlopen` on Haiku.

While not specified in POSIX, this option is widely available (both
GNU/Linux and BSD) and is the only way to atomically check if a shared
object has been loaded.

Change-Id: I061332307d76c84f6a2abb6f92c4ed964bd90a1e
Reviewed-on: https://review.haiku-os.org/c/haiku/+/9161
Reviewed-by: waddlesplash <[email protected]>
Tested-by: Commit checker robot <[email protected]>
Reviewed-by: Jérôme Duval <[email protected]>
This commit is contained in:
Trung Nguyen
2025-04-14 16:31:59 +00:00
committed by waddlesplash
parent a1e94e45fc
commit 8da9c85cbf
4 changed files with 80 additions and 0 deletions
+1
View File
@@ -13,6 +13,7 @@
#define RTLD_NOW 1 /* the file gets relocated at load time */ #define RTLD_NOW 1 /* the file gets relocated at load time */
#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 */
#define RTLD_NOLOAD 4 /* do not load any new object */
/* not-yet-POSIX extensions (dlsym() handles) */ /* not-yet-POSIX extensions (dlsym() handles) */
#define RTLD_DEFAULT ((void*)0) #define RTLD_DEFAULT ((void*)0)
+2
View File
@@ -651,6 +651,8 @@ load_library(char const *path, uint32 flags, bool addOn, void* caller,
path, image->id); path, image->id);
*_handle = image; *_handle = image;
return image->id; return image->id;
} else if ((flags & RTLD_NOLOAD) != 0) {
return B_NAME_NOT_FOUND;
} }
// First of all, find the caller image. // First of all, find the caller image.
@@ -0,0 +1,76 @@
#!/bin/sh
# program
#
# dlopen():
# liba.so (no load)
# liba.so
# liba.so (no load)
#
# Expected: First attempt fails, next two attemps succeed,
# returning the same handles.
. ./test_setup
# create liba.so
cat > liba.c << EOI
int a() { return 42; }
EOI
# build
compile_lib -o liba.so liba.c
# create program
cat > program.c << EOI
#include <dlfcn.h>
#include <stdio.h>
#include <stdlib.h>
int
main()
{
void* liba_fail;
void* liba_1;
void* liba_2;
int (*a)();
liba_fail = dlopen("liba.so", RTLD_LOCAL | RTLD_LAZY | RTLD_NOLOAD);
if (liba_fail != NULL) {
fprintf(stderr, "dlopen() succeeded unexpectedly for non-loaded object");
exit(117);
}
liba_1 = dlopen("liba.so", RTLD_LOCAL | RTLD_LAZY);
if (liba_1 == NULL) {
fprintf(stderr, "Error opening liba.so: %s\n", dlerror());
exit(116);
}
liba_2 = dlopen("liba.so", RTLD_GLOBAL | RTLD_LAZY | RTLD_NOLOAD);
if (liba_2 == NULL) {
fprintf(stderr, "Error opening liba.so: %s\n", dlerror());
exit(115);
}
if (liba_1 != liba_2) {
fprintf(stderr, "dlopen() returned different handles for the same object");
exit(114);
}
a = (int (*)())dlsym(liba_2, "a");
if (a == NULL) {
fprintf(stderr, "Error getting symbol a: %s\n", dlerror());
exit(113);
}
return a();
}
EOI
# build
compile_program_dl -o program program.c
# run
test_run_ok ./program 42
@@ -7,6 +7,7 @@ for test in \
load_resolve_order2 \ load_resolve_order2 \
load_resolve_order3 \ load_resolve_order3 \
load_resolve_order4 \ load_resolve_order4 \
dlopen_noload1 \
dlopen_resolve_basic1 \ dlopen_resolve_basic1 \
dlopen_resolve_basic2 \ dlopen_resolve_basic2 \
dlopen_resolve_basic3 \ dlopen_resolve_basic3 \