Compiling with -Static-Libgcc -Static-Libstdc++ Still Results in Dynamic Dependency on Libc.So

Linking with dynamic library with dependencies

It looks like you are most of the way there already. Well done with your investigation. Let's see if I can help clear up the 'why' behind it.

Here's what the linker is doing. When you link your executable ('main' above) it has some symbols (functions and other things) that are unresolved. It will look down the list of libraries that follow, trying to resolve unresolved symbols. Along the way, it finds that some of the symbols are provided by libB.so, so it notes that they are now resolved by this library.

However, it also discovers that some of those symbols use other symbols that are not yet resolved in your executable, so it now needs to resolve those as well. Without linking against libA.so, your application would be incomplete. Once it links against libA.so, all symbols are resolved and linking is complete.

As you saw, the use of -unresolved-symbols-in-shared-libs, doesn't fix the problem. It just defers it so that those symbols are resolved at run time. That's what -rpath is for: to specify the libraries to be searched at run time. If those symbols can't be resolved then, your app will fail to start.

It's not an easy thing to figure out library dependencies because a symbol could be provided by more than one library and be satisfied by linking against any one of them.

There is another description of this process here: Why does the order in which libraries are linked sometimes cause errors in GCC?

G++ Dynamic Library Linking Issues

(You haven't shown the actual linker error, or provided nearly enough information about the problem, so what follows is partly guesswork...)

If I try to link application D just to libC.so, I get unresolved symbols for the symbols in A and B.

When linking an executable the GNU linker checks that all symbols are available. You can turn that off with --allow-shlib-undefined (to tell GCC to pass that to the linker use -Wl,--allow-shlib-undefined)

It is better not to use that option, but in that case the linker needs to know where to find libA.so and libB.so so it can check that the symbols needed by libC.so will be found. You can do that with the -rpath-link linker option

When using ELF or SunOS, one shared library may require another. This happens when an "ld -shared" link includes a shared library as one of the input files.

When the linker encounters such a dependency when doing a non-shared, non-relocatable link, it will automatically try to locate the required shared library and include it in the link, if it is not included explicitly.

So you should be able to fix the problem by using -Wl,-rpath-link,. to tell the linker to look in the current directory (.) for the libraries libC.so depends on.

I get the impression that link order matters. How so, and how do I know what order to link in?

Yes, link order matters. You should link in the obvious order ;-) If a file foo.cc depends on a library then put the library later in the linker line, so it will be found after processing foo.cc, and if that library depends on another library put that even later, so it will be processed after the earlier library that needs it. If you put a library at the start of the link line then the linker doesn't have any unresolved symbols to look up, so doesn't need to link to that library.

Add dynamic dependency to shared object in C++

Probably the dependency is not listed in the ldd's output because no symbols which are used in B.cpp are found in libA.so. This may happen because of C++ symbol names mangling: if libA.so has been compiled by the C compiler, it may store the symbol for function void foo() under pretty name foo, whereas C++ compiler will mangle it into something like _Z3foov. You can check it with the following commands:

$ # Replace "SomeSharedObject" with the actual name of symbol exported by libA.so.
$ strings libA.so | grep SomeSharedObject
$ strings libB.so | grep SomeSharedObject

To avoid this, one could put the declaration of the symbol foo into an extern "C" {} clause. Then compiler will not mangle this name, and linker will probably find this name in libA.so.

The -l option works as you expect in a laboratory environment:

$ cat bar.cpp 
extern void foo();

void bar()
{
foo();
}
$ cat baz.cpp
extern void bar();

void baz()
{
bar();
}
$ # Link against libssl.so (OpenSSL).
$ # Obviously libssl.so is unnecessary in libbar.so.
$ g++ -fPIC -shared bar.cpp -o libbar.so -lssl
$ ldd libbar.so
statically linked
$ # Link against libbar.so in the current directory
$ g++ -fPIC -shared baz.cpp -o libbaz.so -L`pwd` -lbar
$ ldd libbaz.so
linux-vdso.so.1 => (0x00007fff7cfe2000)
libbar.so => not found

Here libbar.so depends on the function foo. But it hasn't been found in any library, including libssl.so. So ldd reports the shared object libbar.so as "statically linked". All symbols which were not found when libbar.so was produced, will be searched for when creating the final executable which depends on libbar.so.

In turn, libbaz.so depends on libbar.so, because the function void bar() was found in the above shared object which we have specified via -l option. If we omit the -L option, linker would report error like -lbar: not found. If we omit both -L and -l, libbaz.so would not depend on any shared object just as libbar.so.

