The Linux dynamic linker also provides some methods do debug such issues. E.g. you can
export LD_DEBUG=bindings to get lots of information on all symbol bindings. Collect all those outputs in a file, and compare the output in the different scenarios, and you will notice some symbols linking to different files. See the ld.so documentation for more options.
For example, we were tracking down a crash when we linked the TensorFlow into our binary, and also used some embedded Python. We reduced the crash to
import hashlib. It does not crash when not linking TensorFlow. (You find this also being reported here and here.)
With linking TF, I got outputs like this:
2306643: binding file /u/zeyer/.linuxbrew/Cellar/[email protected]/3.11.2_1/lib/python3.11/lib-dynload/_hashlib.cpython-311-x86_64-linux-gnu.so  to /u/zeyer/.local/lib/python3.11/site-packages/tensorflow/libtensorflow_framework.so.2 : normal symbol `EVP_MD_size' [OPENSSL_1_1_0]
python -c "import hashlib" gives me outputs like this:
2307740: binding file /u/zeyer/.linuxbrew/Cellar/[email protected]/3.11.2_1/lib/python3.11/lib-dynload/_hashlib.cpython-311-x86_64-linux-gnu.so  to /work/tools/users/zeyer/linuxbrew/lib/libcrypto.so.1.1 : normal symbol `EVP_MD_size' [OPENSSL_1_1_0]
As you see, in the case with TF, it finds those OpenSSL related symbols in
libtensorflow_framework.so.2, in the other case, it finds them in
libcrypto.so.1.1 (as it should be).
Our solution here was to add
-L/work/tools/users/zeyer/linuxbrew/lib -Wl,-rpath,/work/tools/users/zeyer/linuxbrew/lib -Wl,-no-as-needed -lcrypto to our linker flags, before we link the TF library. So we enforce that
libcrypto.so.1.1 is loaded first. That solves the problem. See here for my compile script.