Frank
Frank

Reputation: 171

Building portable apps on newer systems to support older glibc

I'm trying to build an application that supports older versions of GLIBC, my target is GLIBC 2.17. This application is using several static libraries (curl, openssl). It is being built on a system with GLIBC 2.28. At the moment it requires GLIBC 2.25 (it did require 2.28, but i resolved that, see later in the post for more info). It doesnt currently run on systems with GLIBC 2.17 installed,

./myApp: /lib64/libc.so.6: version 'GLIBC_2.25' not found (required by ./myApp)

My researched pointed to a few ways of building my app so it supported older systems.

  1. Most of my research indicated building this on application on the oldest system I want to support. So in this case building on a system with GLIBC 2.17. I've briefly explored this option. Setting up a build system using GLIBC 2.17 has been difficult. For example Centos7 rungs GLIC 2.17 but it appears that mingw64 is no longer available for it (I'm also cross compiling the application to Windows, creating a 2nd build system is not ideal as it would add to the complexity). So i'd like to leave this as a last resort and explore other options, if they exist.
  2. Upgrade/run multiple versions of GLIBC on the target host - not possible. I dont have control of the end systems
  3. Include glibc as a static library in the application - From what i read, not a good idea.
  4. Use musl instead - Briefly tried this, couldn't get it to compile. I can keep trying this method
  5. Or creating portable apps via this reference: https://insanecoding.blogspot.com/2012/07/creating-portable-linux-binaries.html

The current GLIBC requirements of my application, GLIC2.25 is the highest version it requires.

ldd -v myApp 
        linux-vdso.so.1 (0x00007fff799d6000)
        libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f11232f1000)
        libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f1123130000)
        /lib64/ld-linux-x86-64.so.2 (0x00007f1123805000)

        Version information:
        ./myApp:
                libpthread.so.0 (GLIBC_2.2.5) => /lib/x86_64-linux-gnu/libpthread.so.0
                libc.so.6 (GLIBC_2.14) => /lib/x86_64-linux-gnu/libc.so.6
                libc.so.6 (GLIBC_2.3.4) => /lib/x86_64-linux-gnu/libc.so.6
                libc.so.6 (GLIBC_2.3) => /lib/x86_64-linux-gnu/libc.so.6
                libc.so.6 (GLIBC_2.25) => /lib/x86_64-linux-gnu/libc.so.6
                libc.so.6 (GLIBC_2.7) => /lib/x86_64-linux-gnu/libc.so.6
                libc.so.6 (GLIBC_2.17) => /lib/x86_64-linux-gnu/libc.so.6
                libc.so.6 (GLIBC_2.2.5) => /lib/x86_64-linux-gnu/libc.so.6
        /lib/x86_64-linux-gnu/libpthread.so.0:
                ld-linux-x86-64.so.2 (GLIBC_2.2.5) => /lib64/ld-linux-x86-64.so.2
                ld-linux-x86-64.so.2 (GLIBC_PRIVATE) => /lib64/ld-linux-x86-64.so.2
                libc.so.6 (GLIBC_2.14) => /lib/x86_64-linux-gnu/libc.so.6
                libc.so.6 (GLIBC_2.3.2) => /lib/x86_64-linux-gnu/libc.so.6
                libc.so.6 (GLIBC_2.4) => /lib/x86_64-linux-gnu/libc.so.6
                libc.so.6 (GLIBC_2.2.5) => /lib/x86_64-linux-gnu/libc.so.6
                libc.so.6 (GLIBC_PRIVATE) => /lib/x86_64-linux-gnu/libc.so.6
        /lib/x86_64-linux-gnu/libc.so.6:
                ld-linux-x86-64.so.2 (GLIBC_2.3) => /lib64/ld-linux-x86-64.so.2
                ld-linux-x86-64.so.2 (GLIBC_PRIVATE) => /lib64/ld-linux-x86-64.so.2

I'm currently exploring option 5, and I believe I've narrowed it down to a single function that requires GLIBC 2.25, getentropy

objdump -T myApp | grep GLIBC_ | grep 2.25
0000000000000000  w   DF *UND*  0000000000000000  GLIBC_2.25  getentropy

I dont directly call that function, I may indirectly, but not that i'm aware of. I did some digging and it looks like that function is being called in libcrypto. I was able to find that by building a dynamic library and running it through objdump

objdump -T libcrypto.so | grep getentropy
0000000000000000  w   DF *UND*  0000000000000000  GLIBC_2.25  getentropy

The static library

nm -g libcrypto.a | grep getentropy
                 w getentropy

I created a Centos 7 docker container, which is running GLIBC 2.17 and rebuilt the static library. Note I'm using vcpkg to build the static library. After bringing the static library over to my main build system, which is running GLIBC 2.28, i still have the requirement of GLIBC 2.25

