Link to an old version of libc for more application coverage

Linux binaries are usually dynamically linked to the main system library (libc). This allows you to keep the memory size of a binary file quite small, but binary files that depend on the latest libraries will not work on older systems. Conversely, binaries associated with older libraries will work successfully on the latest systems.

Therefore, in order for our application to have good coverage during distribution, we need to find out the oldest libc that we can support and associate with this binary code.

How to identify an old version of libc that we can reference?

+55
linux linker libc
Oct 27 2018-10-27
source share
4 answers

Determine which characters in the executable are dependent on the unwanted version of glibc.

$ objdump -p myprog ... Version References: required from libc.so.6: 0x09691972 0x00 05 GLIBC_2.3 0x09691a75 0x00 03 GLIBC_2.2.5 $ objdump -T myprog | fgrep GLIBC_2.3 0000000000000000 DF *UND* 0000000000000000 GLIBC_2.3 realpath 

Look in the dependent library to see if there are characters in older versions that you can refer to:

 $ objdump -T /lib/libc.so.6 | grep -w realpath 0000000000105d90 g DF .text 0000000000000021 (GLIBC_2.2.5) realpath 000000000003e7b0 g DF .text 00000000000004bf GLIBC_2.3 realpath 

We were lucky!

Request the version from GLIBC_2.2.5 in your code:

 #include <limits.h> #include <stdlib.h> __asm__(".symver realpath,realpath@GLIBC_2.2.5"); int main () { realpath ("foo", "bar"); } 

Note that GLIBC_2.3 is no longer required:

 $ objdump -p myprog ... Version References: required from libc.so.6: 0x09691a75 0x00 02 GLIBC_2.2.5 $ objdump -T myprog | grep realpath 0000000000000000 DF *UND* 0000000000000000 GLIBC_2.2.5 realpath 

See http://www.trevorpounds.com/blog/?p=103 for more information.

+65
May 12 '11 at 11:51
source share

Unfortunately, @Sam's solution doesn’t work very well in my situation. But, along his way, I found my way to solve this.

This is my situation:

I am writing a C ++ program using the Thrift framework (this is RPC middleware). I prefer a static link to a dynamic link, so my program is linked statically to libthrift.a instead of libthrift.so. However, libthrift.a is dynamically linked to glibc, and since my libthrift.a is built on my system using glibc 2.15, my libthrift.a uses memcpy version 2.14 ( memcpy @ GLIBC_2. 14 ) provided by glibc 2.15.

But the problem is that our server machines have only glibc 2.5 version, which has only memcpy@GLIBC_2.2.5 . It is much lower than memcpy@GLIBC_2.14 . So, of course, my server program cannot run on these machines.

And I found this solution:

  • Using .symver to get the memcpy@GLIBC_2.2.5 link.

  • Write my own __ wrap_memcpy function, which simply calls memcpy@GLIBC_2.2.5 .

  • When linking my program, add the -Wl, - wrap = memcpy option to gcc / g ++.

The code used in steps 1 and 2 is given here: https://gist.github.com/nicky-zs/7541169

+8
Nov 19 '13 at 6:54
source share

To do this in a more automated way, you can use the following script to create a list of all the characters that are newer in your GLIBC than in this version (set on line 2). It creates a glibc.h file (the file name specified by the script argument) that contains all the necessary .symver . You can then add -include glibc.h to your CFLAGS to make sure that it goes into your entire compilation.

This is sufficient if you are not using any static libraries that were compiled without the above. If you do this and you do not want to recompile, you can use objcopy to create a copy of the library with characters renamed to old versions. The second script on the bottom line creates a version of your libstdc++.a that will reference the old glibc characters. Adding -L. (or -Lpath/to/libstdc++.a/ ) will force your program to statically link libstdC ++ without binding a bunch of new characters. If you do not need this, delete the last two lines and the line printf ... redeff .

 #!/bin/bash maxver=2.9 headerf=${1:-glibc.h} set -e for lib in libc.so.6 libm.so.6 libpthread.so.0 libdl.so.2 libresolv.so.2 librt.so.1; do objdump -T /usr/lib/$lib done | awk -v maxver=${maxver} -vheaderf=${headerf} -vredeff=${headerf}.redef -f <(cat <<'EOF' BEGIN { split(maxver, ver, /\./) limit_ver = ver[1] * 10000 + ver[2]*100 + ver[3] } /GLIBC_/ { gsub(/\(|\)/, "",$(NF-1)) split($(NF-1), ver, /GLIBC_|\./) vers = ver[2] * 10000 + ver[3]*100 + ver[4] if (vers > 0) { if (symvertext[$(NF)] != $(NF-1)) count[$(NF)]++ if (vers <= limit_ver && vers > symvers[$(NF)]) { symvers[$(NF)] = vers symvertext[$(NF)] = $(NF-1) } } } END { for (s in symvers) { if (count[s] > 1) { printf("__asm__(\".symver %s,%s@%s\");\n", s, s, symvertext[s]) > headerf printf("%s %s@%s\n", s, s, symvertext[s]) > redeff } } } EOF ) sort ${headerf} -o ${headerf} objcopy --redefine-syms=${headerf}.redef /usr/lib/libstdc++.a libstdc++.a rm ${headerf}.redef 
+7
Sep 16 '16 at 18:07
source share

glibc 2.2 is a fairly common minimal version. However, finding the build platform for this version may not be trivial.

Probably the best direction is to think about the oldest OS that you want to support and build on it.

+3
Oct 27 2018-10-27
source share



All Articles