Are runtime libraries inherently dynamic libraries? - c

I am cross compiling for a system with an OpenMP parallelized program, but when I run on the target, I get the error:
can't load library 'libgomp.so.1'
After looking around, I see that it's an OpenMP runtime library. Is there any was to statically link the library it on the compiler host machine, or does it need to be present on the target machine? If it can be statically linked, then what makes a runtime library different from a dynamic library? Could one statically or dynamically link any library, provided the environment was correct?

You can selectively statically link certain libraries by providing certain linker options. For libgomp it would be something like:
gcc -o executable foo.o bar.o -Wl,-static -lgomp -Wl,-Bdynamic -lpthread -lother -llibs
Any library listed between -Wl,-static and -Wl,-Bdynamic will be linked in statically. -fopenmp should not be present in the linking command as it expands to linker flags that get appended after the user supplied options, and therefore libpthread should be listed explicitly. It also means that even simple OpenMP programs have to be compiled and linked in two separate steps for static linking to work.
Example:
// foo.c
#include <stdio.h>
#include <omp.h>
int main(void)
{
#pragma omp parallel
printf("Hello world from thread %d\n", omp_get_thread_num());
return 0;
}
Traditional compilation:
$ gcc -fopenmp -o foo foo.c
$ ldd foo
linux-vdso.so.1 => (0x00007ffff5661000)
libgomp.so.1 => /usr/lib64/libgomp.so.1 (0x0000003bcfa00000)
libpthread.so.0 => /lib64/libpthread.so.0 (0x0000003bc2600000)
libc.so.6 => /lib64/libc.so.6 (0x0000003bc1e00000)
librt.so.1 => /lib64/librt.so.1 (0x0000003bc3200000)
/lib64/ld-linux-x86-64.so.2 (0x0000003bc1a00000)
The program is linked against the DSO version of libgomp.
Fully static linking:
$ gcc -fopenmp -static -o foo foo.c
$ ldd foo
not a dynamic executable
With -static all libraries are linked in statically into the executable.
Linking only libgomp statically:
$ gcc -fopenmp -c foo.c
$ gcc -o foo foo.o -Wl,-static -lgomp -Wl,-Bdynamic -lpthread
$ ldd foo
linux-vdso.so.1 => (0x00007ffdaaf61000)
libpthread.so.0 => /lib64/libpthread.so.0 (0x0000003bc2600000)
libc.so.6 => /lib64/libc.so.6 (0x0000003bc1e00000)
/lib64/ld-linux-x86-64.so.2 (0x0000003bc1a00000)
It is important to maintain the correct order of statically linked objects in that case. If foo.o is placed after -lgomp, a link error results:
$ gcc -o foo -Wl,-static -lgomp -Wl,-Bdynamic foo.o -lpthread
foo.o: In function `main':
foo.c:(.text+0x14): undefined reference to `GOMP_parallel_start'
foo.c:(.text+0x23): undefined reference to `GOMP_parallel_end'
foo.o: In function `main.omp_fn.0':
foo.c:(.text+0x3b): undefined reference to `omp_get_thread_num'
collect2: ld returned 1 exit status
Any object file resulting from source code that contains OpenMP constructs should be placed before -lgomp.

The term "runtime library" is usually used for the standard library and environment needed to run your program. In the case of a C program, it's the C standard library, maybe some other libraries specific for your compiler, and some object files linked to your program to set up the standard C environment.
A "runtime library" can be a dynamic library, or even a collection of multiple dynamic libraries. But it can also be one or more static libraries as well.

Dynamic libraries are convenient way of providing runtime libraries, as many programs will potentially want to link against such a library. And this is why dynamic linking and dynamic libraries are out there - the first process that requires particular dynamic library will cause it to be loaded to memory. Later, this instance of dynamic library can be reused by many processes.
Imagine if you'd have tens of process running and each of them statically link against say C runtime library. I assume memory consumption would grow rather significantly compared to the case where each of these processes would link against single DLL.
In my opinion, if library will be used by many different processes (for example DirectX might be such library) it might be more efficient to provide it as dynamic library. Otherwise, static linking is preferable.

Related

Isn't ld checking for unresolved symbols in shared libraries redundant?

When linking a program against a shared object, ld will ensure that symbols can be resolved. This basically ensures that the interfaces between the program and its shared objects are compatible. After reading Linking with dynamic library with dependencies, I learnt that ld will descend into linked shared objects and attempt to resolve their symbols too.
Aren't my shared object's references already checked when the shared objects are themselves linked?
I can understand the appeal of finding out at link time whether a program has all the pieces it requires to start, but does it seems irrelevant in the context of packages building where shared objects may be distributed separately (Debian's lib* packages, for instance). It introduces recursive build dependencies on systems uninterested in executing built programs.
Can I trust the dependencies resolved when the shared object was built? If so, how safe is it to use -unresolved-symbols=ignore-in-shared-libs when building my program?
You're wondering why a program's linkage should bother to resolve symbols originating in
the shared libraries that it's linked with because:
Aren't my shared object's references already checked when the shared objects are themselves linked?
No they're not, unless you expressly insist on it when you link the shared library,
Here I'm going to build a shared library libfoo.so:
foo.c
extern void bar();
void foo(void)
{
bar();
}
Routinely compile and link:
$ gcc -fPIC -c foo.c
$ gcc -shared -o libfoo.so foo.o
No problem, and bar is undefined:
$ nm --undefined-only libfoo.so | grep bar
U bar
I need to insist to get the linker to object to that:
$ gcc --shared -o libfoo.so foo.o -Wl,--no-undefined
foo.o: In function `foo':
foo.c:(.text+0xa): undefined reference to `bar'
Of course:
main.c
extern void foo(void);
int main(void)
{
foo();
return 0;
}
it won't let me link libfoo with a program:
$ gcc -c main.c
$ gcc -o prog main.o -L. -lfoo
./libfoo.so: undefined reference to `bar'
unless I also resolve bar in the same linkage:
bar.c
#include <stdio.h>
void bar(void)
{
puts("Hello world!");
}
maybe by getting it from another shared library:
gcc -fPIC -c bar.c
$ gcc -shared -o libbar.so bar.o
$ gcc -o prog main.o -L. -lfoo -lbar
And then everything's fine.
$ export LD_LIBRARY_PATH=.; ./prog
Hello world!
It's of the essense of a shared library that it doesn't by default have
to have all of its symbols resolved at linktime. That way that a program - which
typically does need all its symbols resolved a linktime - can get all its symbols
resolved by being linked with more than one library.
Aren't my shared object's references already checked
when the shared objects are themselves linked?
Well, shared libs might have been linked with -Wl,--allow-shlib-undefined or with dummy dependencies so it still makes sense to check them.
Can I trust the dependencies resolved when the shared object was built?
Probly not, current linking environment and the environment used to link original shlibs may be different.
If so, how safe is it to use -unresolved-symbols=ignore-in-shared-libs
when building my program?
You may be missing potential errors in this case (or rather delaying them to runtime which is still bad). Imagine a situation where some of the symbols needed by shared objects are to come from executable itself or from one of the libs which is linked by executable (but not by the shlib which is missing the symbols).
EDIT
Although above is correct, Mike Kinghan's answer gives stronger argument in favor of symbol resolution in libraries during executable link.