ldd -v myApp 
        linux-vdso.so.1 (0x00007fff799d6000)
        libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f11232f1000)
        libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f1123130000)
        /lib64/ld-linux-x86-64.so.2 (0x00007f1123805000)

        Version information:
        ./myApp:
                libpthread.so.0 (GLIBC_2.2.5) => /lib/x86_64-linux-gnu/libpthread.so.0
                libc.so.6 (GLIBC_2.14) => /lib/x86_64-linux-gnu/libc.so.6
                libc.so.6 (GLIBC_2.3.4) => /lib/x86_64-linux-gnu/libc.so.6
                libc.so.6 (GLIBC_2.3) => /lib/x86_64-linux-gnu/libc.so.6
                libc.so.6 (GLIBC_2.25) => /lib/x86_64-linux-gnu/libc.so.6
                libc.so.6 (GLIBC_2.7) => /lib/x86_64-linux-gnu/libc.so.6
                libc.so.6 (GLIBC_2.17) => /lib/x86_64-linux-gnu/libc.so.6
                libc.so.6 (GLIBC_2.2.5) => /lib/x86_64-linux-gnu/libc.so.6

            

The application wont run on my target system that is running GLIBC 2.17.

Please note that myApp originally required GLIBC 2.28, and going through the process with objdump i was able to narrow it down to fcntl64 which was in libcurl. By building libcurl on CentOS7 i was able to remove the GLIBC 2.28 requirement.

Looking through the built binary i found this:

nm -g newAgent | grep getentropy
                 w getentropy@@GLIBC_2.25
             

If I build everything on CentOS 7 i see:

ldd -v myApp 
        linux-vdso.so.1 =>  (0x00007fff4b734000)
        libpthread.so.0 => /lib64/libpthread.so.0 (0x00007f9ea4eef000)
        libc.so.6 => /lib64/libc.so.6 (0x00007f9ea4b21000)
        /lib64/ld-linux-x86-64.so.2 (0x00007f9ea510b000)

        Version information:
        ./myApp:
                libpthread.so.0 (GLIBC_2.2.5) => /lib64/libpthread.so.0
                libc.so.6 (GLIBC_2.14) => /lib64/libc.so.6
                libc.so.6 (GLIBC_2.3.4) => /lib64/libc.so.6
                libc.so.6 (GLIBC_2.3) => /lib64/libc.so.6
                libc.so.6 (GLIBC_2.7) => /lib64/libc.so.6
                libc.so.6 (GLIBC_2.17) => /lib64/libc.so.6
                libc.so.6 (GLIBC_2.2.5) => /lib64/libc.so.6
        .....
[root@f89001979d38 agent_code]# nm -g myApp | grep getentropy
                 w getentropy

It's not linked to GLIBC 2.25. The "w" i believe indicates that it is a weak symbol. My understanding of weak symbols is that the library defines the code for getentropy, but if another version if found, like in GLIBC, then it will use that version instead.

My guestions i guess

  1. Am i missing anything, is something else possibly making the app require GLIBC 2.25?
  2. Can i pass an argument or compile my code somwhow so that it doesnt search for GLIBC getentropy? My end goal is to run this on systems with GLIC 2.17

Upvotes: 2

Views: 929

Answers (1)

Frank
Frank

Reputation: 171

So not sure if this is the best method, but I was able to remove the dependency on getentropy. I am using vcpkg to build the libraries and was able to find in the code where it defines getentropy. Then using this https://stackoverflow.com/a/72778459/4400676 I was able to apply that patch and remove the external dependency.

ldd -v myApp
        linux-vdso.so.1 (0x00007fff57baa000)
        libpthread.so.0 => /lib64/libpthread.so.0 (0x00007f2a4c8f7000)
        libc.so.6 => /lib64/libc.so.6 (0x00007f2a4c000000)
        /lib64/ld-linux-x86-64.so.2 (0x00007f2a4c8fe000)

        Version information:
        ./myApp:
                libpthread.so.0 (GLIBC_2.2.5) => /lib64/libpthread.so.0
                libc.so.6 (GLIBC_2.14) => /lib64/libc.so.6
                libc.so.6 (GLIBC_2.3.4) => /lib64/libc.so.6
                libc.so.6 (GLIBC_2.3) => /lib64/libc.so.6
                libc.so.6 (GLIBC_2.7) => /lib64/libc.so.6
                libc.so.6 (GLIBC_2.17) => /lib64/libc.so.6
                libc.so.6 (GLIBC_2.2.5) => /lib64/libc.so.6
        /lib64/libpthread.so.0:
                libc.so.6 (GLIBC_2.2.5) => /lib64/libc.so.6
        /lib64/libc.so.6:
                ld-linux-x86-64.so.2 (GLIBC_2.2.5) => /lib64/ld-linux-x86-64.so.2
                ld-linux-x86-64.so.2 (GLIBC_2.3) => /lib64/ld-linux-x86-64.so.2
                ld-linux-x86-64.so.2 (GLIBC_PRIVATE) => /lib64/ld-linux-x86-64.so.2

Upvotes: 0

Related Questions