How to see the order of shared library loading - linker

Given an ELF binary or shared object, how can I most easily see the order in which the needed shared libraries will be loaded?
Are they loaded in the order they are listed by readelf -d?

how can I most easily see the order in which the needed shared libraries will be loaded?
Use LD_DEBUG:
LD_DEBUG=files /bin/ls
13444:
13444: file=libc.so.6 [0]; needed by who [0]
...
13444: file=libnss_files.so.2 [0]; needed by who [0]
...
For more info man ld.so.
Are they loaded in the order they are listed by readelf -d?
Not necessarily e.g. it will be influenced by preloading (LD_PRELOAD, /etc/ld.so.preload).

Using LD_DEBUG=files allows you to see in which order the libraries are searched, and in which order they are initialized. The latter may be different from the former.
Are they loaded in the order they are listed by readelf -d
Depends on what you mean by "loaded". A library is "fully loaded" once it's initializer returned.
Under that definition, no: the order of NEEDED dependencies listed in readelf -d and the order of loading are not the same.
Consider a.out which depends on libA.so and libB.so:
readelf -d a.out | grep NEEDED
0x0000000000000001 (NEEDED) Shared library: [libA.so]
0x0000000000000001 (NEEDED) Shared library: [libB.so]
0x0000000000000001 (NEEDED) Shared library: [libc.so.6]
And further, libA.so itself depends on libC.so and libD.so:
readelf -d libA.so | grep NEEDED
0x0000000000000001 (NEEDED) Shared library: [libC.so]
0x0000000000000001 (NEEDED) Shared library: [libD.so]
0x0000000000000001 (NEEDED) Shared library: [libc.so.6]
The order in which the libraries are searched:
LD_DEBUG=files ./a.out |& grep 'needed by'
49169: file=libA.so [0]; needed by ./a.out [0]
49169: file=libB.so [0]; needed by ./a.out [0]
49169: file=libc.so.6 [0]; needed by ./a.out [0]
49169: file=libC.so [0]; needed by ./libA.so [0]
49169: file=libD.so [0]; needed by ./libA.so [0]
The order in which libraries are "fully loaded":
LD_DEBUG=files ./a.out |& grep 'calling init'
69038: calling init: /lib/x86_64-linux-gnu/libc.so.6
69038: calling init: ./libD.so
69038: calling init: ./libC.so
69038: calling init: ./libB.so
69038: calling init: ./libA.so
Other factors that could affect loading order:
LD_PRELOAD or /etc/ld.so.preload.
Any of the libraries can perform dlopen in its initializer.

Related

How to make gcc print out the exact paths of the shared libraries needed by the executable