Add dynamic dependency to shared object in C++

I want to create shared object B that dynamically links to shared object A. I'm using the following command to compile shared object B:
g++ -fPIC -shared -L/path/to/directory -lA -o libB.so B.cpp
It is my understanding that -lA is what tells the linker that libB.so should dynamically link to /path/to/directory/libA.so. However, when I do ldd on the final product, the dependency is not listed (and loading libB.so fails because of these missing dependencies).
ldd libB.so
linux-vdso.so.1 => (0x00007ffd4233e000)
libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007f35072fe000)
libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f35070e7000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f3506de1000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f3506a1c000)
/lib64/ld-linux-x86-64.so.2 (0x00007f3507807000)
Am I wrong about what -l is supposed to do? I assume that the above is a minimal set of dynamic dependencies from C++.
Are there any gotchas to look for? For instance, does the linker simply ignore -l requests when it can't find the file or something (and I have to debug my paths more than I already have)?
Do I have to put something in my C++ code to indicate dependency (like "extern" functions or something)?
Update:
I have determined that the set of dynamic dependencies that ld reports does depend on my C++ code and does not appear to depend on any -L or -l flags I supply. The linker is automatically guessing which shared objects my libB.so should depend on, and it's not assuming enough.
For instance, I know that I'll need B to load A because I call some code that eventually calls code in libA.so. How do I provide this information to the linker?
Clarifications:
What I'm calling "shared object A" is a complex thing that may load some code dynamically. I want to include enough dependencies so that it will not fail with "missing symbols" when it tries to load this code dynamically. That's why I want to force dependencies in B, because the linker might not statically find them in the dependency tree.
Also, I'm using g++ 4.8.4 (Ubuntu 14.04). This is relevant because g++ started implicitly applying -Wl,--as-needed as of version 4.6.
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.
You are compiling to a weird object name. Linking will happen when you create an executable. then you have to mention your various objects and libraries.

