Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I build my Linux c++ app to link to an old version of libc?

I have built an app on Ubuntu 12.04 and have tried running it on an embedded system. I ran apt-cache show libc6 on my dev machine which shows (amongst other things)

Package: libc6
Priority: required
Section: libs
Architecture: i386
Source: eglibc
Version: 2.15-0ubuntu10
Replaces: belocs-locales-bin, libc6-i386
Provides: glibc-2.13-1, libc6-i686

The version of libc6 that exists on the embedded device is 2.8.90. In the \lib directory on the device I have 2 libs

libc-2.8.90.so
libc.so.6

When I copy my application onto the embedded device I get the following errors

/usr/lib/libc.so.6: version `GLIBC_2.15` not found (required by ./ServerSocketApp)

I know that if possible I when I build the application on my dev maching I need to force it to link to the same version of libc6 as exists on the embedded device. The problem I have is that I simply do not know how to do this. Any answers that I have found are meaningless to me right now. Is there some option that I need to pass to g++ to get this to link to version 2.8.90 ??

In desperation I am thinking is it possible to copy the libc on my dev machine onto the embedded device in place of what is there already and hope for the best??? I just cannot seem to find any documentation online that explains in simple terms how you even go about this so any advice at all would be really really welcome as I am tearing my hair out here.

like image 753
mathematician1975 Avatar asked Jul 09 '12 14:07

mathematician1975


1 Answers

OK, here is a somewhat longer explanation, but proceed with care. I still strongly recommend that you setup a chrooted environment to match the one available on the embedded device and use it during the last stage of your build process.

You should understand how dynamically linked ELF executables are loaded and executed. There is something called the run-time link editor (RTLD), also known as the dynamic linker, that takes care of loading all the necessary dynamically linked libraries, fixing relocations and so on. The name of the dynamic linker is /lib/ld-linux.so.2 on 32-bit Linux systems with glibc2 and /lib64/ld-linux-x86-64.so.2 on 64-bit Linux systems with glibc2. The dynamic linker is very tightly coupled to the glibc2 library and usually can only handle the matching version of that library. Also the path to it is hardcoded into the executable by the linker (usually ld, implicitly called by the compiler to do the linking). You can easily check the validty of the last statement by simply doing ldd some_elf_executable - the run-time link editor shows up with the full path:

$ ldd some_elf_executable
linux-vdso.so.1 =>  (0x00007fffab59e000)
libm.so.6 => /lib64/libm.so.6 (0x0000003648400000)
libc.so.6 => /lib64/libc.so.6 (0x0000003648800000)
/lib64/ld-linux-x86-64.so.2 (0x0000003648000000) <--- the RTLD

In order to produce a dynamically linked executable that uses a version of glibc2 different from the one installed on the system, where the executable is to be run, you should link your code with the following set of options to ld:

  • -rpath=/path/to/newer/libs - this one instructs the dynamic linker to first search /path/to/newer/libs when trying to resolve library dependencies. /path/to/newer/libs should match the path where you have copied the newer glibc2 version on the embedded device
  • -rpath-link=/path/to/newer/libs - this option instructs the linker (not the dynamic linker) to use /path/to/newer/libs when resolving dependencies between shared libraries during link time - this should not be normally necessary in your case
  • --dynamic-linker=/path/to/newer/libs/ld-linux.so.2 - this one overrides the path to the RTLD that gets embedded into the executable

The way to provide those options to ld is usually via the -Wl option of GCC.

-rpath=/path/to/newer/libs

becomes:

-Wl,-rpath,/path/to/newer/libs

(notice that the = is replaced by ,)

--dynamic-linker=/path/to/newer/libs/ld-linux.so.2

becomes:

-Wl,--dynamic-linker,/path/to/newer/libs/ld-linux.so.2

You should copy /lib/ld-linux.so.2 from your development system to /path/to/newer/libs/ on the embedded device. You should also copy libc.so.6, the mathematical library libm.so.6 and all the other libraries that are used by the executable or that might get loaded indirectly. Note that libc.so.6 and libm.so.6 are actually symbolic links to the real libraries which have names like libc-2.<version>.so. You should copy those library files and create the appropriate symbolic links to make everybody happy.

like image 51
Hristo Iliev Avatar answered Nov 08 '22 05:11

Hristo Iliev