The program cannot find correct version of glibc/libstdc++, although it was statically linked - gcc

I am trying to link my program statically with glibc, because version of the glibc on the target machine is pretty much unpredictable. I used linker flags -static-libgcc and -static-libstdc++ and it worked fine. The executable is big, but I can live with it. Unfortunately, when I run my executable on the target machine (it is named 'mytest' in the example below) I get the following error:
./mytest: /usr/lib64/libstdc++.so.6: version `GLIBCXX_3.4.11' not found (required by libboost_log.so.1.53.0)
./mytest: /usr/lib64/libstdc++.so.6: version `GLIBCXX_3.4.15' not found (required by libboost_log.so.1.53.0)
./mytest: /usr/lib64/libstdc++.so.6: version `GLIBCXX_3.4.9' not found (required by libboost_log.so.1.53.0)
./mytest: /usr/lib64/libstdc++.so.6: version `GLIBCXX_3.4.15' not found (required by libboost_date_time.so.1.53.0)
./mytest: /usr/lib64/libstdc++.so.6: version `GLIBCXX_3.4.9' not found (required by libboost_thread.so.1.53.0)
If I do 'strings' on mytest, it gives me
$ strings mytest | grep GLIBC
GLIBC_2.9
GLIBC_2.7
GLIBC_2.8
GLIBC_2.3.2
GLIBC_2.2.5
GLIBCXX_3.4.15
GLIBCXX_3.4.11
GLIBCXX_3.4.14
GLIBCXX_3.4.9
GLIBCXX_3.4
What means, I think, that the static linking was working ok. Why does the loader still tries to look for my functions in shared glibc and libstdc++? What am I doing wrong?
Thanks!

I am trying to link my program statically with glibc, because version of the glibc on the target machine is pretty much unpredictable. I used linker flags -static-libgcc and -static-libstdc++ and it worked fine.
That didn't affect the version of glibc (libc), which is different from libgcc and libstdc++. With these flags, you still have produced a dynamically-linked executable, which is expected to not work on an older distribution.
You can link your executable with -static flag, and that should give you a completely static executable.
Update:
After re-reading your question; your problem is not with glibc. Your problem is that you are linking with libboost_log.so, which itself depends on libstdc++.so.6.
The answer then is to link with libboost*.a instead of libboost*.so. You can try to achieve it this way:
g++ $(OBJS) -static-libgcc -static-libstdc++ -Wl,-Bstatic -lboost_log ... \
-Wl,-Bdynamic
(It is very important to have the trailing -Wl,-Bdynamic.)

Linking with -static-libgcc and -static-libstdc++ will only work for those libraries. It looks like you are also linking against the boost libraries (likely dynamically) which then link against libgcc and libstdc++.
Try running the following:
ldd mytest
It should show "not a dynamic executable". If it shows anything else, it means it is dynamically linked against other libraries. It doesn't always work so easily, but try adding -static to the compilation line as well to take care of remaining libraries.

Related

Modify default library search dirs that gcc passes to ld

I want to force new GCC 12 on my old debian (that only has GCC 6 by default) to use fresh libstdc++ headers with new header-only features, but link with old stdlibc++,gcc_s (and other system/compiler libs used by GCC6) to keep binary compatibility with native runtime of old debian (so that users of old GCC6 can link with my binaries without having GCC12).
Of course I know that some functionality in the old runtime will be missing, and ABI is also different, but I guess I can fight with that. Afterall RedHat seems to be using similar scheme for their devtoolset packages (they try to link missing functionality of new runtime statically to your binary if these symbols are not found in native old runtime)
So far I am stuck with -L arguments that GCC is passing to ld.
Here is complete output of /usr/local/gcc12/bin/x86_64-linux-gnu-gcc-12 main.cpp -Wl,-v -v command for simple hello-world main.cpp:
https://pastebin.com/JhYSfg4x
The question: Where does GCC take all these -L paths from, and how do I remove/modify them? I don't want to accidentally link with new version of libraries that were built with GCC12:
-L/usr/lib/gcc/x86_64-linux-gnu -L/usr/local/gcc12/lib/gcc/x86_64-linux-gnu/12 -L/usr/local/gcc12/lib/gcc/x86_64-linux-gnu/12/../../../../lib64 -L/lib/x86_64-linux-gnu -L/lib/../lib64 -L/usr/lib/x86_64-linux-gnu -L/usr/lib/gcc -L/usr/local/gcc12/lib/gcc/x86_64-linux-gnu/12/../../.. /tmp/ccXfhCs4.o
System ld.conf does not mention any paths to /usr/local/gcc12 folder.
-nostdlib and -nodefaultlibs are removing some standard -l flags, but they are not doing anything to -L flags.
Update: I ended up just removing all *.a, .so, *.la files from include, lib and lib64 folders of gcc12, and I also added -L path to native libraries. This way I am sure gcc12 can't pickup one of its libraries for li nking. Not sure if this is good solution, but it works.

GCC gprof complaining GLIBC_2.16 is not found

I have a code running on a PowerPC e500v2 embedded Linux and I want to measure its performance since it is running in an infinite loop. I tried gcc's gprof which was simply by adding -pg option to gcc. When I run the binary on the target device I get this:
./main: /lib/libc.so.6: version GLIBC_2.16 not found (required by ./main)
I am using ELDK 5.6 toolchain with the default CFLAGS and LDFLAGS and these flags: -Wall -lrt -pthread -D_GNU_SOURCE nothing else. Some article suggested defining FORTIFY_SOURCE along with an optimization level but it did not work. I searched for some gcc's feature test macros and tried defining some GLIBC 2.16 specific macros but it did not work.
I faced similar issue with GLIBC 2.17 when I used some structures and functions from <sched.h>, adding _GNU_SOURCE resolved it. Any idea on how to resolve it?
When I run the binary on the target device I get this
Your tool chain targets a version of GLIBC that is newer than what is installed on the target.
This doesn't bite you in non-pg compiles only by accident. An "innocent" change to your source can cause the same problem.
You need to upgrade your target to the version of GLIBC which your toolchain actually builds for.

Link against shared library with SONAME

How can I force the gcc linker to link against a given version (soname) of a shared library on the system?
I need this to enforce that the version of openssl that is #include'ed matches the version that is linked, on any system, even if multiple versions of openssl are installed. To find the ABI version, my configure script first compiles and runs a program that extracts the SONAME from the headers:
#include <openssl/opensslv.h>
#include <stdio.h>
int main () {
printf(SHLIB_VERSION_NUMBER);
return 0;
}
The SHLIB_VERSION_NUMBER contains the so version string, e.g. 0.9.8 or 1.0.2k or 1.1.0. But how do I tell gcc to link against this version of libssl or libcrypto rather than just any -lssl?
I tried "in situ" linking, so that instead of linking with gcc main.c -lcrypto we use:
gcc main.c libcrypto.so.1.1.0
However it seems the linker libcrypto.so.1.1.0 cannot be found:
gcc: error: libcrypto.so.1.1.0: No such file or directory
I guess the system only searches in the standard locations when using the -l flag. Is there a better way to make my software link against libcrypto.so.1.1.0?
To select the correct version of the openssl shared libraries use:
gcc main.c -l:libssl.so.1.0.0 -l:libcrypto.so.1.0.0
The key to answering this question is "how do I control ld so that is links the correct version of a shared library?".
The correct way to pass a linker flag (a command line parameter to ld) using the gnu compilers (gcc, g++, gdc, etc...) is to use the normal ld parameter prefixed with "-l". For example -lssl or -L/usr/local/lib.
Edit: As per How to specify the library version to use at link time? you can read the manual for ld with:man ld.

arm-none-eabi-ld cannot find -mcpu=cortex-m3

There is another question with similar naming but it was never resolved.
I installed arm-none-eabi gcc and binutils from the GNU Arm Embedded PPA on Ubuntu. This toolchain normally works fine.
Today however, in my Makefile, I link with -march=armv7-m -mcpu=cortex-m3 as some of the options. This immediately causes ld to fail like this:
$ arm-none-eabi-ld -mcpu=cortex-m3 -march=armv7-m -Tcm3.ld # and some more options
arm-none-eabi-ld: unrecognised emulation mode: arch=armv7-m
Supported emulations: armelf
What have I done wrong? I can't seem to find any information about this!
I've also tested this with my other toolchain (CodeSourcery, March 2011). That toolchain normally works, but fails now too.
Should I be linking with gcc not ld?
It appears that linking with gcc rather than ld solves the problem. I can even pass in the linker script without having to use -Wl,-T.
I'm still open as to why ld didn't work in the first place.

How to link to a specific version of the standard library (with gcc)

I've installed GCC 3.4 to /opt/gcc-3.4, and I'm using it to compile legacy code which is incompatible with GCC 4. This also means old versions of the C(++) standard libraries, binutils, and utility libraries.
It works fine for some libraries, but fails when compiling libtiff, because it picks up the system libraries in /usr/lib (see output below). This might be an autotools/configure issue, but I'm not sure. I can't find a configure switch or environment variable, and I'd rather not modify my system /usr/lib/libc.so .
So how to make sure it links to the standard library in /opt/gcc-3.4.4/lib, and ignores /lib and /usr/lib completely?
Output of make (excerpt):
libtool: link: g++ -shared -nostdlib /usr/lib/crti.o /opt/gcc-3.4.3/lib/gcc/i686-pc-linux-gnu/3.4.3/crtbeginS.o .libs/tif_stream.o -Wl,--whole-archive ../port/.libs/libport.a -Wl,--no-whole-archive -Wl,-rpath -Wl,/home/jason/d0src34/prereq/tiff-3.9.4/libtiff/.libs -Wl,-rpath -Wl,/opt/gcc-3.4.3/lib -Wl,-rpath -Wl,/home/jason/d0src34/prereq/usr/lib -Wl,-rpath -Wl,/opt/gcc-3.4.3/lib ../libtiff/.libs/libtiff.so -L/usr/lib /usr/lib/libjpeg.so -lz -L/opt/gcc-3.4.3/lib/gcc/i686-pc-linux-gnu/3.4.3 -L/opt/gcc-3.4.3/lib/gcc/i686-pc-linux-gnu/3.4.3/../../.. /opt/gcc-3.4.3/lib/libstdc++.so -L/home/jason/Downloads/gcc-3.4.3/build/i686-pc-linux-gnu/libstdc++-v3/src -L/home/jason/Downloads/gcc-3.4.3/build/i686-pc-linux-gnu/libstdc++-v3/src/.libs -L/home/jason/Downloads/gcc-3.4.3/build/gcc -lm -lc -lgcc_s /opt/gcc-3.4.3/lib/gcc/i686-pc-linux-gnu/3.4.3/crtendS.o /usr/lib/crtn.o -Wl,-soname -Wl,libtiffxx.so.3 -o .libs/libtiffxx.so.3.9.4
/home/jason/d0src34/prereq/usr/bin/ld:/usr/lib/libc.so: file format not recognized; treating as linker script
/home/jason/d0src34/prereq/usr/bin/ld:/usr/lib/libc.so:5: parse error
I've found a (hackish) answer to my own question:
I've been using binutils 2.15, because later versions have an incompatibility with GCC 3.4. In more recent versions, the format of /usr/lib/libc.so has changed, and the old binutils can't parse it.
I temporarily commented out the last line (with "GROUP"), and my code compiled:
/* GNU ld script
Use the shared library, but some functions are only in
the static library, so try that secondarily. */
OUTPUT_FORMAT(elf32-i386)
/* GROUP ( /lib/libc.so.6 /usr/lib/libc_nonshared.a AS_NEEDED ( /lib/ld-linux.so.2 ) ) */
However, I'm not really satisfied, since I can hardly tell other people who want to use the code to edit their system files. Also, I'm not sure if I've linked it to the correct glibc version, since the system /usr/lib is still in the search path, so I can't tell for sure if the binaries will work on other systems.

Resources