xref: /freebsd/share/man/man9/DEFINE_IFUNC.9 (revision 4b9d6057)
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