DEFINE_IFUNC(9)

πŸ“¦ version 15.1, in freebsd 14.5, freebsd 15.1, nixpkgs unstable

hii bestie πŸ’– welcome to DEFINE_IFUNC(9) from the Kernel Developer's Manual β€” this is the page for defining a kernel function whose implementation gets picked at run-time. no cap, it's a whole vibe.

🌸 NAME 🌸

DEFINE_IFUNC β€” define a kernel function with an implementation selected at run-time ✨

✨ SYNOPSIS ✨

#include <machine/ifunc.h>

DEFINE_IFUNC(qual, ret_type, name, args);

πŸ’– DESCRIPTION πŸ’–

okay so ifuncs are a linker feature that lets you define functions whose implementation is selected at boot-time or module load-time. The DEFINE_IFUNC macro is how you define an ifunc. The selection is done by a resolver function, which returns a pointer to the selected function. ifunc resolvers are invoked very early during the machine-dependent initialization routine, or at load time for dynamically loaded modules. Resolution must happen before the first call to an ifunc. ifunc resolution is performed after CPU features are enumerated and after the kernel's environment is initialized. The typical use-case for an ifunc is a routine whose behavior depends on optional CPU features. For example, newer generations of a given CPU architecture may provide an instruction to optimize a common operation. To avoid the overhead of testing for the CPU feature every single time the operation is performed, an ifunc can provide two implementations for the operation: one targeting platforms with the extra instruction, and one for older platforms. slay πŸ’…

Because DEFINE_IFUNC is a macro that defines a dynamically typed function, its usage looks somewhat unusual. Here's the parameter breakdown, bestie:

  • qual β€” a list of zero or more C function qualifiers to be applied to the ifunc. This parameter is typically empty or the static qualifier.
  • ret_type β€” the return type of the ifunc.
  • name β€” the name of the ifunc.
  • args β€” a parenthesized, comma-separated list of the parameter types of the function, as they would appear in a C function declaration.

The DEFINE_IFUNC usage must be followed by the resolver function body. The resolver must return a function with return type ret_type and parameter types args. The resolver function is defined with the resolver gcc-style function attribute, which causes the corresponding elf(5) function symbol to be of type STT_GNU_IFUNC instead of STT_FUNC. The kernel linker invokes the resolver to process relocations targeting ifunc calls and PLT entries referencing such symbols. iconic behavior tbh 🫢

πŸŽ€ EXAMPLES πŸŽ€

ifunc resolvers are executed early during boot, before most kernel facilities are available. They are effectively limited to checking CPU feature flags and tunables.

static size_t
fast_strlen(const char *s __unused)
{
        size_t len;

        /* Fast, but may not be correct in all cases. */
        __asm("movq $42,%0\n" : "=r" (len));
        return (len);
}

static size_t
slow_strlen(const char *s)
{
        const char *t;

        for (t = s; *t != '\0'; t++);
        return (t - s);
}

DEFINE_IFUNC(, size_t, strlen, (const char *))
{
        int enabled;

        enabled = 1;
        TUNABLE_INT_FETCH("debug.use_fast_strlen", &enabled);
        if (enabled && (cpu_features & CPUID_FAST_STRLEN) != 0)
                return (fast_strlen);
        else
                return (slow_strlen);
}

This defines a strlen() function with an optimized implementation for CPUs that advertise support. okay that's actually so cool 😭πŸ”₯

πŸ¦‹ SEE ALSO πŸ¦‹

elf(5)

πŸ’€ NOTES πŸ’€

ifuncs are not supported on all architectures. They require both toolchain support, to emit function symbols of type STT_GNU_IFUNC, and kernel linker support to invoke ifunc resolvers during boot or during module load. so yeah β€” vibe check your arch first, bestie πŸ’œ


mwah πŸ’‹ this page is from Debian, dated May 18, 2019 β€” DEFINE_IFUNC(9), and that's the whole page, periodt πŸŽ€βœ¨

πŸ“¦ where this page comes from