Dynamic Linking of Shared Libraries with Dependencies

I experienced a similar situation, this is what worked for me (using a gcc toolchain):

When you create the shared object libB.so, you unconditionally link the library libA.so, the command should look like this:

gcc -shared -Wl,--no-as-needed -lA -o libB.so b.o

You can then check that libA.so indeed became a dependency for the dynamic linker:

$ ldd libB.so
linux-gate.so.1 => (0xb77ba000)
libA.so => not found
libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xb75f7000)
/lib/ld-linux.so.2 (0xb77bb000)

In your main program it should be sufficient to only dlopen() the library libB.so, and the other library should get linked automatically by the dynamic linker.

Ineffective to use patchelf to add a declared dependency on a dynamic library

This errror:

ld: xxx/intel/oneapi/compiler/2021.2.0/linux/bin/intel64/.../icx-lto.so: error loading plugin: /lib64/libc.so.6: version `GLIBC_2.14' not found. 

appears to be coming from ld.

same errors when using ifort and icc

It looks like both ifort and icc are using linker plugin to perform LTO (link-time optimization).

You need to patchelf the binary which actually fails (ld in this case), not the binary which merely invokes ld (i.e. leave ifort and icc alone).

Usually you can tell the compiler to print more info about the binaries it invokes with e.g. icc -v <rest of command>.

I expect that there is ld (or possibly ld.lld) under .../intel/oneapi/compiler/2021.2.0/linux/..., and you need to patchelf that binary.

Dynamic library forwarding

No, it is not possible to "forward" dynamically linked libraries.

When you link against any library, statically or dynamically, you actually enable your main executable to call on the functions/symbols defined in the linked library.

In your case, the library bar, does not have the function foo() defined in it. So when bar.so is created, the symbols generated are registered in the symbol table of your main executable - program. As, the symbols in the bar lib do not contain any function called foo(), it doesn't get registered in the symbol table of program. So when foo() gets called during time, the loader tries to find the .so in which foo() would be defined among all the libraries you linked during compiling program. Hence the run time error. It doesn't show a compile time error because you had included the foo.h header file to it.

You need to explicitly link all the libraries of which symbols(functions, variables, constants, etc.) you want to reference in the code being compiled.

How does a compiler find out which dynamic link library will be used in my code, if I only include headers-files, where is not describe it?

When you compile a runnable executable, you don't just specify the source code, but also a list of libraries from which undefined references are looked up. With the C standard library, this happens implicitly (unless you tell GCC -nostdinc), so you may not have been consciously aware of this.

The libraries are only consumed by the linker, not the compiler. The linker locates all the undefined references in the libraries. If the library is a static one, the linker just adds the actual machine code to your final executable. On the other hand, if the library is a shared one, the linker only records the name (and version?) of the library in the executable's header. It is then the job of the loader to find appropriate libraries at load time and resolve the missing dependencies on the fly.

On Linux, you can use ldd to list the load-time dependencies of a dynamically linked executable, e.g. try ldd /bin/ls. (On MacOS, you can use otool -L for the same purpose.)

Linking against an old version of libc to provide greater application coverage

Work out which symbols in your executable are creating the dependency on the undesired version of glibc.

$ objdump -p myprog
...
Version References:
required from libc.so.6:
0x09691972 0x00 05 GLIBC_2.3
0x09691a75 0x00 03 GLIBC_2.2.5

$ objdump -T myprog | fgrep GLIBC_2.3
0000000000000000 DF *UND* 0000000000000000 GLIBC_2.3 realpath

Look within the depended-upon library to see if there are any symbols in older versions that you can link against:

$ objdump -T /lib/libc.so.6 | grep -w realpath
0000000000105d90 g DF .text 0000000000000021 (GLIBC_2.2.5) realpath
000000000003e7b0 g DF .text 00000000000004bf GLIBC_2.3 realpath

We're in luck!

Request the version from GLIBC_2.2.5 in your code:

#include <limits.h>
#include <stdlib.h>

__asm__(".symver realpath,realpath@GLIBC_2.2.5");

int main () {
realpath ("foo", "bar");
}

Observe that GLIBC_2.3 is no longer needed:

$ objdump -p myprog
...
Version References:
required from libc.so.6:
0x09691a75 0x00 02 GLIBC_2.2.5

$ objdump -T myprog | grep realpath
0000000000000000 DF *UND* 0000000000000000 GLIBC_2.2.5 realpath

For further information, see http://web.archive.org/web/20160107032111/http://www.trevorpounds.com/blog/?p=103.



Related Topics



Leave a reply



Submit