A deep dive into the 'stat storm' problem in Nix, where the dynamic loader makes hundreds of failing openat() syscalls before a program even starts. The root cause is Nix's per-package store layout requiring long DT_RUNPATH lists in ELF headers, causing O(N×M) failed library searches. Five approaches are analyzed: absolute DT_NEEDED paths (fast but breaks LD_LIBRARY_PATH overrides), RUNPATH symlink farms (preserves overrides but can't handle duplicate sonames), per-DSO ELF note caches (best tradeoffs but requires glibc patch), Guix-style per-package ld.so.cache (breaks cross-compilation), and static linking with musl (drops devenv from 70ms to 16ms but not a general fix). The chosen solution is the ELF note cache, now shipped in patchelf 0.19.0, with a nixpkgs PR pending to enable it across the whole package set. The goal is eventually upstreaming the glibc loader patch.

15m read timeFrom devenv.sh
Post cover image
Table of contents
Why Nix makes the loader work so hardWhat a good fix has to preserveApproach 1: freeze the resolution with absolute pathsApproach 2: the RUNPATH symlink farmApproach 3: a per DSO resolution cache in an ELF noteApproach 4: a Guix style per package ld.so.cacheApproach 5: delete the loader with static linkingWhat about macOS?Side by sideThe final approach
204 Impressions