xref: /illumos-gate/usr/src/uts/common/krtld/reloc.h (revision 4859da614b562d26b86cd0961067070cb5ed350c)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright (c) 1995, 2010, Oracle and/or its affiliates. All rights reserved.
24  *
25  * Copyright 2020 Joyent, Inc.
26  */
27 
28 #ifndef	_RELOC_DOT_H
29 #define	_RELOC_DOT_H
30 
31 #if defined(_KERNEL)
32 #include <sys/bootconf.h>
33 #include <sys/kobj.h>
34 #include <sys/kobj_impl.h>
35 #else
36 #include <rtld.h>
37 #include <conv.h>
38 #endif /* _KERNEL */
39 
40 #include "reloc_defs.h"
41 
42 #ifdef	__cplusplus
43 extern "C" {
44 #endif
45 
46 /*
47  * Global include file for relocation common code.
48  */
49 
50 /*
51  * In user land, redefine the relocation table and relocation engine to be
52  * class/machine specific if necessary.  This allows multiple engines to
53  * reside within a single instance of libld.
54  */
55 #if	!defined(_KERNEL)
56 
57 #if defined(DO_RELOC_LIBLD)
58 #undef DO_RELOC_LIBLD
59 #endif
60 
61 #if	defined(DO_RELOC_LIBLD_X86)
62 
63 #define	DO_RELOC_LIBLD
64 #if	defined(_ELF64)
65 #define	do_reloc_ld		do64_reloc_ld_x86
66 #define	reloc_table		reloc64_table_x86
67 #else
68 #define	do_reloc_ld		do32_reloc_ld_x86
69 #define	reloc_table		reloc32_table_x86
70 #endif
71 
72 #elif	defined(DO_RELOC_LIBLD_SPARC)
73 
74 #define	DO_RELOC_LIBLD
75 #if	defined(_ELF64)
76 #define	do_reloc_ld		do64_reloc_ld_sparc
77 #define	reloc_table		reloc64_table_sparc
78 #else
79 #define	do_reloc_ld		do32_reloc_ld_sparc
80 #define	reloc_table		reloc32_table_sparc
81 #endif
82 
83 #else				/* rtld */
84 
85 #if	defined(_ELF64)
86 #define	do_reloc_rtld		do64_reloc_rtld
87 #define	reloc_table		reloc64_table
88 #else
89 #define	do_reloc_rtld		do32_reloc_rtld
90 #define	reloc_table		reloc32_table
91 #endif
92 
93 #endif
94 
95 #endif	/* !_KERNEL */
96 
97 /*
98  * Relocation table and macros for testing relocation table flags.
99  */
100 extern	const Rel_entry	reloc_table[];
101 
102 #define	IS_PLT(X)		RELTAB_IS_PLT(X, reloc_table)
103 #define	IS_GOT_RELATIVE(X)	RELTAB_IS_GOT_RELATIVE(X, reloc_table)
104 #define	IS_GOT_PC(X)		RELTAB_IS_GOT_PC(X, reloc_table)
105 #define	IS_GOTPCREL(X)		RELTAB_IS_GOTPCREL(X, reloc_table)
106 #define	IS_GOT_BASED(X)		RELTAB_IS_GOT_BASED(X, reloc_table)
107 #define	IS_GOT_OPINS(X)		RELTAB_IS_GOT_OPINS(X, reloc_table)
108 #define	IS_GOT_REQUIRED(X)	RELTAB_IS_GOT_REQUIRED(X, reloc_table)
109 #define	IS_PC_RELATIVE(X)	RELTAB_IS_PC_RELATIVE(X, reloc_table)
110 #define	IS_ADD_RELATIVE(X)	RELTAB_IS_ADD_RELATIVE(X, reloc_table)
111 #define	IS_REGISTER(X)		RELTAB_IS_REGISTER(X, reloc_table)
112 #define	IS_NOTSUP(X)		RELTAB_IS_NOTSUP(X, reloc_table)
113 #define	IS_SEG_RELATIVE(X)	RELTAB_IS_SEG_RELATIVE(X, reloc_table)
114 #define	IS_EXTOFFSET(X)		RELTAB_IS_EXTOFFSET(X, reloc_table)
115 #define	IS_SEC_RELATIVE(X)	RELTAB_IS_SEC_RELATIVE(X, reloc_table)
116 #define	IS_TLS_INS(X)		RELTAB_IS_TLS_INS(X, reloc_table)
117 #define	IS_TLS_GD(X)		RELTAB_IS_TLS_GD(X, reloc_table)
118 #define	IS_TLS_LD(X)		RELTAB_IS_TLS_LD(X, reloc_table)
119 #define	IS_TLS_IE(X)		RELTAB_IS_TLS_IE(X, reloc_table)
120 #define	IS_TLS_LE(X)		RELTAB_IS_TLS_LE(X, reloc_table)
121 #define	IS_LOCALBND(X)		RELTAB_IS_LOCALBND(X, reloc_table)
122 #define	IS_SIZE(X)		RELTAB_IS_SIZE(X, reloc_table)
123 
124 /*
125  * Relocation engine.
126  *
127  * The do_reloc() code is used in three different places: The kernel,
128  * the link-editor, and the runtime linker. All three convey the same
129  * basic information with the first 5 arguments:
130  *
131  * 1)	Relocation type. The kernel and runtime linker pass this as
132  *	an integer value, while the link-editor passes it as a Rel_desc
133  *	descriptor. The relocation engine only looks at the rel_rtype
134  *	field of this descriptor, and does not examine the other fields,
135  *	which are explicitly allowed to contain garbage.
136  * 2)	Address of offset
137  * 3)	Address of value
138  * 4)	Name of symbol associated with the relocation, used if it is
139  *	necessary to report an error. The kernel and runtime linker pass
140  *	directly as a string pointer. The link-editor passes the address
141  *	of a rel_desc_sname_func_t function, which can be called by do_reloc(),
142  *	passing it the Rel_desc pointer (argument 1, above), to obtain the
143  *	string pointer.
144  * 5)	String giving the source file for the relocation.
145  *
146  * In addition:
147  *	- The linker and rtld want a link map pointer argument
148  *	- The linker wants to pass a byte swap argument that tells
149  *		the relocation engine that the data it is relocating
150  *		has the opposite byte order of the system running the
151  *		linker.
152  *	- The linker is a cross-linker, meaning that it can examine
153  *		relocation records for target hosts other than that of
154  *		the currently running system. This means that multiple
155  *		versions of the relocation code must be able to reside
156  *		in a single program, without namespace clashes.
157  *
158  * To ensure that there is never any confusion about which version is
159  * being linked to, we give each variant a different name, even though
160  * each one is generated from the same source code.
161  *
162  *	do_reloc_krtld()
163  *	The kernel version is provided if the _KERNEL macro is defined.
164  *
165  *	do_reloc_ld()
166  *	The ld version is provided if the DO_RELOC_LIBLD_ macro is defined.
167  *
168  *	do_reloc_rtld()
169  *	The rtld version is provided if neither _KERNEL or DO_RELOC_LIBLD
170  *	are defined.
171  *
172  * Implementations of do_reloc() should use these same macros to
173  * conditionalize any code not used by all three versions.
174  */
175 #if defined(_KERNEL)
176 extern	int	do_reloc_krtld(uchar_t, uchar_t *, Xword *, const char *,
177 		    const char *);
178 #elif defined(DO_RELOC_LIBLD)
179 extern	int	do_reloc_ld(Rel_desc *, uchar_t *, Xword *,
180 		    rel_desc_sname_func_t, const char *, int, void *);
181 #else
182 extern	int	do_reloc_rtld(uchar_t, uchar_t *, Xword *, const char *,
183 		    const char *, void *);
184 #endif
185 
186 #if defined(_KERNEL)
187 /*
188  * These are macro's that are only needed for krtld.  Many of these are already
189  * defined in the sgs/include files referenced by ld and rtld
190  */
191 #define	S_MASK(n)	((1l << (n)) - 1l)
192 #define	S_INRANGE(v, n)	(((-(1l << (n)) - 1l) < (v)) && ((v) < (1l << (n))))
193 
194 /*
195  * Message strings used by doreloc().
196  */
197 #define	MSG_STR_UNKNOWN		"(unknown)"
198 
199 #define	MSG_REL_PREGEN		"relocation error: %s: "
200 #define	MSG_REL_PREFIL		"relocation error: file %s: "
201 #define	MSG_REL_FILE		"file %s: "
202 #define	MSG_REL_SYM		"symbol %s: "
203 #define	MSG_REL_VALUE		"value 0x%llx "
204 #define	MSG_REL_LOSEBITS	"loses %d bits at "
205 
206 #define	MSG_REL_UNIMPL		"unimplemented relocation type: %d"
207 #define	MSG_REL_UNSUPSZ		"offset size (%d bytes) is not supported"
208 #define	MSG_REL_NONALIGN	"offset 0x%llx is non-aligned"
209 #define	MSG_REL_UNNOBITS	"unsupported number of bits: %d"
210 #define	MSG_REL_OFFSET		"offset 0x%llx"
211 #define	MSG_REL_NOFIT		"value 0x%llx does not fit"
212 
213 /*
214  * Provide a macro to select the appropriate conversion routine for this
215  * architecture.
216  */
217 #if defined(__amd64)
218 
219 extern const char	*conv_reloc_amd64_type(Word);
220 #define	CONV_RELOC_TYPE	conv_reloc_amd64_type
221 
222 #elif defined(__i386)
223 
224 extern const char	*conv_reloc_386_type(Word);
225 #define	CONV_RELOC_TYPE	conv_reloc_386_type
226 
227 #elif defined(__sparc)
228 
229 extern const char	*conv_reloc_SPARC_type(Word);
230 #define	CONV_RELOC_TYPE	conv_reloc_SPARC_type
231 
232 #else
233 #error platform not defined!
234 #endif
235 
236 
237 /*
238  * Note:  dlerror() only keeps track of a single error string, and therefore
239  * must have errors reported through a single eprintf() call.  The kernel's
240  * _kobj_printf is somewhat more limited, and must receive messages with only
241  * one argument to the format string.  The following macros account for these
242  * differences, as krtld and rtld share the same do_reloc() source.
243  */
244 #define	REL_ERR_UNIMPL(lml, file, sym, rtype) \
245 	_kobj_printf(ops, MSG_REL_PREFIL, (file)); \
246 	_kobj_printf(ops, MSG_REL_SYM, ((sym) ? (sym) : MSG_STR_UNKNOWN)); \
247 	_kobj_printf(ops, MSG_REL_UNIMPL, (int)(rtype))
248 
249 #define	REL_ERR_UNSUPSZ(lml, file, sym, rtype, size) \
250 	_kobj_printf(ops, MSG_REL_PREGEN, CONV_RELOC_TYPE((rtype))); \
251 	_kobj_printf(ops, MSG_REL_FILE, (file)); \
252 	_kobj_printf(ops, MSG_REL_SYM, ((sym) ? (sym) : MSG_STR_UNKNOWN)); \
253 	_kobj_printf(ops, MSG_REL_UNSUPSZ, (int)(size))
254 
255 #define	REL_ERR_NONALIGN(lml, file, sym, rtype, off) \
256 	_kobj_printf(ops, MSG_REL_PREGEN, CONV_RELOC_TYPE((rtype))); \
257 	_kobj_printf(ops, MSG_REL_FILE, (file)); \
258 	_kobj_printf(ops, MSG_REL_SYM, ((sym) ? (sym) : MSG_STR_UNKNOWN)); \
259 	_kobj_printf(ops, MSG_REL_NONALIGN, (u_longlong_t)EC_OFF((off)))
260 
261 #define	REL_ERR_UNNOBITS(lml, file, sym, rtype, nbits) \
262 	_kobj_printf(ops, MSG_REL_PREGEN, CONV_RELOC_TYPE((rtype))); \
263 	_kobj_printf(ops, MSG_REL_FILE, (file)); \
264 	_kobj_printf(ops, MSG_REL_SYM, ((sym) ? (sym) : MSG_STR_UNKNOWN)); \
265 	_kobj_printf(ops, MSG_REL_UNNOBITS, (nbits))
266 
267 #define	REL_ERR_LOSEBITS(lml, file, sym, rtype, uvalue, nbits, off) \
268 	_kobj_printf(ops, MSG_REL_PREGEN, CONV_RELOC_TYPE((rtype))); \
269 	_kobj_printf(ops, MSG_REL_FILE, (file)); \
270 	_kobj_printf(ops, MSG_REL_SYM, ((sym) ? (sym) : MSG_STR_UNKNOWN)); \
271 	_kobj_printf(ops, MSG_REL_VALUE, (u_longlong_t)EC_XWORD((uvalue))); \
272 	_kobj_printf(ops, MSG_REL_LOSEBITS, (int)(nbits)); \
273 	_kobj_printf(ops, MSG_REL_OFFSET, (u_longlong_t)EC_NATPTR((off)))
274 
275 #define	REL_ERR_NOFIT(lml, file, sym, rtype, uvalue) \
276 	_kobj_printf(ops, MSG_REL_PREGEN, CONV_RELOC_TYPE((rtype))); \
277 	_kobj_printf(ops, MSG_REL_FILE, (file)); \
278 	_kobj_printf(ops, MSG_REL_SYM, ((sym) ? (sym) : MSG_STR_UNKNOWN)); \
279 	_kobj_printf(ops, MSG_REL_NOFIT, (u_longlong_t)EC_XWORD((uvalue)))
280 
281 
282 #else	/* !_KERNEL */
283 
284 extern	const char *demangle(const char *);
285 
286 #define	REL_ERR_UNIMPL(lml, file, sym, rtype) \
287 	(eprintf(lml, ERR_FATAL, MSG_INTL(MSG_REL_UNIMPL), (file), \
288 	    ((sym) ? demangle(sym) : MSG_INTL(MSG_STR_UNKNOWN)), (int)(rtype)))
289 
290 #define	REL_ERR_UNSUPSZ(lml, file, sym, rtype, size) \
291 	(eprintf(lml, ERR_FATAL, MSG_INTL(MSG_REL_UNSUPSZ), \
292 	    conv_reloc_type_static(M_MACH, (rtype), 0), (file), \
293 	    ((sym) ? demangle(sym) : MSG_INTL(MSG_STR_UNKNOWN)), (int)(size)))
294 
295 #define	REL_ERR_NONALIGN(lml, file, sym, rtype, off) \
296 	(eprintf(lml, ERR_FATAL, MSG_INTL(MSG_REL_NONALIGN), \
297 	    conv_reloc_type_static(M_MACH, (rtype), 0), (file), \
298 	    ((sym) ? demangle(sym) : MSG_INTL(MSG_STR_UNKNOWN)), EC_OFF((off))))
299 
300 #define	REL_ERR_UNNOBITS(lml, file, sym, rtype, nbits) \
301 	(eprintf(lml, ERR_FATAL, MSG_INTL(MSG_REL_UNNOBITS), \
302 	    conv_reloc_type_static(M_MACH, (rtype), 0), (file), \
303 	    ((sym) ? demangle(sym) : MSG_INTL(MSG_STR_UNKNOWN)), (nbits)))
304 
305 #define	REL_ERR_LOSEBITS(lml, file, sym, rtype, uvalue, nbits, off) \
306 	(eprintf(lml, ERR_FATAL,  MSG_INTL(MSG_REL_LOSEBITS), \
307 	    conv_reloc_type_static(M_MACH, (rtype), 0), (file), \
308 	    ((sym) ? demangle(sym) : MSG_INTL(MSG_STR_UNKNOWN)), \
309 	    EC_XWORD((uvalue)), (nbits), EC_NATPTR((off))))
310 
311 #define	REL_ERR_NOFIT(lml, file, sym, rtype, uvalue) \
312 	(eprintf(lml, ERR_FATAL, MSG_INTL(MSG_REL_NOFIT), \
313 	    conv_reloc_type_static(M_MACH, (rtype), 0), (file), \
314 	    ((sym) ? demangle(sym) : MSG_INTL(MSG_STR_UNKNOWN)), \
315 	    EC_XWORD((uvalue))))
316 
317 #endif	/* _KERNEL */
318 
319 #ifdef	__cplusplus
320 }
321 #endif
322 
323 #endif /* _RELOC_DOT_H */
324