linkerelfloader

Isn't `-no-plt` always preferrable to `-z now`?


I know that keeping the GOT writable in an ELF program throughout execution is a glaring attack surface and understand that it was decided to avoid it by defaulting to -z relro and sometimes -z now (at the compiler level? Distro level? Not sure).

What I don't understand is why do we still bother erecting the elaborate PLT structure to prepare for lazy binding, then populate it entirely at load time. Wouldn't it have been better to default to -no-plt? Is there some tradeoff I'm missing?


Solution

  • My guess is -fno-plt is not used by default in GCC because it disables any possibility of lazy binding.

    Not keeping it the default lets the developer explicitly and knowingly choose it as an option if required.

    Even if the link time option of -z relro and -z now are used, one can still use the environment variable LD_BIND_NOT at run time to modify the behaviour of ld.so. This is useful, as documented here, for use in conjunction with LD_DEBUG for debugging and trouble shooting. But that works only if the PLT entries are still around.

    Also, there is a reference here of GNU Indirect Functions needing the PLT for their reasonable operation. Without the PLT, GNU Indirect Functions require TEXTRELs which is considered retrograde. In fact, the answers to this question explain why GOT and PLT are retained even in statically linked binaries. GNU Indirect Functions are used in glibc, for instance, for enhanced runtime performance optimizations.

    The PLT does have a bunch of uses, for which it is may be preferred, not to be kicked out by default. Even if it is not used, having the PLT entries around does have its advantages.

    This link has some discussion of different platforms including support for -fno-plt and some making it the default with benefits and downsides mentioned.