Reputation: 295
man ld
has the following to say about -z lazy
:
...tell the dynamic linker to defer function call resolution to the point when the function is called ... Lazy binding is the default.
On the other hand, gcc --verbose main.c
passes -z now -z relro
to ld for a main.c with an empty main()
$ gcc --verbose main.c
Using built-in specs.
COLLECT_GCC=gcc
[...]
Thread model: posix
gcc version 7.5.0 (Ubuntu 7.5.0-3ubuntu1~18.04)
[...]
COLLECT_GCC_OPTIONS='-v' '-mtune=generic' '-march=x86-64'
/usr/lib/gcc/x86_64-linux-gnu/7/collect2 [...] -pie -z now -z relro [...]
I see this in Ubuntu 18.04 and 19.04 with default installations of gcc.
So -z lazy
might be the default for ld, but where/why does gcc change that to -z now -z relro
?
Upvotes: 4
Views: 6897
Reputation: 811
It is a ELF binary hardening feature introduced in Ubuntu 16.10 along with PIE enabled by default.
Lazy binding can improve program startup performance by deferring resolution of function symbols. This means partial GOT data (in .got.plt section) has to be writable in runtime. So the .got.plt may be exploit by "GOT overwrite" attack.
When BIND_NOW is enabled, all symbols will be resolved before executing the program code. The .got.plt section is merged into .got section by ld. The ld.so changes the .got section to read-only before calling program entry point. This is called full RELRO.
See this, and this article for more details.
Upvotes: 14