ldd
lists the shared libraries which its argument requires. With the -v
option it lists all available information, including version symbols.
Lines of the form
linux-vdso.so.1 => (0x00007fffa3dff000)
librt.so.1 => /lib64/librt.so.1 (0x00007fea7a7b2000)
libstdc++.so.6 => /usr/lib64/libstdc++.so.6 (0x00007fea7a4ab000)
list the libraries required by libAtlasUtilsPB.so
, and how they’re resolved; in your case all the required libraries are found. linux-vdso.so.1
is special, it’s a virtual library provided by the kernel.
Lines of the form
libgcc_s.so.1 (GCC_3.0) => /lib64/libgcc_s.so.1
libm.so.6 (GLIBC_2.2.5) => /lib64/libm.so.6
libpthread.so.0 (GLIBC_2.2.5) => /lib64/libpthread.so.0
list the version symbols required by libAtlasUtilsPB.so
, and again how they’re resolved. This is where ldd
fails to resolve items, which it indicates both by indicating “not found” here and by printing error messages at the start of its output.
GLIBC_...
, GLIBCXX_...
etc. are version symbols, which are used in some libraries (including the GNU C library and the GCC libraries) to identify required versions and to manage backward compatibility. A binary (executable or library) will usually end up requiring multiple versions, based on the symbols it really uses from the target library. To satisfy the requirements of a given binary, you need to provide a library which supports all the required versions — i.e. a library matching at least the highest version symbol in the list of requirements.
The reason multiple versions can end up being required, is that each imported object (function etc.) can have a version, and a given binary can link against multiple versions across all the functions it uses. For example, picking an example with two versions on my system, /lib/x86_64-linux-gnu/libgcc_s.so.1
, ldd -v
shows
/lib/x86_64-linux-gnu/libgcc_s.so.1:
libc.so.6 (GLIBC_2.14) => /lib/x86_64-linux-gnu/libc.so.6
libc.so.6 (GLIBC_2.2.5) => /lib/x86_64-linux-gnu/libc.so.6
libgcc_s.so.1
needs two version symbols from libc.so.6
. To figure out why, we need to look at the undefined symbols it contains — these are the symbols it needs to import:
$ objdump -T /lib/x86_64-linux-gnu/libgcc_s.so.1|grep -F '*UND*'
0000000000000000 DF *UND* 0000000000000000 GLIBC_2.2.5 dl_iterate_phdr
0000000000000000 DF *UND* 0000000000000000 GLIBC_2.2.5 free
0000000000000000 w D *UND* 0000000000000000 __pthread_key_create
0000000000000000 DF *UND* 0000000000000000 GLIBC_2.2.5 abort
0000000000000000 w D *UND* 0000000000000000 _ITM_deregisterTMCloneTable
0000000000000000 DF *UND* 0000000000000000 GLIBC_2.2.5 strlen
0000000000000000 w D *UND* 0000000000000000 pthread_getspecific
0000000000000000 DF *UND* 0000000000000000 GLIBC_2.2.5 memset
0000000000000000 DF *UND* 0000000000000000 GLIBC_2.2.5 calloc
0000000000000000 w D *UND* 0000000000000000 pthread_key_create
0000000000000000 w D *UND* 0000000000000000 __gmon_start__
0000000000000000 DF *UND* 0000000000000000 GLIBC_2.14 memcpy
0000000000000000 w D *UND* 0000000000000000 pthread_once
0000000000000000 w DF *UND* 0000000000000000 GLIBC_2.2.5 pthread_mutex_unlock
0000000000000000 DF *UND* 0000000000000000 GLIBC_2.2.5 malloc
0000000000000000 w D *UND* 0000000000000000 pthread_setspecific
0000000000000000 DF *UND* 0000000000000000 GLIBC_2.2.5 realloc
0000000000000000 w D *UND* 0000000000000000 _Jv_RegisterClasses
0000000000000000 w D *UND* 0000000000000000 _ITM_registerTMCloneTable
0000000000000000 w DF *UND* 0000000000000000 GLIBC_2.2.5 __cxa_finalize
0000000000000000 w DF *UND* 0000000000000000 GLIBC_2.2.5 pthread_mutex_lock
This lists a number of versioned symbols (those with GLIBC_2.2.5
or GLIBC_2.14
in the second-last column), and we can see here that the versions match those which we saw with ldd
. Why do we end up with multiple versions symbols? This is where backwards compatibility comes in. Version 2.2.5 is the baseline for symbol versioning in the GNU C library; any function which was present in version 2.2.5 carries that version. In version 2.13 of the GNU C library, the behaviour of memcpy
was changed; this broke a number of programs, so in version 2.14, a backwards-compatible version was put in place with the optional GLIBC_2.2.5
version tag, and a new version added with the GLIBC_2.14
version tag. Thus old binaries built with earlier versions of the C library use the old version of memcpy
, and binaries built with version 2.14 and later use the new version of memcpy
.
The same story applies to libstdc++.so.6
, but with many more changes with updated version numbers; the libstdc++
manual provides details.
In your case, you need libstdc++.so.6
matching GLIBCXX_3.4.18
, i.e. the version provided by GCC 4.8.0 or later, and version 2.14 of the GNU C library.
You can’t easily build binaries on RHEL 7 and run them on RHEL 6 (that’s why the major version is different). You’d be better off rebuilding your program on RHEL 6...