LD_PRELOAD pitfalls
LD_PRELOAD is a great hack. I recently encountered a strange error while generating compile_commands.json
with rizsotto/Bear.
Guess what, the culprit is LD_PRELOAD.
A strange error
I was trying to hack on nix. Following nix’s official instructions, I started a nix shell with nix develop
in which we have all the building dependencies (with their versions locked) for nix.
I attempted to generate compile_commands.json
for my language server clangd by running bear -- make
.
I got
make: /nix/store/nprym6lf8lzhp1irb42lb4vp8069l5rj-glibc-2.32-54/lib/libc.so.6: version `GLIBC_2.34' not found (required by /nix/store/8lgjaqkvi7kwgjqlfsf0jdk62n0s572g-bear-3.0.14/libexec/bear/libexec.so)
make: /nix/store/nprym6lf8lzhp1irb42lb4vp8069l5rj-glibc-2.32-54/lib/libc.so.6: version `GLIBC_2.33' not found (required by /nix/store/psijdi9190zgbp053y6dj3ax4y2l70gk-gcc-11.2.0-lib/lib/libstdc++.so.6)
make: /nix/store/nprym6lf8lzhp1irb42lb4vp8069l5rj-glibc-2.32-54/lib/libc.so.6: version `GLIBC_2.34' not found (required by /nix/store/psijdi9190zgbp053y6dj3ax4y2l70gk-gcc-11.2.0-lib/lib/libstdc++.so.6)
make: /nix/store/nprym6lf8lzhp1irb42lb4vp8069l5rj-glibc-2.32-54/lib/libc.so.6: version `GLIBC_2.34' not found (required by /nix/store/psijdi9190zgbp053y6dj3ax4y2l70gk-gcc-11.2.0-lib/lib/libgcc_s.so.1)
I was baffled by this error message, as make
actually never depends on libexec.so
, libstdc++.so.6
or libgcc_s.so.1
.
This can be verified with ldd $(which make)
linux-vdso.so.1 (0x00007ffcb3b84000)
libdl.so.2 => /nix/store/nprym6lf8lzhp1irb42lb4vp8069l5rj-glibc-2.32-54/lib/libdl.so.2 (0x00007fb41cf33000)
libc.so.6 => /nix/store/nprym6lf8lzhp1irb42lb4vp8069l5rj-glibc-2.32-54/lib/libc.so.6 (0x00007fb41cd72000)
/nix/store/nprym6lf8lzhp1irb42lb4vp8069l5rj-glibc-2.32-54/lib/ld-linux-x86-64.so.2 => /nix/store/nprym6lf8lzhp1irb42lb4vp8069l5rj-glibc-2.32-54/lib64/ld-linux-x86-64.so.2 (0x00007fb41cf3a000)
Moreover, as shown in the ldd output, make
only depends on glibc-2.32-54
. Where does this GLIBC_2.34
come from?
Bot running bear
and make
separately and running bear -- make
outside the nix shell are OK.
So who reports this cryptic error and what on hell does this means?
The theory
Bear’s preloaded libexec.so
The spoiler is in this article’s title. bear
used LD_PRELOAD
to preload a dynamic library,
/nix/store/8lgjaqkvi7kwgjqlfsf0jdk62n0s572g-bear-3.0.14/libexec/bear/libexec.so
, to the building process.
This dynamic library is used to trace which processes are launched by the building command.
It would become clear if we have a look at libexec.so
’s dynamic symbols.
readelf -s /nix/store/8lgjaqkvi7kwgjqlfsf0jdk62n0s572g-bear-3.0.14/libexec/bear/libexec.so
shows
Symbol table '.dynsym' contains 34 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
1: 0000000000000000 0 FUNC GLOBAL DEFAULT UND [...]@GLIBC_2.2.5 (2)
2: 0000000000000000 0 OBJECT GLOBAL DEFAULT UND [...]@GLIBC_2.2.5 (2)
3: 0000000000000000 0 FUNC WEAK DEFAULT UND [...]@GLIBC_2.2.5 (2)
4: 0000000000000000 0 FUNC GLOBAL DEFAULT UND [...]@GLIBC_2.2.5 (2)
5: 0000000000000000 0 FUNC GLOBAL DEFAULT UND [...]@GLIBC_2.2.5 (2)
6: 0000000000000000 0 OBJECT GLOBAL DEFAULT UND _[...]@CXXABI_1.3 (3)
7: 0000000000000000 0 FUNC GLOBAL DEFAULT UND fsync@GLIBC_2.2.5 (2)
8: 0000000000000000 0 FUNC GLOBAL DEFAULT UND [...]@GLIBC_2.2.5 (2)
9: 0000000000000000 0 FUNC GLOBAL DEFAULT UND c[...]@GLIBC_2.17 (4)
10: 0000000000000000 0 FUNC GLOBAL DEFAULT UND dlsym@GLIBC_2.34 (5)
11: 0000000000000000 0 OBJECT WEAK DEFAULT UND [...]@GLIBC_2.2.5 (2)
12: 0000000000000000 0 FUNC GLOBAL DEFAULT UND __[...]@GLIBC_2.4 (6)
13: 0000000000000000 0 FUNC GLOBAL DEFAULT UND [...]@GLIBC_2.2.5 (2)
14: 0000000000000000 0 FUNC GLOBAL DEFAULT UND [...]@GLIBC_2.2.5 (2)
15: 0000000000000000 0 FUNC GLOBAL DEFAULT UND __[...]@GLIBC_2.8 (7)
16: 0000000000000000 0 FUNC GLOBAL DEFAULT UND [...]@GLIBC_2.2.5 (2)
17: 0000000000000000 0 OBJECT GLOBAL DEFAULT UND [...]@GLIBC_2.2.5 (2)
18: 0000000000000000 0 NOTYPE WEAK DEFAULT UND _ITM_deregisterT[...]
19: 0000000000000000 0 NOTYPE WEAK DEFAULT UND __gmon_start__
20: 0000000000000000 0 NOTYPE WEAK DEFAULT UND _ITM_registerTMC[...]
21: 0000000000002190 280 FUNC GLOBAL DEFAULT 12 posix_spawnp
22: 0000000000001660 241 FUNC GLOBAL DEFAULT 12 execvp
23: 0000000000001570 233 FUNC GLOBAL DEFAULT 12 execvpe
24: 0000000000001470 241 FUNC GLOBAL DEFAULT 12 execv
25: 0000000000001ba0 565 FUNC GLOBAL DEFAULT 12 execlp
26: 0000000000002070 280 FUNC GLOBAL DEFAULT 12 posix_spawn
27: 0000000000001380 233 FUNC GLOBAL DEFAULT 12 execve
28: 0000000000001760 257 FUNC GLOBAL DEFAULT 12 execvP
29: 0000000000001de0 650 FUNC GLOBAL DEFAULT 12 execle
30: 0000000000001870 233 FUNC GLOBAL DEFAULT 12 exect
31: 0000000000001240 96 FUNC GLOBAL DEFAULT 12 on_load
32: 0000000000001220 32 FUNC GLOBAL DEFAULT 12 on_unload
33: 0000000000001960 565 FUNC GLOBAL DEFAULT 12 execl
We can see, there are several symbols related to exec
, which can be used to trace the commands gcc/clang would run to build the nix program.
What is this error?
This error message is reported by glibc’s dynamic linker.
If we were to trace the loading of dynamic libraries with strace bear -- make
and LD_DEBUG=files,versions bear -- make
.
We will find ld.so
first tries to load libexec.so
(because of the environment variable LD_PRELOAD, see below),
and then loads make
’s direct dynamic library dependencies, finally it loads those libraries’ dynamic library dependencies.
4002469: file=/nix/store/8lgjaqkvi7kwgjqlfsf0jdk62n0s572g-bear-3.0.14/libexec/bear/libexec.so [0]; needed by make [0]
4002469: file=/nix/store/8lgjaqkvi7kwgjqlfsf0jdk62n0s572g-bear-3.0.14/libexec/bear/libexec.so [0]; generating link map
4002469: dynamic: 0x00007f1dfc4b6d20 base: 0x00007f1dfc4b0000 size: 0x0000000000009068
4002469: entry: 0x00007f1dfc4b0000 phdr: 0x00007f1dfc4b0040 phnum: 10
4002469:
4002469:
4002469: file=libdl.so.2 [0]; needed by make [0]
4002469: find library=libdl.so.2 [0]; searching
4002469: search path=/nix/store/nprym6lf8lzhp1irb42lb4vp8069l5rj-glibc-2.32-54/lib/tls/x86_64/x86_64:/nix/store/nprym6lf8lzhp1irb42lb4vp8069l5rj-glibc-2.32-54/lib/tls/x86_64:/nix/store/nprym6lf8lzhp1irb42lb4vp8069l5rj-glibc-2.32-54/lib/tls/x86_64:/nix/store/nprym6lf8lzhp1irb42lb4vp8069l5rj-glibc-2.32-54/lib/tls:/nix/store/nprym6lf8lzhp1irb42lb4vp8069l5rj-glibc-2.32-54/lib/x86_64/x86_64:/nix/store/nprym6lf8lzhp1irb42lb4vp8069l5rj-glibc-2.32-54/lib/x86_64:/nix/store/nprym6lf8lzhp1irb42lb4vp8069l5rj-glibc-2.32-54/lib/x86_64:/nix/store/nprym6lf8lzhp1irb42lb4vp8069l5rj-glibc-2.32-54/lib (system search path)
4002469: trying file=/nix/store/nprym6lf8lzhp1irb42lb4vp8069l5rj-glibc-2.32-54/lib/tls/x86_64/x86_64/libdl.so.2
4002469: trying file=/nix/store/nprym6lf8lzhp1irb42lb4vp8069l5rj-glibc-2.32-54/lib/tls/x86_64/libdl.so.2
4002469: trying file=/nix/store/nprym6lf8lzhp1irb42lb4vp8069l5rj-glibc-2.32-54/lib/tls/x86_64/libdl.so.2
4002469: trying file=/nix/store/nprym6lf8lzhp1irb42lb4vp8069l5rj-glibc-2.32-54/lib/tls/libdl.so.2
4002469: trying file=/nix/store/nprym6lf8lzhp1irb42lb4vp8069l5rj-glibc-2.32-54/lib/x86_64/x86_64/libdl.so.2
4002469: trying file=/nix/store/nprym6lf8lzhp1irb42lb4vp8069l5rj-glibc-2.32-54/lib/x86_64/libdl.so.2
4002469: trying file=/nix/store/nprym6lf8lzhp1irb42lb4vp8069l5rj-glibc-2.32-54/lib/x86_64/libdl.so.2
4002469: trying file=/nix/store/nprym6lf8lzhp1irb42lb4vp8069l5rj-glibc-2.32-54/lib/libdl.so.2
4002469:
4002469: file=libdl.so.2 [0]; generating link map
4002469: dynamic: 0x00007f1dfc4aecf8 base: 0x00007f1dfc4ab000 size: 0x0000000000004090
4002469: entry: 0x00007f1dfc4ac120 phdr: 0x00007f1dfc4ab040 phnum: 9
4002469:
4002469:
4002469: file=libc.so.6 [0]; needed by make [0]
4002469: find library=libc.so.6 [0]; searching
4002469: search path=/nix/store/nprym6lf8lzhp1irb42lb4vp8069l5rj-glibc-2.32-54/lib (system search path)
4002469: trying file=/nix/store/nprym6lf8lzhp1irb42lb4vp8069l5rj-glibc-2.32-54/lib/libc.so.6
4002469:
4002469: file=libc.so.6 [0]; generating link map
4002469: dynamic: 0x00007f1dfc4a39c0 base: 0x00007f1dfc2ea000 size: 0x00000000001c0230
4002469: entry: 0x00007f1dfc311f30 phdr: 0x00007f1dfc2ea040 phnum: 12
4002469:
4002469:
4002469: file=libstdc++.so.6 [0]; needed by /nix/store/8lgjaqkvi7kwgjqlfsf0jdk62n0s572g-bear-3.0.14/libexec/bear/libexec.so [0]
4002469: find library=libstdc++.so.6 [0]; searching
4002469: search path=/nix/store/ayrsyv7npr0lcbann4k9lxr19x813f0z-glibc-2.34-115/lib/tls/x86_64/x86_64:/nix/store/ayrsyv7npr0lcbann4k9lxr19x813f0z-glibc-2.34-115/lib/tls/x86_64:/nix/store/ayrsyv7npr0lcbann4k9lxr19x813f0z-glibc-2.34-115/lib/tls/x86_64:/nix/store/ayrsyv7npr0lcbann4k9lxr19x813f0z-glibc-2.34-115/lib/tls:/nix/store/ayrsyv7npr0lcbann4k9lxr19x813f0z-glibc-2.34-115/lib/x86_64/x86_64:/nix/store/ayrsyv7npr0lcbann4k9lxr19x813f0z-glibc-2.34-115/lib/x86_64:/nix/store/ayrsyv7npr0lcbann4k9lxr19x813f0z-glibc-2.34-115/lib/x86_64:/nix/store/ayrsyv7npr0lcbann4k9lxr19x813f0z-glibc-2.34-115/lib:/nix/store/psijdi9190zgbp053y6dj3ax4y2l70gk-gcc-11.2.0-lib/lib/tls/x86_64/x86_64:/nix/store/psijdi9190zgbp053y6dj3ax4y2l70gk-gcc-11.2.0-lib/lib/tls/x86_64:/nix/store/psijdi9190zgbp053y6dj3ax4y2l70gk-gcc-11.2.0-lib/lib/tls/x86_64:/nix/store/psijdi9190zgbp053y6dj3ax4y2l70gk-gcc-11.2.0-lib/lib/tls:/nix/store/psijdi9190zgbp053y6dj3ax4y2l70gk-gcc-11.2.0-lib/lib/x86_64/x86_64:/nix/store/psijdi9190zgbp053y6dj3ax4y2l70gk-gcc-11.2.0-lib/lib/x86_64:/nix/store/psijdi9190zgbp053y6dj3ax4y2l70gk-gcc-11.2.0-lib/lib/x86_64:/nix/store/psijdi9190zgbp053y6dj3ax4y2l70gk-gcc-11.2.0-lib/lib (RUNPATH from file /nix/store/8lgjaqkvi7kwgjqlfsf0jdk62n0s572g-bear-3.0.14/libexec/bear/libexec.so)
4002469: trying file=/nix/store/ayrsyv7npr0lcbann4k9lxr19x813f0z-glibc-2.34-115/lib/tls/x86_64/x86_64/libstdc++.so.6
4002469: trying file=/nix/store/ayrsyv7npr0lcbann4k9lxr19x813f0z-glibc-2.34-115/lib/tls/x86_64/libstdc++.so.6
4002469: trying file=/nix/store/ayrsyv7npr0lcbann4k9lxr19x813f0z-glibc-2.34-115/lib/tls/x86_64/libstdc++.so.6
4002469: trying file=/nix/store/ayrsyv7npr0lcbann4k9lxr19x813f0z-glibc-2.34-115/lib/tls/libstdc++.so.6
4002469: trying file=/nix/store/ayrsyv7npr0lcbann4k9lxr19x813f0z-glibc-2.34-115/lib/x86_64/x86_64/libstdc++.so.6
4002469: trying file=/nix/store/ayrsyv7npr0lcbann4k9lxr19x813f0z-glibc-2.34-115/lib/x86_64/libstdc++.so.6
4002469: trying file=/nix/store/ayrsyv7npr0lcbann4k9lxr19x813f0z-glibc-2.34-115/lib/x86_64/libstdc++.so.6
4002469: trying file=/nix/store/ayrsyv7npr0lcbann4k9lxr19x813f0z-glibc-2.34-115/lib/libstdc++.so.6
4002469: trying file=/nix/store/psijdi9190zgbp053y6dj3ax4y2l70gk-gcc-11.2.0-lib/lib/tls/x86_64/x86_64/libstdc++.so.6
4002469: trying file=/nix/store/psijdi9190zgbp053y6dj3ax4y2l70gk-gcc-11.2.0-lib/lib/tls/x86_64/libstdc++.so.6
4002469: trying file=/nix/store/psijdi9190zgbp053y6dj3ax4y2l70gk-gcc-11.2.0-lib/lib/tls/x86_64/libstdc++.so.6
4002469: trying file=/nix/store/psijdi9190zgbp053y6dj3ax4y2l70gk-gcc-11.2.0-lib/lib/tls/libstdc++.so.6
4002469: trying file=/nix/store/psijdi9190zgbp053y6dj3ax4y2l70gk-gcc-11.2.0-lib/lib/x86_64/x86_64/libstdc++.so.6
4002469: trying file=/nix/store/psijdi9190zgbp053y6dj3ax4y2l70gk-gcc-11.2.0-lib/lib/x86_64/libstdc++.so.6
4002469: trying file=/nix/store/psijdi9190zgbp053y6dj3ax4y2l70gk-gcc-11.2.0-lib/lib/x86_64/libstdc++.so.6
4002469: trying file=/nix/store/psijdi9190zgbp053y6dj3ax4y2l70gk-gcc-11.2.0-lib/lib/libstdc++.so.6
4002469:
4002469: file=libstdc++.so.6 [0]; generating link map
4002469: dynamic: 0x00007f1dfc2e2be0 base: 0x00007f1dfc0d6000 size: 0x0000000000213840
4002469: entry: 0x00007f1dfc0d6000 phdr: 0x00007f1dfc0d6040 phnum: 11
ld.so
finds out libexec.so
’s dependency libc.so.6
is already satisfied.
libexec.so
’s dynamic section is shown below.
Dynamic section at offset 0x5d20 contains 32 entries:
Tag Type Name/Value
0x0000000000000001 (NEEDED) Shared library: [libdl.so.2]
0x0000000000000001 (NEEDED) Shared library: [libstdc++.so.6]
0x0000000000000001 (NEEDED) Shared library: [libm.so.6]
0x0000000000000001 (NEEDED) Shared library: [libc.so.6]
0x000000000000000e (SONAME) Library soname: [libexec.so]
0x000000000000001d (RUNPATH) Library runpath: [/nix/store/ayrsyv7npr0lcbann4k9lxr19x813f0z-glibc-2.34-115/lib:/nix/store/psijdi9190zgbp053y6dj3ax4y2l70gk-gcc-11.2.0-lib/lib]
So ld.so
does not load libc.so.6
again. Instead it tries to checking if the version provided in glibc.so
satisfies the requirements of libexec.so
.
4002469: checking for version `GLIBC_2.34' in file /nix/store/nprym6lf8lzhp1irb42lb4vp8069l5rj-glibc-2.32-54/lib/libc.so.6 [0] required by file /nix/store/8lgjaqkvi7kwgjqlfsf0jdk62n0s572g-bear-3.0.14/libexec/bear/libexec.so [0]
Unfortunately the version definition section .gnu.version_d
of libc.so.6
does not have
the GLIBC_2.34
in the version needs section .gnu.version_r
of libexec.so
.
Thus, the dynamic linker exits promptly. See All about symbol versioning for more information.
The solution
It is nix’s hermiticity that caused this problem. Because make
specifies the exact path of libc.so.6
in its binary (by modifying library runpath with patchelf). make
must load glibc 2.32, while libexec.so
requires glibc 2.34.
If we were able to use a generic runpath like /usr/lib
, then ld.so
may have loaded glibc 2.34, thus a happy ending.
Resorting to /usr/lib
is not a necessary evil. We have a simpler solution.
Adding bear
to nativeBuildDeps
suffices. In this way, bear
and make
are guaranteed to have the same dependent glibc
version, as they are built with the bootstrap-stage4-stdenv-linux
.
The experiment
Let’s verify our theory above without looking into the bear’s code.
A tricky part of debugging this is that make
exits immediately and bear
folks a few times.
Because make
exits immediately, we have to find a breakpoint not too late, otherwise we have no chance to inspect the status of make
.
Because bear folks a few times, it is somewhat hard for running gdb --args bear -- make
directly to debug make
.
My trick is to run bear -- /nix/store/d60gkg5dkw4y5kc055n4m0xyvcjz65im-bash-interactive-5.1-p16/bin/bash -c 'echo $$; read; exec make'
.
Note /nix/store/d60gkg5dkw4y5kc055n4m0xyvcjz65im-bash-interactive-5.1-p16/bin/bash
must have compatible glibc version with bear
, or
it will immediately exit like make
.
This command outputs the pid, say 3887495, make
was to have and wait for our input to continue to run make
.
We can view current loaded dynamic library for bash with cat /proc/3887495/maps
.
Let’s set two breakpoints, dl_main
and _dl_signal_cexception
, the first is near the entry point of the dynamic linker,
while the second is immediately before the abnormal exit. We also set follow-fork-mode child
for gdb.
This way, we will be able to debug make
instead of bear
. We press enter and make let gdb continue to run the debugee.
To verify our theory, we can run tr '\0' '\n' < /proc/$(pgrep make)/environ | grep bear
, which, as expected, shows
INTERCEPT_REPORT_COMMAND=/nix/store/8lgjaqkvi7kwgjqlfsf0jdk62n0s572g-bear-3.0.14/libexec/bear/wrapper
LD_PRELOAD=/nix/store/8lgjaqkvi7kwgjqlfsf0jdk62n0s572g-bear-3.0.14/libexec/bear/libexec.so
Moreover, grep -i glibc /proc/$(pgrep make)/maps
shows
7fdf6500a000-7fdf65019000 r--p 00000000 00:1c 3391892 /nix/store/ayrsyv7npr0lcbann4k9lxr19x813f0z-glibc-2.34-115/lib/libm.so.6
7fdf65019000-7fdf65086000 r-xp 0000f000 00:1c 3391892 /nix/store/ayrsyv7npr0lcbann4k9lxr19x813f0z-glibc-2.34-115/lib/libm.so.6
7fdf65086000-7fdf650e0000 r--p 0007c000 00:1c 3391892 /nix/store/ayrsyv7npr0lcbann4k9lxr19x813f0z-glibc-2.34-115/lib/libm.so.6
7fdf650e0000-7fdf650e1000 ---p 000d6000 00:1c 3391892 /nix/store/ayrsyv7npr0lcbann4k9lxr19x813f0z-glibc-2.34-115/lib/libm.so.6
7fdf650e1000-7fdf650e3000 rw-p 000d6000 00:1c 3391892 /nix/store/ayrsyv7npr0lcbann4k9lxr19x813f0z-glibc-2.34-115/lib/libm.so.6
7fdf652f7000-7fdf6531d000 r--p 00000000 00:1c 7355687 /nix/store/nprym6lf8lzhp1irb42lb4vp8069l5rj-glibc-2.32-54/lib/libc-2.32.so
7fdf6531d000-7fdf65461000 r-xp 00026000 00:1c 7355687 /nix/store/nprym6lf8lzhp1irb42lb4vp8069l5rj-glibc-2.32-54/lib/libc-2.32.so
7fdf65461000-7fdf654ad000 r--p 0016a000 00:1c 7355687 /nix/store/nprym6lf8lzhp1irb42lb4vp8069l5rj-glibc-2.32-54/lib/libc-2.32.so
7fdf654ad000-7fdf654ae000 ---p 001b6000 00:1c 7355687 /nix/store/nprym6lf8lzhp1irb42lb4vp8069l5rj-glibc-2.32-54/lib/libc-2.32.so
7fdf654ae000-7fdf654b4000 rw-p 001b6000 00:1c 7355687 /nix/store/nprym6lf8lzhp1irb42lb4vp8069l5rj-glibc-2.32-54/lib/libc-2.32.so
7fdf654b8000-7fdf654b9000 r--p 00000000 00:1c 7355694 /nix/store/nprym6lf8lzhp1irb42lb4vp8069l5rj-glibc-2.32-54/lib/libdl-2.32.so
7fdf654b9000-7fdf654ba000 r-xp 00001000 00:1c 7355694 /nix/store/nprym6lf8lzhp1irb42lb4vp8069l5rj-glibc-2.32-54/lib/libdl-2.32.so
7fdf654ba000-7fdf654bb000 r--p 00002000 00:1c 7355694 /nix/store/nprym6lf8lzhp1irb42lb4vp8069l5rj-glibc-2.32-54/lib/libdl-2.32.so
7fdf654bb000-7fdf654bd000 rw-p 00002000 00:1c 7355694 /nix/store/nprym6lf8lzhp1irb42lb4vp8069l5rj-glibc-2.32-54/lib/libdl-2.32.so
7fdf654c9000-7fdf654ca000 r--p 00000000 00:1c 7355677 /nix/store/nprym6lf8lzhp1irb42lb4vp8069l5rj-glibc-2.32-54/lib/ld-2.32.so
7fdf654ca000-7fdf654ea000 r-xp 00001000 00:1c 7355677 /nix/store/nprym6lf8lzhp1irb42lb4vp8069l5rj-glibc-2.32-54/lib/ld-2.32.so
7fdf654ea000-7fdf654f3000 r--p 00021000 00:1c 7355677 /nix/store/nprym6lf8lzhp1irb42lb4vp8069l5rj-glibc-2.32-54/lib/ld-2.32.so
7fdf654f3000-7fdf654f6000 rw-p 00029000 00:1c 7355677 /nix/store/nprym6lf8lzhp1irb42lb4vp8069l5rj-glibc-2.32-54/lib/ld-2.32.so
As we can see, only libc-2.32.so
was loaded and libm.so.6
from 2.34 is loaded (because only libexec.so
depends on libm
).