reloc.h revision 6206:6b0ed502a8e7
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
44extern "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 */
101extern	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)
160extern	int	do_reloc_krtld(uchar_t, uchar_t *, Xword *, const char *,
161		    const char *);
162#elif defined(DO_RELOC_LIBLD)
163extern	int	do_reloc_ld(uchar_t, uchar_t *, Xword *, const char *,
164		    const char *, int, void *);
165#else
166extern	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
203extern const char	*conv_reloc_amd64_type(Word);
204#define	CONV_RELOC_TYPE	conv_reloc_amd64_type
205
206#elif defined(__i386)
207
208extern const char	*conv_reloc_386_type(Word);
209#define	CONV_RELOC_TYPE	conv_reloc_386_type
210
211#elif defined(__sparc)
212
213extern 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
268extern	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