Using a glibc version that is different from the system-provided one shouldn't require the use of containers, as I recently heard someone claim. Let's take a look at how dynamic linking works and what the options are.
I've a linux/ubuntu (24.04) executable that links to libpthread.so. But, ldd does not list libpthread. However, the program runs and calls pthread functions without any issues. My questions ...
1. Why doesn't ldd list libpthread? What possible reasons?
2. When a program starts, is there a way to display the all shared objects it was able to link to as well as those it wasn't?
2. If a program started successfully, it means all shared objects were found. The way to look at this would be to look at what the dynamic linker is doing before it starts the program. Some value of LD_DEBUG and looking at the messages it prints should let you do that; see https://man7.org/linux/man-pages/man8/ld.so.8.html. But actually, running ldd on the binary will tell you precisely this because missing libraries will show up as "not present".
To ship a binary on Linux, the traditional wisdom has been be compile with a Glibc as old as possible? Can this trick be used to ship a binary with a Glibc as _new_ as possible? As long as all the symbol versions needed by various other components on the system are present in the shipped Glibc, everything should run fine, correct?
As an aside, sometimes you may encounter the reverse problem: running an older binary against an older Glibc version, on a modern system (https://stackoverflow.com/questions/76162069). But the binary may depend on other libraries (such as libX11), so a switch to an older Glibc & interpreter will require you to also bring older versions of all the dependencies, which can be more easily achieved via chroot, a Docker container, or a VM.
I've a linux/ubuntu (24.04) executable that links to libpthread.so. But, ldd does not list libpthread. However, the program runs and calls pthread functions without any issues. My questions ...
1. Why doesn't ldd list libpthread? What possible reasons?
2. When a program starts, is there a way to display the all shared objects it was able to link to as well as those it wasn't?
1. I don't know exactly, but the answer seems to lie somewhere in https://man7.org/linux/man-pages/man7/pthreads.7.html after the "Compiling on Linux" subsection. Insane stuff I had never seen before...
2. If a program started successfully, it means all shared objects were found. The way to look at this would be to look at what the dynamic linker is doing before it starts the program. Some value of LD_DEBUG and looking at the messages it prints should let you do that; see https://man7.org/linux/man-pages/man8/ld.so.8.html. But actually, running ldd on the binary will tell you precisely this because missing libraries will show up as "not present".
To ship a binary on Linux, the traditional wisdom has been be compile with a Glibc as old as possible? Can this trick be used to ship a binary with a Glibc as _new_ as possible? As long as all the symbol versions needed by various other components on the system are present in the shipped Glibc, everything should run fine, correct?
That's a great read, thank you!
As an aside, sometimes you may encounter the reverse problem: running an older binary against an older Glibc version, on a modern system (https://stackoverflow.com/questions/76162069). But the binary may depend on other libraries (such as libX11), so a switch to an older Glibc & interpreter will require you to also bring older versions of all the dependencies, which can be more easily achieved via chroot, a Docker container, or a VM.