See the comment at https://bugs.winehq.org/show_bug.cgi?id=50257#c20 for context. % cat weak_sym_override_test.c #include <assert.h> #include <dlfcn.h> #include <stdlib.h> #include <stdio.h> #if SHLIB void* calloc(size_t number, size_t size) { printf("libc called\n"); exit(1); } #else int main() { assert(dlopen("override.so", RTLD_NOW) != NULL); setenv("WHATEVER", "1", 0); // uses calloc internally return 0; } #endif % cc -shared -fPIC -DSHLIB weak_sym_override_test.c -o override.so && cc weak_sym_override_test.c -Wl,-rpath,. -o test % ./test libc called Doesn't happen with LD_BIND_NOW=1. No idea how that works on Linux, glibc consistently avoids calling weak symbols it exports, preferring internal versions prefixed with with __ (two underscores) instead, thus there is no obvious way to test it.
Yes this is really a libc problem, not rtld. We do not use internal namespace consistently. OTOH for malloc(3) related functions, I suspect the decision was deliberate to make it possible to interpose system implementation with any other user provided with LD_PRELOAD.
> OTOH for malloc(3) related functions, I suspect the decision was deliberate to make it possible to interpose system implementation with any other user provided with LD_PRELOAD. Well, I tested (before filling the bug) whether this works in general and, as expected, it doesn't: % cat weak_sym_override_test2.c #include <assert.h> #include <dlfcn.h> #include <stdlib.h> #include <stdio.h> #if defined(ORIG) void __attribute__((weak)) test() { printf("original\n"); } void wrapper() { test(); } #elif defined(OVERRIDE) void test() { printf("override\n"); } #else extern void wrapper(); int main() { assert(dlopen("override.so", RTLD_NOW) != NULL); wrapper(); return 0; } #endif % cc -shared -fPIC -DORIG weak_sym_override_test2.c -o orig.so % cc -shared -fPIC -DOVERRIDE weak_sym_override_test2.c -o override.so % cc weak_sym_override_test2.c orig.so -Wl,-rpath,. -o test % ./test original Did I miss some compilation flags or something? How do I deliberately get this effect?
You need to LD_PRELOAD your interposer, I noted it in my comment #1. solo% LD_PRELOAD=./override.so ./test override In your example, dlopened object would be added at the end of the global list and in fact its symbols are interposed by the objects loaded at startup, i.e. the effect is reverse. (And your example misses RTLD_GLOBAL, but does not matter much).
A commit in branch main references this bug: URL: https://cgit.FreeBSD.org/ports/commit/?id=1d2af6e08958ac78de9fae727283ac8cdaf8705f commit 1d2af6e08958ac78de9fae727283ac8cdaf8705f Author: Alex S <iwtcex@gmail.com> AuthorDate: 2021-07-26 09:06:49 +0000 Commit: Gerald Pfeifer <gerald@FreeBSD.org> CommitDate: 2021-07-26 09:10:27 +0000 emulators/wine: Invoke with LD_BIND_NOW and revampe WoW Wine 6.0 and later need LD_BIND_NOW / LD_32_BIND_NOW on FreeBSD, cf. https://bugs.winehq.org/show_bug.cgi?id=50257 and https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=252307 so move the actual binaries to wine64.bin / wine.bin and invoke them via a script that does those settings. Also revamp the WoW handling/packging which combines 32-bit/i386 Wine into 64-bit/amd64 Wine. Submitted by: Alex S <iwtcex@gmail.com> PR: 257284, 252307 emulators/wine/Makefile | 10 +++++++++ emulators/wine/pkg-plist | 8 ++++++-- emulators/wine/pkg32.sh (new) | 13 ++++++++++++ emulators/wine/wine-wow64.sh (new) | 42 ++++++++++++++++++++++++++++++++++++++ emulators/wine/wine.sh (new) | 14 +++++++++++++ 5 files changed, 85 insertions(+), 2 deletions(-)
A commit in branch main references this bug: URL: https://cgit.FreeBSD.org/ports/commit/?id=27ae28dd240c63c37a2fe17d2a2440d1beda5870 commit 27ae28dd240c63c37a2fe17d2a2440d1beda5870 Author: Gerald Pfeifer <gerald@FreeBSD.org> AuthorDate: 2021-08-02 21:40:18 +0000 Commit: Gerald Pfeifer <gerald@FreeBSD.org> CommitDate: 2021-08-02 21:40:19 +0000 emulators/wine-devel: Invoke with LD_BIND_NOW and revampe WoW Forward port 1d2af6e08958ac78de9fae727283ac8cdaf8705f and its two follow-up fixes ad15b0e748b6bd93ef1e36b1c605c1da29d10565 and 1b5885c463320a2af0e7fe2ed0fdca93d760ad19 from emulators/wine: Wine 6.0 and later need LD_BIND_NOW / LD_32_BIND_NOW on FreeBSD, cf. https://bugs.winehq.org/show_bug.cgi?id=50257 and https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=252307 so move the actual binaries to wine64.bin / wine.bin and invoke them via a script that does those settings. [1] Also revamp the WoW handling/packging which combines 32-bit/i386 Wine into 64-bit/amd64 Wine. [1] Submitted by: Alex S <iwtcex@gmail.com> [1] PR: 257284 [1], 252307 [1], 255336, 257020 emulators/wine-devel/Makefile | 12 ++++++++ emulators/wine-devel/files/pkg32.sh (new) | 15 +++++++++ emulators/wine-devel/files/wine-wow64.sh (new) | 42 ++++++++++++++++++++++++++ emulators/wine-devel/files/wine.sh (new) | 14 +++++++++ emulators/wine-devel/pkg-plist | 8 +++-- 5 files changed, 89 insertions(+), 2 deletions(-)