Skip to content

Commit ee05371

Browse files
committed
Add LBT_USE_RTLD_DEEPBIND capability
Certain tools such as sanitizers don't like us loading libraries with `RTLD_DEEPBIND`, so since we already have the workarounds in place for systems that don't have `RTLD_DEEPBIND` at all, let's change these from using compile-time constants to instead use a runtime switch that can be overridden through setting the environment variable `LBT_USE_RTLD_DEEPBIND=0` before running our program.
1 parent 1bd5437 commit ee05371

File tree

8 files changed

+67
-22
lines changed

8 files changed

+67
-22
lines changed

src/Make.inc

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,10 @@ ifeq ($(OS),Linux)
4040
LDFLAGS += -ldl
4141
# We also want `-fvisibility=protected` on Linux, to match other platforms
4242
CFLAGS += -fvisibility=protected
43+
# There are bugs with `-fvisibility=protected` and certain versions of `ld`,
44+
# see https://sourceware.org/bugzilla/show_bug.cgi?id=26815 for more
45+
# We work around this by using `gold` on Linux
46+
LDFLAGS += -fuse-ld=gold
4347
endif
4448
4549
ifeq ($(OS),WINNT)

src/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ include $(LBT_ROOT)/src/Make.inc
55
all: $(builddir)/libblastrampoline.$(SHLIB_EXT)
66

77
# Objects we'll build
8-
MAIN_OBJS := libblastrampoline.o dl_utils.o config.o autodetection.o threading.o deepbindless_surrogates.o trampolines/trampolines_$(ARCH).o
8+
MAIN_OBJS := libblastrampoline.o dl_utils.o config.o autodetection.o threading.o deepbindless.o trampolines/trampolines_$(ARCH).o
99

1010
# Include win_utils.c on windws
1111
ifeq ($(OS),WINNT)

src/autodetection.c

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -46,13 +46,15 @@ int32_t autodetect_blas_interface(void * isamax_addr) {
4646
int64_t incx = 1;
4747

4848
// Override `lsame_` to point to our `fake_lsame` if we're unable to `RTLD_DEEPBIND`
49-
#ifdef LBT_DEEPBINDLESS
50-
push_fake_lsame();
51-
#endif
49+
if (use_deepbind == 0) {
50+
push_fake_lsame();
51+
}
52+
5253
int64_t max_idx = isamax(&n, X, &incx);
53-
#ifdef LBT_DEEPBINDLESS
54-
pop_fake_lsame();
55-
#endif
54+
55+
if (use_deepbind == 0) {
56+
pop_fake_lsame();
57+
}
5658

5759
// Although we declare that `isamax` returns an `int64_t`, it may not actually do so,
5860
// since if it's an LP64 binary it's probably returning an `int32_t`. Depending on the

src/deepbindless_surrogates.c renamed to src/deepbindless.c

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,20 @@
11
#include "libblastrampoline_internal.h"
22

3-
#if defined(LBT_DEEPBINDLESS)
3+
/*
4+
* Users can force an RTLD_DEEPBIND-capable system to avoid using RTLD_DEEPBIND
5+
* by setting `LBT_USE_RTLD_DEEPBIND=0` in their environment. This function
6+
* returns `0x01` if it will use `RTLD_DEEPBIND` when loading a library, and
7+
* `0x00` otherwise.
8+
*/
9+
#if defined(LBT_DEEPBINDLESS) || !defined(RTLD_DEEPBIND)
10+
uint8_t use_deepbind = 0x00;
11+
#else
12+
uint8_t use_deepbind = 0x01;
13+
#endif
14+
LBT_DLLEXPORT const uint8_t lbt_get_use_deepbind() {
15+
return use_deepbind;
16+
}
17+
418

519
int lsame_idx = -1;
620
const void *old_lsame32 = NULL, *old_lsame64 = NULL;
@@ -76,5 +90,3 @@ int fake_lsame(char * ca, char * cb) {
7690
}
7791
return inta == intb;
7892
}
79-
80-
#endif // LBT_DEEPBINDLESS

