5

I have a crash in some software I am writing which I suspect may be caused by symbol conflicts between two different shared libraries (when I disable one of the shared libraries the other starts working).

is there a tool I can use that will look through the libraries loaded by a program and tell me if there are any symbols defined in more than one library?

3 Answers 3

3

There are commonly-available utilities which can be used in a shell script to solve the problem (though I don't recall seeing a script which combines them to solve the problem). The nm utility is used to find symbols in an object file or executable. On most systems, ldd (otool on macOS) shows the shared libraries used by an executable. For the former, for example, I have a script (listused.sh) in ncurses which lists all of the symbols in its libraries and whether those are testable by a program using the libraries (see report in test/README).

The -C option is useful (if you're interested in C++ libraries), but the libraries may be stripped (lacking debugging information). However, the -D option (available on "recent" systems, e.g., almost anything updated in the past 10-15 years) provides symbols for dynamic libraries:

Display the dynamic symbols rather than the normal symbols. This is only meaningful for dynamic objects, such as certain types of shared libraries.

Only display dynamic symbols. This option is only meaningful for shared libraries.

Displays the SHT_DYNSYM symbol information. This is the symbol table used by ld.so.1 and is present even in stripped dynamic executables. If –D is not specified, the default behavior is to display the SHT_SYMTAB symbol information.

This is not a feature of less recent systems, at least according to their documentation:

(someone might know offhand the timeline for introducing the feature).

I've used the feature in a few scripts such as analyze-curses-symbols.

Further reading:

If you use the -quickstart_info option, ld tells you if conflicts arise. It also tells you to run elfdump with the -Dc option to find the conflicts. See the elfdump(1) man page for more information about how to read the output produced by elfdump.

  • However, elfdump is not standardized (even to the extent that nm is), and that -Dc is not found in other implementations such as this one, for Solaris. (There are related programs for Solaris).
0

nm -C library.so | grep -i symbol

is probably what you're looking for. It might not work for stripped libraries though.

1
  • This only works if the shared library is not stripped.
    – schily
    Commented Jun 24, 2020 at 13:15
0

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 [0] to /u/zeyer/.local/lib/python3.11/site-packages/tensorflow/libtensorflow_framework.so.2 [0]: normal symbol `EVP_MD_size' [OPENSSL_1_1_0]

Just running 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 [0] to /work/tools/users/zeyer/linuxbrew/lib/libcrypto.so.1.1 [0]: 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.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .