Re: Attacks LD_PRELOAD
Simple answer: Static linking creates a different type of file that the dynamic linker does not understand:
Create hello_world.c and compile it with: "gcc -o hello_world hello_world.c" then run: "file hello_world" and you get output like:
hello_world: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=8ff789376a00beebceecf9d11428eed4fd02622b, for GNU/Linux 3.2.0, not stripped
Now compile it again with: "gcc -o static_world -static hello_world.c" and run "file static_world":
static_world: ELF 64-bit LSB executable, x86-64, version 1 (GNU/Linux), statically linked, BuildID[sha1]=93e4e42fed15a9819b3df716d95c8f60e4bdc796, for GNU/Linux 3.2.0, not stripped
Note that hello_world has an interpreter (the dynamic linker) but static world does not. hello_world can be executed via its interpreter: "/lib64/ld-linux-x86-64.so.2 ./hello_world" and it runs fine. Try "/lib64/ld-linux-x86-64.so.2 ./static_world". I got a Segmentation fault - the dynamic linker (which is the thing that uses LD_PRELOAD) does not understand static executables at all and promptly dies of confusion.
It goes deeper: even if the dynamic linker did not crash and did load the libraries from LD_PRELOAD for a static executable, the dynamic libraries would have their constructors executed but would not be able to redirect calls inside the static executable. Static calls know where the required functions are and go straight there. Dynamic calls read a function pointer variable that initially point to a function in the dynamic linker. The dynamic linker looks up the name in the loaded shared libraries (and loads more if the name is not found) then updates the function pointer to point at the shared library function then calls it.
That is a lot of complexity but hello world is about 16kB and static_world is 780kB (using puts, it would be worse with printf). If every executable is static you are going to use a lot of memory and really thrash the caches.
Complicated answer: Some functionality is implemented by dynamic libraries unless you pay close attention. The obvious example is the name service switch in the C library. If you did not do anything clever, user data is stored in /etc/password in a simple human readable file. You could store it in a database and the C library would provide functions that hide the difference to programs by loading a different shared library.