The code that handled non-PLT GNU IFUNC relocations was removed in r343484.
This may leave some relocations unhandled, which can cause crashes or misbehavior.
For instance, on PowerPC64, the code snippet below causes a crash:
void *(*f)(void *, const void *, size_t); f = memcpy; f(dst, src, len);
This happens because memcpy is an IFUNC on PowerPC64, and the assignment of its
pointer to f causes a non-PLT GNU IFUNC relocation to be generated. As the
relocation is not handled, it remains 0, resulting in an indirect call to a
NULL pointer. Another example is Postgres, that has a very similar code fragment
and is currently crashing when invoked by initdb.
The problem also occurs on amd64, but it's harder to trigger it.
But it can be reproduced by creating a test library that exports an
imemcpy function, that mimics memcpy but is an IFUNC, and building the
test program as PIE. Or by using amd64_get_fbase function instead of memcpy.
It also occurs on non-PIE binaries, when a shared object takes the address of
an IFUNC defined on another shared object
(but if the same IFUNC is also used by the main binary, then rtld end up finding
the symbol in the PLT of the main binary and the issue doesn't occur).
On PowerPC64, it happens more frequently because its binaries always use
the TOC to reference global symbols, that has a role similar to the GOT.
One possible solution for the issue described would be to revert r343484
(ifunc_init() would also need to be called earlier, before relocate_objects()).
The main problem with it is that, as described in r343484 and D17529, it
restricts what IFUNC resolvers can do, mainly by disallowing them to use
symbols that are defined (or visible) outside the resolver's translation unit.
Note, however, that this conforms to the restrictions listed at
Because of that and also to take advantage of the late IFUNC resolving that is
now implemented in rtld, this patch simply moves the resolving of non-PLT GNU IFUNC
relocations inside resolve_object_ifunc().