Why do I have to explicitly link to pthreads in my main.c compilation when my main.c does not use pthreads?

In Linux, I have a shared library I made that uses pthreads and a main.c that does not.
libpthread.so shows up in an ldd of my shared library, which is correct.
$ ldd libmapreduce.so.1.0
linux-gate.so.1 => (0x0067d000)
libpthread.so.0 => /lib/libpthread.so.0 (0x0058c000)
[...]
But when I compile and link my main.c that does not use pthreads to my shared library that does, I see:
$ icc -Wall -o main main.c -lmapreduce
/opt/intel/Compiler/11.1/046/lib/ia32/libiomp5.so: undefined reference to `pthread_atfork'
Adding -lpthread to my compile command, i.e.,
$ icc -Wall -o main main.c -lmapreduce -lpthread
resolves the undefined reference.
Why do I need to explicitly link to libpthread when my main.c does not use it and my shared library already has libpthread linked in?
In order to create an executable or DLL you need to link in the transitive closure of all dependencies in your program. Because main.c links in sharedlib you must also link in all dependencies of sharedlib which includes pthreads.
Thank you R.. and Pavan Manjunath, for encouraging me to keep digging.
The link step for the shared library libmapreduce.so looked like:
icc -shared -g -o libmapreduce.so.1.0 map.o map_wrp.o -openmp [...] -lpthread -ldl
That -openmp link flag was not needed and in fact introduced the undefined reference to pthread_atfork. The undefined reference to pthread_atfork did not show up until I tried to link a main.c with the shared library libmapreduce.so. Re-creating libmapreduce.so without the -openmp flag removed the problem.

Can I mix static and shared-object libraries when linking?

I have a C project that produces ten executables, all of which I would like to be linked in statically. The problem I am facing is that one of these executables uses a 3rd-party library of which only the shared-object version is available.
If I pass the -static flag to gcc, ld will error saying it can't find the library in question (I presume it's looking for the .a version) and the executable will not be built. Ideally, I would like to be able to tell 'ld' to statically link as much as it can and fail over to the shared object library if a static library cannot be found.
In the interium I tried something like gcc -static -lib1 -lib2 -shared -lib3rdparty foo.c -o foo.exe in hopes that 'ld' would statically link in lib1 and lib2 but only have a run-time dependence on lib3rdparty. Unfortunatly, this did not work as I intended; instead the -shared flag overwrote the -static flag and everything was compiled as shared-objects.
Is statically linking an all-or-nothing deal, or is there some way I can mix and match?
Looking at this thread you can see that it can be done. The guys at GNU suggest
gcc foo.c -Wl,-Bstatic -lbar -lbaz -lqux -Wl,-Bdynamic -lcorge -o foo.exe

How to link to a different libc file?

I want to supply the shared libraries along with my program rather than using the target system's due to version differences.
ldd says my program uses these shared libs:
linux-gate.so.1 => (0xf7ef0000)**(made by kernel)**
libc.so.6 => /lib32/libc.so.6 (0xf7d88000)**(libc-2.7.so)**
/lib/ld-linux.so.2 (0xf7ef1000)**(ld-2.7.so)**
I have successfully linked ld-xxx.so by compiling with:
gcc -std=c99 -D_POSIX_C_SOURCE=200112L -O2 -m32 -s -Wl,-dynamic-linker,ld-2.7.so myprogram.c
But I have not managed to successful link libc-xxx.so. How can I do that ?
I found out how to do it:
rpath specifies where the provided libraries are located. This folder should contain: libc.so.6, libdl.so.2, libgcc_s.so.1 and maybe more. Check with strace to find out which libraries your binary file uses.
ld.so is the provided linker
gcc -Xlinker -rpath=/default/path/to/libraries -Xlinker -I/default/path/to/libraries/ld.so program.c
Passing -nodefaultlibs or -nostdlib to gcc will tell it to not pass the default libraries as arguments to ld. You will then be able to explicitly specify the libc you want to link against. See the gcc(1) man page for more details and caveats regarding both options.

Resources