Certain libs use dlopen() which needs dynamic linking. Mesa, Pam, Qt (static is possible but a lot of stuff will break), Glibc(static is possible but nsswitch.conf will break), Alsa. So most graphical apps will fail to be pure static(Prob possible but will hardware/config specific). So we need to tackle and provide alternatives to dlopen.
Running NSS and PAM modules in-process was IMO a historical mistake. Convenient in one aspect, rather inconvenient and impractical in many others.
If we were to redo these today, I think we'd do them out-of-process and talk to them over UNIX domain sockets or pipes.
The transitive dependencies of NSS and PAM modules can also wreak havoc with your application. There are many bugs which have arisen because of these limitations. Yes, looking at you, GnuTLS.
OpenBSD chose BSD Auth over PAM for this reason. With BSD Auth the C API invokes binaries in /usr/lib/auth which are SUID or SGID according to which permissions are required for the credential store.