On Fri, Jun 24, 2011 at 05:16:12PM -0400, Adam Jackson wrote:
and compiling it. In this case, -z relro on its own will not help:
the
address of the 'exit' function isn't known until it's first called,
because function resolution is normally done lazily, and because the
'exit' symbol is not provided in the executable itself. So the
exit_type_array will end up in the final executable in a writeable
section. However, -z relro _will_ constify relocations that end up as
part of the same linked object, eg, a function defined in one
translation unit whose address is taken in another.
If instead you say both -z relro and -z now, then you are explicitly
asking the runtime linker to resolve all symbols up front. In this case
the address of 'exit' _will_ be known before ctors are run, which means
the array can be emitted in a .data.rel.ro section, which is initially
writeable but made read-only after relocations.
For binaries the address of 'exit' will be actually the exit@plt address
in the .plt section of the binary, and for symbols that don't have plt
entries in the binary, it is still a normal relocation against the symbol.
Only .rel{,a}.plt relocations are resolved lazily, all other relocations
are always resolved immediately. So if you have relocation against exit
in .data.rel.ro section in a shared library, it will be resolved right away
and then .data.rel.ro can be write protected if PT_GNU_RELRO covers it.
Either it will resolve to exit@plt in the binary if any, or to the
definition. With -z now in addition to -z relro, the only differences
are that .dynamic flags will tell ld.so to disable lazy relocation
and that PT_GNU_RELRO will also cover the .got.plt section, which is
normally after the PT_GNU_RELRO section, so it can be written into.
Jakub