src/dl_utils.c

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ void throw_dl_error(const char * path) {
2222

2323
/*
2424
* Load the given `path`, using `RTLD_NOW | RTLD_LOCAL` and `RTLD_DEEPBIND`, if available
25+
* If `use_deepbind` is set to `0`, don't use `RTLD_DEEPBIND` even if it's available.
2526
*/
2627
void * load_library(const char * path) {
2728
void * new_handle = NULL;
@@ -34,13 +35,21 @@ void * load_library(const char * path) {
3435
}
3536
new_handle = (void *)LoadLibraryExW(wpath, NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
3637
#else
37-
// If we have `RTLD_DEEPBIND`, use it!
38+
39+
// If `use_deepbind` is set to `0`, we voluntarily avoid using
40+
// `RTLD_DEEPBIND` even if it's available. This is primarily used
41+
// in conjunction with sanitizer tools, which abhor the presence of
42+
// deepbound libraries.
43+
if (use_deepbind == 0) {
44+
new_handle = dlopen(path, RTLD_NOW | RTLD_LOCAL);
45+
}
3846
#if defined(RTLD_DEEPBIND)
39-
new_handle = dlopen(path, RTLD_NOW | RTLD_LOCAL | RTLD_DEEPBIND);
40-
#else
41-
new_handle = dlopen(path, RTLD_NOW | RTLD_LOCAL);
42-
#endif
47+
else {
48+
new_handle = dlopen(path, RTLD_NOW | RTLD_LOCAL | RTLD_DEEPBIND);
49+
}
4350
#endif
51+
#endif // defined(_OS_WINDOWS_)
52+
4453
if (new_handle == NULL) {
4554
throw_dl_error(path);
4655
}

src/libblastrampoline.c

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ int32_t set_forward_by_index(int32_t symbol_idx, const void * addr, int32_t inte
5252
} else {
5353
(*exported_func64_addrs[symbol_idx]) = addr;
5454

55-
// If we're on an RTLD_DEEPBINDless system and our workaround is activated,
55+
// If we're on an RTLD_DEEPBIND-less system and our workaround is activated,
5656
// we take over our own 32-bit symbols as well.
5757
if (deepbindless_interfaces_loaded & DEEPBINDLESS_INTERFACE_ILP64_LOADED) {
5858
(*exported_func32_addrs[symbol_idx]) = addr;
@@ -230,7 +230,7 @@ LBT_DLLEXPORT int32_t lbt_forward(const char * libname, int32_t clear, int32_t v
230230
* attempts to load another one without setting the `clear` flag, we refuse to
231231
* load it on a deepbindless system, printing out to `stderr` if we're verbose.
232232
*/
233-
#if defined(LBT_DEEPBINDLESS)
233+
234234
// If `clear` is set, we clear our tracking
235235
if (clear) {
236236
deepbindless_interfaces_loaded = 0x00;
@@ -240,13 +240,13 @@ LBT_DLLEXPORT int32_t lbt_forward(const char * libname, int32_t clear, int32_t v
240240
// we bind to the suffix-"" names, so even if the names of that library
241241
// internally are suffixed to something else, we ourselves will interfere with
242242
// a future suffix-"" ILP64 BLAS.
243-
if (interface == LBT_INTERFACE_LP64) {
243+
if ((use_deepbind == 0x00) && (interface == LBT_INTERFACE_LP64)) {
244244
deepbindless_interfaces_loaded |= DEEPBINDLESS_INTERFACE_LP64_LOADED;
245245
}
246246

247247
// We only mark a loaded ILP64 BLAS if it is a suffix-"" BLAS, since that is
248248
// the only case in which it will interfere with our LP64 BLAS symbols.
249-
if (lib_suffix[0] == '\0' && interface == LBT_INTERFACE_ILP64) {
249+
if ((use_deepbind == 0x00) && (lib_suffix[0] == '\0' && interface == LBT_INTERFACE_ILP64)) {
250250
deepbindless_interfaces_loaded |= DEEPBINDLESS_INTERFACE_ILP64_LOADED;
251251
}
252252

@@ -257,7 +257,6 @@ LBT_DLLEXPORT int32_t lbt_forward(const char * libname, int32_t clear, int32_t v
257257
}
258258
return 0;
259259
}
260-
#endif
261260

262261
// If `clear` is set, drop all information about previously-loaded libraries
263262
if (clear) {
@@ -307,6 +306,19 @@ __attribute__((constructor)) void init(void) {
307306
printf("libblastrampoline initializing\n");
308307
}
309308

309+
#if !defined(LBT_DEEPBINDLESS)
310+
// If LBT_USE_RTLD_DEEPBIND == "0", we avoid using RTLD_DEEPBIND on a
311+
// deepbind-capable system. This is mostly useful for sanitizers, which
312+
// abhor such library loading shenanigans.
313+
const char * deepbindless_str = getenv("LBT_USE_RTLD_DEEPBIND");
314+
if (deepbindless_str != NULL && strcmp(deepbindless_str, "0") == 0) {
315+
use_deepbind = 0x00;
316+
if (verbose) {
317+
printf("LBT_USE_RTLD_DEEPBIND=0 detected; avoiding usage of RTLD_DEEPBIND\n");
318+
}
319+
}
320+
#endif // !defined(LBT_DEEPBINDLESS)
321+
310322
// LBT_DEFAULT_LIBS is a semicolon-separated list of paths that should be loaded as BLAS libraries
311323
const char * default_libs = getenv("LBT_DEFAULT_LIBS");
312324
if (default_libs != NULL) {

src/libblastrampoline.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,13 @@ LBT_DLLEXPORT void lbt_default_func_print_error();
161161
*/
162162
LBT_DLLEXPORT const void * lbt_get_default_func();
163163

164+
/*
165+
* Users can force an RTLD_DEEPBIND-capable system to avoid using RTLD_DEEPBIND by setting
166+
* `LBT_USE_RTLD_DEEPBIND=0` in their environment. This function returns `0x01` if it will
167+
* use `RTLD_DEEPBIND` when loading a library, and `0x00` otherwise.
168+
*/
169+
LBT_DLLEXPORT const uint8_t lbt_get_use_deepbind();
170+
164171
/*
165172
* Sets the default function that gets called if no mapping has been set for an exported symbol.
166173
* `NULL` is a valid address, if a segfault upon calling an uninitialized function is desirable.

src/libblastrampoline_internal.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,9 +82,8 @@ int32_t autodetect_interface(void * handle, const char * suffix);
8282
int autodetect_f2c(void * handle, const char * suffix);
8383
#endif
8484

85-
#ifdef LBT_DEEPBINDLESS
8685
// Functions in deepbindless_surrogates.c
8786
void push_fake_lsame();
8887
void pop_fake_lsame();
8988
int fake_lsame(char * ca, char * cb);
90-
#endif
89+
extern uint8_t use_deepbind;

0 commit comments

Comments
 (0)