I was hoping to create an automated tool that copies the needed shared libraries for any C program to a directory, so one can ship directly to end-users.
For example, I have a C program that uses openssl. Subsequently, it needs the following shared libraries to execute.
$ gcc test.c -lssl -lcrypto
$ readelf -d a.out
Dynamic section at offset 0x2dd8 contains 28 entries:
Tag Type Name/Value
0x0000000000000001 (NEEDED) Shared library: [libssl.so.1.1]
0x0000000000000001 (NEEDED) Shared library: [libcrypto.so.1.1]
0x0000000000000001 (NEEDED) Shared library: [libc.so.6]
0x000000000000000c (INIT) 0x1000
0x000000000000000d (FINI) 0x11b4
...
How can I make gcc output the exact path of the .so-files, so that I can copy them to a local directory and bundle into a zipfile?
(I'm planning to use the -rpath switch, to add that local directory to runtime library search path)
You can use dynamic injection. (On linux)You modify the environment variables as below
export DYLD_LIBRARY_PATH=path/of/your/shared/library
export DYLD_INSERT_LIBRARIES="name/of/library"
export DYLD_FORCE_FLAT_NAMESPACE=1 //by default
You can create the .sh script to run on run time like below
#!/bin/sh
export DYLD_LIBRARY_PATH=path/of/your/shared/library
export DYLD_INSERT_LIBRARIES="name/of/library"
export DYLD_FORCE_FLAT_NAMESPACE=1 //by default
$#

Gentoo ld generates RUNPATH in library when -Wl,-rpath is used

I have such a directory structure: symlink pointing onto directory and symlink point to a library:
$ libtrotl.so -> /usr/local/lib64/tora-3.1/../libtrotl.so
$ instantclient -> /usr/lib/oracle/12.1/client64/lib
When I dlopen library libtrotl.so, all dependent libs are resolved and loaded.
Thanks to RPATH.
$ readelf -d libtrotl.so
Dynamic section at offset 0x17e7a8 contains 31 entries:
Tag Type Name/Value
0x0000000000000001 (NEEDED) Shared library: [libclntsh.so.12.1]
0x0000000000000001 (NEEDED) Shared library: [libboost_system.so.1.60.0]
0x0000000000000001 (NEEDED) Shared library: [libstdc++.so.6]
0x0000000000000001 (NEEDED) Shared library: [libm.so.6]
0x0000000000000001 (NEEDED) Shared library: [libgcc_s.so.1]
0x0000000000000001 (NEEDED) Shared library: [libc.so.6]
0x000000000000000e (SONAME) Library soname: [libtrotl.so]
0x000000000000000f (RPATH) Library rpath: [$ORIGIN/instantclient/]
0x000000000000000c (INIT) 0xe7898
$ ldd libtrotl.so
linux-vdso.so.1 (0x00007ffdc25d1000)
libclntsh.so.12.1 => /home/ivan/.TOra3/poracle/./instantclient/libclntsh.so.12.1 (0x00007f6cd0c37000)
libboost_system.so.1.60.0 => /lib64/libboost_system.so.1.60.0 (0x00007f6cd0a24000)
libstdc++.so.6 => /lib64/libstdc++.so.6 (0x00007f6cd069c000)
libm.so.6 => /lib64/libm.so.6 (0x00007f6cd0393000)
libgcc_s.so.1 => /lib64/libgcc_s.so.1 (0x00007f6cd017b000)
libc.so.6 => /lib64/libc.so.6 (0x00007f6ccfdb9000)
libmql1.so => /home/ivan/.TOra3/poracle/./instantclient/libmql1.so (0x00007f6ccfb43000)
libipc1.so => /home/ivan/.TOra3/poracle/./instantclient/libipc1.so (0x00007f6ccf7c4000)
libnnz12.so => /home/ivan/.TOra3/poracle/./instantclient/libnnz12.so (0x00007f6ccf0ba000)
I just use -Wl,-rpath,"\$ORIGIN/instantclient/" as compile flag and it works everywhere - except for Gentoo.
Gentoo linker(GNU gold (Gentoo 2.25.1 p1.1 2.25.1) 1.11) adds RUNPATH insead of RPATH.
0x000000000000001d (RUNPATH) Library runpath: [$ORIGIN/instantclient/]
Then dynamic linker does not resolve libraries.
(Gentoo)$ ldd libtrotl.so
linux-vdso.so.1 (0x00007ffe5c3e9000)
libclntsh.so.12.1 => /home/ivan/.TOra3/poracle/./instantclient/libclntsh.so.12.1 (0x00007f245dc9e000)
libstdc++.so.6 => /usr/lib/gcc/x86_64-pc-linux-gnu/4.9.4/libstdc++.so.6 (0x00007f245d933000)
libm.so.6 => /lib64/libm.so.6 (0x00007f245d62e000)
libgcc_s.so.1 => /usr/lib/gcc/x86_64-pc-linux-gnu/4.9.4/libgcc_s.so.1 (0x00007f245d417000)
libc.so.6 => /lib64/libc.so.6 (0x00007f245d07d000)
libmql1.so => not found
libipc1.so => not found
libnnz12.so => not found
libons.so => not found
As you can see, in second case library libmql1.so is not found although it is present in instantclient sub-directory. How can I set RPATH on Gentoo?
DT_RPATH tags are deprecated, DT_RUNPATH is the modern implementation with a couple different semantics. Gentoo link editors (both ld and gold) will not generate the deprecated tags by default. You can (but probably shouldn't) disable these by passing -Wl,--disable-new-dtags, but that is not recommended as I said.
There is an older pot from Qt that explains the difference of these two when using plugins: http://blog.qt.io/blog/2011/10/28/rpath-and-runpath/

Link problems with libc++abi when linking against libc++ via cmake

I'm trying to build a simple ("hello world") C++ program with LLVM/Clang 3.7.0 built from sources against the toolchain's libc++, with the command line:
clang++ -std=c++14 -stdlib=libc++ -fno-exceptions hello.cpp
However, I get the following errors:
/usr/bin/ld: warning: libc++abi.so.1, needed by /bulk/workbench/llvm/3.7.0
/toolchain4/bin/../lib/libc++.so, not found (try using -rpath or -rpath-link)
/bulk/workbench/llvm/3.7.0/toolchain4/bin/../lib/libc++.so: undefined reference to `__cxa_rethrow_primary_exception'
/bulk/workbench/llvm/3.7.0/toolchain4/bin/../lib/libc++.so: undefined reference to `__cxa_decrement_exception_refcount'
/bulk/workbench/llvm/3.7.0/toolchain4/bin/../lib/libc++.so: undefined reference to `std::out_of_range::~out_of_range()'
[...]
The LD_LIBRARY_PATH is not set and the toolchain's install directory is added to my working PATH by:
export PATH=$PATH:/bulk/workbench/llvm/3.7.0/toolchain4/bin/
I'm on Ubuntu GNU/Linux 14.04 and I have not installed anything LLVM or Clang related packages from any repository.
According to the libc++ documentation:
On Linux libc++ can typically be used with only ‘-stdlib=libc++’. However some libc++ installations require the user manually link libc++abi themselves. If you are running into linker errors when using libc++ try adding ‘-lc++abi’ to the link line.
Doing as suggested gives a successful build.
So, my question is this:
Why do I have to specify the -lc++abi dependency explicitly on the line of the build command?
Doing
readelf -d $(llvm-config --libdir)/libc++.so
gives
Dynamic section at offset 0xb68c8 contains 31 entries:
Tag Type Name/Value
0x0000000000000001 (NEEDED) Shared library: [libc++abi.so.1]
0x0000000000000001 (NEEDED) Shared library: [libpthread.so.0]
0x0000000000000001 (NEEDED) Shared library: [libc.so.6]
0x0000000000000001 (NEEDED) Shared library: [libm.so.6]
0x0000000000000001 (NEEDED) Shared library: [librt.so.1]
0x0000000000000001 (NEEDED) Shared library: [libgcc_s.so.1]
0x000000000000000e (SONAME) Library soname: [libc++.so.1]
0x000000000000000f (RPATH) Library rpath: [$ORIGIN/../lib]
0x000000000000000c (INIT) 0x350a8
[...]
Shouldn't the embedded RPATH in the dynamic section of the ELF be considered by ld as described in its man page under the section -rpath-link=dir?
Moreover, when I set the LD_LIBRARY_PATH with
LD_LIBRARY_PATH=$(llvm-config --libdir)
the initial build command (without specifying -lc++abi) works, as also described in the 5th clause of the aforementioned man entry.

Dynamic library "forwarding"

[Edit: In short, the question is: when I link against a dynamic library that is linked against another dynamic library, do I have to explicitly link against that as well?]
I saw something like this in a piece of software. It doesn't work and now I am wondering whether it is supposed to work. Can I link a library "bar" dynamically against another library "foo" and then link against that library to access the symbols from "foo" (because "bar" should want to be linked to "foo")? (I am using linux and gcc 4.8.2 in case that matters.)
Concretely suppose I have the three files below. Now I do
gcc -c -Wall -Werror -fpic foo.c
gcc -shared -olibfoo.so foo.o
at which point I would usually do
gcc -o program main.c -L. -lfoo
to get a working program. Now instead I do
gcc -shared -olibbar.so -L. -lfoo
gcc -o program main.c -L. -lbar
This doesn't work:
/tmp/cciNSTyI.o: In function `main':
main.c:(.text+0xf): undefined reference to `foo'
collect2: error: ld returned 1 exit status
Should it?
foo.h
#ifndef foo_h__
#define foo_h__
extern void foo(void);
#endif
foo.c
#include <stdio.h>
void foo(void)
{
puts("foo");
}
main.c
#include <stdio.h>
#include "foo.h"
int main(void)
{
puts("Library test...");
foo();
return 0;
}
Edit: I wrote an answer about my understanding of what's going on below.
One thing I'm still not quite clear about is the order of arguments: If (with a file bar.c as in that answer) I link bar with the lines (note the position of "bar.o")
gcc -o program main.c -L. -lbar
gcc -shared -olibbar.so -L. -lfoo bar.o
then it "bar" does not depend on "foo":
> readelf -d libbar.so
Dynamic section at offset 0xe18 contains 24 entries:
Tag Type Name/Value
0x0000000000000001 (NEEDED) Shared library: [libc.so.6]
0x000000000000000c (INIT) 0x5a8
[...]
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.
when I link against a dynamic library that is linked against another dynamic library, do I have to explicitly link against that as well?
No.
That other library must be linked against shared libraries it requires, otherwise it would be one massive fuster cluck (the one you get with .a files).
Imagine someone else adding a shared library dependency to a shared library you use. That would cause your application to fail at link-time (at best) or run-time. This is why shared libraries carry their own dependencies.
You can use readelf utility to examine shared library dependencies, e.g.:
$ readelf -d /usr/lib64/libboost_wave-mt.so
Dynamic section at offset 0x12fd58 contains 30 entries:
Tag Type Name/Value
0x0000000000000001 (NEEDED) Shared library: [libpthread.so.0]
0x0000000000000001 (NEEDED) Shared library: [librt.so.1]
0x0000000000000001 (NEEDED) Shared library: [libboost_filesystem-mt.so.5]
0x0000000000000001 (NEEDED) Shared library: [libboost_thread-mt.so.5]
0x0000000000000001 (NEEDED) Shared library: [libboost_date_time-mt.so.5]
0x0000000000000001 (NEEDED) Shared library: [libboost_system-mt.so.5]
0x0000000000000001 (NEEDED) Shared library: [libstdc++.so.6]
0x0000000000000001 (NEEDED) Shared library: [libm.so.6]
0x0000000000000001 (NEEDED) Shared library: [libgcc_s.so.1]
0x0000000000000001 (NEEDED) Shared library: [libc.so.6]
0x000000000000000e (SONAME) Library soname: [libboost_wave-mt.so.5]
0x000000000000000c (INIT) 0xb49f0
0x000000000000000d (FINI) 0x10c018
0x000000006ffffef5 (GNU_HASH) 0x1b8
0x0000000000000005 (STRTAB) 0xbe08
0x0000000000000006 (SYMTAB) 0x2cb8
0x000000000000000a (STRSZ) 637705 (bytes)
0x000000000000000b (SYMENT) 24 (bytes)
0x0000000000000003 (PLTGOT) 0x3308a8
0x0000000000000002 (PLTRELSZ) 7584 (bytes)
0x0000000000000014 (PLTREL) RELA
0x0000000000000017 (JMPREL) 0xb2c50
0x0000000000000007 (RELA) 0xa8600
0x0000000000000008 (RELASZ) 42576 (bytes)
0x0000000000000009 (RELAENT) 24 (bytes)
0x000000006ffffffe (VERNEED) 0xa8530
0x000000006fffffff (VERNEEDNUM) 4
0x000000006ffffff0 (VERSYM) 0xa7912
0x000000006ffffff9 (RELACOUNT) 405
0x0000000000000000 (NULL) 0x0
Note NEEDED attributes - these are the shared libraries that get loaded automatically when you load this shared library.
In
gcc -shared -olibbar.so -L. -lfoo
You produce a shared library from a shared library. In this case you need to do partial linking with --relocatable linker option:
gcc -shared -Wl,--relocatable -olibbar.so -L. -lfoo
This is following up on the answer by Maxim Egorushkin (in particular using readelf was instructive).
First it seems that only libraries are marked as "NEEDED" if they are actually needed anywhere, i.e. if some symbol defined by them is used at all. In the example in the question this is of course not the case.
Second, even if via these dependencies "foo" ends up being linked in, its symbols are still not available to main.c unless it is linked in explicitly.
To verify this behaviour, consider the files
bar.h
#ifndef bar_h__
#define bar_h__
extern void bar(void);
#endif
and
bar.c
#include <stdio.h>
#include "foo.h"
void bar(void)
{
foo();
puts("bar");
}
that are compiled and linked via
gcc -o program main.c -L. -lbar
gcc -shared -olibbar.so -L. -lfoo bar.o
Then "bar" depends on "foo" (unlike in the answer):
> readelf -d libbar.so
Dynamic section at offset 0xe08 contains 25 entries:
Tag Type Name/Value
0x0000000000000001 (NEEDED) Shared library: [libfoo.so]
0x0000000000000001 (NEEDED) Shared library: [libc.so.6]
0x000000000000000c (INIT) 0x5b0
If one replaces every "foo" by "bar" in the file main.c above, one can compile and link everything to a working program
gcc -o program main.c -L. -lbar -Wl,-rpath-link .
If one keeps the "foo"-lines, linking fails because the foo-symbol cannot be resolved (the program isn't even linked against "bar").
The interesting case is the one where calls to both "foo" and "bar" occur. Now main.c is linked against "bar" which is linked against "foo", but the symbols in "foo" are still not available to main.c.
This behaviour actually makes sense because main.c might depend on a different library defining a function foo() and then it doesn't want to know about the one that "bar" uses. And if that behaviour is desired, also the optimization of not "NEEDing" libraries that aren't needed is valid.

cross-compiling GTK for Raspberry Pi

I am trying to complete this tutorial [here]here. I am running Ubuntu 32bit and I am trying to cross compile for a Raspberry Pi with Raspbian.
When I ran make, I get his error:
/home/alby/rpi/tools/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian/bin/../lib/gcc /arm-linux-gnueabihf/4.8.3/../../../../arm-linux-gnueabihf/bin/ld: warning: libgraphite2.so.2.0.0, needed by /home/alby/rpi/usr/lib/arm-linux-gnueabihf/libharfbuzz.so.0, not found (try using -rpath or -rpath-link)
/home/alby/rpi/usr/lib/arm-linux-gnueabihf/libharfbuzz.so.0: undefined reference to `gr_seg_advance_X'
/home/alby/rpi/usr/lib/arm-linux-gnueabihf/libharfbuzz.so.0: undefined reference to `gr_slot_can_insert_before'
etc..
libharfbuzz.so.0 is in the correct location. I checked for dependency
readelf -d libharfbuzz.so.0 | grep NEEDED
and this is the output:
0x00000001 (NEEDED) Shared library: [libgobject-2.0.so.0]
0x00000001 (NEEDED) Shared library: [libglib-2.0.so.0]
0x00000001 (NEEDED) Shared library: [libfreetype.so.6]
0x00000001 (NEEDED) Shared library: [libgraphite2.so.2.0.0]
0x00000001 (NEEDED) Shared library: [libgcc_s.so.1]
0x00000001 (NEEDED) Shared library: [libc.so.6]
0x00000001 (NEEDED) Shared library: [ld-linux-armhf.so.3]
This is the first time I try cross-compilation, maybe I am missing something very obvious, but I cannot find out what it is.
thanks Alb

Resources