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.