1.\" Copyright (c) 2019 The FreeBSD Foundation 2.\" 3.\" This documentation was written by Mark Johnston <markj@FreeBSD.org> 4.\" under sponsorship from the FreeBSD Foundation. 5.\" 6.\" Redistribution and use in source and binary forms, with or without 7.\" modification, are permitted provided that the following conditions 8.\" are met: 9.\" 1. Redistributions of source code must retain the above copyright 10.\" notice, this list of conditions and the following disclaimer. 11.\" 2. Redistributions in binary form must reproduce the above copyright 12.\" notice, this list of conditions and the following disclaimer in the 13.\" documentation and/or other materials provided with the distribution. 14.\" 15.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25.\" SUCH DAMAGE. 26.\" 27.Dd May 18, 2019 28.Dt DEFINE_IFUNC 9 29.Os 30.Sh NAME 31.Nm DEFINE_IFUNC 32.Nd define a kernel function with an implementation selected at run-time 33.Sh SYNOPSIS 34.In machine/ifunc.h 35.Fn DEFINE_IFUNC qual ret_type name args 36.Sh DESCRIPTION 37ifuncs are a linker feature which allows the programmer to define functions 38whose implementation is selected at boot-time or module load-time. 39The 40.Nm 41macro can be used to define an ifunc. 42The selection is performed by a resolver function, which returns a pointer 43to the selected function. 44ifunc resolvers are invoked very early during the machine-dependent 45initialization routine, or at load time for dynamically loaded modules. 46Resolution must occur before the first call to an ifunc. 47ifunc resolution is performed after CPU features are enumerated and after the 48kernel's environment is initialized. 49The typical use-case for an ifunc is a routine whose behavior depends on 50optional CPU features. 51For example, newer generations of a given CPU architecture may provide an 52instruction to optimize a common operation. 53To avoid the overhead of testing for the CPU feature each time the operation 54is performed, an ifunc can be used to provide two implementations for the 55operation: one targeting platforms with the extra instruction, and one 56for older platforms. 57.Pp 58Because 59.Nm 60is a macro that defines a dynamically typed function, its usage looks somewhat 61unusual. 62The 63.Ar qual 64parameter is a list of zero or more C function qualifiers to be applied to the 65ifunc. 66This parameter is typically empty or the 67.Dv static 68qualifier. 69.Ar ret_type 70is the return type of the ifunc. 71.Ar name 72is the name of the ifunc. 73.Ar args 74is a parenthesized, comma-separated list of the parameter types of the function, 75as they would appear in a C function declaration. 76.Pp 77The 78.Nm 79usage must be followed by the resolver function body. 80The resolver must return a function with return type 81.Ar ret_type 82and parameter types 83.Ar args . 84The resolver function is defined with the 85.Ql resolver 86gcc-style function attribute, causing the corresponding 87.Xr elf 5 88function symbol to be of type 89.Dv STT_GNU_IFUNC 90instead of 91.Dv STT_FUNC . 92The kernel linker invokes the resolver to process relocations targeting ifunc 93calls and PLT entries referencing such symbols. 94.Sh EXAMPLES 95ifunc resolvers are executed early during boot, before most kernel facilities 96are available. 97They are effectively limited to checking CPU feature flags and tunables. 98.Bd -literal 99static size_t 100fast_strlen(const char *s __unused) 101{ 102 size_t len; 103 104 /* Fast, but may not be correct in all cases. */ 105 __asm("movq $42,%0\\n" : "=r" (len)); 106 return (len); 107} 108 109static size_t 110slow_strlen(const char *s) 111{ 112 const char *t; 113 114 for (t = s; *t != '\\0'; t++); 115 return (t - s); 116} 117 118DEFINE_IFUNC(, size_t, strlen, (const char *)) 119{ 120 int enabled; 121 122 enabled = 1; 123 TUNABLE_INT_FETCH("debug.use_fast_strlen", &enabled); 124 if (enabled && (cpu_features & CPUID_FAST_STRLEN) != 0) 125 return (fast_strlen); 126 else 127 return (slow_strlen); 128} 129.Ed 130.Pp 131This defines a 132.Fn strlen 133function with an optimized implementation for CPUs that advertise support. 134.Sh SEE ALSO 135.Xr elf 5 136.Sh NOTES 137ifuncs are not supported on all architectures. 138They require both toolchain support, to emit function symbols of type 139.Dv STT_GNU_IFUNC , 140and kernel linker support to invoke ifunc resolvers during boot or 141during module load. 142