Selective Static Linking Of Library Functions In Shared Library
ld, linux, shared-libraries, static-linking
Solution
The following points attempt to answer the questions I had posed:
- ld does not seem to allow you to omit linking in certain symbols from a static library. The usage of `--just-symbols` or `--undefined` (or the `EXTERN` linker script command) will not prevent ld from linking the symbols.
To convert a static library, libfoobar.a, into a shared one, libfoobar.so.1.0, and exporting all visible symbols. You can also use `--version-script` and other methods to export only a subset of symbols.
`ld -shared -soname libfoobar.so.1 -o libfoobar.so.1.0 --whole-archive libfoobar.a --no-whole-archive`
It is better to delete archive members from a copy of your static library than it is to extract them because there may be internal dependencies you have to manage. For example, assuming you are exporting all symbols, you can generate a map file from your main executable. You can then grep for all the archive members that the executable pulled in from the copy of the static library and delete them from the copy. So when your DSO is linking in the static library, it will leave the same symbols unresolved.
It is possible to specify your main executable as a shared library for your DSO if you compile the executable with the `--pie` option. Your DSO will link first to your executable if it preceded the static library in the link command. The caveat is that the main executable must be available via `LD_LIBRARY_PATH` or `-rpath`. Furthermore, using strace reveals that, since the executable is a dependency of your library, it is loaded again when your DSO loads.
`ld -shared -rpath '$ORIGIN' -L. -lc -ldl -o DSO.so DSO.o app libfoobar.a`
The dynamic linker will use the executable's version of foo first unless you call dlopen() with the `RTLD_DEEPBIND` flag. Using strace reveals that the entire DSO is file mapped mmap2() into memory. However, Wikipedia claims that for mmap "The actual reads from disk are performed in "lazy" manner, after a specific location is accessed." If this is true, then the duplicate foo will not be loaded. Note that the override only happens if your DSO exported the function foo. Otherwise, the function foo that was statically linked into your DSO will be used whenever your DSO calls foo.
In conclusion, if mmap() uses a lazy read, then the best solution is to link your DSO in the normal manner and let the dynamic linker and linux take care of the rest.
Problem
I want to create a shared library that uses functions from a 3rd-party static library. For example, `foo` and `bar` from `libfoobar.a`. I know that my main application is also using `foo` and will be exporting that symbol. So I simply want to link in `bar` to save code size and leave 'foo' unresolved (as it will be provided by main application). If I include `libfoobar.a`, the linker ld will include both functions in my shared library. If I don't include `libfoobar.a`, my library will not have access to function `bar` because the application itself is not linking in `bar`. Questions: - Is there a way to tell ld to only resolve certain symbols when building the shared library? - Turn `libfoobar.a` into a shared library? - Extract file containing function `bar` from `libfoobar.a` and specify that on the linker line? - Don't worry about it, the run-time loader will use `bar` from your application so the copy of `bar` in the shared library will not be loaded?