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