xref: /illumos-gate/usr/src/uts/common/krtld/reloc.h (revision bb57d1f5164aca913cbd286ae1b61c896167cfa7)
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 2007 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/machelf.h>
34 #include <sys/bootconf.h>
35 #include <sys/kobj.h>
36 #include <sys/kobj_impl.h>
37 #else
38 #include <machdep.h>
39 #include <rtld.h>
40 #include <conv.h>
41 #endif /* _KERNEL */
42 
43 #include <relmach.h>
44 
45 #ifdef	__cplusplus
46 extern "C" {
47 #endif
48 
49 /*
50  * Global include file for relocation common code.
51  *
52  * Flags for reloc_entry->re_flags
53  */
54 #define	FLG_RE_NOTREL		0x00000000
55 #define	FLG_RE_GOTADD		0x00000001	/* create a GOT entry */
56 #define	FLG_RE_GOTREL		0x00000002	/* GOT based */
57 #define	FLG_RE_GOTPC		0x00000004	/* GOT - P */
58 #define	FLG_RE_GOTOPINS		0x00000008	/* GOTOP instruction */
59 #define	FLG_RE_PCREL		0x00000010
60 #define	FLG_RE_PLTREL		0x00000020
61 #define	FLG_RE_VERIFY		0x00000040	/* verify value fits */
62 #define	FLG_RE_UNALIGN		0x00000080	/* offset is not aligned */
63 #define	FLG_RE_WDISP16		0x00000100	/* funky sparc DISP16 rel */
64 #define	FLG_RE_SIGN		0x00000200	/* value is signed */
65 #define	FLG_RE_ADDRELATIVE	0x00000400	/* RELATIVE relocation */
66 						/*	required for non- */
67 						/*	fixed objects */
68 #define	FLG_RE_EXTOFFSET	0x00000800	/* extra offset required */
69 #define	FLG_RE_REGISTER		0x00001000	/* relocation initializes */
70 						/*    a REGISTER by OLO10 */
71 #define	FLG_RE_SIZE		0x00002000	/* symbol size required */
72 
73 #define	FLG_RE_NOTSUP		0x00010000	/* relocation not supported */
74 
75 #define	FLG_RE_SEGREL		0x00040000	/* segment relative */
76 #define	FLG_RE_SECREL		0x00080000	/* section relative */
77 
78 #define	FLG_RE_TLSGD		0x00200000	/* TLS GD relocation */
79 #define	FLG_RE_TLSLD		0x00400000	/* TLS LD relocation */
80 #define	FLG_RE_TLSIE		0x00800000	/* TLS IE relocation */
81 #define	FLG_RE_TLSLE		0x01000000	/* TLS LE relocation */
82 #define	FLG_RE_LOCLBND		0x02000000	/* relocation must bind */
83 						/*    locally */
84 
85 /*
86  * In user land, redefine the relocation table and relocation engine to be
87  * class specific if necessary.  This allows both engines to reside in the
88  * intel/amd version of libld.
89  */
90 #if	!defined(_KERNEL)
91 #if	defined(_ELF64)
92 #define	do_reloc_ld		do64_reloc_ld
93 #define	do_reloc_rtld		do64_reloc_rtld
94 #define	reloc_table		reloc64_table
95 #else
96 #define	do_reloc_ld		do32_reloc_ld
97 #define	do_reloc_rtld		do32_reloc_rtld
98 #define	reloc_table		reloc32_table
99 #endif
100 #endif
101 
102 /*
103  * Relocation table and macros for testing relocation table flags.
104  */
105 extern	const Rel_entry		reloc_table[];
106 
107 #define	IS_PLT(X)		((reloc_table[(X)].re_flags & \
108 					FLG_RE_PLTREL) != 0)
109 #define	IS_GOT_RELATIVE(X)	((reloc_table[(X)].re_flags & \
110 					FLG_RE_GOTADD) != 0)
111 #define	IS_GOT_PC(X)		((reloc_table[(X)].re_flags & \
112 					FLG_RE_GOTPC) != 0)
113 #define	IS_GOTPCREL(X)		((reloc_table[(X)].re_flags & \
114 					(FLG_RE_GOTPC | FLG_RE_GOTADD)) == \
115 					(FLG_RE_GOTPC | FLG_RE_GOTADD))
116 #define	IS_GOT_BASED(X)		((reloc_table[(X)].re_flags & \
117 					FLG_RE_GOTREL) != 0)
118 #define	IS_GOT_OPINS(X)		((reloc_table[(X)].re_flags & \
119 					FLG_RE_GOTOPINS) != 0)
120 #define	IS_GOT_REQUIRED(X)	((reloc_table[(X)].re_flags & \
121 					(FLG_RE_GOTADD | FLG_RE_GOTREL | \
122 					FLG_RE_GOTPC | FLG_RE_GOTOPINS)) != 0)
123 #define	IS_PC_RELATIVE(X)	((reloc_table[(X)].re_flags & \
124 					FLG_RE_PCREL) != 0)
125 #define	IS_ADD_RELATIVE(X)	((reloc_table[(X)].re_flags & \
126 					FLG_RE_ADDRELATIVE) != 0)
127 #define	IS_REGISTER(X)		((reloc_table[(X)].re_flags & \
128 					FLG_RE_REGISTER) != 0)
129 #define	IS_NOTSUP(X)		((reloc_table[(X)].re_flags & \
130 					FLG_RE_NOTSUP) != 0)
131 #define	IS_SEG_RELATIVE(X)	((reloc_table[(X)].re_flags & \
132 					FLG_RE_SEGREL) != 0)
133 #define	IS_EXTOFFSET(X)		((reloc_table[(X)].re_flags & \
134 					FLG_RE_EXTOFFSET) != 0)
135 #define	IS_SEC_RELATIVE(X)	((reloc_table[(X)].re_flags & \
136 					FLG_RE_SECREL) != 0)
137 #define	IS_TLS_INS(X)		((reloc_table[(X)].re_flags & \
138 					(FLG_RE_TLSGD | FLG_RE_TLSLD | \
139 					FLG_RE_TLSIE | FLG_RE_TLSLE)) != 0)
140 #define	IS_TLS_GD(X)		((reloc_table[(X)].re_flags & \
141 					FLG_RE_TLSGD) != 0)
142 #define	IS_TLS_LD(X)		((reloc_table[(X)].re_flags & \
143 					FLG_RE_TLSLD) != 0)
144 #define	IS_TLS_IE(X)		((reloc_table[(X)].re_flags & \
145 					FLG_RE_TLSIE) != 0)
146 #define	IS_TLS_LE(X)		((reloc_table[(X)].re_flags & \
147 					FLG_RE_TLSLE) != 0)
148 #define	IS_LOCALBND(X)		((reloc_table[(X)].re_flags & \
149 					FLG_RE_LOCLBND) != 0)
150 #define	IS_SIZE(X)		((reloc_table[(X)].re_flags &\
151 					FLG_RE_SIZE) != 0)
152 
153 /*
154  * Relocation engine.
155  *
156  * The do_reloc() code is used in three different places: The kernel,
157  * the linker, and the runtime linker. All three use the same first
158  * 5 arguments. In addition:
159  *	- The linker and rtld want a link map pointer argument
160  *	- The linker wants to pass a byte swap argument that tells
161  *		the relocation engine that the data it is relocating
162  *		has the opposite byte order of the system running the
163  *		linker.
164  *
165  * To ensure that there is never any confusion about which version is
166  * being linked to, we give each variant a different name, even though
167  * each one is generated from the same source code.
168  *
169  *	do_reloc_krtld()
170  *	The kernel version is provided if the _KERNEL macro is defined.
171  *
172  *	do_reloc_ld()
173  *	The ld version is provided if the DO_RELOC_LIBLD macro is defined.
174  *
175  *	do_reloc_rtld()
176  *	The rtld version is provided if neither _KERNEL or DO_RELOC_LIBLD
177  *	are defined.
178  *
179  * Implementations of do_reloc() should use these same macros to
180  * conditionalize any code not used by all three versions.
181  */
182 #if defined(_KERNEL)
183 extern	int	do_reloc_krtld(uchar_t, uchar_t *, Xword *, const char *,
184 		    const char *);
185 #elif defined(DO_RELOC_LIBLD)
186 extern	int	do_reloc_ld(uchar_t, uchar_t *, Xword *, const char *,
187 		    const char *, int, void *);
188 #else
189 extern	int	do_reloc_rtld(uchar_t, uchar_t *, Xword *, const char *,
190 		    const char *, void *);
191 #endif
192 
193 #if defined(_KERNEL)
194 /*
195  * These are macro's that are only needed for krtld.  Many of these are already
196  * defined in the sgs/include files referenced by ld and rtld
197  */
198 #define	S_MASK(n)	((1l << (n)) - 1l)
199 #define	S_INRANGE(v, n)	(((-(1l << (n)) - 1l) < (v)) && ((v) < (1l << (n))))
200 
201 /*
202  * Message strings used by doreloc().
203  */
204 #define	MSG_STR_UNKNOWN		"(unknown)"
205 
206 #define	MSG_REL_PREGEN		"relocation error: %s: "
207 #define	MSG_REL_PREFIL		"relocation error: file %s: "
208 #define	MSG_REL_FILE		"file %s: "
209 #define	MSG_REL_SYM		"symbol %s: "
210 #define	MSG_REL_VALUE		"value 0x%llx "
211 #define	MSG_REL_LOSEBITS	"loses %d bits at "
212 
213 #define	MSG_REL_UNIMPL		"unimplemented relocation type: %d"
214 #define	MSG_REL_UNSUPSZ		"offset size (%d bytes) is not supported"
215 #define	MSG_REL_NONALIGN	"offset 0x%llx is non-aligned"
216 #define	MSG_REL_UNNOBITS	"unsupported number of bits: %d"
217 #define	MSG_REL_OFFSET		"offset 0x%llx"
218 #define	MSG_REL_NOFIT		"value 0x%llx does not fit"
219 
220 /*
221  * Provide a macro to select the appropriate conversion routine for this
222  * architecture.
223  */
224 #if defined(__amd64)
225 
226 extern const char	*conv_reloc_amd64_type(Word);
227 #define	CONV_RELOC_TYPE	conv_reloc_amd64_type
228 
229 #elif defined(__i386)
230 
231 extern const char	*conv_reloc_386_type(Word);
232 #define	CONV_RELOC_TYPE	conv_reloc_386_type
233 
234 #elif defined(__sparc)
235 
236 extern const char	*conv_reloc_SPARC_type(Word);
237 #define	CONV_RELOC_TYPE	conv_reloc_SPARC_type
238 
239 #else
240 #error platform not defined!
241 #endif
242 
243 /*
244  * Note:  dlerror() only keeps track of a single error string, and therefore
245  * must have errors reported through a single eprintf() call.  The kernel's
246  * _kobj_printf is somewhat more limited, and must receive messages with only
247  * one argument to the format string.  The following macros account for these
248  * differences, as krtld and rtld share the same do_reloc() source.
249  */
250 #define	REL_ERR_UNIMPL(lml, file, sym, rtype) \
251 	_kobj_printf(ops, MSG_REL_PREFIL, (file)); \
252 	_kobj_printf(ops, MSG_REL_SYM, ((sym) ? (sym) : MSG_STR_UNKNOWN)); \
253 	_kobj_printf(ops, MSG_REL_UNIMPL, (int)(rtype))
254 
255 #define	REL_ERR_UNSUPSZ(lml, file, sym, rtype, size) \
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_UNSUPSZ, (int)(size))
260 
261 #define	REL_ERR_NONALIGN(lml, file, sym, rtype, off) \
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_NONALIGN, EC_OFF((off)))
266 
267 #define	REL_ERR_UNNOBITS(lml, file, sym, rtype, nbits) \
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_UNNOBITS, (nbits))
272 
273 #define	REL_ERR_LOSEBITS(lml, file, sym, rtype, uvalue, nbits, off) \
274 	_kobj_printf(ops, MSG_REL_PREGEN, CONV_RELOC_TYPE((rtype))); \
275 	_kobj_printf(ops, MSG_REL_FILE, (file)); \
276 	_kobj_printf(ops, MSG_REL_SYM, ((sym) ? (sym) : MSG_STR_UNKNOWN)); \
277 	_kobj_printf(ops, MSG_REL_VALUE, EC_XWORD((uvalue))); \
278 	_kobj_printf(ops, MSG_REL_LOSEBITS, (int)(nbits)); \
279 	_kobj_printf(ops, MSG_REL_OFFSET, EC_NATPTR((off)))
280 
281 #define	REL_ERR_NOFIT(lml, file, sym, rtype, uvalue) \
282 	_kobj_printf(ops, MSG_REL_PREGEN, CONV_RELOC_TYPE((rtype))); \
283 	_kobj_printf(ops, MSG_REL_FILE, (file)); \
284 	_kobj_printf(ops, MSG_REL_SYM, ((sym) ? (sym) : MSG_STR_UNKNOWN)); \
285 	_kobj_printf(ops, MSG_REL_NOFIT, EC_XWORD((uvalue)))
286 
287 
288 #else	/* !_KERNEL */
289 
290 extern	const char *demangle(const char *);
291 
292 #define	REL_ERR_UNIMPL(lml, file, sym, rtype) \
293 	(eprintf(lml, ERR_FATAL, MSG_INTL(MSG_REL_UNIMPL), (file), \
294 	    ((sym) ? demangle(sym) : MSG_INTL(MSG_STR_UNKNOWN)), (int)(rtype)))
295 
296 #define	REL_ERR_UNSUPSZ(lml, file, sym, rtype, size) \
297 	(eprintf(lml, ERR_FATAL, MSG_INTL(MSG_REL_UNSUPSZ), \
298 	    conv_reloc_type_static(M_MACH, (rtype), 0), (file), \
299 	    ((sym) ? demangle(sym) : MSG_INTL(MSG_STR_UNKNOWN)), (int)(size)))
300 
301 #define	REL_ERR_NONALIGN(lml, file, sym, rtype, off) \
302 	(eprintf(lml, ERR_FATAL, MSG_INTL(MSG_REL_NONALIGN), \
303 	    conv_reloc_type_static(M_MACH, (rtype), 0), (file), \
304 	    ((sym) ? demangle(sym) : MSG_INTL(MSG_STR_UNKNOWN)), EC_OFF((off))))
305 
306 #define	REL_ERR_UNNOBITS(lml, file, sym, rtype, nbits) \
307 	(eprintf(lml, ERR_FATAL, MSG_INTL(MSG_REL_UNNOBITS), \
308 	    conv_reloc_type_static(M_MACH, (rtype), 0), (file), \
309 	    ((sym) ? demangle(sym) : MSG_INTL(MSG_STR_UNKNOWN)), (nbits)))
310 
311 #define	REL_ERR_LOSEBITS(lml, file, sym, rtype, uvalue, nbits, off) \
312 	(eprintf(lml, ERR_FATAL,  MSG_INTL(MSG_REL_LOSEBITS), \
313 	    conv_reloc_type_static(M_MACH, (rtype), 0), (file), \
314 	    ((sym) ? demangle(sym) : MSG_INTL(MSG_STR_UNKNOWN)), \
315 	    EC_XWORD((uvalue)), (nbits), EC_NATPTR((off))))
316 
317 #define	REL_ERR_NOFIT(lml, file, sym, rtype, uvalue) \
318 	(eprintf(lml, ERR_FATAL, MSG_INTL(MSG_REL_NOFIT), \
319 	    conv_reloc_type_static(M_MACH, (rtype), 0), (file), \
320 	    ((sym) ? demangle(sym) : MSG_INTL(MSG_STR_UNKNOWN)), \
321 	    EC_XWORD((uvalue))))
322 
323 #define	REL_ERR_NOSWAP(lml, file, sym, rtype) \
324 	(eprintf(lml, ERR_FATAL, MSG_INTL(MSG_REL_NOSWAP), \
325 	    conv_reloc_type_static(M_MACH, (rtype), 0), (file), \
326 	    ((sym) ? demangle(sym) : MSG_INTL(MSG_STR_UNKNOWN))))
327 
328 #endif	/* _KERNEL */
329 
330 #ifdef	__cplusplus
331 }
332 #endif
333 
334 #endif /* _RELOC_DOT_H */
335