[PATCH] manual: Document indirect functions (IFUNC)
Adhemerval Zanella Netto
adhemerval.zanella@linaro.org
Thu Jun 18 19:48:56 GMT 2026
On 17/06/26 06:48, Yury Khrustalev wrote:
> On Wed, Jun 10, 2026 at 03:24:06PM -0300, Adhemerval Zanella wrote:
>> Add a new section to the Dynamic Linker chapter describing the
>> STT_GNU_IFUNC mechanism: the resolver calling convention for each
>> supported architecture, when resolvers run, and the functionality
>> supported in resolvers (TLS access, stack protector, cross-object
>> references) along with the remaining restrictions, reflecting the
>> recent ordering fixes (BZ 20680, BZ 23240, BZ 28817, BZ 34164,
>> BZ 34170). Also cross-reference it from the hardening section.
>
> Thanks, this is very helpful addition to the Glibc manual! Some
> comments below.
>
>> ---
>> manual/dynlink.texi | 287 +++++++++++++++++++++++++++++++++++++++++++-
>> 1 file changed, 284 insertions(+), 3 deletions(-)
>>
>> diff --git a/manual/dynlink.texi b/manual/dynlink.texi
>> index 5c1579ff098..66c313657b5 100644
>>
>> ...
>>
>> +Indirect functions are usually defined using the @code{ifunc} function
>> +attribute provided by GCC and compatible compilers:
>> +
>> +@smallexample
>> +static int
>> +my_func_generic (int a)
>> +@{
>> + /* @r{@dots{}} */
>> +@}
>> +
>> +static int
>> +my_func_vectorized (int a)
>> +@{
>> + /* @r{@dots{}} */
>> +@}
>> +
>> +/* @r{The resolver returns the address of the selected
>> + implementation.} */
>> +static int (*my_func_resolver (void)) (int)
>
> Perhaps, static int (*my_func_resolver (int)) (void)?
I used Andreas Suggestion of:
static typeof (my_func_generic) *
my_func_resolver (void)
>
>>
>> ...
>>
>> +The architecture-specific conventions are:
>> +
>> +@table @asis
>> +@item AArch64
>> +@smallexample
>> +#include <sys/ifunc.h>
>> +
>> +void *resolver (uint64_t hwcap, const __ifunc_arg_t *arg);
>
> On AArch64 the preferred way is (see [1]):
>
> void *resolver (uint64_t, const uint64_t *)
>
> While using __ifunc_arg_t is acceptable, it is somewhat confusing
> in light of recent extension of this argument to hwcap3,4.
Ack, the __ifunc_arg_t is also a type in the reserved namespace.
>
> [1]: https://github.com/ARM-software/abi-aa/blob/main/sysvabi64/sysvabi64.rst#gnu-c-library-ifunc-interface
>
> Perhaps, just reference [1] in this section for the details to avoid
> repetition that might diverge in the future?
Ack, I added:
The canonical documentation for this interface is the
@cite{GNU C Library ifunc interface} section of the @cite{ELF for the
Arm 64-bit Architecture (AArch64)} ABI, available at
@uref{https://github.com/ARM-software/abi-aa/blob/main/sysvabi64/sysvabi64.rst#gnu-c-library-ifunc-interface}.
>
> That said, the section in [1] that tries to describe Glibc handling of
> ifunc resolvers should probably be updated or removed (with a reference
> to the updated Glibc manual), so that AArch64-specific things are
> described in [1] while Glibc-specific things are described here.
Interesting, I was not aware ARM sysvabi has added ifunc ABI specification.
The doc it says that if sys/ifunc.h is used we can use __ifunc_arg_t instead
of the canonical 'uint64_t'. I think we should stick to uint64_t, as you
suggested.
>
>>
>> ...
>>
>> +@subsection When IFUNC Resolvers Run
>> +
>> +Resolver functions run early, before the process or the newly loaded
>> +objects are fully initialized. The exact point at which a resolver
>> +runs depends on how the indirect function is referenced and how the
>> +program is linked:
>> +
>> +@itemize @bullet
>> +@item
>> +In dynamically linked programs, resolvers for non-lazy references run
>> +during relocation processing at program startup, before ELF
>> +constructors and before @code{main}.
>
> Should we also say, perhaps in another section aimed at Glibc contributors,
> when resolvers run with respect to the process start-up stages (e.g. after
> tunables processing etc)?
I started to document it, but I circled back for two reasons:
1. It's an implementation detail, not a contract: The stage list (tunables,
security_init, relro, libc early-init, etc.) differs between the static and
dynamic paths and shifts between releases. We might have to reorder some
due either bug or some new feature.
2. The stable, useful facts are already covered: what a resolver author actually
needs is what *state* is valid when the resolver runs.
So I focused on documenting the features that are available during IFUNC
resolution, instead of how they are implemented.
The is one extra guarantee that I think it would be worth to add:
tunables and glibc's CPU-feature detection are processed before any resolver
runs (which might be required by resolvers to correctly select a variant,
e.g. via <sys/platform/x86.h>, or the arg hwcaps):
@item
Tunables (@pxref{Tunables}) and the architecture-specific CPU feature
detection used by @theglibc{} are processed before any resolver runs.
A resolver that selects an implementation based on @theglibc{}'s CPU
feature data therefore observes values that already reflect any tunable
that masks hardware capabilities, such as @code{glibc.cpu.hwcaps}
(@pxref{Hardware Capability Tunables}).
>
>> Non-lazy references include data
>> +relocations against the function address (for example, initialized
>> +function pointer variables), and all references if lazy binding is
>> +disabled (for example, with the @option{-z now}
>
> s/link-time option/static link-time option/
> (I know it's almost obvious, but I think it would be more precise.)
Ack.
>
>>
>> ...
>>
>> +@subsection Supported Functionality in IFUNC Resolvers
>> +
>> +Because resolvers run during relocation processing, only a restricted
>> +execution environment is available to them. @Theglibc{} guarantees
>> +the following:
>> +
>> +@itemize @bullet
>> +@item
>> +The thread control block (TCB) of the initial thread is set up before
>> +any resolver runs.
>
> Does this apply to Glibc's own resolvers? I think it's worth to
> point this out.
Yes, the TCB guarantee (and the other environment guarantees) do apply to
glibc's own resolvers and I have added a note about:
@Theglibc{} itself defines indirect functions and the guarantees above
apply to these internal resolvers as well.
I did not added glibc own internal implementation constraints, like
the resolves should not call functions that are themselves indirect
functions, because this does not add much in manual.
>
>>
>> ...
>>
>> +The guarantees described in this section are provided by @theglibc{}
>> +version 2.44 and later.
>
> I think we should mention this above before we list guarantees.
> Perhaps add a "since X version" in each guarantee in case we add more
> in the future versions.
Right, I had the mental model that the manual would be read for an
specific version (like the manual of 2.44 when targetting glibc 2.44),
but I think it would be better to make it more explicit. I will extend
it by adding which version each guarantee was introduced.
>
>> ...
>
> Thanks,
> Yury
>
More information about the Libc-alpha
mailing list