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

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.

Related

How to debug "cannot open shared object file: No such file or directory"?

On our project at work, where I use a build system managed by another team, I am running into an issue where I am able to compile and link the binary, but then when executing it, it complains about being unable to load a shared object file, it should never have been linked against:
/home/me/build/bin/executable: error while loading shared libraries: libicui18n.so.52.1: cannot open shared object file: No such file or directory
The curious part is, that the only instance of the file name libicui18n.so.52.1 I can even find on my machine are /opt/onlyoffice/desktopeditors/libicui18n.so.52.1 and /home/me/.local/opt/foxitsoftware/foxitreader/lib/libicui18n.so.52.1, which I definitely don't link against, at least according to linker command executed by the build system:
It does not occur as any of the explicit /absolute/path/to/libsomething.so.42.3 files.
Nothing related is given as -L option.
Nothing related is given as /absolute/path/to/libsomething.a file.
Nothing related is in $LD_LIBRARY_PATH or $LIBRARY_PATH.
The Intel Fortran compiler has no reason to include those in the default paths.
So now I am wondering, how else the libicui18n.so.52.1 may be linked against, and how I may go about debugging such an issue.
how else the libicui18n.so.52.1 may be linked against
ELF libraries can specify "what name should be used at runtime" independently of the name of the library itself. Example:
gcc -fPIC -shared -o libt.so t.c -Wl,--soname=libfoo.so.1.2.3
gcc main.c -L. -lt
./a.out
./a.out: error while loading shared libraries: libfoo.so.1.2.3: cannot open shared object file: No such file or directory
Here, the library is built in a way which requires libfoo.so.1.2.3 at runtime, although no such library exists. It is up to the packaging system to provide such library (or a symlink).
You can examine a library to see what name it expects to be used at runtime like so:
readelf -d libt.so | grep SONAME
0x000000000000000e (SONAME) Library soname: [libfoo.so.1.2.3]
You can examine the list of libraries a.out requires at runtime like so:
readelf -d ./a.out | grep NEEDED
0x0000000000000001 (NEEDED) Shared library: [libfoo.so.1.2.3]
0x0000000000000001 (NEEDED) Shared library: [libc.so.6]
how I may go about debugging such an issue.
As above. Your next question is probably "how can I fix this issue?".
Since libicui18n.so.52.1 is installed, but not installed into a directory which the dynamic linker will search by default, all you have to do is tell your binary to add the non-standard /opt/onlyoffice/desktopeditors directory the list of directories to search.
You do that by adding -Wl,-rpath=/opt/onlyoffice/desktopeditors to your executable's link line.
You can also add /opt/onlyoffice/desktopeditors to LD_LIBRARY_PATH, but using -Wl,-rpath is preferred.

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
$#

How to see the order of shared library loading

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.

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