xref: /illumos-gate/usr/src/uts/intel/amd64/krtld/doreloc.c (revision 1fa2a66491e7d8ae0be84e7da4da8e812480c710)
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) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
24  */
25 
26 #if	defined(_KERNEL)
27 #include	<sys/types.h>
28 #include	"reloc.h"
29 #else
30 #define	ELF_TARGET_AMD64
31 #if defined(DO_RELOC_LIBLD)
32 #undef DO_RELOC_LIBLD
33 #define	DO_RELOC_LIBLD_X86
34 #endif
35 #include	<stdio.h>
36 #include	"sgs.h"
37 #include	"machdep.h"
38 #include	"libld.h"
39 #include	"reloc.h"
40 #include	"conv.h"
41 #include	"msg.h"
42 #endif
43 
44 /*
45  * We need to build this code differently when it is used for
46  * cross linking:
47  *	- Data alignment requirements can differ from those
48  *		of the running system, so we can't access data
49  *		in units larger than a byte
50  *	- We have to include code to do byte swapping when the
51  *		target and linker host use different byte ordering,
52  *		but such code is a waste when running natively.
53  */
54 #if !defined(DO_RELOC_LIBLD) || defined(__x86)
55 #define	DORELOC_NATIVE
56 #endif
57 
58 /*
59  * This table represents the current relocations that do_reloc() is able to
60  * process.  The relocations below that are marked SPECIAL are relocations that
61  * take special processing and shouldn't actually ever be passed to do_reloc().
62  */
63 const Rel_entry	reloc_table[R_AMD64_NUM] = {
64 	[R_AMD64_NONE]		= {0, FLG_RE_NOTREL, 0, 0, 0},
65 	[R_AMD64_64]		= {0, FLG_RE_NOTREL, 8, 0, 0},
66 	[R_AMD64_PC32]		= {0, FLG_RE_PCREL, 4, 0, 0},
67 	[R_AMD64_GOT32]		= {0, FLG_RE_NOTSUP, 0, 0, 0},
68 	[R_AMD64_PLT32]		= {0, FLG_RE_PCREL | FLG_RE_PLTREL |
69 	    FLG_RE_VERIFY | FLG_RE_SIGN, 4, 0, 0},
70 	[R_AMD64_COPY]		= {0, FLG_RE_NOTSUP, 0, 0, 0},	/* SPECIAL */
71 	[R_AMD64_GLOB_DAT]	= {0, FLG_RE_NOTREL, 8, 0, 0},
72 	[R_AMD64_JUMP_SLOT]	= {0, FLG_RE_NOTSUP, 0, 0, 0},	/* SPECIAL */
73 	[R_AMD64_RELATIVE]	= {0, FLG_RE_NOTREL, 8, 0, 0},
74 	[R_AMD64_GOTPCREL]	= {0, FLG_RE_GOTPC | FLG_RE_GOTADD, 4, 0, 0},
75 	[R_AMD64_32]		= {0, FLG_RE_NOTREL, 4, 0, 0},
76 	[R_AMD64_32S]		= {0, FLG_RE_NOTREL, 4, 0, 0},
77 	[R_AMD64_16]		= {0, FLG_RE_NOTREL, 2, 0, 0},
78 	[R_AMD64_PC16]		= {0, FLG_RE_PCREL, 2, 0, 0},
79 	[R_AMD64_8]		= {0, FLG_RE_NOTREL, 1, 0, 0},
80 	[R_AMD64_PC8]		= {0, FLG_RE_PCREL, 1, 0, 0},
81 	[R_AMD64_DTPMOD64]	= {0, FLG_RE_NOTREL, 8, 0, 0},
82 	[R_AMD64_DTPOFF64]	= {0, FLG_RE_NOTREL, 8, 0, 0},
83 	[R_AMD64_TPOFF64]	= {0, FLG_RE_NOTREL, 8, 0, 0},
84 	[R_AMD64_TLSGD]		= {0, FLG_RE_GOTPC | FLG_RE_GOTADD |
85 	    FLG_RE_TLSGD, 4, 0, 0},
86 	[R_AMD64_TLSLD]		= {0, FLG_RE_GOTPC | FLG_RE_GOTADD |
87 	    FLG_RE_TLSLD, 4, 0, 0},
88 	[R_AMD64_DTPOFF32]	= {0, FLG_RE_TLSLD, 4, 0, 0},
89 	[R_AMD64_GOTTPOFF]	= {0, FLG_RE_GOTPC | FLG_RE_GOTADD |
90 	    FLG_RE_TLSIE, 4, 0, 0},
91 	[R_AMD64_TPOFF32]	= {0, FLG_RE_TLSLE, 4, 0, 0},
92 	[R_AMD64_PC64]		= {0, FLG_RE_PCREL, 8, 0, 0},
93 	[R_AMD64_GOTOFF64]	= {0, FLG_RE_GOTREL, 8, 0, 0},
94 	[R_AMD64_GOTPC32]	= {0, FLG_RE_PCREL | FLG_RE_GOTPC |
95 	    FLG_RE_LOCLBND, 4, 0, 0},
96 	[R_AMD64_GOT64]		= {0, FLG_RE_NOTSUP, 0, 0, 0},
97 	[R_AMD64_GOTPCREL64]	= {0, FLG_RE_NOTSUP, 0, 0, 0},
98 	[R_AMD64_GOTPC64]	= {0, FLG_RE_NOTSUP, 0, 0, 0},
99 	[R_AMD64_GOTPLT64]	= {0, FLG_RE_NOTSUP, 0, 0, 0},
100 	[R_AMD64_PLTOFF64]	= {0, FLG_RE_NOTSUP, 0, 0, 0},
101 	[R_AMD64_SIZE32]	= {0, FLG_RE_SIZE, 4, 0, 0},
102 	[R_AMD64_SIZE64]	= {0, FLG_RE_SIZE, 8, 0, 0},
103 	[R_AMD64_GOTPC32_TLSDESC] = {0, FLG_RE_NOTSUP, 0, 0, 0},
104 	[R_AMD64_TLSDESC_CALL]	= {0, FLG_RE_NOTSUP, 0, 0, 0},
105 	[R_AMD64_TLSDESC]	= {0, FLG_RE_NOTSUP, 0, 0, 0},
106 	[R_AMD64_IRELATIVE]	= {0, FLG_RE_NOTSUP, 0, 0, 0},
107 	[R_AMD64_RELATIVE64]	= {0, FLG_RE_NOTSUP, 0, 0, 0},
108 	[R_AMD64_UNKNOWN39]	= {0, FLG_RE_NOTSUP, 0, 0, 0},
109 	[R_AMD64_UNKNOWN40]	= {0, FLG_RE_NOTSUP, 0, 0, 0},
110 	[R_AMD64_GOTPCRELX]	= {0, FLG_RE_GOTPC | FLG_RE_GOTADD, 4, 0, 0},
111 	[R_AMD64_REX_GOTPCRELX]	= {0, FLG_RE_GOTPC | FLG_RE_GOTADD, 4, 0, 0},
112 };
113 #if	(R_AMD64_NUM != (R_AMD64_REX_GOTPCRELX + 1))
114 #error	"R_AMD64_NUM has grown"
115 #endif
116 
117 /*
118  * Write a single relocated value to its reference location.
119  * We assume we wish to add the relocation amount, value, to the
120  * value of the address already present at the offset.
121  *
122  * NAME				VALUE	FIELD		CALCULATION
123  *
124  * R_AMD64_NONE			 0	none		none
125  * R_AMD64_64			 1	word64		S + A
126  * R_AMD64_PC32			 2	word64		S + A
127  * R_AMD64_GOT32		 3	word32		G + A
128  * R_AMD64_PLT32		 4	word32		L + A - P
129  * R_AMD64_COPY			 5	none		none
130  * R_AMD64_GLOB_DAT		 6	word64		S
131  * R_AMD64_JUMP_SLOT		 7	word64		S
132  * R_AMD64_RELATIVE		 8	word64		B + A
133  * R_AMD64_GOTPCREL		 9	word32		G + GOT + A - P
134  * R_AMD64_32			10	word32		S + A
135  * R_AMD64_32S			11	word32		S + A
136  * R_AMD64_16			12	word16		S + A
137  * R_AMD64_PC16			13	word16		S + A - P
138  * R_AMD64_8			14	word8		S + A
139  * R_AMD64_PC8			15	word8		S + A - P
140  * R_AMD64_DTPMOD64		16	word64
141  * R_AMD64_DTPOFF64		17	word64
142  * R_AMD64_TPOFF64		18	word64
143  * R_AMD64_TLSGD		19	word32
144  * R_AMD64_TLSLD		20	word32
145  * R_AMD64_DTPOFF32		21	word32
146  * R_AMD64_GOTTPOFF		22	word32
147  * R_AMD64_TPOFF32		23	word32
148  * R_AMD64_PC64			24	word32		S + A - P
149  * R_AMD64_GOTOFF64		25	word32		S + A - GOT
150  * R_AMD64_GOTPC32		26	word32		GOT + A - P
151  * R_AMD64_GOT64		27			future expansion
152  * R_AMD64_GOTPCREL64		28			future expansion
153  * R_AMD64_GOTPC64		29			future expansion
154  * R_AMD64_GOTPLT64		30			future expansion
155  * R_AMD64_PLTOFF64		31			future expansion
156  * R_AMD64_SIZE32		32	word32		Z + A
157  * R_AMD64_SIZE64		33	word64		Z + A
158  * R_AMD64_GOTPC32_TLSDESC	34	word32
159  * R_AMD64_TLSDESC_CALL		35	none
160  * R_AMD64_TLSDESC		36	word64*2
161  * R_AMD64_IRELATIVE		37	word64		indirect (B + A)
162  * R_AMD64_RELATIVE64		38	word64		B + A
163  * R_AMD64_GOTPCRELX		41	word32		G + GOT + A - P
164  * R_AMD64_REX_GOTPCRELX	42	word32		G + GOT + A - P
165  *
166  * Relocation calculations:
167  *	A	Represents the addend used to compute the value of the
168  *		relocatable field.
169  *
170  *	B	Represents the base address at which a shared objects has
171  *		been loaded into memory during executaion.  Generally, a
172  *		shared objects is built with a 0 base virtual address,
173  *		but the execution address will be different.
174  *
175  *	G	Represents the offset into the global offset table
176  *		at which the relocation entry's symbol will reside
177  *		during execution.
178  *
179  *	GOT	Rrepresents the address of the global offset table.
180  *
181  *	L	Represents the place (section offset or address) of
182  *		the Procedure Linkage Table entry for a symbol.
183  *
184  *	P	Represents the place (section offset or address) of the
185  *		storage unit being relocated (computed using r_offset).
186  *
187  *	S	Represents the value of the symbol whose index resides
188  *		in the relocation entry.
189  *
190  *	Z	the size of the symbol whose index resides in the relocation
191  *		entry
192  */
193 
194 
195 /*
196  * Bits that must be cleared or identical for a value to act as if extended in
197  * the given way.
198  */
199 #define	ZEROEXBITS	0xffffffff00000000ULL
200 #define	SIGNEXBITS	0xffffffff80000000ULL
201 
202 /* BEGIN CSTYLED */
203 #if defined(_KERNEL)
204 #define	lml	0		/* Needed by arglist of REL_ERR_* macros */
205 int
206 do_reloc_krtld(uchar_t rtype, uchar_t *off, Xword *value, const char *sym,
207     const char *file)
208 #elif defined(DO_RELOC_LIBLD)
209 /*ARGSUSED5*/
210 int
211 do_reloc_ld(Rel_desc *rdesc, uchar_t *off, Xword *value,
212     rel_desc_sname_func_t rel_desc_sname_func,
213     const char *file, int bswap, void *lml)
214 #else
215 int
216 do_reloc_rtld(uchar_t rtype, uchar_t *off, Xword *value, const char *sym,
217     const char *file, void *lml)
218 #endif
219 {
220 /* END CSTYLED */
221 #ifdef DO_RELOC_LIBLD
222 #define	sym (* rel_desc_sname_func)(rdesc)
223 	uchar_t	rtype = rdesc->rel_rtype;
224 #endif
225 	const Rel_entry	*rep;
226 
227 	rep = &reloc_table[rtype];
228 
229 	switch (rep->re_fsize) {
230 	case 1:
231 		/* LINTED */
232 		*((uchar_t *)off) = (uchar_t)(*value);
233 		break;
234 
235 	case 2:
236 #if defined(DORELOC_NATIVE)
237 		/* LINTED */
238 		*((Half *)off) = (Half)(*value);
239 #else
240 		{
241 			Half	v = (Half)(*value);
242 			uchar_t	*v_bytes = (uchar_t *)&v;
243 
244 			if (bswap) {
245 				UL_ASSIGN_BSWAP_HALF(off, v_bytes);
246 			} else {
247 				UL_ASSIGN_HALF(off, v_bytes);
248 			}
249 		}
250 #endif
251 		break;
252 
253 	case 4:
254 		/*
255 		 * The amd64 psABI requires that we perform the following
256 		 * verifications:
257 		 *
258 		 *    The R_AMD64_32 and R_AMD64_32S relocations truncate the
259 		 *    computed value to 32bits.  Verify that the generated value
260 		 *    for the R_AMD64_32/32S relocation zero-extends (sign
261 		 *    extends) to the original 64-bit value.
262 		 *
263 		 * Also, the following relocations are all 32 bit PC relative
264 		 * references.  Validate that the value being written will fit
265 		 * in the field provided.
266 		 *
267 		 *    R_AMD64_PC32, R_AMD64_GOTPC32, R_AMD64_GOTPCREL,
268 		 *    R_AMD64_GOTPCRELX, R_AMD64_REX_GOTPCRELX.
269 		 */
270 		if (rtype == R_AMD64_32) {
271 			/*
272 			 * Verify that this value will act as a zero-extended
273 			 * unsigned 32 bit value.  That is, that the upper
274 			 * 32 bits are zero.
275 			 */
276 			if ((*value & ZEROEXBITS) != 0) {
277 				/*
278 				 * To keep chkmsg() happy:
279 				 *  MSG_INTL(MSG_REL_NOFIT)
280 				 */
281 				REL_ERR_NOFIT(lml, file, sym, rtype, *value);
282 				return (0);
283 			}
284 		} else if ((rtype == R_AMD64_32S) || (rtype == R_AMD64_PC32) ||
285 		    (rtype == R_AMD64_GOTPCREL) || (rtype == R_AMD64_GOTPC32) ||
286 		    (rtype == R_AMD64_GOTPCRELX) ||
287 		    (rtype == R_AMD64_REX_GOTPCRELX)) {
288 			/*
289 			 * Verify that this value will act as a sign-extended
290 			 * signed 32 bit value, that is that the upper 33 bits
291 			 * are either all zero or all one.
292 			 */
293 			if (((*value & SIGNEXBITS) != SIGNEXBITS) &&
294 			    ((*value & SIGNEXBITS) != 0)) {
295 				/*
296 				 * To keep chkmsg() happy:
297 				 *  MSG_INTL(MSG_REL_NOFIT)
298 				 */
299 				REL_ERR_NOFIT(lml, file, sym, rtype, *value);
300 				return (0);
301 			}
302 		}
303 
304 #if defined(DORELOC_NATIVE)
305 		/* LINTED */
306 		*((Word *)off) += *value;
307 #else
308 		{
309 			Word	v;
310 			uchar_t	*v_bytes = (uchar_t *)&v;
311 
312 			if (bswap) {
313 				UL_ASSIGN_BSWAP_WORD(v_bytes, off);
314 				v += *value;
315 				UL_ASSIGN_BSWAP_WORD(off, v_bytes);
316 			} else {
317 				UL_ASSIGN_WORD(v_bytes, off);
318 				v += *value;
319 				UL_ASSIGN_WORD(off, v_bytes);
320 			}
321 		}
322 #endif
323 		break;
324 
325 	case 8:
326 #if defined(DORELOC_NATIVE)
327 		/* LINTED */
328 		*((Xword *)off) += *value;
329 #else
330 		{
331 			Xword	v;
332 			uchar_t	*v_bytes = (uchar_t *)&v;
333 
334 			if (bswap) {
335 				UL_ASSIGN_BSWAP_XWORD(v_bytes, off);
336 				v += *value;
337 				UL_ASSIGN_BSWAP_XWORD(off, v_bytes);
338 			} else {
339 				UL_ASSIGN_XWORD(v_bytes, off);
340 				v += *value;
341 				UL_ASSIGN_XWORD(off, v_bytes);
342 			}
343 		}
344 #endif
345 		break;
346 	default:
347 		/*
348 		 * To keep chkmsg() happy: MSG_INTL(MSG_REL_UNSUPSZ)
349 		 */
350 		REL_ERR_UNSUPSZ(lml, file, sym, rtype, rep->re_fsize);
351 		return (0);
352 	}
353 	return (1);
354 
355 #ifdef DO_RELOC_LIBLD
356 #undef sym
357 #endif
358 }
359