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.\" $FreeBSD$ 28.\" 29.Dd May 18, 2019 30.Dt DEFINE_IFUNC 9 31.Os 32.Sh NAME 33.Nm DEFINE_IFUNC 34.Nd define a kernel function with an implementation selected at run-time 35.Sh SYNOPSIS 36.In machine/ifunc.h 37.Fn DEFINE_IFUNC qual ret_type name args 38.Sh DESCRIPTION 39ifuncs are a linker feature which allows the programmer to define functions 40whose implementation is selected at boot-time or module load-time. 41The 42.Nm 43macro can be used to define an ifunc. 44The selection is performed by a resolver function, which returns a pointer 45to the selected function. 46ifunc resolvers are invoked very early during the machine-dependent 47initialization routine, or at load time for dynamically loaded modules. 48Resolution must occur before the first call to an ifunc. 49ifunc resolution is performed after CPU features are enumerated and after the 50kernel's environment is initialized. 51The typical use-case for an ifunc is a routine whose behavior depends on 52optional CPU features. 53For example, newer generations of a given CPU architecture may provide an 54instruction to optimize a common operation. 55To avoid the overhead of testing for the CPU feature each time the operation 56is performed, an ifunc can be used to provide two implementations for the 57operation: one targeting platforms with the extra instruction, and one 58for older platforms. 59.Pp 60Because 61.Nm 62is a macro that defines a dynamically typed function, its usage looks somewhat 63unusual. 64The 65.Ar qual 66parameter is a list of zero or more C function qualifiers to be applied to the 67ifunc. 68This parameter is typically empty or the 69.Dv static 70qualifier. 71.Ar ret_type 72is the return type of the ifunc. 73.Ar name 74is the name of the ifunc. 75.Ar args 76is a parenthesized, comma-separated list of the parameter types of the function, 77as they would appear in a C function declaration. 78.Pp 79The 80.Nm 81usage must be followed by the resolver function body. 82The resolver must return a function with return type 83.Ar ret_type 84and parameter types 85.Ar args . 86The resolver function is defined with the 87.Ql resolver 88gcc-style function attribute, causing the corresponding 89.Xr elf 5 90function symbol to be of type 91.Dv STT_GNU_IFUNC 92instead of 93.Dv STT_FUNC . 94The kernel linker invokes the resolver to process relocations targeting ifunc 95calls and PLT entries referencing such symbols. 96.Sh EXAMPLES 97ifunc resolvers are executed early during boot, before most kernel facilities 98are available. 99They are effectively limited to checking CPU feature flags and tunables. 100.Bd -literal 101static size_t 102fast_strlen(const char *s __unused) 103{ 104 size_t len; 105 106 /* Fast, but may not be correct in all cases. */ 107 __asm("movq $42,%0\\n" : "=r" (len)); 108 return (len); 109} 110 111static size_t 112slow_strlen(const char *s) 113{ 114 const char *t; 115 116 for (t = s; *t != '\\0'; t++); 117 return (t - s); 118} 119 120DEFINE_IFUNC(, size_t, strlen, (const char *)) 121{ 122 int enabled; 123 124 enabled = 1; 125 TUNABLE_INT_FETCH("debug.use_fast_strlen", &enabled); 126 if (enabled && (cpu_features & CPUID_FAST_STRLEN) != 0) 127 return (fast_strlen); 128 else 129 return (slow_strlen); 130} 131.Ed 132.Pp 133This defines a 134.Fn strlen 135function with an optimized implementation for CPUs that advertise support. 136.Sh SEE ALSO 137.Xr elf 5 138.Sh NOTES 139ifuncs are not supported on all architectures. 140They require both toolchain support, to emit function symbols of type 141.Dv STT_GNU_IFUNC , 142and kernel linker support to invoke ifunc resolvers during boot or 143during module load. 144