Home > Software engineering >  Mismatch between output of ldd --version and ldd -r -v a.out
Mismatch between output of ldd --version and ldd -r -v a.out

Time:12-19

I am trying to make sense of how output of ldd --version and ldd -v a.out

I have the below simple program

#include <iostream>
#include <string>
#include <cstring>

int main()
{
    std::cout << "Hello world" << std::endl;
    std::string a = "Test string";
    char b[15] = {};
    memcpy(b, a.c_str(), 15);
    std::cout << b << std::endl;
    return 0;
}

I compile it with following command

g --std=c 17 test.cpp

I want to find out which glibc version this program is going to use when I run say memcpy.

The output of ldd --version on this system is:

ldd --version
ldd (Ubuntu GLIBC 2.31-0ubuntu9.2) 2.31
Copyright (C) 2020 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
Written by Roland McGrath and Ulrich Drepper.

The output of ldd -v a.out is

ldd -v a.out 
    linux-vdso.so.1 (0x00007ffe7d3f3000)
    libstdc  .so.6 => /usr/lib/x86_64-linux-gnu/libstdc  .so.6 (0x00007f050bb2f000)
    libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f050bb14000)
    libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f050b922000)
    libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f050b7d3000)
    /lib64/ld-linux-x86-64.so.2 (0x00007f050bd3a000)

    Version information:
    ./a.out:
        libgcc_s.so.1 (GCC_3.0) => /lib/x86_64-linux-gnu/libgcc_s.so.1
        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
        libstdc  .so.6 (GLIBCXX_3.4.21) => /usr/lib/x86_64-linux-gnu/libstdc  .so.6
        libstdc  .so.6 (CXXABI_1.3) => /usr/lib/x86_64-linux-gnu/libstdc  .so.6
        libstdc  .so.6 (GLIBCXX_3.4) => /usr/lib/x86_64-linux-gnu/libstdc  .so.6
    /usr/lib/x86_64-linux-gnu/libstdc  .so.6:
        libm.so.6 (GLIBC_2.2.5) => /lib/x86_64-linux-gnu/libm.so.6
        ld-linux-x86-64.so.2 (GLIBC_2.3) => /lib64/ld-linux-x86-64.so.2
        libgcc_s.so.1 (GCC_4.2.0) => /lib/x86_64-linux-gnu/libgcc_s.so.1
        libgcc_s.so.1 (GCC_3.4) => /lib/x86_64-linux-gnu/libgcc_s.so.1
        libgcc_s.so.1 (GCC_3.3) => /lib/x86_64-linux-gnu/libgcc_s.so.1
        libgcc_s.so.1 (GCC_3.0) => /lib/x86_64-linux-gnu/libgcc_s.so.1
        libc.so.6 (GLIBC_2.14) => /lib/x86_64-linux-gnu/libc.so.6
        libc.so.6 (GLIBC_2.6) => /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.18) => /lib/x86_64-linux-gnu/libc.so.6
        libc.so.6 (GLIBC_2.16) => /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.3.4) => /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.3.2) => /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/libgcc_s.so.1:
        libc.so.6 (GLIBC_2.14) => /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/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
    /lib/x86_64-linux-gnu/libm.so.6:
        ld-linux-x86-64.so.2 (GLIBC_PRIVATE) => /lib64/ld-linux-x86-64.so.2
        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

What I can not understand is that if ldd --version says that I have GLIBC version 2.31 available then why did my executables ldd output say GLIBC_2.4 and GLIBC_2.2.5 for a.out.

What is the right way to understand this?

What would happen if I have compiled a binary on a system that has old version of libc.so (suppose has highest version of GLIBC as 2.17) and then run the binary on a system with new version of libc.so (suppose has highest version of GLIBC as 2.31) ?

Thanks

CodePudding user response:

You should read this answer, and look at the output from readelf -V a.out.

When a program is linked, it records the symbol version(s) used (current) at the time of the link.

Many of the symbols your program is using have not changed since e.g. GLIBC_2.2.5, so ldd says: you need at least version GLIBC_2.2.5 (for these symbols). Some of the symbols you use have changed in GLIBC-2.16, GLIBC-2.17 and GLIBC-2.18, so ldd says that you need these as well.

What would happen if I have compiled a binary on a system that has old version of libc.so (suppose has highest version of GLIBC as 2.17) and then run the binary on a system with new version of libc.so (suppose has highest version of GLIBC as 2.31) ?

The recorded symbols (encoded into a.out) will all be GLIBC_2.17 or older, and the program will run fine on a newer system, because GLIBC guarantees backward compatibility (programs built on an older system continue to run fine on newer ones).

But if you did the inverse -- built on a GLIBC-2.31 system and tried to run the program on a GLIBC-2.17 one, it may (or may not, depending on which symbols it actually uses) fail.

In the example you provided, the highest required version of GLIBC is GLIBC_2.18. Therefore, this particular a.out will work fine on a GLIBC-2.18 or newer system, but will fail on GLIBC-2.17 or older one.

  • Related